UNPKG

4.55 kBJavaScriptView Raw
1"use strict";
2
3const path = require("path");
4
5const worker = require("./worker");
6
7const schema = require("./loader-options.json");
8
9const {
10 isAbsoluteURL
11} = require("./utils.js");
12/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
13
14/** @typedef {import("webpack").Compilation} Compilation */
15
16/**
17 * @template T
18 * @typedef {Object} LoaderOptions<T>
19 * @property {string} [severityError] Allows to choose how errors are displayed.
20 * @property {import("./index").Minimizer<T> | import("./index").Minimizer<T>[]} [minimizer]
21 * @property {import("./index").Generator<T>[]} [generator]
22 */
23
24/**
25 * @template T
26 * @this {import("webpack").LoaderContext<LoaderOptions<T>>}
27 * @param {Buffer} content
28 * @returns {Promise<Buffer | undefined>}
29 */
30
31
32async function loader(content) {
33 // Avoid optimize twice
34 if (this._module && this._module.buildMeta && this._module.buildMeta.imageMinimizerPluginInfo && (this._module.buildMeta.imageMinimizerPluginInfo.minimized || this._module.buildMeta.imageMinimizerPluginInfo.generated)) {
35 return content;
36 } // @ts-ignore
37
38
39 const options = this.getOptions(
40 /** @type {Schema} */
41 schema);
42 const callback = this.async();
43 const {
44 generator,
45 minimizer,
46 severityError
47 } = options;
48
49 if (!minimizer && !generator) {
50 callback(new Error("Not configured 'minimizer' or 'generator' options, please setup them"));
51 return;
52 }
53
54 let transformer = minimizer;
55 let parsedQuery;
56
57 if (this.resourceQuery.length > 0) {
58 parsedQuery = new URLSearchParams(this.resourceQuery);
59
60 if (parsedQuery.has("as")) {
61 if (!generator) {
62 callback(new Error("Please specify the 'generator' option to use 'as' query param for generation purposes."));
63 return;
64 }
65
66 const as = parsedQuery.get("as");
67 const presets = generator.filter(item => item.preset === as);
68
69 if (presets.length > 1) {
70 callback(new Error("Found several identical pereset names, the 'preset' option should be unique"));
71 return;
72 }
73
74 if (presets.length === 0) {
75 callback(new Error(`Can't find '${as}' preset in the 'generator' option`));
76 return;
77 }
78
79 [transformer] = presets;
80 }
81 }
82
83 if (!transformer) {
84 callback(null, content);
85 return;
86 }
87
88 const isAbsolute = isAbsoluteURL(this.resourcePath);
89 const filename = isAbsolute ? this.resourcePath : path.relative(this.rootContext, this.resourcePath);
90 const minifyOptions =
91 /** @type {import("./index").InternalWorkerOptions<T>} */
92 {
93 input: content,
94 filename,
95 severityError,
96 transformer,
97 generateFilename:
98 /** @type {Compilation} */
99 this._compilation.getAssetPath.bind(this._compilation)
100 };
101 const output = await worker(minifyOptions);
102
103 if (output.errors && output.errors.length > 0) {
104 output.errors.forEach(error => {
105 this.emitError(error);
106 });
107 callback(null, content);
108 return;
109 }
110
111 if (output.warnings && output.warnings.length > 0) {
112 output.warnings.forEach(warning => {
113 this.emitWarning(warning);
114 });
115 } // Change content of the data URI after minimizer
116
117
118 if (this._module && this._module.resourceResolveData && this._module.resourceResolveData.encodedContent) {
119 const isBase64 = /^base64$/i.test(this._module.resourceResolveData.encoding);
120 this._module.resourceResolveData.encodedContent = isBase64 ? output.data.toString("base64") : encodeURIComponent(output.data.toString("utf-8")).replace(/[!'()*]/g, character => `%${
121 /** @type {number} */
122 character.codePointAt(0).toString(16)}`);
123 } else {
124 let query = this.resourceQuery;
125
126 if (parsedQuery) {
127 // Remove query param from the bundle due we need that only for bundle purposes
128 const stringifiedParsedQuery = parsedQuery.toString();
129 query = stringifiedParsedQuery.length > 0 ? `?${stringifiedParsedQuery}` : "";
130 parsedQuery.delete("as");
131 } // Old approach for `file-loader` and other old loaders
132
133
134 this.resourcePath = isAbsolute ? output.filename : path.join(this.rootContext, output.filename);
135 this.resourceQuery = query; // Change name of assets modules after generator
136
137 if (this._module && !this._module.matchResource) {
138 this._module.matchResource = `${output.filename}${query}`;
139 }
140 } // TODO: search better API
141
142
143 if (this._module) {
144 this._module.buildMeta = { ...this._module.buildMeta,
145 imageMinimizerPluginInfo: output.info
146 };
147 }
148
149 callback(null, output.data);
150}
151
152loader.raw = true;
153module.exports = loader;
\No newline at end of file