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");
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
},
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
.