Merge branch 'main' into fix-12408

This commit is contained in:
Tobias Koppers 2022-04-04 11:24:52 +02:00 committed by GitHub
commit 07242beec5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 231 additions and 48 deletions

View File

@ -1436,7 +1436,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
* @returns {void}
*/
_processModuleDependencies(module, callback) {
/** @type {Array<{factory: ModuleFactory, dependencies: Dependency[], originModule: Module|null}>} */
/** @type {Array<{factory: ModuleFactory, dependencies: Dependency[], context: string|undefined, originModule: Module|null}>} */
const sortedDependencies = [];
/** @type {DependenciesBlock} */
@ -1668,6 +1668,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
sortedDependencies.push({
factory: factoryCacheKey2,
dependencies: list,
context: dep.getContext(),
originModule: module
});
}

View File

@ -545,8 +545,21 @@ class Compiler {
*/
runAsChild(callback) {
const startTime = Date.now();
const finalCallback = (err, entries, compilation) => {
try {
callback(err, entries, compilation);
} catch (e) {
const err = new WebpackError(
`compiler.runAsChild callback error: ${e}`
);
err.details = e.stack;
this.parentCompilation.errors.push(err);
}
};
this.compile((err, compilation) => {
if (err) return callback(err);
if (err) return finalCallback(err);
this.parentCompilation.children.push(compilation);
for (const { name, source, info } of compilation.getAssets()) {
@ -561,7 +574,7 @@ class Compiler {
compilation.startTime = startTime;
compilation.endTime = Date.now();
return callback(null, entries, compilation);
return finalCallback(null, entries, compilation);
});
}

View File

@ -1104,9 +1104,13 @@ module.exports = webpackEmptyAsyncContext;`;
)
);
const set = new Set();
const allDeps = /** @type {ContextElementDependency[]} */ (
this.dependencies.concat(this.blocks.map(b => b.dependencies[0]))
);
const allDeps =
this.dependencies.length > 0
? /** @type {ContextElementDependency[]} */ (this.dependencies).slice()
: [];
for (const block of this.blocks)
for (const dep of block.dependencies)
allDeps.push(/** @type {ContextElementDependency} */ (dep));
set.add(RuntimeGlobals.module);
set.add(RuntimeGlobals.hasOwnProperty);
if (allDeps.length > 0) {

View File

@ -292,7 +292,6 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
} = options;
if (!regExp || !resource) return callback(null, []);
let severalContexts = false;
const addDirectoryChecked = (ctx, directory, visited, callback) => {
fs.realpath(directory, (err, realPath) => {
if (err) return callback(err);
@ -359,15 +358,13 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
alternatives = alternatives
.filter(obj => regExp.test(obj.request))
.map(obj => {
const request = severalContexts
? join(fs, obj.context, obj.request)
: obj.request;
const dep = new ContextElementDependency(
request + resourceQuery + resourceFragment,
`${obj.request}${resourceQuery}${resourceFragment}`,
obj.request,
typePrefix,
category,
referencedExports
referencedExports,
obj.context
);
dep.optional = true;
return dep;
@ -414,7 +411,6 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
if (typeof resource === "string") {
visitResource(resource, callback);
} else {
severalContexts = true;
asyncLib.map(resource, visitResource, (err, result) => {
if (err) return callback(err);

View File

@ -182,6 +182,13 @@ class Dependency {
this._loc = undefined;
}
/**
* @returns {string | undefined} a request context
*/
getContext() {
return undefined;
}
/**
* @returns {string | null} an identifier to merge equal requests
*/

View File

@ -6,6 +6,7 @@
"use strict";
const { create: createResolver } = require("enhanced-resolve");
const nodeModule = require("module");
const asyncLib = require("neo-async");
const AsyncQueue = require("./util/AsyncQueue");
const StackedCacheMap = require("./util/StackedCacheMap");
@ -22,6 +23,8 @@ const processAsyncTree = require("./util/processAsyncTree");
const supportsEsm = +process.versions.modules >= 83;
const builtinModules = new Set(nodeModule.builtinModules);
let FS_ACCURACY = 2000;
const EMPTY_SET = new Set();
@ -1673,6 +1676,11 @@ class FileSystemInfo {
// e.g. import.meta
continue;
}
// we should not track Node.js build dependencies
if (dependency.startsWith("node:")) continue;
if (builtinModules.has(dependency)) continue;
push({
type: RBDT_RESOLVE_ESM_FILE,
context,

View File

@ -639,10 +639,14 @@ class PackContentItems {
} catch (e) {
rollback(s);
if (e === NOT_SERIALIZABLE) continue;
logger.warn(
`Skipped not serializable cache item '${key}': ${e.message}`
);
logger.debug(e.stack);
const msg = "Skipped not serializable cache item";
if (e.message.includes("ModuleBuildError")) {
logger.log(`${msg} (in build error): ${e.message}`);
logger.debug(`${msg} '${key}' (in build error): ${e.stack}`);
} else {
logger.warn(`${msg}: ${e.message}`);
logger.debug(`${msg} '${key}': ${e.stack}`);
}
}
}
write(null);

View File

@ -14,11 +14,27 @@ const ModuleDependency = require("./ModuleDependency");
/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
class ContextElementDependency extends ModuleDependency {
constructor(request, userRequest, typePrefix, category, referencedExports) {
/**
* @param {string} request request
* @param {string|undefined} userRequest user request
* @param {string} typePrefix type prefix
* @param {string} category category
* @param {string[][]=} referencedExports referenced exports
* @param {string=} context context
*/
constructor(
request,
userRequest,
typePrefix,
category,
referencedExports,
context
) {
super(request);
this.referencedExports = referencedExports;
this._typePrefix = typePrefix;
this._category = category;
this._context = context || undefined;
if (userRequest) {
this.userRequest = userRequest;
@ -33,6 +49,20 @@ class ContextElementDependency extends ModuleDependency {
return "context element";
}
/**
* @returns {string | undefined} a request context
*/
getContext() {
return this._context;
}
/**
* @returns {string | null} an identifier to merge equal requests
*/
getResourceIdentifier() {
return `context${this._context || ""}|${super.getResourceIdentifier()}`;
}
get category() {
return this._category;
}
@ -56,6 +86,7 @@ class ContextElementDependency extends ModuleDependency {
const { write } = context;
write(this._typePrefix);
write(this._category);
write(this._context);
write(this.referencedExports);
super.serialize(context);
}
@ -64,6 +95,7 @@ class ContextElementDependency extends ModuleDependency {
const { read } = context;
this._typePrefix = read();
this._category = read();
this._context = read();
this.referencedExports = read();
super.deserialize(context);
}

View File

@ -28,7 +28,8 @@ module.exports = function () {
var currentStatus = "idle";
// while downloading
var blockingPromises;
var blockingPromises = 0;
var blockingPromisesWaiting = [];
// The update info
var currentUpdateApplyHandlers;
@ -218,17 +219,28 @@ module.exports = function () {
return Promise.all(results);
}
function unblock() {
if (--blockingPromises === 0) {
setStatus("ready").then(function () {
if (blockingPromises === 0) {
var list = blockingPromisesWaiting;
blockingPromisesWaiting = [];
for (var i = 0; i < list.length; i++) {
list[i]();
}
}
});
}
}
function trackBlockingPromise(promise) {
switch (currentStatus) {
case "ready":
setStatus("prepare");
blockingPromises.push(promise);
waitForBlockingPromises(function () {
return setStatus("ready");
});
return promise;
/* fallthrough */
case "prepare":
blockingPromises.push(promise);
blockingPromises++;
promise.then(unblock, unblock);
return promise;
default:
return promise;
@ -236,11 +248,11 @@ module.exports = function () {
}
function waitForBlockingPromises(fn) {
if (blockingPromises.length === 0) return fn();
var blocker = blockingPromises;
blockingPromises = [];
return Promise.all(blocker).then(function () {
return waitForBlockingPromises(fn);
if (blockingPromises === 0) return fn();
return new Promise(function (resolve) {
blockingPromisesWaiting.push(function () {
resolve(fn());
});
});
}
@ -261,7 +273,6 @@ module.exports = function () {
return setStatus("prepare").then(function () {
var updatedModules = [];
blockingPromises = [];
currentUpdateApplyHandlers = [];
return Promise.all(
@ -298,7 +309,11 @@ module.exports = function () {
function hotApply(options) {
if (currentStatus !== "ready") {
return Promise.resolve().then(function () {
throw new Error("apply() is only allowed in ready status");
throw new Error(
"apply() is only allowed in ready status (state: " +
currentStatus +
")"
);
});
}
return internalApply(options);

View File

@ -443,15 +443,16 @@ module.exports = function () {
) {
promises.push($loadUpdateChunk$(chunkId, updatedModulesList));
currentUpdateChunks[chunkId] = true;
} else {
currentUpdateChunks[chunkId] = false;
}
});
if ($ensureChunkHandlers$) {
$ensureChunkHandlers$.$key$Hmr = function (chunkId, promises) {
if (
currentUpdateChunks &&
!$hasOwnProperty$(currentUpdateChunks, chunkId) &&
$hasOwnProperty$($installedChunks$, chunkId) &&
$installedChunks$[chunkId] !== undefined
$hasOwnProperty$(currentUpdateChunks, chunkId) &&
!currentUpdateChunks[chunkId]
) {
promises.push($loadUpdateChunk$(chunkId));
currentUpdateChunks[chunkId] = true;

View File

@ -310,9 +310,11 @@ class UmdLibraryPlugin extends AbstractLibraryPlugin {
: " var a = factory();\n") +
" for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n" +
" }\n") +
`})(${
runtimeTemplate.outputOptions.globalObject
}, function(${externalsArguments(externals)}) {\nreturn `,
`})(${runtimeTemplate.outputOptions.globalObject}, ${
runtimeTemplate.supportsArrowFunction()
? `(${externalsArguments(externals)}) =>`
: `function(${externalsArguments(externals)})`
} {\nreturn `,
"webpack/universalModuleDefinition"
),
source,

View File

@ -288,7 +288,7 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule {
"var waitingUpdateResolves = {};",
"function loadUpdateChunk(chunkId, updatedModulesList) {",
Template.indent([
`if (updatedModulesList) currentUpdatedModulesList = updatedModulesList;`,
"currentUpdatedModulesList = updatedModulesList;",
`return new Promise(${runtimeTemplate.basicFunction(
"resolve, reject",
[

View File

@ -1,6 +1,6 @@
{
"name": "webpack",
"version": "5.70.0",
"version": "5.71.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",

View File

@ -133,7 +133,7 @@ describe("BuildDependencies", () => {
);
fs.writeFileSync(
path.resolve(inputDirectory, "esm-async-dependency.mjs"),
"export default 0;"
'import path from "node:path"; import vm from "vm"; export default 0;'
);
await exec("0", {
invalidBuildDependencies: true,

View File

@ -619,7 +619,12 @@ const describeCases = config => {
const fn = runInNewContext
? vm.runInNewContext(code, globalContext, p)
: vm.runInThisContext(code, p);
fn.call(m.exports, ...argValues);
fn.call(
testConfig.nonEsmThis
? testConfig.nonEsmThis(module)
: m.exports,
...argValues
);
document.currentScript = oldCurrentScript;
return m.exports;
}

View File

@ -148,9 +148,10 @@ describe("ContextModuleFactory", () => {
expect(res).not.toStrictEqual([]);
expect(Array.isArray(res)).toBe(true);
expect(res.map(r => r.request)).toEqual([
"/a/B/a?query#hash",
"/b/A/b?query#hash"
"./B/a?query#hash",
"./A/b?query#hash"
]);
expect(res.map(r => r.getContext())).toEqual(["/a", "/b"]);
expect(res.map(r => r.userRequest)).toEqual(["./B/a", "./A/b"]);
done();
}

View File

@ -0,0 +1 @@
export const log = 1;

View File

@ -0,0 +1,13 @@
async function dynamic_import(dir, name) {
if (dir === "a") {
return import(
/* webpackChunkName: "a" */
/* webpackMode: "lazy-once" */
`./dynamic_a/${name}.js`);
}
throw new Error();
}
it("should compile and run", async () => {
await dynamic_import("a", "module_a1");
});

View File

@ -0,0 +1,19 @@
const locales = import.meta.webpackContext('./locales', {
recursive: false,
regExp: /(en|hu)\.json$/i,
});
const vuetify = import.meta.webpackContext('vuetify/lib/locale', {
recursive: false,
regExp: /(en|hu)\.json$/i,
});
it('should resolve "./locales"', () => {
expect(locales("./en.json")).toEqual({});
expect(() => locales("./hu.json")).toThrow();
});
it('should resolve "vuetify"', () => {
expect(vuetify("./en.json")).toEqual({});
expect(vuetify("./hu.json")).toEqual({});
expect(() => vuetify("./ru.json")).toThrow();
});

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,4 @@
{
"name": "vuetify",
"version": "1.0.0"
}

View File

@ -0,0 +1,8 @@
const path = require("path");
/** @type {import("../../../../").Configuration} */
module.exports = {
resolve: {
modules: ["node_modules", path.resolve(__dirname, "./node_modules")]
}
};

View File

@ -0,0 +1,5 @@
it("should compile and run", () => {
expect(hello()).toBe("hello");
});
export function hello() { return "hello"; }

View File

@ -0,0 +1,9 @@
const CONTEXT = {};
module.exports = {
nonEsmThis(module) {
return CONTEXT;
},
findBundle() {
return ["./runtime.js", "./main.js"];
}
};

View File

@ -0,0 +1,19 @@
/** @type {import("../../../../").Configuration} */
module.exports = {
mode: "production",
entry: {
main: "./index.js"
},
output: {
filename: "[name].js",
library: "MyLibrary",
libraryTarget: "umd",
chunkLoading: "jsonp",
chunkFormat: "array-push",
globalObject: "this"
},
optimization: {
minimize: false,
runtimeChunk: "single"
}
};

View File

@ -5,22 +5,27 @@ module.hot.accept("./file");
const asyncNext = () => {
return new Promise((resolve, reject) => {
NEXT((err, stats) => {
if(err) return reject(err);
if (err) return reject(err);
resolve(stats);
});
});
}
};
it("should download the missing update chunk on import", () => {
expect(value).toBe(1);
return asyncNext().then(() => {
return module.hot.check().then(() => {
return import("./chunk").then(chunk => {
return Promise.all([
import("./chunk"),
import("./unaffected-chunk")
]).then(([chunk, unaffectedChunk]) => {
expect(value).toBe(1);
expect(chunk.default).toBe(10);
expect(unaffectedChunk.default).toBe(10);
return module.hot.apply().then(() => {
expect(value).toBe(2);
expect(chunk.default).toBe(20);
expect(unaffectedChunk.default).toBe(10);
});
});
});

View File

@ -0,0 +1,5 @@
import value from "./unaffected-inner";
module.hot.accept("./unaffected-inner");
export { value as default };

View File

@ -0,0 +1 @@
export default 10;

3
types.d.ts vendored
View File

@ -2462,7 +2462,7 @@ declare interface ContainerReferencePluginOptions {
shareScope?: string;
}
declare abstract class ContextElementDependency extends ModuleDependency {
referencedExports: any;
referencedExports?: string[][];
}
declare class ContextExclusionPlugin {
constructor(negativeMatcher: RegExp);
@ -2645,6 +2645,7 @@ declare class Dependency {
endLine?: any,
endColumn?: any
): void;
getContext(): undefined | string;
getResourceIdentifier(): null | string;
couldAffectReferencingModule(): boolean | typeof TRANSITIVE;