I've found a lot of stuff about "Unexpected character '@'" happening with webpack, but none of it related specifically to, or helpful with, getting that error for the externals
webpack option. I've used this before, both with and without @-signs, without any trouble, so I don't know why webpack is getting cranky now.
const TerserPlugin = require('terser-webpack-plugin');
module.exports = () => {
return {
mode: 'production',
target: 'node',
entry: './build.ts',
output: {
path: __dirname,
filename: `build.js`
},
node: {
__dirname: false,
__filename: false,
},
resolve: {
extensions: ['.ts', '.js'],
mainFields: ['es2015', 'module', 'main', 'browser']
},
module: {
rules: [
{
test: /\.ts$/i,
loader: 'ts-loader',
options: { configFile: 'tsconfig-build.json' },
exclude: [/\/node_modules\//]
}
]
},
externals: ['chalk', '@tubular/util'],
optimization: {
minimize: true,
minimizer: [new TerserPlugin({
terserOptions: {
mangle: false,
output: { max_line_len: 511 }
}
})],
},
};
};
The @ is a necessary part of the package name that I want to exclude, and I've exclude such packages before, so this is both mysterious and annoying.
Anyone have any idea what's wrong here?
I've found a lot of stuff about "Unexpected character '@'" happening with webpack, but none of it related specifically to, or helpful with, getting that error for the externals
webpack option. I've used this before, both with and without @-signs, without any trouble, so I don't know why webpack is getting cranky now.
const TerserPlugin = require('terser-webpack-plugin');
module.exports = () => {
return {
mode: 'production',
target: 'node',
entry: './build.ts',
output: {
path: __dirname,
filename: `build.js`
},
node: {
__dirname: false,
__filename: false,
},
resolve: {
extensions: ['.ts', '.js'],
mainFields: ['es2015', 'module', 'main', 'browser']
},
module: {
rules: [
{
test: /\.ts$/i,
loader: 'ts-loader',
options: { configFile: 'tsconfig-build.json' },
exclude: [/\/node_modules\//]
}
]
},
externals: ['chalk', '@tubular/util'],
optimization: {
minimize: true,
minimizer: [new TerserPlugin({
terserOptions: {
mangle: false,
output: { max_line_len: 511 }
}
})],
},
};
};
The @ is a necessary part of the package name that I want to exclude, and I've exclude such packages before, so this is both mysterious and annoying.
Anyone have any idea what's wrong here?
Share Improve this question asked May 15, 2021 at 19:30 kshetlinekshetline 13.8k6 gold badges49 silver badges91 bronze badges 5- I'm facing the same problem with '@vue/position-api'. Did you filled a bug report or something ? – Johnny5 Commented May 20, 2021 at 14:06
- No, I haven't filed a bug report. I wasn't sure if it was a bug, or something I'd set up incorrectly. It's beginning to sound like a bug, however. What's weird is I have other projects right now that use the @ without any problem, so I don't know what the difference is well enough to characterize the bug. – kshetline Commented May 20, 2021 at 14:13
- Does your working projects uses the same version of webpack ? Mine uses webpack 5.37.0 – Johnny5 Commented May 20, 2021 at 14:41
-
The error does not happend if I add
type: 'umd'
to thelibrary
node. – Johnny5 Commented May 20, 2021 at 18:17 - I'm using webpack 5.37.0 both where @ works and where it doesn't. But just like you, where it works I'm using 'umd'. – kshetline Commented May 20, 2021 at 18:58
3 Answers
Reset to default 4I found a solution, I was also facing the same issue with Vue.js Project --mode production
. All other modes were working fine.
externals:[
{
["@pany/library-name"]:{
root: "@pany/library-name"
}
}
]
This is basically using the object syntax from official docs.
Webpack
externals option is dependent on the externalsType one. By default, externalsType
is var
, this means that you expect this variable to exists in the global scope.
For example, if we import jQuery
in the browser through a script link:
<script src="https://code.jquery./jquery-3.7.0.slim.min.js" ...></script>
There will be a global variable in the window
object named jQuery
, so this Webpack
configuration:
externals: {
jquery: 'jQuery'
}
Is stating:
When you find an import from
jquery
remove it from the bundle and use thejQuery
global variable in its place.
If you put this configuration without externalsType
:
externals: ['@tubular/util'],
Webpack will try to replace those requires or imports by a global variable named @tubular/util
in this way:
var t=@tubular/util;
And that will throw an error for sure.
On your specific case, @tubular/util
imported through a script tag creates a tbUtil
global variable, so your configuration should be:
externals: {
'@tubular/util': 'tbUtil'
}
This error could also appear if someone is trying to pile a Node
bundle and they want to exclude some packages from the bundle that are already installed. For example, if you use this externals
configuration without specifying a proper externalsType
, you will get a similar error.
{
externals: ['@babel/core']
}
In these cases, you should specify a proper externalsType
depending on your needs (these are all the options):
{
externals: ['@babel/core'],
externalsType: 'monjs'
}
And then, Webpack
will replace
import { transform } from '@babel/core';
into something like:
var b=require("@babel/core");
var t=b.transform;
And it will not ship @babel/core
in the bundle.
I found an answer, but it's certainly not the answer I was looking for.
If I use the package webpack-node-externals
, I can externalize all node_modules
like this:
const nodeExternals = require('webpack-node-externals');
// ...
externalsPresets: { node: true },
externals: [nodeExternals()],
In this particular case excluding all node externals happens to be just fine, so webpack-node-externals
solves my immediate problem. But if I wanted to be more selective, and wanted to exclude a package with an @ in the name, I'd still have a mystery on my hands.