Skip to content

Commit

Permalink
Runtime requirement support in NormalModule, Generators and Dependenc…
Browse files Browse the repository at this point in the history
…yTemplate
  • Loading branch information
sokra committed Nov 29, 2018
1 parent 507c2a8 commit c1e89c0
Show file tree
Hide file tree
Showing 21 changed files with 1,076 additions and 802 deletions.
96 changes: 78 additions & 18 deletions lib/Compilation.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,9 @@ class Compilation {
() => new SyncBailHook(["chunk", "runtimeRequirements"])
),

/** @type {SyncHook<RuntimeModule, Chunk>} */
runtimeModule: new SyncHook(["module", "chunk"]),

/** @type {SyncHook<Iterable<Module>, any>} */
reviveModules: new SyncHook(["modules", "records"]),
/** @type {SyncHook<Iterable<Module>>} */
Expand Down Expand Up @@ -326,6 +329,16 @@ class Compilation {
/** @type {SyncHook<Iterable<Chunk>, any>} */
recordChunks: new SyncHook(["chunks", "records"]),

/** @type {SyncHook} */
beforeModuleHash: new SyncHook([]),
/** @type {SyncHook} */
afterModuleHash: new SyncHook([]),

/** @type {SyncHook} */
beforeRuntimeRequirements: new SyncHook([]),
/** @type {SyncHook} */
afterRuntimeRequirements: new SyncHook([]),

/** @type {SyncHook} */
beforeHash: new SyncHook([]),
/** @type {SyncHook<Chunk>} */
Expand Down Expand Up @@ -1165,8 +1178,6 @@ class Compilation {

const shouldRecord = this.hooks.shouldRecord.call() !== false;

this.processRuntimeRequirements(entryChunkGroups);

this.hooks.reviveModules.call(this.modules, this.records);
this.hooks.beforeModuleIds.call(this.modules);
this.hooks.moduleIds.call(this.modules);
Expand All @@ -1186,6 +1197,14 @@ class Compilation {
this.hooks.recordChunks.call(this.chunks, this.records);
}

this.hooks.beforeModuleHash.call();
this.createModuleHashes();
this.hooks.afterModuleHash.call();

this.hooks.beforeRuntimeRequirements.call();
this.processRuntimeRequirements(entryChunkGroups);
this.hooks.afterRuntimeRequirements.call();

this.hooks.beforeHash.call();
this.createHash();
this.hooks.afterHash.call();
Expand Down Expand Up @@ -1284,15 +1303,27 @@ class Compilation {
* @returns {void}
*/
processRuntimeRequirements(entrypoints) {
const { chunkGraph } = this;
const {
chunkGraph,
moduleGraph,
runtimeTemplate,
dependencyTemplates
} = this;

/** @type {Map<Module, Iterable<string>>} */
const moduleRequirements = new Map();

for (const module of this.modules) {
const runtimeRequirements = module.getRuntimeRequirements(chunkGraph);
if (runtimeRequirements) {
moduleRequirements.set(module, runtimeRequirements);
if (chunkGraph.getNumberOfModuleChunks(module) > 0) {
const runtimeRequirements = module.getRuntimeRequirements({
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph
});
if (runtimeRequirements) {
moduleRequirements.set(module, runtimeRequirements);
}
}
}

Expand All @@ -1301,7 +1332,7 @@ class Compilation {

for (const chunk of this.chunks) {
const set = new Set();
for (const module of chunk.modulesIterable) {
for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
const runtimeRequirements = moduleRequirements.get(module);
if (runtimeRequirements !== undefined) {
for (const r of runtimeRequirements) set.add(r);
Expand Down Expand Up @@ -1349,11 +1380,34 @@ class Compilation {
* @returns {void}
*/
addRuntimeModule(chunk, module) {
// Deprecated ModuleGraph association
ModuleGraph.setModuleGraphForModule(module, this.moduleGraph);

// add it to the list
this.modules.add(module);

// connect to the chunk graph
this.chunkGraph.connectChunkAndModule(chunk, module);
this.chunkGraph.connectChunkAndRuntimeModule(chunk, module);

// Setup internals
this.moduleGraph.setUsedExports(module, new SortableSet());
ModuleGraph.setModuleGraphForModule(module, this.moduleGraph);

// Call hook
this.hooks.runtimeModule.call(module, chunk);

// Determine hash of the module
const { chunkGraph } = this;
const { hashFunction, hashDigest, hashDigestLength } = this.outputOptions;

const moduleHash = createHash(hashFunction);
module.updateHash(moduleHash, chunkGraph);
const moduleHashDigest = moduleHash.digest(hashDigest);
chunkGraph.setModuleHashes(
module,
moduleHashDigest,
moduleHashDigest.substr(0, hashDigestLength)
);
}

/**
Expand Down Expand Up @@ -2097,6 +2151,21 @@ class Compilation {
this.missingDependencies.sort();
}

createModuleHashes() {
const chunkGraph = this.chunkGraph;
const { hashFunction, hashDigest, hashDigestLength } = this.outputOptions;
for (const module of this.modules) {
const moduleHash = createHash(hashFunction);
module.updateHash(moduleHash, chunkGraph);
const moduleHashDigest = moduleHash.digest(hashDigest);
chunkGraph.setModuleHashes(
module,
moduleHashDigest,
moduleHashDigest.substr(0, hashDigestLength)
);
}
}

createHash() {
const chunkGraph = this.chunkGraph;
const outputOptions = this.outputOptions;
Expand All @@ -2121,16 +2190,7 @@ class Compilation {
for (const error of this.errors) {
hash.update(`${error.message}`);
}
for (const module of this.modules) {
const moduleHash = createHash(hashFunction);
module.updateHash(moduleHash, chunkGraph);
const moduleHashDigest = moduleHash.digest(hashDigest);
chunkGraph.setModuleHashes(
module,
moduleHashDigest,
moduleHashDigest.substr(0, hashDigestLength)
);
}

// clone needed as sort below is inplace mutation
const chunks = Array.from(this.chunks);
/**
Expand Down
4 changes: 2 additions & 2 deletions lib/ContextModule.js
Original file line number Diff line number Diff line change
Expand Up @@ -846,10 +846,10 @@ webpackEmptyAsyncContext.id = ${JSON.stringify(id)};`;

/**
* Get a list of runtime requirements
* @param {ChunkGraph} chunkGraph chunk graph
* @param {SourceContext} context context for code generation
* @returns {Iterable<string> | null} required runtime modules
*/
getRuntimeRequirements(chunkGraph) {
getRuntimeRequirements({ chunkGraph }) {
const set = [];
const allDeps = /** @type {ContextElementDependency[]} */ (this.dependencies.concat(
this.blocks.map(b => b.dependencies[0])
Expand Down
9 changes: 0 additions & 9 deletions lib/Dependency.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,6 @@ class Dependency {
return null;
}

/**
* Get a list of runtime requirements
* @param {ChunkGraph} chunkGraph chunk graph
* @returns {Set<string> | null} required runtime modules
*/
getRuntimeRequirements(chunkGraph) {
return null;
}

/**
* Update the hash
* @param {Hash} hash hash to be updated
Expand Down
1 change: 1 addition & 0 deletions lib/DependencyTemplate.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* @property {DependencyTemplates} dependencyTemplates the dependency templates
* @property {ModuleGraph} moduleGraph the module graph
* @property {ChunkGraph} chunkGraph the chunk graph
* @property {Set<string>} runtimeRequirements the requirements for runtime
* @property {Module} module current module
* @property {InitFragment[]} initFragments mutable array of init fragments for the current module
*/
Expand Down
1 change: 1 addition & 0 deletions lib/Generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* @property {RuntimeTemplate} runtimeTemplate the runtime template
* @property {ModuleGraph} moduleGraph the module graph
* @property {ChunkGraph} chunkGraph the chunk graph
* @property {Set<string>} runtimeRequirements the requirements for runtime
* @property {string} type which kind of code should be generated
*/

Expand Down
1 change: 1 addition & 0 deletions lib/JavascriptGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ class JavascriptGenerator extends Generator {
moduleGraph: generateContext.moduleGraph,
chunkGraph: generateContext.chunkGraph,
module,
runtimeRequirements: generateContext.runtimeRequirements,
initFragments
};

Expand Down
4 changes: 2 additions & 2 deletions lib/Module.js
Original file line number Diff line number Diff line change
Expand Up @@ -570,10 +570,10 @@ class Module extends DependenciesBlock {

/**
* Get a list of runtime requirements
* @param {ChunkGraph} chunkGraph chunk graph
* @param {SourceContext} context context for code generation
* @returns {Iterable<string> | null} required runtime modules
*/
getRuntimeRequirements(chunkGraph) {
getRuntimeRequirements(context) {
return null;
}

Expand Down
72 changes: 41 additions & 31 deletions lib/NormalModule.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ makeSerializable(

/**
* @typedef {Object} CachedSourceEntry
* @property {TODO} source the generated source
* @property {string} hash the hash value
*/

Expand Down Expand Up @@ -167,7 +166,7 @@ class NormalModule extends Module {
this._buildHash = "";
/** @type {number=} */
this.buildTimestamp = undefined;
/** @private @type {Map<string, CachedSourceEntry>} */
/** @private @type {Map<string, GenerateSourceResult & CachedSourceEntry>} */
this._cachedSources = new Map();

// Cache
Expand Down Expand Up @@ -590,7 +589,7 @@ class NormalModule extends Module {
* @param {DependencyTemplates} dependencyTemplates dependency templates
* @returns {string} hash
*/
getHashDigest(chunkGraph, dependencyTemplates) {
_getHashDigest(chunkGraph, dependencyTemplates) {
const hash = chunkGraph.getModuleHash(this);
const dtHash = dependencyTemplates.getHash();
return `${hash}-${dtHash}`;
Expand All @@ -600,37 +599,64 @@ class NormalModule extends Module {
* @param {SourceContext} sourceContext source context
* @returns {Source} generated source
*/
source({
source(sourceContext) {
return this._generateSource(sourceContext).source;
}

/**
* @typedef {Object} GenerateSourceContext
*/

/**
* @typedef {Object} GenerateSourceResult
* @property {Source} source the generated source
* @property {Set<string>} runtimeRequirements the requirements for the runtime
*/

/**
* @param {SourceContext} sourceContext source context
* @returns {GenerateSourceResult} generated source result
*/
_generateSource({
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph,
type = "javascript"
}) {
const hashDigest = this.getHashDigest(chunkGraph, dependencyTemplates);
const hashDigest = this._getHashDigest(chunkGraph, dependencyTemplates);
const cacheEntry = this._cachedSources.get(type);
if (cacheEntry !== undefined && cacheEntry.hash === hashDigest) {
// We can reuse the cached source
return cacheEntry.source;
// We can reuse the cached data
return cacheEntry;
}

/** @type {Set<string>} */
const runtimeRequirements = new Set();

const source = this.generator.generate(this, {
dependencyTemplates,
runtimeTemplate,
moduleGraph,
chunkGraph,
runtimeRequirements,
type
});

const cachedSource = new CachedSource(source);
this._cachedSources.set(type, {
source: cachedSource,
hash: hashDigest
});

// TODO remove cast when webpack-sources types are fixed
// CachedSource is not a Source?
const fixedSource = /** @type {TODO} */ (cachedSource);
return fixedSource;

/** @type {GenerateSourceResult & CachedSourceEntry} */
const resultEntry = {
source: fixedSource,
runtimeRequirements,
hash: hashDigest
};
this._cachedSources.set(type, resultEntry);
return resultEntry;
}

/**
Expand Down Expand Up @@ -701,27 +727,11 @@ class NormalModule extends Module {

/**
* Get a list of runtime requirements
* @param {ChunkGraph} chunkGraph chunk graph
* @param {SourceContext} context context for code generation
* @returns {Iterable<string> | null} required runtime modules
*/
getRuntimeRequirements(chunkGraph) {
const set = new Set();
const queue = new Set();
queue.add(this);
for (const block of queue) {
for (const dep of block.dependencies) {
const runtimeReq = dep.getRuntimeRequirements(chunkGraph);
if (runtimeReq) {
for (const item of runtimeReq) {
set.add(item);
}
}
}
for (const inner of block.blocks) {
queue.add(inner);
}
}
return set;
getRuntimeRequirements(context) {
return this._generateSource(context).runtimeRequirements;
}

/**
Expand Down
2 changes: 2 additions & 0 deletions lib/ProgressPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ class ProgressPlugin {
afterOptimizeChunkIds: "after chunk id optimization",
recordModules: "record modules",
recordChunks: "record chunks",
beforeModuleHash: "module hashing",
beforeRuntimeRequirements: "runtime requirements",
beforeHash: "hashing",
contentHash: "content hashing",
afterHash: "after hashing",
Expand Down
Loading

0 comments on commit c1e89c0

Please sign in to comment.