fusion-cli/build/plugins/client-chunk-metadata-state-hydrator-plugin.js (103 lines of code) (raw):
/** Copyright (c) 2018 Uber Technologies, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
/*eslint-env node */
/*::
import type {ClientChunkMetadataState, ClientChunkMetadata} from "../types.js";
*/
const assert = require('assert');
class ClientChunkMetadataStateHydrator {
/*::
state: ClientChunkMetadataState;
*/
constructor(state /*: ClientChunkMetadataState*/) {
this.state = state;
}
apply(compiler /*: Object*/) {
const name = this.constructor.name;
compiler.hooks.invalid.tap(name, () => {
this.state.reset();
});
compiler.hooks.thisCompilation.tap(name, compilation => {
compilation.hooks.afterOptimizeChunkAssets.tap(name, chunks => {
const fileManifest = chunkIndexFromWebpackChunks(chunks);
const urlMap = chunkMapFromWebpackChunks(chunks);
const {criticalPaths, criticalIds} = criticalChunkInfo(
compilation,
chunks
);
this.state.resolve({
fileManifest,
urlMap,
criticalIds,
criticalPaths,
...getChunkInfo(compilation, chunks),
});
});
});
}
}
module.exports = ClientChunkMetadataStateHydrator;
function chunkIndexFromWebpackChunks(chunks) {
const chunkIdsByFile = new Map();
for (const c of chunks) {
const chunkId = c.id;
const files = [];
// Iterate through the groups this chunk belongs to, adding the files of the other chunks in that group as well
for (const g of c.groupsIterable) {
for (const cc of g.chunks) {
for (const m of cc.modulesIterable) {
if (m.resource) {
files.push(m.resource);
} else if (m.modules) {
files.push(...m.modules.map(module => module.resource));
}
}
}
}
for (const path of files) {
if (!chunkIdsByFile.has(path)) {
chunkIdsByFile.set(path, new Set());
}
const chunkIds = chunkIdsByFile.get(path);
if (chunkIds) {
chunkIds.add(chunkId);
}
}
}
return chunkIdsByFile;
}
function chunkMapFromWebpackChunks(chunks) {
const chunkMap = new Map();
chunks.forEach(chunk => {
const [filename] = chunk.files;
const inner = new Map();
inner.set('es5', filename);
chunkMap.set(chunk.id, inner);
});
return chunkMap;
}
function getChunkInfo(compilation, chunks) {
assert(
compilation.entrypoints.size === 1,
`fusion-cli expects there to be a single entrypoint, but there was ${compilation.entrypoints.size}. This is a bug in fusion-cli.`
);
const allChunks = new Map();
const runtimeChunkIds = new Set();
const initialChunkIds = new Set();
for (const chunk of chunks) {
allChunks.set(chunk.id, chunk.files[0]);
if (chunk.hasRuntime()) {
runtimeChunkIds.add(chunk.id);
} else if (chunk.canBeInitial()) {
initialChunkIds.add(chunk.id);
}
}
assert(
runtimeChunkIds.size === 1,
`fusion-cli expects there to be a single runtime chunk, but there was ${runtimeChunkIds.size}. This is a bug in fusion-cli.`
);
return {
chunks: allChunks,
runtimeChunkIds,
initialChunkIds,
};
}
function criticalChunkInfo(compilation, chunks) {
const mainEntrypoint = compilation.entrypoints.get('main');
const chunkIds = mainEntrypoint.chunks.map(c => c.id);
const chunkPaths = mainEntrypoint.chunks.map(c => c.files[0]);
return {
criticalIds: chunkIds,
criticalPaths: chunkPaths,
};
}