diff --git a/examples/cjs-tree-shaking/README.md b/examples/cjs-tree-shaking/README.md new file mode 100644 index 000000000..661b62185 --- /dev/null +++ b/examples/cjs-tree-shaking/README.md @@ -0,0 +1,282 @@ +# example.js + +```javascript +const inc = require("./increment").increment; +var a = 1; +inc(a); // 2 +``` + +# increment.js + +```javascript +const add = require("./math").add; +exports.increment = function increment(val) { + return add(val, 1); +}; +exports.incrementBy2 = function incrementBy2(val) { + return add(val, 2); +}; +exports.decrement = function decrement(val) { + return add(val, 1); +}; +``` + +# math.js + +```javascript +exports.add = function add() { + var sum = 0, + i = 0, + args = arguments, + l = args.length; + while (i < l) { + sum += args[i++]; + } + return sum; +}; + +exports.multiply = function multiply() { + var product = 0, + i = 0, + args = arguments, + l = args.length; + while (i < l) { + sum *= args[i++]; + } + return sum; +}; +``` + +# dist/output.js + +```javascript +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ([ +/* 0 */, +/* 1 */ +/*!**********************!*\ + !*** ./increment.js ***! + \**********************/ +/*! exports type: default defaultObject: redirect */ +/*! export decrement [provided] [unused] [renamed to C] */ +/*! export default [provided] [unused] [no name, virtual] */ +/*! export decrement [provided] [unused] [renamed to C] */ +/*! export increment [provided] [used] [renamed to pD] */ +/*! export incrementBy2 [provided] [unused] [renamed to ju] */ +/*! other exports [not provided] [unused] */ +/*! export increment [provided] [used] [renamed to pD] */ +/*! export incrementBy2 [provided] [unused] [renamed to ju] */ +/*! other exports [not provided] [unused] */ +/*! runtime requirements: __webpack_require__, __webpack_exports__ */ +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +var __webpack_unused_export__; +const add = __webpack_require__(/*! ./math */ 2)/* .add */ .K; +exports.pD = function increment(val) { + return add(val, 1); +}; +__webpack_unused_export__ = function incrementBy2(val) { + return add(val, 2); +}; +__webpack_unused_export__ = function decrement(val) { + return add(val, 1); +}; + + +/***/ }), +/* 2 */ +/*!*****************!*\ + !*** ./math.js ***! + \*****************/ +/*! exports type: default defaultObject: redirect */ +/*! export add [provided] [used] [renamed to K] */ +/*! export default [provided] [unused] [no name, virtual] */ +/*! export add [provided] [used] [renamed to K] */ +/*! export multiply [provided] [unused] [renamed to j] */ +/*! other exports [not provided] [unused] */ +/*! export multiply [provided] [unused] [renamed to j] */ +/*! other exports [not provided] [unused] */ +/*! runtime requirements: __webpack_exports__ */ +/***/ ((__unused_webpack_module, exports) => { + +var __webpack_unused_export__; +exports.K = function add() { + var sum = 0, + i = 0, + args = arguments, + l = args.length; + while (i < l) { + sum += args[i++]; + } + return sum; +}; + +__webpack_unused_export__ = function multiply() { + var product = 0, + i = 0, + args = arguments, + l = args.length; + while (i < l) { + sum *= args[i++]; + } + return sum; +}; + + +/***/ }) +/******/ ]); +``` + +
/* webpack runtime code */ + +``` js +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ if(__webpack_module_cache__[moduleId]) { +/******/ return __webpack_module_cache__[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +``` + +
+ +``` js +(() => { +/*!********************!*\ + !*** ./example.js ***! + \********************/ +/*! dynamic exports type */ +/*! exports [maybe provided (runtime-defined)] [unused] */ +/*! runtime requirements: __webpack_require__ */ +const inc = __webpack_require__(/*! ./increment */ 1)/* .increment */ .pD; +var a = 1; +inc(a); // 2 + +})(); + +/******/ })() +; +``` + +# dist/output.js (production) + +```javascript +/*! For license information please see output.js.LICENSE */ +(()=>{var r=[,(r,t,n)=>{const e=n(2).K;t.pD=function(r){return e(r,1)}},(r,t)=>{t.K=function(){for(var r=0,t=0,n=arguments,e=n.length;t{var n=[,(n,r,t)=>{const e=t(2).add;r.increment=function(n){return e(n,1)},r.incrementBy2=function(n){return e(n,2)},r.decrement=function(n){return e(n,1)}},(n,r)=>{r.add=function(){for(var n=0,r=0,t=arguments,e=t.length;r ./example.js main + ./example.js 70 bytes [built] + [no exports used] + entry ./example.js main + ./increment.js 251 bytes [built] + [exports: default, decrement, increment, incrementBy2] + [only some exports used: increment] + cjs full require ./increment ./example.js 1:12-44 + ./math.js 313 bytes [built] + [exports: default, add, multiply] + [only some exports used: add] + cjs full require ./math ./increment.js 1:12-33 +Child + Hash: 0a1b2c3d4e5f6a7b8c9d + Asset Size + without.js 3.7 KiB [emitted] [name: main] + Entrypoint main = without.js + chunk without.js (main) 634 bytes [entry] [rendered] + > ./example.js main + ./example.js 70 bytes [built] + [used exports unknown] + entry ./example.js main + ./increment.js 251 bytes [built] + [exports: default, decrement, increment, incrementBy2] + [used exports unknown] + cjs full require ./increment ./example.js 1:12-44 + ./math.js 313 bytes [built] + [exports: default, add, multiply] + [used exports unknown] + cjs full require ./math ./increment.js 1:12-33 +``` + +## Production mode + +``` +Hash: 0a1b2c3d4e5f6a7b8c9d +Version: webpack 5.0.0-beta.7 +Child + Hash: 0a1b2c3d4e5f6a7b8c9d + Asset Size + output.js 348 bytes [emitted] [name: main] + output.js.LICENSE 1.16 KiB [emitted] + Entrypoint main = output.js + chunk output.js (main) 634 bytes [entry] [rendered] + > ./example.js main + ./example.js 70 bytes [built] + [no exports used] + entry ./example.js main + ./increment.js 251 bytes [built] + [exports: default, decrement, increment, incrementBy2] + [only some exports used: increment] + cjs full require ./increment ./example.js 1:12-44 + ./math.js 313 bytes [built] + [exports: default, add, multiply] + [only some exports used: add] + cjs full require ./math ./increment.js 1:12-33 +Child + Hash: 0a1b2c3d4e5f6a7b8c9d + Asset Size + without.js 534 bytes [emitted] [name: main] + without.js.LICENSE 1.49 KiB [emitted] + Entrypoint main = without.js + chunk without.js (main) 634 bytes [entry] [rendered] + > ./example.js main + ./example.js 70 bytes [built] + [used exports unknown] + entry ./example.js main + ./increment.js 251 bytes [built] + [exports: default, decrement, increment, incrementBy2] + [used exports unknown] + cjs full require ./increment ./example.js 1:12-44 + ./math.js 313 bytes [built] + [exports: default, add, multiply] + [used exports unknown] + cjs full require ./math ./increment.js 1:12-33 +``` diff --git a/examples/cjs-tree-shaking/build.js b/examples/cjs-tree-shaking/build.js new file mode 100644 index 000000000..7492e9f9f --- /dev/null +++ b/examples/cjs-tree-shaking/build.js @@ -0,0 +1,2 @@ +global.NO_TARGET_ARGS = true; +require("../build-common"); diff --git a/examples/cjs-tree-shaking/cases.txt b/examples/cjs-tree-shaking/cases.txt new file mode 100644 index 000000000..34bc275e0 --- /dev/null +++ b/examples/cjs-tree-shaking/cases.txt @@ -0,0 +1,58 @@ +BAD: + +module.exports = abc; module.exports.xxx = abc; abc.xxx; +exports = abc; +module.exports +exports +this +function f() { return this; } module.exports = { f }; module.exports.xxx = abc; + + +EXPORTS: + +exports.xxx = abc; + +module.exports.xxx = abc; +this.xxx = abc +Object.defineProperty(exports, "xxx", { ... }) +Object.defineProperty(module.exports, "xxx", { ... }) +Object.defineProperty(this, "xxx", { ... }) +module.exports.xxx +exports.xxx +this.xxx +module.exports = function() {}; module.exports.xxx = abc; +module.exports = { ... }; module.exports.xxx = abc; + +OBJECTS: + +module.exports = { xxx: abc }; + +IMPORT: + +require(x).xxx +var { xxx } = require(x); +var x = require(x); x.xxx; + +REEXPORT: + +module.exports.xxx = require(x); +module.exports.xxx = require(x).xxx; +exports.xxx = require(x); +exports.xxx = require(x).xxx; +module.exports = { xxx2: require(x) }; +module.exports = { xxx2: require(x).xxx }; +var xxx = require(x); exports.xxx = xxx; +var xxx = require(x); exports.xxx = xxx.xxx; +var xxx = require(x); module.exports = { xxx }; +var xxx = require(x); module.exports = { xxx: xxx.xxx }; + +TRANSPILED: + +TypeScript: +function __export(m) { for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; } +__export(require(x)); + +Babel: +var xxx = _interopRequireDefault(require(x)); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +xxx.xxx; diff --git a/examples/cjs-tree-shaking/example.js b/examples/cjs-tree-shaking/example.js new file mode 100644 index 000000000..824a4d22b --- /dev/null +++ b/examples/cjs-tree-shaking/example.js @@ -0,0 +1,3 @@ +const inc = require("./increment").increment; +var a = 1; +inc(a); // 2 diff --git a/examples/cjs-tree-shaking/increment.js b/examples/cjs-tree-shaking/increment.js new file mode 100644 index 000000000..df54369b9 --- /dev/null +++ b/examples/cjs-tree-shaking/increment.js @@ -0,0 +1,10 @@ +const add = require("./math").add; +exports.increment = function increment(val) { + return add(val, 1); +}; +exports.incrementBy2 = function incrementBy2(val) { + return add(val, 2); +}; +exports.decrement = function decrement(val) { + return add(val, 1); +}; diff --git a/examples/cjs-tree-shaking/math.js b/examples/cjs-tree-shaking/math.js new file mode 100644 index 000000000..97a0ac866 --- /dev/null +++ b/examples/cjs-tree-shaking/math.js @@ -0,0 +1,21 @@ +exports.add = function add() { + var sum = 0, + i = 0, + args = arguments, + l = args.length; + while (i < l) { + sum += args[i++]; + } + return sum; +}; + +exports.multiply = function multiply() { + var product = 0, + i = 0, + args = arguments, + l = args.length; + while (i < l) { + sum *= args[i++]; + } + return sum; +}; diff --git a/examples/cjs-tree-shaking/template.md b/examples/cjs-tree-shaking/template.md new file mode 100644 index 000000000..68a8221b9 --- /dev/null +++ b/examples/cjs-tree-shaking/template.md @@ -0,0 +1,49 @@ +# example.js + +```javascript +_{{example.js}}_ +``` + +# increment.js + +```javascript +_{{increment.js}}_ +``` + +# math.js + +```javascript +_{{math.js}}_ +``` + +# dist/output.js + +```javascript +_{{dist/output.js}}_ +``` + +# dist/output.js (production) + +```javascript +_{{production:dist/output.js}}_ +``` + +# dist/without.js (same without tree shaking) + +```javascript +_{{production:dist/without.js}}_ +``` + +# Info + +## Unoptimized + +``` +_{{stdout}}_ +``` + +## Production mode + +``` +_{{production:stdout}}_ +``` diff --git a/examples/cjs-tree-shaking/webpack.config.js b/examples/cjs-tree-shaking/webpack.config.js new file mode 100644 index 000000000..b40c7be44 --- /dev/null +++ b/examples/cjs-tree-shaking/webpack.config.js @@ -0,0 +1,26 @@ +module.exports = [ + { + entry: "./example.js", + output: { + pathinfo: true, + filename: "output.js" + }, + optimization: { + moduleIds: "size", + usedExports: true, + mangleExports: true + } + }, + { + entry: "./example.js", + output: { + pathinfo: true, + filename: "without.js" + }, + optimization: { + moduleIds: "size", + usedExports: false, + mangleExports: false + } + } +]; diff --git a/lib/CommonJsStuffPlugin.js b/lib/CommonJsStuffPlugin.js deleted file mode 100644 index b1601cc79..000000000 --- a/lib/CommonJsStuffPlugin.js +++ /dev/null @@ -1,260 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ - -"use strict"; - -const RuntimeGlobals = require("./RuntimeGlobals"); -const RuntimeModule = require("./RuntimeModule"); -const Template = require("./Template"); -const ModuleDecoratorDependency = require("./dependencies/ModuleDecoratorDependency"); -const RuntimeRequirementsDependency = require("./dependencies/RuntimeRequirementsDependency"); -const { - evaluateToIdentifier, - expressionIsUnsupported, - toConstantDependency -} = require("./javascript/JavascriptParserHelpers"); - -class CommonJsStuffPlugin { - apply(compiler) { - compiler.hooks.compilation.tap( - "CommonJsStuffPlugin", - (compilation, { normalModuleFactory }) => { - compilation.dependencyFactories.set( - ModuleDecoratorDependency, - normalModuleFactory - ); - compilation.dependencyTemplates.set( - ModuleDecoratorDependency, - new ModuleDecoratorDependency.Template() - ); - - compilation.hooks.runtimeRequirementInModule - .for(RuntimeGlobals.harmonyModuleDecorator) - .tap("CommonJsStuffPlugin", (module, set) => { - set.add(RuntimeGlobals.module); - set.add(RuntimeGlobals.requireScope); - }); - - compilation.hooks.runtimeRequirementInModule - .for(RuntimeGlobals.nodeModuleDecorator) - .tap("CommonJsStuffPlugin", (module, set) => { - set.add(RuntimeGlobals.module); - set.add(RuntimeGlobals.requireScope); - }); - - compilation.hooks.runtimeRequirementInTree - .for(RuntimeGlobals.harmonyModuleDecorator) - .tap("CommonJsStuffPlugin", (chunk, set) => { - compilation.addRuntimeModule( - chunk, - new HarmonyModuleDecoratorRuntimeModule() - ); - }); - - compilation.hooks.runtimeRequirementInTree - .for(RuntimeGlobals.nodeModuleDecorator) - .tap("CommonJsStuffPlugin", (chunk, set) => { - compilation.addRuntimeModule( - chunk, - new NodeModuleDecoratorRuntimeModule() - ); - }); - - const handler = (parser, parserOptions) => { - parser.hooks.expression - .for("require.main.require") - .tap( - "CommonJsStuffPlugin", - expressionIsUnsupported( - parser, - "require.main.require is not supported by webpack." - ) - ); - parser.hooks.expression - .for("module.parent.require") - .tap( - "CommonJsStuffPlugin", - expressionIsUnsupported( - parser, - "module.parent.require is not supported by webpack." - ) - ); - parser.hooks.expression - .for("require.main") - .tap( - "CommonJsStuffPlugin", - toConstantDependency( - parser, - `${RuntimeGlobals.moduleCache}[${RuntimeGlobals.entryModuleId}]`, - [RuntimeGlobals.moduleCache, RuntimeGlobals.entryModuleId] - ) - ); - parser.hooks.expression - .for("module.loaded") - .tap("CommonJsStuffPlugin", expr => { - parser.state.module.buildMeta.moduleConcatenationBailout = - "module.loaded"; - return toConstantDependency( - parser, - `${RuntimeGlobals.module}.l`, - [RuntimeGlobals.module] - )(expr); - }); - parser.hooks.expression - .for("module.id") - .tap("CommonJsStuffPlugin", expr => { - parser.state.module.buildMeta.moduleConcatenationBailout = - "module.id"; - return toConstantDependency( - parser, - `${RuntimeGlobals.module}.i`, - [RuntimeGlobals.module] - )(expr); - }); - parser.hooks.expression - .for("module.exports") - .tap("CommonJsStuffPlugin", expr => { - const module = parser.state.module; - const isHarmony = - module.buildMeta && module.buildMeta.exportsType; - if (!isHarmony) { - if (module.moduleArgument === "module") { - // avoid rewriting module.exports for backward-compat - const dep = new RuntimeRequirementsDependency([ - RuntimeGlobals.module - ]); - dep.loc = expr.loc; - module.addPresentationalDependency(dep); - return true; - } - return toConstantDependency( - parser, - `${module.moduleArgument}.exports`, - [RuntimeGlobals.module] - )(expr); - } - }); - parser.hooks.expression - .for("this") - .tap("CommonJsStuffPlugin", expr => { - if (!parser.scope.topLevelScope) return; - const module = parser.state.module; - const isHarmony = - module.buildMeta && module.buildMeta.exportsType; - if (!isHarmony) { - return toConstantDependency(parser, "this", [ - RuntimeGlobals.thisAsExports - ])(expr); - } - }); - parser.hooks.evaluateIdentifier.for("module.hot").tap( - "CommonJsStuffPlugin", - evaluateToIdentifier("module.hot", "module", () => ["hot"], false) - ); - parser.hooks.expression - .for("module") - .tap("CommonJsStuffPlugin", expr => { - const isHarmony = - parser.state.module.buildMeta && - parser.state.module.buildMeta.exportsType; - const dep = new ModuleDecoratorDependency( - isHarmony - ? RuntimeGlobals.harmonyModuleDecorator - : RuntimeGlobals.nodeModuleDecorator - ); - dep.loc = expr.loc; - parser.state.module.addPresentationalDependency(dep); - return true; - }); - }; - - normalModuleFactory.hooks.parser - .for("javascript/auto") - .tap("CommonJsStuffPlugin", handler); - normalModuleFactory.hooks.parser - .for("javascript/dynamic") - .tap("CommonJsStuffPlugin", handler); - } - ); - } -} - -class HarmonyModuleDecoratorRuntimeModule extends RuntimeModule { - constructor() { - super("harmony module decorator"); - } - - /** - * @returns {string} runtime code - */ - generate() { - const { runtimeTemplate } = this.compilation; - return Template.asString([ - `${ - RuntimeGlobals.harmonyModuleDecorator - } = ${runtimeTemplate.basicFunction("module", [ - "module = Object.create(module);", - "if (!module.children) module.children = [];", - "Object.defineProperty(module, 'loaded', {", - Template.indent([ - "enumerable: true,", - `get: ${runtimeTemplate.returningFunction("module.l")}` - ]), - "});", - "Object.defineProperty(module, 'id', {", - Template.indent([ - "enumerable: true,", - `get: ${runtimeTemplate.returningFunction("module.i")}` - ]), - "});", - "Object.defineProperty(module, 'exports', {", - Template.indent([ - "enumerable: true,", - `set: ${runtimeTemplate.basicFunction("", [ - "throw new Error('ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: ' + module.id);" - ])}` - ]), - "});", - "return module;" - ])};` - ]); - } -} - -class NodeModuleDecoratorRuntimeModule extends RuntimeModule { - constructor() { - super("node module decorator"); - } - - /** - * @returns {string} runtime code - */ - generate() { - const { runtimeTemplate } = this.compilation; - return Template.asString([ - `${ - RuntimeGlobals.nodeModuleDecorator - } = ${runtimeTemplate.basicFunction("module", [ - "module.paths = [];", - "if (!module.children) module.children = [];", - "Object.defineProperty(module, 'loaded', {", - Template.indent([ - "enumerable: true,", - `get: ${runtimeTemplate.returningFunction("module.l")}` - ]), - "});", - "Object.defineProperty(module, 'id', {", - Template.indent([ - "enumerable: true,", - `get: ${runtimeTemplate.returningFunction("module.i")}` - ]), - "});", - "return module;" - ])};` - ]); - } -} - -module.exports = CommonJsStuffPlugin; diff --git a/lib/ContextModule.js b/lib/ContextModule.js index e517edc08..7ba242c82 100644 --- a/lib/ContextModule.js +++ b/lib/ContextModule.js @@ -462,13 +462,12 @@ class ContextModule extends Module { return 9; } const moduleGraph = chunkGraph.moduleGraph; + // bitfield + let hasType = 0; + const comparator = compareModulesById(chunkGraph); // if we filter first we get a new array // therefor we dont need to create a clone of dependencies explicitly // therefore the order of this is !important! - let hasNonHarmony = false; - let hasNamespace = false; - let hasNamed = false; - const comparator = compareModulesById(chunkGraph); const fakeMap = dependencies .map(dependency => ({ module: moduleGraph.getModule(dependency), @@ -477,30 +476,46 @@ class ContextModule extends Module { .filter(item => item.module) .sort((a, b) => comparator(a.module, b.module)) .reduce((map, { dependency: dep, module }) => { - const exportsType = module.buildMeta && module.buildMeta.exportsType; + const exportsType = module.getExportsType( + this.options.namespaceObject === "strict" + ); const id = chunkGraph.getModuleId(module); - if (!exportsType) { - map[id] = this.options.namespaceObject === "strict" ? 1 : 7; - hasNonHarmony = true; - } else if (exportsType === "namespace") { - map[id] = 9; - hasNamespace = true; - } else if (exportsType === "default") { - map[id] = this.options.namespaceObject === "strict" ? 1 : 3; - hasNamed = true; + switch (exportsType) { + case "namespace": + map[id] = 9; + hasType |= 1; + break; + case "dynamic": + map[id] = 7; + hasType |= 2; + break; + case "dynamic-default": + case "default-only": + map[id] = 1; + hasType |= 4; + break; + case "default-with-named": + map[id] = 3; + hasType |= 8; + break; + default: + throw new Error(`Unexpected exports type ${exportsType}`); } return map; }, Object.create(null)); - if (!hasNamespace && hasNonHarmony && !hasNamed) { - return this.options.namespaceObject === "strict" ? 1 : 7; - } - if (hasNamespace && !hasNonHarmony && !hasNamed) { + if (hasType === 1) { return 9; } - if (!hasNamespace && !hasNonHarmony && hasNamed) { - return this.options.namespaceObject === "strict" ? 1 : 3; + if (hasType === 2) { + return 7; } - if (!hasNamespace && !hasNonHarmony && !hasNamed) { + if (hasType === 4) { + return 1; + } + if (hasType === 8) { + return 3; + } + if (hasType === 0) { return 9; } return fakeMap; diff --git a/lib/Module.js b/lib/Module.js index f7e5947c6..cd7a15bae 100644 --- a/lib/Module.js +++ b/lib/Module.js @@ -65,7 +65,8 @@ const makeSerializable = require("./util/makeSerializable"); * @property {string=} exportsArgument * @property {boolean=} strict * @property {string=} moduleConcatenationBailout - * @property {("default" | "namespace")=} exportsType + * @property {("default" | "namespace" | "flagged")=} exportsType + * @property {(boolean | "redirect" | "redirect-warn")=} defaultObject * @property {boolean=} strictHarmonyModule * @property {boolean=} async */ @@ -364,6 +365,29 @@ class Module extends DependenciesBlock { return (this.buildInfo && this.buildInfo.moduleArgument) || "module"; } + /** + * @param {boolean} strict the importing module is strict + * @returns {"dynamic" | "dynamic-default" | "namespace" | "default-only" | "default-with-named"} export type + */ + getExportsType(strict) { + switch (this.buildMeta && this.buildMeta.exportsType) { + case "flagged": + return strict ? "dynamic-default" : "namespace"; + case "namespace": + return "namespace"; + case "default": + switch (this.buildMeta.defaultObject) { + case "redirect": + case "redirect-warn": + return strict ? "default-only" : "default-with-named"; + default: + return "default-only"; + } + default: + return strict ? "dynamic-default" : "dynamic"; + } + } + /** * @param {Dependency} presentationalDependency dependency being tied to module. * This is a Dependency without edge in the module graph. It's only for presentation. @@ -602,7 +626,11 @@ class Module extends DependenciesBlock { for (const exportInfo of exportsInfo.orderedExports) { hash.update(exportInfo.name); hash.update(exportInfo.used + ""); - hash.update(exportInfo.usedName + ""); + hash.update( + exportInfo.usedName === ModuleGraph.SKIP_OVER_NAME + ? "" + : exportInfo.usedName + "" + ); } if (this.presentationalDependencies !== undefined) { for (const dep of this.presentationalDependencies) { diff --git a/lib/ModuleGraph.js b/lib/ModuleGraph.js index 2ca028d47..0495dfb1f 100644 --- a/lib/ModuleGraph.js +++ b/lib/ModuleGraph.js @@ -24,6 +24,8 @@ const makeSerializable = require("./util/makeSerializable"); const EMPTY_ARRAY = []; +const SKIP_OVER_NAME = Symbol("skip over name"); + /** @typedef {0|1|2|3|4} UsageStateType */ const UsageState = Object.freeze({ @@ -130,12 +132,8 @@ class ExportsInfo { this._exportsAreOrdered = true; } - setRedirectToDefaultObject() { - const defaultInfo = this.getExportInfo("default"); - defaultInfo.canMangleProvide = false; - defaultInfo.usedName = ""; - const inner = defaultInfo.createNestedExportsInfo(); - this._redirectTo = inner; + setRedirectNamedTo(exportsInfo) { + this._redirectTo = exportsInfo; } setHasProvideInfo() { @@ -190,8 +188,6 @@ class ExportsInfo { const info = this._exports.get(name); if (info !== undefined) return info; if (this._redirectTo) return this._redirectTo.getExportInfo(name); - if (!name) - throw new Error("ModuleGraph.getExportInfo name must be a valid string"); const newInfo = new ExportInfo(name, this._otherExportsInfo); this._exports.set(name, newInfo); this._exportsAreOrdered = false; @@ -456,11 +452,16 @@ class ExportsInfo { let info = this.getReadOnlyExportInfo(name[0]); const x = info.getUsedName(name[0]); if (x === false) return false; - const arr = x === name[0] && name.length === 1 ? name : x ? [x] : []; + const arr = + x === name[0] && name.length === 1 + ? name + : x !== SKIP_OVER_NAME + ? [x] + : EMPTY_ARRAY; if (name.length === 1) { return arr; } - if (info.exportsInfo) { + if (info.exportsInfo && info.used === UsageState.OnlyPropertiesUsed) { const nested = info.exportsInfo.getUsedName(name.slice(1)); if (!nested) return false; return arr.concat(nested); @@ -527,7 +528,7 @@ class ExportInfo { constructor(name, initFrom) { /** @type {string} */ this.name = name; - /** @type {string | null} */ + /** @type {string | null | SKIP_OVER_NAME} */ this.usedName = initFrom ? initFrom.usedName : null; /** @type {UsageStateType} */ this.used = initFrom ? initFrom.used : UsageState.NoInfo; @@ -628,7 +629,9 @@ class ExportInfo { getRenameInfo() { if (this.usedName !== null && this.usedName !== this.name) { - return this.usedName ? `renamed to ${this.usedName}` : "no name, virtual"; + return this.usedName !== SKIP_OVER_NAME + ? `renamed to ${JSON.stringify(this.usedName).slice(1, -1)}` + : "no name, virtual"; } switch (this.canMangleProvide) { case undefined: @@ -958,7 +961,20 @@ class ModuleGraph { */ finishModule(module) { if (module.buildMeta.exportsType === "default") { - this.getExportsInfo(module).setRedirectToDefaultObject(); + const exportsInfo = this.getExportsInfo(module); + const defaultInfo = exportsInfo.getExportInfo("default"); + defaultInfo.canMangleProvide = false; + defaultInfo.provided = true; + defaultInfo.usedName = SKIP_OVER_NAME; + if (module.buildMeta.defaultObject) { + const innerObject = defaultInfo.createNestedExportsInfo(); + if ( + module.buildMeta.defaultObject === "redirect" || + module.buildMeta.defaultObject === "redirect-warn" + ) { + exportsInfo.setRedirectNamedTo(innerObject); + } + } } } @@ -1322,4 +1338,5 @@ module.exports = ModuleGraph; module.exports.ModuleGraphConnection = ModuleGraphConnection; module.exports.ExportsInfo = ExportsInfo; module.exports.ExportInfo = ExportInfo; +module.exports.SKIP_OVER_NAME = SKIP_OVER_NAME; module.exports.UsageState = UsageState; diff --git a/lib/ModuleInfoHeaderPlugin.js b/lib/ModuleInfoHeaderPlugin.js index d9974518e..1cef3d88a 100644 --- a/lib/ModuleInfoHeaderPlugin.js +++ b/lib/ModuleInfoHeaderPlugin.js @@ -33,9 +33,10 @@ const printExportsInfoToSource = (source, indent, exportsInfo) => { for (const exportInfo of exportsInfo.orderedExports) { source.add( Template.toComment( - `${indent}export ${ - exportInfo.name - } [${exportInfo.getProvidedInfo()}] [${exportInfo.getUsedInfo()}] [${exportInfo.getRenameInfo()}]` + `${indent}export ${JSON.stringify(exportInfo.name).slice( + 1, + -1 + )} [${exportInfo.getProvidedInfo()}] [${exportInfo.getUsedInfo()}] [${exportInfo.getRenameInfo()}]` ) + "\n" ); if (exportInfo.exportsInfo) { @@ -79,6 +80,14 @@ class ModuleInfoHeaderPlugin { source.add("/*!****" + reqStrStar + "****!*\\\n"); source.add(" !*** " + reqStr + " ***!\n"); source.add(" \\****" + reqStrStar + "****/\n"); + const exportsType = module.buildMeta.exportsType; + source.add( + Template.toComment( + exportsType + ? `${exportsType} exports` + : "unknown exports (runtime-defined)" + ) + "\n" + ); const exportsInfo = moduleGraph.getExportsInfo(module); printExportsInfoToSource(source, "", exportsInfo); source.add( diff --git a/lib/Parser.js b/lib/Parser.js index fe59f70e2..5ec26adcc 100644 --- a/lib/Parser.js +++ b/lib/Parser.js @@ -13,13 +13,15 @@ const AbstractMethodError = require("./AbstractMethodError"); /** @typedef {Record} PreparsedAst */ /** - * @typedef {Object} ParserState + * @typedef {Object} ParserStateBase * @property {NormalModule} current * @property {NormalModule} module * @property {Compilation} compilation * @property {TODO} options */ +/** @typedef {Record & ParserStateBase} ParserState */ + class Parser { /** * @param {string | Buffer | PreparsedAst} source the source to parse diff --git a/lib/RuntimeGlobals.js b/lib/RuntimeGlobals.js index d5783ca6a..3efdb8009 100644 --- a/lib/RuntimeGlobals.js +++ b/lib/RuntimeGlobals.js @@ -35,6 +35,16 @@ exports.returnExportsFromRuntime = "return-exports-from-runtime"; */ exports.module = "module"; +/** + * the internal module object + */ +exports.moduleId = "module.id"; + +/** + * the internal module object + */ +exports.moduleLoaded = "module.loaded"; + /** * the bundle public path */ diff --git a/lib/RuntimePlugin.js b/lib/RuntimePlugin.js index ce9243d31..5417b3a2b 100644 --- a/lib/RuntimePlugin.js +++ b/lib/RuntimePlugin.js @@ -45,6 +45,11 @@ const GLOBALS_ON_REQUIRE = [ RuntimeGlobals.instantiateWasm ]; +const MODULE_DEPENDENCIES = { + [RuntimeGlobals.moduleLoaded]: [RuntimeGlobals.module], + [RuntimeGlobals.moduleId]: [RuntimeGlobals.module] +}; + const TREE_DEPENDENCIES = { [RuntimeGlobals.definePropertyGetters]: [RuntimeGlobals.hasOwnProperty], [RuntimeGlobals.compatGetDefaultExport]: [ @@ -88,6 +93,14 @@ class RuntimePlugin { for (const dep of deps) set.add(dep); }); } + for (const req of Object.keys(MODULE_DEPENDENCIES)) { + const deps = MODULE_DEPENDENCIES[req]; + compilation.hooks.runtimeRequirementInModule + .for(req) + .tap("RuntimePlugin", (chunk, set) => { + for (const dep of deps) set.add(dep); + }); + } compilation.hooks.runtimeRequirementInTree .for(RuntimeGlobals.definePropertyGetters) .tap("RuntimePlugin", chunk => { diff --git a/lib/RuntimeTemplate.js b/lib/RuntimeTemplate.js index 69a735280..6f9cd32e5 100644 --- a/lib/RuntimeTemplate.js +++ b/lib/RuntimeTemplate.js @@ -326,25 +326,26 @@ class RuntimeTemplate { request, weak }); - const exportsType = module.buildMeta && module.buildMeta.exportsType; - if (exportsType === "namespace") { - const rawModule = this.moduleRaw({ - module, - chunkGraph, - request, - weak, - runtimeRequirements - }); - return rawModule; - } else if (strict) { - runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); - return `${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 1)`; - } else if (exportsType === "default") { - runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); - return `${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 3)`; - } else { - runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); - return `${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 7)`; + const exportsType = module.getExportsType(strict); + switch (exportsType) { + case "namespace": + return this.moduleRaw({ + module, + chunkGraph, + request, + weak, + runtimeRequirements + }); + case "default-with-named": + runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); + return `${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 3)`; + case "default-only": + case "dynamic-default": + runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); + return `${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 1)`; + case "dynamic": + runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); + return `${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 7)`; } } @@ -427,54 +428,46 @@ class RuntimeTemplate { request, weak }); - const exportsType = module.buildMeta && module.buildMeta.exportsType; - if (exportsType === "namespace") { - if (header) { - const rawModule = this.moduleRaw({ - module, - chunkGraph, - request, - weak, - runtimeRequirements - }); - getModuleFunction = this.basicFunction( - "", - `${header}return ${rawModule};` - ); - } else { - runtimeRequirements.add(RuntimeGlobals.require); - getModuleFunction = `__webpack_require__.bind(null, ${comment}${idExpr})`; - } - } else if (strict) { - runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); - if (header) { - const returnExpression = `${RuntimeGlobals.createFakeNamespaceObject}(${moduleIdExpr}, 1)`; - getModuleFunction = header - ? this.basicFunction("", `${header}return ${returnExpression};`) - : this.returningFunction(returnExpression); - } else { - getModuleFunction = `${RuntimeGlobals.createFakeNamespaceObject}.bind(__webpack_require__, ${comment}${idExpr}, 1)`; - } - } else if (exportsType === "default") { - runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); - if (header) { - const returnExpression = `${RuntimeGlobals.createFakeNamespaceObject}(${moduleIdExpr}, 3)`; - getModuleFunction = header - ? this.basicFunction("", `${header}return ${returnExpression};`) - : this.returningFunction(returnExpression); - } else { - getModuleFunction = `${RuntimeGlobals.createFakeNamespaceObject}.bind(__webpack_require__, ${comment}${idExpr}, 3)`; - } - } else { - runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); - if (header) { - const returnExpression = `${RuntimeGlobals.createFakeNamespaceObject}(${moduleIdExpr}, 7)`; - getModuleFunction = header - ? this.basicFunction("", `${header}return ${returnExpression};`) - : this.returningFunction(returnExpression); - } else { - getModuleFunction = `${RuntimeGlobals.createFakeNamespaceObject}.bind(__webpack_require__, ${comment}${idExpr}, 7)`; - } + const exportsType = module.getExportsType(strict); + let fakeType = 0; + switch (exportsType) { + case "namespace": + if (header) { + const rawModule = this.moduleRaw({ + module, + chunkGraph, + request, + weak, + runtimeRequirements + }); + getModuleFunction = this.basicFunction( + "", + `${header}return ${rawModule};` + ); + } else { + runtimeRequirements.add(RuntimeGlobals.require); + getModuleFunction = `__webpack_require__.bind(__webpack_require__, ${comment}${idExpr})`; + } + break; + case "dynamic": + fakeType |= 7; + /* fall through */ + case "default-with-named": + fakeType |= 3; + /* fall through */ + case "default-only": + case "dynamic-default": + fakeType |= 1; + runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); + if (header) { + const returnExpression = `${RuntimeGlobals.createFakeNamespaceObject}(${moduleIdExpr}, ${fakeType})`; + getModuleFunction = header + ? this.basicFunction("", `${header}return ${returnExpression};`) + : this.returningFunction(returnExpression); + } else { + getModuleFunction = `${RuntimeGlobals.createFakeNamespaceObject}.bind(__webpack_require__, ${comment}${idExpr}, ${fakeType})`; + } + break; } return `${promise || "Promise.resolve()"}.then(${getModuleFunction})`; @@ -552,6 +545,7 @@ class RuntimeTemplate { * @param {boolean} options.asiSafe true, if location is safe for ASI, a bracket can be emitted * @param {boolean} options.isCall true, if expression will be called * @param {boolean} options.callContext when false, call context will not be preserved + * @param {boolean} options.defaultInterop when true and accessing the default exports, interop code will be generated * @param {string} options.importVar the identifier name of the import variable * @param {InitFragment[]} options.initFragments init fragments will be added here * @param {Set} options.runtimeRequirements if set, will be filled with runtime requirements @@ -566,6 +560,7 @@ class RuntimeTemplate { asiSafe, isCall, callContext, + defaultInterop, importVar, initFragments, runtimeRequirements @@ -580,26 +575,43 @@ class RuntimeTemplate { } const exportsType = module.buildMeta && module.buildMeta.exportsType; - if (!exportsType) { - if (exportName.length > 0 && exportName[0] === "default") { - if (!originModule.buildMeta.strictHarmonyModule) { - if (isCall) { - return `${importVar}_default()${propertyAccess(exportName, 1)}`; - } else if (asiSafe) { - return `(${importVar}_default()${propertyAccess(exportName, 1)})`; + if (defaultInterop) { + if (!exportsType) { + if (exportName.length > 0 && exportName[0] === "default") { + if (!originModule.buildMeta.strictHarmonyModule) { + if (isCall) { + return `${importVar}_default()${propertyAccess(exportName, 1)}`; + } else if (asiSafe) { + return `(${importVar}_default()${propertyAccess(exportName, 1)})`; + } else { + return `${importVar}_default.a${propertyAccess(exportName, 1)}`; + } } else { - return `${importVar}_default.a${propertyAccess(exportName, 1)}`; + return `${importVar}${propertyAccess(exportName, 1)}`; + } + } else if (originModule.buildMeta.strictHarmonyModule) { + if (exportName.length > 0) { + return ( + "/* non-default import from non-esm module */undefined" + + propertyAccess(exportName, 1) + ); + } else { + runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); + initFragments.push( + new InitFragment( + `var ${importVar}_namespace_cache;\n`, + InitFragment.STAGE_CONSTANTS, + -1, + `${importVar}_namespace_cache` + ) + ); + return `/*#__PURE__*/ (${importVar}_namespace_cache || (${importVar}_namespace_cache = ${RuntimeGlobals.createFakeNamespaceObject}(${importVar})))`; } - } else { - return `${importVar}${propertyAccess(exportName, 1)}`; } - } else if (originModule.buildMeta.strictHarmonyModule) { - if (exportName.length > 0) { - return ( - "/* non-default import from non-esm module */undefined" + - propertyAccess(exportName, 1) - ); - } else { + } + + if (exportsType === "default") { + if (exportName.length === 0) { runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); initFragments.push( new InitFragment( @@ -609,30 +621,20 @@ class RuntimeTemplate { `${importVar}_namespace_cache` ) ); - return `/*#__PURE__*/ (${importVar}_namespace_cache || (${importVar}_namespace_cache = ${RuntimeGlobals.createFakeNamespaceObject}(${importVar})))`; + const content = `${importVar}_namespace_cache || (${importVar}_namespace_cache = ${ + RuntimeGlobals.createFakeNamespaceObject + }(${importVar}, ${ + originModule.buildMeta.strictHarmonyModule ? 0 : 2 + }))`; + if (asiSafe) { + return `/*#__PURE__*/ (${content})`; + } else { + return `/*#__PURE__*/ Object(${content})`; + } } } } - if (exportsType === "default") { - if (exportName.length === 0) { - runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); - initFragments.push( - new InitFragment( - `var ${importVar}_namespace_cache;\n`, - InitFragment.STAGE_CONSTANTS, - -1, - `${importVar}_namespace_cache` - ) - ); - return `/*#__PURE__*/ (${importVar}_namespace_cache || (${importVar}_namespace_cache = ${ - RuntimeGlobals.createFakeNamespaceObject - }(${importVar}, ${ - originModule.buildMeta.strictHarmonyModule ? 0 : 2 - })))`; - } - } - if (exportName.length > 0) { const exportsInfo = moduleGraph.getExportsInfo(module); const used = exportsInfo.getUsedName(exportName); diff --git a/lib/SelfModuleFactory.js b/lib/SelfModuleFactory.js new file mode 100644 index 000000000..b2430a440 --- /dev/null +++ b/lib/SelfModuleFactory.js @@ -0,0 +1,21 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +class SelfModuleFactory { + constructor(moduleGraph) { + this.moduleGraph = moduleGraph; + } + + create(data, callback) { + const module = this.moduleGraph.getParentModule(data.dependencies[0]); + callback(null, { + module + }); + } +} + +module.exports = SelfModuleFactory; diff --git a/lib/Template.js b/lib/Template.js index 44f274dba..a3ea7a28d 100644 --- a/lib/Template.js +++ b/lib/Template.js @@ -27,6 +27,9 @@ const { compareIds } = require("./util/comparators"); const START_LOWERCASE_ALPHABET_CODE = "a".charCodeAt(0); const START_UPPERCASE_ALPHABET_CODE = "A".charCodeAt(0); const DELTA_A_TO_Z = "z".charCodeAt(0) - START_LOWERCASE_ALPHABET_CODE + 1; +const NUMBER_OF_IDENTIFIER_START_CHARS = DELTA_A_TO_Z * 2 + 2; // a-z A-Z _ $ +const NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS = + NUMBER_OF_IDENTIFIER_START_CHARS + 10; // a-z A-Z _ $ 0-9 const FUNCTION_CONTENT_REGEX = /^function\s?\(\)\s?\{\r?\n?|\r?\n?\}$/g; const INDENT_MULTILINE_REGEX = /^\t/gm; const LINE_SEPARATOR_REGEX = /\r?\n/g; @@ -124,30 +127,73 @@ class Template { .replace(MATCH_PADDED_HYPHENS_REPLACE_REGEX, ""); } - // map number to a single character a-z, A-Z or <_ + number> if number is too big + // map number to a single character a-z, A-Z or mulitple characters if number is too big /** - * * @param {number} n number to convert to ident * @returns {string} returns single character ident */ static numberToIdentifier(n) { + if (n >= NUMBER_OF_IDENTIFIER_START_CHARS) { + // use multiple letters + return ( + Template.numberToIdentifier(n % NUMBER_OF_IDENTIFIER_START_CHARS) + + Template.numberToIdentifierContinuation( + Math.floor(n / NUMBER_OF_IDENTIFIER_START_CHARS) + ) + ); + } + // lower case if (n < DELTA_A_TO_Z) { return String.fromCharCode(START_LOWERCASE_ALPHABET_CODE + n); } + n -= DELTA_A_TO_Z; // upper case - if (n < DELTA_A_TO_Z * 2) { - return String.fromCharCode( - START_UPPERCASE_ALPHABET_CODE + n - DELTA_A_TO_Z + if (n < DELTA_A_TO_Z) { + return String.fromCharCode(START_UPPERCASE_ALPHABET_CODE + n); + } + + if (n === DELTA_A_TO_Z) return "_"; + return "$"; + } + + /** + * @param {number} n number to convert to ident + * @returns {string} returns single character ident + */ + static numberToIdentifierContinuation(n) { + if (n >= NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS) { + // use multiple letters + return ( + Template.numberToIdentifierContinuation( + n % NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS + ) + + Template.numberToIdentifierContinuation( + Math.floor(n / NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS) + ) ); } - // use multiple letters - return ( - Template.numberToIdentifier(n % (2 * DELTA_A_TO_Z)) + - Template.numberToIdentifier(Math.floor(n / (2 * DELTA_A_TO_Z))) - ); + // lower case + if (n < DELTA_A_TO_Z) { + return String.fromCharCode(START_LOWERCASE_ALPHABET_CODE + n); + } + n -= DELTA_A_TO_Z; + + // upper case + if (n < DELTA_A_TO_Z) { + return String.fromCharCode(START_UPPERCASE_ALPHABET_CODE + n); + } + n -= DELTA_A_TO_Z; + + // numbers + if (n < 10) { + return `${n}`; + } + + if (n === 10) return "_"; + return "$"; } /** @@ -358,3 +404,5 @@ class Template { } module.exports = Template; +module.exports.NUMBER_OF_IDENTIFIER_START_CHARS = NUMBER_OF_IDENTIFIER_START_CHARS; +module.exports.NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS = NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS; diff --git a/lib/WebpackOptionsApply.js b/lib/WebpackOptionsApply.js index f21ed0d94..2eb27c0e5 100644 --- a/lib/WebpackOptionsApply.js +++ b/lib/WebpackOptionsApply.js @@ -18,7 +18,6 @@ const RecordIdsPlugin = require("./RecordIdsPlugin"); const RuntimePlugin = require("./RuntimePlugin"); const APIPlugin = require("./APIPlugin"); -const CommonJsStuffPlugin = require("./CommonJsStuffPlugin"); const CompatibilityPlugin = require("./CompatibilityPlugin"); const ConstPlugin = require("./ConstPlugin"); const ExportsInfoApiPlugin = require("./ExportsInfoApiPlugin"); @@ -341,7 +340,6 @@ class WebpackOptionsApply extends OptionsApply { const NodeStuffPlugin = require("./NodeStuffPlugin"); new NodeStuffPlugin(options.node).apply(compiler); } - new CommonJsStuffPlugin().apply(compiler); new APIPlugin().apply(compiler); new ExportsInfoApiPlugin().apply(compiler); new ConstPlugin().apply(compiler); diff --git a/lib/dependencies/AMDDefineDependencyParserPlugin.js b/lib/dependencies/AMDDefineDependencyParserPlugin.js index a5bdb4655..817ab225b 100644 --- a/lib/dependencies/AMDDefineDependencyParserPlugin.js +++ b/lib/dependencies/AMDDefineDependencyParserPlugin.js @@ -12,6 +12,7 @@ const AMDRequireContextDependency = require("./AMDRequireContextDependency"); const AMDRequireItemDependency = require("./AMDRequireItemDependency"); const ConstDependency = require("./ConstDependency"); const ContextDependencyHelpers = require("./ContextDependencyHelpers"); +const DynamicExports = require("./DynamicExports"); const LocalModuleDependency = require("./LocalModuleDependency"); const { addLocalModule, getLocalModule } = require("./LocalModulesHelpers"); @@ -217,6 +218,7 @@ class AMDDefineDependencyParserPlugin { default: return; } + DynamicExports.bailout(parser.state); let fnParams = null; let fnParamsOffset = 0; if (fn) { diff --git a/lib/dependencies/CommonJsExportsDependency.js b/lib/dependencies/CommonJsExportsDependency.js new file mode 100644 index 000000000..29a3f3ec0 --- /dev/null +++ b/lib/dependencies/CommonJsExportsDependency.js @@ -0,0 +1,182 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const InitFragment = require("../InitFragment"); +const { UsageState } = require("../ModuleGraph"); +const RuntimeGlobals = require("../RuntimeGlobals"); +const makeSerializable = require("../util/makeSerializable"); +const propertyAccess = require("../util/propertyAccess"); +const NullDependency = require("./NullDependency"); + +/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */ +/** @typedef {import("../Dependency")} Dependency */ +/** @typedef {import("../Dependency").ExportsSpec} ExportsSpec */ +/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */ +/** @typedef {import("../ModuleGraph")} ModuleGraph */ + +class CommonJsExportsDependency extends NullDependency { + constructor(range, base, names) { + super(); + this.range = range; + this.base = base; + this.names = names; + } + + get type() { + return "cjs exports"; + } + + /** + * Returns the exported names + * @param {ModuleGraph} moduleGraph module graph + * @returns {ExportsSpec | undefined} export names + */ + getExports(moduleGraph) { + return { + exports: [this.names[0]], + dependencies: undefined + }; + } + + serialize(context) { + const { write } = context; + write(this.range); + write(this.base); + write(this.names); + super.serialize(context); + } + + deserialize(context) { + const { read } = context; + this.range = read(); + this.base = read(); + this.names = read(); + super.deserialize(context); + } +} + +makeSerializable( + CommonJsExportsDependency, + "webpack/lib/dependencies/CommonJsExportsDependency" +); + +CommonJsExportsDependency.Template = class CommonJsExportsDependencyTemplate extends NullDependency.Template { + /** + * @param {Dependency} dependency the dependency for which the template should be applied + * @param {ReplaceSource} source the current replace source which can be modified + * @param {DependencyTemplateContext} templateContext the context object + * @returns {void} + */ + apply( + dependency, + source, + { module, moduleGraph, initFragments, runtimeRequirements } + ) { + const dep = /** @type {CommonJsExportsDependency} */ (dependency); + let used; + if (module.buildMeta.exportsType === "default") { + const defaultInfo = moduleGraph.getExportInfo(module, "default"); + if (defaultInfo.used === UsageState.Used) { + used = dep.names; + } else { + used = defaultInfo.exportsInfo.getUsedName(dep.names); + } + } else { + used = moduleGraph.getExportsInfo(module).getUsedName(dep.names); + } + + let base = undefined; + let type; + switch (dep.base) { + case "exports": + runtimeRequirements.add(RuntimeGlobals.exports); + base = module.exportsArgument; + type = "expression"; + break; + case "module.exports": + runtimeRequirements.add(RuntimeGlobals.module); + base = `${module.moduleArgument}.exports`; + type = "expression"; + break; + case "this": + runtimeRequirements.add(RuntimeGlobals.thisAsExports); + base = "this"; + type = "expression"; + break; + case "Object.defineProperty(exports)": + runtimeRequirements.add(RuntimeGlobals.exports); + base = module.exportsArgument; + type = "Object.defineProperty"; + break; + case "Object.defineProperty(module.exports)": + runtimeRequirements.add(RuntimeGlobals.module); + base = `${module.moduleArgument}.exports`; + type = "Object.defineProperty"; + break; + case "Object.defineProperty(this)": + runtimeRequirements.add(RuntimeGlobals.thisAsExports); + base = "this"; + type = "Object.defineProperty"; + break; + default: + throw new Error(`Unsupported base ${dep.base}`); + } + + switch (type) { + case "expression": + if (!used) { + initFragments.push( + new InitFragment( + "var __webpack_unused_export__;\n", + InitFragment.STAGE_CONSTANTS, + 0, + "__webpack_unused_export__" + ) + ); + source.replace( + dep.range[0], + dep.range[1] - 1, + "__webpack_unused_export__" + ); + return; + } + source.replace( + dep.range[0], + dep.range[1] - 1, + `${base}${propertyAccess(used)}` + ); + return; + case "Object.defineProperty": + if (!used) { + initFragments.push( + new InitFragment( + "var __webpack_unused_export__;\n", + InitFragment.STAGE_CONSTANTS, + 0, + "__webpack_unused_export__" + ) + ); + source.replace( + dep.range[0], + dep.range[1] - 1, + "__webpack_unused_export__ = (" + ); + return; + } + source.replace( + dep.range[0], + dep.range[1] - 1, + `Object.defineProperty(${base}${propertyAccess( + used.slice(0, -1) + )}, ${JSON.stringify(used[used.length - 1])}, ` + ); + return; + } + } +}; + +module.exports = CommonJsExportsDependency; diff --git a/lib/dependencies/CommonJsExportsParserPlugin.js b/lib/dependencies/CommonJsExportsParserPlugin.js new file mode 100644 index 000000000..a33cfd279 --- /dev/null +++ b/lib/dependencies/CommonJsExportsParserPlugin.js @@ -0,0 +1,231 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const RuntimeGlobals = require("../RuntimeGlobals"); +const { evaluateToString } = require("../javascript/JavascriptParserHelpers"); +const CommonJsExportsDependency = require("./CommonJsExportsDependency"); +const CommonJsSelfReferenceDependency = require("./CommonJsSelfReferenceDependency"); +const DynamicExports = require("./DynamicExports"); +const HarmonyExports = require("./HarmonyExports"); +const ModuleDecoratorDependency = require("./ModuleDecoratorDependency"); + +/** @typedef {import("../NormalModule")} NormalModule */ +/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */ + +/** @type {WeakMap} */ +const moduleExportsState = new WeakMap(); + +const getValueOfPropertyDescription = expr => { + if (expr.type !== "ObjectExpression") return; + for (const property of expr.properties) { + if (property.computed) continue; + const key = property.key; + if (key.type !== "Identifier" || key.name !== "value") continue; + return property.value; + } +}; + +const isTruthyLiteral = expr => { + switch (expr.type) { + case "Literal": + return !!expr.value; + case "UnaryExpression": + if (expr.operator === "!") return isFalsyLiteral(expr.argument); + } + return false; +}; + +const isFalsyLiteral = expr => { + switch (expr.type) { + case "Literal": + return !expr.value; + case "UnaryExpression": + if (expr.operator === "!") return isTruthyLiteral(expr.argument); + } + return false; +}; + +class CommonJsExportsParserPlugin { + static bailout(module) { + const value = moduleExportsState.get(module); + moduleExportsState.set(module, false); + if (value === true) { + module.buildMeta.exportsType = undefined; + module.buildMeta.defaultObject = false; + } + } + + /** + * @param {JavascriptParser} parser the parser + */ + apply(parser) { + const enableStructuredExports = () => { + DynamicExports.enable(parser.state); + }; + const checkNamespace = (members, valueExpr) => { + if (!DynamicExports.isEnabled(parser.state)) return; + if (members.length > 0 && members[0] === "__esModule") { + if (isTruthyLiteral(valueExpr)) { + DynamicExports.setFlagged(parser.state); + } else { + DynamicExports.bailout(parser.state); + } + } + }; + const bailout = () => { + DynamicExports.bailout(parser.state); + }; + + // metadata // + parser.hooks.evaluateTypeof + .for("module") + .tap("CommonJsExportsParserPlugin", evaluateToString("object")); + parser.hooks.evaluateTypeof + .for("exports") + .tap("CommonJsPlugin", evaluateToString("object")); + + // exporting // + parser.hooks.assignMemberChain + .for("exports") + .tap("CommonJsExportsParserPlugin", (expr, members) => { + if (HarmonyExports.isEnabled(parser.state)) return; + enableStructuredExports(); + checkNamespace(members, expr.right); + const dep = new CommonJsExportsDependency( + expr.left.range, + "exports", + members + ); + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + return true; + }); + parser.hooks.assignMemberChain + .for("this") + .tap("CommonJsExportsParserPlugin", (expr, members) => { + if (HarmonyExports.isEnabled(parser.state)) return; + if (!parser.scope.topLevelScope) return; + enableStructuredExports(); + checkNamespace(members, expr.right); + const dep = new CommonJsExportsDependency( + expr.left.range, + "this", + members + ); + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + return true; + }); + parser.hooks.assignMemberChain + .for("module") + .tap("CommonJsExportsParserPlugin", (expr, members) => { + if (HarmonyExports.isEnabled(parser.state)) return; + if (members[0] !== "exports" || members.length <= 1) return; + enableStructuredExports(); + checkNamespace(members, expr.right); + const dep = new CommonJsExportsDependency( + expr.left.range, + "module.exports", + members.slice(1) + ); + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + return true; + }); + parser.hooks.call + .for("Object.defineProperty") + .tap("CommonJsExportsParserPlugin", expression => { + const expr = /** @type {import("estree").CallExpression} */ (expression); + if (expr.arguments.length !== 3) return; + if (expr.arguments[0].type === "SpreadElement") return; + if (expr.arguments[1].type === "SpreadElement") return; + if (expr.arguments[2].type === "SpreadElement") return; + const exportsArg = parser.evaluateExpression(expr.arguments[0]); + if (!exportsArg || !exportsArg.isIdentifier()) return; + if ( + exportsArg.identifier !== "exports" && + exportsArg.identifier !== "module.exports" && + exportsArg.identifier !== "this" + ) { + return; + } + const propertyArg = parser.evaluateExpression(expr.arguments[1]); + if (!propertyArg) return; + const property = propertyArg.asString(); + if (typeof property !== "string") return; + enableStructuredExports(); + const descArg = expr.arguments[2]; + checkNamespace([property], getValueOfPropertyDescription(descArg)); + const dep = new CommonJsExportsDependency( + [expr.callee.range[0], expr.arguments[2].range[0]], + `Object.defineProperty(${exportsArg.identifier})`, + [property] + ); + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + + parser.walkExpression(expr.arguments[2]); + return true; + }); + + // Self reference // + parser.hooks.expression + .for("exports") + .tap("CommonJsExportsParserPlugin", expr => { + if (HarmonyExports.isEnabled(parser.state)) return; + bailout(); + const dep = new CommonJsSelfReferenceDependency( + expr.range, + "exports", + [] + ); + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + return true; + }); + parser.hooks.expression + .for("module.exports") + .tap("CommonJsExportsParserPlugin", expr => { + if (HarmonyExports.isEnabled(parser.state)) return; + bailout(); + const dep = new CommonJsSelfReferenceDependency( + expr.range, + "module.exports", + [] + ); + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + return true; + }); + parser.hooks.expression + .for("this") + .tap("CommonJsExportsParserPlugin", expr => { + if (HarmonyExports.isEnabled(parser.state)) return; + if (!parser.scope.topLevelScope) return; + bailout(); + const dep = new CommonJsSelfReferenceDependency(expr.range, "this", []); + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + return true; + }); + + // Bailouts // + parser.hooks.expression.for("module").tap("CommonJsPlugin", expr => { + bailout(); + const isHarmony = HarmonyExports.isEnabled(parser.state); + const dep = new ModuleDecoratorDependency( + isHarmony + ? RuntimeGlobals.harmonyModuleDecorator + : RuntimeGlobals.nodeModuleDecorator + ); + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + return true; + }); + } +} +module.exports = CommonJsExportsParserPlugin; diff --git a/lib/dependencies/CommonJsFullRequireDependency.js b/lib/dependencies/CommonJsFullRequireDependency.js new file mode 100644 index 000000000..ef57bd072 --- /dev/null +++ b/lib/dependencies/CommonJsFullRequireDependency.js @@ -0,0 +1,121 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const makeSerializable = require("../util/makeSerializable"); +const ModuleDependency = require("./ModuleDependency"); + +/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */ +/** @typedef {import("../Dependency")} Dependency */ +/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */ +/** @typedef {import("../ModuleGraph")} ModuleGraph */ + +class CommonJsFullRequireDependency extends ModuleDependency { + /** + * @param {string} request the request string + * @param {[number, number]} range location in source code + * @param {string[]} names accessed properties on module + */ + constructor(request, range, names) { + super(request); + this.range = range; + this.names = names; + this.call = false; + this.asiSafe = false; + } + + /** + * Returns list of exports referenced by this dependency + * @param {ModuleGraph} moduleGraph module graph + * @returns {string[][]} referenced exports + */ + getReferencedExports(moduleGraph) { + if (this.call) { + const importedModule = moduleGraph.getModule(this); + if ( + !importedModule || + importedModule.getExportsType(false) !== "namespace" + ) { + return [this.names.slice(0, -1)]; + } + } + return [this.names]; + } + + serialize(context) { + const { write } = context; + write(this.names); + write(this.call); + write(this.asiSafe); + super.serialize(context); + } + + deserialize(context) { + const { read } = context; + this.names = read(); + this.call = read(); + this.asiSafe = read(); + super.deserialize(context); + } + + get type() { + return "cjs full require"; + } +} + +CommonJsFullRequireDependency.Template = class CommonJsFullRequireDependencyTemplate extends ModuleDependency.Template { + /** + * @param {Dependency} dependency the dependency for which the template should be applied + * @param {ReplaceSource} source the current replace source which can be modified + * @param {DependencyTemplateContext} templateContext the context object + * @returns {void} + */ + apply( + dependency, + source, + { + module, + runtimeTemplate, + moduleGraph, + chunkGraph, + runtimeRequirements, + initFragments + } + ) { + const dep = /** @type {CommonJsFullRequireDependency} */ (dependency); + if (!dep.range) return; + const importedModule = moduleGraph.getModule(dep); + const exports = runtimeTemplate.moduleExports({ + module: importedModule, + chunkGraph, + request: dep.request, + weak: dep.weak, + runtimeRequirements + }); + const exportExpr = runtimeTemplate.exportFromImport({ + moduleGraph, + module: importedModule, + request: dep.request, + exportName: dep.names, + originModule: module, + asiSafe: dep.asiSafe, + isCall: dep.call, + callContext: undefined, + defaultInterop: false, + importVar: exports, + initFragments, + runtimeRequirements + }); + source.replace(dep.range[0], dep.range[1] - 1, exportExpr); + } +}; + +makeSerializable( + CommonJsFullRequireDependency, + "webpack/lib/dependencies/CommonJsFullRequireDependency" +); + +module.exports = CommonJsFullRequireDependency; diff --git a/lib/dependencies/CommonJsImportsParserPlugin.js b/lib/dependencies/CommonJsImportsParserPlugin.js new file mode 100644 index 000000000..d321bd928 --- /dev/null +++ b/lib/dependencies/CommonJsImportsParserPlugin.js @@ -0,0 +1,340 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const RuntimeGlobals = require("../RuntimeGlobals"); +const { + evaluateToIdentifier, + evaluateToString, + expressionIsUnsupported, + toConstantDependency +} = require("../javascript/JavascriptParserHelpers"); +const CommonJsFullRequireDependency = require("./CommonJsFullRequireDependency"); +const CommonJsRequireContextDependency = require("./CommonJsRequireContextDependency"); +const CommonJsRequireDependency = require("./CommonJsRequireDependency"); +const ConstDependency = require("./ConstDependency"); +const ContextDependencyHelpers = require("./ContextDependencyHelpers"); +const LocalModuleDependency = require("./LocalModuleDependency"); +const { getLocalModule } = require("./LocalModulesHelpers"); +const RequireHeaderDependency = require("./RequireHeaderDependency"); +const RequireResolveContextDependency = require("./RequireResolveContextDependency"); +const RequireResolveDependency = require("./RequireResolveDependency"); +const RequireResolveHeaderDependency = require("./RequireResolveHeaderDependency"); + +class CommonJsImportsParserPlugin { + constructor(options) { + this.options = options; + } + + apply(parser) { + const options = this.options; + + // metadata // + const tapRequireExpression = (expression, getMembers) => { + parser.hooks.typeof + .for(expression) + .tap( + "CommonJsPlugin", + toConstantDependency(parser, JSON.stringify("function")) + ); + parser.hooks.evaluateTypeof + .for(expression) + .tap("CommonJsPlugin", evaluateToString("function")); + parser.hooks.evaluateIdentifier + .for(expression) + .tap( + "CommonJsPlugin", + evaluateToIdentifier(expression, "require", getMembers, true) + ); + }; + tapRequireExpression("require", () => []); + tapRequireExpression("require.resolve", () => ["resolve"]); + tapRequireExpression("require.resolveWeak", () => ["resolveWeak"]); + + // Weird stuff // + parser.hooks.assign.for("require").tap("CommonJsPlugin", expr => { + // to not leak to global "require", we need to define a local require here. + const dep = new ConstDependency("var require;", 0); + dep.loc = expr.loc; + parser.state.module.addPresentationalDependency(dep); + return true; + }); + + // Unsupported // + parser.hooks.expression + .for("require.main.require") + .tap( + "CommonJsPlugin", + expressionIsUnsupported( + parser, + "require.main.require is not supported by webpack." + ) + ); + parser.hooks.call + .for("require.main.require") + .tap( + "CommonJsPlugin", + expressionIsUnsupported( + parser, + "require.main.require is not supported by webpack." + ) + ); + parser.hooks.expression + .for("module.parent.require") + .tap( + "CommonJsPlugin", + expressionIsUnsupported( + parser, + "module.parent.require is not supported by webpack." + ) + ); + parser.hooks.call + .for("module.parent.require") + .tap( + "CommonJsPlugin", + expressionIsUnsupported( + parser, + "module.parent.require is not supported by webpack." + ) + ); + + // renaming // + parser.hooks.canRename.for("require").tap("CommonJsPlugin", () => true); + parser.hooks.rename.for("require").tap("CommonJsPlugin", expr => { + // To avoid "not defined" error, replace the value with undefined + const dep = new ConstDependency("undefined", expr.range); + dep.loc = expr.loc; + parser.state.module.addPresentationalDependency(dep); + return false; + }); + + // inspection // + parser.hooks.expression + .for("require.cache") + .tap( + "CommonJsImportsParserPlugin", + toConstantDependency(parser, RuntimeGlobals.moduleCache, [ + RuntimeGlobals.moduleCache, + RuntimeGlobals.moduleId, + RuntimeGlobals.moduleLoaded + ]) + ); + + // require as expression // + parser.hooks.expression + .for("require") + .tap("CommonJsImportsParserPlugin", expr => { + const dep = new CommonJsRequireContextDependency( + { + request: options.unknownContextRequest, + recursive: options.unknownContextRecursive, + regExp: options.unknownContextRegExp, + mode: "sync" + }, + expr.range + ); + dep.critical = + options.unknownContextCritical && + "require function is used in a way in which dependencies cannot be statically extracted"; + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + }); + + // require // + const processRequireItem = (expr, param) => { + if (param.isString()) { + const dep = new CommonJsRequireDependency(param.string, param.range); + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + } + }; + const processRequireContext = (expr, param) => { + const dep = ContextDependencyHelpers.create( + CommonJsRequireContextDependency, + expr.range, + param, + expr, + options, + {}, + parser + ); + if (!dep) return; + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + }; + + const createRequireHandler = callNew => expr => { + if (expr.arguments.length !== 1) return; + let localModule; + const param = parser.evaluateExpression(expr.arguments[0]); + if (param.isConditional()) { + let isExpression = false; + for (const p of param.options) { + const result = processRequireItem(expr, p); + if (result === undefined) { + isExpression = true; + } + } + if (!isExpression) { + const dep = new RequireHeaderDependency(expr.callee.range); + dep.loc = expr.loc; + parser.state.module.addPresentationalDependency(dep); + return true; + } + } + if ( + param.isString() && + (localModule = getLocalModule(parser.state, param.string)) + ) { + localModule.flagUsed(); + const dep = new LocalModuleDependency(localModule, expr.range, callNew); + dep.loc = expr.loc; + parser.state.module.addPresentationalDependency(dep); + return true; + } else { + const result = processRequireItem(expr, param); + if (result === undefined) { + processRequireContext(expr, param); + } else { + const dep = new RequireHeaderDependency(expr.callee.range); + dep.loc = expr.loc; + parser.state.module.addPresentationalDependency(dep); + } + return true; + } + }; + parser.hooks.call + .for("require") + .tap("CommonJsImportsParserPlugin", createRequireHandler(false)); + parser.hooks.new + .for("require") + .tap("CommonJsImportsParserPlugin", createRequireHandler(true)); + parser.hooks.call + .for("module.require") + .tap("CommonJsImportsParserPlugin", createRequireHandler(false)); + parser.hooks.new + .for("module.require") + .tap("CommonJsImportsParserPlugin", createRequireHandler(true)); + + // require with property access // + const chainHandler = (expr, calleeMembers, callExpr, members) => { + if (callExpr.arguments.length !== 1) return; + const param = parser.evaluateExpression(callExpr.arguments[0]); + if (param.isString() && !getLocalModule(parser.state, param.string)) { + const dep = new CommonJsFullRequireDependency( + param.string, + expr.range, + members + ); + dep.asiSafe = !parser.isAsiPosition(expr.range[0]); + dep.loc = expr.loc; + parser.state.module.addDependency(dep); + return true; + } + }; + const callChainHandler = (expr, calleeMembers, callExpr, members) => { + if (callExpr.arguments.length !== 1) return; + const param = parser.evaluateExpression(callExpr.arguments[0]); + if (param.isString() && !getLocalModule(parser.state, param.string)) { + const dep = new CommonJsFullRequireDependency( + param.string, + expr.callee.range, + members + ); + dep.call = true; + dep.asiSafe = !parser.isAsiPosition(expr.range[0]); + dep.loc = expr.callee.loc; + parser.state.module.addDependency(dep); + return true; + } + }; + parser.hooks.memberChainOfCallMemberChain + .for("require") + .tap("CommonJsImportsParserPlugin", chainHandler); + parser.hooks.memberChainOfCallMemberChain + .for("module.require") + .tap("CommonJsImportsParserPlugin", chainHandler); + parser.hooks.callMemberChainOfCallMemberChain + .for("require") + .tap("CommonJsImportsParserPlugin", callChainHandler); + parser.hooks.callMemberChainOfCallMemberChain + .for("module.require") + .tap("CommonJsImportsParserPlugin", callChainHandler); + + // require.resolve // + const processResolve = (expr, weak) => { + if (expr.arguments.length !== 1) return; + const param = parser.evaluateExpression(expr.arguments[0]); + if (param.isConditional()) { + for (const option of param.options) { + const result = processResolveItem(expr, option, weak); + if (result === undefined) { + processResolveContext(expr, option, weak); + } + } + const dep = new RequireResolveHeaderDependency(expr.callee.range); + dep.loc = expr.loc; + parser.state.module.addPresentationalDependency(dep); + return true; + } else { + const result = processResolveItem(expr, param, weak); + if (result === undefined) { + processResolveContext(expr, param, weak); + } + const dep = new RequireResolveHeaderDependency(expr.callee.range); + dep.loc = expr.loc; + parser.state.module.addPresentationalDependency(dep); + return true; + } + }; + const processResolveItem = (expr, param, weak) => { + if (param.isString()) { + const dep = new RequireResolveDependency(param.string, param.range); + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + dep.weak = weak; + parser.state.current.addDependency(dep); + return true; + } + }; + const processResolveContext = (expr, param, weak) => { + const dep = ContextDependencyHelpers.create( + RequireResolveContextDependency, + param.range, + param, + expr, + options, + { + mode: weak ? "weak" : "sync" + }, + parser + ); + if (!dep) return; + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + }; + + parser.hooks.call + .for("require.resolve") + .tap("RequireResolveDependencyParserPlugin", expr => { + return processResolve(expr, false); + }); + parser.hooks.call + .for("require.resolveWeak") + .tap("RequireResolveDependencyParserPlugin", expr => { + return processResolve(expr, true); + }); + } +} +module.exports = CommonJsImportsParserPlugin; diff --git a/lib/dependencies/CommonJsPlugin.js b/lib/dependencies/CommonJsPlugin.js index 543165d29..753a8a5f4 100644 --- a/lib/dependencies/CommonJsPlugin.js +++ b/lib/dependencies/CommonJsPlugin.js @@ -5,22 +5,27 @@ "use strict"; +const RuntimeGlobals = require("../RuntimeGlobals"); +const RuntimeModule = require("../RuntimeModule"); +const SelfModuleFactory = require("../SelfModuleFactory"); +const Template = require("../Template"); +const CommonJsExportsDependency = require("./CommonJsExportsDependency"); +const CommonJsFullRequireDependency = require("./CommonJsFullRequireDependency"); const CommonJsRequireContextDependency = require("./CommonJsRequireContextDependency"); const CommonJsRequireDependency = require("./CommonJsRequireDependency"); -const ConstDependency = require("./ConstDependency"); +const CommonJsSelfReferenceDependency = require("./CommonJsSelfReferenceDependency"); +const ModuleDecoratorDependency = require("./ModuleDecoratorDependency"); const RequireHeaderDependency = require("./RequireHeaderDependency"); const RequireResolveContextDependency = require("./RequireResolveContextDependency"); const RequireResolveDependency = require("./RequireResolveDependency"); const RequireResolveHeaderDependency = require("./RequireResolveHeaderDependency"); +const RuntimeRequirementsDependency = require("./RuntimeRequirementsDependency"); -const CommonJsRequireDependencyParserPlugin = require("./CommonJsRequireDependencyParserPlugin"); -const RequireResolveDependencyParserPlugin = require("./RequireResolveDependencyParserPlugin"); - -const RuntimeGlobals = require("../RuntimeGlobals"); +const CommonJsExportsParserPlugin = require("./CommonJsExportsParserPlugin"); +const CommonJsImportsParserPlugin = require("./CommonJsImportsParserPlugin"); const { evaluateToIdentifier, - evaluateToString, toConstantDependency } = require("../javascript/JavascriptParserHelpers"); @@ -43,6 +48,15 @@ class CommonJsPlugin { new CommonJsRequireDependency.Template() ); + compilation.dependencyFactories.set( + CommonJsFullRequireDependency, + normalModuleFactory + ); + compilation.dependencyTemplates.set( + CommonJsFullRequireDependency, + new CommonJsFullRequireDependency.Template() + ); + compilation.dependencyFactories.set( CommonJsRequireContextDependency, contextModuleFactory @@ -80,72 +94,116 @@ class CommonJsPlugin { new RequireHeaderDependency.Template() ); + compilation.dependencyTemplates.set( + CommonJsExportsDependency, + new CommonJsExportsDependency.Template() + ); + + const selfFactory = new SelfModuleFactory(compilation.moduleGraph); + + compilation.dependencyFactories.set( + CommonJsSelfReferenceDependency, + selfFactory + ); + compilation.dependencyTemplates.set( + CommonJsSelfReferenceDependency, + new CommonJsSelfReferenceDependency.Template() + ); + + compilation.dependencyFactories.set( + ModuleDecoratorDependency, + selfFactory + ); + compilation.dependencyTemplates.set( + ModuleDecoratorDependency, + new ModuleDecoratorDependency.Template() + ); + + compilation.hooks.runtimeRequirementInModule + .for(RuntimeGlobals.harmonyModuleDecorator) + .tap("CommonJsPlugin", (module, set) => { + set.add(RuntimeGlobals.module); + set.add(RuntimeGlobals.requireScope); + }); + + compilation.hooks.runtimeRequirementInModule + .for(RuntimeGlobals.nodeModuleDecorator) + .tap("CommonJsPlugin", (module, set) => { + set.add(RuntimeGlobals.module); + set.add(RuntimeGlobals.requireScope); + }); + + compilation.hooks.runtimeRequirementInTree + .for(RuntimeGlobals.harmonyModuleDecorator) + .tap("CommonJsPlugin", (chunk, set) => { + compilation.addRuntimeModule( + chunk, + new HarmonyModuleDecoratorRuntimeModule() + ); + }); + + compilation.hooks.runtimeRequirementInTree + .for(RuntimeGlobals.nodeModuleDecorator) + .tap("CommonJsPlugin", (chunk, set) => { + compilation.addRuntimeModule( + chunk, + new NodeModuleDecoratorRuntimeModule() + ); + }); + const handler = (parser, parserOptions) => { if (parserOptions.commonjs !== undefined && !parserOptions.commonjs) return; - - const tapRequireExpression = (expression, getMembers) => { - parser.hooks.typeof - .for(expression) - .tap( - "CommonJsPlugin", - toConstantDependency(parser, JSON.stringify("function")) - ); - parser.hooks.evaluateTypeof - .for(expression) - .tap("CommonJsPlugin", evaluateToString("function")); - parser.hooks.evaluateIdentifier - .for(expression) - .tap( - "CommonJsPlugin", - evaluateToIdentifier(expression, "require", getMembers, true) - ); - }; - tapRequireExpression("require", () => []); - tapRequireExpression("require.resolve", () => ["resolve"]); - tapRequireExpression("require.resolveWeak", () => ["resolveWeak"]); - - parser.hooks.evaluateTypeof - .for("module") - .tap("CommonJsPlugin", evaluateToString("object")); - parser.hooks.expression.for("exports").tap("CommonJsPlugin", expr => { - const module = parser.state.module; - const isHarmony = module.buildMeta && module.buildMeta.exportsType; - if (!isHarmony) { - return toConstantDependency(parser, module.exportsArgument, [ - RuntimeGlobals.exports - ])(expr); - } - }); - parser.hooks.assign.for("require").tap("CommonJsPlugin", expr => { - // to not leak to global "require", we need to define a local require here. - const dep = new ConstDependency("var require;", 0); - dep.loc = expr.loc; - parser.state.module.addPresentationalDependency(dep); - return true; - }); - parser.hooks.canRename - .for("require") - .tap("CommonJsPlugin", () => true); - parser.hooks.rename.for("require").tap("CommonJsPlugin", expr => { - // To avoid "not defined" error, replace the value with undefined - const dep = new ConstDependency("undefined", expr.range); - dep.loc = expr.loc; - parser.state.module.addPresentationalDependency(dep); - return false; - }); parser.hooks.typeof .for("module") .tap( "CommonJsPlugin", toConstantDependency(parser, JSON.stringify("object")) ); - parser.hooks.evaluateTypeof - .for("exports") - .tap("CommonJsPlugin", evaluateToString("object")); - new CommonJsRequireDependencyParserPlugin(options).apply(parser); - new RequireResolveDependencyParserPlugin(options).apply(parser); + parser.hooks.expression + .for("require.main") + .tap( + "CommonJsPlugin", + toConstantDependency( + parser, + `${RuntimeGlobals.moduleCache}[${RuntimeGlobals.entryModuleId}]`, + [RuntimeGlobals.moduleCache, RuntimeGlobals.entryModuleId] + ) + ); + parser.hooks.expression + .for("module.loaded") + .tap("CommonJsPlugin", expr => { + parser.state.module.buildMeta.moduleConcatenationBailout = + "module.loaded"; + const dep = new RuntimeRequirementsDependency([ + RuntimeGlobals.moduleLoaded + ]); + dep.loc = expr.loc; + parser.state.module.addPresentationalDependency(dep); + return true; + }); + + parser.hooks.expression + .for("module.id") + .tap("CommonJsPlugin", expr => { + parser.state.module.buildMeta.moduleConcatenationBailout = + "module.id"; + const dep = new RuntimeRequirementsDependency([ + RuntimeGlobals.moduleId + ]); + dep.loc = expr.loc; + parser.state.module.addPresentationalDependency(dep); + return true; + }); + + parser.hooks.evaluateIdentifier.for("module.hot").tap( + "CommonJsPlugin", + evaluateToIdentifier("module.hot", "module", () => ["hot"], false) + ); + + new CommonJsImportsParserPlugin(options).apply(parser); + new CommonJsExportsParserPlugin().apply(parser); }; normalModuleFactory.hooks.parser @@ -158,4 +216,57 @@ class CommonJsPlugin { ); } } + +class HarmonyModuleDecoratorRuntimeModule extends RuntimeModule { + constructor() { + super("harmony module decorator"); + } + + /** + * @returns {string} runtime code + */ + generate() { + const { runtimeTemplate } = this.compilation; + return Template.asString([ + `${ + RuntimeGlobals.harmonyModuleDecorator + } = ${runtimeTemplate.basicFunction("module", [ + "module = Object.create(module);", + "if (!module.children) module.children = [];", + "Object.defineProperty(module, 'exports', {", + Template.indent([ + "enumerable: true,", + `set: ${runtimeTemplate.basicFunction("", [ + "throw new Error('ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: ' + module.id);" + ])}` + ]), + "});", + "return module;" + ])};` + ]); + } +} + +class NodeModuleDecoratorRuntimeModule extends RuntimeModule { + constructor() { + super("node module decorator"); + } + + /** + * @returns {string} runtime code + */ + generate() { + const { runtimeTemplate } = this.compilation; + return Template.asString([ + `${ + RuntimeGlobals.nodeModuleDecorator + } = ${runtimeTemplate.basicFunction("module", [ + "module.paths = [];", + "if (!module.children) module.children = [];", + "return module;" + ])};` + ]); + } +} + module.exports = CommonJsPlugin; diff --git a/lib/dependencies/CommonJsRequireDependencyParserPlugin.js b/lib/dependencies/CommonJsRequireDependencyParserPlugin.js deleted file mode 100644 index cb94089b5..000000000 --- a/lib/dependencies/CommonJsRequireDependencyParserPlugin.js +++ /dev/null @@ -1,136 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ - -"use strict"; - -const RuntimeGlobals = require("../RuntimeGlobals"); -const { - toConstantDependency -} = require("../javascript/JavascriptParserHelpers"); -const CommonJsRequireContextDependency = require("./CommonJsRequireContextDependency"); -const CommonJsRequireDependency = require("./CommonJsRequireDependency"); -const ContextDependencyHelpers = require("./ContextDependencyHelpers"); -const LocalModuleDependency = require("./LocalModuleDependency"); -const { getLocalModule } = require("./LocalModulesHelpers"); -const RequireHeaderDependency = require("./RequireHeaderDependency"); - -class CommonJsRequireDependencyParserPlugin { - constructor(options) { - this.options = options; - } - - apply(parser) { - const options = this.options; - - const processItem = (expr, param) => { - if (param.isString()) { - const dep = new CommonJsRequireDependency(param.string, param.range); - dep.loc = expr.loc; - dep.optional = !!parser.scope.inTry; - parser.state.current.addDependency(dep); - return true; - } - }; - const processContext = (expr, param) => { - const dep = ContextDependencyHelpers.create( - CommonJsRequireContextDependency, - expr.range, - param, - expr, - options, - {}, - parser - ); - if (!dep) return; - dep.loc = expr.loc; - dep.optional = !!parser.scope.inTry; - parser.state.current.addDependency(dep); - return true; - }; - - parser.hooks.expression - .for("require.cache") - .tap( - "CommonJsRequireDependencyParserPlugin", - toConstantDependency(parser, RuntimeGlobals.moduleCache, [ - RuntimeGlobals.moduleCache - ]) - ); - parser.hooks.expression - .for("require") - .tap("CommonJsRequireDependencyParserPlugin", expr => { - const dep = new CommonJsRequireContextDependency( - { - request: options.unknownContextRequest, - recursive: options.unknownContextRecursive, - regExp: options.unknownContextRegExp, - mode: "sync" - }, - expr.range - ); - dep.critical = - options.unknownContextCritical && - "require function is used in a way in which dependencies cannot be statically extracted"; - dep.loc = expr.loc; - dep.optional = !!parser.scope.inTry; - parser.state.current.addDependency(dep); - return true; - }); - - const createHandler = callNew => expr => { - if (expr.arguments.length !== 1) return; - let localModule; - const param = parser.evaluateExpression(expr.arguments[0]); - if (param.isConditional()) { - let isExpression = false; - for (const p of param.options) { - const result = processItem(expr, p); - if (result === undefined) { - isExpression = true; - } - } - if (!isExpression) { - const dep = new RequireHeaderDependency(expr.callee.range); - dep.loc = expr.loc; - parser.state.module.addPresentationalDependency(dep); - return true; - } - } - if ( - param.isString() && - (localModule = getLocalModule(parser.state, param.string)) - ) { - localModule.flagUsed(); - const dep = new LocalModuleDependency(localModule, expr.range, callNew); - dep.loc = expr.loc; - parser.state.module.addPresentationalDependency(dep); - return true; - } else { - const result = processItem(expr, param); - if (result === undefined) { - processContext(expr, param); - } else { - const dep = new RequireHeaderDependency(expr.callee.range); - dep.loc = expr.loc; - parser.state.module.addPresentationalDependency(dep); - } - return true; - } - }; - parser.hooks.call - .for("require") - .tap("CommonJsRequireDependencyParserPlugin", createHandler(false)); - parser.hooks.new - .for("require") - .tap("CommonJsRequireDependencyParserPlugin", createHandler(true)); - parser.hooks.call - .for("module.require") - .tap("CommonJsRequireDependencyParserPlugin", createHandler(false)); - parser.hooks.new - .for("module.require") - .tap("CommonJsRequireDependencyParserPlugin", createHandler(true)); - } -} -module.exports = CommonJsRequireDependencyParserPlugin; diff --git a/lib/dependencies/CommonJsSelfReferenceDependency.js b/lib/dependencies/CommonJsSelfReferenceDependency.js new file mode 100644 index 000000000..9fec7c9a4 --- /dev/null +++ b/lib/dependencies/CommonJsSelfReferenceDependency.js @@ -0,0 +1,136 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const { UsageState } = require("../ModuleGraph"); +const RuntimeGlobals = require("../RuntimeGlobals"); +const makeSerializable = require("../util/makeSerializable"); +const propertyAccess = require("../util/propertyAccess"); +const NullDependency = require("./NullDependency"); + +/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */ +/** @typedef {import("../Dependency")} Dependency */ +/** @typedef {import("../Dependency").ExportsSpec} ExportsSpec */ +/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */ +/** @typedef {import("../ModuleGraph")} ModuleGraph */ + +class CommonJsSelfReferenceDependency extends NullDependency { + constructor(range, base, names) { + super(); + this.range = range; + this.base = base; + this.names = names; + } + + get type() { + return "cjs self exports reference"; + } + + /** + * @returns {string | null} an identifier to merge equal requests + */ + getResourceIdentifier() { + return `self`; + } + + /** + * Returns list of exports referenced by this dependency + * @param {ModuleGraph} moduleGraph module graph + * @returns {string[][]} referenced exports + */ + getReferencedExports(moduleGraph) { + return [this.names]; + } + + serialize(context) { + const { write } = context; + write(this.range); + write(this.base); + write(this.names); + super.serialize(context); + } + + deserialize(context) { + const { read } = context; + this.range = read(); + this.base = read(); + this.names = read(); + super.deserialize(context); + } +} + +makeSerializable( + CommonJsSelfReferenceDependency, + "webpack/lib/dependencies/CommonJsSelfReferenceDependency" +); + +CommonJsSelfReferenceDependency.Template = class CommonJsSelfReferenceDependencyTemplate extends NullDependency.Template { + /** + * @param {Dependency} dependency the dependency for which the template should be applied + * @param {ReplaceSource} source the current replace source which can be modified + * @param {DependencyTemplateContext} templateContext the context object + * @returns {void} + */ + apply( + dependency, + source, + { module, moduleGraph, initFragments, runtimeRequirements } + ) { + const dep = /** @type {CommonJsSelfReferenceDependency} */ (dependency); + let used; + if (dep.names.length === 0) { + used = dep.names; + } else if (module.buildMeta && module.buildMeta.exportsType === "default") { + const defaultInfo = moduleGraph.getExportInfo(module, "default"); + if (defaultInfo.used === UsageState.Used) { + used = dep.names; + } else { + used = defaultInfo.exportsInfo.getUsedName(dep.names); + } + } else { + used = moduleGraph.getExportsInfo(module).getUsedName(dep.names); + } + if (!used) { + throw new Error( + "Self-reference dependency has unused export name: This should not happen" + ); + } + + let base = undefined; + switch (dep.base) { + case "exports": + runtimeRequirements.add(RuntimeGlobals.exports); + base = module.exportsArgument; + break; + case "module.exports": + runtimeRequirements.add(RuntimeGlobals.module); + base = `${module.moduleArgument}.exports`; + break; + case "this": + runtimeRequirements.add(RuntimeGlobals.thisAsExports); + base = "this"; + break; + default: + throw new Error(`Unsupported base ${dep.base}`); + } + + if (base === dep.base && used.join() === dep.names.join()) { + // Nothing has to be changed + // We don't use a replacement for compat reasons + // for plugins that update `module._source` which they + // shouldn't do! + return; + } + + source.replace( + dep.range[0], + dep.range[1] - 1, + `/* self exports access */ ${base}${propertyAccess(used)}` + ); + } +}; + +module.exports = CommonJsSelfReferenceDependency; diff --git a/lib/dependencies/DynamicExports.js b/lib/dependencies/DynamicExports.js new file mode 100644 index 000000000..1ac1007f1 --- /dev/null +++ b/lib/dependencies/DynamicExports.js @@ -0,0 +1,57 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +/** @typedef {import("../Parser").ParserState} ParserState */ + +/** @type {WeakMap} */ +const parserStateExportsState = new WeakMap(); + +/** + * @param {ParserState} parserState parser state + * @returns {void} + */ +exports.bailout = parserState => { + const value = parserStateExportsState.get(parserState); + parserStateExportsState.set(parserState, false); + if (value === true) { + parserState.module.buildMeta.exportsType = undefined; + parserState.module.buildMeta.defaultObject = false; + } +}; + +/** + * @param {ParserState} parserState parser state + * @returns {void} + */ +exports.enable = parserState => { + const value = parserStateExportsState.get(parserState); + if (value === false) return; + parserStateExportsState.set(parserState, true); + if (value !== true) { + parserState.module.buildMeta.exportsType = "default"; + parserState.module.buildMeta.defaultObject = "redirect"; + } +}; + +/** + * @param {ParserState} parserState parser state + * @returns {void} + */ +exports.setFlagged = parserState => { + const value = parserStateExportsState.get(parserState); + if (value !== true) return; + parserState.module.buildMeta.exportsType = "flagged"; +}; + +/** + * @param {ParserState} parserState parser state + * @returns {boolean} true, when enabled + */ +exports.isEnabled = parserState => { + const value = parserStateExportsState.get(parserState); + return value === true; +}; diff --git a/lib/dependencies/HarmonyDetectionParserPlugin.js b/lib/dependencies/HarmonyDetectionParserPlugin.js index 941b66420..d7d631262 100644 --- a/lib/dependencies/HarmonyDetectionParserPlugin.js +++ b/lib/dependencies/HarmonyDetectionParserPlugin.js @@ -5,7 +5,9 @@ "use strict"; +const DynamicExports = require("./DynamicExports"); const HarmonyCompatibilityDependency = require("./HarmonyCompatibilityDependency"); +const HarmonyExports = require("./HarmonyExports"); module.exports = class HarmonyDetectionParserPlugin { constructor(options) { @@ -48,16 +50,10 @@ module.exports = class HarmonyDetectionParserPlugin { index: -3 }; module.addPresentationalDependency(compatDep); - parser.state.harmonyModule = true; + DynamicExports.bailout(parser.state); + HarmonyExports.enable(parser.state, isStrictHarmony); parser.scope.isStrict = true; - module.buildMeta.exportsType = "namespace"; module.buildMeta.async = isAsync; - module.buildInfo.strict = true; - module.buildInfo.exportsArgument = "__webpack_exports__"; - if (isStrictHarmony) { - module.buildMeta.strictHarmonyModule = true; - module.buildInfo.moduleArgument = "__webpack_module__"; - } } }); @@ -68,7 +64,7 @@ module.exports = class HarmonyDetectionParserPlugin { "The top-level-await experiment is not enabled (set experiments.topLevelAwait: true to enabled it)" ); } - if (!parser.state.harmonyModule) { + if (!HarmonyExports.isEnabled(parser.state)) { throw new Error( "Top-level-await is only supported in EcmaScript Modules" ); @@ -77,15 +73,13 @@ module.exports = class HarmonyDetectionParserPlugin { }); const skipInHarmony = () => { - const module = parser.state.module; - if (module && module.buildMeta && module.buildMeta.exportsType) { + if (HarmonyExports.isEnabled(parser.state)) { return true; } }; const nullInHarmony = () => { - const module = parser.state.module; - if (module && module.buildMeta && module.buildMeta.exportsType) { + if (HarmonyExports.isEnabled(parser.state)) { return null; } }; diff --git a/lib/dependencies/HarmonyExportImportedSpecifierDependency.js b/lib/dependencies/HarmonyExportImportedSpecifierDependency.js index 897cbe009..7b2fcf2a3 100644 --- a/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +++ b/lib/dependencies/HarmonyExportImportedSpecifierDependency.js @@ -29,7 +29,7 @@ const HarmonyImportDependency = require("./HarmonyImportDependency"); /** @typedef {import("../WebpackError")} WebpackError */ /** @typedef {import("../util/Hash")} Hash */ -/** @typedef {"missing"|"unused"|"empty-star"|"reexport-non-harmony-default"|"reexport-named-default"|"reexport-namespace-object"|"reexport-fake-named-namespace-object"|"reexport-fake-namespace-object"|"reexport-non-harmony-undefined"|"normal-reexport"|"dynamic-reexport"} ExportModeType */ +/** @typedef {"missing"|"unused"|"empty-star"|"reexport-dynamic-default"|"reexport-dynamic-default-default"|"reexport-named-default"|"reexport-namespace-object"|"reexport-fake-namespace-object"|"reexport-undefined"|"normal-reexport"|"dynamic-reexport"} ExportModeType */ const idsSymbol = Symbol("HarmonyExportImportedSpecifierDependency.ids"); @@ -190,30 +190,35 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency { return mode; } - const strictHarmonyModule = parentModule.buildMeta.strictHarmonyModule; + const importedExportsType = importedModule.getExportsType( + parentModule.buildMeta.strictHarmonyModule + ); - const isNotAHarmonyModule = - importedModule.buildMeta && !importedModule.buildMeta.exportsType; - const isNamedModule = - importedModule.buildMeta && - importedModule.buildMeta.exportsType === "default"; + const isDynamic = importedExportsType === "dynamic"; + const isDynamicDefault = importedExportsType === "dynamic-default"; + const isDefaultOnly = importedExportsType === "default-only"; + const isDefaultWithNamed = importedExportsType === "default-with-named"; // Special handling for reexporting the default export - // from non-harmony modules + // from non-namespace modules if (name && ids.length > 0 && ids[0] === "default") { - if (isNotAHarmonyModule) { - const mode = new ExportMode("reexport-non-harmony-default"); + if (isDynamic) { + const mode = new ExportMode("reexport-dynamic-default"); mode.name = name; return mode; - } else if (isNamedModule) { + } else if (isDefaultOnly || isDefaultWithNamed) { const exportInfo = exportsInfo.getReadOnlyExportInfo(name); const mode = new ExportMode("reexport-named-default"); mode.name = name; mode.partialNamespaceExportInfo = exportInfo; + return mode; + } else if (isDynamicDefault) { + const mode = new ExportMode("reexport-dynamic-default-default"); + mode.name = name; return mode; } } @@ -225,8 +230,8 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency { if (ids.length > 0) { // export { name as name } - if ((isNotAHarmonyModule || isNamedModule) && strictHarmonyModule) { - mode = new ExportMode("reexport-non-harmony-undefined"); + if (isDefaultOnly || isDynamicDefault) { + mode = new ExportMode("reexport-undefined"); mode.name = name; } else { mode = new ExportMode("normal-reexport"); @@ -235,14 +240,16 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency { } } else { // export { * as name } - if (isNotAHarmonyModule && strictHarmonyModule) { + if (isDefaultOnly || isDynamicDefault) { mode = new ExportMode("reexport-fake-namespace-object"); mode.name = name; - } else if (isNamedModule) { - mode = new ExportMode("reexport-fake-named-namespace-object"); + mode.partialNamespaceExportInfo = exportInfo; + mode.fakeType = 0; + } else if (isDefaultWithNamed) { + mode = new ExportMode("reexport-fake-namespace-object"); mode.name = name; mode.partialNamespaceExportInfo = exportInfo; - mode.fakeType = strictHarmonyModule ? 0 : 2; + mode.fakeType = 2; } else { mode = new ExportMode("reexport-namespace-object"); mode.name = name; @@ -363,10 +370,10 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency { case "missing": case "unused": case "empty-star": - case "reexport-non-harmony-undefined": + case "reexport-undefined": return Dependency.NO_EXPORTS_REFERENCED; - case "reexport-non-harmony-default": + case "reexport-dynamic-default": return Dependency.DEFAULT_EXPORT_REFERENCED; case "reexport-named-default": { @@ -383,7 +390,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency { } case "reexport-namespace-object": - case "reexport-fake-named-namespace-object": { + case "reexport-fake-namespace-object": { if (!mode.partialNamespaceExportInfo) return Dependency.NS_OBJECT_REFERENCED; /** @type {string[][]} */ @@ -396,8 +403,8 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency { return referencedExports; } - case "reexport-fake-namespace-object": case "dynamic-reexport": + case "reexport-dynamic-default-default": return Dependency.NS_OBJECT_REFERENCED; case "normal-reexport": @@ -468,14 +475,14 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency { })), dependencies: [moduleGraph.getModule(this)] }; - case "reexport-fake-namespace-object": - case "reexport-non-harmony-default": - case "reexport-non-harmony-undefined": + case "reexport-dynamic-default": + case "reexport-dynamic-default-default": + case "reexport-undefined": return { exports: [mode.name], dependencies: [moduleGraph.getModule(this)] }; - case "reexport-fake-named-namespace-object": + case "reexport-fake-namespace-object": case "reexport-namespace-object": return { exports: [ @@ -678,23 +685,33 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS ); break; - case "reexport-non-harmony-default": + case "reexport-dynamic-default": initFragments.push( this.getReexportFragment( module, - "reexport default from non-harmony", + "reexport default from dynamic", module.getUsedName(moduleGraph, mode.name), importVar, - module.buildMeta && module.buildMeta.strictHarmonyModule - ? "" - : null, + null, + runtimeRequirements + ) + ); + break; + + case "reexport-dynamic-default-default": + initFragments.push( + this.getReexportFragment( + module, + "reexport dynamic as default", + module.getUsedName(moduleGraph, mode.name), + importVar, + "", runtimeRequirements ) ); break; case "reexport-fake-namespace-object": - case "reexport-fake-named-namespace-object": initFragments.push( ...this.getReexportFakeNamespaceObjectFragments( module, @@ -706,7 +723,7 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS ); break; - case "reexport-non-harmony-undefined": + case "reexport-undefined": initFragments.push( this.getReexportFragment( module, diff --git a/lib/dependencies/HarmonyExports.js b/lib/dependencies/HarmonyExports.js new file mode 100644 index 000000000..452865923 --- /dev/null +++ b/lib/dependencies/HarmonyExports.js @@ -0,0 +1,40 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +/** @typedef {import("../Parser").ParserState} ParserState */ + +/** @type {WeakMap} */ +const parserStateExportsState = new WeakMap(); + +/** + * @param {ParserState} parserState parser state + * @param {boolean} isStrictHarmony strict harmony mode should be enabled + * @returns {void} + */ +exports.enable = (parserState, isStrictHarmony) => { + const value = parserStateExportsState.get(parserState); + if (value === false) return; + parserStateExportsState.set(parserState, true); + if (value !== true) { + parserState.module.buildMeta.exportsType = "namespace"; + parserState.module.buildInfo.strict = true; + parserState.module.buildInfo.exportsArgument = "__webpack_exports__"; + if (isStrictHarmony) { + parserState.module.buildMeta.strictHarmonyModule = true; + parserState.module.buildInfo.moduleArgument = "__webpack_module__"; + } + } +}; + +/** + * @param {ParserState} parserState parser state + * @returns {boolean} true, when enabled + */ +exports.isEnabled = parserState => { + const value = parserStateExportsState.get(parserState); + return value === true; +}; diff --git a/lib/dependencies/HarmonyImportDependency.js b/lib/dependencies/HarmonyImportDependency.js index 83320bfa6..63048e853 100644 --- a/lib/dependencies/HarmonyImportDependency.js +++ b/lib/dependencies/HarmonyImportDependency.js @@ -94,62 +94,68 @@ class HarmonyImportDependency extends ModuleDependency { return; } - const exportsType = - importedModule.buildMeta && importedModule.buildMeta.exportsType; - if (!exportsType) { - // It's not an harmony module - if ( - moduleGraph.getParentModule(this).buildMeta.strictHarmonyModule && - ids.length > 0 && - ids[0] !== "default" - ) { - // In strict harmony modules we only support the default export + const parentModule = moduleGraph.getParentModule(this); + const exportsType = importedModule.getExportsType( + parentModule.buildMeta.strictHarmonyModule + ); + switch (exportsType) { + case "default-only": + case "dynamic-default": + // It's has only a default export + if (ids.length > 0 && ids[0] !== "default") { + // In strict harmony modules we only support the default export + return [ + new HarmonyLinkingError( + `Can't import the named export ${ids + .map(id => `'${id}'`) + .join( + "." + )} ${additionalMessage} from default-exporting module (only default export is available)` + ) + ]; + } + return; + case "default-with-named": + // It has a default export and named properties redirect + // In some cases we still want to warn here + if ( + ids.length > 0 && + ids[0] !== "default" && + importedModule.buildMeta.defaultObject === "redirect-warn" + ) { + // For these modules only the default export is supported + return [ + new HarmonyLinkingError( + `Should not import the named export ${ids + .map(id => `'${id}'`) + .join( + "." + )} ${additionalMessage} from default-exporting module (only default export is available soon)` + ) + ]; + } + return; + case "namespace": + if (ids.length === 0) { + return; + } + + if (moduleGraph.isExportProvided(importedModule, ids) !== false) { + // It's provided or we are not sure + return; + } + + // We are sure that it's not provided return [ new HarmonyLinkingError( - `Can't import the named export ${ids + `export ${ids .map(id => `'${id}'`) - .join( - "." - )} ${additionalMessage} from non EcmaScript module (only default export is available)` + .join(".")} ${additionalMessage} was not found in '${ + this.userRequest + }'` ) ]; - } - return; - } else if (exportsType === "default") { - if (ids.length > 0 && ids[0] !== "default") { - // For these modules only the default export is supported - return [ - new HarmonyLinkingError( - `Can't import the named export ${ids - .map(id => `'${id}'`) - .join( - "." - )} ${additionalMessage} from JSON module (only default export is available)` - ) - ]; - } - return; } - - if (ids.length === 0) { - return; - } - - if (moduleGraph.isExportProvided(importedModule, ids) !== false) { - // It's provided or we are not sure - return; - } - - // We are sure that it's not provided - return [ - new HarmonyLinkingError( - `export ${ids - .map(id => `'${id}'`) - .join(".")} ${additionalMessage} was not found in '${ - this.userRequest - }'` - ) - ]; } /** @@ -161,12 +167,15 @@ class HarmonyImportDependency extends ModuleDependency { updateHash(hash, chunkGraph) { super.updateHash(hash, chunkGraph); const importedModule = chunkGraph.moduleGraph.getModule(this); - hash.update( - (importedModule && - (!importedModule.buildMeta || importedModule.buildMeta.exportsType)) + - "" - ); - if (chunkGraph.moduleGraph.isAsync(importedModule)) hash.update("async"); + if (importedModule) { + const parentModule = chunkGraph.moduleGraph.getParentModule(this); + hash.update( + importedModule.getExportsType( + parentModule.buildMeta && parentModule.buildMeta.strictHarmonyModule + ) + ); + if (chunkGraph.moduleGraph.isAsync(importedModule)) hash.update("async"); + } hash.update(`${this.sourceOrder}`); if (this.await) hash.update("await"); } diff --git a/lib/dependencies/HarmonyImportDependencyParserPlugin.js b/lib/dependencies/HarmonyImportDependencyParserPlugin.js index 532ffbf03..2d73b6994 100644 --- a/lib/dependencies/HarmonyImportDependencyParserPlugin.js +++ b/lib/dependencies/HarmonyImportDependencyParserPlugin.js @@ -9,6 +9,7 @@ const HotModuleReplacementPlugin = require("../HotModuleReplacementPlugin"); const ConstDependency = require("./ConstDependency"); const HarmonyAcceptDependency = require("./HarmonyAcceptDependency"); const HarmonyAcceptImportDependency = require("./HarmonyAcceptImportDependency"); +const HarmonyExports = require("./HarmonyExports"); const HarmonyImportSideEffectDependency = require("./HarmonyImportSideEffectDependency"); const HarmonyImportSpecifierDependency = require("./HarmonyImportSpecifierDependency"); @@ -168,7 +169,7 @@ module.exports = class HarmonyImportDependencyParserPlugin { hotAcceptCallback.tap( "HarmonyImportDependencyParserPlugin", (expr, requests) => { - if (!parser.state.harmonyModule) { + if (!HarmonyExports.isEnabled(parser.state)) { // This is not a harmony module, skip it return; } @@ -192,7 +193,7 @@ module.exports = class HarmonyImportDependencyParserPlugin { hotAcceptWithoutCallback.tap( "HarmonyImportDependencyParserPlugin", (expr, requests) => { - if (!parser.state.harmonyModule) { + if (!HarmonyExports.isEnabled(parser.state)) { // This is not a harmony module, skip it return; } diff --git a/lib/dependencies/HarmonyImportSpecifierDependency.js b/lib/dependencies/HarmonyImportSpecifierDependency.js index 1cae0fedf..9a03ecb1d 100644 --- a/lib/dependencies/HarmonyImportSpecifierDependency.js +++ b/lib/dependencies/HarmonyImportSpecifierDependency.js @@ -171,9 +171,6 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency { if (importedModule) { const exportsInfo = moduleGraph.getExportsInfo(importedModule); hash.update(`${exportsInfo.getUsedName(ids)}`); - hash.update( - (!importedModule.buildMeta || importedModule.buildMeta.exportsType) + "" - ); } } @@ -246,6 +243,7 @@ HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependen asiSafe: dep.asiSafe || dep.shorthand, isCall: dep.call, callContext: !dep.directImport, + defaultInterop: true, importVar: dep.getImportVar(moduleGraph), initFragments, runtimeRequirements diff --git a/lib/dependencies/HarmonyTopLevelThisParserPlugin.js b/lib/dependencies/HarmonyTopLevelThisParserPlugin.js index 1ecc3f7ce..9981c10fd 100644 --- a/lib/dependencies/HarmonyTopLevelThisParserPlugin.js +++ b/lib/dependencies/HarmonyTopLevelThisParserPlugin.js @@ -6,6 +6,7 @@ "use strict"; const ConstDependency = require("./ConstDependency"); +const HarmonyExports = require("./HarmonyExports"); class HarmonyTopLevelThisParserPlugin { apply(parser) { @@ -13,12 +14,11 @@ class HarmonyTopLevelThisParserPlugin { .for("this") .tap("HarmonyTopLevelThisParserPlugin", node => { if (!parser.scope.topLevelScope) return; - const module = parser.state.module; - const isHarmony = !!(module.buildMeta && module.buildMeta.exportsType); - if (isHarmony) { + if (HarmonyExports.isEnabled(parser.state)) { const dep = new ConstDependency("undefined", node.range, null); dep.loc = node.loc; parser.state.module.addPresentationalDependency(dep); + return this; } }); } diff --git a/lib/dependencies/ModuleDecoratorDependency.js b/lib/dependencies/ModuleDecoratorDependency.js index 66733ee8e..353dd4f86 100644 --- a/lib/dependencies/ModuleDecoratorDependency.js +++ b/lib/dependencies/ModuleDecoratorDependency.js @@ -34,6 +34,22 @@ class ModuleDecoratorDependency extends NullDependency { return "module decorator"; } + /** + * @returns {string | null} an identifier to merge equal requests + */ + getResourceIdentifier() { + return `self`; + } + + /** + * Returns list of exports referenced by this dependency + * @param {ModuleGraph} moduleGraph module graph + * @returns {string[][]} referenced exports + */ + getReferencedExports(moduleGraph) { + return [[]]; + } + /** * Update the hash * @param {Hash} hash hash to be updated @@ -76,6 +92,8 @@ ModuleDecoratorDependency.Template = class ModuleDecoratorDependencyTemplate ext { module, chunkGraph, initFragments, runtimeRequirements } ) { const dep = /** @type {ModuleDecoratorDependency} */ (dependency); + runtimeRequirements.add(RuntimeGlobals.moduleLoaded); + runtimeRequirements.add(RuntimeGlobals.moduleId); runtimeRequirements.add(RuntimeGlobals.module); runtimeRequirements.add(dep.decorator); initFragments.push( diff --git a/lib/dependencies/RequireResolveDependency.js b/lib/dependencies/RequireResolveDependency.js index c58a988e2..4960578d0 100644 --- a/lib/dependencies/RequireResolveDependency.js +++ b/lib/dependencies/RequireResolveDependency.js @@ -5,10 +5,13 @@ "use strict"; +const Dependency = require("../Dependency"); const makeSerializable = require("../util/makeSerializable"); const ModuleDependency = require("./ModuleDependency"); const ModuleDependencyAsId = require("./ModuleDependencyTemplateAsId"); +/** @typedef {import("../ModuleGraph")} ModuleGraph */ + class RequireResolveDependency extends ModuleDependency { constructor(request, range) { super(request); @@ -20,6 +23,16 @@ class RequireResolveDependency extends ModuleDependency { return "require.resolve"; } + /** + * Returns list of exports referenced by this dependency + * @param {ModuleGraph} moduleGraph module graph + * @returns {string[][]} referenced exports + */ + getReferencedExports(moduleGraph) { + // This doesn't use any export + return Dependency.NO_EXPORTS_REFERENCED; + } + serialize(context) { const { write } = context; diff --git a/lib/dependencies/RequireResolveDependencyParserPlugin.js b/lib/dependencies/RequireResolveDependencyParserPlugin.js deleted file mode 100644 index 5fce979ac..000000000 --- a/lib/dependencies/RequireResolveDependencyParserPlugin.js +++ /dev/null @@ -1,87 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ - -"use strict"; - -const ContextDependencyHelpers = require("./ContextDependencyHelpers"); -const RequireResolveContextDependency = require("./RequireResolveContextDependency"); -const RequireResolveDependency = require("./RequireResolveDependency"); -const RequireResolveHeaderDependency = require("./RequireResolveHeaderDependency"); - -class RequireResolveDependencyParserPlugin { - constructor(options) { - this.options = options; - } - - apply(parser) { - const options = this.options; - - const process = (expr, weak) => { - if (expr.arguments.length !== 1) return; - const param = parser.evaluateExpression(expr.arguments[0]); - if (param.isConditional()) { - for (const option of param.options) { - const result = processItem(expr, option, weak); - if (result === undefined) { - processContext(expr, option, weak); - } - } - const dep = new RequireResolveHeaderDependency(expr.callee.range); - dep.loc = expr.loc; - parser.state.module.addPresentationalDependency(dep); - return true; - } else { - const result = processItem(expr, param, weak); - if (result === undefined) { - processContext(expr, param, weak); - } - const dep = new RequireResolveHeaderDependency(expr.callee.range); - dep.loc = expr.loc; - parser.state.module.addPresentationalDependency(dep); - return true; - } - }; - const processItem = (expr, param, weak) => { - if (param.isString()) { - const dep = new RequireResolveDependency(param.string, param.range); - dep.loc = expr.loc; - dep.optional = !!parser.scope.inTry; - dep.weak = weak; - parser.state.current.addDependency(dep); - return true; - } - }; - const processContext = (expr, param, weak) => { - const dep = ContextDependencyHelpers.create( - RequireResolveContextDependency, - param.range, - param, - expr, - options, - { - mode: weak ? "weak" : "sync" - }, - parser - ); - if (!dep) return; - dep.loc = expr.loc; - dep.optional = !!parser.scope.inTry; - parser.state.current.addDependency(dep); - return true; - }; - - parser.hooks.call - .for("require.resolve") - .tap("RequireResolveDependencyParserPlugin", expr => { - return process(expr, false); - }); - parser.hooks.call - .for("require.resolveWeak") - .tap("RequireResolveDependencyParserPlugin", expr => { - return process(expr, true); - }); - } -} -module.exports = RequireResolveDependencyParserPlugin; diff --git a/lib/javascript/JavascriptModulesPlugin.js b/lib/javascript/JavascriptModulesPlugin.js index a1896ace8..d7a2b2559 100644 --- a/lib/javascript/JavascriptModulesPlugin.js +++ b/lib/javascript/JavascriptModulesPlugin.js @@ -867,6 +867,10 @@ class JavascriptModulesPlugin { : Template.asString([ "__webpack_modules__[moduleId](module, module.exports, __webpack_require__);" ]); + const needModuleId = runtimeRequirements.has(RuntimeGlobals.moduleId); + const needModuleLoaded = runtimeRequirements.has( + RuntimeGlobals.moduleLoaded + ); const content = Template.asString([ "// Check if module is in cache", "if(__webpack_module_cache__[moduleId]) {", @@ -874,7 +878,11 @@ class JavascriptModulesPlugin { "}", "// Create a new module (and put it into the cache)", "var module = __webpack_module_cache__[moduleId] = {", - Template.indent(["i: moduleId,", "l: false,", "exports: {}"]), + Template.indent([ + needModuleId ? "id: moduleId," : "// no module.id needed", + needModuleLoaded ? "loaded: false," : "// no module.loaded needed", + "exports: {}" + ]), "};", "", outputOptions.strictModuleExceptionHandling @@ -893,10 +901,14 @@ class JavascriptModulesPlugin { "// Execute the module function", moduleExecution ]), - "", - "// Flag the module as loaded", - "module.l = true;", - "", + needModuleLoaded + ? Template.asString([ + "", + "// Flag the module as loaded", + "module.loaded = true;", + "" + ]) + : "", "// Return the exports of the module", "return module.exports;" ]); diff --git a/lib/javascript/JavascriptParser.js b/lib/javascript/JavascriptParser.js index 307e00d17..a9e3a0bd8 100644 --- a/lib/javascript/JavascriptParser.js +++ b/lib/javascript/JavascriptParser.js @@ -10,6 +10,7 @@ const { SyncBailHook, HookMap } = require("tapable"); const vm = require("vm"); const Parser = require("../Parser"); const StackedMap = require("../util/StackedMap"); +const memorize = require("../util/memorize"); const BasicEvaluatedExpression = require("./BasicEvaluatedExpression"); /** @typedef {import("acorn").Options} AcornOptions */ @@ -41,6 +42,8 @@ const BasicEvaluatedExpression = require("./BasicEvaluatedExpression"); /** @typedef {import("../Parser").ParserState} ParserState */ /** @typedef {import("../Parser").PreparsedAst} PreparsedAst */ +const EMPTY_ARRAY = []; + // Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API const parser = AcornParser.extend(require("../parsing/importAwaitAcornPlugin")); @@ -84,6 +87,25 @@ const joinRanges = (startRange, endRange) => { return [startRange[0], endRange[1]]; }; +const objectAndMembersToName = (object, membersReversed) => { + let name = object; + for (let i = membersReversed.length - 1; i >= 0; i--) { + name = name + "." + membersReversed[i]; + } + return name; +}; + +const getRootName = expression => { + switch (expression.type) { + case "Identifier": + return expression.name; + case "ThisExpression": + return "this"; + default: + return undefined; + } +}; + /** @type {AcornOptions} */ const defaultParserOptions = { ranges: true, @@ -186,6 +208,10 @@ class JavascriptParser extends Parser { rename: new HookMap(() => new SyncBailHook(["initExpression"])), /** @type {HookMap>} */ assign: new HookMap(() => new SyncBailHook(["expression"])), + /** @type {HookMap>} */ + assignMemberChain: new HookMap( + () => new SyncBailHook(["expression", "members"]) + ), /** @type {HookMap>} */ typeof: new HookMap(() => new SyncBailHook(["expression"])), /** @type {SyncBailHook<[ExpressionNode], boolean | void>} */ @@ -194,15 +220,38 @@ class JavascriptParser extends Parser { topLevelAwait: new SyncBailHook(["expression"]), /** @type {HookMap>} */ call: new HookMap(() => new SyncBailHook(["expression"])), - /** @type {HookMap>} */ + /** Something like "a.b()" */ + /** @type {HookMap>} */ callMemberChain: new HookMap( () => new SyncBailHook(["expression", "members"]) ), + /** Something like "a.b().c.d" */ + /** @type {HookMap>} */ + memberChainOfCallMemberChain: new HookMap( + () => + new SyncBailHook([ + "expression", + "calleeMembers", + "callExpression", + "members" + ]) + ), + /** Something like "a.b().c.d()"" */ + /** @type {HookMap>} */ + callMemberChainOfCallMemberChain: new HookMap( + () => + new SyncBailHook([ + "expression", + "calleeMembers", + "innerCallExpression", + "members" + ]) + ), /** @type {HookMap>} */ new: new HookMap(() => new SyncBailHook(["expression"])), /** @type {HookMap>} */ expression: new HookMap(() => new SyncBailHook(["expression"])), - /** @type {HookMap>} */ + /** @type {HookMap>} */ expressionMemberChain: new HookMap( () => new SyncBailHook(["expression", "members"]) ), @@ -219,6 +268,7 @@ class JavascriptParser extends Parser { this.sourceType = sourceType; /** @type {ScopeInfo} */ this.scope = undefined; + /** @type {ParserState} */ this.state = undefined; this.comments = undefined; this.semicolons = undefined; @@ -1996,6 +2046,23 @@ class JavascriptParser extends Parser { } }); this.walkPattern(expression.left); + } else if (expression.left.type === "MemberExpression") { + const exprName = this.getMemberExpressionInfo(expression.left, [ + "expression" + ]); + if (exprName) { + if ( + this.callHooksForInfo( + this.hooks.assignMemberChain, + exprName.rootInfo, + expression, + exprName.getMembers() + ) + ) { + return; + } + } + this.walkExpression(expression.left); } else { this.walkExpression(expression.left); } @@ -2140,6 +2207,22 @@ class JavascriptParser extends Parser { // (function(…) { }(…)) this._walkIIFE(expression.callee, expression.arguments, null); } else { + if (expression.callee.type === "MemberExpression") { + const exprInfo = this.getMemberExpressionInfo(expression.callee, [ + "call" + ]); + if (exprInfo && exprInfo.type === "call") { + const result = this.callHooksForInfo( + this.hooks.callMemberChainOfCallMemberChain, + exprInfo.rootInfo, + expression, + exprInfo.getCalleeMembers(), + exprInfo.call, + exprInfo.getMembers() + ); + if (result === true) return; + } + } const callee = this.evaluateExpression(expression.callee); if (callee.isIdentifier()) { const result1 = this.callHooksForInfo( @@ -2157,40 +2240,72 @@ class JavascriptParser extends Parser { if (result2 === true) return; } - if (expression.callee) this.walkExpression(expression.callee); + if (expression.callee) { + if (expression.callee.type === "MemberExpression") { + // because of call context we need to walk the call context as expression + this.walkExpression(expression.callee.object); + if (expression.callee.computed === true) + this.walkExpression(expression.callee.property); + } else { + this.walkExpression(expression.callee); + } + } if (expression.arguments) this.walkExpressions(expression.arguments); } } walkMemberExpression(expression) { - const exprName = this.getNameForExpression(expression); - if (exprName) { - this.walkMemberExpressionWithExpressionName( - expression, - exprName.name, - exprName.rootInfo, - exprName.getMembers() - ); - return; + const exprInfo = this.getMemberExpressionInfo(expression, [ + "call", + "expression" + ]); + if (exprInfo) { + switch (exprInfo.type) { + case "expression": { + const members = exprInfo.getMembers(); + const result = this.callHooksForInfo( + this.hooks.expressionMemberChain, + exprInfo.rootInfo, + expression, + members + ); + if (result === true) return; + this.walkMemberExpressionWithExpressionName( + expression, + exprInfo.name, + exprInfo.rootInfo, + members + ); + return; + } + case "call": { + const result = this.callHooksForInfo( + this.hooks.memberChainOfCallMemberChain, + exprInfo.rootInfo, + expression, + exprInfo.getCalleeMembers(), + exprInfo.call, + exprInfo.getMembers() + ); + if (result === true) return; + // Fast skip over the member chain as we already called memberChainOfCallMemberChain + // and call computed property are literals anyway + this.walkExpression(exprInfo.call); + return; + } + } } this.walkExpression(expression.object); if (expression.computed === true) this.walkExpression(expression.property); } walkMemberExpressionWithExpressionName(expression, name, rootInfo, members) { - const result1 = this.callHooksForInfo( - this.hooks.expressionMemberChain, - rootInfo, - expression, - members - ); - if (result1 === true) return; - const result2 = this.callHooksForInfo( + const result = this.callHooksForInfo( this.hooks.expression, name, expression ); - if (result2 === true) return; + if (result === true) return; if (expression.object.type === "MemberExpression") { // optimize case where expression.object is a MemberExpression too. // we can keep info here when calling walkMemberExpression directly @@ -2219,7 +2334,7 @@ class JavascriptParser extends Parser { } callHooksForExpression(hookMap, expr, ...args) { - const exprName = this.getNameForExpression(expr); + const exprName = this.getMemberExpressionInfo(expr, ["expression"]); if (exprName !== undefined) { return this.callHooksForInfoWithFallback( hookMap, @@ -2235,7 +2350,7 @@ class JavascriptParser extends Parser { * @template T * @template R * @param {HookMap>} hookMap hooks the should be called - * @param {ExpressionNode} expr expression info + * @param {MemberExpressionNode} expr expression info * @param {function(string, string | ScopeInfo | VariableInfo, function(): string[]): any} fallback callback when variable in not handled by hooks * @param {function(string): any} defined callback when variable is defined * @param {AsArray} args args for the hook @@ -2248,7 +2363,7 @@ class JavascriptParser extends Parser { defined, ...args ) { - const exprName = this.getNameForExpression(expr); + const exprName = this.getMemberExpressionInfo(expr, ["expression"]); if (exprName !== undefined) { return this.callHooksForInfoWithFallback( hookMap, @@ -2677,6 +2792,7 @@ class JavascriptParser extends Parser { isStrict: false, definitions: new StackedMap() }; + /** @type {ParserState} */ this.state = state; this.comments = comments; this.semicolons = semicolons; @@ -2691,6 +2807,7 @@ class JavascriptParser extends Parser { } this.hooks.finish.call(ast, comments); this.scope = oldScope; + /** @type {ParserState} */ this.state = oldState; this.comments = oldComments; this.semicolons = oldSemicolons; @@ -2843,60 +2960,112 @@ class JavascriptParser extends Parser { } /** - * @param {ExpressionNode} expression an expression - * @returns {{ name: string, rootInfo: ExportedVariableInfo, getMembers: () => string[]}} name info + * @param {MemberExpressionNode} expression an member expression + * @returns {{ members: string[], object: ExpressionNode | SuperNode }} member names (reverse order) and remaining object */ - getNameForExpression(expression) { + extractMemberExpressionChain(expression) { + /** @type {AnyNode} */ let expr = expression; - const exprName = []; + const members = []; while (expr.type === "MemberExpression") { - if (expr.object.type === "Super") return undefined; if (expr.computed) { if (expr.property.type !== "Literal") break; - exprName.push(`${expr.property.value}`); + members.push(`${expr.property.value}`); } else { if (expr.property.type !== "Identifier") break; - exprName.push(expr.property.name); + members.push(expr.property.name); } expr = expr.object; } - let rootName; - if (expr.type === "Identifier") { - rootName = expr.name; - } else if (expr.type === "ThisExpression") { - rootName = "this"; - } else { - return undefined; - } - const rootInfo = this.getVariableInfo(rootName); - /** @type {string | ScopeInfo | true} */ - let resolvedRoot; - if (rootInfo instanceof VariableInfo) { - resolvedRoot = rootInfo.freeName; - } else { - resolvedRoot = rootInfo; - } - if (typeof resolvedRoot !== "string") { - return undefined; - } - let name = resolvedRoot; - for (let i = exprName.length - 1; i >= 0; i--) { - name = name + "." + exprName[i]; - } - let reversed = false; return { - name, - rootInfo, - getMembers: () => { - if (!reversed) { - exprName.reverse(); - reversed = true; - } - return exprName; - } + members, + object: expr }; } + /** + * @param {string} varName variable name + * @returns {{name: string, info: VariableInfo | string}} name of the free variable and variable info for that + */ + getFreeInfoFromVariable(varName) { + const info = this.getVariableInfo(varName); + let name; + if (info instanceof VariableInfo) { + name = info.freeName; + if (typeof name !== "string") return undefined; + } else if (typeof info !== "string") { + return undefined; + } else { + name = info; + } + return { info, name }; + } + + /** @typedef {{ type: "call", call: CallExpressionNode, calleeName: string, rootInfo: string | VariableInfo, getCalleeMembers: () => string[], name: string, getMembers: () => string[]}} CallExpressionInfo */ + /** @typedef {{ type: "expression", rootInfo: string | VariableInfo, name: string, getMembers: () => string[]}} ExpressionExpressionInfo */ + + /** + * @param {MemberExpressionNode} expression an member expression + * @param {("call"|"expression")[]} allowedTypes which types should be returned + * @returns {CallExpressionInfo | ExpressionExpressionInfo | undefined} expression info + */ + getMemberExpressionInfo(expression, allowedTypes) { + const possibleTypes = new Set(allowedTypes); + const { object, members } = this.extractMemberExpressionChain(expression); + switch (object.type) { + case "CallExpression": { + if (!possibleTypes.has("call")) return undefined; + let callee = object.callee; + let rootMembers = EMPTY_ARRAY; + if (callee.type === "MemberExpression") { + ({ + object: callee, + members: rootMembers + } = this.extractMemberExpressionChain(callee)); + } + const rootName = getRootName(callee); + if (!rootName) return undefined; + const result = this.getFreeInfoFromVariable(rootName); + if (!result) return undefined; + const { info: rootInfo, name: resolvedRoot } = result; + const calleeName = objectAndMembersToName(resolvedRoot, rootMembers); + return { + type: "call", + call: object, + calleeName, + rootInfo, + getCalleeMembers: memorize(() => rootMembers.reverse()), + name: objectAndMembersToName(`${calleeName}()`, members), + getMembers: memorize(() => members.reverse()) + }; + } + case "Identifier": + case "ThisExpression": { + if (!possibleTypes.has("expression")) return undefined; + const rootName = getRootName(object); + if (!rootName) return undefined; + + const result = this.getFreeInfoFromVariable(rootName); + if (!result) return undefined; + const { info: rootInfo, name: resolvedRoot } = result; + return { + type: "expression", + name: objectAndMembersToName(resolvedRoot, members), + rootInfo, + getMembers: memorize(() => members.reverse()) + }; + } + } + } + + /** + * @param {MemberExpressionNode} expression an expression + * @returns {{ name: string, rootInfo: ExportedVariableInfo, getMembers: () => string[]}} name info + */ + getNameForExpression(expression) { + return this.getMemberExpressionInfo(expression, ["expression"]); + } + /** * @param {string} code source code * @param {ParseOptions} options parsing options diff --git a/lib/json/JsonParser.js b/lib/json/JsonParser.js index 1c0fcdabd..b7032b4a9 100644 --- a/lib/json/JsonParser.js +++ b/lib/json/JsonParser.js @@ -44,6 +44,8 @@ class JsonParser extends Parser { state.module.buildInfo.jsonData = data; state.module.buildInfo.strict = true; state.module.buildMeta.exportsType = "default"; + state.module.buildMeta.defaultObject = + typeof data === "object" ? "redirect-warn" : false; state.module.addDependency( new JsonExportsDependency(JsonExportsDependency.getExportsFromData(data)) ); diff --git a/lib/optimize/ConcatenatedModule.js b/lib/optimize/ConcatenatedModule.js index 610e79429..ebd401444 100644 --- a/lib/optimize/ConcatenatedModule.js +++ b/lib/optimize/ConcatenatedModule.js @@ -232,48 +232,50 @@ const getExternalImport = ( ? "" : Template.toNormalComment(`${exportName.join(".")}`); let exprStart; + const exportsType = importedModule.getExportsType(strictHarmonyModule); if (exportName.length === 0) { - switch (importedModule.buildMeta.exportsType) { - case "default": + switch (exportsType) { + case "dynamic-default": + case "default-only": + case "default-with-named": info.interopNamespaceObjectUsed = true; exprStart = info.interopNamespaceObjectName; break; case "namespace": exprStart = info.name; break; + case "dynamic": + exprStart = info.name; + break; default: - if (strictHarmonyModule) { - info.interopNamespaceObjectUsed = true; - exprStart = info.interopNamespaceObjectName; - break; - } else { - exprStart = info.name; - break; - } + throw new Error(`Unexpected exportsType ${exportsType}`); } } else { - switch (importedModule.buildMeta.exportsType) { - case "default": + switch (exportsType) { + case "default-with-named": case "namespace": break; - default: - if (strictHarmonyModule) { - if (exportName[0] === "default") { - exprStart = info.name; - } else { - exprStart = "/* non-default import from non-esm module */undefined"; - } + case "default-only": + case "dynamic-default": + if (exportName[0] === "default") { + exprStart = info.name; } else { - if (exportName[0] === "default") { - info.interopDefaultAccessUsed = true; - exprStart = asCall - ? `${info.interopDefaultAccessName}()` - : asiSafe - ? `(${info.interopDefaultAccessName}())` - : `${info.interopDefaultAccessName}.a`; - } + exprStart = + "/* non-default import from default-exporting module */undefined"; } break; + case "dynamic": + if (exportName[0] === "default") { + info.interopDefaultAccessUsed = true; + exprStart = asCall + ? `${info.interopDefaultAccessName}()` + : asiSafe + ? `(${info.interopDefaultAccessName}())` + : `${info.interopDefaultAccessName}.a`; + } + break; + default: + throw new Error(`Unexpected exportsType ${exportsType}`); } } if (exprStart) { @@ -978,6 +980,7 @@ class ConcatenatedModule extends Module { info.name = externalName; if ( info.module.buildMeta.exportsType === "default" || + info.module.buildMeta.exportsType === "flagged" || !info.module.buildMeta.exportsType ) { const externalNameInterop = this.findNewName( @@ -1090,7 +1093,10 @@ class ConcatenatedModule extends Module { result.add( `var ${info.interopNamespaceObjectName} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${info.name}, 2);\n` ); - } else if (!info.module.buildMeta.exportsType) { + } else if ( + info.module.buildMeta.exportsType === "flagged" || + !info.module.buildMeta.exportsType + ) { runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject); result.add( `var ${info.interopNamespaceObjectName} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${info.name});\n` diff --git a/lib/optimize/MangleExportsPlugin.js b/lib/optimize/MangleExportsPlugin.js index d0669f60a..6f2e86468 100644 --- a/lib/optimize/MangleExportsPlugin.js +++ b/lib/optimize/MangleExportsPlugin.js @@ -6,7 +6,11 @@ "use strict"; const { UsageState } = require("../ModuleGraph"); -const { numberToIdentifier } = require("../Template"); +const { + numberToIdentifier, + NUMBER_OF_IDENTIFIER_START_CHARS, + NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS +} = require("../Template"); const { assignDeterministicIds } = require("../ids/IdHelpers"); const { concatComparators, @@ -62,7 +66,7 @@ const mangleExportsInfo = (exportsInfo, canBeArray) => { // Don't rename 1-2 char exports or exports that can't be mangled for (const exportInfo of exportsInfo.ownedExports) { const name = exportInfo.name; - if (typeof exportInfo.usedName !== "string") { + if (exportInfo.usedName === null) { if ( exportInfo.canMangle !== true || (name.length === 1 && /^[a-zA-Z0-9_$]/.test(name)) || @@ -76,7 +80,8 @@ const mangleExportsInfo = (exportsInfo, canBeArray) => { } if ( exportInfo.exportsInfoOwned && - exportInfo.used === UsageState.OnlyPropertiesUsed + (exportInfo.used === UsageState.OnlyPropertiesUsed || + exportInfo.used === UsageState.Unused) ) { mangleExportsInfo(exportInfo.exportsInfo, true); } @@ -93,8 +98,11 @@ const mangleExportsInfo = (exportsInfo, canBeArray) => { e.usedName = name; return true; }, - [26, 52], - 52, + [ + NUMBER_OF_IDENTIFIER_START_CHARS, + NUMBER_OF_IDENTIFIER_START_CHARS * NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS + ], + NUMBER_OF_IDENTIFIER_CONTINUATION_CHARS, usedNames.size ); }; diff --git a/lib/util/internalSerializables.js b/lib/util/internalSerializables.js index f01e4fd5e..e0af6cf40 100644 --- a/lib/util/internalSerializables.js +++ b/lib/util/internalSerializables.js @@ -32,8 +32,14 @@ module.exports = { require("../dependencies/CachedConstDependency"), "dependencies/CommonJsRequireContextDependency": () => require("../dependencies/CommonJsRequireContextDependency"), + "dependencies/CommonJsExportsDependency": () => + require("../dependencies/CommonJsExportsDependency"), + "dependencies/CommonJsFullRequireDependency": () => + require("../dependencies/CommonJsFullRequireDependency"), "dependencies/CommonJsRequireDependency": () => require("../dependencies/CommonJsRequireDependency"), + "dependencies/CommonJsSelfReferenceDependency": () => + require("../dependencies/CommonJsSelfReferenceDependency"), "dependencies/ConstDependency": () => require("../dependencies/ConstDependency"), "dependencies/ContextDependency": () => diff --git a/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js b/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js index f6f0bc98c..bc2a8a0f1 100644 --- a/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +++ b/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js @@ -57,6 +57,7 @@ class AsyncWebAssemblyJavascriptGenerator extends Generator { runtimeRequirements } = generateContext; runtimeRequirements.add(RuntimeGlobals.module); + runtimeRequirements.add(RuntimeGlobals.moduleId); runtimeRequirements.add(RuntimeGlobals.exports); runtimeRequirements.add(RuntimeGlobals.instantiateWasm); /** @type {InitFragment[]} */ @@ -120,6 +121,7 @@ class AsyncWebAssemblyJavascriptGenerator extends Generator { asiSafe: true, isCall: false, callContext: false, + defaultInterop: true, importVar, initFragments, runtimeRequirements @@ -143,7 +145,7 @@ class AsyncWebAssemblyJavascriptGenerator extends Generator { : undefined; const instantiateCall = - `${RuntimeGlobals.instantiateWasm}(${module.exportsArgument}, ${module.moduleArgument}.i` + + `${RuntimeGlobals.instantiateWasm}(${module.exportsArgument}, ${module.moduleArgument}.id` + (importsObj ? `, ${importsObj})` : `)`); const source = new RawSource( diff --git a/lib/wasm/WebAssemblyJavascriptGenerator.js b/lib/wasm/WebAssemblyJavascriptGenerator.js index 697654ec4..a0912689c 100644 --- a/lib/wasm/WebAssemblyJavascriptGenerator.js +++ b/lib/wasm/WebAssemblyJavascriptGenerator.js @@ -100,6 +100,7 @@ class WebAssemblyJavascriptGenerator extends Generator { asiSafe: true, isCall: false, callContext: null, + defaultInterop: true, initFragments, runtimeRequirements }) @@ -127,6 +128,7 @@ class WebAssemblyJavascriptGenerator extends Generator { asiSafe: true, isCall: false, callContext: null, + defaultInterop: true, initFragments, runtimeRequirements })};`, @@ -164,6 +166,7 @@ class WebAssemblyJavascriptGenerator extends Generator { // need these globals runtimeRequirements.add(RuntimeGlobals.module); + runtimeRequirements.add(RuntimeGlobals.moduleId); runtimeRequirements.add(RuntimeGlobals.wasmInstances); if (exportsInfo.otherExportsInfo.used !== UsageState.Unused) { runtimeRequirements.add(RuntimeGlobals.makeNamespaceObject); @@ -178,7 +181,7 @@ class WebAssemblyJavascriptGenerator extends Generator { [ '"use strict";', "// Instantiate WebAssembly module", - `var wasmExports = ${RuntimeGlobals.wasmInstances}[${module.moduleArgument}.i];`, + `var wasmExports = ${RuntimeGlobals.wasmInstances}[${module.moduleArgument}.id];`, exportsInfo.otherExportsInfo.used !== UsageState.Unused ? `${RuntimeGlobals.makeNamespaceObject}(${module.exportsArgument});` diff --git a/test/Errors.test.js b/test/Errors.test.js index 7a3a1442a..c7ca783f6 100644 --- a/test/Errors.test.js +++ b/test/Errors.test.js @@ -188,7 +188,7 @@ it("should emit warning for require.main.require", async () => { "errors": Array [], "warnings": Array [ Object { - "loc": "1:0-20", + "loc": "1:0-30", "message": "require.main.require is not supported by webpack.", "moduleId": 0, "moduleIdentifier": "/test/fixtures/errors/require.main.require.js", @@ -207,7 +207,7 @@ it("should emit warning for module.parent.require", async () => { "errors": Array [], "warnings": Array [ Object { - "loc": "1:0-21", + "loc": "1:0-31", "message": "module.parent.require is not supported by webpack.", "moduleId": 0, "moduleIdentifier": "/test/fixtures/errors/module.parent.require.js", diff --git a/test/Stats.test.js b/test/Stats.test.js index db5de492b..b8a23a627 100644 --- a/test/Stats.test.js +++ b/test/Stats.test.js @@ -202,10 +202,10 @@ describe("Stats", () => { "comparedForEmit": false, "emitted": true, "info": Object { - "size": 198, + "size": 182, }, "name": "entryA.js", - "size": 198, + "size": 182, }, Object { "auxiliaryChunkIdHints": Array [], @@ -217,10 +217,10 @@ describe("Stats", () => { "comparedForEmit": false, "emitted": true, "info": Object { - "size": 1881, + "size": 1865, }, "name": "entryB.js", - "size": 1881, + "size": 1865, }, ], "assetsByChunkName": Object { diff --git a/test/__snapshots__/StatsTestCases.test.js.snap b/test/__snapshots__/StatsTestCases.test.js.snap index 4adbec241..4fac74991 100644 --- a/test/__snapshots__/StatsTestCases.test.js.snap +++ b/test/__snapshots__/StatsTestCases.test.js.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`StatsTestCases should print correct stats for aggressive-splitting-entry 1`] = ` -"Hash: 3e9a5156d285240100f86c0a654fac4022388023 +"Hash: 31d55881a19b3d2759ff5cdd6b7270331317c7f6 Child fitting: - Hash: 3e9a5156d285240100f8 + Hash: 31d55881a19b3d2759ff Time: Xms Built at: 1970-04-20 12:42:42 PublicPath: (none) @@ -11,9 +11,9 @@ Child fitting: fitting-1e85d2c6a3bb53369456.js 1.91 KiB [emitted] [immutable] fitting-32fa512a201604f3e8b7.js 1.08 KiB [emitted] [immutable] fitting-64ea4fa3fe9d8c4817d8.js 1.91 KiB [emitted] [immutable] - fitting-924d7c5cc437ae97bc00.js 13 KiB [emitted] [immutable] - Entrypoint main = fitting-1e85d2c6a3bb53369456.js fitting-64ea4fa3fe9d8c4817d8.js fitting-924d7c5cc437ae97bc00.js - chunk fitting-924d7c5cc437ae97bc00.js 1.87 KiB (javascript) 6.44 KiB (runtime) [entry] [rendered] + fitting-7b2cab993ce99b4797fe.js 13 KiB [emitted] [immutable] + Entrypoint main = fitting-1e85d2c6a3bb53369456.js fitting-64ea4fa3fe9d8c4817d8.js fitting-7b2cab993ce99b4797fe.js + chunk fitting-7b2cab993ce99b4797fe.js 1.87 KiB (javascript) 6.44 KiB (runtime) [entry] [rendered] > ./index main ./e.js 899 bytes [built] ./f.js 900 bytes [built] @@ -31,17 +31,17 @@ Child fitting: > ./g ./index.js 7:0-13 ./g.js 916 bytes [built] Child content-change: - Hash: 6c0a654fac4022388023 + Hash: 5cdd6b7270331317c7f6 Time: Xms Built at: 1970-04-20 12:42:42 PublicPath: (none) Asset Size content-change-1e85d2c6a3bb53369456.js 1.91 KiB [emitted] [immutable] - content-change-21dae9f8fb83a384de5a.js 13 KiB [emitted] [immutable] content-change-32fa512a201604f3e8b7.js 1.08 KiB [emitted] [immutable] content-change-64ea4fa3fe9d8c4817d8.js 1.91 KiB [emitted] [immutable] - Entrypoint main = content-change-1e85d2c6a3bb53369456.js content-change-64ea4fa3fe9d8c4817d8.js content-change-21dae9f8fb83a384de5a.js - chunk content-change-21dae9f8fb83a384de5a.js 1.87 KiB (javascript) 6.45 KiB (runtime) [entry] [rendered] + content-change-7e58af86a6d19030ceaa.js 13 KiB [emitted] [immutable] + Entrypoint main = content-change-1e85d2c6a3bb53369456.js content-change-64ea4fa3fe9d8c4817d8.js content-change-7e58af86a6d19030ceaa.js + chunk content-change-7e58af86a6d19030ceaa.js 1.87 KiB (javascript) 6.45 KiB (runtime) [entry] [rendered] > ./index main ./e.js 899 bytes [built] ./f.js 900 bytes [built] @@ -61,7 +61,7 @@ Child content-change: `; exports[`StatsTestCases should print correct stats for aggressive-splitting-on-demand 1`] = ` -"Hash: 1f444a718517af4d97d0 +"Hash: 291229eefd3fe9850e83 Time: Xms Built at: 1970-04-20 12:42:42 PublicPath: (none) @@ -70,7 +70,7 @@ PublicPath: (none) 21fd8e73389271e24957.js 1.91 KiB [emitted] [immutable] 64ea4fa3fe9d8c4817d8.js 1.91 KiB [emitted] [immutable] 6a2a05a9feb43a535129.js 1.91 KiB [emitted] [immutable] -adff9df7a105cc65b63f.js 9.39 KiB [emitted] [immutable] [name: main] +7dc5d02991fa5ab5ee39.js 9.34 KiB [emitted] [immutable] [name: main] ae7ced4135ed4f2282f6.js 1.91 KiB [emitted] [immutable] b4a95c5544295741de67.js 1010 bytes [emitted] [immutable] b63bab94d02c84e0f081.js 1.91 KiB [emitted] [immutable] @@ -78,12 +78,12 @@ db9a189ff52c97050941.js 1.91 KiB [emitted] [immutable] de61daf57f7861bbb2f6.js 1.91 KiB [emitted] [immutable] f80243284f4ab491b78e.js 1.91 KiB [emitted] [immutable] fb5a5560e641649a6ed8.js 1010 bytes [emitted] [immutable] -Entrypoint main = adff9df7a105cc65b63f.js +Entrypoint main = 7dc5d02991fa5ab5ee39.js chunk 64ea4fa3fe9d8c4817d8.js 1.76 KiB [rendered] [recorded] aggressive splitted > ./c ./d ./e ./index.js 3:0-30 ./c.js 899 bytes [built] ./d.js 899 bytes [built] -chunk adff9df7a105cc65b63f.js (main) 248 bytes (javascript) 4.55 KiB (runtime) [entry] [rendered] +chunk 7dc5d02991fa5ab5ee39.js (main) 248 bytes (javascript) 4.55 KiB (runtime) [entry] [rendered] > ./index main ./index.js 248 bytes [built] + 5 hidden chunk modules @@ -131,13 +131,13 @@ chunk b4a95c5544295741de67.js 899 bytes [rendered] `; exports[`StatsTestCases should print correct stats for asset 1`] = ` -"Hash: f6c1cb50597248a12805 +"Hash: af0de91ff8df9396500e Time: Xms Built at: 1970-04-20 12:42:42 Asset Size -7095cdad7dbe7d0415ca.png 14.6 KiB [emitted] [immutable] [name: (main)] - bundle.js 10.7 KiB [emitted] [name: main] -Entrypoint main = bundle.js (7095cdad7dbe7d0415ca.png) +6eef074bdaf47143a239.png 14.6 KiB [emitted] [immutable] [name: (main)] + bundle.js 10.6 KiB [emitted] [name: main] +Entrypoint main = bundle.js (6eef074bdaf47143a239.png) ./index.js 111 bytes [built] ./images/file.png 42 bytes (javascript) 14.6 KiB (asset) [built] ./images/file.svg 915 bytes [built] @@ -445,13 +445,13 @@ Child all: `; exports[`StatsTestCases should print correct stats for chunk-module-id-range 1`] = ` -"Hash: fb5c63d2e82f70b6a022 +"Hash: 024b7b1350be3708ba8e Time: Xms Built at: 1970-04-20 12:42:42 PublicPath: (none) Asset Size -main1.js 4.44 KiB [emitted] [name: main1] -main2.js 4.43 KiB [emitted] [name: main2] +main1.js 4.39 KiB [emitted] [name: main1] +main2.js 4.38 KiB [emitted] [name: main2] Entrypoint main1 = main1.js Entrypoint main2 = main2.js chunk main2.js (main2) 136 bytes (javascript) 668 bytes (runtime) [entry] [rendered] @@ -473,7 +473,7 @@ chunk main1.js (main1) 136 bytes (javascript) 668 bytes (runtime) [entry] [rende `; exports[`StatsTestCases should print correct stats for chunks 1`] = ` -"Hash: f7bc9eacfcfa73a582b4 +"Hash: 8aa3985794dcb0a9189a Time: Xms Built at: 1970-04-20 12:42:42 PublicPath: (none) @@ -481,11 +481,12 @@ PublicPath: (none) 460.bundle.js 324 bytes [emitted] 524.bundle.js 210 bytes [emitted] 996.bundle.js 142 bytes [emitted] - bundle.js 7.91 KiB [emitted] [name: main] + bundle.js 7.86 KiB [emitted] [name: main] Entrypoint main = bundle.js chunk bundle.js (main) 73 bytes (javascript) 4.25 KiB (runtime) >{460}< >{996}< [entry] [rendered] > ./index main ./a.js 22 bytes [built] + cjs self exports reference ./a.js 1:0-14 cjs require ./a ./index.js 1:0-14 Xms -> Xms (resolving: Xms, restoring: Xms, integration: Xms, building: Xms, storing: Xms) ./index.js 51 bytes [built] @@ -501,31 +502,35 @@ chunk 524.bundle.js 44 bytes <{460}> [rendered] > ./c.js 1:0-52 ./d.js 22 bytes [built] require.ensure item ./d ./c.js 1:0-52 + cjs self exports reference ./d.js 1:0-14 Xms -> Xms -> Xms (resolving: Xms, restoring: Xms, integration: Xms, building: Xms, storing: Xms) ./e.js 22 bytes [built] require.ensure item ./e ./c.js 1:0-52 + cjs self exports reference ./e.js 1:0-14 Xms -> Xms -> Xms (resolving: Xms, restoring: Xms, integration: Xms, building: Xms, storing: Xms) chunk 996.bundle.js 22 bytes <{179}> [rendered] > ./b ./index.js 2:0-16 ./b.js 22 bytes [built] + cjs self exports reference ./b.js 1:0-14 amd require ./b ./index.js 2:0-16 Xms -> Xms (resolving: Xms, restoring: Xms, integration: Xms, building: Xms, storing: Xms)" `; exports[`StatsTestCases should print correct stats for chunks-development 1`] = ` -"Hash: bed3963e09b8f3d8b779 +"Hash: bb9c09a55e8e0ee99069 Time: Xms Built at: 1970-04-20 12:42:42 PublicPath: (none) Asset Size - b_js.bundle.js 359 bytes [emitted] - bundle.js 8.49 KiB [emitted] [name: main] - c_js.bundle.js 588 bytes [emitted] -d_js-e_js.bundle.js 759 bytes [emitted] + b_js.bundle.js 400 bytes [emitted] + bundle.js 8.52 KiB [emitted] [name: main] + c_js.bundle.js 629 bytes [emitted] +d_js-e_js.bundle.js 841 bytes [emitted] Entrypoint main = bundle.js chunk b_js.bundle.js 22 bytes <{main}> [rendered] > ./b ./index.js 2:0-16 ./b.js 22 bytes [built] + cjs self exports reference ./b.js 1:0-14 amd require ./b ./index.js 2:0-16 Xms -> Xms (resolving: Xms, restoring: Xms, integration: Xms, building: Xms, storing: Xms) chunk c_js.bundle.js 54 bytes <{main}> >{d_js-e_js}< [rendered] @@ -537,13 +542,16 @@ chunk d_js-e_js.bundle.js 60 bytes <{c_js}> [rendered] > ./c.js 1:0-52 ./d.js 22 bytes [built] require.ensure item ./d ./c.js 1:0-52 + cjs self exports reference ./d.js 1:0-14 Xms -> Xms -> Xms (resolving: Xms, restoring: Xms, integration: Xms, building: Xms, storing: Xms) ./e.js 38 bytes [built] require.ensure item ./e ./c.js 1:0-52 + cjs self exports reference ./e.js 2:0-14 Xms -> Xms -> Xms (resolving: Xms, restoring: Xms, integration: Xms, building: Xms, storing: Xms) chunk bundle.js (main) 73 bytes (javascript) 4.25 KiB (runtime) >{b_js}< >{c_js}< [entry] [rendered] > ./index main ./a.js 22 bytes [built] + cjs self exports reference ./a.js 1:0-14 cjs require ./a ./e.js 1:0-14 cjs require ./a ./index.js 1:0-14 Xms -> Xms (resolving: Xms, restoring: Xms, integration: Xms, building: Xms, storing: Xms) @@ -597,12 +605,12 @@ Entrypoint main = main.js `; exports[`StatsTestCases should print correct stats for commons-chunk-min-size-0 1`] = ` -"Hash: c78165fa4b8e1f543b90 +"Hash: 52d6ddbdf7da6ee8696f Time: Xms Built at: 1970-04-20 12:42:42 Asset Size 429.js 278 bytes [emitted] [id hint: vendor-1] -entry-1.js 5.37 KiB [emitted] [name: entry-1] +entry-1.js 5.32 KiB [emitted] [name: entry-1] Entrypoint entry-1 = 429.js entry-1.js ./entry-1.js 145 bytes [built] ./modules/a.js 22 bytes [built] @@ -615,11 +623,11 @@ Entrypoint entry-1 = 429.js entry-1.js `; exports[`StatsTestCases should print correct stats for commons-chunk-min-size-Infinity 1`] = ` -"Hash: e1811e7bd2b08fe91369 +"Hash: 1ac8d9f0a39f52c3c2a6 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size - entry-1.js 5.37 KiB [emitted] [name: entry-1] + entry-1.js 5.32 KiB [emitted] [name: entry-1] vendor-1.js 278 bytes [emitted] [name: vendor-1] [id hint: vendor-1] Entrypoint entry-1 = vendor-1.js entry-1.js ./entry-1.js 145 bytes [built] @@ -633,26 +641,26 @@ Entrypoint entry-1 = vendor-1.js entry-1.js `; exports[`StatsTestCases should print correct stats for commons-plugin-issue-4980 1`] = ` -"Hash: f574fa9691641230a92dbf35dda4a5870c2b90b4 +"Hash: cc1067a9ed68395a22d361ebf4f77d289ef5d090 Child - Hash: f574fa9691641230a92d + Hash: cc1067a9ed68395a22d3 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size - app.6a509d33476291bd4b84-1.js 5.91 KiB [emitted] [immutable] [name: app] - vendor.6b4bbfa3863de7632c2b-1.js 615 bytes [emitted] [immutable] [name: vendor] [id hint: vendor] - Entrypoint app = vendor.6b4bbfa3863de7632c2b-1.js app.6a509d33476291bd4b84-1.js + app.e7c3ca90761b75404b15-1.js 5.86 KiB [emitted] [immutable] [name: app] + vendor.611fd9bad8fe7de29fe7-1.js 615 bytes [emitted] [immutable] [name: vendor] [id hint: vendor] + Entrypoint app = vendor.611fd9bad8fe7de29fe7-1.js app.e7c3ca90761b75404b15-1.js ./entry-1.js + 2 modules 190 bytes [built] ./constants.js 87 bytes [built] + 3 hidden modules Child - Hash: bf35dda4a5870c2b90b4 + Hash: 61ebf4f77d289ef5d090 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size - app.3e294cabb068ca84e0dc-2.js 5.92 KiB [emitted] [immutable] [name: app] - vendor.6b4bbfa3863de7632c2b-2.js 615 bytes [emitted] [immutable] [name: vendor] [id hint: vendor] - Entrypoint app = vendor.6b4bbfa3863de7632c2b-2.js app.3e294cabb068ca84e0dc-2.js + app.3543b1c65e6a5b58cae6-2.js 5.87 KiB [emitted] [immutable] [name: app] + vendor.611fd9bad8fe7de29fe7-2.js 615 bytes [emitted] [immutable] [name: vendor] [id hint: vendor] + Entrypoint app = vendor.611fd9bad8fe7de29fe7-2.js app.3543b1c65e6a5b58cae6-2.js ./entry-2.js + 2 modules 197 bytes [built] ./constants.js 87 bytes [built] + 3 hidden modules" @@ -676,81 +684,81 @@ exports[`StatsTestCases should print correct stats for concat-and-sideeffects 1` `; exports[`StatsTestCases should print correct stats for context-independence 1`] = ` -"Hash: 3c160984a980dac95b913c160984a980dac95b9111fdc8efed5dc9a0356111fdc8efed5dc9a03561 +"Hash: 6506665a35d2ca5d31ac6506665a35d2ca5d31accf181f0e0e06350b116acf181f0e0e06350b116a Child - Hash: 3c160984a980dac95b91 + Hash: 6506665a35d2ca5d31ac Time: Xms Built at: 1970-04-20 12:42:42 Asset Size - 703-31a50198ea37e1d30825.js 438 bytes [emitted] [immutable] - 703-31a50198ea37e1d30825.js.map 343 bytes [emitted] [dev] - main-4124fe68a732c1b5d1ad.js 8.18 KiB [emitted] [immutable] [name: main] - main-4124fe68a732c1b5d1ad.js.map 7.23 KiB [emitted] [dev] [name: (main)] - Entrypoint main = main-4124fe68a732c1b5d1ad.js (main-4124fe68a732c1b5d1ad.js.map) + 703-3e2afd6460ceb1cd6f5f.js 438 bytes [emitted] [immutable] + 703-3e2afd6460ceb1cd6f5f.js.map 343 bytes [emitted] [dev] + main-a1003986d61ab330d2c5.js 8.14 KiB [emitted] [immutable] [name: main] + main-a1003986d61ab330d2c5.js.map 7.2 KiB [emitted] [dev] [name: (main)] + Entrypoint main = main-a1003986d61ab330d2c5.js (main-a1003986d61ab330d2c5.js.map) ./a/index.js 40 bytes [built] ./a/chunk.js + 1 modules 66 bytes [built] + 6 hidden modules Child - Hash: 3c160984a980dac95b91 + Hash: 6506665a35d2ca5d31ac Time: Xms Built at: 1970-04-20 12:42:42 Asset Size - 703-31a50198ea37e1d30825.js 438 bytes [emitted] [immutable] - 703-31a50198ea37e1d30825.js.map 343 bytes [emitted] [dev] - main-4124fe68a732c1b5d1ad.js 8.18 KiB [emitted] [immutable] [name: main] - main-4124fe68a732c1b5d1ad.js.map 7.23 KiB [emitted] [dev] [name: (main)] - Entrypoint main = main-4124fe68a732c1b5d1ad.js (main-4124fe68a732c1b5d1ad.js.map) + 703-3e2afd6460ceb1cd6f5f.js 438 bytes [emitted] [immutable] + 703-3e2afd6460ceb1cd6f5f.js.map 343 bytes [emitted] [dev] + main-a1003986d61ab330d2c5.js 8.14 KiB [emitted] [immutable] [name: main] + main-a1003986d61ab330d2c5.js.map 7.2 KiB [emitted] [dev] [name: (main)] + Entrypoint main = main-a1003986d61ab330d2c5.js (main-a1003986d61ab330d2c5.js.map) ./b/index.js 40 bytes [built] ./b/chunk.js + 1 modules 66 bytes [built] + 6 hidden modules Child - Hash: 11fdc8efed5dc9a03561 + Hash: cf181f0e0e06350b116a Time: Xms Built at: 1970-04-20 12:42:42 Asset Size - 703-71c02d17a0d4fdf148ec.js 962 bytes [emitted] [immutable] - main-105b1b44c9785e4fec51.js 8.52 KiB [emitted] [immutable] [name: main] - Entrypoint main = main-105b1b44c9785e4fec51.js + 703-d51a9ad771055bba3447.js 962 bytes [emitted] [immutable] + main-f8577eeb56b10147974d.js 8.48 KiB [emitted] [immutable] [name: main] + Entrypoint main = main-f8577eeb56b10147974d.js ./a/index.js 40 bytes [built] ./a/chunk.js + 1 modules 66 bytes [built] + 6 hidden modules Child - Hash: 11fdc8efed5dc9a03561 + Hash: cf181f0e0e06350b116a Time: Xms Built at: 1970-04-20 12:42:42 Asset Size - 703-71c02d17a0d4fdf148ec.js 962 bytes [emitted] [immutable] - main-105b1b44c9785e4fec51.js 8.52 KiB [emitted] [immutable] [name: main] - Entrypoint main = main-105b1b44c9785e4fec51.js + 703-d51a9ad771055bba3447.js 962 bytes [emitted] [immutable] + main-f8577eeb56b10147974d.js 8.48 KiB [emitted] [immutable] [name: main] + Entrypoint main = main-f8577eeb56b10147974d.js ./b/index.js 40 bytes [built] ./b/chunk.js + 1 modules 66 bytes [built] + 6 hidden modules" `; exports[`StatsTestCases should print correct stats for define-plugin 1`] = ` -"Hash: d3bf22fe31b2dd574a379f4263d8fe2702bed0c5263ccfc8da5389b5549d +"Hash: c4dfb63f41372476179f8a83bd0cdb16b7f71a200e0127ecbe2c521924dd Child - Hash: d3bf22fe31b2dd574a37 + Hash: c4dfb63f41372476179f Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - 123.js 1.33 KiB [emitted] [name: main] + Asset Size + 123.js 1.3 KiB [emitted] [name: main] Entrypoint main = 123.js ./index.js 24 bytes [built] Child - Hash: 9f4263d8fe2702bed0c5 + Hash: 8a83bd0cdb16b7f71a20 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - 321.js 1.33 KiB [emitted] [name: main] + Asset Size + 321.js 1.3 KiB [emitted] [name: main] Entrypoint main = 321.js ./index.js 24 bytes [built] Child - Hash: 263ccfc8da5389b5549d + Hash: 0e0127ecbe2c521924dd Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - both.js 1.33 KiB [emitted] [name: main] + Asset Size + both.js 1.3 KiB [emitted] [name: main] Entrypoint main = both.js ./index.js 24 bytes [built]" `; @@ -779,11 +787,11 @@ Unexpected end of JSON input while parsing near '' `; exports[`StatsTestCases should print correct stats for exclude-with-loader 1`] = ` -"Hash: 44a857698e21eeb6ec4a +"Hash: 574b1154129671ae12ac Time: Xms Built at: 1970-04-20 12:42:42 Asset Size -bundle.js 3.51 KiB [emitted] [name: main] +bundle.js 3.46 KiB [emitted] [name: main] + 1 hidden asset Entrypoint main = bundle.js (5bcd36918d225eeda398ea3f372b7f16.json) ./index.js 77 bytes [built] @@ -792,24 +800,24 @@ Entrypoint main = bundle.js (5bcd36918d225eeda398ea3f372b7f16.json) `; exports[`StatsTestCases should print correct stats for external 1`] = ` -"Hash: 5607d9fc220b23d6ba41 +"Hash: e1259a13508c6d1d1e0c Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size -main.js 1.25 KiB [emitted] [name: main] + Asset Size +main.js 1.2 KiB [emitted] [name: main] Entrypoint main = main.js ./index.js 17 bytes [built] external \\"test\\" 42 bytes [built]" `; exports[`StatsTestCases should print correct stats for filter-warnings 1`] = ` -"Hash: 2e946c1b63d5a742a8ff2e946c1b63d5a742a8ff2e946c1b63d5a742a8ff2e946c1b63d5a742a8ff2e946c1b63d5a742a8ff2e946c1b63d5a742a8ff2e946c1b63d5a742a8ff2e946c1b63d5a742a8ff2e946c1b63d5a742a8ff2e946c1b63d5a742a8ff2e946c1b63d5a742a8ff2e946c1b63d5a742a8ff2e946c1b63d5a742a8ff +"Hash: 9c6e8f427e9f60ed33269c6e8f427e9f60ed33269c6e8f427e9f60ed33269c6e8f427e9f60ed33269c6e8f427e9f60ed33269c6e8f427e9f60ed33269c6e8f427e9f60ed33269c6e8f427e9f60ed33269c6e8f427e9f60ed33269c6e8f427e9f60ed33269c6e8f427e9f60ed33269c6e8f427e9f60ed33269c6e8f427e9f60ed3326 Child undefined: - Hash: 2e946c1b63d5a742a8ff + Hash: 9c6e8f427e9f60ed3326 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - bundle0.js 1010 bytes [emitted] [name: main] + Asset Size + bundle0.js 556 bytes [emitted] [name: main] Entrypoint main = bundle0.js WARNING in Terser Plugin: Dropping unused function someRemoteUnUsedFunction1 [webpack://./a.js:3,0] @@ -835,53 +843,53 @@ Child undefined: WARNING in Terser Plugin: Dropping unused function someUnUsedFunction5 [webpack://./index.js:12,0] Child Terser: - Hash: 2e946c1b63d5a742a8ff + Hash: 9c6e8f427e9f60ed3326 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - bundle1.js 1010 bytes [emitted] [name: main] + Asset Size + bundle1.js 556 bytes [emitted] [name: main] Entrypoint main = bundle1.js Child /Terser/: - Hash: 2e946c1b63d5a742a8ff + Hash: 9c6e8f427e9f60ed3326 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - bundle2.js 1010 bytes [emitted] [name: main] + Asset Size + bundle2.js 556 bytes [emitted] [name: main] Entrypoint main = bundle2.js Child warnings => true: - Hash: 2e946c1b63d5a742a8ff + Hash: 9c6e8f427e9f60ed3326 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - bundle3.js 1010 bytes [emitted] [name: main] + Asset Size + bundle3.js 556 bytes [emitted] [name: main] Entrypoint main = bundle3.js Child [Terser]: - Hash: 2e946c1b63d5a742a8ff + Hash: 9c6e8f427e9f60ed3326 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - bundle4.js 1010 bytes [emitted] [name: main] + Asset Size + bundle4.js 556 bytes [emitted] [name: main] Entrypoint main = bundle4.js Child [/Terser/]: - Hash: 2e946c1b63d5a742a8ff + Hash: 9c6e8f427e9f60ed3326 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - bundle5.js 1010 bytes [emitted] [name: main] + Asset Size + bundle5.js 556 bytes [emitted] [name: main] Entrypoint main = bundle5.js Child [warnings => true]: - Hash: 2e946c1b63d5a742a8ff + Hash: 9c6e8f427e9f60ed3326 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - bundle6.js 1010 bytes [emitted] [name: main] + Asset Size + bundle6.js 556 bytes [emitted] [name: main] Entrypoint main = bundle6.js Child should not filter: - Hash: 2e946c1b63d5a742a8ff + Hash: 9c6e8f427e9f60ed3326 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - bundle7.js 1010 bytes [emitted] [name: main] + Asset Size + bundle7.js 556 bytes [emitted] [name: main] Entrypoint main = bundle7.js WARNING in Terser Plugin: Dropping unused function someRemoteUnUsedFunction1 [webpack://./a.js:3,0] @@ -907,11 +915,11 @@ Child should not filter: WARNING in Terser Plugin: Dropping unused function someUnUsedFunction5 [webpack://./index.js:12,0] Child /should not filter/: - Hash: 2e946c1b63d5a742a8ff + Hash: 9c6e8f427e9f60ed3326 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - bundle8.js 1010 bytes [emitted] [name: main] + Asset Size + bundle8.js 556 bytes [emitted] [name: main] Entrypoint main = bundle8.js WARNING in Terser Plugin: Dropping unused function someRemoteUnUsedFunction1 [webpack://./a.js:3,0] @@ -937,11 +945,11 @@ Child /should not filter/: WARNING in Terser Plugin: Dropping unused function someUnUsedFunction5 [webpack://./index.js:12,0] Child warnings => false: - Hash: 2e946c1b63d5a742a8ff + Hash: 9c6e8f427e9f60ed3326 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - bundle9.js 1010 bytes [emitted] [name: main] + Asset Size + bundle9.js 556 bytes [emitted] [name: main] Entrypoint main = bundle9.js WARNING in Terser Plugin: Dropping unused function someRemoteUnUsedFunction1 [webpack://./a.js:3,0] @@ -967,11 +975,11 @@ Child warnings => false: WARNING in Terser Plugin: Dropping unused function someUnUsedFunction5 [webpack://./index.js:12,0] Child [should not filter]: - Hash: 2e946c1b63d5a742a8ff + Hash: 9c6e8f427e9f60ed3326 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - bundle10.js 1010 bytes [emitted] [name: main] + Asset Size + bundle10.js 556 bytes [emitted] [name: main] Entrypoint main = bundle10.js WARNING in Terser Plugin: Dropping unused function someRemoteUnUsedFunction1 [webpack://./a.js:3,0] @@ -997,11 +1005,11 @@ Child [should not filter]: WARNING in Terser Plugin: Dropping unused function someUnUsedFunction5 [webpack://./index.js:12,0] Child [/should not filter/]: - Hash: 2e946c1b63d5a742a8ff + Hash: 9c6e8f427e9f60ed3326 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - bundle11.js 1010 bytes [emitted] [name: main] + Asset Size + bundle11.js 556 bytes [emitted] [name: main] Entrypoint main = bundle11.js WARNING in Terser Plugin: Dropping unused function someRemoteUnUsedFunction1 [webpack://./a.js:3,0] @@ -1027,11 +1035,11 @@ Child [/should not filter/]: WARNING in Terser Plugin: Dropping unused function someUnUsedFunction5 [webpack://./index.js:12,0] Child [warnings => false]: - Hash: 2e946c1b63d5a742a8ff + Hash: 9c6e8f427e9f60ed3326 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size - bundle12.js 1010 bytes [emitted] [name: main] + Asset Size + bundle12.js 556 bytes [emitted] [name: main] Entrypoint main = bundle12.js WARNING in Terser Plugin: Dropping unused function someRemoteUnUsedFunction1 [webpack://./a.js:3,0] @@ -1153,19 +1161,19 @@ chunk trees.js (trees) 71 bytes [rendered] exports[`StatsTestCases should print correct stats for immutable 1`] = ` " Asset Size -1b847d037d2872a4c68b.js 346 bytes [emitted] [immutable] -945fb1b905025df1339f.js 9.88 KiB [emitted] [immutable] [name: main]" +1b847d037d2872a4c68b.js 387 bytes [emitted] [immutable] +945fb1b905025df1339f.js 9.87 KiB [emitted] [immutable] [name: main]" `; exports[`StatsTestCases should print correct stats for import-context-filter 1`] = ` -"Hash: fde587e1bdf604f24e67 +"Hash: 60c4e631146a1ea0f372 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size 398.js 484 bytes [emitted] 544.js 484 bytes [emitted] 718.js 484 bytes [emitted] -entry.js 9.61 KiB [emitted] [name: entry] +entry.js 9.56 KiB [emitted] [name: entry] Entrypoint entry = entry.js ./entry.js 450 bytes [built] ./templates lazy ^\\\\.\\\\/.*$ include: \\\\.js$ exclude: \\\\.noimport\\\\.js$ namespace object 160 bytes [optional] [built] @@ -1176,7 +1184,7 @@ Entrypoint entry = entry.js `; exports[`StatsTestCases should print correct stats for import-weak 1`] = ` -"Hash: 413c9966016a5c6b709a +"Hash: 7160e41d3347e9709803 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size @@ -1213,42 +1221,42 @@ Compilation error while processing magic comment(-s): /* webpackPrefetch: nope * `; exports[`StatsTestCases should print correct stats for issue-7577 1`] = ` -"Hash: db17495307f9577cdf0574f8b47a2c1a85c2641ba52e42c5fb5bcb0d0cc1 +"Hash: 94b82a2154c061cc7c6bb42f5fd308c78eb622dd3f7a76e8638213c06464 Child - Hash: db17495307f9577cdf05 + Hash: 94b82a2154c061cc7c6b Time: Xms Built at: 1970-04-20 12:42:42 Asset Size a-all-a_js-a0ca01d3da48ab4385f6.js 144 bytes [emitted] [immutable] [id hint: all] a-main-fa06855251b873131c2c.js 115 bytes [emitted] [immutable] [name: main] - a-runtime~main-58c0c5b1e0b10f369a33.js 4.93 KiB [emitted] [immutable] [name: runtime~main] - Entrypoint main = a-runtime~main-58c0c5b1e0b10f369a33.js a-all-a_js-a0ca01d3da48ab4385f6.js a-main-fa06855251b873131c2c.js + a-runtime~main-286640ef21ec9cc6b07a.js 4.88 KiB [emitted] [immutable] [name: runtime~main] + Entrypoint main = a-runtime~main-286640ef21ec9cc6b07a.js a-all-a_js-a0ca01d3da48ab4385f6.js a-main-fa06855251b873131c2c.js ./a.js 18 bytes [built] + 2 hidden modules Child - Hash: 74f8b47a2c1a85c2641b + Hash: b42f5fd308c78eb622dd Time: Xms Built at: 1970-04-20 12:42:42 Asset Size - b-all-b_js-3219344d13cc334d7831.js 479 bytes [emitted] [immutable] [id hint: all] - b-main-6da637b8d22f213c8475.js 148 bytes [emitted] [immutable] [name: main] - b-runtime~main-79835f2c8b4a4d8e8e21.js 5.86 KiB [emitted] [immutable] [name: runtime~main] + b-all-b_js-50bf184dfe57dc2022a6.js 479 bytes [emitted] [immutable] [id hint: all] + b-main-ffc8dbdfb8f2c2b16817.js 148 bytes [emitted] [immutable] [name: main] + b-runtime~main-a6e42222a1a01acc0438.js 5.81 KiB [emitted] [immutable] [name: runtime~main] b-vendors-node_modules_vendor_js-a51f8ed2c8dc9ce97afd.js 189 bytes [emitted] [immutable] [id hint: vendors] - Entrypoint main = b-runtime~main-79835f2c8b4a4d8e8e21.js b-vendors-node_modules_vendor_js-a51f8ed2c8dc9ce97afd.js b-all-b_js-3219344d13cc334d7831.js b-main-6da637b8d22f213c8475.js + Entrypoint main = b-runtime~main-a6e42222a1a01acc0438.js b-vendors-node_modules_vendor_js-a51f8ed2c8dc9ce97afd.js b-all-b_js-50bf184dfe57dc2022a6.js b-main-ffc8dbdfb8f2c2b16817.js ./b.js 17 bytes [built] ./node_modules/vendor.js 23 bytes [built] + 4 hidden modules Child - Hash: a52e42c5fb5bcb0d0cc1 + Hash: 3f7a76e8638213c06464 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size - c-all-b_js-3219344d13cc334d7831.js 506 bytes [emitted] [immutable] [id hint: all] - c-all-c_js-6756694a5d280748f5a3.js 382 bytes [emitted] [immutable] [id hint: all] + c-all-b_js-50bf184dfe57dc2022a6.js 506 bytes [emitted] [immutable] [id hint: all] + c-all-c_js-6756694a5d280748f5a3.js 397 bytes [emitted] [immutable] [id hint: all] c-main-476756bfcb471445cf2c.js 164 bytes [emitted] [immutable] [name: main] - c-runtime~main-346ca173662bb43e22ef.js 11.4 KiB [emitted] [immutable] [name: runtime~main] + c-runtime~main-912fc4f81a625e30b5f0.js 11.3 KiB [emitted] [immutable] [name: runtime~main] c-vendors-node_modules_vendor_js-a51f8ed2c8dc9ce97afd.js 189 bytes [emitted] [immutable] [id hint: vendors] - Entrypoint main = c-runtime~main-346ca173662bb43e22ef.js c-all-c_js-6756694a5d280748f5a3.js c-main-476756bfcb471445cf2c.js (prefetch: c-vendors-node_modules_vendor_js-a51f8ed2c8dc9ce97afd.js c-all-b_js-3219344d13cc334d7831.js) + Entrypoint main = c-runtime~main-912fc4f81a625e30b5f0.js c-all-c_js-6756694a5d280748f5a3.js c-main-476756bfcb471445cf2c.js (prefetch: c-vendors-node_modules_vendor_js-a51f8ed2c8dc9ce97afd.js c-all-b_js-50bf184dfe57dc2022a6.js) ./c.js 61 bytes [built] ./b.js 17 bytes [built] ./node_modules/vendor.js 23 bytes [built] @@ -1256,13 +1264,13 @@ Child `; exports[`StatsTestCases should print correct stats for limit-chunk-count-plugin 1`] = ` -"Hash: a0800a69d4b65916acc0edef925c59c09542572206d0ef7ed1356dcf7ae27c24a1e7619f90a97b8a +"Hash: 15b4b06d5bdcf1dbb317c2ee020bd44fb8139f6b23dbaedcbaa797e2000666278eec152159ba577e Child 1 chunks: - Hash: a0800a69d4b65916acc0 + Hash: 15b4b06d5bdcf1dbb317 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size - bundle1.js 4.19 KiB [emitted] [name: main] + bundle1.js 4.14 KiB [emitted] [name: main] Entrypoint main = bundle1.js chunk bundle1.js (main) 219 bytes (javascript) 1.32 KiB (runtime) <{179}> >{179}< [entry] [rendered] ./a.js 22 bytes [built] @@ -1273,12 +1281,12 @@ Child 1 chunks: ./index.js 101 bytes [built] + 4 hidden chunk modules Child 2 chunks: - Hash: edef925c59c095425722 + Hash: c2ee020bd44fb8139f6b Time: Xms Built at: 1970-04-20 12:42:42 Asset Size 459.bundle2.js 666 bytes [emitted] [name: c] - bundle2.js 9.82 KiB [emitted] [name: main] + bundle2.js 9.77 KiB [emitted] [name: main] Entrypoint main = bundle2.js chunk bundle2.js (main) 101 bytes (javascript) 5.48 KiB (runtime) >{459}< [entry] [rendered] ./index.js 101 bytes [built] @@ -1290,13 +1298,13 @@ Child 2 chunks: ./d.js 22 bytes [built] ./e.js 22 bytes [built] Child 3 chunks: - Hash: 06d0ef7ed1356dcf7ae2 + Hash: 23dbaedcbaa797e20006 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size 459.bundle3.js 530 bytes [emitted] [name: c] 524.bundle3.js 210 bytes [emitted] - bundle3.js 9.82 KiB [emitted] [name: main] + bundle3.js 9.77 KiB [emitted] [name: main] Entrypoint main = bundle3.js chunk bundle3.js (main) 101 bytes (javascript) 5.48 KiB (runtime) >{459}< [entry] [rendered] ./index.js 101 bytes [built] @@ -1309,14 +1317,14 @@ Child 3 chunks: ./d.js 22 bytes [built] ./e.js 22 bytes [built] Child 4 chunks: - Hash: 7c24a1e7619f90a97b8a + Hash: 66278eec152159ba577e Time: Xms Built at: 1970-04-20 12:42:42 Asset Size 394.bundle4.js 210 bytes [emitted] 459.bundle4.js 394 bytes [emitted] [name: c] 524.bundle4.js 210 bytes [emitted] - bundle4.js 9.82 KiB [emitted] [name: main] + bundle4.js 9.77 KiB [emitted] [name: main] Entrypoint main = bundle4.js chunk bundle4.js (main) 101 bytes (javascript) 5.48 KiB (runtime) >{394}< >{459}< [entry] [rendered] ./index.js 101 bytes [built] @@ -1374,11 +1382,11 @@ Entrypoint main = main.js `; exports[`StatsTestCases should print correct stats for max-modules 1`] = ` -"Hash: 41d1bca9d8ea1cc53215 +"Hash: 896d8a1d7b73a2ef9139 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size -main.js 5.34 KiB [emitted] [name: main] +main.js 5.29 KiB [emitted] [name: main] Entrypoint main = main.js ./index.js 181 bytes [built] ./a.js?1 33 bytes [built] @@ -1404,11 +1412,11 @@ Entrypoint main = main.js `; exports[`StatsTestCases should print correct stats for max-modules-default 1`] = ` -"Hash: 41d1bca9d8ea1cc53215 +"Hash: 896d8a1d7b73a2ef9139 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size -main.js 5.34 KiB [emitted] [name: main] +main.js 5.29 KiB [emitted] [name: main] Entrypoint main = main.js ./index.js 181 bytes [built] ./a.js?1 33 bytes [built] @@ -1429,7 +1437,7 @@ Entrypoint main = main.js `; exports[`StatsTestCases should print correct stats for module-assets 1`] = ` -"Hash: 6c0e387dd087e95c56bb +"Hash: 7ab754f97dbdb21a19b7 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size @@ -1437,7 +1445,7 @@ Built at: 1970-04-20 12:42:42 2.png 21 KiB [emitted] [name: (a, b)] a.js 988 bytes [emitted] [name: a] b.js 616 bytes [emitted] [name: b] -main.js 9.12 KiB [emitted] [name: main] +main.js 9.1 KiB [emitted] [name: main] Entrypoint main = main.js Chunk Group a = a.js (1.png 2.png) Chunk Group b = b.js (2.png) @@ -1513,12 +1521,12 @@ chunk 923.js 37 bytes [rendered] exports[`StatsTestCases should print correct stats for module-deduplication-named 1`] = ` " Asset Size -async1.js 824 bytes [emitted] [name: async1] -async2.js 824 bytes [emitted] [name: async2] -async3.js 824 bytes [emitted] [name: async3] - e1.js 10.2 KiB [emitted] [name: e1] - e2.js 10.2 KiB [emitted] [name: e2] - e3.js 10.2 KiB [emitted] [name: e3] +async1.js 839 bytes [emitted] [name: async1] +async2.js 839 bytes [emitted] [name: async2] +async3.js 839 bytes [emitted] [name: async3] + e1.js 10.1 KiB [emitted] [name: e1] + e2.js 10.1 KiB [emitted] [name: e2] + e3.js 10.1 KiB [emitted] [name: e3] Entrypoint e1 = e1.js Entrypoint e2 = e2.js Entrypoint e3 = e3.js @@ -1580,11 +1588,11 @@ If you don't want to include a polyfill, you can use an empty module like this: `; exports[`StatsTestCases should print correct stats for module-reasons 1`] = ` -"Hash: c7a7f12c42b568c704da +"Hash: a74cbe7b899ea89c631e Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size -main.js 1.46 KiB [emitted] [name: main] + Asset Size +main.js 1.4 KiB [emitted] [name: main] Entrypoint main = main.js ./index.js + 2 modules 102 bytes [built] entry ./index main @@ -1701,11 +1709,11 @@ Child `; exports[`StatsTestCases should print correct stats for named-chunks-plugin 1`] = ` -"Hash: c2a9265bba5ea48f8d32 +"Hash: 477a050407dcda362944 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size - entry.js 5.24 KiB [emitted] [name: entry] + entry.js 5.19 KiB [emitted] [name: entry] vendor.js 241 bytes [emitted] [name: vendor] [id hint: vendor] Entrypoint entry = vendor.js entry.js ./entry.js 72 bytes [built] @@ -1716,11 +1724,11 @@ Entrypoint entry = vendor.js entry.js `; exports[`StatsTestCases should print correct stats for named-chunks-plugin-async 1`] = ` -"Hash: 5b2d8bf6cb7123270228 +"Hash: b805309f74f84a36f101 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size - entry.js 9.68 KiB [emitted] [name: entry] + entry.js 9.63 KiB [emitted] [name: entry] modules_a_js.js 316 bytes [emitted] modules_b_js.js 153 bytes [emitted] Entrypoint entry = entry.js @@ -1745,7 +1753,7 @@ You can also set it to 'none' to disable any default behavior. Learn more: https `; exports[`StatsTestCases should print correct stats for optimize-chunks 1`] = ` -"Hash: 7311a4db759e711d1ef5 +"Hash: eb848647a72300169555 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size @@ -1756,7 +1764,7 @@ Built at: 1970-04-20 12:42:42 cir1.js 334 bytes [emitted] [name: cir1] cir2 from cir1.js 378 bytes [emitted] [name: cir2 from cir1] cir2.js 334 bytes [emitted] [name: cir2] - main.js 8.71 KiB [emitted] [name: main] + main.js 8.66 KiB [emitted] [name: main] Entrypoint main = main.js chunk ab.js (ab) 2 bytes <{179}> >{753}< [rendered] > ./index.js 1:0-6:8 @@ -1813,9 +1821,9 @@ You may need an appropriate loader to handle this file type, currently no loader `; exports[`StatsTestCases should print correct stats for performance-different-mode-and-target 1`] = ` -"Hash: 085386bf0cb4accbb1eb085386bf0cb4accbb1eb085386bf0cb4accbb1eb1499b9952c8259430fac1499b9952c8259430fac1499b9952c8259430fac085386bf0cb4accbb1eb +"Hash: 604851a4140d08550dd4604851a4140d08550dd4604851a4140d08550dd45cbd53d350a417320d6a5cbd53d350a417320d6a5cbd53d350a417320d6a604851a4140d08550dd4 Child - Hash: 085386bf0cb4accbb1eb + Hash: 604851a4140d08550dd4 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size @@ -1838,7 +1846,7 @@ Child For more info visit https://webpack.js.org/guides/code-splitting/ Child - Hash: 085386bf0cb4accbb1eb + Hash: 604851a4140d08550dd4 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size @@ -1861,7 +1869,7 @@ Child For more info visit https://webpack.js.org/guides/code-splitting/ Child - Hash: 085386bf0cb4accbb1eb + Hash: 604851a4140d08550dd4 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size @@ -1869,7 +1877,7 @@ Child Entrypoint main = no-warning.pro-node.js ./index.js 293 KiB [built] Child - Hash: 1499b9952c8259430fac + Hash: 5cbd53d350a417320d6a Time: Xms Built at: 1970-04-20 12:42:42 Asset Size @@ -1877,7 +1885,7 @@ Child Entrypoint main = no-warning.dev-web.js ./index.js 293 KiB [built] Child - Hash: 1499b9952c8259430fac + Hash: 5cbd53d350a417320d6a Time: Xms Built at: 1970-04-20 12:42:42 Asset Size @@ -1885,7 +1893,7 @@ Child Entrypoint main = no-warning.dev-node.js ./index.js 293 KiB [built] Child - Hash: 1499b9952c8259430fac + Hash: 5cbd53d350a417320d6a Time: Xms Built at: 1970-04-20 12:42:42 Asset Size @@ -1893,7 +1901,7 @@ Child Entrypoint main [big] = no-warning.dev-web-with-limit-set.js ./index.js 293 KiB [built] Child - Hash: 085386bf0cb4accbb1eb + Hash: 604851a4140d08550dd4 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size @@ -1970,7 +1978,7 @@ exports[`StatsTestCases should print correct stats for performance-no-async-chun Built at: 1970-04-20 12:42:42 Asset Size main.js 294 KiB [emitted] [big] [name: main] - sec.js 1.41 KiB [emitted] [name: sec] + sec.js 1.36 KiB [emitted] [name: sec] Entrypoint main [big] = main.js Entrypoint sec = sec.js ./index.js 32 bytes [built] @@ -2084,7 +2092,7 @@ exports[`StatsTestCases should print correct stats for preload 1`] = ` " Asset Size inner.js 114 bytes [emitted] [name: inner] inner2.js 154 bytes [emitted] [name: inner2] - main.js 11.9 KiB [emitted] [name: main] + main.js 11.8 KiB [emitted] [name: main] normal.js 113 bytes [emitted] [name: normal] preloaded.js 557 bytes [emitted] [name: preloaded] preloaded2.js 113 bytes [emitted] [name: preloaded2] @@ -2108,7 +2116,7 @@ exports[`StatsTestCases should print correct stats for preset-detailed 1`] = ` <+> [LogTestPlugin] Collaped group [LogTestPlugin] Log [LogTestPlugin] End -Hash: cc6b3725f6c0e8507ded +Hash: 75c2283ae108b4adfd48 Time: Xms Built at: 1970-04-20 12:42:42 PublicPath: (none) @@ -2116,7 +2124,7 @@ PublicPath: (none) 460.js 324 bytes {460} [emitted] 524.js 210 bytes {524} [emitted] 996.js 142 bytes {996} [emitted] -main.js 7.91 KiB {179} [emitted] [name: main] +main.js 7.86 KiB {179} [emitted] [name: main] Entrypoint main = main.js chunk {179} main.js (main) 73 bytes (javascript) 4.24 KiB (runtime) >{460}< >{996}< [entry] [rendered] > ./index main @@ -2228,14 +2236,14 @@ exports[`StatsTestCases should print correct stats for preset-normal 1`] = ` " [LogTestPlugin] Error [LogTestPlugin] Warning [LogTestPlugin] Info -Hash: cc6b3725f6c0e8507ded +Hash: 75c2283ae108b4adfd48 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size 460.js 324 bytes [emitted] 524.js 210 bytes [emitted] 996.js 142 bytes [emitted] -main.js 7.91 KiB [emitted] [name: main] +main.js 7.86 KiB [emitted] [name: main] Entrypoint main = main.js ./index.js 51 bytes [built] ./a.js 22 bytes [built] @@ -2329,7 +2337,7 @@ exports[`StatsTestCases should print correct stats for preset-verbose 1`] = ` [LogTestPlugin] Inner inner message [LogTestPlugin] Log [LogTestPlugin] End -Hash: cc6b3725f6c0e8507ded +Hash: 75c2283ae108b4adfd48 Time: Xms Built at: 1970-04-20 12:42:42 PublicPath: (none) @@ -2337,12 +2345,13 @@ PublicPath: (none) 460.js 324 bytes {460} [emitted] 524.js 210 bytes {524} [emitted] 996.js 142 bytes {996} [emitted] -main.js 7.91 KiB {179} [emitted] [name: main] +main.js 7.86 KiB {179} [emitted] [name: main] Entrypoint main = main.js chunk {179} main.js (main) 73 bytes (javascript) 4.24 KiB (runtime) >{460}< >{996}< [entry] [rendered] > ./index main [847] ./a.js 22 bytes {179} [depth 1] [built] ModuleConcatenation bailout: Module is not an ECMAScript module + cjs self exports reference [847] ./a.js 1:0-14 cjs require ./a [10] ./index.js 1:0-14 Xms [10] -> Xms (resolving: Xms, restoring: Xms, integration: Xms, building: Xms, storing: Xms) [10] ./index.js 51 bytes {179} [depth 0] [built] @@ -2376,15 +2385,18 @@ chunk {524} 524.js 44 bytes <{460}> [rendered] [767] ./d.js 22 bytes {524} [depth 2] [built] ModuleConcatenation bailout: Module is not an ECMAScript module require.ensure item ./d [460] ./c.js 1:0-52 + cjs self exports reference [767] ./d.js 1:0-14 Xms [10] -> Xms [460] -> Xms (resolving: Xms, restoring: Xms, integration: Xms, building: Xms, storing: Xms) [390] ./e.js 22 bytes {524} [depth 2] [built] ModuleConcatenation bailout: Module is not an ECMAScript module require.ensure item ./e [460] ./c.js 1:0-52 + cjs self exports reference [390] ./e.js 1:0-14 Xms [10] -> Xms [460] -> Xms (resolving: Xms, restoring: Xms, integration: Xms, building: Xms, storing: Xms) chunk {996} 996.js 22 bytes <{179}> [rendered] > ./b [10] ./index.js 2:0-16 [996] ./b.js 22 bytes {996} [depth 1] [built] ModuleConcatenation bailout: Module is not an ECMAScript module + cjs self exports reference [996] ./b.js 1:0-14 amd require ./b [10] ./index.js 2:0-16 Xms [10] -> Xms (resolving: Xms, restoring: Xms, integration: Xms, building: Xms, storing: Xms) @@ -2433,11 +2445,11 @@ LOG from webpack.SplitChunksPlugin `; exports[`StatsTestCases should print correct stats for resolve-plugin-context 1`] = ` -"Hash: b424ab63ddfccbe2edb4 +"Hash: 2b3ef749cda92d3cfac9 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size -bundle.js 1.55 KiB [emitted] [name: main] + Asset Size +bundle.js 1.5 KiB [emitted] [name: main] Entrypoint main = bundle.js ./index.js 48 bytes [built] ./node_modules/abc/index.js 16 bytes [built] @@ -2447,11 +2459,11 @@ Entrypoint main = bundle.js `; exports[`StatsTestCases should print correct stats for reverse-sort-modules 1`] = ` -"Hash: 41d1bca9d8ea1cc53215 +"Hash: 896d8a1d7b73a2ef9139 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size -main.js 5.34 KiB [emitted] [name: main] +main.js 5.29 KiB [emitted] [name: main] Entrypoint main = main.js ./index.js 181 bytes [built] ./a.js?1 33 bytes [built] @@ -2485,8 +2497,8 @@ exports[`StatsTestCases should print correct stats for runtime-chunk-integration "Child base: Asset Size without-505.js 1.22 KiB [emitted] - without-main1.js 556 bytes [emitted] [name: main1] - without-runtime.js 9.83 KiB [emitted] [name: runtime] + without-main1.js 601 bytes [emitted] [name: main1] + without-runtime.js 9.78 KiB [emitted] [name: runtime] Entrypoint main1 = without-runtime.js without-main1.js ./main1.js 66 bytes [built] ./b.js 20 bytes [built] @@ -2496,8 +2508,8 @@ exports[`StatsTestCases should print correct stats for runtime-chunk-integration Child manifest is named entry: Asset Size with-505.js 1.22 KiB [emitted] - with-main1.js 556 bytes [emitted] [name: main1] - with-manifest.js 9.96 KiB [emitted] [name: manifest] + with-main1.js 601 bytes [emitted] [name: main1] + with-manifest.js 9.91 KiB [emitted] [name: manifest] Entrypoint main1 = with-manifest.js with-main1.js Entrypoint manifest = with-manifest.js ./main1.js 66 bytes [built] @@ -2519,7 +2531,7 @@ Entrypoint e2 = runtime.js e2.js" `; exports[`StatsTestCases should print correct stats for scope-hoisting-bailouts 1`] = ` -"Hash: 6c0e3ff2d7cd6333531e +"Hash: ea361a8a1e8207bed262 Time: Xms Built at: 1970-04-20 12:42:42 Entrypoint index = index.js @@ -2549,9 +2561,9 @@ external \\"external\\" 42 bytes [built] `; exports[`StatsTestCases should print correct stats for scope-hoisting-multi 1`] = ` -"Hash: c32b7b7b3c075bb1b7ee58dad7f1031821535004 +"Hash: e2c7355c011145721c930f50cdfccf67cfa8eb2a Child - Hash: c32b7b7b3c075bb1b7ee + Hash: e2c7355c011145721c93 Time: Xms Built at: 1970-04-20 12:42:42 Entrypoint first = a-vendor.js a-first.js @@ -2569,7 +2581,7 @@ Child ./common_lazy_shared.js 25 bytes [built] + 12 hidden modules Child - Hash: 58dad7f1031821535004 + Hash: 0f50cdfccf67cfa8eb2a Time: Xms Built at: 1970-04-20 12:42:42 Entrypoint first = b-vendor.js b-first.js @@ -2596,12 +2608,12 @@ Child `; exports[`StatsTestCases should print correct stats for side-effects-issue-7428 1`] = ` -"Hash: 058fc77aba938f0dc820 +"Hash: dd7339ec873427ae72f9 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size 1.js 642 bytes [emitted] -main.js 9.94 KiB [emitted] [name: main] +main.js 9.9 KiB [emitted] [name: main] Entrypoint main = main.js ./main.js + 1 modules 231 bytes [built] [no exports used] @@ -2647,7 +2659,7 @@ Entrypoint main = main.js `; exports[`StatsTestCases should print correct stats for side-effects-simple-unused 1`] = ` -"Hash: 016a135c0421bd2fc947 +"Hash: 5e65a865b852c4d57af6 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size @@ -2684,7 +2696,7 @@ exports[`StatsTestCases should print correct stats for simple 1`] = ` Time: Xms Built at: 1970-04-20 12:42:42 Asset Size -bundle.js 270 bytes [emitted] [name: main] +bundle.js 311 bytes [emitted] [name: main] Entrypoint main = bundle.js ./index.js 1 bytes [built]" `; @@ -3698,11 +3710,11 @@ chunk default/async-a.js (async-a) 134 bytes <{179}> [rendered] `; exports[`StatsTestCases should print correct stats for tree-shaking 1`] = ` -"Hash: 7682a53187338c456c65 +"Hash: 06b3690c160b35374c1d Time: Xms Built at: 1970-04-20 12:42:42 Asset Size -bundle.js 7.23 KiB [emitted] [name: main] +bundle.js 7.17 KiB [emitted] [name: main] Entrypoint main = bundle.js ./index.js 316 bytes [built] [1 warning] [no exports] @@ -3741,11 +3753,11 @@ require.include() is deprecated and will be removed soon. `; exports[`StatsTestCases should print correct stats for warnings-terser 1`] = ` -"Hash: fd5c5b8a9bb97e3968a4 +"Hash: dcfa5b734e4c3a1e9e77 Time: Xms Built at: 1970-04-20 12:42:42 - Asset Size -bundle.js 1010 bytes [emitted] [name: main] + Asset Size +bundle.js 823 bytes [emitted] [name: main] Entrypoint main = bundle.js ./index.js 299 bytes [built] [no exports used] @@ -3765,20 +3777,20 @@ WARNING in Terser Plugin: Dropping unused function someUnRemoteUsedFunction5 [we `; exports[`StatsTestCases should print correct stats for wasm-explorer-examples-sync 1`] = ` -"Hash: c2f1d1cb06dadb29613f +"Hash: ebe9b2a585519304a1c8 Time: Xms Built at: 1970-04-20 12:42:42 Asset Size 1d55f77c08cd19684f13.module.wasm 154 bytes [emitted] [immutable] 200c03abdc3f4ae1e15c.module.wasm 290 bytes [emitted] [immutable] - 230.bundle.js 221 bytes [emitted] + 230.bundle.js 222 bytes [emitted] 256e72dd8b9a83a6e45b.module.wasm 120 bytes [emitted] [immutable] 325.bundle.js 3.74 KiB [emitted] 526.bundle.js 368 bytes [emitted] [id hint: vendors] - 780.bundle.js 524 bytes [emitted] - 99.bundle.js 219 bytes [emitted] + 780.bundle.js 526 bytes [emitted] + 99.bundle.js 220 bytes [emitted] a0e9dd97d7ced35a5b2c.module.wasm 154 bytes [emitted] [immutable] - bundle.js 11.1 KiB [emitted] [name: main-1df31ce3] + bundle.js 11.2 KiB [emitted] [name: main-1df31ce3] d37b3336426771c2a6e2.module.wasm 531 bytes [emitted] [immutable] ebd3f263522776d85971.module.wasm 156 bytes [emitted] [immutable] Entrypoint main = bundle.js diff --git a/test/cases/cjs-tree-shaking/bailouts/accessing-call-context.js b/test/cases/cjs-tree-shaking/bailouts/accessing-call-context.js new file mode 100644 index 000000000..1e925b722 --- /dev/null +++ b/test/cases/cjs-tree-shaking/bailouts/accessing-call-context.js @@ -0,0 +1,5 @@ +module.exports.func = function f() { + "use strict"; + return this; +}; +module.exports.abc = "abc"; diff --git a/test/cases/cjs-tree-shaking/bailouts/accessing-module.js b/test/cases/cjs-tree-shaking/bailouts/accessing-module.js new file mode 100644 index 000000000..1ae2ff1eb --- /dev/null +++ b/test/cases/cjs-tree-shaking/bailouts/accessing-module.js @@ -0,0 +1,7 @@ +exports.abc = "abc"; + +function f(m) { + m.exports = { abc: "abc", def: "def" }; +} + +f(module); diff --git a/test/cases/cjs-tree-shaking/bailouts/assign-exports-assign.js b/test/cases/cjs-tree-shaking/bailouts/assign-exports-assign.js new file mode 100644 index 000000000..5382b0246 --- /dev/null +++ b/test/cases/cjs-tree-shaking/bailouts/assign-exports-assign.js @@ -0,0 +1,6 @@ +exports.abc = "abc"; + +var newObj = {}; +exports = newObj; + +exports.def = "def"; diff --git a/test/cases/cjs-tree-shaking/bailouts/assign-exports-define.js b/test/cases/cjs-tree-shaking/bailouts/assign-exports-define.js new file mode 100644 index 000000000..416b24a58 --- /dev/null +++ b/test/cases/cjs-tree-shaking/bailouts/assign-exports-define.js @@ -0,0 +1,6 @@ +Object.defineProperty(exports, "abc", { value: "abc" }); + +var newObj = {}; +exports = newObj; + +Object.defineProperty(exports, "def", { value: "def" }); diff --git a/test/cases/cjs-tree-shaking/bailouts/define-module-properties.js b/test/cases/cjs-tree-shaking/bailouts/define-module-properties.js new file mode 100644 index 000000000..3e2c0dfb1 --- /dev/null +++ b/test/cases/cjs-tree-shaking/bailouts/define-module-properties.js @@ -0,0 +1,10 @@ +exports.abc = "abc"; + +Object.defineProperties(module, { + exports: { + value: { + abc: "abc", + def: "def" + } + } +}); diff --git a/test/cases/cjs-tree-shaking/bailouts/define-module-property.js b/test/cases/cjs-tree-shaking/bailouts/define-module-property.js new file mode 100644 index 000000000..2ec922101 --- /dev/null +++ b/test/cases/cjs-tree-shaking/bailouts/define-module-property.js @@ -0,0 +1,8 @@ +exports.abc = "abc"; + +Object.defineProperty(module, "exports", { + value: { + abc: "abc", + def: "def" + } +}); diff --git a/test/cases/cjs-tree-shaking/bailouts/index.js b/test/cases/cjs-tree-shaking/bailouts/index.js new file mode 100644 index 000000000..665c352dc --- /dev/null +++ b/test/cases/cjs-tree-shaking/bailouts/index.js @@ -0,0 +1,56 @@ +it("should bailout when reading whole exports object from this", () => { + var test = require("./reading-this").test; + expect(test().abc).toBe("abc"); +}); + +it("should bailout when reading whole exports object from exports", () => { + var test = require("./reading-exports").test; + expect(test().abc).toBe("abc"); +}); + +it("should bailout when reading whole exports object from module.exports", () => { + var test = require("./reading-module-exports").test; + expect(test().abc).toBe("abc"); +}); + +it("should reassigning exports (assign values)", () => { + expect(require("./assign-exports-assign?1").abc).toBe("abc"); + expect(require("./assign-exports-assign?2").def).toBe(undefined); +}); + +it("should reassigning exports (define values)", () => { + expect(require("./assign-exports-define").abc).toBe("abc"); + expect(require("./assign-exports-define").def).toBe(undefined); +}); + +it("should not mangle or remove nested properties", () => { + expect(require("./nested-property").abc).toBe("abc"); +}); + +it("should be able to access the exports via call context", () => { + expect(require("./accessing-call-context?1").func().abc).toBe("abc"); + var cc = require("./accessing-call-context?2"); + expect(cc.func().abc).toBe("abc"); + var func = require("./accessing-call-context?3").func; + expect(func()).toBe(undefined); +}); + +it("should be able to define an exports property on module (property)", () => { + expect(require("./define-module-property?2").abc).toBe("abc"); + expect(require("./define-module-property?1").def).toBe("def"); +}); + +it("should be able to define an exports property on module (properties)", () => { + expect(require("./define-module-properties?2").abc).toBe("abc"); + expect(require("./define-module-properties?1").def).toBe("def"); +}); + +it("should be able to do stuff with the module object", () => { + expect(require("./accessing-module?2").abc).toBe("abc"); + expect(require("./accessing-module?1").def).toBe("def"); +}); + +it("should be able to use AMD to define exports", () => { + expect(require("./using-amd?2").abc).toBe("abc"); + expect(require("./using-amd?1").def).toBe("def"); +}); diff --git a/test/cases/cjs-tree-shaking/bailouts/nested-property.js b/test/cases/cjs-tree-shaking/bailouts/nested-property.js new file mode 100644 index 000000000..4777d1581 --- /dev/null +++ b/test/cases/cjs-tree-shaking/bailouts/nested-property.js @@ -0,0 +1,8 @@ +var abc = {}; + +module.exports = abc; + +module.exports.abc = "abc"; +module.exports.def = "def"; + +expect(abc).toEqual({ abc: "abc", def: "def" }); diff --git a/test/cases/cjs-tree-shaking/bailouts/reading-exports.js b/test/cases/cjs-tree-shaking/bailouts/reading-exports.js new file mode 100644 index 000000000..7c994d85b --- /dev/null +++ b/test/cases/cjs-tree-shaking/bailouts/reading-exports.js @@ -0,0 +1,5 @@ +exports.abc = "abc"; + +exports.test = function() { + return exports; +}; diff --git a/test/cases/cjs-tree-shaking/bailouts/reading-module-exports.js b/test/cases/cjs-tree-shaking/bailouts/reading-module-exports.js new file mode 100644 index 000000000..53c6437c5 --- /dev/null +++ b/test/cases/cjs-tree-shaking/bailouts/reading-module-exports.js @@ -0,0 +1,5 @@ +exports.abc = "abc"; + +exports.test = function() { + return module.exports; +}; diff --git a/test/cases/cjs-tree-shaking/bailouts/reading-this.js b/test/cases/cjs-tree-shaking/bailouts/reading-this.js new file mode 100644 index 000000000..dace36f75 --- /dev/null +++ b/test/cases/cjs-tree-shaking/bailouts/reading-this.js @@ -0,0 +1,5 @@ +exports.abc = "abc"; + +exports.test = () => { + return this; +}; diff --git a/test/cases/cjs-tree-shaking/bailouts/using-amd.js b/test/cases/cjs-tree-shaking/bailouts/using-amd.js new file mode 100644 index 000000000..28366950f --- /dev/null +++ b/test/cases/cjs-tree-shaking/bailouts/using-amd.js @@ -0,0 +1,5 @@ +exports.abc = "not-abc"; +define({ + abc: "abc", + def: "def" +}); diff --git a/test/cases/cjs-tree-shaking/cjs-to-esm/index.js b/test/cases/cjs-tree-shaking/cjs-to-esm/index.js new file mode 100644 index 000000000..1c5838ace --- /dev/null +++ b/test/cases/cjs-tree-shaking/cjs-to-esm/index.js @@ -0,0 +1,10 @@ +it("should allow to require esm", () => { + expect(require("./module?1").abc).toBe("abc"); + expect(typeof require("./module?2").func).toBe("function"); + // check if a function called with a namespace object as context + // still yield the same optimization, compared to only accessing + // the export + expect(Object.keys(require("./module?3").func())).toEqual( + Object.keys(require.cache[require.resolve("./module?2")].exports) + ); +}); diff --git a/test/cases/cjs-tree-shaking/cjs-to-esm/module.js b/test/cases/cjs-tree-shaking/cjs-to-esm/module.js new file mode 100644 index 000000000..6532d0868 --- /dev/null +++ b/test/cases/cjs-tree-shaking/cjs-to-esm/module.js @@ -0,0 +1,6 @@ +export const abc = "abc"; +export const def = "def"; +export const func = function() { + "use strict"; + return this; +}; diff --git a/test/cases/cjs-tree-shaking/esm-to-cjs/index.js b/test/cases/cjs-tree-shaking/esm-to-cjs/index.js new file mode 100644 index 000000000..71e5362a4 --- /dev/null +++ b/test/cases/cjs-tree-shaking/esm-to-cjs/index.js @@ -0,0 +1,9 @@ +import m1 from "./module?1"; +import m2 from "./module?2"; +import { abc } from "./module?3"; + +it("should allow to import cjs with esm", () => { + expect(m1.abc).toBe("abc"); + expect(m2).toEqual({ abc: "abc", def: "def" }); + expect(abc).toBe("abc"); +}); diff --git a/test/cases/cjs-tree-shaking/esm-to-cjs/module.js b/test/cases/cjs-tree-shaking/esm-to-cjs/module.js new file mode 100644 index 000000000..0d3ae4379 --- /dev/null +++ b/test/cases/cjs-tree-shaking/esm-to-cjs/module.js @@ -0,0 +1,2 @@ +exports.abc = "abc"; +exports.def = "def"; diff --git a/test/cases/cjs-tree-shaking/exports/assign-exports-property.js b/test/cases/cjs-tree-shaking/exports/assign-exports-property.js new file mode 100644 index 000000000..0d3ae4379 --- /dev/null +++ b/test/cases/cjs-tree-shaking/exports/assign-exports-property.js @@ -0,0 +1,2 @@ +exports.abc = "abc"; +exports.def = "def"; diff --git a/test/cases/cjs-tree-shaking/exports/assign-module-exports-property.js b/test/cases/cjs-tree-shaking/exports/assign-module-exports-property.js new file mode 100644 index 000000000..2136b98d7 --- /dev/null +++ b/test/cases/cjs-tree-shaking/exports/assign-module-exports-property.js @@ -0,0 +1,2 @@ +module.exports.abc = "abc"; +module.exports.def = "def"; diff --git a/test/cases/cjs-tree-shaking/exports/assign-this-property.js b/test/cases/cjs-tree-shaking/exports/assign-this-property.js new file mode 100644 index 000000000..37d1ecb94 --- /dev/null +++ b/test/cases/cjs-tree-shaking/exports/assign-this-property.js @@ -0,0 +1,2 @@ +this.abc = "abc"; +this.def = "def"; diff --git a/test/cases/cjs-tree-shaking/exports/attach-to-arrow-function.js b/test/cases/cjs-tree-shaking/exports/attach-to-arrow-function.js new file mode 100644 index 000000000..abc9576d2 --- /dev/null +++ b/test/cases/cjs-tree-shaking/exports/attach-to-arrow-function.js @@ -0,0 +1,3 @@ +module.exports = () => "abc"; + +module.exports.def = "def"; diff --git a/test/cases/cjs-tree-shaking/exports/attach-to-function.js b/test/cases/cjs-tree-shaking/exports/attach-to-function.js new file mode 100644 index 000000000..9341f94fd --- /dev/null +++ b/test/cases/cjs-tree-shaking/exports/attach-to-function.js @@ -0,0 +1,5 @@ +module.exports = function() { + return "abc"; +}; + +module.exports.def = "def"; diff --git a/test/cases/cjs-tree-shaking/exports/attach-to-object.js b/test/cases/cjs-tree-shaking/exports/attach-to-object.js new file mode 100644 index 000000000..43abfd882 --- /dev/null +++ b/test/cases/cjs-tree-shaking/exports/attach-to-object.js @@ -0,0 +1,5 @@ +module.exports = { + abc: "abc" +}; + +module.exports.def = "def"; diff --git a/test/cases/cjs-tree-shaking/exports/define-exports-property.js b/test/cases/cjs-tree-shaking/exports/define-exports-property.js new file mode 100644 index 000000000..8fdaf76e9 --- /dev/null +++ b/test/cases/cjs-tree-shaking/exports/define-exports-property.js @@ -0,0 +1,2 @@ +Object.defineProperty(exports, "abc", { enumerable: true, value: "abc" }); +Object.defineProperty(exports, "def", { enumerable: true, value: "def" }); diff --git a/test/cases/cjs-tree-shaking/exports/define-module-exports-property.js b/test/cases/cjs-tree-shaking/exports/define-module-exports-property.js new file mode 100644 index 000000000..4ac21240a --- /dev/null +++ b/test/cases/cjs-tree-shaking/exports/define-module-exports-property.js @@ -0,0 +1,8 @@ +Object.defineProperty(module.exports, "abc", { + enumerable: true, + value: "abc" +}); +Object.defineProperty(module.exports, "def", { + enumerable: true, + value: "def" +}); diff --git a/test/cases/cjs-tree-shaking/exports/define-this-property.js b/test/cases/cjs-tree-shaking/exports/define-this-property.js new file mode 100644 index 000000000..2cfbf578d --- /dev/null +++ b/test/cases/cjs-tree-shaking/exports/define-this-property.js @@ -0,0 +1,2 @@ +Object.defineProperty(this, "abc", { enumerable: true, value: "abc" }); +Object.defineProperty(this, "def", { enumerable: true, value: "def" }); diff --git a/test/cases/cjs-tree-shaking/exports/index.js b/test/cases/cjs-tree-shaking/exports/index.js new file mode 100644 index 000000000..2524d9c11 --- /dev/null +++ b/test/cases/cjs-tree-shaking/exports/index.js @@ -0,0 +1,83 @@ +it("should allow to export via exports", () => { + expect(require("./assign-exports-property?1").abc).toBe("abc"); + expect(require("./assign-exports-property?2")).toEqual({ + abc: "abc", + def: "def" + }); +}); + +it("should allow to export via module.exports", () => { + expect(require("./assign-module-exports-property?1").abc).toBe("abc"); + expect(require("./assign-module-exports-property?2")).toEqual({ + abc: "abc", + def: "def" + }); +}); + +it("should allow to export via this", () => { + expect(require("./assign-this-property?1").abc).toBe("abc"); + expect(require("./assign-this-property?2")).toEqual({ + abc: "abc", + def: "def" + }); +}); + +it("should allow to export via define property on exports", () => { + expect(require("./define-exports-property?1").abc).toBe("abc"); + expect(require("./define-exports-property?2")).toEqual({ + abc: "abc", + def: "def" + }); +}); + +it("should allow to export via define property on module.exports", () => { + expect(require("./define-module-exports-property?1").abc).toBe("abc"); + expect(require("./define-module-exports-property?2")).toEqual({ + abc: "abc", + def: "def" + }); +}); + +it("should allow to export via define property on this", () => { + expect(require("./define-this-property?1").abc).toBe("abc"); + expect(require("./define-this-property?2")).toEqual({ + abc: "abc", + def: "def" + }); +}); + +it("should allow to read own exports via exports", () => { + var test = require("./reading-self-from-exports").test; + expect(test()).toBe("abc"); +}); + +it("should allow to read own exports via module.exports", () => { + var test = require("./reading-self-from-module-exports").test; + expect(test()).toBe("abc"); +}); + +it("should allow to read own exports via this", () => { + var test = require("./reading-self-from-this").test; + expect(test()).toBe("abc"); +}); + +it("should allow to attach exports to object", () => { + expect(require("./attach-to-object?1").abc).toBe("abc"); + expect(require("./attach-to-object?2").def).toBe("def"); + expect(require("./attach-to-object?3").abc).toBe("abc"); + expect(require("./attach-to-object?3").def).toBe("def"); +}); + +it("should allow to attach exports to function", () => { + expect(require("./attach-to-function?1")()).toBe("abc"); + expect(require("./attach-to-function?2").def).toBe("def"); + expect(require("./attach-to-function?3")()).toBe("abc"); + expect(require("./attach-to-function?3").def).toBe("def"); +}); + +it("should allow to attach exports to arrow function", () => { + expect(require("./attach-to-arrow-function?1")()).toBe("abc"); + expect(require("./attach-to-arrow-function?2").def).toBe("def"); + expect(require("./attach-to-arrow-function?3")()).toBe("abc"); + expect(require("./attach-to-arrow-function?3").def).toBe("def"); +}); diff --git a/test/cases/cjs-tree-shaking/exports/reading-self-from-exports.js b/test/cases/cjs-tree-shaking/exports/reading-self-from-exports.js new file mode 100644 index 000000000..bee3ff361 --- /dev/null +++ b/test/cases/cjs-tree-shaking/exports/reading-self-from-exports.js @@ -0,0 +1,5 @@ +exports.abc = "abc"; + +exports.test = function() { + return exports.abc; +}; diff --git a/test/cases/cjs-tree-shaking/exports/reading-self-from-module-exports.js b/test/cases/cjs-tree-shaking/exports/reading-self-from-module-exports.js new file mode 100644 index 000000000..9b197bfb8 --- /dev/null +++ b/test/cases/cjs-tree-shaking/exports/reading-self-from-module-exports.js @@ -0,0 +1,5 @@ +exports.abc = "abc"; + +exports.test = function() { + return module.exports.abc; +}; diff --git a/test/cases/cjs-tree-shaking/exports/reading-self-from-this.js b/test/cases/cjs-tree-shaking/exports/reading-self-from-this.js new file mode 100644 index 000000000..ee4452148 --- /dev/null +++ b/test/cases/cjs-tree-shaking/exports/reading-self-from-this.js @@ -0,0 +1,5 @@ +exports.abc = "abc"; + +exports.test = () => { + return this.abc; +}; diff --git a/test/cases/cjs-tree-shaking/importing/index.js b/test/cases/cjs-tree-shaking/importing/index.js new file mode 100644 index 000000000..fb044fcad --- /dev/null +++ b/test/cases/cjs-tree-shaking/importing/index.js @@ -0,0 +1,15 @@ +it("should be able to import a module via require and property", () => { + expect(require("./module").abc).toBe("abc"); +}); + +it("should be able to import a module via require and destruct", () => { + var { abc } = require("./module"); + expect(abc).toBe("abc"); +}); + +it("should be able to import a module via require and exports object", () => { + var module1 = require("./module?1"); + expect(module1.abc).toBe("abc"); + var module2 = require("./module?2"); + expect(module2).toEqual({ abc: "abc", def: "def" }); +}); diff --git a/test/cases/cjs-tree-shaking/importing/module.js b/test/cases/cjs-tree-shaking/importing/module.js new file mode 100644 index 000000000..0d3ae4379 --- /dev/null +++ b/test/cases/cjs-tree-shaking/importing/module.js @@ -0,0 +1,2 @@ +exports.abc = "abc"; +exports.def = "def"; diff --git a/test/cases/cjs-tree-shaking/mutate/index.js b/test/cases/cjs-tree-shaking/mutate/index.js new file mode 100644 index 000000000..cd913b48f --- /dev/null +++ b/test/cases/cjs-tree-shaking/mutate/index.js @@ -0,0 +1,33 @@ +import module1 from "./module?1"; +import module2, { a } from "./module?2"; + +it("should allow mutating imported modules (changing existing exports)", () => { + expect(module1.abc).toBe("abc"); + expect(module1.def).toBe("def"); + module1.abc = "new-abc"; + expect(module1.abc).toBe("new-abc"); + expect(module1.def).toBe("def"); +}); + +it("should allow mutating imported modules (adding new properties)", () => { + expect(module2.abc).toBe("abc"); + expect(module2.def).toBe("def"); + expect(module2.ghi).toBe(undefined); + expect(module2.Oi).toBe(undefined); + expect(module2.a).toBe(undefined); + expect(a).toBe(undefined); + expect(module2[""]).toBe(undefined); + module2.ghi = "ghi"; + module2.Oi = "Oi"; + module2.a = "a"; + module2[""] = {}; + module2[""].abc = "abc"; + expect(module2.abc).toBe("abc"); + expect(module2.def).toBe("def"); + expect(module2.ghi).toBe("ghi"); + expect(module2.Oi).toBe("Oi"); + expect(module2.a).toBe("a"); + expect(a).toBe("a"); + expect(module2[""]).toEqual({ abc: "abc" }); + expect(module2[""].abc).toBe("abc"); +}); diff --git a/test/cases/cjs-tree-shaking/mutate/module.js b/test/cases/cjs-tree-shaking/mutate/module.js new file mode 100644 index 000000000..0d3ae4379 --- /dev/null +++ b/test/cases/cjs-tree-shaking/mutate/module.js @@ -0,0 +1,2 @@ +exports.abc = "abc"; +exports.def = "def"; diff --git a/test/cases/cjs-tree-shaking/namespace/index.js b/test/cases/cjs-tree-shaking/namespace/index.js new file mode 100644 index 000000000..e4407ae46 --- /dev/null +++ b/test/cases/cjs-tree-shaking/namespace/index.js @@ -0,0 +1,25 @@ +it("should allow to create namespace exports via __esModule on exports", async () => { + expect(await import("./namespace-via-exports")).toBe( + require("./namespace-via-exports") + ); +}); +it("should allow to create namespace exports via __esModule on literal", async () => { + expect(await import("./namespace-via-literal")).toBe( + require("./namespace-via-literal") + ); +}); +it("should allow to create namespace exports via __esModule with Object.defineProperty", async () => { + expect(await import("./namespace-via-define-property")).toBe( + require("./namespace-via-define-property") + ); +}); +it("should allow to create namespace exports via __esModule with Object.defineProperty minimized true", async () => { + expect(await import("./namespace-via-define-property-minimized")).toBe( + require("./namespace-via-define-property-minimized") + ); +}); +it("should allow to create namespace exports via __esModule with Object.defineProperties", async () => { + expect(await import("./namespace-via-define-properties")).toBe( + require("./namespace-via-define-properties") + ); +}); diff --git a/test/cases/cjs-tree-shaking/namespace/namespace-via-define-properties.js b/test/cases/cjs-tree-shaking/namespace/namespace-via-define-properties.js new file mode 100644 index 000000000..fcf031e86 --- /dev/null +++ b/test/cases/cjs-tree-shaking/namespace/namespace-via-define-properties.js @@ -0,0 +1,5 @@ +Object.defineProperties(exports, { + __esModule: { value: true }, + abc: { enumerable: true, value: "abc" }, + default: { enumerable: true, value: "default" } +}); diff --git a/test/cases/cjs-tree-shaking/namespace/namespace-via-define-property-minimized.js b/test/cases/cjs-tree-shaking/namespace/namespace-via-define-property-minimized.js new file mode 100644 index 000000000..cd10e84bf --- /dev/null +++ b/test/cases/cjs-tree-shaking/namespace/namespace-via-define-property-minimized.js @@ -0,0 +1,3 @@ +Object.defineProperty(exports, "__esModule", { value: !0 }); +exports.abc = "abc"; +exports.default = "default"; diff --git a/test/cases/cjs-tree-shaking/namespace/namespace-via-define-property.js b/test/cases/cjs-tree-shaking/namespace/namespace-via-define-property.js new file mode 100644 index 000000000..50c67588d --- /dev/null +++ b/test/cases/cjs-tree-shaking/namespace/namespace-via-define-property.js @@ -0,0 +1,3 @@ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.abc = "abc"; +exports.default = "default"; diff --git a/test/cases/cjs-tree-shaking/namespace/namespace-via-exports.js b/test/cases/cjs-tree-shaking/namespace/namespace-via-exports.js new file mode 100644 index 000000000..92cc687c7 --- /dev/null +++ b/test/cases/cjs-tree-shaking/namespace/namespace-via-exports.js @@ -0,0 +1,3 @@ +exports.__esModule = true; +exports.abc = "abc"; +exports.default = "default"; \ No newline at end of file diff --git a/test/cases/cjs-tree-shaking/namespace/namespace-via-literal.js b/test/cases/cjs-tree-shaking/namespace/namespace-via-literal.js new file mode 100644 index 000000000..21867372a --- /dev/null +++ b/test/cases/cjs-tree-shaking/namespace/namespace-via-literal.js @@ -0,0 +1,5 @@ +module.exports = { + __esModule: true, + abc: "abc", + default: "default" +}; diff --git a/test/cases/cjs-tree-shaking/objects/direct-object.js b/test/cases/cjs-tree-shaking/objects/direct-object.js new file mode 100644 index 000000000..f32a5fb07 --- /dev/null +++ b/test/cases/cjs-tree-shaking/objects/direct-object.js @@ -0,0 +1,4 @@ +module.exports = { + abc: "abc", + def: "def" +}; diff --git a/test/cases/cjs-tree-shaking/objects/index.js b/test/cases/cjs-tree-shaking/objects/index.js new file mode 100644 index 000000000..cf9fa76da --- /dev/null +++ b/test/cases/cjs-tree-shaking/objects/index.js @@ -0,0 +1,9 @@ +it("should be able to export an object literal", () => { + expect(require("./direct-object?1").abc).toBe("abc"); + expect(require("./direct-object?2")).toEqual({ abc: "abc", def: "def" }); +}); + +it("should be able to export an object literal indirect", () => { + expect(require("./indirect-object?1").abc).toBe("abc"); + expect(require("./indirect-object?2")).toEqual({ abc: "abc", def: "def" }); +}); diff --git a/test/cases/cjs-tree-shaking/objects/indirect-object.js b/test/cases/cjs-tree-shaking/objects/indirect-object.js new file mode 100644 index 000000000..9df708c91 --- /dev/null +++ b/test/cases/cjs-tree-shaking/objects/indirect-object.js @@ -0,0 +1,6 @@ +var value = { + abc: "abc", + def: "def" +}; + +module.exports = value; diff --git a/test/cases/cjs-tree-shaking/reexports/index.js b/test/cases/cjs-tree-shaking/reexports/index.js new file mode 100644 index 000000000..2fb27e1d3 --- /dev/null +++ b/test/cases/cjs-tree-shaking/reexports/index.js @@ -0,0 +1,41 @@ +it("should allow to reexport a exports object (this, exports)", () => { + expect(require("./reexport-whole-exports?1").m1.abc).toBe("abc"); + expect(require("./reexport-whole-exports?2").m2.abc).toBe("abc"); + expect(require("./reexport-whole-exports?3").m3.abc).toBe("abc"); + expect(require("./reexport-whole-exports?4").m4.abc).toBe("abc"); +}); + +it("should allow to reexport a exports object (module.exports, object literal)", () => { + expect(require("./reexport-whole-module-exports?1").m1.abc).toBe("abc"); + expect(require("./reexport-whole-module-exports?2").m2.abc).toBe("abc"); + expect(require("./reexport-whole-module-exports?3").m3.abc).toBe("abc"); + expect(require("./reexport-whole-module-exports?4").m4.abc).toBe("abc"); +}); + +it("should allow to reexport a imported property (this, exports)", () => { + expect(require("./reexport-property-exports?1").p1).toBe("abc"); + expect(require("./reexport-property-exports?2").p2).toBe("abc"); + expect(require("./reexport-property-exports?3").p3).toBe("abc"); + expect(require("./reexport-property-exports?4").p4).toBe("abc"); +}); + +it("should allow to reexport a imported property (module.exports, object literal)", () => { + expect(require("./reexport-property-module-exports?1").p1).toBe("abc"); + expect(require("./reexport-property-module-exports?2").p2).toBe("abc"); + expect(require("./reexport-property-module-exports?3").p3).toBe("abc"); + expect(require("./reexport-property-module-exports?4").p4).toBe("abc"); +}); + +it("should allow to reexport a reexported exports object (this, exports)", () => { + expect(require("./reexport-reexport-exports?1").x1.abc).toBe("abc"); + expect(require("./reexport-reexport-exports?2").x2.abc).toBe("abc"); + expect(require("./reexport-reexport-exports?3").x3.abc).toBe("abc"); + expect(require("./reexport-reexport-exports?4").x4.abc).toBe("abc"); +}); + +it("should allow to reexport a reexported exports object (module.exports, object literal)", () => { + expect(require("./reexport-reexport-module-exports?1").x1.abc).toBe("abc"); + expect(require("./reexport-reexport-module-exports?2").x2.abc).toBe("abc"); + expect(require("./reexport-reexport-module-exports?3").x3.abc).toBe("abc"); + expect(require("./reexport-reexport-module-exports?4").x4.abc).toBe("abc"); +}); diff --git a/test/cases/cjs-tree-shaking/reexports/module.js b/test/cases/cjs-tree-shaking/reexports/module.js new file mode 100644 index 000000000..0d3ae4379 --- /dev/null +++ b/test/cases/cjs-tree-shaking/reexports/module.js @@ -0,0 +1,2 @@ +exports.abc = "abc"; +exports.def = "def"; diff --git a/test/cases/cjs-tree-shaking/reexports/reexport-property-exports.js b/test/cases/cjs-tree-shaking/reexports/reexport-property-exports.js new file mode 100644 index 000000000..011358abf --- /dev/null +++ b/test/cases/cjs-tree-shaking/reexports/reexport-property-exports.js @@ -0,0 +1,6 @@ +exports.p1 = require("./module?pe1").abc; +var m2 = require("./module?pe2"); +exports.p2 = m2.abc; +this.p3 = require("./module?pe3").abc; +var m4 = require("./module?pe4"); +this.p4 = m4.abc; diff --git a/test/cases/cjs-tree-shaking/reexports/reexport-property-module-exports.js b/test/cases/cjs-tree-shaking/reexports/reexport-property-module-exports.js new file mode 100644 index 000000000..d08197d67 --- /dev/null +++ b/test/cases/cjs-tree-shaking/reexports/reexport-property-module-exports.js @@ -0,0 +1,8 @@ +var m2 = require("./module?pme2"); +module.exports = { + p1: require("./module?pme1").abc, + p2: m2.abc +}; +module.exports.p3 = require("./module?pme3").abc; +var m4 = require("./module?pme4"); +module.exports.p4 = m4.abc; diff --git a/test/cases/cjs-tree-shaking/reexports/reexport-reexport-exports.js b/test/cases/cjs-tree-shaking/reexports/reexport-reexport-exports.js new file mode 100644 index 000000000..6bfd379d6 --- /dev/null +++ b/test/cases/cjs-tree-shaking/reexports/reexport-reexport-exports.js @@ -0,0 +1,6 @@ +exports.x1 = require("./reexport-whole-exports?x1").m1; +var m2 = require("./reexport-whole-exports?x2"); +exports.x2 = m2.m2; +this.x3 = require("./reexport-whole-exports?x3").m3; +var m4 = require("./reexport-whole-exports?x4"); +this.x4 = m4.m4; diff --git a/test/cases/cjs-tree-shaking/reexports/reexport-reexport-module-exports.js b/test/cases/cjs-tree-shaking/reexports/reexport-reexport-module-exports.js new file mode 100644 index 000000000..41c61110b --- /dev/null +++ b/test/cases/cjs-tree-shaking/reexports/reexport-reexport-module-exports.js @@ -0,0 +1,8 @@ +var m2 = require("./reexport-whole-module-exports?x2"); +module.exports = { + x1: require("./reexport-whole-module-exports?x1").m1, + x2: m2.m2 +}; +module.exports.x3 = require("./reexport-whole-module-exports?x3").m3; +var m4 = require("./reexport-whole-module-exports?x4"); +module.exports.x4 = m4.m4; diff --git a/test/cases/cjs-tree-shaking/reexports/reexport-whole-exports.js b/test/cases/cjs-tree-shaking/reexports/reexport-whole-exports.js new file mode 100644 index 000000000..8fb1a720e --- /dev/null +++ b/test/cases/cjs-tree-shaking/reexports/reexport-whole-exports.js @@ -0,0 +1,6 @@ +exports.m1 = require("./module?we1"); +var m2 = require("./module?we2"); +exports.m2 = m2; +this.m3 = require("./module?we3"); +var m4 = require("./module?we4"); +this.m4 = m4; diff --git a/test/cases/cjs-tree-shaking/reexports/reexport-whole-module-exports.js b/test/cases/cjs-tree-shaking/reexports/reexport-whole-module-exports.js new file mode 100644 index 000000000..e17157394 --- /dev/null +++ b/test/cases/cjs-tree-shaking/reexports/reexport-whole-module-exports.js @@ -0,0 +1,8 @@ +var m2 = require("./module?wme2"); +module.exports = { + m1: require("./module?wme1"), + m2 +}; +module.exports.m3 = require("./module?wme3"); +var m4 = require("./module?wme4"); +module.exports.m4 = m4; diff --git a/test/cases/cjs-tree-shaking/transpiled/babel-default-interop.js b/test/cases/cjs-tree-shaking/transpiled/babel-default-interop.js new file mode 100644 index 000000000..8accb6fef --- /dev/null +++ b/test/cases/cjs-tree-shaking/transpiled/babel-default-interop.js @@ -0,0 +1,5 @@ +var xxx = _interopRequireDefault(require("./module?2")); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} +module.exports = xxx.default.abc; diff --git a/test/cases/cjs-tree-shaking/transpiled/index.js b/test/cases/cjs-tree-shaking/transpiled/index.js new file mode 100644 index 000000000..d7a8a7e2e --- /dev/null +++ b/test/cases/cjs-tree-shaking/transpiled/index.js @@ -0,0 +1,14 @@ +it("should support typescript export *", () => { + expect(require("./typescript-reexport").abc).toBe("abc"); +}); + +it("should support babel default interop", () => { + var xxx2 = _interopRequireDefault(require("./module?2")); + var xxx3 = _interopRequireDefault(require("./module?3")); + expect(xxx2.default.abc).toBe("abc"); + expect(xxx3.default).toEqual({ abc: "abc", def: "def" }); +}); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} diff --git a/test/cases/cjs-tree-shaking/transpiled/module.js b/test/cases/cjs-tree-shaking/transpiled/module.js new file mode 100644 index 000000000..0d3ae4379 --- /dev/null +++ b/test/cases/cjs-tree-shaking/transpiled/module.js @@ -0,0 +1,2 @@ +exports.abc = "abc"; +exports.def = "def"; diff --git a/test/cases/cjs-tree-shaking/transpiled/typescript-reexport.js b/test/cases/cjs-tree-shaking/transpiled/typescript-reexport.js new file mode 100644 index 000000000..1d623783a --- /dev/null +++ b/test/cases/cjs-tree-shaking/transpiled/typescript-reexport.js @@ -0,0 +1,4 @@ +function __export(m) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; +} +__export(require("./module?1")); diff --git a/test/cases/cjs-tree-shaking/weird-names/index.js b/test/cases/cjs-tree-shaking/weird-names/index.js new file mode 100644 index 000000000..453a0120c --- /dev/null +++ b/test/cases/cjs-tree-shaking/weird-names/index.js @@ -0,0 +1,16 @@ +import m from "./module"; + +it("should allow any name as exports in CommonJs", () => { + expect(m.abc).toBe("abc"); + expect(m[""]).toBe(""); + expect(m["default"]).toBe("default"); + expect(m["0"]).toBe("0"); + expect(m[1]).toBe(1); + expect(m.length).toBe("length"); + expect(m["0_0"]).toBe("0_0"); + expect(m.if).toBe("if"); + expect(m["\0"]).toBe("\0"); + expect(m["\n"]).toBe("\n"); + expect(m["*/"]).toBe("*/"); + expect(m["a.b.c"]).toBe("a.b.c"); +}); diff --git a/test/cases/cjs-tree-shaking/weird-names/module.js b/test/cases/cjs-tree-shaking/weird-names/module.js new file mode 100644 index 000000000..af166b755 --- /dev/null +++ b/test/cases/cjs-tree-shaking/weird-names/module.js @@ -0,0 +1,12 @@ +exports.abc = "abc"; +exports[""] = ""; +exports["default"] = "default"; +exports["0"] = "0"; +exports[1] = 1; +exports.length = "length"; +exports["0_0"] = "0_0"; +exports.if = "if"; +exports["\0"] = "\0"; +exports["\n"] = "\n"; +exports["*/"] = "*/"; +exports["a.b.c"] = "a.b.c"; diff --git a/test/cases/json/import-by-name-with-concatenation/warnings.js b/test/cases/json/import-by-name-with-concatenation/warnings.js index d124326de..82fc687d9 100644 --- a/test/cases/json/import-by-name-with-concatenation/warnings.js +++ b/test/cases/json/import-by-name-with-concatenation/warnings.js @@ -1,17 +1,17 @@ module.exports = [ [ - /Can't import the named export '2' \(imported as 'c'\) from JSON module \(only default export is available\)/ + /Should not import the named export '2' \(imported as 'c'\) from default-exporting module \(only default export is available soon\)/ ], [ - /Can't import the named export 'aa' \(imported as 'aa'\) from JSON module \(only default export is available\)/ + /Should not import the named export 'aa' \(imported as 'aa'\) from default-exporting module \(only default export is available soon\)/ ], [ - /Can't import the named export 'bb' \(imported as 'bb'\) from JSON module \(only default export is available\)/ + /Should not import the named export 'bb' \(imported as 'bb'\) from default-exporting module \(only default export is available soon\)/ ], [ - /Can't import the named export 'named' \(imported as 'named'\) from JSON module \(only default export is available\)/ + /Should not import the named export 'named' \(imported as 'named'\) from default-exporting module \(only default export is available soon\)/ ], [ - /Can't import the named export 'named' \(imported as 'gnamed'\) from JSON module \(only default export is available\)/ + /Should not import the named export 'named' \(imported as 'gnamed'\) from default-exporting module \(only default export is available soon\)/ ] ]; diff --git a/test/cases/json/import-by-name/warnings.js b/test/cases/json/import-by-name/warnings.js index d124326de..82fc687d9 100644 --- a/test/cases/json/import-by-name/warnings.js +++ b/test/cases/json/import-by-name/warnings.js @@ -1,17 +1,17 @@ module.exports = [ [ - /Can't import the named export '2' \(imported as 'c'\) from JSON module \(only default export is available\)/ + /Should not import the named export '2' \(imported as 'c'\) from default-exporting module \(only default export is available soon\)/ ], [ - /Can't import the named export 'aa' \(imported as 'aa'\) from JSON module \(only default export is available\)/ + /Should not import the named export 'aa' \(imported as 'aa'\) from default-exporting module \(only default export is available soon\)/ ], [ - /Can't import the named export 'bb' \(imported as 'bb'\) from JSON module \(only default export is available\)/ + /Should not import the named export 'bb' \(imported as 'bb'\) from default-exporting module \(only default export is available soon\)/ ], [ - /Can't import the named export 'named' \(imported as 'named'\) from JSON module \(only default export is available\)/ + /Should not import the named export 'named' \(imported as 'named'\) from default-exporting module \(only default export is available soon\)/ ], [ - /Can't import the named export 'named' \(imported as 'gnamed'\) from JSON module \(only default export is available\)/ + /Should not import the named export 'named' \(imported as 'gnamed'\) from default-exporting module \(only default export is available soon\)/ ] ]; diff --git a/test/cases/json/reexport/warnings.js b/test/cases/json/reexport/warnings.js index 50af7f5ec..c9990f3c9 100644 --- a/test/cases/json/reexport/warnings.js +++ b/test/cases/json/reexport/warnings.js @@ -1,5 +1,5 @@ module.exports = [ [ - /Can't import the named export 'named' \(reexported as 'fNamed'\) from JSON module \(only default export is available\)/ + /Should not import the named export 'named' \(reexported as 'fNamed'\) from default-exporting module \(only default export is available soon\)/ ] ]; diff --git a/test/cases/mjs/cjs-import-default/errors.js b/test/cases/mjs/cjs-import-default/errors.js index b5a4af50a..d0ecea7f3 100644 --- a/test/cases/mjs/cjs-import-default/errors.js +++ b/test/cases/mjs/cjs-import-default/errors.js @@ -1,11 +1,11 @@ module.exports = [ [ - /Can't import the named export 'data' \(imported as 'data'\) from non EcmaScript module \(only default export is available\)/ + /Can't import the named export 'data' \(imported as 'data'\) from default-exporting module \(only default export is available\)/ ], [ - /Can't import the named export 'data' \(imported as 'data'\) from non EcmaScript module \(only default export is available\)/ + /Can't import the named export 'data' \(imported as 'data'\) from default-exporting module \(only default export is available\)/ ], [ - /Can't import the named export 'data' \(reexported as 'data'\) from non EcmaScript module \(only default export is available\)/ + /Can't import the named export 'data' \(reexported as 'data'\) from default-exporting module \(only default export is available\)/ ] ]; diff --git a/test/cases/mjs/namespace-object-lazy/index.mjs b/test/cases/mjs/namespace-object-lazy/index.mjs index 5192ed9c2..f6601db55 100644 --- a/test/cases/mjs/namespace-object-lazy/index.mjs +++ b/test/cases/mjs/namespace-object-lazy/index.mjs @@ -53,8 +53,7 @@ function contextMixed(name) { function promiseTest(promise, equalsTo) { return promise.then(function(results) { - for(const result of results) - expect(result).toEqual(equalsTo); + expect(results).toEqual(results.map(() => equalsTo)); }); } diff --git a/test/cases/parsing/harmony-duplicate-export/index.js b/test/cases/parsing/harmony-duplicate-export/index.js index 83ed81cb0..23b7c2d18 100644 --- a/test/cases/parsing/harmony-duplicate-export/index.js +++ b/test/cases/parsing/harmony-duplicate-export/index.js @@ -21,7 +21,7 @@ it("should not overwrite when using star export (known exports)", function() { expect(x4).toBe("b"); expect(x5).toBe("c"); expect(x6).toBe("a"); - expect(x7).toBe("b"); // Looks wrong, but is irrelevant as this should be an error anyway + expect(x7).toBe("d"); // Looks wrong, but is irrelevant as this should be an error anyway }); it("should not overwrite when using star export (unknown exports)", function() { @@ -31,5 +31,5 @@ it("should not overwrite when using star export (unknown exports)", function() { expect(y4).toBe("b"); expect(y5).toBe("c"); expect(y6).toBe("a"); - expect(y7).toBe("b"); // Looks wrong, but is irrelevant as this should be an error anyway + expect(y7).toBe("d"); // Looks wrong, but is irrelevant as this should be an error anyway }); diff --git a/test/cases/scope-hoisting/json-reexport-6700/warnings.js b/test/cases/scope-hoisting/json-reexport-6700/warnings.js index 5d963765d..1bce6f573 100644 --- a/test/cases/scope-hoisting/json-reexport-6700/warnings.js +++ b/test/cases/scope-hoisting/json-reexport-6700/warnings.js @@ -1,8 +1,8 @@ module.exports = [ [ - /Can't import the named export 'a' \(reexported as 'a'\) from JSON module \(only default export is available\)/ + /Should not import the named export 'a' \(reexported as 'a'\) from default-exporting module \(only default export is available soon\)/ ], [ - /Can't import the named export 'b' \(reexported as 'b'\) from JSON module \(only default export is available\)/ + /Should not import the named export 'b' \(reexported as 'b'\) from default-exporting module \(only default export is available soon\)/ ] ]; diff --git a/test/configCases/json/tree-shaking-default/warnings.js b/test/configCases/json/tree-shaking-default/warnings.js index d99eafdf1..6857cae53 100644 --- a/test/configCases/json/tree-shaking-default/warnings.js +++ b/test/configCases/json/tree-shaking-default/warnings.js @@ -1 +1 @@ -module.exports = [[/Can't import the named export/]]; +module.exports = [[/Should not import the named export/]]; diff --git a/test/hotCases/errors/decline/index.js b/test/hotCases/errors/decline/index.js index e7b844a0a..01e094ed4 100644 --- a/test/hotCases/errors/decline/index.js +++ b/test/hotCases/errors/decline/index.js @@ -4,8 +4,8 @@ it("should abort when module is declined by parent", (done) => { expect(a).toBe(1); NEXT(require("../../update")((err) => { try { - expect(/Aborted because of declined dependency: \.\/b\.js in \.\/a\.js/.test(err.message)).toBe(true); - expect(/Update propagation: \.\/c\.js -> \.\/b\.js -> \.\/a\.js/.test(err.message)).toBe(true); + expect(err.message).toMatch(/Aborted because of declined dependency: \.\/b\.js in \.\/a\.js/); + expect(err.message).toMatch(/Update propagation: \.\/c\.js -> \.\/b\.js -> \.\/a\.js/); done(); } catch(e) { done(e); diff --git a/test/hotCases/errors/self-decline/index.js b/test/hotCases/errors/self-decline/index.js index b5814ee08..ff7f37749 100644 --- a/test/hotCases/errors/self-decline/index.js +++ b/test/hotCases/errors/self-decline/index.js @@ -4,8 +4,8 @@ it("should abort when module is declined by itself", (done) => { expect(a).toBe(1); NEXT(require("../../update")((err) => { try { - expect(/Aborted because of self decline: \.\/a\.js/.test(err.message)).toBe(true); - expect(/Update propagation: \.\/c\.js -> \.\/b\.js -> \.\/a\.js/.test(err.message)).toBe(true); + expect(err.message).toMatch(/Aborted because of self decline: \.\/a\.js/); + expect(err.message).toMatch(/Update propagation: \.\/c\.js -> \.\/b\.js -> \.\/a\.js/); done(); } catch(e) { done(e); diff --git a/test/hotCases/errors/unaccepted/index.js b/test/hotCases/errors/unaccepted/index.js index 5409a58f7..864a55380 100644 --- a/test/hotCases/errors/unaccepted/index.js +++ b/test/hotCases/errors/unaccepted/index.js @@ -6,8 +6,8 @@ it("should abort when module is not accepted", (done) => { expect(b).toBe(1); NEXT(require("../../update")((err) => { try { - expect(/Aborted because \.\/c\.js is not accepted/.test(err.message)).toBe(true); - expect(/Update propagation: \.\/c\.js -> \.\/b\.js -> \.\/index\.js/.test(err.message)).toBe(true); + expect(err.message).toMatch(/Aborted because \.\/c\.js is not accepted/); + expect(err.message).toMatch(/Update propagation: \.\/c\.js -> \.\/b\.js -> \.\/index\.js/); done(); } catch(e) { done(e); } })); diff --git a/test/statsCases/filter-warnings/a.js b/test/statsCases/filter-warnings/a.js index c5264c9c2..259e3bd7a 100644 --- a/test/statsCases/filter-warnings/a.js +++ b/test/statsCases/filter-warnings/a.js @@ -1,4 +1,4 @@ -module.export = function someUsedFunction() {}; +module.exports = function someUsedFunction() {}; function someRemoteUnUsedFunction1() {} function someRemoteUnUsedFunction2() {} diff --git a/test/watchCases/plugins/module-concatenation-plugin/0/index.js b/test/watchCases/plugins/module-concatenation-plugin/0/index.js index 91b447495..e99887547 100644 --- a/test/watchCases/plugins/module-concatenation-plugin/0/index.js +++ b/test/watchCases/plugins/module-concatenation-plugin/0/index.js @@ -9,5 +9,5 @@ it("should watch for changes", function() { expect(require("./foo/" + WATCH_STEP)).toBe('This should be working.' + WATCH_STEP); } - expect(STATS_JSON.modules.length).toBe(7 + Number(WATCH_STEP)); + expect(STATS_JSON.modules.filter(m => !m.runtime).length).toBe(4 + Number(WATCH_STEP)); });