| 1 | /*
|
|---|
| 2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
|---|
| 3 | Author Tobias Koppers @sokra
|
|---|
| 4 | */
|
|---|
| 5 |
|
|---|
| 6 | "use strict";
|
|---|
| 7 |
|
|---|
| 8 | const ExternalModuleFactoryPlugin = require("../ExternalModuleFactoryPlugin");
|
|---|
| 9 | const DelegatedSourceDependency = require("../dependencies/DelegatedSourceDependency");
|
|---|
| 10 | const WebpackError = require("../errors/WebpackError");
|
|---|
| 11 | const { makePathsRelative } = require("../util/identifier");
|
|---|
| 12 | const parseJson = require("../util/parseJson");
|
|---|
| 13 | const DelegatedModuleFactoryPlugin = require("./DelegatedModuleFactoryPlugin");
|
|---|
| 14 |
|
|---|
| 15 | /** @typedef {import("../../declarations/WebpackOptions").Externals} Externals */
|
|---|
| 16 | /** @typedef {import("../../declarations/plugins/dll/DllReferencePlugin").DllReferencePluginOptions} DllReferencePluginOptions */
|
|---|
| 17 | /** @typedef {import("../../declarations/plugins/dll/DllReferencePlugin").DllReferencePluginOptionsContent} DllReferencePluginOptionsContent */
|
|---|
| 18 | /** @typedef {import("../../declarations/plugins/dll/DllReferencePlugin").DllReferencePluginOptionsManifest} DllReferencePluginOptionsManifest */
|
|---|
| 19 | /** @typedef {import("../Compiler")} Compiler */
|
|---|
| 20 | /** @typedef {import("../Compiler").CompilationParams} CompilationParams */
|
|---|
| 21 | /** @typedef {import("../util/fs").InputFileSystem} InputFileSystem */
|
|---|
| 22 |
|
|---|
| 23 | /** @typedef {{ path: string, data: DllReferencePluginOptionsManifest | undefined, error: Error | undefined }} CompilationDataItem */
|
|---|
| 24 |
|
|---|
| 25 | const PLUGIN_NAME = "DllReferencePlugin";
|
|---|
| 26 |
|
|---|
| 27 | class DllReferencePlugin {
|
|---|
| 28 | /**
|
|---|
| 29 | * Creates an instance of DllReferencePlugin.
|
|---|
| 30 | * @param {DllReferencePluginOptions} options options object
|
|---|
| 31 | */
|
|---|
| 32 | constructor(options) {
|
|---|
| 33 | this.options = options;
|
|---|
| 34 | }
|
|---|
| 35 |
|
|---|
| 36 | /**
|
|---|
| 37 | * Applies the plugin by registering its hooks on the compiler.
|
|---|
| 38 | * @param {Compiler} compiler the compiler instance
|
|---|
| 39 | * @returns {void}
|
|---|
| 40 | */
|
|---|
| 41 | apply(compiler) {
|
|---|
| 42 | compiler.hooks.validate.tap(PLUGIN_NAME, () => {
|
|---|
| 43 | compiler.validate(
|
|---|
| 44 | () => require("../../schemas/plugins/dll/DllReferencePlugin.json"),
|
|---|
| 45 | this.options,
|
|---|
| 46 | {
|
|---|
| 47 | name: "Dll Reference Plugin",
|
|---|
| 48 | baseDataPath: "options"
|
|---|
| 49 | },
|
|---|
| 50 | (options) =>
|
|---|
| 51 | require("../../schemas/plugins/dll/DllReferencePlugin.check")(options)
|
|---|
| 52 | );
|
|---|
| 53 | });
|
|---|
| 54 | compiler.hooks.compilation.tap(
|
|---|
| 55 | PLUGIN_NAME,
|
|---|
| 56 | (compilation, { normalModuleFactory }) => {
|
|---|
| 57 | compilation.dependencyFactories.set(
|
|---|
| 58 | DelegatedSourceDependency,
|
|---|
| 59 | normalModuleFactory
|
|---|
| 60 | );
|
|---|
| 61 | }
|
|---|
| 62 | );
|
|---|
| 63 |
|
|---|
| 64 | /** @type {WeakMap<CompilationParams, CompilationDataItem>} */
|
|---|
| 65 | const compilationData = new WeakMap();
|
|---|
| 66 |
|
|---|
| 67 | compiler.hooks.beforeCompile.tapAsync(PLUGIN_NAME, (params, callback) => {
|
|---|
| 68 | if ("manifest" in this.options) {
|
|---|
| 69 | const manifest = this.options.manifest;
|
|---|
| 70 | if (typeof manifest === "string") {
|
|---|
| 71 | /** @type {InputFileSystem} */
|
|---|
| 72 | (compiler.inputFileSystem).readFile(manifest, (err, result) => {
|
|---|
| 73 | if (err) return callback(err);
|
|---|
| 74 | /** @type {CompilationDataItem} */
|
|---|
| 75 | const data = {
|
|---|
| 76 | path: manifest,
|
|---|
| 77 | data: undefined,
|
|---|
| 78 | error: undefined
|
|---|
| 79 | };
|
|---|
| 80 | // Catch errors parsing the manifest so that blank
|
|---|
| 81 | // or malformed manifest files don't kill the process.
|
|---|
| 82 | try {
|
|---|
| 83 | data.data =
|
|---|
| 84 | /** @type {DllReferencePluginOptionsManifest} */
|
|---|
| 85 | (
|
|---|
| 86 | /** @type {unknown} */
|
|---|
| 87 | (parseJson(/** @type {Buffer} */ (result).toString("utf8")))
|
|---|
| 88 | );
|
|---|
| 89 | } catch (parseErr) {
|
|---|
| 90 | // Store the error in the params so that it can
|
|---|
| 91 | // be added as a compilation error later on.
|
|---|
| 92 | const manifestPath = makePathsRelative(
|
|---|
| 93 | compiler.context,
|
|---|
| 94 | manifest,
|
|---|
| 95 | compiler.root
|
|---|
| 96 | );
|
|---|
| 97 | data.error = new DllManifestError(
|
|---|
| 98 | manifestPath,
|
|---|
| 99 | /** @type {Error} */ (parseErr).message
|
|---|
| 100 | );
|
|---|
| 101 | }
|
|---|
| 102 | compilationData.set(params, data);
|
|---|
| 103 | return callback();
|
|---|
| 104 | });
|
|---|
| 105 | return;
|
|---|
| 106 | }
|
|---|
| 107 | }
|
|---|
| 108 | return callback();
|
|---|
| 109 | });
|
|---|
| 110 |
|
|---|
| 111 | compiler.hooks.compile.tap(PLUGIN_NAME, (params) => {
|
|---|
| 112 | let name = this.options.name;
|
|---|
| 113 | let sourceType = this.options.sourceType;
|
|---|
| 114 | let resolvedContent =
|
|---|
| 115 | "content" in this.options ? this.options.content : undefined;
|
|---|
| 116 | if ("manifest" in this.options) {
|
|---|
| 117 | const manifestParameter = this.options.manifest;
|
|---|
| 118 | /** @type {undefined | DllReferencePluginOptionsManifest} */
|
|---|
| 119 | let manifest;
|
|---|
| 120 | if (typeof manifestParameter === "string") {
|
|---|
| 121 | const data =
|
|---|
| 122 | /** @type {CompilationDataItem} */
|
|---|
| 123 | (compilationData.get(params));
|
|---|
| 124 | // If there was an error parsing the manifest
|
|---|
| 125 | // file, exit now because the error will be added
|
|---|
| 126 | // as a compilation error in the "compilation" hook.
|
|---|
| 127 | if (data.error) {
|
|---|
| 128 | return;
|
|---|
| 129 | }
|
|---|
| 130 | manifest = data.data;
|
|---|
| 131 | } else {
|
|---|
| 132 | manifest = manifestParameter;
|
|---|
| 133 | }
|
|---|
| 134 | if (manifest) {
|
|---|
| 135 | if (!name) name = manifest.name;
|
|---|
| 136 | if (!sourceType) sourceType = manifest.type;
|
|---|
| 137 | if (!resolvedContent) resolvedContent = manifest.content;
|
|---|
| 138 | }
|
|---|
| 139 | }
|
|---|
| 140 | /** @type {Externals} */
|
|---|
| 141 | const externals = {};
|
|---|
| 142 | const source = `dll-reference ${name}`;
|
|---|
| 143 | externals[source] = /** @type {string} */ (name);
|
|---|
| 144 | const normalModuleFactory = params.normalModuleFactory;
|
|---|
| 145 | new ExternalModuleFactoryPlugin(sourceType || "var", externals).apply(
|
|---|
| 146 | normalModuleFactory
|
|---|
| 147 | );
|
|---|
| 148 | new DelegatedModuleFactoryPlugin({
|
|---|
| 149 | source,
|
|---|
| 150 | type: this.options.type,
|
|---|
| 151 | scope: this.options.scope,
|
|---|
| 152 | context: this.options.context || compiler.context,
|
|---|
| 153 | content:
|
|---|
| 154 | /** @type {DllReferencePluginOptionsContent} */
|
|---|
| 155 | (resolvedContent),
|
|---|
| 156 | extensions: this.options.extensions,
|
|---|
| 157 | associatedObjectForCache: compiler.root
|
|---|
| 158 | }).apply(normalModuleFactory);
|
|---|
| 159 | });
|
|---|
| 160 |
|
|---|
| 161 | compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation, params) => {
|
|---|
| 162 | if ("manifest" in this.options) {
|
|---|
| 163 | const manifest = this.options.manifest;
|
|---|
| 164 | if (typeof manifest === "string") {
|
|---|
| 165 | const data =
|
|---|
| 166 | /** @type {CompilationDataItem} */
|
|---|
| 167 | (compilationData.get(params));
|
|---|
| 168 | // If there was an error parsing the manifest file, add the
|
|---|
| 169 | // error as a compilation error to make the compilation fail.
|
|---|
| 170 | if (data.error) {
|
|---|
| 171 | compilation.errors.push(
|
|---|
| 172 | /** @type {DllManifestError} */ (data.error)
|
|---|
| 173 | );
|
|---|
| 174 | }
|
|---|
| 175 | compilation.fileDependencies.add(manifest);
|
|---|
| 176 | }
|
|---|
| 177 | }
|
|---|
| 178 | });
|
|---|
| 179 | }
|
|---|
| 180 | }
|
|---|
| 181 |
|
|---|
| 182 | class DllManifestError extends WebpackError {
|
|---|
| 183 | /**
|
|---|
| 184 | * Creates an instance of DllManifestError.
|
|---|
| 185 | * @param {string} filename filename of the manifest
|
|---|
| 186 | * @param {string} message error message
|
|---|
| 187 | */
|
|---|
| 188 | constructor(filename, message) {
|
|---|
| 189 | super();
|
|---|
| 190 |
|
|---|
| 191 | this.name = "DllManifestError";
|
|---|
| 192 | this.message = `Dll manifest ${filename}\n${message}`;
|
|---|
| 193 | }
|
|---|
| 194 | }
|
|---|
| 195 |
|
|---|
| 196 | module.exports = DllReferencePlugin;
|
|---|