@rushstack/webpack4-module-minifier-plugin 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +24 -0
- package/README.md +61 -0
- package/dist/tsdoc-metadata.json +11 -0
- package/dist/webpack4-module-minifier-plugin.d.ts +346 -0
- package/lib/AsyncImportCompressionPlugin.d.ts +14 -0
- package/lib/AsyncImportCompressionPlugin.d.ts.map +1 -0
- package/lib/AsyncImportCompressionPlugin.js +200 -0
- package/lib/AsyncImportCompressionPlugin.js.map +1 -0
- package/lib/Constants.d.ts +28 -0
- package/lib/Constants.d.ts.map +1 -0
- package/lib/Constants.js +33 -0
- package/lib/Constants.js.map +1 -0
- package/lib/GenerateLicenseFileForAsset.d.ts +13 -0
- package/lib/GenerateLicenseFileForAsset.d.ts.map +1 -0
- package/lib/GenerateLicenseFileForAsset.js +79 -0
- package/lib/GenerateLicenseFileForAsset.js.map +1 -0
- package/lib/ModuleMinifierPlugin.d.ts +18 -0
- package/lib/ModuleMinifierPlugin.d.ts.map +1 -0
- package/lib/ModuleMinifierPlugin.js +439 -0
- package/lib/ModuleMinifierPlugin.js.map +1 -0
- package/lib/ModuleMinifierPlugin.types.d.ts +217 -0
- package/lib/ModuleMinifierPlugin.types.d.ts.map +1 -0
- package/lib/ModuleMinifierPlugin.types.js +5 -0
- package/lib/ModuleMinifierPlugin.types.js.map +1 -0
- package/lib/OverrideWebpackIdentifierAllocation.d.ts +2 -0
- package/lib/OverrideWebpackIdentifierAllocation.d.ts.map +1 -0
- package/lib/OverrideWebpackIdentifierAllocation.js +9 -0
- package/lib/OverrideWebpackIdentifierAllocation.js.map +1 -0
- package/lib/ParallelCompiler.d.ts +11 -0
- package/lib/ParallelCompiler.d.ts.map +1 -0
- package/lib/ParallelCompiler.js +90 -0
- package/lib/ParallelCompiler.js.map +1 -0
- package/lib/PortableMinifierIdsPlugin.d.ts +13 -0
- package/lib/PortableMinifierIdsPlugin.d.ts.map +1 -0
- package/lib/PortableMinifierIdsPlugin.js +129 -0
- package/lib/PortableMinifierIdsPlugin.js.map +1 -0
- package/lib/RehydrateAsset.d.ts +11 -0
- package/lib/RehydrateAsset.d.ts.map +1 -0
- package/lib/RehydrateAsset.js +143 -0
- package/lib/RehydrateAsset.js.map +1 -0
- package/lib/index.d.ts +9 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +32 -0
- package/lib/index.js.map +1 -0
- package/lib/workerPool/WebpackWorker.d.ts +2 -0
- package/lib/workerPool/WebpackWorker.d.ts.map +1 -0
- package/lib/workerPool/WebpackWorker.js +101 -0
- package/lib/workerPool/WebpackWorker.js.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
@rushstack/webpack4-module-minifier-plugin
|
|
2
|
+
|
|
3
|
+
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
|
|
5
|
+
MIT License
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
8
|
+
a copy of this software and associated documentation files (the
|
|
9
|
+
"Software"), to deal in the Software without restriction, including
|
|
10
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
11
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
12
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
13
|
+
the following conditions:
|
|
14
|
+
|
|
15
|
+
The above copyright notice and this permission notice shall be
|
|
16
|
+
included in all copies or substantial portions of the Software.
|
|
17
|
+
|
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
20
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
21
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
22
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
23
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
24
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# @rushstack/webpack4-module-minifier-plugin
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
`npm install @rushstack/webpack4-module-minifier-plugin --save-dev`
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
This Webpack plugin performs minification of production assets on a per-module basis, rather than minifying an entire chunk at a time.
|
|
10
|
+
It issues async calls to the minifier for each unique module and each unique set of chunk boilerplate (i.e. the webpack runtime and the structure of the module list).
|
|
11
|
+
This improves minification time by:
|
|
12
|
+
- Avoiding duplicate work for each module that is included in multiple distinct assets/chunks (this is common with async chunks)
|
|
13
|
+
- Handing smaller code chunks to the minifier at a time (AST analysis is superlinear in size of the AST)
|
|
14
|
+
- Even single asset builds will likely still contain multiple modules in the final output, which can be split across available CPU cores
|
|
15
|
+
|
|
16
|
+
## Use with `[hash]` and `[contenthash]` tokens
|
|
17
|
+
The plugin will do its best to update webpack hashes if changing the direct inputs (`useSourceMap`, `compressAsyncImports` or `usePortableModules`) to the plugin, but if altering the `minifier` property itself, you may need to use the `output.hashSalt` property to force a change to the hashes, especially if leverging the `MessagePortMinifier` or similar, since it has no direct access to the configuration of the minifier.
|
|
18
|
+
|
|
19
|
+
## Parallel execution
|
|
20
|
+
If running on node 10, you will need to ensure that the `--experimental-workers` flag is enabled.
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
const { ModuleMinifierPlugin, WorkerPoolMinifier } = require('@rushstack/webpack4-module-minifier-plugin');
|
|
24
|
+
|
|
25
|
+
// In your webpack options:
|
|
26
|
+
optimization: {
|
|
27
|
+
minimizer: [
|
|
28
|
+
new ModuleMinifierPlugin({
|
|
29
|
+
minifier: new WorkerPoolMinifier(),
|
|
30
|
+
// If not provided, the plugin will attempt to guess from `mode` and `devtool`.
|
|
31
|
+
// Providing it expressly gives better results
|
|
32
|
+
useSourceMap: true
|
|
33
|
+
})
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Single-threaded execution
|
|
39
|
+
You can also run the ModuleMinifierPlugin in a single-threaded configuration.
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
// webpack.config.js
|
|
43
|
+
const { ModuleMinifierPlugin, LocalMinifier } = require('@rushstack/webpack4-module-minifier-plugin');
|
|
44
|
+
|
|
45
|
+
// In your webpack options:
|
|
46
|
+
optimization: {
|
|
47
|
+
minimizer: [
|
|
48
|
+
new ModuleMinifierPlugin({
|
|
49
|
+
minifier: new LocalMinifier()
|
|
50
|
+
})
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Links
|
|
56
|
+
|
|
57
|
+
- [CHANGELOG.md](
|
|
58
|
+
https://github.com/microsoft/rushstack/blob/main/webpack/module-minifier-plugin/CHANGELOG.md) - Find
|
|
59
|
+
out what's new in the latest version
|
|
60
|
+
|
|
61
|
+
`@rushstack/webpack4-module-minifier-plugin` is part of the [Rush Stack](https://rushstack.io/) family of projects.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// This file is read by tools that parse documentation comments conforming to the TSDoc standard.
|
|
2
|
+
// It should be published with your NPM package. It should not be tracked by Git.
|
|
3
|
+
{
|
|
4
|
+
"tsdocVersion": "0.12",
|
|
5
|
+
"toolPackages": [
|
|
6
|
+
{
|
|
7
|
+
"packageName": "@microsoft/api-extractor",
|
|
8
|
+
"packageVersion": "7.25.2"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import type { AsyncSeriesWaterfallHook } from 'tapable';
|
|
2
|
+
import { Compiler } from 'webpack';
|
|
3
|
+
import { getIdentifier } from '@rushstack/module-minifier';
|
|
4
|
+
import { ILocalMinifierOptions } from '@rushstack/module-minifier';
|
|
5
|
+
import { IMinifierConnection } from '@rushstack/module-minifier';
|
|
6
|
+
import { IModuleMinificationCallback } from '@rushstack/module-minifier';
|
|
7
|
+
import { IModuleMinificationErrorResult } from '@rushstack/module-minifier';
|
|
8
|
+
import { IModuleMinificationRequest } from '@rushstack/module-minifier';
|
|
9
|
+
import { IModuleMinificationResult } from '@rushstack/module-minifier';
|
|
10
|
+
import { IModuleMinificationSuccessResult } from '@rushstack/module-minifier';
|
|
11
|
+
import { IModuleMinifier } from '@rushstack/module-minifier';
|
|
12
|
+
import { IModuleMinifierFunction } from '@rushstack/module-minifier';
|
|
13
|
+
import { IWorkerPoolMinifierOptions } from '@rushstack/module-minifier';
|
|
14
|
+
import { LocalMinifier } from '@rushstack/module-minifier';
|
|
15
|
+
import { MessagePortMinifier } from '@rushstack/module-minifier';
|
|
16
|
+
import { NoopMinifier } from '@rushstack/module-minifier';
|
|
17
|
+
import { Plugin } from 'webpack';
|
|
18
|
+
import type { ReplaceSource } from 'webpack-sources';
|
|
19
|
+
import { Source } from 'webpack-sources';
|
|
20
|
+
import type { SyncWaterfallHook } from 'tapable';
|
|
21
|
+
import * as webpack from 'webpack';
|
|
22
|
+
import { WorkerPoolMinifier } from '@rushstack/module-minifier';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Token to replace the object or array of module definitions so that the minifier can operate on the Webpack runtime or chunk boilerplate in isolation
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
export declare const CHUNK_MODULES_TOKEN: '__WEBPACK_CHUNK_MODULES__';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Generates a companion asset containing all extracted comments. If it is non-empty, returns a banner comment directing users to said companion asset.
|
|
32
|
+
*
|
|
33
|
+
* @param compilation - The webpack compilation
|
|
34
|
+
* @param asset - The asset to process
|
|
35
|
+
* @param minifiedModules - The minified modules to pull comments from
|
|
36
|
+
* @param assetName - The name of the asset
|
|
37
|
+
* @public
|
|
38
|
+
*/
|
|
39
|
+
export declare function generateLicenseFileForAsset(compilation: webpack.compilation.Compilation, asset: IAssetInfo, minifiedModules: IModuleMap): string;
|
|
40
|
+
|
|
41
|
+
export { getIdentifier }
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The comment objects from the Acorn parser inside of webpack
|
|
45
|
+
* @internal
|
|
46
|
+
*/
|
|
47
|
+
export declare interface _IAcornComment {
|
|
48
|
+
type: 'Line' | 'Block';
|
|
49
|
+
value: string;
|
|
50
|
+
start: number;
|
|
51
|
+
end: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Information about a dehydrated webpack ECMAScript asset
|
|
56
|
+
* @public
|
|
57
|
+
*/
|
|
58
|
+
export declare interface IAssetInfo {
|
|
59
|
+
/**
|
|
60
|
+
* The (minified) boilerplate code for the asset. Will contain a token to be replaced by the minified modules.
|
|
61
|
+
*/
|
|
62
|
+
source: Source;
|
|
63
|
+
/**
|
|
64
|
+
* The name of the asset, used to index into compilation.assets
|
|
65
|
+
*/
|
|
66
|
+
fileName: string;
|
|
67
|
+
/**
|
|
68
|
+
* The ids of the modules that are part of the chunk corresponding to this asset
|
|
69
|
+
*/
|
|
70
|
+
modules: (string | number)[];
|
|
71
|
+
/**
|
|
72
|
+
* The raw chunk object from Webpack, in case information from it is necessary for reconstruction
|
|
73
|
+
*/
|
|
74
|
+
chunk: webpack.compilation.Chunk;
|
|
75
|
+
/**
|
|
76
|
+
* The set of external names to postprocess
|
|
77
|
+
*/
|
|
78
|
+
externalNames: Map<string, string>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* A map from file names to dehydrated assets
|
|
83
|
+
* @public
|
|
84
|
+
*/
|
|
85
|
+
export declare type IAssetMap = Map<string, IAssetInfo>;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The set of data remaining to rehydrate in the current compilation
|
|
89
|
+
* @public
|
|
90
|
+
*/
|
|
91
|
+
export declare interface IDehydratedAssets {
|
|
92
|
+
/**
|
|
93
|
+
* The set of remaining assets to rehydrate. Each tap may remove some or all assets from this collection
|
|
94
|
+
*/
|
|
95
|
+
assets: IAssetMap;
|
|
96
|
+
/**
|
|
97
|
+
* The set of modules to use for rehydrating assets.
|
|
98
|
+
*/
|
|
99
|
+
modules: IModuleMap;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Extension of the webpack Module typings with members that are used by this Plugin
|
|
104
|
+
* @public
|
|
105
|
+
*/
|
|
106
|
+
export declare interface IExtendedModule extends webpack.compilation.Module {
|
|
107
|
+
/**
|
|
108
|
+
* Is this module external?
|
|
109
|
+
*/
|
|
110
|
+
external?: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Concatenated modules
|
|
113
|
+
*/
|
|
114
|
+
modules?: IExtendedModule[];
|
|
115
|
+
/**
|
|
116
|
+
* Recursively scan the dependencies of a module
|
|
117
|
+
*/
|
|
118
|
+
hasDependencies(callback: (dep: webpack.compilation.Dependency) => boolean | void): boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Id for the module
|
|
121
|
+
*/
|
|
122
|
+
id: string | number | null;
|
|
123
|
+
/**
|
|
124
|
+
* Gets a descriptive identifier for the module.
|
|
125
|
+
*/
|
|
126
|
+
identifier(): string;
|
|
127
|
+
/**
|
|
128
|
+
* Gets a friendly identifier for the module.
|
|
129
|
+
*/
|
|
130
|
+
readableIdentifier(requestShortener: unknown): string;
|
|
131
|
+
/**
|
|
132
|
+
* Path to the physical file this module represents
|
|
133
|
+
*/
|
|
134
|
+
resource?: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export { ILocalMinifierOptions }
|
|
138
|
+
|
|
139
|
+
export { IMinifierConnection }
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Information about a minified module
|
|
143
|
+
* @public
|
|
144
|
+
*/
|
|
145
|
+
export declare interface IModuleInfo {
|
|
146
|
+
/**
|
|
147
|
+
* The (minified) code of this module. Will be a function expression.
|
|
148
|
+
*/
|
|
149
|
+
source: Source;
|
|
150
|
+
/**
|
|
151
|
+
* The raw module object from Webpack, in case information from it is necessary for reconstruction
|
|
152
|
+
*/
|
|
153
|
+
module: IExtendedModule;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* A map from module ids to minified modules
|
|
158
|
+
* @public
|
|
159
|
+
*/
|
|
160
|
+
export declare type IModuleMap = Map<string | number, IModuleInfo>;
|
|
161
|
+
|
|
162
|
+
export { IModuleMinificationCallback }
|
|
163
|
+
|
|
164
|
+
export { IModuleMinificationErrorResult }
|
|
165
|
+
|
|
166
|
+
export { IModuleMinificationRequest }
|
|
167
|
+
|
|
168
|
+
export { IModuleMinificationResult }
|
|
169
|
+
|
|
170
|
+
export { IModuleMinificationSuccessResult }
|
|
171
|
+
|
|
172
|
+
export { IModuleMinifier }
|
|
173
|
+
|
|
174
|
+
export { IModuleMinifierFunction }
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Hooks provided by the ModuleMinifierPlugin
|
|
178
|
+
* @public
|
|
179
|
+
*/
|
|
180
|
+
export declare interface IModuleMinifierPluginHooks {
|
|
181
|
+
/**
|
|
182
|
+
* Hook invoked at the start of optimizeChunkAssets to rehydrate the minified boilerplate and runtime into chunk assets.
|
|
183
|
+
*/
|
|
184
|
+
rehydrateAssets: AsyncSeriesWaterfallHook<IDehydratedAssets, webpack.compilation.Compilation>;
|
|
185
|
+
/**
|
|
186
|
+
* Hook invoked on a module id to get the final rendered id.
|
|
187
|
+
*/
|
|
188
|
+
finalModuleId: SyncWaterfallHook<string | number | undefined, webpack.compilation.Compilation>;
|
|
189
|
+
/**
|
|
190
|
+
* Hook invoked on code after it has been returned from the minifier.
|
|
191
|
+
*/
|
|
192
|
+
postProcessCodeFragment: SyncWaterfallHook<ReplaceSource, IPostProcessFragmentContext>;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Options to the ModuleMinifierPlugin constructor
|
|
197
|
+
* @public
|
|
198
|
+
*/
|
|
199
|
+
export declare interface IModuleMinifierPluginOptions {
|
|
200
|
+
/**
|
|
201
|
+
* Minifier implementation to use. Required.
|
|
202
|
+
*/
|
|
203
|
+
minifier: IModuleMinifier;
|
|
204
|
+
/**
|
|
205
|
+
* Whether to enable source map processing. If not provided, will attempt to guess based on `mode` and `devtool` in the webpack config.
|
|
206
|
+
* Set to `false` for faster builds at the expense of debuggability.
|
|
207
|
+
*/
|
|
208
|
+
sourceMap?: boolean;
|
|
209
|
+
/**
|
|
210
|
+
* Instructs the plugin to alter the code of modules to maximize portability across compilations.
|
|
211
|
+
*/
|
|
212
|
+
usePortableModules?: boolean;
|
|
213
|
+
/**
|
|
214
|
+
* Instructs the plugin to alter the code of async import statements to compress better and be portable across compilations.
|
|
215
|
+
*/
|
|
216
|
+
compressAsyncImports?: boolean;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* This is the second parameter to the NormalModuleFactory `module` hook
|
|
221
|
+
* @internal
|
|
222
|
+
*/
|
|
223
|
+
export declare interface _INormalModuleFactoryModuleData {
|
|
224
|
+
resourceResolveData?: {
|
|
225
|
+
/**
|
|
226
|
+
* Contents of the description file (package.json) for the module
|
|
227
|
+
*/
|
|
228
|
+
descriptionFileData?: {
|
|
229
|
+
/**
|
|
230
|
+
* The name of the package
|
|
231
|
+
*/
|
|
232
|
+
name: string;
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* Absolute path of the description file (package.json) for the module
|
|
236
|
+
*/
|
|
237
|
+
descriptionFilePath?: string;
|
|
238
|
+
/**
|
|
239
|
+
* Absolute path of the directory containing the description file (package.json) for the module
|
|
240
|
+
*/
|
|
241
|
+
descriptionFileRoot?: string;
|
|
242
|
+
/**
|
|
243
|
+
* Relative path from the description file (package.json) to the module
|
|
244
|
+
*/
|
|
245
|
+
relativePath?: string;
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Argument to the postProcessCodeFragment hook for the current execution context
|
|
251
|
+
* @public
|
|
252
|
+
*/
|
|
253
|
+
export declare interface IPostProcessFragmentContext {
|
|
254
|
+
/**
|
|
255
|
+
* The current webpack compilation, for error reporting
|
|
256
|
+
*/
|
|
257
|
+
compilation: webpack.compilation.Compilation;
|
|
258
|
+
/**
|
|
259
|
+
* A name to use for logging
|
|
260
|
+
*/
|
|
261
|
+
loggingName: string;
|
|
262
|
+
/**
|
|
263
|
+
* The current module being processed, or `undefined` if not in a module (e.g. the bootstrapper)
|
|
264
|
+
*/
|
|
265
|
+
module: webpack.compilation.Module | undefined;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* This is the second parameter to the thisCompilation and compilation webpack.Compiler hooks.
|
|
270
|
+
* @internal
|
|
271
|
+
*/
|
|
272
|
+
export declare interface _IWebpackCompilationData {
|
|
273
|
+
normalModuleFactory: webpack.compilation.NormalModuleFactory;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export { IWorkerPoolMinifierOptions }
|
|
277
|
+
|
|
278
|
+
export { LocalMinifier }
|
|
279
|
+
|
|
280
|
+
export { MessagePortMinifier }
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Prefix to wrap `function (module, __webpack_exports__, __webpack_require__) { ... }` so that the minifier doesn't delete it.
|
|
284
|
+
* Public because alternate Minifier implementations may wish to know about it.
|
|
285
|
+
* @public
|
|
286
|
+
*/
|
|
287
|
+
export declare const MODULE_WRAPPER_PREFIX: '__MINIFY_MODULE__(';
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Suffix to wrap `function (module, __webpack_exports__, __webpack_require__) { ... }` so that the minifier doesn't delete it.
|
|
291
|
+
* Public because alternate Minifier implementations may wish to know about it.
|
|
292
|
+
* @public
|
|
293
|
+
*/
|
|
294
|
+
export declare const MODULE_WRAPPER_SUFFIX: ');';
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Webpack plugin that minifies code on a per-module basis rather than per-asset. The actual minification is handled by the input `minifier` object.
|
|
298
|
+
* @public
|
|
299
|
+
*/
|
|
300
|
+
export declare class ModuleMinifierPlugin implements webpack.Plugin {
|
|
301
|
+
readonly hooks: IModuleMinifierPluginHooks;
|
|
302
|
+
minifier: IModuleMinifier;
|
|
303
|
+
private readonly _enhancers;
|
|
304
|
+
private readonly _sourceMap;
|
|
305
|
+
private readonly _optionsForHash;
|
|
306
|
+
constructor(options: IModuleMinifierPluginOptions);
|
|
307
|
+
apply(compiler: webpack.Compiler): void;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export { NoopMinifier }
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Plugin responsible for converting the Webpack module ids (of whatever variety) to stable ids before code is handed to the minifier, then back again.
|
|
314
|
+
* Uses the node module identity of the target module. Will emit an error if it encounters multiple versions of the same package in the same compilation.
|
|
315
|
+
* @public
|
|
316
|
+
*/
|
|
317
|
+
export declare class PortableMinifierModuleIdsPlugin implements Plugin {
|
|
318
|
+
private readonly _minifierHooks;
|
|
319
|
+
constructor(minifierHooks: IModuleMinifierPluginHooks);
|
|
320
|
+
apply(compiler: Compiler): void;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Rehydrates an asset with minified modules.
|
|
325
|
+
* @param asset - The asset
|
|
326
|
+
* @param moduleMap - The minified modules
|
|
327
|
+
* @param banner - A banner to inject for license information
|
|
328
|
+
* @public
|
|
329
|
+
*/
|
|
330
|
+
export declare function rehydrateAsset(asset: IAssetInfo, moduleMap: IModuleMap, banner: string): Source;
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Stage # to use when this should be the last tap in the hook
|
|
334
|
+
* @public
|
|
335
|
+
*/
|
|
336
|
+
export declare const STAGE_AFTER: 100;
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Stage # to use when this should be the first tap in the hook
|
|
340
|
+
* @public
|
|
341
|
+
*/
|
|
342
|
+
export declare const STAGE_BEFORE: -100;
|
|
343
|
+
|
|
344
|
+
export { WorkerPoolMinifier }
|
|
345
|
+
|
|
346
|
+
export { }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Compiler, Plugin } from 'webpack';
|
|
2
|
+
import { IModuleMinifierPluginHooks } from './ModuleMinifierPlugin.types';
|
|
3
|
+
/**
|
|
4
|
+
* Plugin that replaces `Promise.all([__webpack_require__.e(1), __webpack_require__.e(12)]).then(__webpack_require__.t.bind(123,7))`
|
|
5
|
+
* with more concise expressions like `__webpack_require__.ee([1,12],123,7)`, etc.
|
|
6
|
+
*
|
|
7
|
+
* Also ensures that the code seen by the minifier does not contain chunk ids, and is therefore portable across chunks/compilations.
|
|
8
|
+
*/
|
|
9
|
+
export declare class AsyncImportCompressionPlugin implements Plugin {
|
|
10
|
+
private readonly _minifierHooks;
|
|
11
|
+
constructor(minifierHooks: IModuleMinifierPluginHooks);
|
|
12
|
+
apply(compiler: Compiler): void;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=AsyncImportCompressionPlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AsyncImportCompressionPlugin.d.ts","sourceRoot":"","sources":["../src/AsyncImportCompressionPlugin.ts"],"names":[],"mappings":"AAGA,OAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAOpD,OAAO,EAEL,0BAA0B,EAE3B,MAAM,8BAA8B,CAAC;AA2EtC;;;;;GAKG;AACH,qBAAa,4BAA6B,YAAW,MAAM;IACzD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6B;gBAEzC,aAAa,EAAE,0BAA0B;IAIrD,KAAK,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;CAoLvC"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
|
|
3
|
+
// See LICENSE in the project root for license information.
|
|
4
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
|
+
};
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.AsyncImportCompressionPlugin = void 0;
|
|
9
|
+
const webpack_1 = __importDefault(require("webpack"));
|
|
10
|
+
const { Template } = webpack_1.default;
|
|
11
|
+
const Constants_1 = require("./Constants");
|
|
12
|
+
const PLUGIN_NAME = 'AsyncImportCompressionPlugin';
|
|
13
|
+
const TAP_AFTER = {
|
|
14
|
+
name: PLUGIN_NAME,
|
|
15
|
+
stage: Constants_1.STAGE_AFTER
|
|
16
|
+
};
|
|
17
|
+
const ASYNC_IMPORT_PREFIX = '__IMPORT_ASYNC';
|
|
18
|
+
const ASYNC_IMPORT_REGEX = /__IMPORT_ASYNC[^\)]+/g;
|
|
19
|
+
function getImportDependency(compilation) {
|
|
20
|
+
for (const key of compilation.dependencyTemplates.keys()) {
|
|
21
|
+
if (key.name === 'ImportDependency') {
|
|
22
|
+
return key;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
throw new Error(`Could not find ImportDependency!`);
|
|
26
|
+
}
|
|
27
|
+
function getImportTypeExpression(module, originModule) {
|
|
28
|
+
var _a, _b;
|
|
29
|
+
const exportsType = (_a = module.buildMeta) === null || _a === void 0 ? void 0 : _a.exportsType;
|
|
30
|
+
const strict = (_b = originModule.buildMeta) === null || _b === void 0 ? void 0 : _b.strictHarmonyModule;
|
|
31
|
+
// Logic translated from:
|
|
32
|
+
// https://github.com/webpack/webpack/blob/3956274f1eada621e105208dcab4608883cdfdb2/lib/RuntimeTemplate.js#L110-L122
|
|
33
|
+
if (exportsType === 'namespace') {
|
|
34
|
+
// Use the raw module directly
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
else if (exportsType === 'named') {
|
|
38
|
+
// Create a new namespace object and forward all exports
|
|
39
|
+
return ',3';
|
|
40
|
+
}
|
|
41
|
+
else if (strict) {
|
|
42
|
+
// Synthetic default export
|
|
43
|
+
return ',1';
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// If modules is marked __esModule, return raw module, otherwise create a new namespace object and forward all exports
|
|
47
|
+
return ',7';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function needChunkOnDemandLoadingCode(chunk) {
|
|
51
|
+
for (const chunkGroup of chunk.groupsIterable) {
|
|
52
|
+
if (chunkGroup.getNumberOfChildren() > 0) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Plugin that replaces `Promise.all([__webpack_require__.e(1), __webpack_require__.e(12)]).then(__webpack_require__.t.bind(123,7))`
|
|
60
|
+
* with more concise expressions like `__webpack_require__.ee([1,12],123,7)`, etc.
|
|
61
|
+
*
|
|
62
|
+
* Also ensures that the code seen by the minifier does not contain chunk ids, and is therefore portable across chunks/compilations.
|
|
63
|
+
*/
|
|
64
|
+
class AsyncImportCompressionPlugin {
|
|
65
|
+
constructor(minifierHooks) {
|
|
66
|
+
this._minifierHooks = minifierHooks;
|
|
67
|
+
}
|
|
68
|
+
apply(compiler) {
|
|
69
|
+
const asyncImportMap = new Map();
|
|
70
|
+
const asyncImportGroups = new Map();
|
|
71
|
+
let rankedImportGroups;
|
|
72
|
+
this._minifierHooks.postProcessCodeFragment.tap({
|
|
73
|
+
name: PLUGIN_NAME,
|
|
74
|
+
stage: -1
|
|
75
|
+
}, (source, context) => {
|
|
76
|
+
const code = source.original().source();
|
|
77
|
+
let localImports;
|
|
78
|
+
ASYNC_IMPORT_REGEX.lastIndex = -1;
|
|
79
|
+
// RegExp.exec uses null or an array as the return type, explicitly
|
|
80
|
+
let match = null;
|
|
81
|
+
while ((match = ASYNC_IMPORT_REGEX.exec(code))) {
|
|
82
|
+
const token = match[0];
|
|
83
|
+
if (!localImports) {
|
|
84
|
+
if (!context.module) {
|
|
85
|
+
context.compilation.errors.push(new Error(`Unexpected async import ${token} in non-module context ${context.loggingName}`));
|
|
86
|
+
return source;
|
|
87
|
+
}
|
|
88
|
+
localImports = asyncImportMap.get(context.module);
|
|
89
|
+
if (!localImports) {
|
|
90
|
+
context.compilation.errors.push(new Error(`Unexpected async import ${token} in module ${context.loggingName}`));
|
|
91
|
+
return source;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const localImport = localImports.get(token);
|
|
95
|
+
if (!localImport) {
|
|
96
|
+
context.compilation.errors.push(new Error(`Missing metadata for ${token} in module ${context.loggingName}`));
|
|
97
|
+
return source;
|
|
98
|
+
}
|
|
99
|
+
const { meta, module } = localImport;
|
|
100
|
+
const chunkExpression = meta.index < 0 ? JSON.stringify(meta.chunkIds) : `${meta.index}`;
|
|
101
|
+
const mapped = this._minifierHooks.finalModuleId.call(module.id, context.compilation);
|
|
102
|
+
const idExpr = mapped === undefined ? module.id : mapped;
|
|
103
|
+
// Replace with a reference or array of ideas, the target module id, and the type of import
|
|
104
|
+
source.replace(match.index, ASYNC_IMPORT_REGEX.lastIndex - 1, `${chunkExpression},${JSON.stringify(idExpr)}${getImportTypeExpression(module, context.module)}`);
|
|
105
|
+
}
|
|
106
|
+
return source;
|
|
107
|
+
});
|
|
108
|
+
compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
|
|
109
|
+
asyncImportMap.clear();
|
|
110
|
+
asyncImportGroups.clear();
|
|
111
|
+
compilation.hooks.beforeChunkAssets.tap(TAP_AFTER, () => {
|
|
112
|
+
const ImportDependency = getImportDependency(compilation);
|
|
113
|
+
for (const module of compilation.modules) {
|
|
114
|
+
const toProcess = module.modules || [module];
|
|
115
|
+
for (const child of toProcess) {
|
|
116
|
+
child.hasDependencies((dep) => {
|
|
117
|
+
if (dep instanceof ImportDependency) {
|
|
118
|
+
const { module: targetModule } = dep;
|
|
119
|
+
let localAsyncImports = asyncImportMap.get(module);
|
|
120
|
+
if (!localAsyncImports) {
|
|
121
|
+
asyncImportMap.set(module, (localAsyncImports = new Map()));
|
|
122
|
+
}
|
|
123
|
+
const chunkGroup = dep.block.chunkGroup;
|
|
124
|
+
const chunkIds = chunkGroup
|
|
125
|
+
? chunkGroup.chunks.map((chunk) => chunk.id).sort()
|
|
126
|
+
: [];
|
|
127
|
+
const idString = chunkIds.join(';');
|
|
128
|
+
let meta = asyncImportGroups.get(idString);
|
|
129
|
+
if (!meta) {
|
|
130
|
+
asyncImportGroups.set(idString, (meta = {
|
|
131
|
+
chunkCount: chunkIds.length,
|
|
132
|
+
chunkIds: chunkIds,
|
|
133
|
+
count: 0,
|
|
134
|
+
index: -1
|
|
135
|
+
}));
|
|
136
|
+
}
|
|
137
|
+
meta.count++;
|
|
138
|
+
const stringKey = `${targetModule.id}`.replace(/[^A-Za-z0-9_$]/g, '_');
|
|
139
|
+
const key = `${ASYNC_IMPORT_PREFIX}${stringKey}`;
|
|
140
|
+
localAsyncImports.set(key, {
|
|
141
|
+
meta,
|
|
142
|
+
module: targetModule
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const rankedImports = [...asyncImportGroups]
|
|
149
|
+
.filter((x) => x[1].count > 1)
|
|
150
|
+
.sort((x, y) => {
|
|
151
|
+
let diff = y[1].count - x[1].count;
|
|
152
|
+
if (!diff) {
|
|
153
|
+
diff = y[1].chunkCount - x[1].chunkCount;
|
|
154
|
+
}
|
|
155
|
+
if (!diff) {
|
|
156
|
+
diff = x[0] > y[0] ? 1 : x[0] < y[0] ? -1 : 0;
|
|
157
|
+
}
|
|
158
|
+
return diff;
|
|
159
|
+
});
|
|
160
|
+
for (let i = 0, len = rankedImports.length; i < len; i++) {
|
|
161
|
+
rankedImports[i][1].index = i;
|
|
162
|
+
// console.log(rankedImports[i]);
|
|
163
|
+
}
|
|
164
|
+
rankedImportGroups = rankedImports.map((x) => x[1]);
|
|
165
|
+
// Have to do this after the official plugin in order to override
|
|
166
|
+
compilation.dependencyTemplates.set(ImportDependency, {
|
|
167
|
+
apply(dep, source) {
|
|
168
|
+
const stringKey = `${dep.module.id}`.replace(/[^A-Za-z0-9_$]/g, '_');
|
|
169
|
+
const key = `${ASYNC_IMPORT_PREFIX}${stringKey}`;
|
|
170
|
+
const content = `__webpack_require__.ee(${key})`;
|
|
171
|
+
source.replace(dep.block.range[0], dep.block.range[1] - 1, content);
|
|
172
|
+
}
|
|
173
|
+
// Typings in webpack are incorrect. This is a DependencyTemplate object
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
compilation.mainTemplate.hooks.requireExtensions.tap(PLUGIN_NAME, (source, chunk) => {
|
|
177
|
+
if (!needChunkOnDemandLoadingCode(chunk)) {
|
|
178
|
+
return source;
|
|
179
|
+
}
|
|
180
|
+
const { requireFn } = compilation.mainTemplate;
|
|
181
|
+
return Template.asString([
|
|
182
|
+
`var asyncImportChunkGroups = [`,
|
|
183
|
+
rankedImportGroups
|
|
184
|
+
? rankedImportGroups.map((x) => Template.indent(JSON.stringify(x.chunkIds))).join(',\n')
|
|
185
|
+
: '',
|
|
186
|
+
`];`,
|
|
187
|
+
`${requireFn}.ee = function (groupOrId, moduleId, importType) {`,
|
|
188
|
+
Template.indent([
|
|
189
|
+
`return Promise.all((Array.isArray(groupOrId) ? groupOrId : asyncImportChunkGroups[groupOrId]).map(function (x) { return ${requireFn}.e(x); }))`,
|
|
190
|
+
`.then(importType ? ${requireFn}.t.bind(0,moduleId,importType) : ${requireFn}.bind(0,moduleId));`
|
|
191
|
+
]),
|
|
192
|
+
`};`,
|
|
193
|
+
source
|
|
194
|
+
]);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
exports.AsyncImportCompressionPlugin = AsyncImportCompressionPlugin;
|
|
200
|
+
//# sourceMappingURL=AsyncImportCompressionPlugin.js.map
|