mirror of https://github.com/webpack/webpack.git
commit
f0ae54d478
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ const isInstalled = packageName => {
|
|||
* @typedef {Object} CliOption
|
||||
* @property {string} name display name
|
||||
* @property {string} package npm package name
|
||||
* @property {string} binName name of the executable file
|
||||
* @property {string} alias shortcut for choice
|
||||
* @property {boolean} installed currently installed?
|
||||
* @property {string} url homepage
|
||||
|
|
@ -58,6 +59,7 @@ const CLIs = [
|
|||
{
|
||||
name: "webpack-cli",
|
||||
package: "webpack-cli",
|
||||
binName: "webpack-cli",
|
||||
alias: "cli",
|
||||
installed: isInstalled("webpack-cli"),
|
||||
url: "https://github.com/webpack/webpack-cli",
|
||||
|
|
@ -66,6 +68,7 @@ const CLIs = [
|
|||
{
|
||||
name: "webpack-command",
|
||||
package: "webpack-command",
|
||||
binName: "webpack-command",
|
||||
alias: "command",
|
||||
installed: isInstalled("webpack-command"),
|
||||
url: "https://github.com/webpack-contrib/webpack-command",
|
||||
|
|
@ -154,7 +157,10 @@ if (installedClis.length === 0) {
|
|||
});
|
||||
});
|
||||
} else if (installedClis.length === 1) {
|
||||
require(installedClis[0].package); // eslint-disable-line
|
||||
const path = require("path");
|
||||
const pkgPath = require.resolve(`${installedClis[0].package}/package.json`);
|
||||
const pkg = require(pkgPath); // eslint-disable-line
|
||||
require(path.resolve(path.dirname(pkgPath), pkg.bin[installedClis[0].binName])); // eslint-disable-line
|
||||
} else {
|
||||
console.warn(
|
||||
`You have installed ${installedClis
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,12 @@ class ChunkGroup {
|
|||
this.chunks = [];
|
||||
/** @type {OriginRecord[]} */
|
||||
this.origins = [];
|
||||
/** Indicies in top-down order */
|
||||
/** @private @type {Map<Module, number>} */
|
||||
this._moduleIndicies = new Map();
|
||||
/** Indicies in bottom-up order */
|
||||
/** @private @type {Map<Module, number>} */
|
||||
this._moduleIndicies2 = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -440,6 +446,44 @@ class ChunkGroup {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the top-down index of a module in this ChunkGroup
|
||||
* @param {Module} module module for which the index should be set
|
||||
* @param {number} index the index of the module
|
||||
* @returns {void}
|
||||
*/
|
||||
setModuleIndex(module, index) {
|
||||
this._moduleIndicies.set(module, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the top-down index of a module in this ChunkGroup
|
||||
* @param {Module} module the module
|
||||
* @returns {number} index
|
||||
*/
|
||||
getModuleIndex(module) {
|
||||
return this._moduleIndicies.get(module);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bottom-up index of a module in this ChunkGroup
|
||||
* @param {Module} module module for which the index should be set
|
||||
* @param {number} index the index of the module
|
||||
* @returns {void}
|
||||
*/
|
||||
setModuleIndex2(module, index) {
|
||||
this._moduleIndicies2.set(module, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bottom-up index of a module in this ChunkGroup
|
||||
* @param {Module} module the module
|
||||
* @returns {number} index
|
||||
*/
|
||||
getModuleIndex2(module) {
|
||||
return this._moduleIndicies2.get(module);
|
||||
}
|
||||
|
||||
checkConstraints() {
|
||||
const chunk = this;
|
||||
for (const child of chunk._children) {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ const Queue = require("./util/Queue");
|
|||
const SortableSet = require("./util/SortableSet");
|
||||
const GraphHelpers = require("./GraphHelpers");
|
||||
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
|
||||
/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
|
||||
|
||||
const byId = (a, b) => {
|
||||
if (a.id < b.id) return -1;
|
||||
if (a.id > b.id) return 1;
|
||||
|
|
@ -234,8 +238,6 @@ class Compilation {
|
|||
this._modules = new Map();
|
||||
this.cache = null;
|
||||
this.records = null;
|
||||
this.nextFreeModuleIndex = undefined;
|
||||
this.nextFreeModuleIndex2 = undefined;
|
||||
this.additionalChunkAssets = [];
|
||||
this.assets = {};
|
||||
this.errors = [];
|
||||
|
|
@ -845,8 +847,6 @@ class Compilation {
|
|||
}
|
||||
this.hooks.afterOptimizeDependencies.call(this.modules);
|
||||
|
||||
this.nextFreeModuleIndex = 0;
|
||||
this.nextFreeModuleIndex2 = 0;
|
||||
for (const preparedEntrypoint of this._preparedEntrypoints) {
|
||||
const module = preparedEntrypoint.module;
|
||||
const name = preparedEntrypoint.name;
|
||||
|
|
@ -864,7 +864,6 @@ class Compilation {
|
|||
chunk.entryModule = module;
|
||||
chunk.name = name;
|
||||
|
||||
this.assignIndex(module);
|
||||
this.assignDepth(module);
|
||||
}
|
||||
this.processDependenciesBlocksForChunkGroups(this.chunkGroups.slice());
|
||||
|
|
@ -1013,6 +1012,13 @@ class Compilation {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TODO} groupOptions options for the chunk group
|
||||
* @param {Module} module the module the references the chunk group
|
||||
* @param {TODO} loc the location from with the chunk group is reference (inside of module)
|
||||
* @param {string} request the request from which the the chunk group is referenced
|
||||
* @returns {ChunkGroup} the new or existing chunk group
|
||||
*/
|
||||
addChunkInGroup(groupOptions, module, loc, request) {
|
||||
if (typeof groupOptions === "string") {
|
||||
groupOptions = { name: groupOptions };
|
||||
|
|
@ -1056,70 +1062,6 @@ class Compilation {
|
|||
return chunk;
|
||||
}
|
||||
|
||||
assignIndex(module) {
|
||||
const assignIndexToModule = module => {
|
||||
// enter module
|
||||
if (typeof module.index !== "number") {
|
||||
module.index = this.nextFreeModuleIndex++;
|
||||
|
||||
// leave module
|
||||
queue.push(() => (module.index2 = this.nextFreeModuleIndex2++));
|
||||
|
||||
// enter it as block
|
||||
assignIndexToDependencyBlock(module);
|
||||
}
|
||||
};
|
||||
|
||||
const assignIndexToDependency = dependency => {
|
||||
if (dependency.module) {
|
||||
queue.push(() => assignIndexToModule(dependency.module));
|
||||
}
|
||||
};
|
||||
|
||||
const assignIndexToDependencyBlock = block => {
|
||||
let allDependencies = [];
|
||||
|
||||
const iteratorDependency = d => allDependencies.push(d);
|
||||
|
||||
const iteratorBlock = b =>
|
||||
queue.push(() => assignIndexToDependencyBlock(b));
|
||||
|
||||
if (block.variables) {
|
||||
iterationBlockVariable(block.variables, iteratorDependency);
|
||||
}
|
||||
|
||||
if (block.dependencies) {
|
||||
iterationOfArrayCallback(block.dependencies, iteratorDependency);
|
||||
}
|
||||
if (block.blocks) {
|
||||
const blocks = block.blocks;
|
||||
let indexBlock = blocks.length;
|
||||
while (indexBlock--) {
|
||||
iteratorBlock(blocks[indexBlock]);
|
||||
}
|
||||
}
|
||||
|
||||
let indexAll = allDependencies.length;
|
||||
while (indexAll--) {
|
||||
iteratorAllDependencies(allDependencies[indexAll]);
|
||||
}
|
||||
};
|
||||
|
||||
const queue = [
|
||||
() => {
|
||||
assignIndexToModule(module);
|
||||
}
|
||||
];
|
||||
|
||||
const iteratorAllDependencies = d => {
|
||||
queue.push(() => assignIndexToDependency(d));
|
||||
};
|
||||
|
||||
while (queue.length) {
|
||||
queue.pop()();
|
||||
}
|
||||
}
|
||||
|
||||
assignDepth(module) {
|
||||
const queue = new Set([module]);
|
||||
let depth;
|
||||
|
|
@ -1162,7 +1104,12 @@ class Compilation {
|
|||
}
|
||||
}
|
||||
|
||||
// This method creates the Chunk graph from the Module graph
|
||||
/**
|
||||
* This method creates the Chunk graph from the Module graph
|
||||
* @private
|
||||
* @param {TODO[]} inputChunkGroups chunk groups which are processed
|
||||
* @returns {void}
|
||||
*/
|
||||
processDependenciesBlocksForChunkGroups(inputChunkGroups) {
|
||||
// Process is splitting into two parts:
|
||||
// Part one traverse the module graph and builds a very basic chunks graph
|
||||
|
|
@ -1172,10 +1119,12 @@ class Compilation {
|
|||
// eachother and Blocks with Chunks. It stops traversing when all modules
|
||||
// for a chunk are already available. So it doesn't connect unneeded chunks.
|
||||
|
||||
const chunkDependencies = new Map(); // Map<Chunk, Array<{Module, Chunk}>>
|
||||
/** @type {Map<Chunk, {block: DependenciesBlock, chunkGroup: ChunkGroup}[]>} */
|
||||
const chunkDependencies = new Map();
|
||||
const allCreatedChunkGroups = new Set();
|
||||
|
||||
// PREPARE
|
||||
/** @type {Map<DependenciesBlock, { modules: Module[], blocks: AsyncDependenciesBlock[]}>} */
|
||||
const blockInfoMap = new Map();
|
||||
|
||||
const iteratorDependency = d => {
|
||||
|
|
@ -1202,7 +1151,15 @@ class Compilation {
|
|||
blockQueue.push(b);
|
||||
};
|
||||
|
||||
let block, blockQueue, blockInfoModules, blockInfoBlocks;
|
||||
/** @type {DependenciesBlock} */
|
||||
let block;
|
||||
/** @type {TODO} */
|
||||
let blockQueue;
|
||||
/** @type {Set<TODO>} */
|
||||
let blockInfoModules;
|
||||
/** @type {TODO[]} */
|
||||
let blockInfoBlocks;
|
||||
|
||||
for (const module of this.modules) {
|
||||
blockQueue = [module];
|
||||
while (blockQueue.length > 0) {
|
||||
|
|
@ -1223,7 +1180,7 @@ class Compilation {
|
|||
}
|
||||
|
||||
const blockInfo = {
|
||||
modules: blockInfoModules,
|
||||
modules: Array.from(blockInfoModules),
|
||||
blocks: blockInfoBlocks
|
||||
};
|
||||
blockInfoMap.set(block, blockInfo);
|
||||
|
|
@ -1232,15 +1189,49 @@ class Compilation {
|
|||
|
||||
// PART ONE
|
||||
|
||||
/** @type {Map<ChunkGroup, { index: number, index2: number }>} */
|
||||
const chunkGroupCounters = new Map();
|
||||
for (const chunkGroup of inputChunkGroups) {
|
||||
chunkGroupCounters.set(chunkGroup, { index: 0, index2: 0 });
|
||||
}
|
||||
|
||||
let nextFreeModuleIndex = 0;
|
||||
let nextFreeModuleIndex2 = 0;
|
||||
|
||||
/** @type {Map<DependenciesBlock, ChunkGroup>} */
|
||||
const blockChunkGroups = new Map();
|
||||
|
||||
// Start with the provided modules/chunks
|
||||
const queue = inputChunkGroups.map(chunkGroup => ({
|
||||
const ADD_AND_ENTER_MODULE = 0;
|
||||
const ENTER_MODULE = 1;
|
||||
const PROCESS_BLOCK = 2;
|
||||
const LEAVE_MODULE = 3;
|
||||
|
||||
/**
|
||||
* @typedef {Object} QueueItem
|
||||
* @property {number} action
|
||||
* @property {DependenciesBlock} block
|
||||
* @property {Module} module
|
||||
* @property {Chunk} chunk
|
||||
* @property {ChunkGroup} chunkGroup
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {ChunkGroup} chunkGroup chunk group
|
||||
* @returns {QueueItem} queue item
|
||||
*/
|
||||
const chunkGroupToQueueItem = chunkGroup => ({
|
||||
action: ENTER_MODULE,
|
||||
block: chunkGroup.chunks[0].entryModule,
|
||||
module: chunkGroup.chunks[0].entryModule,
|
||||
chunk: chunkGroup.chunks[0],
|
||||
chunkGroup
|
||||
}));
|
||||
});
|
||||
|
||||
// Start with the provided modules/chunks
|
||||
/** @type {QueueItem[]} */
|
||||
let queue = inputChunkGroups.map(chunkGroupToQueueItem).reverse();
|
||||
/** @type {QueueItem[]} */
|
||||
let queueDelayed = [];
|
||||
|
||||
let module, chunk, chunkGroup;
|
||||
|
||||
|
|
@ -1263,6 +1254,7 @@ class Compilation {
|
|||
b.loc,
|
||||
b.request
|
||||
);
|
||||
chunkGroupCounters.set(c, { index: 0, index2: 0 });
|
||||
blockChunkGroups.set(b, c);
|
||||
allCreatedChunkGroups.add(c);
|
||||
}
|
||||
|
|
@ -1280,7 +1272,8 @@ class Compilation {
|
|||
});
|
||||
|
||||
// 3. We enqueue the DependenciesBlock for traversal
|
||||
queue.push({
|
||||
queueDelayed.push({
|
||||
action: PROCESS_BLOCK,
|
||||
block: b,
|
||||
module: module,
|
||||
chunk: c.chunks[0],
|
||||
|
|
@ -1291,33 +1284,95 @@ class Compilation {
|
|||
// Iterative traversal of the Module graph
|
||||
// Recursive would be simpler to write but could result in Stack Overflows
|
||||
while (queue.length) {
|
||||
const queueItem = queue.pop();
|
||||
module = queueItem.module;
|
||||
block = queueItem.block;
|
||||
chunk = queueItem.chunk;
|
||||
chunkGroup = queueItem.chunkGroup;
|
||||
while (queue.length) {
|
||||
const queueItem = queue.pop();
|
||||
module = queueItem.module;
|
||||
block = queueItem.block;
|
||||
chunk = queueItem.chunk;
|
||||
chunkGroup = queueItem.chunkGroup;
|
||||
|
||||
// get prepared block info
|
||||
const blockInfo = blockInfoMap.get(block);
|
||||
switch (queueItem.action) {
|
||||
case ADD_AND_ENTER_MODULE: {
|
||||
// We connect Module and Chunk when not already done
|
||||
if (chunk.addModule(module)) {
|
||||
module.addChunk(chunk);
|
||||
} else {
|
||||
// already connected, skip it
|
||||
break;
|
||||
}
|
||||
}
|
||||
// fallthrough
|
||||
case ENTER_MODULE: {
|
||||
if (chunkGroup !== undefined) {
|
||||
const index = chunkGroup.getModuleIndex(module);
|
||||
if (index === undefined) {
|
||||
chunkGroup.setModuleIndex(
|
||||
module,
|
||||
chunkGroupCounters.get(chunkGroup).index++
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse all referenced modules
|
||||
for (const refModule of blockInfo.modules) {
|
||||
// We connect Module and Chunk when not already done
|
||||
if (chunk.addModule(refModule)) {
|
||||
refModule.addChunk(chunk);
|
||||
if (module.index === null) {
|
||||
module.index = nextFreeModuleIndex++;
|
||||
}
|
||||
|
||||
// And enqueue the Module for traversal
|
||||
queue.push({
|
||||
block: refModule,
|
||||
module: refModule,
|
||||
chunk,
|
||||
chunkGroup
|
||||
});
|
||||
queue.push({
|
||||
action: LEAVE_MODULE,
|
||||
block,
|
||||
module,
|
||||
chunk,
|
||||
chunkGroup
|
||||
});
|
||||
}
|
||||
// fallthrough
|
||||
case PROCESS_BLOCK: {
|
||||
// get prepared block info
|
||||
const blockInfo = blockInfoMap.get(block);
|
||||
|
||||
// Traverse all referenced modules
|
||||
for (let i = blockInfo.modules.length - 1; i >= 0; i--) {
|
||||
const refModule = blockInfo.modules[i];
|
||||
if (chunk.containsModule(refModule)) {
|
||||
// skip early if already connected
|
||||
continue;
|
||||
}
|
||||
// enqueue the add and enter to enter in the correct order
|
||||
// this is relevant with circular dependencies
|
||||
queue.push({
|
||||
action: ADD_AND_ENTER_MODULE,
|
||||
block: refModule,
|
||||
module: refModule,
|
||||
chunk,
|
||||
chunkGroup
|
||||
});
|
||||
}
|
||||
|
||||
// Traverse all Blocks
|
||||
iterationOfArrayCallback(blockInfo.blocks, iteratorBlock);
|
||||
break;
|
||||
}
|
||||
case LEAVE_MODULE: {
|
||||
if (chunkGroup !== undefined) {
|
||||
const index = chunkGroup.getModuleIndex2(module);
|
||||
if (index === undefined) {
|
||||
chunkGroup.setModuleIndex2(
|
||||
module,
|
||||
chunkGroupCounters.get(chunkGroup).index2++
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (module.index2 === null) {
|
||||
module.index2 = nextFreeModuleIndex2++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse all Blocks
|
||||
iterationOfArrayCallback(blockInfo.blocks, iteratorBlock);
|
||||
const tempQueue = queue;
|
||||
queue = queueDelayed.reverse();
|
||||
queueDelayed = tempQueue;
|
||||
}
|
||||
|
||||
// PART TWO
|
||||
|
|
|
|||
|
|
@ -14,26 +14,44 @@ const {
|
|||
} = require("./JavascriptParserHelpers");
|
||||
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();
|
||||
}
|
||||
|
|
@ -41,7 +59,7 @@ const toCode = code => {
|
|||
return "(" + code.toString() + ")";
|
||||
}
|
||||
if (typeof code === "object") {
|
||||
return stringifyObj(code);
|
||||
return stringifyObj(code, parser);
|
||||
}
|
||||
return code + "";
|
||||
};
|
||||
|
|
@ -51,6 +69,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(
|
||||
|
|
@ -69,6 +91,7 @@ class DefinePlugin {
|
|||
if (
|
||||
code &&
|
||||
typeof code === "object" &&
|
||||
!(code instanceof RuntimeValue) &&
|
||||
!(code instanceof RegExp)
|
||||
) {
|
||||
walkDefinitions(code, prefix + key + ".");
|
||||
|
|
@ -93,7 +116,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).tap("DefinePlugin", approve);
|
||||
parser.hooks.evaluateIdentifier
|
||||
|
|
@ -109,21 +131,23 @@ 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)
|
||||
? toConstantDependencyWithWebpackRequire(parser, code)
|
||||
: toConstantDependency(parser, code)
|
||||
);
|
||||
parser.hooks.expression.for(key).tap("DefinePlugin", expr => {
|
||||
const strCode = toCode(code, parser);
|
||||
if (/__webpack_require__/.test(strCode)) {
|
||||
return toConstantDependencyWithWebpackRequire(
|
||||
parser,
|
||||
strCode
|
||||
)(expr);
|
||||
} else {
|
||||
return 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
|
||||
|
|
@ -135,12 +159,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 toConstantDependency(
|
||||
|
|
@ -151,7 +181,6 @@ class DefinePlugin {
|
|||
};
|
||||
|
||||
const applyObjectDefine = (key, obj) => {
|
||||
const code = stringifyObj(obj);
|
||||
parser.hooks.canRename.for(key).tap("DefinePlugin", approve);
|
||||
parser.hooks.evaluateIdentifier
|
||||
.for(key)
|
||||
|
|
@ -161,14 +190,17 @@ class DefinePlugin {
|
|||
parser.hooks.evaluateTypeof
|
||||
.for(key)
|
||||
.tap("DefinePlugin", evaluateToString("object"));
|
||||
parser.hooks.expression
|
||||
.for(key)
|
||||
.tap(
|
||||
"DefinePlugin",
|
||||
/__webpack_require__/.test(code)
|
||||
? toConstantDependencyWithWebpackRequire(parser, code)
|
||||
: toConstantDependency(parser, code)
|
||||
);
|
||||
parser.hooks.expression.for(key).tap("DefinePlugin", expr => {
|
||||
const strCode = stringifyObj(obj, parser);
|
||||
|
||||
if (/__webpack_require__/.test(strCode)) {
|
||||
return toConstantDependencyWithWebpackRequire(parser, strCode)(
|
||||
expr
|
||||
);
|
||||
} else {
|
||||
return toConstantDependency(parser, strCode)(expr);
|
||||
}
|
||||
});
|
||||
parser.hooks.typeof
|
||||
.for(key)
|
||||
.tap(
|
||||
|
|
|
|||
|
|
@ -41,11 +41,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -265,6 +265,7 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
|
|||
"make",
|
||||
options => options.mode === "development"
|
||||
);
|
||||
this.set("optimization.hashedModuleIds", false);
|
||||
this.set(
|
||||
"optimization.namedChunks",
|
||||
"make",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
class Queue {
|
||||
/**
|
||||
* @param {IterableIterator<T>=} items The initial elements.
|
||||
* @param {Iterable<T>=} items The initial elements.
|
||||
*/
|
||||
constructor(items) {
|
||||
/** @private @type {Set<T>} */
|
||||
|
|
|
|||
|
|
@ -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)};`
|
||||
),
|
||||
"}"
|
||||
])
|
||||
: ""
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "webpack",
|
||||
"version": "4.12.2",
|
||||
"version": "4.13.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",
|
||||
|
|
@ -103,6 +103,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\"",
|
||||
|
|
|
|||
|
|
@ -1563,6 +1563,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]
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1 @@
|
|||
import "./shared";
|
||||
|
|
@ -0,0 +1 @@
|
|||
import "./shared";
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import "./a";
|
||||
import(/* webpackChunkName: "async" */ "./async");
|
||||
import "./b";
|
||||
import "./c";
|
||||
|
||||
it("should compile", () => {});
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import "./c";
|
||||
import(/* webpackChunkName: "async" */ "./async");
|
||||
import "./b";
|
||||
import "./a";
|
||||
|
||||
it("should compile", () => {});
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
findBundle: function(i, options) {
|
||||
return ["entry1.js", "entry2.js"];
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/** @typedef {import("../../../../lib/Compilation")} Compilation */
|
||||
/** @typedef {import("../../../../lib/Module")} Module */
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
entry1: "./entry1",
|
||||
entry2: "./entry2"
|
||||
},
|
||||
output: {
|
||||
filename: "[name].js"
|
||||
},
|
||||
plugins: [
|
||||
function() {
|
||||
/**
|
||||
* @param {Compilation} compilation compilation
|
||||
* @returns {void}
|
||||
*/
|
||||
const handler = compilation => {
|
||||
compilation.hooks.afterSeal.tap("testcase", () => {
|
||||
const data = {};
|
||||
for (const [name, group] of compilation.namedChunkGroups) {
|
||||
/** @type {Map<Module, number>} */
|
||||
const modules = new Map();
|
||||
const modules2 = new Map();
|
||||
for (const chunk of group.chunks) {
|
||||
for (const module of chunk.modulesIterable) {
|
||||
modules.set(module, group.getModuleIndex(module));
|
||||
modules2.set(module, group.getModuleIndex2(module));
|
||||
}
|
||||
}
|
||||
const sortedModules = Array.from(modules).sort((a, b) => {
|
||||
return a[1] - b[1];
|
||||
});
|
||||
const sortedModules2 = Array.from(modules2).sort((a, b) => {
|
||||
return a[1] - b[1];
|
||||
});
|
||||
const text = sortedModules
|
||||
.map(
|
||||
([m, index]) =>
|
||||
`${index}: ${m.readableIdentifier(
|
||||
compilation.requestShortener
|
||||
)}`
|
||||
)
|
||||
.join(", ");
|
||||
const text2 = sortedModules2
|
||||
.map(
|
||||
([m, index]) =>
|
||||
`${index}: ${m.readableIdentifier(
|
||||
compilation.requestShortener
|
||||
)}`
|
||||
)
|
||||
.join(", ");
|
||||
data[name + "Index"] = text;
|
||||
data[name + "Index2"] = text2;
|
||||
}
|
||||
expect(data).toEqual({
|
||||
entry1Index:
|
||||
"0: ./entry1.js, 1: ./a.js, 2: ./shared.js, 3: ./b.js, 4: ./c.js",
|
||||
entry1Index2:
|
||||
"0: ./shared.js, 1: ./a.js, 2: ./b.js, 3: ./c.js, 4: ./entry1.js",
|
||||
entry2Index:
|
||||
"0: ./entry2.js, 1: ./c.js, 2: ./b.js, 3: ./shared.js, 4: ./a.js",
|
||||
entry2Index2:
|
||||
"0: ./c.js, 1: ./shared.js, 2: ./b.js, 3: ./a.js, 4: ./entry2.js",
|
||||
asyncIndex: "0: ./async.js",
|
||||
asyncIndex2: "0: ./async.js"
|
||||
});
|
||||
const indicies = compilation.modules
|
||||
.map(
|
||||
m =>
|
||||
`${m.index}: ${m.readableIdentifier(
|
||||
compilation.requestShortener
|
||||
)}`
|
||||
)
|
||||
.join(", ");
|
||||
const indicies2 = compilation.modules
|
||||
.map(
|
||||
m =>
|
||||
`${m.index2}: ${m.readableIdentifier(
|
||||
compilation.requestShortener
|
||||
)}`
|
||||
)
|
||||
.join(", ");
|
||||
expect(indicies).toEqual(
|
||||
"2: ./shared.js, 4: ./c.js, 3: ./b.js, 1: ./a.js, 6: ./async.js, 5: ./entry2.js, 0: ./entry1.js"
|
||||
);
|
||||
expect(indicies2).toEqual(
|
||||
"0: ./shared.js, 3: ./c.js, 2: ./b.js, 1: ./a.js, 6: ./async.js, 5: ./entry2.js, 4: ./entry1.js"
|
||||
);
|
||||
});
|
||||
};
|
||||
this.hooks.compilation.tap("testcase", handler);
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
@ -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 @@
|
|||
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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}, [])
|
||||
})
|
||||
]
|
||||
};
|
||||
|
|
@ -1750,9 +1750,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