Merge pull request #10080 from webpack/feature/cjs-tree-shaking
CommonJs Tree Shaking
This commit is contained in:
commit
964160a97f
|
@ -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
|
||||
```
|
|
@ -0,0 +1,2 @@
|
|||
global.NO_TARGET_ARGS = true;
|
||||
require("../build-common");
|
|
@ -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;
|
|
@ -0,0 +1,3 @@
|
|||
const inc = require("./increment").increment;
|
||||
var a = 1;
|
||||
inc(a); // 2
|
|
@ -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);
|
||||
};
|
|
@ -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;
|
||||
};
|
|
@ -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}}_
|
||||
```
|
|
@ -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
|
||||
}
|
||||
}
|
||||
];
|
|
@ -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;
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
};
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
|
@ -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;"
|
||||
]);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
);
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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": () =>
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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});`
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
@ -0,0 +1,5 @@
|
|||
module.exports.func = function f() {
|
||||
"use strict";
|
||||
return this;
|
||||
};
|
||||
module.exports.abc = "abc";
|
|
@ -0,0 +1,7 @@
|
|||
exports.abc = "abc";
|
||||
|
||||
function f(m) {
|
||||
m.exports = { abc: "abc", def: "def" };
|
||||
}
|
||||
|
||||
f(module);
|
|
@ -0,0 +1,6 @@
|
|||
exports.abc = "abc";
|
||||
|
||||
var newObj = {};
|
||||
exports = newObj;
|
||||
|
||||
exports.def = "def";
|
|
@ -0,0 +1,6 @@
|
|||
Object.defineProperty(exports, "abc", { value: "abc" });
|
||||
|
||||
var newObj = {};
|
||||
exports = newObj;
|
||||
|
||||
Object.defineProperty(exports, "def", { value: "def" });
|
|
@ -0,0 +1,10 @@
|
|||
exports.abc = "abc";
|
||||
|
||||
Object.defineProperties(module, {
|
||||
exports: {
|
||||
value: {
|
||||
abc: "abc",
|
||||
def: "def"
|
||||
}
|
||||
}
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
exports.abc = "abc";
|
||||
|
||||
Object.defineProperty(module, "exports", {
|
||||
value: {
|
||||
abc: "abc",
|
||||
def: "def"
|
||||
}
|
||||
});
|
|
@ -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");
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
var abc = {};
|
||||
|
||||
module.exports = abc;
|
||||
|
||||
module.exports.abc = "abc";
|
||||
module.exports.def = "def";
|
||||
|
||||
expect(abc).toEqual({ abc: "abc", def: "def" });
|
|
@ -0,0 +1,5 @@
|
|||
exports.abc = "abc";
|
||||
|
||||
exports.test = function() {
|
||||
return exports;
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
exports.abc = "abc";
|
||||
|
||||
exports.test = function() {
|
||||
return module.exports;
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
exports.abc = "abc";
|
||||
|
||||
exports.test = () => {
|
||||
return this;
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
exports.abc = "not-abc";
|
||||
define({
|
||||
abc: "abc",
|
||||
def: "def"
|
||||
});
|
|
@ -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)
|
||||
);
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
export const abc = "abc";
|
||||
export const def = "def";
|
||||
export const func = function() {
|
||||
"use strict";
|
||||
return this;
|
||||
};
|
|
@ -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");
|
||||
});
|
|
@ -0,0 +1,2 @@
|
|||
exports.abc = "abc";
|
||||
exports.def = "def";
|
|
@ -0,0 +1,2 @@
|
|||
exports.abc = "abc";
|
||||
exports.def = "def";
|
|
@ -0,0 +1,2 @@
|
|||
module.exports.abc = "abc";
|
||||
module.exports.def = "def";
|
|
@ -0,0 +1,2 @@
|
|||
this.abc = "abc";
|
||||
this.def = "def";
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = () => "abc";
|
||||
|
||||
module.exports.def = "def";
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = function() {
|
||||
return "abc";
|
||||
};
|
||||
|
||||
module.exports.def = "def";
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
abc: "abc"
|
||||
};
|
||||
|
||||
module.exports.def = "def";
|
|
@ -0,0 +1,2 @@
|
|||
Object.defineProperty(exports, "abc", { enumerable: true, value: "abc" });
|
||||
Object.defineProperty(exports, "def", { enumerable: true, value: "def" });
|
|
@ -0,0 +1,8 @@
|
|||
Object.defineProperty(module.exports, "abc", {
|
||||
enumerable: true,
|
||||
value: "abc"
|
||||
});
|
||||
Object.defineProperty(module.exports, "def", {
|
||||
enumerable: true,
|
||||
value: "def"
|
||||
});
|
|
@ -0,0 +1,2 @@
|
|||
Object.defineProperty(this, "abc", { enumerable: true, value: "abc" });
|
||||
Object.defineProperty(this, "def", { enumerable: true, value: "def" });
|
|
@ -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");
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
exports.abc = "abc";
|
||||
|
||||
exports.test = function() {
|
||||
return exports.abc;
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
exports.abc = "abc";
|
||||
|
||||
exports.test = function() {
|
||||
return module.exports.abc;
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
exports.abc = "abc";
|
||||
|
||||
exports.test = () => {
|
||||
return this.abc;
|
||||
};
|
|
@ -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" });
|
||||
});
|
|
@ -0,0 +1,2 @@
|
|||
exports.abc = "abc";
|
||||
exports.def = "def";
|
|
@ -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");
|
||||
});
|
|
@ -0,0 +1,2 @@
|
|||
exports.abc = "abc";
|
||||
exports.def = "def";
|
|
@ -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")
|
||||
);
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
Object.defineProperties(exports, {
|
||||
__esModule: { value: true },
|
||||
abc: { enumerable: true, value: "abc" },
|
||||
default: { enumerable: true, value: "default" }
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
Object.defineProperty(exports, "__esModule", { value: !0 });
|
||||
exports.abc = "abc";
|
||||
exports.default = "default";
|
|
@ -0,0 +1,3 @@
|
|||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.abc = "abc";
|
||||
exports.default = "default";
|
|
@ -0,0 +1,3 @@
|
|||
exports.__esModule = true;
|
||||
exports.abc = "abc";
|
||||
exports.default = "default";
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
__esModule: true,
|
||||
abc: "abc",
|
||||
default: "default"
|
||||
};
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
abc: "abc",
|
||||
def: "def"
|
||||
};
|
|
@ -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" });
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
var value = {
|
||||
abc: "abc",
|
||||
def: "def"
|
||||
};
|
||||
|
||||
module.exports = value;
|
|
@ -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");
|
||||
});
|
|
@ -0,0 +1,2 @@
|
|||
exports.abc = "abc";
|
||||
exports.def = "def";
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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
Loading…
Reference in New Issue