-
Notifications
You must be signed in to change notification settings - Fork 0
/
client-build-manifest-plugin.js
104 lines (87 loc) · 3.47 KB
/
client-build-manifest-plugin.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
const { RawSource } = require("webpack-sources");
const {
ROUTE_NAME_REGEX,
IS_BUNDLED_PAGE_REGEX,
CLIENT_STATIC_FILES_RUNTIME_MAIN
} = require("next-server/constants");
const CLIENT_BUILD_MANIFEST = "client-build-manifest.json";
// This plugin creates a build-manifest.json for all assets that are being output
// It has a mapping of "entry" filename to real filename. Because the real filename can be hashed in production
module.exports = class ClientBuildManifestPlugin {
apply(compiler) {
compiler.hooks.emit.tapAsync(
"NextJsBuildManifest",
(compilation, callback) => {
const { chunks } = compilation;
const assetMap = {
devFiles: [],
clientPageDeps: {},
clientPages: {}
};
const mainJsChunk = chunks.find(
c => c.name === CLIENT_STATIC_FILES_RUNTIME_MAIN
);
const mainJsFiles =
mainJsChunk && mainJsChunk.files.length > 0
? mainJsChunk.files.filter(file => /\.js$/.test(file))
: [];
for (const filePath of Object.keys(compilation.assets)) {
const path = filePath.replace(/\\/g, "/");
if (/^static\/development\/dll\//.test(path)) {
assetMap.devFiles.push(path);
}
}
// compilation.entrypoints is a Map object, so iterating over it 0 is the key and 1 is the value
for (const [, entrypoint] of compilation.entrypoints.entries()) {
const result = ROUTE_NAME_REGEX.exec(entrypoint.name);
if (!result || !result[1]) {
continue;
}
const pagePath = `/${result[1].replace(/\\/g, "/")}`;
const filesForEntry = [];
for (const chunk of entrypoint.chunks) {
// If there's no name or no files
if (!chunk.name || !chunk.files) {
continue;
}
for (const file of chunk.files) {
if (/\.map$/.test(file) || /\.hot-update\.js$/.test(file)) {
continue;
}
// Only `.js` and `.css` files are added for now. In the future we can also handle other file types.
if (!/\.js$/.test(file) && !/\.css$/.test(file)) {
continue;
}
// The page bundles are manually added to _document.js as they need extra properties
if (IS_BUNDLED_PAGE_REGEX.exec(file)) {
assetMap.clientPages[pagePath] = file.replace(/\\/g, "/");
continue;
}
filesForEntry.push(file.replace(/\\/g, "/"));
}
}
assetMap.clientPageDeps[pagePath] = [
...filesForEntry,
...mainJsFiles
];
}
if (typeof assetMap.clientPageDeps["/index"] !== "undefined") {
assetMap.clientPageDeps["/"] = assetMap.clientPageDeps["/index"];
}
if (typeof assetMap.clientPages["/index"] !== "undefined") {
assetMap.clientPages["/"] = assetMap.clientPages["/index"];
}
assetMap.clientPageDeps = Object.keys(assetMap.clientPageDeps)
.sort()
.reduce((a, c) => ((a[c] = assetMap.clientPageDeps[c]), a), {});
assetMap.clientPages = Object.keys(assetMap.clientPages)
.sort()
.reduce((a, c) => ((a[c] = assetMap.clientPages[c]), a), {});
compilation.assets[CLIENT_BUILD_MANIFEST] = new RawSource(
JSON.stringify(assetMap, null, 2)
);
callback();
}
);
}
};