Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In NextJS, how to build when referencing external npm package that contains SVGs?

My nextjs project (let's call it TheHost) references another npm package (let's call it ThePackage).

SVGs load fine when defined within TheHost, but importing ThePackage fails because next tries to interpret the svg as javascript... so I get the following error when doing a next build:

SyntaxError: Unexpected token '<'

To re-iterate, SVGs work fine when referencing an svg defined in TheHost itself. The problem seems to be importing npm packages that contain SVGs.

It doesn't matter if I import a component from ThePackage that uses an SVG or not, just the fact that somewhere in the npm package it contains an "import xxx from '../path/to/svg' is enough to break next build.

For what it's worth, the ThePackage's transpiled javascript reads the svg as follows:

var _mysvg = require("../path/to/the-svg.svg");

Lots of details:

The next build stack trace is:

> Using external babel configuration
> Location: "/Users/w/dev/TheHost/.babelrc"
Creating an optimized production build

Compiled successfully.

> Build error occurred
/Users/w/dev/TheHost/node_modules/ThePackage/build/assets/card_background.svg:1
<svg viewBox="0 0 860 382" fill="none" xmlns="http://www.w3.org/2000/svg">
^

SyntaxError: Unexpected token '<'
    at Module._compile (internal/modules/cjs/loader.js:895:18)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10)
    at Module.load (internal/modules/cjs/loader.js:815:32)
    at Function.Module._load (internal/modules/cjs/loader.js:727:14)
    at Module.require (internal/modules/cjs/loader.js:852:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.<anonymous> (/Users/w/dev/TheHost/node_modules/TheProject/build/card/style.js:14:47)
    at Module._compile (internal/modules/cjs/loader.js:959:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10)
    at Module.load (internal/modules/cjs/loader.js:815:32) {
  type: 'SyntaxError'
}
Automatically optimizing pages .%

The .babelrc file:

{
  "presets": [
    "next/babel"
  ],
  "plugins": [
    "babel-plugin-styled-components",
    "inline-react-svg"
  ]
}

The next.config.js file:

const withSourceMaps = require("@zeit/next-source-maps");
const withImages = require("next-images");

module.exports = withImages(
  withSourceMaps({
    env: { *** redacted *** },
    publicRuntimeConfig: { *** redacted *** },
    webpack: (config, options) => {
      if (!options.isServer) {
        config.resolve.alias["@sentry/node"] = "@sentry/browser";
      }
      config.module.rules.push({
        test: /\.svg$/,
        use: ["@svgr/webpack"]
      });
      return config;
    }
  })
);

The nextjs svgr package versions are as follows:

"next": "^9.2.1",
"next-images": "^1.3.0",
"@svgr/webpack": "^5.1.0",
"babel-eslint": "^10.0.3",
"babel-plugin-inline-react-svg": "^1.1.1",

ThePackage is built with the following output configuration (webpack):

  entry: './src/index.js',
  output: {
    path: buildFolder,
    filename: 'ThePackage.js',
    library: 'ThePackage',
    libraryTarget: 'umd', /* Note: umd */
    umdNamedDefine: true
  },
like image 833
willem Avatar asked Feb 19 '20 12:02

willem


People also ask

What is npm package manager?

The Node.js Package Manager (npm) is the default and most popular package manager in Node.js ecosystem that is primarily used to install and maintain external modules in Node.js application. Users can basically install the node modules needed for their application using npm. How to export Modules ?

How to add CSS file in nextjs?

You can add the css file in head of nextjs. and in the render method, inside the return add a head tag similar to ordinary HTML, the head tag should be inside a div. <div> <Head> <title>Test</title> <link href="/static/master.css" rel="stylesheet" key="test"/> </Head> </div> also the css should be in static folder.

How do I deploy nextnext's Node JS application?

Next.js can be deployed to any hosting provider that supports Node.js. For example, AWS EC2 or a DigitalOcean Droplet. First, ensure your package.json has the "build" and "start" scripts: Then, run next build to build your application. Finally, run next start to start the Node.js server.

How to include an SVG file in a JSX file?

<svg> is a standard HTML tag that can be directly used in JSX. That means if your SVG is quite short, it can be easiest to include it in place. You can use a regular img tag and reference the SVG by URL. You need to place the image in the /public directory and reference it relative to that. This file would be in the root of the public directory.


1 Answers

NextJS ignores node_modules by default so you'd need to specifically allow your config to be able to transpile your package. Fortunately, someone has already created a NextJS plugin to allow this: https://github.com/martpie/next-transpile-modules

I'd also suggest using Next Compose Plugins to neaten up the config. In the end, your next.config.js will look something like this:

const withSourceMaps = require("@zeit/next-source-maps");
const withImages = require("next-images");
const withPlugins = require('next-compose-plugins');
const withTM = require('next-transpile-modules')(['ThePackage']);

module.exports = withPlugins([
    withTM,
    [
        withImages,
        {
            exclude: /\.svg$/
        }
    ],
    withSourceMaps
],
{
    env: { *** redacted *** },
    publicRuntimeConfig: { *** redacted *** },
    webpack: (config, options) => {
      if (!options.isServer) {
        config.resolve.alias["@sentry/node"] = "@sentry/browser";
      }
      config.module.rules.push({
        test: /\.svg$/,
        use: ["@svgr/webpack"]
      });
      return config;
    }
});

I've also excluded SVGs from being processed by withImages.

like image 90
Seagyn Davis Avatar answered Sep 19 '22 11:09

Seagyn Davis