Async chunk loading breaks complex expressions in globalObject option
See original GitHub issueBug report
What is the current behavior?
// webpack.config.js
output: {
library: 'myLib',
libraryTarget: 'umd',
globalObject: 'typeof self !== \'undefined\' ? self : this',
},
optimization: {
splitChunks: {
chunks: 'all',
minSize: 1,
}
}
// index.js
await import('./chunk')
generates code
var chunkLoadingGlobal = typeof self !== 'undefined' ? self : this["webpackChunkmyLib"] = typeof self !== 'undefined' ? self : this["webpackChunkmyLib"] || [];
/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
The ternary expression for globalObject
isn’t protected as an expression, but gets mixed with the surrounding code.
In case the condition is true (typeof self !== 'undefined'
) and consequent path is taken, the result of this expression ends up being the equivalent of
var chunkLoadingGlobal = self
which then throws in the next line
Uncaught TypeError: chunkLoadingGlobal.forEach is not a function
Similar code also gets generated to the async chunk
typeof self !== 'undefined' ? self : this["webpackChunkmyLib"] =
which would also fail if the execution ever got that far.
If the current behavior is a bug, please provide the steps to reproduce. Full minimal reproducible example in noppa/webpack-global-object-issue-repro.
What is the expected behavior?
The code in globalObject
option should be treated as an arbitrary expression and either lifted to a variable or wrapped in parenthesis
var root = typeof self !== 'undefined' ? self : this
var chunkLoadingGlobal = root["webpackChunkmyLib"] = root["webpackChunkmyLib"] || [];
The problem is easily enough fixed on the user’s side:
- globalObject: 'typeof self !== \'undefined\' ? self : this',
+ globalObject: '(typeof self !== \'undefined\' ? self : this)',
and I get that this issue could end up closed as “working as intended”. However, I think that this limitation should then at least be mentioned in the docs and/or some kind of warning should be given. The nasty thing about the current behavior is that the code only breaks under very specific conditions:
- The app must contain async chunks. Without them,
globalObject
is only used in expression
```
})(typeof self !== 'undefined' ? self : this, function() {
```
which doesn't break the way the `chunkLoadingGlobal` code does. Simply adding `/* webpackMode: "eager" */ ` to the import will "fix" the issue.
- The condition in ternary must be true, as the RHS of the ternary actually works fine. In practice this means that the app crashes in browser (where
self
is defined) but not in Node.
Thus, the broken globalObject
code is already widely used in the wild: grep.app search for unparenthesized ternaries in globalObject option.
I believe that at least these issues could be caused by this:
- StackOverflow jsonpArray.push is undefined when the output library code splits
- Related issue in vue-cli
- #9766 not for the OP of that issue but maybe for the commenters saying that setting
jsonpFunction
didn’t fix the issue for them
Other relevant information: webpack version: 5.26.3 and 4.46.0 Node.js version: 15.6.0 Operating System: Additional tools:
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (5 by maintainers)
Top GitHub Comments
To be honestly using
()
is always good, because it is always protect your code, but yes we can fix it@alexander-akait I think better to add notes to docs.
I think from option name is expected to get an identifier or member expression at least (not conditional expression) at runtimeok, I rethink… lets fix it.