Merge pull request #10080 from webpack/feature/cjs-tree-shaking

CommonJs Tree Shaking
This commit is contained in:
Tobias Koppers 2019-12-08 22:45:14 +01:00 committed by GitHub
commit 964160a97f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
119 changed files with 3312 additions and 1157 deletions

View File

@ -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;
};
/***/ })
/******/ ]);
```
<details><summary><code>/* webpack runtime code */</code></summary>
``` 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;
/******/ }
/******/
/************************************************************************/
```
</details>
``` 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<e;)r+=n[t++];return r}}],t={};function n(e){if(t[e])return t[e].exports;var o=t[e]={exports:{}};return r[e](o,o.exports,n),o.exports}(0,n(1).pD)(1)})();
```
# dist/without.js (same without tree shaking)
```javascript
/*! For license information please see without.js.LICENSE */
(()=>{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<e;)n+=t[r++];return n},r.multiply=function(){for(var n=0,r=arguments,t=r.length;n<t;)sum*=r[n++];return sum}}],r={};function t(e){if(r[e])return r[e].exports;var u=r[e]={exports:{}};return n[e](u,u.exports,t),u.exports}(0,t(1).increment)(1)})();
```
# Info
## Unoptimized
```
Hash: 0a1b2c3d4e5f6a7b8c9d
Version: webpack 5.0.0-beta.7
Child
Hash: 0a1b2c3d4e5f6a7b8c9d
Asset Size
output.js 3.44 KiB [emitted] [name: main]
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 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
```

View File

@ -0,0 +1,2 @@
global.NO_TARGET_ARGS = true;
require("../build-common");

View File

@ -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;

View File

@ -0,0 +1,3 @@
const inc = require("./increment").increment;
var a = 1;
inc(a); // 2

View File

@ -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);
};

View File

@ -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;
};

View File

@ -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}}_
```

View File

@ -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
}
}
];

View File

@ -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;

View File

@ -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;

View File

@ -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
? "<skip-over-name>"
: exportInfo.usedName + ""
);
}
if (this.presentationalDependencies !== undefined) {
for (const dep of this.presentationalDependencies) {

View File

@ -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;

View File

@ -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(

View File

@ -13,13 +13,15 @@ const AbstractMethodError = require("./AbstractMethodError");
/** @typedef {Record<string, any>} PreparsedAst */
/**
* @typedef {Object} ParserState
* @typedef {Object} ParserStateBase
* @property {NormalModule} current
* @property {NormalModule} module
* @property {Compilation} compilation
* @property {TODO} options
*/
/** @typedef {Record<string, any> & ParserStateBase} ParserState */
class Parser {
/**
* @param {string | Buffer | PreparsedAst} source the source to parse

View File

@ -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
*/

View File

@ -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 => {

View File

@ -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<string>} 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);

21
lib/SelfModuleFactory.js Normal file
View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View File

@ -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;

View File

@ -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<NormalModule, boolean>} */
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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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<ParserState, boolean>} */
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;
};

View File

@ -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;
}
};

View File

@ -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,

View File

@ -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<ParserState, boolean>} */
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;
};

View File

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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}
});
}

View File

@ -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(

View File

@ -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;

View File

@ -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;

View File

@ -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;"
]);

View File

@ -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<SyncBailHook<[import("estree").AssignmentExpression], boolean | void>>} */
assign: new HookMap(() => new SyncBailHook(["expression"])),
/** @type {HookMap<SyncBailHook<[import("estree").AssignmentExpression, string[]], boolean | void>>} */
assignMemberChain: new HookMap(
() => new SyncBailHook(["expression", "members"])
),
/** @type {HookMap<SyncBailHook<[ExpressionNode], boolean | void>>} */
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<SyncBailHook<[ExpressionNode], boolean | void>>} */
call: new HookMap(() => new SyncBailHook(["expression"])),
/** @type {HookMap<SyncBailHook<[ExpressionNode, any[]], boolean | void>>} */
/** Something like "a.b()" */
/** @type {HookMap<SyncBailHook<[ExpressionNode, string[]], boolean | void>>} */
callMemberChain: new HookMap(
() => new SyncBailHook(["expression", "members"])
),
/** Something like "a.b().c.d" */
/** @type {HookMap<SyncBailHook<[ExpressionNode, string[], CallExpressionNode, string[]], boolean | void>>} */
memberChainOfCallMemberChain: new HookMap(
() =>
new SyncBailHook([
"expression",
"calleeMembers",
"callExpression",
"members"
])
),
/** Something like "a.b().c.d()"" */
/** @type {HookMap<SyncBailHook<[ExpressionNode, string[], CallExpressionNode, string[]], boolean | void>>} */
callMemberChainOfCallMemberChain: new HookMap(
() =>
new SyncBailHook([
"expression",
"calleeMembers",
"innerCallExpression",
"members"
])
),
/** @type {HookMap<SyncBailHook<[ExpressionNode], boolean | void>>} */
new: new HookMap(() => new SyncBailHook(["expression"])),
/** @type {HookMap<SyncBailHook<[ExpressionNode], boolean | void>>} */
expression: new HookMap(() => new SyncBailHook(["expression"])),
/** @type {HookMap<SyncBailHook<[ExpressionNode, any[]], boolean | void>>} */
/** @type {HookMap<SyncBailHook<[ExpressionNode, string[]], boolean | void>>} */
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<SyncBailHook<T, R>>} 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<T>} 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

View File

@ -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))
);

View File

@ -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`

View File

@ -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
);
};

View File

@ -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": () =>

View File

@ -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(

View File

@ -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});`

View File

@ -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": "<cwd>/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": "<cwd>/test/fixtures/errors/module.parent.require.js",

View File

@ -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 {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
module.exports.func = function f() {
"use strict";
return this;
};
module.exports.abc = "abc";

View File

@ -0,0 +1,7 @@
exports.abc = "abc";
function f(m) {
m.exports = { abc: "abc", def: "def" };
}
f(module);

View File

@ -0,0 +1,6 @@
exports.abc = "abc";
var newObj = {};
exports = newObj;
exports.def = "def";

View File

@ -0,0 +1,6 @@
Object.defineProperty(exports, "abc", { value: "abc" });
var newObj = {};
exports = newObj;
Object.defineProperty(exports, "def", { value: "def" });

View File

@ -0,0 +1,10 @@
exports.abc = "abc";
Object.defineProperties(module, {
exports: {
value: {
abc: "abc",
def: "def"
}
}
});

View File

@ -0,0 +1,8 @@
exports.abc = "abc";
Object.defineProperty(module, "exports", {
value: {
abc: "abc",
def: "def"
}
});

View File

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

View File

@ -0,0 +1,8 @@
var abc = {};
module.exports = abc;
module.exports.abc = "abc";
module.exports.def = "def";
expect(abc).toEqual({ abc: "abc", def: "def" });

View File

@ -0,0 +1,5 @@
exports.abc = "abc";
exports.test = function() {
return exports;
};

View File

@ -0,0 +1,5 @@
exports.abc = "abc";
exports.test = function() {
return module.exports;
};

View File

@ -0,0 +1,5 @@
exports.abc = "abc";
exports.test = () => {
return this;
};

View File

@ -0,0 +1,5 @@
exports.abc = "not-abc";
define({
abc: "abc",
def: "def"
});

View File

@ -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)
);
});

View File

@ -0,0 +1,6 @@
export const abc = "abc";
export const def = "def";
export const func = function() {
"use strict";
return this;
};

View File

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

View File

@ -0,0 +1,2 @@
exports.abc = "abc";
exports.def = "def";

View File

@ -0,0 +1,2 @@
exports.abc = "abc";
exports.def = "def";

View File

@ -0,0 +1,2 @@
module.exports.abc = "abc";
module.exports.def = "def";

View File

@ -0,0 +1,2 @@
this.abc = "abc";
this.def = "def";

View File

@ -0,0 +1,3 @@
module.exports = () => "abc";
module.exports.def = "def";

View File

@ -0,0 +1,5 @@
module.exports = function() {
return "abc";
};
module.exports.def = "def";

View File

@ -0,0 +1,5 @@
module.exports = {
abc: "abc"
};
module.exports.def = "def";

View File

@ -0,0 +1,2 @@
Object.defineProperty(exports, "abc", { enumerable: true, value: "abc" });
Object.defineProperty(exports, "def", { enumerable: true, value: "def" });

View File

@ -0,0 +1,8 @@
Object.defineProperty(module.exports, "abc", {
enumerable: true,
value: "abc"
});
Object.defineProperty(module.exports, "def", {
enumerable: true,
value: "def"
});

View File

@ -0,0 +1,2 @@
Object.defineProperty(this, "abc", { enumerable: true, value: "abc" });
Object.defineProperty(this, "def", { enumerable: true, value: "def" });

View File

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

View File

@ -0,0 +1,5 @@
exports.abc = "abc";
exports.test = function() {
return exports.abc;
};

View File

@ -0,0 +1,5 @@
exports.abc = "abc";
exports.test = function() {
return module.exports.abc;
};

View File

@ -0,0 +1,5 @@
exports.abc = "abc";
exports.test = () => {
return this.abc;
};

View File

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

View File

@ -0,0 +1,2 @@
exports.abc = "abc";
exports.def = "def";

View File

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

View File

@ -0,0 +1,2 @@
exports.abc = "abc";
exports.def = "def";

View File

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

View File

@ -0,0 +1,5 @@
Object.defineProperties(exports, {
__esModule: { value: true },
abc: { enumerable: true, value: "abc" },
default: { enumerable: true, value: "default" }
});

View File

@ -0,0 +1,3 @@
Object.defineProperty(exports, "__esModule", { value: !0 });
exports.abc = "abc";
exports.default = "default";

View File

@ -0,0 +1,3 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.abc = "abc";
exports.default = "default";

View File

@ -0,0 +1,3 @@
exports.__esModule = true;
exports.abc = "abc";
exports.default = "default";

View File

@ -0,0 +1,5 @@
module.exports = {
__esModule: true,
abc: "abc",
default: "default"
};

View File

@ -0,0 +1,4 @@
module.exports = {
abc: "abc",
def: "def"
};

View File

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

View File

@ -0,0 +1,6 @@
var value = {
abc: "abc",
def: "def"
};
module.exports = value;

View File

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

View File

@ -0,0 +1,2 @@
exports.abc = "abc";
exports.def = "def";

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

Some files were not shown because too many files have changed in this diff Show More