2021-11-25 10:46:00 +01:00
|
|
|
import type { ComponentType } from 'react'
|
|
|
|
import type { RouteLoader } from './route-loader'
|
feat(next): Support has match and locale option on middleware config (#39257)
## Feature
As the title, support `has` match, `local` that works the same with the `rewrites` and `redirects` of next.config.js on middleware config. With this PR, you can write the config like the following:
```js
export const config = {
matcher: [
"/foo",
{ source: "/bar" },
{
source: "/baz",
has: [
{
type: 'header',
key: 'x-my-header',
value: 'my-value',
}
]
},
{
source: "/en/asdf",
locale: false,
},
]
}
```
Also, fixes https://github.com/vercel/next.js/issues/39428
related https://github.com/vercel/edge-functions/issues/178, https://github.com/vercel/edge-functions/issues/179
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`
Co-authored-by: JJ Kasper <jj@jjsweb.site>
2022-08-31 18:23:30 +02:00
|
|
|
import type { MiddlewareMatcher } from '../build/analysis/get-page-static-info'
|
2022-05-30 20:19:37 +02:00
|
|
|
import { addBasePath } from './add-base-path'
|
|
|
|
import { interpolateAs } from '../shared/lib/router/router'
|
2021-06-30 11:43:31 +02:00
|
|
|
import getAssetPathFromRoute from '../shared/lib/router/utils/get-asset-path-from-route'
|
2022-05-30 20:19:37 +02:00
|
|
|
import { addLocale } from './add-locale'
|
2021-06-30 11:43:31 +02:00
|
|
|
import { isDynamicRoute } from '../shared/lib/router/utils/is-dynamic'
|
|
|
|
import { parseRelativeUrl } from '../shared/lib/router/utils/parse-relative-url'
|
2022-05-27 20:29:04 +02:00
|
|
|
import { removeTrailingSlash } from '../shared/lib/router/utils/remove-trailing-slash'
|
2022-06-14 18:50:05 +02:00
|
|
|
import { createRouteLoader, getClientBuildManifest } from './route-loader'
|
2019-12-24 16:07:44 +01:00
|
|
|
|
2021-11-25 10:46:00 +01:00
|
|
|
declare global {
|
|
|
|
interface Window {
|
feat(next): Support has match and locale option on middleware config (#39257)
## Feature
As the title, support `has` match, `local` that works the same with the `rewrites` and `redirects` of next.config.js on middleware config. With this PR, you can write the config like the following:
```js
export const config = {
matcher: [
"/foo",
{ source: "/bar" },
{
source: "/baz",
has: [
{
type: 'header',
key: 'x-my-header',
value: 'my-value',
}
]
},
{
source: "/en/asdf",
locale: false,
},
]
}
```
Also, fixes https://github.com/vercel/next.js/issues/39428
related https://github.com/vercel/edge-functions/issues/178, https://github.com/vercel/edge-functions/issues/179
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`
Co-authored-by: JJ Kasper <jj@jjsweb.site>
2022-08-31 18:23:30 +02:00
|
|
|
__DEV_MIDDLEWARE_MATCHERS?: MiddlewareMatcher[]
|
2021-11-25 10:46:00 +01:00
|
|
|
__DEV_PAGES_MANIFEST?: { pages: string[] }
|
|
|
|
__SSG_MANIFEST_CB?: () => void
|
|
|
|
__SSG_MANIFEST?: Set<string>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-26 18:34:53 +02:00
|
|
|
export type StyleSheetTuple = { href: string; text: string }
|
2020-08-17 23:20:05 +02:00
|
|
|
export type GoodPageCache = {
|
|
|
|
page: ComponentType
|
|
|
|
mod: any
|
2020-08-26 18:34:53 +02:00
|
|
|
styleSheets: StyleSheetTuple[]
|
2020-08-17 23:20:05 +02:00
|
|
|
}
|
2020-08-12 22:42:05 +02:00
|
|
|
|
2017-04-03 20:10:24 +02:00
|
|
|
export default class PageLoader {
|
2020-08-12 22:42:05 +02:00
|
|
|
private buildId: string
|
|
|
|
private assetPrefix: string
|
2021-11-25 10:46:00 +01:00
|
|
|
private promisedSsgManifest: Promise<Set<string>>
|
|
|
|
private promisedDevPagesManifest?: Promise<string[]>
|
feat(next): Support has match and locale option on middleware config (#39257)
## Feature
As the title, support `has` match, `local` that works the same with the `rewrites` and `redirects` of next.config.js on middleware config. With this PR, you can write the config like the following:
```js
export const config = {
matcher: [
"/foo",
{ source: "/bar" },
{
source: "/baz",
has: [
{
type: 'header',
key: 'x-my-header',
value: 'my-value',
}
]
},
{
source: "/en/asdf",
locale: false,
},
]
}
```
Also, fixes https://github.com/vercel/next.js/issues/39428
related https://github.com/vercel/edge-functions/issues/178, https://github.com/vercel/edge-functions/issues/179
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`
Co-authored-by: JJ Kasper <jj@jjsweb.site>
2022-08-31 18:23:30 +02:00
|
|
|
private promisedMiddlewareMatchers?: Promise<MiddlewareMatcher[]>
|
2020-11-11 19:13:16 +01:00
|
|
|
|
|
|
|
public routeLoader: RouteLoader
|
2020-08-12 22:42:05 +02:00
|
|
|
|
2020-11-11 19:13:16 +01:00
|
|
|
constructor(buildId: string, assetPrefix: string) {
|
|
|
|
this.routeLoader = createRouteLoader(assetPrefix)
|
2020-08-17 23:20:05 +02:00
|
|
|
|
2017-04-03 20:10:24 +02:00
|
|
|
this.buildId = buildId
|
2017-04-18 06:18:43 +02:00
|
|
|
this.assetPrefix = assetPrefix
|
|
|
|
|
2020-05-18 21:24:37 +02:00
|
|
|
this.promisedSsgManifest = new Promise((resolve) => {
|
2021-11-25 10:46:00 +01:00
|
|
|
if (window.__SSG_MANIFEST) {
|
|
|
|
resolve(window.__SSG_MANIFEST)
|
2020-03-02 18:14:40 +01:00
|
|
|
} else {
|
2021-11-25 10:46:00 +01:00
|
|
|
window.__SSG_MANIFEST_CB = () => {
|
|
|
|
resolve(window.__SSG_MANIFEST!)
|
2020-03-02 18:14:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2019-08-08 19:14:33 +02:00
|
|
|
}
|
|
|
|
|
2020-08-13 14:39:36 +02:00
|
|
|
getPageList() {
|
|
|
|
if (process.env.NODE_ENV === 'production') {
|
2020-11-11 19:13:16 +01:00
|
|
|
return getClientBuildManifest().then((manifest) => manifest.sortedPages)
|
2020-08-13 14:39:36 +02:00
|
|
|
} else {
|
2021-11-25 10:46:00 +01:00
|
|
|
if (window.__DEV_PAGES_MANIFEST) {
|
|
|
|
return window.__DEV_PAGES_MANIFEST.pages
|
2020-08-13 14:39:36 +02:00
|
|
|
} else {
|
2022-08-07 21:36:03 +02:00
|
|
|
this.promisedDevPagesManifest ||= fetch(
|
|
|
|
`${this.assetPrefix}/_next/static/development/_devPagesManifest.json`
|
|
|
|
)
|
|
|
|
.then((res) => res.json())
|
|
|
|
.then((manifest: { pages: string[] }) => {
|
|
|
|
window.__DEV_PAGES_MANIFEST = manifest
|
|
|
|
return manifest.pages
|
|
|
|
})
|
|
|
|
.catch((err) => {
|
|
|
|
console.log(`Failed to fetch devPagesManifest:`, err)
|
|
|
|
throw new Error(
|
|
|
|
`Failed to fetch _devPagesManifest.json. Is something blocking that network request?\n` +
|
|
|
|
'Read more: https://nextjs.org/docs/messages/failed-to-fetch-devpagesmanifest'
|
|
|
|
)
|
|
|
|
})
|
|
|
|
return this.promisedDevPagesManifest
|
2020-08-13 14:39:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-01 15:23:24 +02:00
|
|
|
getMiddleware() {
|
2021-10-22 08:40:57 +02:00
|
|
|
if (process.env.NODE_ENV === 'production') {
|
feat(next): Support has match and locale option on middleware config (#39257)
## Feature
As the title, support `has` match, `local` that works the same with the `rewrites` and `redirects` of next.config.js on middleware config. With this PR, you can write the config like the following:
```js
export const config = {
matcher: [
"/foo",
{ source: "/bar" },
{
source: "/baz",
has: [
{
type: 'header',
key: 'x-my-header',
value: 'my-value',
}
]
},
{
source: "/en/asdf",
locale: false,
},
]
}
```
Also, fixes https://github.com/vercel/next.js/issues/39428
related https://github.com/vercel/edge-functions/issues/178, https://github.com/vercel/edge-functions/issues/179
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`
Co-authored-by: JJ Kasper <jj@jjsweb.site>
2022-08-31 18:23:30 +02:00
|
|
|
const middlewareMatchers = process.env.__NEXT_MIDDLEWARE_MATCHERS
|
|
|
|
window.__MIDDLEWARE_MATCHERS = middlewareMatchers
|
|
|
|
? (middlewareMatchers as any as MiddlewareMatcher[])
|
2022-08-01 15:23:24 +02:00
|
|
|
: undefined
|
feat(next): Support has match and locale option on middleware config (#39257)
## Feature
As the title, support `has` match, `local` that works the same with the `rewrites` and `redirects` of next.config.js on middleware config. With this PR, you can write the config like the following:
```js
export const config = {
matcher: [
"/foo",
{ source: "/bar" },
{
source: "/baz",
has: [
{
type: 'header',
key: 'x-my-header',
value: 'my-value',
}
]
},
{
source: "/en/asdf",
locale: false,
},
]
}
```
Also, fixes https://github.com/vercel/next.js/issues/39428
related https://github.com/vercel/edge-functions/issues/178, https://github.com/vercel/edge-functions/issues/179
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`
Co-authored-by: JJ Kasper <jj@jjsweb.site>
2022-08-31 18:23:30 +02:00
|
|
|
return window.__MIDDLEWARE_MATCHERS
|
2021-10-22 08:40:57 +02:00
|
|
|
} else {
|
feat(next): Support has match and locale option on middleware config (#39257)
## Feature
As the title, support `has` match, `local` that works the same with the `rewrites` and `redirects` of next.config.js on middleware config. With this PR, you can write the config like the following:
```js
export const config = {
matcher: [
"/foo",
{ source: "/bar" },
{
source: "/baz",
has: [
{
type: 'header',
key: 'x-my-header',
value: 'my-value',
}
]
},
{
source: "/en/asdf",
locale: false,
},
]
}
```
Also, fixes https://github.com/vercel/next.js/issues/39428
related https://github.com/vercel/edge-functions/issues/178, https://github.com/vercel/edge-functions/issues/179
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`
Co-authored-by: JJ Kasper <jj@jjsweb.site>
2022-08-31 18:23:30 +02:00
|
|
|
if (window.__DEV_MIDDLEWARE_MATCHERS) {
|
|
|
|
return window.__DEV_MIDDLEWARE_MATCHERS
|
2021-10-20 19:52:11 +02:00
|
|
|
} else {
|
feat(next): Support has match and locale option on middleware config (#39257)
## Feature
As the title, support `has` match, `local` that works the same with the `rewrites` and `redirects` of next.config.js on middleware config. With this PR, you can write the config like the following:
```js
export const config = {
matcher: [
"/foo",
{ source: "/bar" },
{
source: "/baz",
has: [
{
type: 'header',
key: 'x-my-header',
value: 'my-value',
}
]
},
{
source: "/en/asdf",
locale: false,
},
]
}
```
Also, fixes https://github.com/vercel/next.js/issues/39428
related https://github.com/vercel/edge-functions/issues/178, https://github.com/vercel/edge-functions/issues/179
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`
Co-authored-by: JJ Kasper <jj@jjsweb.site>
2022-08-31 18:23:30 +02:00
|
|
|
if (!this.promisedMiddlewareMatchers) {
|
2021-11-25 10:46:00 +01:00
|
|
|
// TODO: Decide what should happen when fetching fails instead of asserting
|
|
|
|
// @ts-ignore
|
feat(next): Support has match and locale option on middleware config (#39257)
## Feature
As the title, support `has` match, `local` that works the same with the `rewrites` and `redirects` of next.config.js on middleware config. With this PR, you can write the config like the following:
```js
export const config = {
matcher: [
"/foo",
{ source: "/bar" },
{
source: "/baz",
has: [
{
type: 'header',
key: 'x-my-header',
value: 'my-value',
}
]
},
{
source: "/en/asdf",
locale: false,
},
]
}
```
Also, fixes https://github.com/vercel/next.js/issues/39428
related https://github.com/vercel/edge-functions/issues/178, https://github.com/vercel/edge-functions/issues/179
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`
Co-authored-by: JJ Kasper <jj@jjsweb.site>
2022-08-31 18:23:30 +02:00
|
|
|
this.promisedMiddlewareMatchers = fetch(
|
2021-10-22 08:40:57 +02:00
|
|
|
`${this.assetPrefix}/_next/static/${this.buildId}/_devMiddlewareManifest.json`
|
|
|
|
)
|
|
|
|
.then((res) => res.json())
|
feat(next): Support has match and locale option on middleware config (#39257)
## Feature
As the title, support `has` match, `local` that works the same with the `rewrites` and `redirects` of next.config.js on middleware config. With this PR, you can write the config like the following:
```js
export const config = {
matcher: [
"/foo",
{ source: "/bar" },
{
source: "/baz",
has: [
{
type: 'header',
key: 'x-my-header',
value: 'my-value',
}
]
},
{
source: "/en/asdf",
locale: false,
},
]
}
```
Also, fixes https://github.com/vercel/next.js/issues/39428
related https://github.com/vercel/edge-functions/issues/178, https://github.com/vercel/edge-functions/issues/179
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`
Co-authored-by: JJ Kasper <jj@jjsweb.site>
2022-08-31 18:23:30 +02:00
|
|
|
.then((matchers: MiddlewareMatcher[]) => {
|
|
|
|
window.__DEV_MIDDLEWARE_MATCHERS = matchers
|
|
|
|
return matchers
|
2021-10-22 08:40:57 +02:00
|
|
|
})
|
|
|
|
.catch((err) => {
|
|
|
|
console.log(`Failed to fetch _devMiddlewareManifest`, err)
|
|
|
|
})
|
2021-10-20 19:52:11 +02:00
|
|
|
}
|
2021-11-25 10:46:00 +01:00
|
|
|
// TODO Remove this assertion as this could be undefined
|
feat(next): Support has match and locale option on middleware config (#39257)
## Feature
As the title, support `has` match, `local` that works the same with the `rewrites` and `redirects` of next.config.js on middleware config. With this PR, you can write the config like the following:
```js
export const config = {
matcher: [
"/foo",
{ source: "/bar" },
{
source: "/baz",
has: [
{
type: 'header',
key: 'x-my-header',
value: 'my-value',
}
]
},
{
source: "/en/asdf",
locale: false,
},
]
}
```
Also, fixes https://github.com/vercel/next.js/issues/39428
related https://github.com/vercel/edge-functions/issues/178, https://github.com/vercel/edge-functions/issues/179
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`
Co-authored-by: JJ Kasper <jj@jjsweb.site>
2022-08-31 18:23:30 +02:00
|
|
|
return this.promisedMiddlewareMatchers!
|
2021-10-20 19:52:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-08 17:41:28 +02:00
|
|
|
getDataHref(params: {
|
2021-10-26 18:50:56 +02:00
|
|
|
asPath: string
|
2022-06-08 17:41:28 +02:00
|
|
|
href: string
|
2020-11-02 18:22:40 +01:00
|
|
|
locale?: string | false
|
2022-06-10 19:35:12 +02:00
|
|
|
skipInterpolation?: boolean
|
2021-10-26 18:50:56 +02:00
|
|
|
}): string {
|
2022-06-08 17:41:28 +02:00
|
|
|
const { asPath, href, locale } = params
|
2020-09-03 20:26:52 +02:00
|
|
|
const { pathname: hrefPathname, query, search } = parseRelativeUrl(href)
|
2020-07-13 18:08:12 +02:00
|
|
|
const { pathname: asPathname } = parseRelativeUrl(asPath)
|
2022-06-08 17:41:28 +02:00
|
|
|
const route = removeTrailingSlash(hrefPathname)
|
|
|
|
if (route[0] !== '/') {
|
|
|
|
throw new Error(`Route name should start with a "/", got "${route}"`)
|
|
|
|
}
|
2020-06-29 17:14:45 +02:00
|
|
|
|
2020-08-12 22:42:05 +02:00
|
|
|
const getHrefForSlug = (path: string) => {
|
2021-03-14 13:58:34 +01:00
|
|
|
const dataRoute = getAssetPathFromRoute(
|
2022-05-27 20:29:04 +02:00
|
|
|
removeTrailingSlash(addLocale(path, locale)),
|
2021-03-14 13:58:34 +01:00
|
|
|
'.json'
|
|
|
|
)
|
2020-07-29 18:51:51 +02:00
|
|
|
return addBasePath(
|
2022-06-08 17:41:28 +02:00
|
|
|
`/_next/data/${this.buildId}${dataRoute}${search}`,
|
2022-05-12 18:47:34 +02:00
|
|
|
true
|
2020-07-29 18:51:51 +02:00
|
|
|
)
|
2020-04-26 17:14:39 +02:00
|
|
|
}
|
2020-03-02 18:14:40 +01:00
|
|
|
|
2022-06-08 17:41:28 +02:00
|
|
|
return getHrefForSlug(
|
2022-06-10 19:35:12 +02:00
|
|
|
params.skipInterpolation
|
|
|
|
? asPathname
|
|
|
|
: isDynamicRoute(route)
|
2022-06-08 17:41:28 +02:00
|
|
|
? interpolateAs(hrefPathname, asPathname, query).result
|
|
|
|
: route
|
|
|
|
)
|
2020-03-02 18:14:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-26 16:19:48 +01:00
|
|
|
* @param {string} route - the route (file-system path)
|
2020-03-02 18:14:40 +01:00
|
|
|
*/
|
2021-03-26 16:19:48 +01:00
|
|
|
_isSsg(route: string): Promise<boolean> {
|
2021-11-25 10:46:00 +01:00
|
|
|
return this.promisedSsgManifest.then((manifest) => manifest.has(route))
|
2020-03-02 18:14:40 +01:00
|
|
|
}
|
|
|
|
|
2020-08-13 06:01:15 +02:00
|
|
|
loadPage(route: string): Promise<GoodPageCache> {
|
2020-11-11 19:13:16 +01:00
|
|
|
return this.routeLoader.loadRoute(route).then((res) => {
|
|
|
|
if ('component' in res) {
|
|
|
|
return {
|
|
|
|
page: res.component,
|
|
|
|
mod: res.exports,
|
|
|
|
styleSheets: res.styles.map((o) => ({
|
|
|
|
href: o.href,
|
|
|
|
text: o.content,
|
|
|
|
})),
|
2019-08-08 19:14:33 +02:00
|
|
|
}
|
2017-04-11 18:37:59 +02:00
|
|
|
}
|
2020-11-11 19:13:16 +01:00
|
|
|
throw res.error
|
2017-04-03 20:10:24 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-11-11 19:13:16 +01:00
|
|
|
prefetch(route: string): Promise<void> {
|
|
|
|
return this.routeLoader.prefetch(route)
|
2018-11-25 00:47:39 +01:00
|
|
|
}
|
2017-04-03 20:10:24 +02:00
|
|
|
}
|