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 asyncLib = require("neo-async");
|
---|
9 | const EntryDependency = require("./dependencies/EntryDependency");
|
---|
10 | const { someInIterable } = require("./util/IterableHelpers");
|
---|
11 | const { compareModulesById } = require("./util/comparators");
|
---|
12 | const { dirname, mkdirp } = require("./util/fs");
|
---|
13 |
|
---|
14 | /** @typedef {import("./ChunkGraph").ModuleId} ModuleId */
|
---|
15 | /** @typedef {import("./Compiler")} Compiler */
|
---|
16 | /** @typedef {import("./Compiler").IntermediateFileSystem} IntermediateFileSystem */
|
---|
17 | /** @typedef {import("./Module").BuildMeta} BuildMeta */
|
---|
18 |
|
---|
19 | /**
|
---|
20 | * @typedef {object} ManifestModuleData
|
---|
21 | * @property {string | number} id
|
---|
22 | * @property {BuildMeta} buildMeta
|
---|
23 | * @property {boolean | string[] | undefined} exports
|
---|
24 | */
|
---|
25 |
|
---|
26 | /**
|
---|
27 | * @typedef {object} LibManifestPluginOptions
|
---|
28 | * @property {string=} context Context of requests in the manifest file (defaults to the webpack context).
|
---|
29 | * @property {boolean=} entryOnly If true, only entry points will be exposed (default: true).
|
---|
30 | * @property {boolean=} format If true, manifest json file (output) will be formatted.
|
---|
31 | * @property {string=} name Name of the exposed dll function (external name, use value of 'output.library').
|
---|
32 | * @property {string} path Absolute path to the manifest json file (output).
|
---|
33 | * @property {string=} type Type of the dll bundle (external type, use value of 'output.libraryTarget').
|
---|
34 | */
|
---|
35 |
|
---|
36 | class LibManifestPlugin {
|
---|
37 | /**
|
---|
38 | * @param {LibManifestPluginOptions} options the options
|
---|
39 | */
|
---|
40 | constructor(options) {
|
---|
41 | this.options = options;
|
---|
42 | }
|
---|
43 |
|
---|
44 | /**
|
---|
45 | * Apply the plugin
|
---|
46 | * @param {Compiler} compiler the compiler instance
|
---|
47 | * @returns {void}
|
---|
48 | */
|
---|
49 | apply(compiler) {
|
---|
50 | compiler.hooks.emit.tapAsync(
|
---|
51 | {
|
---|
52 | name: "LibManifestPlugin",
|
---|
53 | stage: 110
|
---|
54 | },
|
---|
55 | (compilation, callback) => {
|
---|
56 | const moduleGraph = compilation.moduleGraph;
|
---|
57 | // store used paths to detect issue and output an error. #18200
|
---|
58 | const usedPaths = new Set();
|
---|
59 | asyncLib.each(
|
---|
60 | Array.from(compilation.chunks),
|
---|
61 | (chunk, callback) => {
|
---|
62 | if (!chunk.canBeInitial()) {
|
---|
63 | callback();
|
---|
64 | return;
|
---|
65 | }
|
---|
66 | const chunkGraph = compilation.chunkGraph;
|
---|
67 | const targetPath = compilation.getPath(this.options.path, {
|
---|
68 | chunk
|
---|
69 | });
|
---|
70 | if (usedPaths.has(targetPath)) {
|
---|
71 | callback(new Error("each chunk must have a unique path"));
|
---|
72 | return;
|
---|
73 | }
|
---|
74 | usedPaths.add(targetPath);
|
---|
75 | const name =
|
---|
76 | this.options.name &&
|
---|
77 | compilation.getPath(this.options.name, {
|
---|
78 | chunk,
|
---|
79 | contentHashType: "javascript"
|
---|
80 | });
|
---|
81 | const content = Object.create(null);
|
---|
82 | for (const module of chunkGraph.getOrderedChunkModulesIterable(
|
---|
83 | chunk,
|
---|
84 | compareModulesById(chunkGraph)
|
---|
85 | )) {
|
---|
86 | if (
|
---|
87 | this.options.entryOnly &&
|
---|
88 | !someInIterable(
|
---|
89 | moduleGraph.getIncomingConnections(module),
|
---|
90 | c => c.dependency instanceof EntryDependency
|
---|
91 | )
|
---|
92 | ) {
|
---|
93 | continue;
|
---|
94 | }
|
---|
95 | const ident = module.libIdent({
|
---|
96 | context:
|
---|
97 | this.options.context ||
|
---|
98 | /** @type {string} */ (compiler.options.context),
|
---|
99 | associatedObjectForCache: compiler.root
|
---|
100 | });
|
---|
101 | if (ident) {
|
---|
102 | const exportsInfo = moduleGraph.getExportsInfo(module);
|
---|
103 | const providedExports = exportsInfo.getProvidedExports();
|
---|
104 | /** @type {ManifestModuleData} */
|
---|
105 | const data = {
|
---|
106 | id: /** @type {ModuleId} */ (chunkGraph.getModuleId(module)),
|
---|
107 | buildMeta: /** @type {BuildMeta} */ (module.buildMeta),
|
---|
108 | exports: Array.isArray(providedExports)
|
---|
109 | ? providedExports
|
---|
110 | : undefined
|
---|
111 | };
|
---|
112 | content[ident] = data;
|
---|
113 | }
|
---|
114 | }
|
---|
115 | const manifest = {
|
---|
116 | name,
|
---|
117 | type: this.options.type,
|
---|
118 | content
|
---|
119 | };
|
---|
120 | // Apply formatting to content if format flag is true;
|
---|
121 | const manifestContent = this.options.format
|
---|
122 | ? JSON.stringify(manifest, null, 2)
|
---|
123 | : JSON.stringify(manifest);
|
---|
124 | const buffer = Buffer.from(manifestContent, "utf8");
|
---|
125 | const intermediateFileSystem =
|
---|
126 | /** @type {IntermediateFileSystem} */ (
|
---|
127 | compiler.intermediateFileSystem
|
---|
128 | );
|
---|
129 | mkdirp(
|
---|
130 | intermediateFileSystem,
|
---|
131 | dirname(intermediateFileSystem, targetPath),
|
---|
132 | err => {
|
---|
133 | if (err) return callback(err);
|
---|
134 | intermediateFileSystem.writeFile(targetPath, buffer, callback);
|
---|
135 | }
|
---|
136 | );
|
---|
137 | },
|
---|
138 | callback
|
---|
139 | );
|
---|
140 | }
|
---|
141 | );
|
---|
142 | }
|
---|
143 | }
|
---|
144 | module.exports = LibManifestPlugin;
|
---|