webpack/lib/JavascriptGenerator.js

167 lines
4.3 KiB
JavaScript
Raw Normal View History

/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
2018-07-30 23:08:51 +08:00
"use strict";
const { ConcatSource, RawSource, ReplaceSource } = require("webpack-sources");
2018-07-28 03:12:09 +08:00
/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("./DependenciesBlock")} DependenciesBlock */
/** @typedef {import("./Dependency")} Dependency */
/** @typedef {import("./DependencyTemplates")} DependencyTemplates */
2018-07-25 03:57:48 +08:00
/** @typedef {import("./InitFragment")} InitFragment */
2018-07-28 03:12:09 +08:00
/** @typedef {import("./Module")} Module */
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
2018-07-25 03:57:48 +08:00
// TODO: clean up this file
// replace with newer constructs
2018-07-25 03:57:48 +08:00
/**
* @param {InitFragment} fragment [TODO]
* @param {number} index [TODO]
* @returns {[InitFragment, number]} [TODO]
*/
const extractFragmentIndex = (fragment, index) => [fragment, index];
2018-07-25 03:57:48 +08:00
/**
* @param {[InitFragment, number]} a first pair
* @param {[InitFragment, number]} b second pair
* @returns {number} sort value
*/
const sortByFragmentIndex = ([a, i], [b, j]) => {
2018-07-25 03:57:48 +08:00
const x = a.priority - b.priority;
return x !== 0 ? x : i - j;
};
class JavascriptGenerator {
2018-07-28 03:12:09 +08:00
/**
* @param {Module} module the entry module
* @param {DependencyTemplates} dependencyTemplates the dependency templates
* @param {RuntimeTemplate} runtimeTemplate the runtime template
2018-07-28 03:12:09 +08:00
* @returns {Source} the generated source
*/
generate(module, dependencyTemplates, runtimeTemplate) {
const originalSource = module.originalSource();
2018-02-25 09:00:20 +08:00
if (!originalSource) {
return new RawSource("throw new Error('No source available');");
}
const source = new ReplaceSource(originalSource);
const dependencyFragments = [];
2018-02-25 09:00:20 +08:00
this.sourceBlock(
module,
module,
dependencyTemplates,
dependencyFragments,
2018-02-25 09:00:20 +08:00
source,
runtimeTemplate
);
if (dependencyFragments.length > 0) {
2018-07-25 01:56:35 +08:00
// Sort fragments by priority. If 2 fragments have the same priority,
// use their index.
const sortedFragments = dependencyFragments
.map(extractFragmentIndex)
.sort(sortByFragmentIndex);
2018-07-25 01:56:35 +08:00
// Deduplicate fragments. If a fragment has no key, it is always included.
const keyedFragments = new Map();
for (const [fragment] of sortedFragments) {
2018-07-25 01:56:35 +08:00
keyedFragments.set(fragment.key || Symbol(), fragment);
}
const concatSource = new ConcatSource();
for (const fragment of keyedFragments.values()) {
concatSource.add(fragment.content);
}
concatSource.add(source);
return concatSource;
} else {
return source;
}
}
2018-07-28 03:12:09 +08:00
/**
* @param {Module} module the module to generate
* @param {DependenciesBlock} block [TODO]
* @param {DependencyTemplates} dependencyTemplates the dependency templates
* @param {InitFragment[]} dependencyFragments [TODO]
* @param {ReplaceSource} source the current replace source which can be modified
* @param {RuntimeTemplate} runtimeTemplate the runtime template
* @returns {void}
*/
2018-02-25 09:00:20 +08:00
sourceBlock(
module,
block,
dependencyTemplates,
dependencyFragments,
2018-02-25 09:00:20 +08:00
source,
runtimeTemplate
) {
for (const dependency of block.dependencies) {
this.sourceDependency(
dependency,
dependencyTemplates,
dependencyFragments,
2018-02-25 09:00:20 +08:00
source,
runtimeTemplate
);
}
2018-02-25 09:00:20 +08:00
for (const childBlock of block.blocks) {
this.sourceBlock(
module,
childBlock,
dependencyTemplates,
dependencyFragments,
source,
runtimeTemplate
);
}
}
2018-07-28 03:12:09 +08:00
/**
* @param {TODO} dependency the dependency to generate
* @param {DependencyTemplates} dependencyTemplates the dependency templates
* @param {InitFragment[]} dependencyFragments [TODO]
* @param {ReplaceSource} source the current replace source which can be modified
* @param {RuntimeTemplate} runtimeTemplate the runtime template
* @returns {void}
*/
sourceDependency(
dependency,
dependencyTemplates,
dependencyFragments,
source,
runtimeTemplate
) {
const template = dependencyTemplates.get(dependency.constructor);
if (!template) {
2018-02-25 09:00:20 +08:00
throw new Error(
"No template for dependency: " + dependency.constructor.name
);
}
template.apply(dependency, source, runtimeTemplate, dependencyTemplates);
2018-07-25 03:57:48 +08:00
const fragments = template.getInitFragments(
dependency,
source, // TODO remove this argument
runtimeTemplate,
dependencyTemplates
);
if (fragments) {
for (const fragment of fragments) {
dependencyFragments.push(fragment);
}
}
}
}
module.exports = JavascriptGenerator;