webpack
Version:
Packs ECMAScript/CommonJs/AMD modules for the browser. Allows you to split your codebase into multiple bundles, which can be loaded on demand. Supports loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.
134 lines (125 loc) • 4.15 kB
JavaScript
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
;
const RuntimeGlobals = require("../runtime/RuntimeGlobals");
const lazyModule = require("../util/lazyModule");
/** @import Compiler from "../Compiler" */
// only a chunk graph carrying a prefetch/preload relation emits these
const getChunkPrefetchFunctionRuntimeModule = lazyModule(() =>
require("./ChunkPrefetchFunctionRuntimeModule")
);
const getChunkPrefetchStartupRuntimeModule = lazyModule(() =>
require("./ChunkPrefetchStartupRuntimeModule")
);
const getChunkPrefetchTriggerRuntimeModule = lazyModule(() =>
require("./ChunkPrefetchTriggerRuntimeModule")
);
const getChunkPreloadTriggerRuntimeModule = lazyModule(() =>
require("./ChunkPreloadTriggerRuntimeModule")
);
const PLUGIN_NAME = "ChunkPrefetchPreloadPlugin";
/**
* Adds runtime support for chunk prefetch and preload relationships discovered
* in the chunk graph.
*/
class ChunkPrefetchPreloadPlugin {
/**
* Registers compilation hooks that emit the runtime modules responsible for
* scheduling chunk prefetch and preload requests.
* @param {Compiler} compiler the compiler
* @returns {void}
*/
apply(compiler) {
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
compilation.hooks.additionalChunkRuntimeRequirements.tap(
PLUGIN_NAME,
(chunk, set, { chunkGraph }) => {
if (chunkGraph.getNumberOfEntryModules(chunk) === 0) return;
const startupChildChunks = chunk.getChildrenOfTypeInOrder(
chunkGraph,
"prefetchOrder"
);
if (startupChildChunks) {
set.add(RuntimeGlobals.prefetchChunk);
set.add(RuntimeGlobals.onChunksLoaded);
// This is the one startup callback that is queued behind a priority.
set.add(RuntimeGlobals.hasChunkPriority);
set.add(RuntimeGlobals.exports);
compilation.addLazyRuntimeModule(
chunk,
getChunkPrefetchStartupRuntimeModule,
(Ctor) => new Ctor(startupChildChunks)
);
}
}
);
compilation.hooks.additionalTreeRuntimeRequirements.tap(
PLUGIN_NAME,
(chunk, set, { chunkGraph }) => {
const chunkMap = chunk.getChildIdsByOrdersMap(chunkGraph);
if (chunkMap.prefetch) {
set.add(RuntimeGlobals.prefetchChunk);
compilation.addLazyRuntimeModule(
chunk,
getChunkPrefetchTriggerRuntimeModule,
(Ctor) => new Ctor(chunkMap.prefetch)
);
}
if (chunkMap.preload) {
set.add(RuntimeGlobals.preloadChunk);
compilation.addLazyRuntimeModule(
chunk,
getChunkPreloadTriggerRuntimeModule,
(Ctor) => new Ctor(chunkMap.preload)
);
}
if (chunkMap.cssPreload) {
// A CSS-only preload reaches the CSS handler itself, so it asks for
// the handlers alone: nothing here calls the function fanning out
// across them.
set.add(RuntimeGlobals.preloadChunkHandlers);
compilation.addLazyRuntimeModule(
chunk,
getChunkPreloadTriggerRuntimeModule,
(Ctor) => new Ctor(chunkMap.cssPreload, "cssPreload")
);
}
}
);
// The handlers object carries the runtime module, so a chunk asking only for
// it ships no fan-out function. That is read here rather than in `create`,
// which runs once the requirement pass is over.
for (const [type, fn, handlers] of /** @type {const} */ ([
[
"prefetch",
RuntimeGlobals.prefetchChunk,
RuntimeGlobals.prefetchChunkHandlers
],
[
"preload",
RuntimeGlobals.preloadChunk,
RuntimeGlobals.preloadChunkHandlers
]
])) {
compilation.hooks.runtimeRequirementInTree
.for(fn)
.tap(PLUGIN_NAME, (chunk, set) => {
set.add(handlers);
});
compilation.hooks.runtimeRequirementInTree
.for(handlers)
.tap(PLUGIN_NAME, (chunk, set) => {
const runtimeFunction = set.has(fn) ? fn : null;
compilation.addLazyRuntimeModule(
chunk,
getChunkPrefetchFunctionRuntimeModule,
(Ctor) => new Ctor(type, runtimeFunction, handlers)
);
});
}
});
}
}
module.exports = ChunkPrefetchPreloadPlugin;