-
Notifications
You must be signed in to change notification settings - Fork 26.1k
/
pages-manifest-plugin.ts
138 lines (123 loc) · 3.71 KB
/
pages-manifest-plugin.ts
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import { webpack, sources } from 'next/dist/compiled/webpack/webpack'
import {
PAGES_MANIFEST,
VIEW_PATHS_MANIFEST,
} from '../../../shared/lib/constants'
import getRouteFromEntrypoint from '../../../server/get-route-from-entrypoint'
import { normalizePathSep } from '../../../shared/lib/page-path/normalize-path-sep'
export type PagesManifest = { [page: string]: string }
let edgeServerPages = {}
let nodeServerPages = {}
let edgeServerRootPaths = {}
let nodeServerRootPaths = {}
// This plugin creates a pages-manifest.json from page entrypoints.
// This is used for mapping paths like `/` to `.next/server/static/<buildid>/pages/index.js` when doing SSR
// It's also used by next export to provide defaultPathMap
export default class PagesManifestPlugin implements webpack.Plugin {
serverless: boolean
dev: boolean
isEdgeRuntime: boolean
rootEnabled: boolean
constructor({
serverless,
dev,
isEdgeRuntime,
rootEnabled,
}: {
serverless: boolean
dev: boolean
isEdgeRuntime: boolean
rootEnabled: boolean
}) {
this.serverless = serverless
this.dev = dev
this.isEdgeRuntime = isEdgeRuntime
this.rootEnabled = rootEnabled
}
createAssets(compilation: any, assets: any) {
const entrypoints = compilation.entrypoints
const pages: PagesManifest = {}
const rootPaths: PagesManifest = {}
for (const entrypoint of entrypoints.values()) {
const pagePath = getRouteFromEntrypoint(entrypoint.name, this.rootEnabled)
if (!pagePath) {
continue
}
const files = entrypoint
.getFiles()
.filter(
(file: string) =>
!file.includes('webpack-runtime') &&
!file.includes('webpack-api-runtime') &&
file.endsWith('.js')
)
// Skip _app.server entry which is empty
if (!files.length) {
continue
}
// Write filename, replace any backslashes in path (on windows) with forwardslashes for cross-platform consistency.
let file = files[files.length - 1]
if (!this.dev) {
if (!this.isEdgeRuntime) {
file = file.slice(3)
}
}
file = normalizePathSep(file)
if (entrypoint.name.startsWith('views/')) {
rootPaths[pagePath] = file
} else {
pages[pagePath] = file
}
}
// This plugin is used by both the Node server and Edge server compilers,
// we need to merge both pages to generate the full manifest.
if (this.isEdgeRuntime) {
edgeServerPages = pages
edgeServerRootPaths = rootPaths
} else {
nodeServerPages = pages
nodeServerRootPaths = rootPaths
}
assets[
`${!this.dev && !this.isEdgeRuntime ? '../' : ''}` + PAGES_MANIFEST
] = new sources.RawSource(
JSON.stringify(
{
...edgeServerPages,
...nodeServerPages,
},
null,
2
)
)
if (this.rootEnabled) {
assets[
`${!this.dev && !this.isEdgeRuntime ? '../' : ''}` + VIEW_PATHS_MANIFEST
] = new sources.RawSource(
JSON.stringify(
{
...edgeServerRootPaths,
...nodeServerRootPaths,
},
null,
2
)
)
}
}
apply(compiler: webpack.Compiler): void {
compiler.hooks.make.tap('NextJsPagesManifest', (compilation) => {
// @ts-ignore TODO: Remove ignore when webpack 5 is stable
compilation.hooks.processAssets.tap(
{
name: 'NextJsPagesManifest',
// @ts-ignore TODO: Remove ignore when webpack 5 is stable
stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS,
},
(assets: any) => {
this.createAssets(compilation, assets)
}
)
})
}
}