Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix outputModule with initial splitChunks #14829

Merged
merged 4 commits into from Nov 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/container/ContainerEntryModule.js
Expand Up @@ -10,6 +10,7 @@ const AsyncDependenciesBlock = require("../AsyncDependenciesBlock");
const Module = require("../Module");
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const StaticExportsDependency = require("../dependencies/StaticExportsDependency");
const makeSerializable = require("../util/makeSerializable");
const ContainerExposedDependency = require("./ContainerExposedDependency");

Expand Down Expand Up @@ -104,6 +105,7 @@ class ContainerEntryModule extends Module {
strict: true,
topLevelDeclarations: new Set(["moduleMap", "get", "init"])
};
this.buildMeta.exportsType = "namespace";

this.clearDependenciesAndBlocks();

Expand All @@ -127,6 +129,7 @@ class ContainerEntryModule extends Module {
}
this.addBlock(block);
}
this.addDependency(new StaticExportsDependency(["get", "init"], false));

callback();
}
Expand Down
123 changes: 74 additions & 49 deletions lib/esm/ModuleChunkFormatPlugin.js
Expand Up @@ -5,18 +5,16 @@

"use strict";

const { ConcatSource, RawSource } = require("webpack-sources");
const { ConcatSource } = require("webpack-sources");
const { RuntimeGlobals } = require("..");
const HotUpdateChunk = require("../HotUpdateChunk");
const Template = require("../Template");
const { getAllChunks } = require("../javascript/ChunkHelpers");
const {
getCompilationHooks,
getChunkFilenameTemplate
} = require("../javascript/JavascriptModulesPlugin");
const {
generateEntryStartup,
updateHashForEntryStartup
} = require("../javascript/StartupHelpers");
const { updateHashForEntryStartup } = require("../javascript/StartupHelpers");

/** @typedef {import("../Compiler")} Compiler */

Expand Down Expand Up @@ -84,63 +82,90 @@ class ModuleChunkFormatPlugin {
}
)
.split("/");
const runtimeOutputName = compilation
.getPath(
getChunkFilenameTemplate(
runtimeChunk,
compilation.outputOptions
),
{
chunk: runtimeChunk,
contentHashType: "javascript"
}
)
.split("/");

// remove filename, we only need the directory
const outputFilename = currentOutputName.pop();
currentOutputName.pop();

// remove common parts
while (
currentOutputName.length > 0 &&
runtimeOutputName.length > 0 &&
currentOutputName[0] === runtimeOutputName[0]
) {
currentOutputName.shift();
runtimeOutputName.shift();
}
const getRelativePath = chunk => {
const baseOutputName = currentOutputName.slice();
const chunkOutputName = compilation
.getPath(
getChunkFilenameTemplate(
chunk,
compilation.outputOptions
),
{
chunk: chunk,
contentHashType: "javascript"
}
)
.split("/");

// create final path
const runtimePath =
(currentOutputName.length > 0
? "../".repeat(currentOutputName.length)
: "./") + runtimeOutputName.join("/");
// remove common parts
while (
baseOutputName.length > 0 &&
chunkOutputName.length > 0 &&
baseOutputName[0] === chunkOutputName[0]
) {
baseOutputName.shift();
chunkOutputName.shift();
}
// create final path
return (
(baseOutputName.length > 0
? "../".repeat(baseOutputName.length)
: "./") + chunkOutputName.join("/")
);
};

const entrySource = new ConcatSource();
entrySource.add(source);
entrySource.add(";\n\n// load runtime\n");
entrySource.add(
`import __webpack_require__ from ${JSON.stringify(
runtimePath
)};\n`
);
entrySource.add(
`import * as __webpack_self_exports__ from ${JSON.stringify(
"./" + outputFilename
getRelativePath(runtimeChunk)
)};\n`
);
entrySource.add(
`${RuntimeGlobals.externalInstallChunk}(__webpack_self_exports__);\n`
);
const startupSource = new RawSource(
generateEntryStartup(
chunkGraph,
runtimeTemplate,
entries,
chunk,
false
)

const startupSource = new ConcatSource();
startupSource.add(
`var __webpack_exec__ = ${runtimeTemplate.returningFunction(
`__webpack_require__(${RuntimeGlobals.entryModuleId} = moduleId)`,
"moduleId"
)}\n`
);

const loadedChunks = new Set();
let index = 0;
for (let i = 0; i < entries.length; i++) {
const [module, entrypoint] = entries[i];
const final = i + 1 === entries.length;
const moduleId = chunkGraph.getModuleId(module);
const chunks = getAllChunks(
entrypoint,
runtimeChunk,
undefined
);
for (const chunk of chunks) {
if (loadedChunks.has(chunk)) continue;
loadedChunks.add(chunk);
startupSource.add(
`import * as __webpack_chunk_${index}__ from ${JSON.stringify(
getRelativePath(chunk)
)};\n`
);
startupSource.add(
`${RuntimeGlobals.externalInstallChunk}(__webpack_chunk_${index}__);\n`
);
index++;
}
startupSource.add(
`${
final ? "var __webpack_exports__ = " : ""
}__webpack_exec__(${JSON.stringify(moduleId)});\n`
);
}

entrySource.add(
hooks.renderStartup.call(
startupSource,
Expand Down
33 changes: 33 additions & 0 deletions lib/javascript/ChunkHelpers.js
@@ -0,0 +1,33 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/

"use strict";

const Entrypoint = require("../Entrypoint");

/** @typedef {import("../Chunk")} Chunk */

/**
* @param {Entrypoint} entrypoint a chunk group
* @param {Chunk} excludedChunk1 current chunk which is excluded
* @param {Chunk} excludedChunk2 runtime chunk which is excluded
* @returns {Set<Chunk>} chunks
*/
const getAllChunks = (entrypoint, excludedChunk1, excludedChunk2) => {
const queue = new Set([entrypoint]);
const chunks = new Set();
for (const entrypoint of queue) {
for (const chunk of entrypoint.chunks) {
if (chunk === excludedChunk1) continue;
if (chunk === excludedChunk2) continue;
chunks.add(chunk);
}
for (const parent of entrypoint.parentsIterable) {
if (parent instanceof Entrypoint) queue.add(parent);
}
}
return chunks;
};
exports.getAllChunks = getAllChunks;
26 changes: 1 addition & 25 deletions lib/javascript/StartupHelpers.js
Expand Up @@ -5,10 +5,10 @@

"use strict";

const Entrypoint = require("../Entrypoint");
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const { isSubset } = require("../util/SetHelpers");
const { getAllChunks } = require("./ChunkHelpers");
const { chunkHasJs } = require("./JavascriptModulesPlugin");

/** @typedef {import("../util/Hash")} Hash */
Expand All @@ -19,30 +19,6 @@ const { chunkHasJs } = require("./JavascriptModulesPlugin");
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
/** @typedef {(string|number)[]} EntryItem */

// TODO move to this file to ../javascript/ChunkHelpers.js

/**
* @param {Entrypoint} entrypoint a chunk group
* @param {Chunk} excludedChunk1 current chunk which is excluded
* @param {Chunk} excludedChunk2 runtime chunk which is excluded
* @returns {Set<Chunk>} chunks
*/
const getAllChunks = (entrypoint, excludedChunk1, excludedChunk2) => {
const queue = new Set([entrypoint]);
const chunks = new Set();
for (const entrypoint of queue) {
for (const chunk of entrypoint.chunks) {
if (chunk === excludedChunk1) continue;
if (chunk === excludedChunk2) continue;
chunks.add(chunk);
}
for (const parent of entrypoint.parentsIterable) {
if (parent instanceof Entrypoint) queue.add(parent);
}
}
return chunks;
};

const EXPORT_PREFIX = "var __webpack_exports__ = ";

/**
Expand Down