-
Notifications
You must be signed in to change notification settings - Fork 27.2k
/
index.ts
160 lines (139 loc) · 5.28 KB
/
index.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import type { webpack } from 'next/dist/compiled/webpack/webpack'
import { stringify } from 'querystring'
import { getModuleBuildInfo } from '../get-module-build-info'
import { PagesRouteModuleOptions } from '../../../../server/future/route-modules/pages/module'
import { RouteKind } from '../../../../server/future/route-kind'
import { normalizePagePath } from '../../../../shared/lib/page-path/normalize-page-path'
import { MiddlewareConfig } from '../../../analysis/get-page-static-info'
import { decodeFromBase64, encodeToBase64 } from '../utils'
import { isInstrumentationHookFile } from '../../../worker'
type RouteLoaderOptionsInput = {
page: string
pages: { [page: string]: string }
preferredRegion: string | string[] | undefined
absolutePagePath: string
middlewareConfig: MiddlewareConfig
}
/**
* The options for the route loader.
*/
type RouteLoaderOptions = {
/**
* The page name for this particular route.
*/
page: string
/**
* The preferred region for this route.
*/
preferredRegion: string | string[] | undefined
/**
* The absolute path to the userland page file.
*/
absolutePagePath: string
absoluteAppPath: string
absoluteDocumentPath: string
middlewareConfigBase64: string
}
/**
* Returns the loader entry for a given page.
*
* @param options the options to create the loader entry
* @returns the encoded loader entry
*/
export function getRouteLoaderEntry(options: RouteLoaderOptionsInput): string {
const query: RouteLoaderOptions = {
page: options.page,
preferredRegion: options.preferredRegion,
absolutePagePath: options.absolutePagePath,
// These are the path references to the internal components that may be
// overridden by userland components.
absoluteAppPath: options.pages['/_app'],
absoluteDocumentPath: options.pages['/_document'],
middlewareConfigBase64: encodeToBase64(options.middlewareConfig),
}
return `next-route-loader?${stringify(query)}!`
}
/**
* Handles the `next-route-loader` options.
* @returns the loader definition function
*/
const loader: webpack.LoaderDefinitionFunction<RouteLoaderOptions> =
function () {
const {
page,
preferredRegion,
absolutePagePath,
absoluteAppPath,
absoluteDocumentPath,
middlewareConfigBase64,
} = this.getOptions()
// Ensure we only run this loader for as a module.
if (!this._module) {
throw new Error('Invariant: expected this to reference a module')
}
const middlewareConfig: MiddlewareConfig = decodeFromBase64(
middlewareConfigBase64
)
// Attach build info to the module.
const buildInfo = getModuleBuildInfo(this._module)
buildInfo.route = {
page,
absolutePagePath,
preferredRegion,
middlewareConfig,
}
const options: Omit<PagesRouteModuleOptions, 'userland' | 'components'> = {
definition: {
kind: RouteKind.PAGES,
page: normalizePagePath(page),
pathname: page,
// The following aren't used in production.
bundlePath: '',
filename: '',
},
}
return `
// Next.js Route Loader
import RouteModule from "next/dist/server/future/route-modules/pages/module"
import { hoist } from "next/dist/build/webpack/loaders/next-route-loader/helpers"
// Import the app and document modules.
import * as moduleDocument from ${JSON.stringify(absoluteDocumentPath)}
import * as moduleApp from ${JSON.stringify(absoluteAppPath)}
// Import the userland code.
import * as userland from ${JSON.stringify(absolutePagePath)}
// Re-export the component (should be the default export).
export default hoist(userland, "default")
// Re-export methods.
export const getStaticProps = hoist(userland, "getStaticProps")
export const getStaticPaths = hoist(userland, "getStaticPaths")
export const getServerSideProps = hoist(userland, "getServerSideProps")
export const config = hoist(userland, "config")
export const reportWebVitals = hoist(userland, "reportWebVitals")
${
// When we're building the instrumentation page (only when the
// instrumentation file conflicts with a page also labeled
// /instrumentation) hoist the `register` method.
isInstrumentationHookFile(page)
? 'export const register = hoist(userland, "register")'
: ''
}
// Re-export legacy methods.
export const unstable_getStaticProps = hoist(userland, "unstable_getStaticProps")
export const unstable_getStaticPaths = hoist(userland, "unstable_getStaticPaths")
export const unstable_getStaticParams = hoist(userland, "unstable_getStaticParams")
export const unstable_getServerProps = hoist(userland, "unstable_getServerProps")
export const unstable_getServerSideProps = hoist(userland, "unstable_getServerSideProps")
// Create and export the route module that will be consumed.
const options = ${JSON.stringify(options)}
const routeModule = new RouteModule({
...options,
components: {
App: moduleApp.default,
Document: moduleDocument.default,
},
userland,
})
export { routeModule }
`
}
export default loader