Merge branch 'master' into feature/type-compiler-compilation-save
This commit is contained in:
commit
6e68f96d16
|
@ -51,6 +51,12 @@ or in watch mode
|
|||
yarn test:unit --watch
|
||||
```
|
||||
|
||||
### To update Jest snapshots use
|
||||
|
||||
```bash
|
||||
yarn test:update-snapshots
|
||||
```
|
||||
|
||||
### To run code formatter (prettier) run
|
||||
|
||||
```bash
|
||||
|
|
|
@ -4,7 +4,7 @@ It's built separately from the app part. The vendors dll is only built when the
|
|||
|
||||
The DllPlugin in combination with the `output.library` option exposes the internal require function as global variable in the target environment.
|
||||
|
||||
A manifest is creates which includes mappings from module names to internal ids.
|
||||
A manifest is created which includes mappings from module names to internal ids.
|
||||
|
||||
### webpack.config.js
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ It's built separately from the app part. The vendors dll is only built when the
|
|||
|
||||
The DllPlugin in combination with the `output.library` option exposes the internal require function as global variable in the target environment.
|
||||
|
||||
A manifest is creates which includes mappings from module names to internal ids.
|
||||
A manifest is created which includes mappings from module names to internal ids.
|
||||
|
||||
### webpack.config.js
|
||||
|
||||
|
|
|
@ -45,8 +45,10 @@ const ModuleDependency = require("./dependencies/ModuleDependency");
|
|||
/** @typedef {import("./dependencies/SingleEntryDependency")} SingleEntryDependency */
|
||||
/** @typedef {import("./dependencies/MultiEntryDependency")} MultiEntryDependency */
|
||||
/** @typedef {import("./dependencies/DllEntryDependency")} DllEntryDependency */
|
||||
/** @typedef {import("./dependencies/DependencyReference")} DependencyReference */
|
||||
/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
|
||||
/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
|
||||
/** @typedef {import("./Dependency")} Dependency */
|
||||
/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
|
||||
/** @typedef {import("./Dependency").DependencyTemplate} DependencyTemplate */
|
||||
/** @typedef {import("./util/createHash").Hash} Hash */
|
||||
|
@ -213,7 +215,15 @@ class Compilation extends Tapable {
|
|||
failedModule: new SyncHook(["module", "error"]),
|
||||
/** @type {SyncHook<Module>} */
|
||||
succeedModule: new SyncHook(["module"]),
|
||||
/** @type {SyncHook<Module[]>} */
|
||||
|
||||
/** @type {SyncWaterfallHook<DependencyReference, Dependency, Module>} */
|
||||
dependencyReference: new SyncWaterfallHook([
|
||||
"dependencyReference",
|
||||
"dependency",
|
||||
"module"
|
||||
]),
|
||||
|
||||
/** @type {SyncHook<Module[]>} */
|
||||
finishModules: new SyncHook(["modules"]),
|
||||
/** @type {SyncHook<Module>} */
|
||||
finishRebuildingModule: new SyncHook(["module"]),
|
||||
|
@ -1429,6 +1439,19 @@ class Compilation extends Tapable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module the module containing the dependency
|
||||
* @param {Dependency} dependency the dependency
|
||||
* @returns {DependencyReference} a reference for the dependency
|
||||
*/
|
||||
getDependencyReference(module, dependency) {
|
||||
// TODO remove dep.getReference existance check in webpack 5
|
||||
if (typeof dependency.getReference !== "function") return null;
|
||||
const ref = dependency.getReference();
|
||||
if (!ref) return null;
|
||||
return this.hooks.dependencyReference.call(ref, dependency, module);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates the Chunk graph from the Module graph
|
||||
* @private
|
||||
|
@ -1458,7 +1481,7 @@ class Compilation extends Tapable {
|
|||
*/
|
||||
const iteratorDependency = d => {
|
||||
// We skip Dependencies without Reference
|
||||
const ref = d.getReference();
|
||||
const ref = this.getDependencyReference(currentModule, d);
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
|
@ -1484,6 +1507,8 @@ class Compilation extends Tapable {
|
|||
blockQueue.push(b);
|
||||
};
|
||||
|
||||
/** @type {Module} */
|
||||
let currentModule;
|
||||
/** @type {DependenciesBlock} */
|
||||
let block;
|
||||
/** @type {DependenciesBlock[]} */
|
||||
|
@ -1495,6 +1520,7 @@ class Compilation extends Tapable {
|
|||
|
||||
for (const module of this.modules) {
|
||||
blockQueue = [module];
|
||||
currentModule = module;
|
||||
while (blockQueue.length > 0) {
|
||||
block = blockQueue.pop();
|
||||
blockInfoModules = new Set();
|
||||
|
@ -2246,6 +2272,8 @@ class Compilation extends Tapable {
|
|||
createChunkAssets() {
|
||||
const outputOptions = this.outputOptions;
|
||||
const cachedSourceMap = new Map();
|
||||
/** @type {Map<string, {hash: string, source: Source, chunk: Chunk}>} */
|
||||
const alreadyWrittenFiles = new Map();
|
||||
for (let i = 0; i < this.chunks.length; i++) {
|
||||
const chunk = this.chunks[i];
|
||||
chunk.files = [];
|
||||
|
@ -2268,6 +2296,28 @@ class Compilation extends Tapable {
|
|||
const cacheName = fileManifest.identifier;
|
||||
const usedHash = fileManifest.hash;
|
||||
filenameTemplate = fileManifest.filenameTemplate;
|
||||
file = this.getPath(filenameTemplate, fileManifest.pathOptions);
|
||||
|
||||
// check if the same filename was already written by another chunk
|
||||
const alreadyWritten = alreadyWrittenFiles.get(file);
|
||||
if (alreadyWritten !== undefined) {
|
||||
if (alreadyWritten.hash === usedHash) {
|
||||
if (this.cache) {
|
||||
this.cache[cacheName] = {
|
||||
hash: usedHash,
|
||||
source: alreadyWritten.source
|
||||
};
|
||||
}
|
||||
chunk.files.push(file);
|
||||
this.hooks.chunkAsset.call(chunk, file);
|
||||
continue;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Conflict: Multiple chunks emit assets to the same filename ${file}` +
|
||||
` (chunks ${alreadyWritten.chunk.id} and ${chunk.id})`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (
|
||||
this.cache &&
|
||||
this.cache[cacheName] &&
|
||||
|
@ -2294,7 +2344,6 @@ class Compilation extends Tapable {
|
|||
};
|
||||
}
|
||||
}
|
||||
file = this.getPath(filenameTemplate, fileManifest.pathOptions);
|
||||
if (this.assets[file] && this.assets[file] !== source) {
|
||||
throw new Error(
|
||||
`Conflict: Multiple assets emit to the same filename ${file}`
|
||||
|
@ -2303,6 +2352,11 @@ class Compilation extends Tapable {
|
|||
this.assets[file] = source;
|
||||
chunk.files.push(file);
|
||||
this.hooks.chunkAsset.call(chunk, file);
|
||||
alreadyWrittenFiles.set(file, {
|
||||
hash: usedHash,
|
||||
source,
|
||||
chunk
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
this.errors.push(
|
||||
|
|
|
@ -9,26 +9,44 @@ const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
|
|||
const ParserHelpers = require("./ParserHelpers");
|
||||
const NullFactory = require("./NullFactory");
|
||||
|
||||
const stringifyObj = obj => {
|
||||
class RuntimeValue {
|
||||
constructor(fn, fileDependencies) {
|
||||
this.fn = fn;
|
||||
this.fileDependencies = fileDependencies || [];
|
||||
}
|
||||
|
||||
exec(parser) {
|
||||
for (const fileDependency of this.fileDependencies) {
|
||||
parser.state.module.buildInfo.fileDependencies.add(fileDependency);
|
||||
}
|
||||
|
||||
return this.fn();
|
||||
}
|
||||
}
|
||||
|
||||
const stringifyObj = (obj, parser) => {
|
||||
return (
|
||||
"Object({" +
|
||||
Object.keys(obj)
|
||||
.map(key => {
|
||||
const code = obj[key];
|
||||
return JSON.stringify(key) + ":" + toCode(code);
|
||||
return JSON.stringify(key) + ":" + toCode(code, parser);
|
||||
})
|
||||
.join(",") +
|
||||
"})"
|
||||
);
|
||||
};
|
||||
|
||||
const toCode = code => {
|
||||
const toCode = (code, parser) => {
|
||||
if (code === null) {
|
||||
return "null";
|
||||
}
|
||||
if (code === undefined) {
|
||||
return "undefined";
|
||||
}
|
||||
if (code instanceof RuntimeValue) {
|
||||
return toCode(code.exec(parser), parser);
|
||||
}
|
||||
if (code instanceof RegExp && code.toString) {
|
||||
return code.toString();
|
||||
}
|
||||
|
@ -36,7 +54,7 @@ const toCode = code => {
|
|||
return "(" + code.toString() + ")";
|
||||
}
|
||||
if (typeof code === "object") {
|
||||
return stringifyObj(code);
|
||||
return stringifyObj(code, parser);
|
||||
}
|
||||
return code + "";
|
||||
};
|
||||
|
@ -46,6 +64,10 @@ class DefinePlugin {
|
|||
this.definitions = definitions;
|
||||
}
|
||||
|
||||
static runtimeValue(fn, fileDependencies) {
|
||||
return new RuntimeValue(fn, fileDependencies);
|
||||
}
|
||||
|
||||
apply(compiler) {
|
||||
const definitions = this.definitions;
|
||||
compiler.hooks.compilation.tap(
|
||||
|
@ -64,6 +86,7 @@ class DefinePlugin {
|
|||
if (
|
||||
code &&
|
||||
typeof code === "object" &&
|
||||
!(code instanceof RuntimeValue) &&
|
||||
!(code instanceof RegExp)
|
||||
) {
|
||||
walkDefinitions(code, prefix + key + ".");
|
||||
|
@ -90,7 +113,6 @@ class DefinePlugin {
|
|||
if (isTypeof) key = key.replace(/^typeof\s+/, "");
|
||||
let recurse = false;
|
||||
let recurseTypeof = false;
|
||||
code = toCode(code);
|
||||
if (!isTypeof) {
|
||||
parser.hooks.canRename
|
||||
.for(key)
|
||||
|
@ -108,24 +130,25 @@ class DefinePlugin {
|
|||
*/
|
||||
if (recurse) return;
|
||||
recurse = true;
|
||||
const res = parser.evaluate(code);
|
||||
const res = parser.evaluate(toCode(code, parser));
|
||||
recurse = false;
|
||||
res.setRange(expr.range);
|
||||
return res;
|
||||
});
|
||||
parser.hooks.expression
|
||||
.for(key)
|
||||
.tap(
|
||||
"DefinePlugin",
|
||||
/__webpack_require__/.test(code)
|
||||
? ParserHelpers.toConstantDependencyWithWebpackRequire(
|
||||
parser,
|
||||
code
|
||||
)
|
||||
: ParserHelpers.toConstantDependency(parser, code)
|
||||
);
|
||||
parser.hooks.expression.for(key).tap("DefinePlugin", expr => {
|
||||
const strCode = toCode(code, parser);
|
||||
if (/__webpack_require__/.test(strCode)) {
|
||||
return ParserHelpers.toConstantDependencyWithWebpackRequire(
|
||||
parser,
|
||||
strCode
|
||||
)(expr);
|
||||
} else {
|
||||
return ParserHelpers.toConstantDependency(parser, strCode)(
|
||||
expr
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
const typeofCode = isTypeof ? code : "typeof (" + code + ")";
|
||||
parser.hooks.evaluateTypeof.for(key).tap("DefinePlugin", expr => {
|
||||
/**
|
||||
* this is needed in case there is a recursion in the DefinePlugin
|
||||
|
@ -137,12 +160,18 @@ class DefinePlugin {
|
|||
*/
|
||||
if (recurseTypeof) return;
|
||||
recurseTypeof = true;
|
||||
const typeofCode = isTypeof
|
||||
? toCode(code, parser)
|
||||
: "typeof (" + toCode(code, parser) + ")";
|
||||
const res = parser.evaluate(typeofCode);
|
||||
recurseTypeof = false;
|
||||
res.setRange(expr.range);
|
||||
return res;
|
||||
});
|
||||
parser.hooks.typeof.for(key).tap("DefinePlugin", expr => {
|
||||
const typeofCode = isTypeof
|
||||
? toCode(code, parser)
|
||||
: "typeof (" + toCode(code, parser) + ")";
|
||||
const res = parser.evaluate(typeofCode);
|
||||
if (!res.isString()) return;
|
||||
return ParserHelpers.toConstantDependency(
|
||||
|
@ -153,7 +182,6 @@ class DefinePlugin {
|
|||
};
|
||||
|
||||
const applyObjectDefine = (key, obj) => {
|
||||
const code = stringifyObj(obj);
|
||||
parser.hooks.canRename
|
||||
.for(key)
|
||||
.tap("DefinePlugin", ParserHelpers.approve);
|
||||
|
@ -162,29 +190,29 @@ class DefinePlugin {
|
|||
.tap("DefinePlugin", expr =>
|
||||
new BasicEvaluatedExpression().setTruthy().setRange(expr.range)
|
||||
);
|
||||
parser.hooks.evaluateTypeof
|
||||
.for(key)
|
||||
.tap("DefinePlugin", ParserHelpers.evaluateToString("object"));
|
||||
parser.hooks.expression
|
||||
.for(key)
|
||||
.tap(
|
||||
"DefinePlugin",
|
||||
/__webpack_require__/.test(code)
|
||||
? ParserHelpers.toConstantDependencyWithWebpackRequire(
|
||||
parser,
|
||||
code
|
||||
)
|
||||
: ParserHelpers.toConstantDependency(parser, code)
|
||||
);
|
||||
parser.hooks.typeof
|
||||
.for(key)
|
||||
.tap(
|
||||
"DefinePlugin",
|
||||
ParserHelpers.toConstantDependency(
|
||||
parser.hooks.evaluateTypeof.for(key).tap("DefinePlugin", expr => {
|
||||
return ParserHelpers.evaluateToString("object")(expr);
|
||||
});
|
||||
parser.hooks.expression.for(key).tap("DefinePlugin", expr => {
|
||||
const strCode = stringifyObj(obj, parser);
|
||||
|
||||
if (/__webpack_require__/.test(strCode)) {
|
||||
return ParserHelpers.toConstantDependencyWithWebpackRequire(
|
||||
parser,
|
||||
JSON.stringify("object")
|
||||
)
|
||||
);
|
||||
strCode
|
||||
)(expr);
|
||||
} else {
|
||||
return ParserHelpers.toConstantDependency(parser, strCode)(
|
||||
expr
|
||||
);
|
||||
}
|
||||
});
|
||||
parser.hooks.typeof.for(key).tap("DefinePlugin", expr => {
|
||||
return ParserHelpers.toConstantDependency(
|
||||
parser,
|
||||
JSON.stringify("object")
|
||||
)(expr);
|
||||
});
|
||||
};
|
||||
|
||||
walkDefinitions(definitions, "");
|
||||
|
|
|
@ -63,11 +63,9 @@ class DependenciesBlockVariable {
|
|||
|
||||
hasDependencies(filter) {
|
||||
if (filter) {
|
||||
if (this.dependencies.some(filter)) return true;
|
||||
} else {
|
||||
if (this.dependencies.length > 0) return true;
|
||||
return this.dependencies.some(filter);
|
||||
}
|
||||
return false;
|
||||
return this.dependencies.length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
*/
|
||||
"use strict";
|
||||
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
|
||||
|
||||
/** @typedef {false | true | string[]} UsedExports */
|
||||
|
||||
const addToSet = (a, b) => {
|
||||
for (const item of b) {
|
||||
if (!a.includes(item)) a.push(item);
|
||||
|
@ -54,37 +59,36 @@ class FlagDependencyUsagePlugin {
|
|||
return;
|
||||
}
|
||||
|
||||
queue.push([module, module.usedExports]);
|
||||
queue.push([module, module, module.usedExports]);
|
||||
};
|
||||
|
||||
const processDependenciesBlock = (depBlock, usedExports) => {
|
||||
const processDependenciesBlock = (module, depBlock, usedExports) => {
|
||||
for (const dep of depBlock.dependencies) {
|
||||
processDependency(dep);
|
||||
processDependency(module, dep);
|
||||
}
|
||||
for (const variable of depBlock.variables) {
|
||||
for (const dep of variable.dependencies) {
|
||||
processDependency(dep);
|
||||
processDependency(module, dep);
|
||||
}
|
||||
}
|
||||
for (const block of depBlock.blocks) {
|
||||
queue.push([block, usedExports]);
|
||||
queue.push([module, block, usedExports]);
|
||||
}
|
||||
};
|
||||
|
||||
const processDependency = dep => {
|
||||
// TODO remove dep.getReference existance check in webpack 5
|
||||
const reference = dep.getReference && dep.getReference();
|
||||
const processDependency = (module, dep) => {
|
||||
const reference = compilation.getDependencyReference(module, dep);
|
||||
if (!reference) return;
|
||||
const module = reference.module;
|
||||
const referenceModule = reference.module;
|
||||
const importedNames = reference.importedNames;
|
||||
const oldUsed = module.used;
|
||||
const oldUsedExports = module.usedExports;
|
||||
const oldUsed = referenceModule.used;
|
||||
const oldUsedExports = referenceModule.usedExports;
|
||||
if (
|
||||
!oldUsed ||
|
||||
(importedNames &&
|
||||
(!oldUsedExports || !isSubset(oldUsedExports, importedNames)))
|
||||
) {
|
||||
processModule(module, importedNames);
|
||||
processModule(referenceModule, importedNames);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -92,6 +96,7 @@ class FlagDependencyUsagePlugin {
|
|||
module.used = false;
|
||||
}
|
||||
|
||||
/** @type {[Module, DependenciesBlock, UsedExports][]} */
|
||||
const queue = [];
|
||||
for (const preparedEntrypoint of compilation._preparedEntrypoints) {
|
||||
if (preparedEntrypoint.module) {
|
||||
|
@ -101,7 +106,7 @@ class FlagDependencyUsagePlugin {
|
|||
|
||||
while (queue.length) {
|
||||
const queueItem = queue.pop();
|
||||
processDependenciesBlock(queueItem[0], queueItem[1]);
|
||||
processDependenciesBlock(queueItem[0], queueItem[1], queueItem[2]);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -265,6 +265,10 @@ module.exports = class RuntimeTemplate {
|
|||
|
||||
if (exportName) {
|
||||
const used = module.isUsed(exportName);
|
||||
if (!used) {
|
||||
const comment = Template.toNormalComment(`unused export ${exportName}`);
|
||||
return `${comment} undefined`;
|
||||
}
|
||||
const comment =
|
||||
used !== exportName ? Template.toNormalComment(exportName) + " " : "";
|
||||
const access = `${importVar}[${comment}${JSON.stringify(used)}]`;
|
||||
|
|
|
@ -56,6 +56,7 @@ const RuntimeChunkPlugin = require("./optimize/RuntimeChunkPlugin");
|
|||
const NoEmitOnErrorsPlugin = require("./NoEmitOnErrorsPlugin");
|
||||
const NamedModulesPlugin = require("./NamedModulesPlugin");
|
||||
const NamedChunksPlugin = require("./NamedChunksPlugin");
|
||||
const HashedModuleIdsPlugin = require("./HashedModuleIdsPlugin");
|
||||
const DefinePlugin = require("./DefinePlugin");
|
||||
const SizeLimitsPlugin = require("./performance/SizeLimitsPlugin");
|
||||
const WasmFinalizeExportsPlugin = require("./wasm/WasmFinalizeExportsPlugin");
|
||||
|
@ -354,6 +355,9 @@ class WebpackOptionsApply extends OptionsApply {
|
|||
if (options.optimization.namedModules) {
|
||||
new NamedModulesPlugin().apply(compiler);
|
||||
}
|
||||
if (options.optimization.hashedModuleIds) {
|
||||
new HashedModuleIdsPlugin().apply(compiler);
|
||||
}
|
||||
if (options.optimization.namedChunks) {
|
||||
new NamedChunksPlugin().apply(compiler);
|
||||
}
|
||||
|
|
|
@ -263,6 +263,7 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
|
|||
"make",
|
||||
options => options.mode === "development"
|
||||
);
|
||||
this.set("optimization.hashedModuleIds", false);
|
||||
this.set(
|
||||
"optimization.namedChunks",
|
||||
"make",
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
/** @typedef {import("../Module")} Module */
|
||||
|
||||
class DependencyReference {
|
||||
// TODO webpack 5: module must be dynamic, you must pass a function returning a module
|
||||
// This is needed to remove the hack in ConcatenatedModule
|
||||
// The problem is that the `module` in Dependency could be replaced i. e. because of Scope Hoisting
|
||||
/**
|
||||
*
|
||||
* @param {Module} module the referenced module
|
||||
|
@ -15,6 +18,7 @@ class DependencyReference {
|
|||
* @param {number} order the order information or NaN if don't care
|
||||
*/
|
||||
constructor(module, importedNames, weak = false, order = NaN) {
|
||||
// TODO webpack 5: make it a getter
|
||||
this.module = module;
|
||||
// true: full object
|
||||
// false: only sideeffects/no export
|
||||
|
|
|
@ -602,10 +602,10 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
|
|||
|
||||
getReexportStatement(module, key, name, valueKey) {
|
||||
const exportsName = module.exportsArgument;
|
||||
const returnValue = this.getReturnValue(valueKey);
|
||||
const returnValue = this.getReturnValue(name, valueKey);
|
||||
return `__webpack_require__.d(${exportsName}, ${JSON.stringify(
|
||||
key
|
||||
)}, function() { return ${name}${returnValue}; });\n`;
|
||||
)}, function() { return ${returnValue}; });\n`;
|
||||
}
|
||||
|
||||
getReexportFakeNamespaceObjectStatement(module, key, name) {
|
||||
|
@ -616,20 +616,29 @@ HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedS
|
|||
}
|
||||
|
||||
getConditionalReexportStatement(module, key, name, valueKey) {
|
||||
if (valueKey === false) {
|
||||
return "/* unused export */\n";
|
||||
}
|
||||
const exportsName = module.exportsArgument;
|
||||
const returnValue = this.getReturnValue(valueKey);
|
||||
const returnValue = this.getReturnValue(name, valueKey);
|
||||
return `if(__webpack_require__.o(${name}, ${JSON.stringify(
|
||||
valueKey
|
||||
)})) __webpack_require__.d(${exportsName}, ${JSON.stringify(
|
||||
key
|
||||
)}, function() { return ${name}${returnValue}; });\n`;
|
||||
)}, function() { return ${returnValue}; });\n`;
|
||||
}
|
||||
|
||||
getReturnValue(valueKey) {
|
||||
getReturnValue(name, valueKey) {
|
||||
if (valueKey === null) {
|
||||
return "_default.a";
|
||||
return `${name}_default.a`;
|
||||
}
|
||||
if (valueKey === "") {
|
||||
return name;
|
||||
}
|
||||
if (valueKey === false) {
|
||||
return "/* unused export */ undefined";
|
||||
}
|
||||
|
||||
return valueKey && "[" + JSON.stringify(valueKey) + "]";
|
||||
return `${name}[${JSON.stringify(valueKey)}]`;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -20,6 +20,13 @@ const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibi
|
|||
const createHash = require("../util/createHash");
|
||||
|
||||
/** @typedef {import("../Dependency")} Dependency */
|
||||
/** @typedef {import("../Compilation")} Compilation */
|
||||
|
||||
/**
|
||||
* @typedef {Object} ConcatenationEntry
|
||||
* @property {"concatenated" | "external"} type
|
||||
* @property {Module} module
|
||||
*/
|
||||
|
||||
const ensureNsObjSource = (
|
||||
info,
|
||||
|
@ -125,6 +132,8 @@ const getFinalName = (
|
|||
requestShortener,
|
||||
strictHarmonyModule
|
||||
);
|
||||
} else if (!info.module.isUsed(exportName)) {
|
||||
return "/* unused export */ undefined";
|
||||
}
|
||||
const name = info.internalNames.get(directExport);
|
||||
if (!name) {
|
||||
|
@ -275,7 +284,7 @@ const getPathInAst = (ast, node) => {
|
|||
};
|
||||
|
||||
class ConcatenatedModule extends Module {
|
||||
constructor(rootModule, modules) {
|
||||
constructor(rootModule, modules, concatenationList) {
|
||||
super("javascript/esm", null);
|
||||
super.setChunks(rootModule._chunks);
|
||||
|
||||
|
@ -320,10 +329,9 @@ class ConcatenatedModule extends Module {
|
|||
|
||||
this.warnings = [];
|
||||
this.errors = [];
|
||||
this._orderedConcatenationList = this._createOrderedConcatenationList(
|
||||
rootModule,
|
||||
modulesSet
|
||||
);
|
||||
this._orderedConcatenationList =
|
||||
concatenationList ||
|
||||
ConcatenatedModule.createConcatenationList(rootModule, modulesSet, null);
|
||||
for (const info of this._orderedConcatenationList) {
|
||||
if (info.type === "concatenated") {
|
||||
const m = info.module;
|
||||
|
@ -410,7 +418,13 @@ class ConcatenatedModule extends Module {
|
|||
}, 0);
|
||||
}
|
||||
|
||||
_createOrderedConcatenationList(rootModule, modulesSet) {
|
||||
/**
|
||||
* @param {Module} rootModule the root of the concatenation
|
||||
* @param {Set<Module>} modulesSet a set of modules which should be concatenated
|
||||
* @param {Compilation} compilation the compilation context
|
||||
* @returns {ConcatenationEntry[]} concatenation list
|
||||
*/
|
||||
static createConcatenationList(rootModule, modulesSet, compilation) {
|
||||
const list = [];
|
||||
const set = new Set();
|
||||
|
||||
|
@ -424,15 +438,16 @@ class ConcatenatedModule extends Module {
|
|||
const references = module.dependencies
|
||||
.filter(dep => dep instanceof HarmonyImportDependency)
|
||||
.map(dep => {
|
||||
const ref = dep.getReference();
|
||||
const ref = compilation.getDependencyReference(module, dep);
|
||||
if (ref) map.set(ref, dep);
|
||||
return ref;
|
||||
})
|
||||
.filter(ref => ref);
|
||||
DependencyReference.sort(references);
|
||||
// TODO webpack 5: remove this hack, see also DependencyReference
|
||||
return references.map(ref => {
|
||||
const dep = map.get(ref);
|
||||
return () => dep.getReference().module;
|
||||
return () => compilation.getDependencyReference(module, dep).module;
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -213,8 +213,9 @@ class ModuleConcatenationPlugin {
|
|||
const failureCache = new Map();
|
||||
|
||||
// try to add all imports
|
||||
for (const imp of this.getImports(currentRoot)) {
|
||||
const problem = this.tryToAdd(
|
||||
for (const imp of this._getImports(compilation, currentRoot)) {
|
||||
const problem = this._tryToAdd(
|
||||
compilation,
|
||||
currentConfiguration,
|
||||
imp,
|
||||
possibleInners,
|
||||
|
@ -245,9 +246,15 @@ class ModuleConcatenationPlugin {
|
|||
for (const concatConfiguration of concatConfigurations) {
|
||||
if (usedModules.has(concatConfiguration.rootModule)) continue;
|
||||
const modules = concatConfiguration.getModules();
|
||||
const rootModule = concatConfiguration.rootModule;
|
||||
const newModule = new ConcatenatedModule(
|
||||
concatConfiguration.rootModule,
|
||||
modules
|
||||
rootModule,
|
||||
Array.from(modules),
|
||||
ConcatenatedModule.createConcatenationList(
|
||||
rootModule,
|
||||
modules,
|
||||
compilation
|
||||
)
|
||||
);
|
||||
for (const warning of concatConfiguration.getWarningsSorted()) {
|
||||
newModule.optimizationBailout.push(requestShortener => {
|
||||
|
@ -320,15 +327,16 @@ class ModuleConcatenationPlugin {
|
|||
);
|
||||
}
|
||||
|
||||
getImports(module) {
|
||||
_getImports(compilation, module) {
|
||||
return new Set(
|
||||
module.dependencies
|
||||
|
||||
// Get reference info only for harmony Dependencies
|
||||
.map(
|
||||
dep =>
|
||||
dep instanceof HarmonyImportDependency ? dep.getReference() : null
|
||||
)
|
||||
.map(dep => {
|
||||
if (!(dep instanceof HarmonyImportDependency)) return null;
|
||||
if (!compilation) return dep.getReference();
|
||||
return compilation.getDependencyReference(module, dep);
|
||||
})
|
||||
|
||||
// Reference is valid and has a module
|
||||
// Dependencies are simple enough to concat them
|
||||
|
@ -345,7 +353,7 @@ class ModuleConcatenationPlugin {
|
|||
);
|
||||
}
|
||||
|
||||
tryToAdd(config, module, possibleModules, failureCache) {
|
||||
_tryToAdd(compilation, config, module, possibleModules, failureCache) {
|
||||
const cacheEntry = failureCache.get(module);
|
||||
if (cacheEntry) {
|
||||
return cacheEntry;
|
||||
|
@ -383,7 +391,8 @@ class ModuleConcatenationPlugin {
|
|||
)
|
||||
continue;
|
||||
|
||||
const problem = this.tryToAdd(
|
||||
const problem = this._tryToAdd(
|
||||
compilation,
|
||||
testConfig,
|
||||
reason.module,
|
||||
possibleModules,
|
||||
|
@ -399,8 +408,14 @@ class ModuleConcatenationPlugin {
|
|||
config.set(testConfig);
|
||||
|
||||
// Eagerly try to add imports too if possible
|
||||
for (const imp of this.getImports(module)) {
|
||||
const problem = this.tryToAdd(config, imp, possibleModules, failureCache);
|
||||
for (const imp of this._getImports(compilation, module)) {
|
||||
const problem = this._tryToAdd(
|
||||
compilation,
|
||||
config,
|
||||
imp,
|
||||
possibleModules,
|
||||
failureCache
|
||||
);
|
||||
if (problem) {
|
||||
config.addWarning(imp, problem);
|
||||
}
|
||||
|
@ -451,7 +466,7 @@ class ConcatConfiguration {
|
|||
}
|
||||
|
||||
getModules() {
|
||||
return this.modules.asArray();
|
||||
return this.modules.asSet();
|
||||
}
|
||||
|
||||
clone() {
|
||||
|
|
|
@ -25,7 +25,10 @@ class WasmFinalizeExportsPlugin {
|
|||
for (const reason of module.reasons) {
|
||||
// 2. is referenced by a non-WebAssembly module
|
||||
if (reason.module.type.startsWith("webassembly") === false) {
|
||||
const ref = reason.dependency.getReference();
|
||||
const ref = compilation.getDependencyReference(
|
||||
reason.module,
|
||||
reason.dependency
|
||||
);
|
||||
|
||||
const importedNames = ref.importedNames;
|
||||
|
||||
|
|
|
@ -154,15 +154,21 @@ class JsonpMainTemplatePlugin {
|
|||
: "",
|
||||
"script.charset = 'utf-8';",
|
||||
`script.timeout = ${chunkLoadTimeout / 1000};`,
|
||||
crossOriginLoading
|
||||
? `script.crossOrigin = ${JSON.stringify(crossOriginLoading)};`
|
||||
: "",
|
||||
`if (${mainTemplate.requireFn}.nc) {`,
|
||||
Template.indent(
|
||||
`script.setAttribute("nonce", ${mainTemplate.requireFn}.nc);`
|
||||
),
|
||||
"}",
|
||||
"script.src = jsonpScriptSrc(chunkId);",
|
||||
crossOriginLoading
|
||||
? Template.asString([
|
||||
"if (script.src.indexOf(window.location.origin + '/') !== 0) {",
|
||||
Template.indent(
|
||||
`script.crossOrigin = ${JSON.stringify(crossOriginLoading)};`
|
||||
),
|
||||
"}"
|
||||
])
|
||||
: "",
|
||||
"onScriptComplete = function (event) {",
|
||||
Template.indent([
|
||||
"// avoid mem leaks in IE.",
|
||||
|
@ -208,9 +214,6 @@ class JsonpMainTemplatePlugin {
|
|||
? `link.type = ${JSON.stringify(jsonpScriptType)};`
|
||||
: "",
|
||||
"link.charset = 'utf-8';",
|
||||
crossOriginLoading
|
||||
? `link.crossOrigin = ${JSON.stringify(crossOriginLoading)};`
|
||||
: "",
|
||||
`if (${mainTemplate.requireFn}.nc) {`,
|
||||
Template.indent(
|
||||
`link.setAttribute("nonce", ${mainTemplate.requireFn}.nc);`
|
||||
|
@ -218,7 +221,16 @@ class JsonpMainTemplatePlugin {
|
|||
"}",
|
||||
'link.rel = "preload";',
|
||||
'link.as = "script";',
|
||||
"link.href = jsonpScriptSrc(chunkId);"
|
||||
"link.href = jsonpScriptSrc(chunkId);",
|
||||
crossOriginLoading
|
||||
? Template.asString([
|
||||
"if (link.href.indexOf(window.location.origin + '/') !== 0) {",
|
||||
Template.indent(
|
||||
`link.crossOrigin = ${JSON.stringify(crossOriginLoading)};`
|
||||
),
|
||||
"}"
|
||||
])
|
||||
: ""
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -123,6 +123,9 @@ exportPlugins(exports, {
|
|||
UmdMainTemplatePlugin: () => require("./UmdMainTemplatePlugin"),
|
||||
WatchIgnorePlugin: () => require("./WatchIgnorePlugin")
|
||||
});
|
||||
exportPlugins((exports.dependencies = {}), {
|
||||
DependencyReference: () => require("./dependencies/DependencyReference")
|
||||
});
|
||||
exportPlugins((exports.optimize = {}), {
|
||||
AggressiveMergingPlugin: () => require("./optimize/AggressiveMergingPlugin"),
|
||||
AggressiveSplittingPlugin: () =>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "webpack",
|
||||
"version": "4.12.2",
|
||||
"version": "4.14.0",
|
||||
"author": "Tobias Koppers @sokra",
|
||||
"description": "Packs CommonJs/AMD modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.",
|
||||
"license": "MIT",
|
||||
|
@ -15,7 +15,7 @@
|
|||
"ajv": "^6.1.0",
|
||||
"ajv-keywords": "^3.1.0",
|
||||
"chrome-trace-event": "^1.0.0",
|
||||
"enhanced-resolve": "^4.0.0",
|
||||
"enhanced-resolve": "^4.1.0",
|
||||
"eslint-scope": "^3.7.1",
|
||||
"json-parse-better-errors": "^1.0.2",
|
||||
"loader-runner": "^2.3.0",
|
||||
|
@ -105,6 +105,7 @@
|
|||
"scripts": {
|
||||
"setup": "node ./setup/setup.js",
|
||||
"test": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest",
|
||||
"test:update-snapshots": "yarn jest -u",
|
||||
"test:integration": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.test.js\"",
|
||||
"test:basic": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/{TestCasesNormal,StatsTestCases,ConfigTestCases}.test.js\"",
|
||||
"test:unit": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.unittest.js\"",
|
||||
|
|
|
@ -1554,6 +1554,10 @@
|
|||
"description": "Use readable module identifiers for better debugging",
|
||||
"type": "boolean"
|
||||
},
|
||||
"hashedModuleIds": {
|
||||
"description": "Use hashed module id instead module identifiers for better long term caching",
|
||||
"type": "boolean"
|
||||
},
|
||||
"namedChunks": {
|
||||
"description": "Use readable chunk identifiers for better debugging",
|
||||
"type": "boolean"
|
||||
|
|
|
@ -178,7 +178,14 @@ describe("ConfigTestCases", () => {
|
|||
expect: expect,
|
||||
setTimeout: setTimeout,
|
||||
clearTimeout: clearTimeout,
|
||||
document: new FakeDocument()
|
||||
document: new FakeDocument(),
|
||||
location: {
|
||||
href: "https://test.cases/path/index.html",
|
||||
origin: "https://test.cases",
|
||||
toString() {
|
||||
return "https://test.cases/path/index.html";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function _require(currentDirectory, module) {
|
||||
|
|
|
@ -29,6 +29,7 @@ const DEFAULT_OPTIMIZATIONS = {
|
|||
noEmitOnErrors: false,
|
||||
concatenateModules: false,
|
||||
namedModules: false,
|
||||
hashedModuleIds: false,
|
||||
minimizer: [uglifyJsForTesting]
|
||||
};
|
||||
|
||||
|
|
|
@ -693,7 +693,7 @@ exports[`StatsTestCases should print correct stats for concat-and-sideeffects 1`
|
|||
`;
|
||||
|
||||
exports[`StatsTestCases should print correct stats for define-plugin 1`] = `
|
||||
"Hash: cfe08d4450db77f81610f4228fcb997ec81e2aa6
|
||||
"Hash: cfe08d4450db77f81610f4228fcb997ec81e2aa6bb43e7d151657ea2b793
|
||||
Child
|
||||
Hash: cfe08d4450db77f81610
|
||||
Time: Xms
|
||||
|
@ -709,6 +709,14 @@ Child
|
|||
Asset Size Chunks Chunk Names
|
||||
main.js 3.6 KiB 0 [emitted] main
|
||||
Entrypoint main = main.js
|
||||
[0] ./index.js 24 bytes {0} [built]
|
||||
Child
|
||||
Hash: bb43e7d151657ea2b793
|
||||
Time: Xms
|
||||
Built at: Thu Jan 01 1970 00:00:00 GMT
|
||||
Asset Size Chunks Chunk Names
|
||||
main.js 3.6 KiB 0 [emitted] main
|
||||
Entrypoint main = main.js
|
||||
[0] ./index.js 24 bytes {0} [built]"
|
||||
`;
|
||||
|
||||
|
@ -1830,7 +1838,7 @@ exports[`StatsTestCases should print correct stats for preload 1`] = `
|
|||
normal.js 130 bytes 1 [emitted] normal
|
||||
preloaded2.js 127 bytes 2 [emitted] preloaded2
|
||||
preloaded3.js 130 bytes 3 [emitted] preloaded3
|
||||
main.js 9.87 KiB 4 [emitted] main
|
||||
main.js 9.86 KiB 4 [emitted] main
|
||||
inner.js 136 bytes 5 [emitted] inner
|
||||
inner2.js 201 bytes 6 [emitted] inner2
|
||||
Entrypoint main = main.js (preload: preloaded2.js preloaded.js preloaded3.js)
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
it("should load script without crossorigin attribute (default)", function() {
|
||||
const promise = import("./empty?a" /* webpackChunkName: "crossorigin-default" */);
|
||||
|
||||
var script = document.head._children.pop();
|
||||
__non_webpack_require__("./crossorigin-default.web.js");
|
||||
expect(script.src).toBe("https://test.cases/path/crossorigin-default.web.js");
|
||||
expect(script.crossOrigin).toBe(undefined);
|
||||
|
||||
return promise;
|
||||
});
|
||||
|
||||
it("should load script without crossorigin attribute (relative)", function() {
|
||||
var originalValue = __webpack_public_path__;
|
||||
__webpack_public_path__ = "../";
|
||||
const promise = import("./empty?b" /* webpackChunkName: "crossorigin-relative" */);
|
||||
__webpack_public_path__ = originalValue;
|
||||
|
||||
var script = document.head._children.pop();
|
||||
__non_webpack_require__("./crossorigin-relative.web.js");
|
||||
expect(script.src).toBe("https://test.cases/crossorigin-relative.web.js");
|
||||
expect(script.crossOrigin).toBe(undefined);
|
||||
|
||||
return promise;
|
||||
});
|
||||
|
||||
it("should load script without crossorigin attribute (server relative)", function() {
|
||||
var originalValue = __webpack_public_path__;
|
||||
__webpack_public_path__ = "/server/";
|
||||
const promise = import("./empty?c" /* webpackChunkName: "crossorigin-server-relative" */);
|
||||
__webpack_public_path__ = originalValue;
|
||||
|
||||
var script = document.head._children.pop();
|
||||
__non_webpack_require__("./crossorigin-server-relative.web.js");
|
||||
expect(script.src).toBe("https://test.cases/server/crossorigin-server-relative.web.js");
|
||||
expect(script.crossOrigin).toBe(undefined);
|
||||
|
||||
return promise;
|
||||
});
|
||||
|
||||
it("should load script without crossorigin attribute (same origin)", function() {
|
||||
var originalValue = __webpack_public_path__;
|
||||
__webpack_public_path__ = "https://test.cases/";
|
||||
const promise = import("./empty?d" /* webpackChunkName: "crossorigin-same-origin" */);
|
||||
__webpack_public_path__ = originalValue;
|
||||
|
||||
var script = document.head._children.pop();
|
||||
__non_webpack_require__("./crossorigin-same-origin.web.js");
|
||||
expect(script.src).toBe("https://test.cases/crossorigin-same-origin.web.js");
|
||||
expect(script.crossOrigin).toBe(undefined);
|
||||
|
||||
return promise;
|
||||
});
|
||||
|
||||
it("should load script with crossorigin attribute anonymous (different origin)", function() {
|
||||
var originalValue = __webpack_public_path__;
|
||||
__webpack_public_path__ = "https://example.com/";
|
||||
const promise = import("./empty?e" /* webpackChunkName: "crossorigin-different-origin" */);
|
||||
__webpack_public_path__ = originalValue;
|
||||
|
||||
|
||||
var script = document.head._children.pop();
|
||||
__non_webpack_require__("./crossorigin-different-origin.web.js");
|
||||
expect(script.src).toBe("https://example.com/crossorigin-different-origin.web.js");
|
||||
expect(script.crossOrigin).toBe("anonymous");
|
||||
|
||||
return promise;
|
||||
});
|
|
@ -0,0 +1,13 @@
|
|||
module.exports = {
|
||||
target: "web",
|
||||
output: {
|
||||
chunkFilename: "[name].web.js",
|
||||
crossOriginLoading: "anonymous"
|
||||
},
|
||||
performance: {
|
||||
hints: false
|
||||
},
|
||||
optimization: {
|
||||
minimize: false
|
||||
}
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
import { test, unused } from "./module";
|
||||
|
||||
it("should run the test", () => {
|
||||
expect(test()).toEqual({
|
||||
used: "used",
|
||||
unused: undefined
|
||||
});
|
||||
expect(unused).toEqual(undefined);
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
import { used, unused } from "./reference";
|
||||
|
||||
export function test() {
|
||||
return {
|
||||
used,
|
||||
unused
|
||||
};
|
||||
}
|
||||
|
||||
export { unused }
|
|
@ -0,0 +1,3 @@
|
|||
export var used = "used";
|
||||
|
||||
export var unused = "unused";
|
|
@ -0,0 +1,34 @@
|
|||
const DependencyReference = require("../../../../").dependencies
|
||||
.DependencyReference;
|
||||
module.exports = {
|
||||
optimization: {
|
||||
usedExports: true,
|
||||
concatenateModules: true
|
||||
},
|
||||
plugins: [
|
||||
function() {
|
||||
this.hooks.compilation.tap("Test", compilation => {
|
||||
compilation.hooks.dependencyReference.tap(
|
||||
"Test",
|
||||
(ref, dep, module) => {
|
||||
if (
|
||||
module.identifier().endsWith("module.js") &&
|
||||
ref.module &&
|
||||
ref.module.identifier().endsWith("reference.js") &&
|
||||
Array.isArray(ref.importedNames) &&
|
||||
ref.importedNames.includes("unused")
|
||||
) {
|
||||
return new DependencyReference(
|
||||
ref.module,
|
||||
ref.importedNames.filter(item => item !== "unused"),
|
||||
ref.weak,
|
||||
ref.order
|
||||
);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
]
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
import { test, unused } from "./module";
|
||||
|
||||
it("should run the test", () => {
|
||||
expect(test()).toEqual({
|
||||
used: "used",
|
||||
unused: undefined
|
||||
});
|
||||
expect(unused).toEqual(undefined);
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
import { used, unused } from "./reference";
|
||||
|
||||
export function test() {
|
||||
return {
|
||||
used,
|
||||
unused
|
||||
};
|
||||
}
|
||||
|
||||
export { unused }
|
|
@ -0,0 +1,3 @@
|
|||
export var used = "used";
|
||||
|
||||
export var unused = "unused";
|
|
@ -0,0 +1,34 @@
|
|||
const DependencyReference = require("../../../../").dependencies
|
||||
.DependencyReference;
|
||||
module.exports = {
|
||||
optimization: {
|
||||
usedExports: true,
|
||||
concatenateModules: false
|
||||
},
|
||||
plugins: [
|
||||
function() {
|
||||
this.hooks.compilation.tap("Test", compilation => {
|
||||
compilation.hooks.dependencyReference.tap(
|
||||
"Test",
|
||||
(ref, dep, module) => {
|
||||
if (
|
||||
module.identifier().endsWith("module.js") &&
|
||||
ref.module &&
|
||||
ref.module.identifier().endsWith("reference.js") &&
|
||||
Array.isArray(ref.importedNames) &&
|
||||
ref.importedNames.includes("unused")
|
||||
) {
|
||||
return new DependencyReference(
|
||||
ref.module,
|
||||
ref.importedNames.filter(item => item !== "unused"),
|
||||
ref.weak,
|
||||
ref.order
|
||||
);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
]
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
module.exports = module.id;
|
|
@ -0,0 +1 @@
|
|||
module.exports = module.id;
|
|
@ -0,0 +1 @@
|
|||
module.exports = module.id;
|
|
@ -0,0 +1 @@
|
|||
module.exports = module.id;
|
|
@ -0,0 +1 @@
|
|||
module.exports = module.id;
|
|
@ -0,0 +1,7 @@
|
|||
it("should have named modules ids", function() {
|
||||
for (var i = 1; i <= 5; i++) {
|
||||
var moduleId = require("./files/file" + i + ".js");
|
||||
|
||||
expect(moduleId).toMatch(/^[/=a-zA-Z0-9]{4,5}$/);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
optimization: {
|
||||
hashedModuleIds: true
|
||||
}
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
module.exports = module.id;
|
|
@ -0,0 +1 @@
|
|||
module.exports = module.id;
|
|
@ -0,0 +1 @@
|
|||
module.exports = module.id;
|
|
@ -0,0 +1 @@
|
|||
module.exports = module.id;
|
|
@ -0,0 +1 @@
|
|||
module.exports = module.id;
|
|
@ -0,0 +1,10 @@
|
|||
var path = require("path");
|
||||
|
||||
it("should have named modules ids", function() {
|
||||
for (var i = 1; i <= 5; i++) {
|
||||
var expectedModuleId = "file" + i + ".js";
|
||||
var moduleId = require("./files/file" + i + ".js");
|
||||
|
||||
expect(path.basename(moduleId)).toBe(expectedModuleId);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
optimization: {
|
||||
namedModules: true
|
||||
}
|
||||
};
|
|
@ -2,7 +2,7 @@ it("should be able to load the split chunk on demand", () => {
|
|||
const promise = import(/* webpackChunkName: "shared" */ "./shared");
|
||||
|
||||
const script = document.head._children[0];
|
||||
expect(script.src).toBe("dep~b~shared.js");
|
||||
expect(script.src).toBe("https://test.cases/path/dep~b~shared.js");
|
||||
|
||||
__non_webpack_require__("./dep~b~shared.js");
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
it("should allow reference the same wasm multiple times", function() {
|
||||
return import("./module").then(function(module) {
|
||||
const result = module.run();
|
||||
expect(result).toEqual(84);
|
||||
});
|
||||
});
|
||||
|
||||
it("should allow reference the same wasm multiple times (other chunk)", function() {
|
||||
return import("./module?2").then(function(module) {
|
||||
const result = module.run();
|
||||
expect(result).toEqual(84);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
import { getNumber } from "./wasm.wat?1";
|
||||
import { getNumber as getNumber2 } from "./wasm.wat?2";
|
||||
|
||||
export function run() {
|
||||
return getNumber() + getNumber2();
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
var supportsWebAssembly = require("../../../helpers/supportsWebAssembly");
|
||||
|
||||
module.exports = function(config) {
|
||||
return supportsWebAssembly();
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
(module
|
||||
(type $t0 (func (param i32 i32) (result i32)))
|
||||
(type $t1 (func (result i32)))
|
||||
(func $add (export "add") (type $t0) (param $p0 i32) (param $p1 i32) (result i32)
|
||||
(i32.add
|
||||
(get_local $p0)
|
||||
(get_local $p1)))
|
||||
(func $getNumber (export "getNumber") (type $t1) (result i32)
|
||||
(i32.const 42)))
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
const { CachedSource } = require("webpack-sources");
|
||||
|
||||
/** @typedef {import("../../../lib/Compilation")} Compilation */
|
||||
|
||||
module.exports = {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.wat$/,
|
||||
loader: "wast-loader",
|
||||
type: "webassembly/experimental"
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
function() {
|
||||
this.hooks.compilation.tap(
|
||||
"Test",
|
||||
/**
|
||||
* @param {Compilation} compilation Compilation
|
||||
* @returns {void}
|
||||
*/
|
||||
compilation => {
|
||||
compilation.moduleTemplates.webassembly.hooks.package.tap(
|
||||
"Test",
|
||||
source => {
|
||||
// this is important to make each returned value a new instance
|
||||
return new CachedSource(source);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
]
|
||||
};
|
|
@ -10,11 +10,11 @@ beforeEach(() => {
|
|||
afterEach(() => {
|
||||
__webpack_nonce__ = oldNonce;
|
||||
__webpack_public_path__ = oldPublicPath;
|
||||
})
|
||||
});
|
||||
|
||||
it("should prefetch and preload child chunks on chunk load", () => {
|
||||
__webpack_nonce__ = "nonce";
|
||||
__webpack_public_path__ = "/public/path/";
|
||||
__webpack_public_path__ = "https://example.com/public/path/";
|
||||
|
||||
let link, script;
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ class FakeElement {
|
|||
this._type = type;
|
||||
this._children = [];
|
||||
this._attributes = Object.create(null);
|
||||
this._src = undefined;
|
||||
this._href = undefined;
|
||||
}
|
||||
|
||||
appendChild(node) {
|
||||
|
@ -33,4 +35,40 @@ class FakeElement {
|
|||
getAttribute(name) {
|
||||
return this._attributes[name];
|
||||
}
|
||||
|
||||
_toRealUrl(value) {
|
||||
if (/^\//.test(value)) {
|
||||
return `https://test.cases${value}`;
|
||||
} else if (/^\.\.\//.test(value)) {
|
||||
return `https://test.cases${value.substr(2)}`;
|
||||
} else if (/^\.\//.test(value)) {
|
||||
return `https://test.cases/path${value.substr(1)}`;
|
||||
} else if (/^\w+:\/\//.test(value)) {
|
||||
return value;
|
||||
} else if (/^\/\//.test(value)) {
|
||||
return `https:${value}`;
|
||||
} else {
|
||||
return `https://test.cases/path/${value}`;
|
||||
}
|
||||
}
|
||||
|
||||
set src(value) {
|
||||
if (this._type === "script") {
|
||||
this._src = this._toRealUrl(value);
|
||||
}
|
||||
}
|
||||
|
||||
get src() {
|
||||
return this._src;
|
||||
}
|
||||
|
||||
set href(value) {
|
||||
if (this._type === "link") {
|
||||
this._href = this._toRealUrl(value);
|
||||
}
|
||||
}
|
||||
|
||||
get href() {
|
||||
return this._href;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
123
|
|
@ -0,0 +1 @@
|
|||
321
|
|
@ -1,4 +1,11 @@
|
|||
var webpack = require("../../../");
|
||||
var fs = require("fs");
|
||||
var join = require("path").join;
|
||||
|
||||
function read(path) {
|
||||
return JSON.stringify(fs.readFileSync(join(__dirname, path), "utf8"));
|
||||
}
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
mode: "production",
|
||||
|
@ -18,5 +25,22 @@ module.exports = [
|
|||
VALUE: "321"
|
||||
})
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
mode: "production",
|
||||
entry: "./index",
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
VALUE: webpack.DefinePlugin.runtimeValue(() => read("123.txt"), [
|
||||
"./123.txt"
|
||||
])
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
VALUE: webpack.DefinePlugin.runtimeValue(() => read("321.txt"), [
|
||||
"./321.txt"
|
||||
])
|
||||
})
|
||||
]
|
||||
}
|
||||
];
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
it("should be able to use dynamic defines in watch mode", function() {
|
||||
const module = require("./module");
|
||||
expect(module).toEqual({
|
||||
default: WATCH_STEP,
|
||||
type: "string",
|
||||
[Symbol.toStringTag]: "Module"
|
||||
});
|
||||
});
|
||||
|
||||
it("should not update a define when dependencies list is missing", function() {
|
||||
const module2 = require("./module2");
|
||||
expect(module2).toEqual({
|
||||
default: "0",
|
||||
type: "string",
|
||||
[Symbol.toStringTag]: "Module"
|
||||
});
|
||||
});
|
|
@ -0,0 +1,2 @@
|
|||
export default TEST_VALUE;
|
||||
export const type = typeof TEST_VALUE;
|
|
@ -0,0 +1,2 @@
|
|||
export default TEST_VALUE2;
|
||||
export const type = typeof TEST_VALUE2;
|
|
@ -0,0 +1 @@
|
|||
0
|
|
@ -0,0 +1 @@
|
|||
1
|
|
@ -0,0 +1,22 @@
|
|||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const webpack = require("../../../../");
|
||||
const valueFile = path.resolve(
|
||||
__dirname,
|
||||
"../../../js/watch-src/plugins/define-plugin/value.txt"
|
||||
);
|
||||
module.exports = {
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
TEST_VALUE: webpack.DefinePlugin.runtimeValue(
|
||||
() => {
|
||||
return JSON.stringify(fs.readFileSync(valueFile, "utf-8").trim());
|
||||
},
|
||||
[valueFile]
|
||||
),
|
||||
TEST_VALUE2: webpack.DefinePlugin.runtimeValue(() => {
|
||||
return JSON.stringify(fs.readFileSync(valueFile, "utf-8").trim());
|
||||
}, [])
|
||||
})
|
||||
]
|
||||
};
|
|
@ -1766,9 +1766,9 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
|
|||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
enhanced-resolve@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz#e34a6eaa790f62fccd71d93959f56b2b432db10a"
|
||||
enhanced-resolve@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f"
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
memory-fs "^0.4.0"
|
||||
|
|
Loading…
Reference in New Issue