1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | "use strict";
|
7 |
|
8 | const { cleverMerge } = require("../util/cleverMerge");
|
9 | const { compareModulesByIdentifier } = require("../util/comparators");
|
10 | const createSchemaValidation = require("../util/create-schema-validation");
|
11 | const memoize = require("../util/memoize");
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | const getSchema = name => {
|
19 | const { definitions } = require("../../schemas/WebpackOptions.json");
|
20 | return {
|
21 | definitions,
|
22 | oneOf: [{ $ref: `#/definitions/${name}` }]
|
23 | };
|
24 | };
|
25 |
|
26 | const generatorValidationOptions = {
|
27 | name: "Asset Modules Plugin",
|
28 | baseDataPath: "generator"
|
29 | };
|
30 | const validateGeneratorOptions = {
|
31 | asset: createSchemaValidation(
|
32 | require("../../schemas/plugins/asset/AssetGeneratorOptions.check.js"),
|
33 | () => getSchema("AssetGeneratorOptions"),
|
34 | generatorValidationOptions
|
35 | ),
|
36 | "asset/resource": createSchemaValidation(
|
37 | require("../../schemas/plugins/asset/AssetResourceGeneratorOptions.check.js"),
|
38 | () => getSchema("AssetResourceGeneratorOptions"),
|
39 | generatorValidationOptions
|
40 | ),
|
41 | "asset/inline": createSchemaValidation(
|
42 | require("../../schemas/plugins/asset/AssetInlineGeneratorOptions.check.js"),
|
43 | () => getSchema("AssetInlineGeneratorOptions"),
|
44 | generatorValidationOptions
|
45 | )
|
46 | };
|
47 |
|
48 | const validateParserOptions = createSchemaValidation(
|
49 | require("../../schemas/plugins/asset/AssetParserOptions.check.js"),
|
50 | () => getSchema("AssetParserOptions"),
|
51 | {
|
52 | name: "Asset Modules Plugin",
|
53 | baseDataPath: "parser"
|
54 | }
|
55 | );
|
56 |
|
57 | const getAssetGenerator = memoize(() => require("./AssetGenerator"));
|
58 | const getAssetParser = memoize(() => require("./AssetParser"));
|
59 | const getAssetSourceParser = memoize(() => require("./AssetSourceParser"));
|
60 | const getAssetSourceGenerator = memoize(() =>
|
61 | require("./AssetSourceGenerator")
|
62 | );
|
63 |
|
64 | const type = "asset";
|
65 | const plugin = "AssetModulesPlugin";
|
66 |
|
67 | class AssetModulesPlugin {
|
68 | |
69 |
|
70 |
|
71 |
|
72 |
|
73 | apply(compiler) {
|
74 | compiler.hooks.compilation.tap(
|
75 | plugin,
|
76 | (compilation, { normalModuleFactory }) => {
|
77 | normalModuleFactory.hooks.createParser
|
78 | .for("asset")
|
79 | .tap(plugin, parserOptions => {
|
80 | validateParserOptions(parserOptions);
|
81 | parserOptions = cleverMerge(
|
82 | compiler.options.module.parser.asset,
|
83 | parserOptions
|
84 | );
|
85 |
|
86 | let dataUrlCondition = parserOptions.dataUrlCondition;
|
87 | if (!dataUrlCondition || typeof dataUrlCondition === "object") {
|
88 | dataUrlCondition = {
|
89 | maxSize: 8096,
|
90 | ...dataUrlCondition
|
91 | };
|
92 | }
|
93 |
|
94 | const AssetParser = getAssetParser();
|
95 |
|
96 | return new AssetParser(dataUrlCondition);
|
97 | });
|
98 | normalModuleFactory.hooks.createParser
|
99 | .for("asset/inline")
|
100 | .tap(plugin, parserOptions => {
|
101 | const AssetParser = getAssetParser();
|
102 |
|
103 | return new AssetParser(true);
|
104 | });
|
105 | normalModuleFactory.hooks.createParser
|
106 | .for("asset/resource")
|
107 | .tap(plugin, parserOptions => {
|
108 | const AssetParser = getAssetParser();
|
109 |
|
110 | return new AssetParser(false);
|
111 | });
|
112 | normalModuleFactory.hooks.createParser
|
113 | .for("asset/source")
|
114 | .tap(plugin, parserOptions => {
|
115 | const AssetSourceParser = getAssetSourceParser();
|
116 |
|
117 | return new AssetSourceParser();
|
118 | });
|
119 |
|
120 | for (const type of ["asset", "asset/inline", "asset/resource"]) {
|
121 | normalModuleFactory.hooks.createGenerator
|
122 | .for(type)
|
123 | .tap(plugin, generatorOptions => {
|
124 | validateGeneratorOptions[type](generatorOptions);
|
125 |
|
126 | let dataUrl = undefined;
|
127 | if (type !== "asset/resource") {
|
128 | dataUrl = generatorOptions.dataUrl;
|
129 | if (!dataUrl || typeof dataUrl === "object") {
|
130 | dataUrl = {
|
131 | encoding: undefined,
|
132 | mimetype: undefined,
|
133 | ...dataUrl
|
134 | };
|
135 | }
|
136 | }
|
137 |
|
138 | let filename = undefined;
|
139 | let publicPath = undefined;
|
140 | if (type !== "asset/inline") {
|
141 | filename = generatorOptions.filename;
|
142 | publicPath = generatorOptions.publicPath;
|
143 | }
|
144 |
|
145 | const AssetGenerator = getAssetGenerator();
|
146 |
|
147 | return new AssetGenerator(
|
148 | dataUrl,
|
149 | filename,
|
150 | publicPath,
|
151 | generatorOptions.emit !== false
|
152 | );
|
153 | });
|
154 | }
|
155 | normalModuleFactory.hooks.createGenerator
|
156 | .for("asset/source")
|
157 | .tap(plugin, () => {
|
158 | const AssetSourceGenerator = getAssetSourceGenerator();
|
159 |
|
160 | return new AssetSourceGenerator();
|
161 | });
|
162 |
|
163 | compilation.hooks.renderManifest.tap(plugin, (result, options) => {
|
164 | const { chunkGraph } = compilation;
|
165 | const { chunk, codeGenerationResults } = options;
|
166 |
|
167 | const modules = chunkGraph.getOrderedChunkModulesIterableBySourceType(
|
168 | chunk,
|
169 | "asset",
|
170 | compareModulesByIdentifier
|
171 | );
|
172 | if (modules) {
|
173 | for (const module of modules) {
|
174 | try {
|
175 | const codeGenResult = codeGenerationResults.get(
|
176 | module,
|
177 | chunk.runtime
|
178 | );
|
179 | result.push({
|
180 | render: () => codeGenResult.sources.get(type),
|
181 | filename:
|
182 | module.buildInfo.filename ||
|
183 | codeGenResult.data.get("filename"),
|
184 | info:
|
185 | module.buildInfo.assetInfo ||
|
186 | codeGenResult.data.get("assetInfo"),
|
187 | auxiliary: true,
|
188 | identifier: `assetModule${chunkGraph.getModuleId(module)}`,
|
189 | hash:
|
190 | module.buildInfo.fullContentHash ||
|
191 | codeGenResult.data.get("fullContentHash")
|
192 | });
|
193 | } catch (e) {
|
194 | e.message += `\nduring rendering of asset ${module.identifier()}`;
|
195 | throw e;
|
196 | }
|
197 | }
|
198 | }
|
199 |
|
200 | return result;
|
201 | });
|
202 |
|
203 | compilation.hooks.prepareModuleExecution.tap(
|
204 | "AssetModulesPlugin",
|
205 | (options, context) => {
|
206 | const { codeGenerationResult } = options;
|
207 | const source = codeGenerationResult.sources.get("asset");
|
208 | if (source === undefined) return;
|
209 | context.assets.set(codeGenerationResult.data.get("filename"), {
|
210 | source,
|
211 | info: codeGenerationResult.data.get("assetInfo")
|
212 | });
|
213 | }
|
214 | );
|
215 | }
|
216 | );
|
217 | }
|
218 | }
|
219 |
|
220 | module.exports = AssetModulesPlugin;
|