<!--
Thanks for opening a PR! Your contribution is much appreciated.
In order to make sure your PR is handled as smoothly as possible we
request that you follow the checklist sections below.
Choose the right checklist for the change that you're making:
-->
This serves to add support for [Subresource
Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity)
hashes for scripts added from the new app directory. This also has
support for utilizing nonce values passed from request headers (expected
to be generated per request in middleware) in the bootstrapping scripts
via the `Content-Security-Policy` header as such:
```
Content-Security-Policy: script-src 'nonce-2726c7f26c'
```
Which results in the inline scripts having a new `nonce` attribute hash
added. These features combined support for setting an aggressive Content
Security Policy on scripts loaded.
## Bug
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
## Feature
- [ ] 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`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [x] Errors have helpful link attached, see `contributing.md`
## Documentation / Examples
- [x] Make sure the linting passes by running `pnpm lint`
- [x] The examples guidelines are followed from [our contributing
doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)
Co-authored-by: Steven <steven@ceriously.com>
Makes it possible to switch between edge/server runtime in dev without
breaking the server.
Fixes slack:
[1](https://vercel.slack.com/archives/CGU8HUTUH/p1659082535540549)
[2](https://vercel.slack.com/archives/C02CDC2ALJH/p1658978287244359)
[3](https://vercel.slack.com/archives/C03KAR5DCKC/p1656869427468779)
#### middleware-plugin.ts
`middlewareManifest` moved from module scope to local scope. Stale state
from earlier builds ended up in `middleware-manifest.json`. Functions
that changed from edge to server runtime stayed in the manifest as edge
functions.
#### on-demand-entry-handler.ts
When a server or edge entry is added we check if it has switched
runtime. If that's the case the old entry is removed.
#### Reproduce
Create edge API route and visit `/api/hello`
```js
// pages/api/hello.js
export const config = {
runtime: 'experimental-edge',
}
export default () => new Response('Hello')
```
Change it to a server api route and visit `/api/hello`, it will explode.
```js
// pages/api/hello.js
export default function (req, res) {
res.send('Hello')
}
```
#### Bug not fixed
One EDGE case is not fixed. It occurs if you switch between edge and
server runtime several times without changing the content of the file:
Edge runtime
```js
export const config = {
runtime: 'experimental-edge',
}
export default () => new Response('Hello')
```
Change it to a server runtime
```js
export default function (req, res) {
res.send('Hello')
}
```
Change back to edge runtime, the content of the file is the same as the
first time we compiled the edge runtime version.
```js
export const config = {
runtime: 'experimental-edge',
}
export default () => new Response('Hello')
```
The reason is that both the edge and server compiler emits to the same
file (/.next/server/pages/api/hello.js) which makes this check fail in
webpack:
https://github.com/webpack/webpack/blob/main/lib/Compiler.js#L849-L861
Possible solution is to use different output folders for edge and server
https://vercel.slack.com/archives/CGU8HUTUH/p1661163106667559
Co-authored-by: JJ Kasper <jj@jjsweb.site>
## 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>
Continuation of https://github.com/vercel/next.js/pull/38817 this adds handling to allow leveraging the `experimental-edge` runtime for `app`.
## Bug
- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
Co-authored-by: Jiachi Liu <inbox@huozhi.im>
Follow-up to the earlier enabling of classes/variables etc.
Bug
Related issues linked using fixes #number
Integration tests added
Errors have helpful link attached, see contributing.md
Feature
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
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
Documentation / Examples
Make sure the linting passes by running pnpm lint
The examples guidelines are followed from our contributing doc
Co-authored-by: Steven <steven@ceriously.com>
WIP.
## Bug
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
## Feature
- [ ] 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`
- [ ] 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`
## Documentation / Examples
- [ ] Make sure the linting passes by running `pnpm lint`
- [ ] The examples guidelines are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)
Co-authored-by: Shu Ding <3676859+shuding@users.noreply.github.com>
## What’s in there?
This PR brings more consistency in how errors and warnings are reported when running code in the Edge Runtime:
- Dynamic code evaluation (`eval()`, `new Function()`, `WebAssembly.instantiate()`, `WebAssembly.compile()`…)
- Usage of Node.js global APIs (`BroadcastChannel`, `Buffer`, `TextDecoderStream`, `setImmediate()`...)
- Usage of Node.js modules (`fs`, `path`, `child_process`…)
The new error messages should mention *Edge Runtime* instead of *Middleware*, so they are valid in both cases.
It also fixes a bug where the process polyfill would issue a warning for `process.cwd` (which is `undefined` but legit). Now, one has to invoke the function `process.cwd()` to trigger the error.
It finally fixes the react-dev-overlay, where links from middleware and Edge API route files could not be opened because of the `(middleware)/` prefix in their name.
About the later, please note that we can’t easily remove the prefix or change it for Edge API routes. It comes from the Webpack layer, which is the same for both. We may consider renaming it to *edge* instead in the future.
## How to test?
These changes are almost fully covered with tests:
```bash
pnpm testheadless --testPathPattern runtime-dynamic
pnpm testheadless --testPathPattern runtime-with-node
pnpm testheadless --testPathPattern runtime-module
pnpm testheadless --testPathPattern middleware-dev-errors
```
To try them out manually, you can write a middleware and Edge route files like these:
```jsx
// middleware.js
import { NextResponse } from 'next/server'
import { basename } from 'path'
export default async function middleware() {
eval('2+2')
setImmediate(() => {})
basename()
return NextResponse.next()
}
export const config = { matcher: '/' }
```
```jsx
// pages/api/route.js
import { basename } from 'path'
export default async function handle() {
eval('2+2')
setImmediate(() => {})
basename()
return Response.json({ ok: true })
}
export const config = { runtime: 'experimental-edge' }
```
The expected behaviours are:
- [x] dev, middleware/edge route is using a node.js module: error at runtime (logs + read-dev-overlay):
```bash
error - (middleware)/pages/api/route.js (1:0) @ Object.handle [as handler]
error - The edge runtime does not support Node.js 'path' module.
Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime
> 1 | import { basename } from "path";
2 | export default async function handle() {
```
- [x] build, middleware/edge route is using a node.js module: warning but succeeds
```bash
warn - Compiled with warnings
./middleware.js
A Node.js module is loaded ('path' at line 4) which is not supported in the Edge Runtime.
Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime
./pages/api/route.js
A Node.js module is loaded ('path' at line 1) which is not supported in the Edge Runtime.
Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime
```
- [x] production, middleware/edge route is using a node.js module: error at runtime (logs + 500 error)
```bash
Error: The edge runtime does not support Node.js 'path' module.
Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime
at <unknown> (file:///Users/damien/dev/next.js/packages/next/server/web/sandbox/context.ts:149)
```
- [x] dev, middleware/edge route is using a node.js global API: error at runtime (logs + read-dev-overlay):
```bash
error - (middleware)/pages/api/route.js (4:2) @ Object.handle [as handler]
error - A Node.js API is used (setImmediate) which is not supported in the Edge Runtime.
Learn more: https://nextjs.org/docs/api-reference/edge-runtime
2 |
3 | export default async function handle() {
> 4 | setImmediate(() => {})
| ^
```
- [x] build, middleware/edge route is using a node.js global API: warning but succeeds
```bash
warn - Compiled with warnings
./middleware.js
A Node.js API is used (setImmediate at line: 6) which is not supported in the Edge Runtime.
Learn more: https://nextjs.org/docs/api-reference/edge-runtime
./pages/api/route.js
A Node.js API is used (setImmediate at line: 3) which is not supported in the Edge Runtime.
Learn more: https://nextjs.org/docs/api-reference/edge-runtime
```
- [x] production, middleware/edge route is using a node.js module: error at runtime (logs + 500 error)
```bash
Error: A Node.js API is used (setImmediate) which is not supported in the Edge Runtime.
Learn more: https://nextjs.org/docs/api-reference/edge-runtime
at <unknown> (file:///Users/damien/dev/next.js/packages/next/server/web/sandbox/context.ts:330)
```
- [x] dev, middleware/edge route is loading dynamic code: warning at runtime (logs + read-dev-overlay) and request succeeds (we allow dynamic code in dev only):
```bash
warn - (middleware)/middleware.js (7:2) @ Object.middleware [as handler]
warn - Dynamic Code Evaluation (e. g. 'eval', 'new Function') not allowed in Edge Runtime
5 |
6 | export default async function middleware() {
> 7 | eval('2+2')
```
- [x] build, middleware/edge route is loading dynamic code: build fails with error:
```bash
Failed to compile.
./middleware.js
Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime
Used by default
./pages/api/route.js
Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime
Used by default
```
## Notes to reviewers
Edge-related errors are either issued from `next/server/web/sandbox/context.ts` file (runtime errors) or from `next/build/webpack/plugins/middleware-plugin.ts` (webpack compilation).
The previous implementation (I’m pleading guilty here) was way too verbose: some errors (Node.js global APIs like using `process.cwd()`) could be reported several times, and the previous mechanism to dedupe them (in middleware-plugin) wasn’t really effective.
Changes in tests are due to renaming existing tests such as `test/integration/middleware-with-node.js-apis` into `test/integration/edge-runtime-with-node.js-apis`. I extended them to cover Edge API route.
@hanneslund I’ve pushed the improvement you did in https://github.com/vercel/next.js/pull/38289/ one step further to avoid duplication.
## How to reproduce
1. create a next.js app with a middleware (or an edge route) that imports a node.js module:
```js
// middleware.js
import { NextResponse } from 'next/server'
import { basename } from 'path'
export default async function middleware() {
basename()
return NextResponse.next()
}
```
2. deploy it to vercel with `vc`
3. go to the your function logs in Vercel Front (https://vercel.com/$user/$project/$deployment/functions)
4. in another tab, query your application
> it results in a 500 page:
<img width="517" alt="image" src="https://user-images.githubusercontent.com/186268/179557102-72568ca9-bcfd-49e2-9b9c-c51c3064f2d7.png">
> in the logs you should see:
<img width="1220" alt="image" src="https://user-images.githubusercontent.com/186268/179557266-498f3290-b7df-46ac-8816-7bb396821245.png">
## Expected behavior
The route should fail indeed in a 500, because Edge runtime **does not support node.js modules**. However the error in logs should be completely different:
```shell
error - Error: The edge runtime does not support Node.js 'path' module.
Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime
```
## Notes to reviewers
I introduced this issue in #38234.
Prior to the PR above, the app would not even build, as we were checking imported node.js module during the build with AST analysis.
Since #38234, the app would build and should fail at runtime, with an appropriate error.
The mistake was to declare `__import_unsupported` function in the sandbox's context, that is only used in `next dev` and `next start`, but not shipped to Vercel platform.
By loading it inside webpack loaders (both middleware and edge route), we ensure it will be defined on Vercel as well.
The existing test suite (`pnpm testheadless --testPathPattern=runtime-module-error`) covers them.
* [edge] allow importing blob assets
* Fix test
* extract to a new file, to make it easier to read and review
* Use webpack asset discovery and transform with a loader
* fix tests
* don't prefix assets
* use emitFile
* rename assets to blobs to be more specific
* rename blobs to assets and use webpack's hashing algo
* Dedupe correctly
* Add a Node.js dep test
* Update packages/next/server/next-server.ts
Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com>
* [code review] test remote URL fetches
* [code review] use `import type` for type-only imports
* Update packages/next/server/next-server.ts
Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com>
* Apply suggestions from code review
Co-authored-by: JJ Kasper <jj@jjsweb.site>
Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com>
Co-authored-by: JJ Kasper <jj@jjsweb.site>
## What's in there?
The Edge runtime [does not support Node.js modules](https://edge-runtime.vercel.app/features/available-apis#unsupported-apis).
When building Next.js application, we currently fail the build when detecting node.js module imported from middleware.
This is an blocker for using code that is conditionally loading node.js modules (based on platform/env detection), as @cramforce reported.
This PR implements a new strategy where:
- we can build such middleware/Edge API route code **with a warning**
- we fail at run time, with graceful errors in dev (console & react-dev-overlay error)
- we fail at run time, with console errors in production
## How to test?
All cases are covered with integration tests.
To try them live, create a simple app with a page, a `middleware.js` file and a `pages/api/route.js`file.
Here are iconic examples:
### node.js modules
```js
// middleware.js
import { NextResponse } from 'next/server'
// static
import { basename } from 'path'
export default async function middleware() {
// dynamic
const { basename } = await import('path')
basename()
return NextResponse.next()
}
export const config = { matcher: '/' }
```
```js
// pags/api/route.js
// static
import { isAbsolute } from 'path'
export default async function handle() {
// dynamic
const { isAbsolute } = await import('path')
return Response.json({ useNodeModule: isAbsolute('/test') })
}
export const config = { runtime: 'experimental-edge' }
```
Desired error (+ source code highlight in dev):
> The edge runtime does not support Node.js 'path' module
Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime
Desired warning at build time:
> A Node.js module is loaded ('path' at line 2) which is not supported in the Edge Runtime.
Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime
- [x] in dev middleware, static, shows desired error on stderr
- [x] in dev route, static, shows desired error on stderr
- [x] in dev middleware, dynamic, shows desired error on stderr
- [x] in dev route, dynamic, shows desired error on stderr
- [x] in dev middleware, static, shows desired error on react error overlay
- [x] in dev route, static, shows desired error on react error overlay
- [x] in dev middleware, dynamic, shows desired error on react error overlay
- [x] in dev route, dynamic, shows desired error on react error overlay
- [x] builds middleware successfully, shows build warning, shows desired error on stderr on call
- [x] builds route successfully, shows build warning, shows desired error on stderr on call
### 3rd party modules not found
```js
// middleware.js
import { NextResponse } from 'next/server'
// static
import Unknown from 'unknown'
export default async function middleware() {
// dynamic
const Unknown = await import('unknown')
new Unknown()
return NextResponse.next()
}
```
export const config = { matcher: '/' }
```
```js
// pags/api/route.js
// static
import Unknown from 'unknown'
export default async function handle() {
// dynamic
const Unknown = await import('unknown')
return Response.json({ use3rdPartyModule: Unknown() })
}
export const config = { runtime: 'experimental-edge' }
```
Desired error (+ source code highlight in dev):
> Module not found: Can't resolve 'does-not-exist'
Learn More: https://nextjs.org/docs/messages/module-not-found
- [x] in dev middleware, static, shows desired error on stderr
- [x] in dev route, static, shows desired error on stderr
- [x] in dev middleware, dynamic, shows desired error on stderr
- [x] in dev route, dynamic, shows desired error on stderr
- [x] in dev middleware, static, shows desired error on react error overlay
- [x] in dev route, static, shows desired error on react error overlay
- [x] in dev middleware, dynamic, shows desired error on react error overlay
- [x] in dev route, dynamic, shows desired error on react error overlay
- [x] fails to build middleware, with desired error on stderr
- [x] fails to build route, with desired error on stderr
### unused node.js modules
```js
// middleware.js
import { NextResponse } from 'next/server'
export default async function middleware() {
if (process.exit) {
const { basename } = await import('path')
basename()
}
return NextResponse.next()
}
```
```js
// pags/api/route.js
export default async function handle() {
if (process.exit) {
const { basename } = await import('path')
basename()
}
return Response.json({ useNodeModule: false })
}
export const config = { runtime: 'experimental-edge' }
```
Desired warning at build time:
> A Node.js module is loaded ('path' at line 2) which is not supported in the Edge Runtime.
Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime
- [x] invoke middleware in dev with no error
- [x] invoke route in dev with no error
- [x] builds successfully, shows build warning, invoke middleware with no error
- [x] builds successfully, shows build warning, invoke api-route with no error
## Notes to reviewers
The strategy to implement this feature is to leverages webpack [externals](https://webpack.js.org/configuration/externals/#externals) and run a global `__unsupported_module()` function when using a node.js module from edge function's code.
For the record, I tried using [webpack resolve.fallback](https://webpack.js.org/configuration/resolve/#resolvefallback) and [Webpack.IgnorePlugin](https://webpack.js.org/plugins/ignore-plugin/) but they do not allow throwing proper errors at runtime that would contain the loaded module name for reporting.
`__unsupported_module()` is defined in `EdgeRuntime`, and returns a proxy that's throw on use (whether it's property access, function call, new operator... synchronous & promise-based styles).
However there's an issue with error reporting: webpack does not includes the import lines in the generated sourcemaps, preventing from displaying useful errors.
I extended our middleware-plugin to supplement the sourcemaps (when analyzing edge function code, it saves which module is imported from which file, together with line/column/source)
The react-dev-overlay was adapted to look for this additional information when the caught error relates to modules, instead of looking at sourcemaps.
I removed the previous mechanism (built by @nkzawa ) which caught webpack errors at built time to change the displayed error message (files `next/build/index.js`, `next/build/utils.ts` and `wellknown-errors-plugin`)
x-ref: #31506
This PR migrates existing SSR on edge from middleware to edge functions implmentation. So that we can get rid of limitation of middleware and resolve the conflicts between middleware and edge SSR routes.
* Adding edge functions matching route in middleware catch all route,keep the order as `middleware catch all` -> redirects/rewrites -> `edge catch all` -> others
* Dropping middleware related code for edge SSR: removing client info and preflight request handling
In Middlewares, dynamic code execution is not allowed. Currently, we warn if eval / new Function are invoked in dev but don't warn another dynamic code execution in WebAssembly.
This PR adds warnings for `WebAssembly.compile` and `WebAssembly.instantiate` with a buffer parameter (note that `WebAssembly.instantiate` with a **module** parameter is legit) invocations. Note that other methods that compile WASM dynamically such as `WebAssembly.compileStreaming` are not exposed to users so we don't need to cover them.
## Bug
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
## Feature
- [ ] 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
- [x] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [x] Errors have helpful link attached, see `contributing.md`
## Documentation / Examples
- [ ] Make sure the linting passes by running `pnpm lint`
- [ ] The examples guidelines are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)
Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com>
* Ensure custom middleware matcher is used correctly in client manifest
* lint-fix
* patch e2e case
* fix rsc case
* update test
* add missing normalize
* Re-introduce Edge API Endpoints
This reverts commit 210fa39961, and
re-introduces Edge API endpoints as a possible runtime selection in API
endpoints.
This is done by exporting a `config` object:
```ts
export config = { runtime: 'edge' }
```
Note: `'edge'` will probably change into `'experimental-edge'` to show
that this is experimental and the API might change in the future.
* Support `experimental-edge`, but allow `edge` too
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit enables the following patterns in Middleware:
```ts
// with a dot notation
const { ENV_VAR, "ENV-VAR": myEnvVar } = process.env;
// or with an object access
const { ENV_VAR2, "ENV-VAR2": myEnvVar2 } = process["env"];
```
### Related
- @cramforce asked this fixed here: https://github.com/vercel/next.js/pull/37514#discussion_r892437257
## Feature
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [x] 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`
This PR will allow Middleware to set its matcher through `export const config = { matching: ... }`
## Related
* This PR is rebased off #37121
## Feature
- [ ] 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`
- [ ] 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`
## Documentation / Examples
- [ ] Make sure the linting passes by running `yarn lint`
## Feature
This PR introduces the ability to provide `runtime: "edge"` in API endpoints, the same as the experimental RSC runtime configurations.
- [ ] 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`
- [ ] 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`
## Documentation / Examples
- [ ] Make sure the linting passes by running `yarn lint`
_Hello Next.js team! First PR here, I hope I've followed the right practices._
### What's in there?
It has been decided to only support the following uses cases in Next.js' middleware:
- rewrite the URL (`x-middleware-rewrite` response header)
- redirect to another URL (`Location` response header)
- pass on to the next piece in the request pipeline (`x-middleware-next` response header)
1. during development, a warning on console tells developers when they are returning a response (either with `Response` or `NextResponse`).
2. at build time, this warning becomes an error.
3. at run time, returning a response body will trigger a 500 HTTP error with a JSON payload containing the detailed error.
All returned/thrown errors contain a link to the documentation.
This is a breaking feature compared to the _beta_ middleware implementation, and also removes `NextResponse.json()` which makes no sense any more.
### How to try it?
- runtime behavior: `HEADLESS=true yarn jest test/integration/middleware/core`
- build behavior : `yarn jest test/integration/middleware/build-errors`
- development behavior: `HEADLESS=true yarn jest test/development/middleware-warnings`
### Notes to reviewers
The limitation happens in next's web adapter. ~The initial implementation was to check `response.body` existence, but it turns out [`Response.redirect()`](https://github.com/vercel/next.js/blob/canary/packages/next/server/web/spec-compliant/response.ts#L42-L53) may set the response body (https://github.com/vercel/next.js/pull/31886). Hence why the proposed implementation specifically looks at response headers.~
`Response.redirect()` and `NextResponse.redirect()` do not need to include the final location in their body: it is handled by next server https://github.com/vercel/next.js/blob/canary/packages/next/server/next-server.ts#L1142
Because this is a breaking change, I had to adjust several tests cases, previously returning JSON/stream/text bodies. When relevant, these middlewares are returning data using response headers.
About DevEx: relying on AST analysis to detect forbidden use cases is not as good as running the code.
Such cases are easy to detect:
```js
new Response('a text value')
new Response(JSON.stringify({ /* whatever */ })
```
But these are false-positive cases:
```js
function returnNull() { return null }
new Response(returnNull())
function doesNothing() {}
new Response(doesNothing())
```
However, I see no good reasons to let users ship middleware such as the one above, hence why the build will fail, even if _technically speaking_, they are not setting the response body.
## Feature
- [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
- [x] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [x] Errors have helpful link attached, see `contributing.md`
## Documentation / Examples
- [x] Make sure the linting passes by running `yarn lint`
This PR deprecates declaring a middleware under `pages` in favour of the project root naming it after `middleware` instead of `_middleware`. This is in the context of having a simpler execution model for middleware and also ships some refactor work. There is a ton of a code to be simplified after this deprecation but I think it is best to do it progressively.
With this PR, when in development, we will **fail** whenever we find a nested middleware but we do **not** include it in the compiler so if the project is using it, it will no longer work. For production we will **fail** too so it will not be possible to build and deploy a deprecated middleware. The error points to a page that should also be reviewed as part of **documentation**.
Aside from the deprecation, this migrates all middleware tests to work with a single middleware. It also splits tests into multiple folders to make them easier to isolate and work with. Finally it ships some small code refactor and simplifications.
## What's in there?
Partially fixes https://github.com/vercel/edge-functions/issues/82
Relates to #36715
Our webpack plugin for middleware leverages static analysis to detect Dyanamic code evaluation in user `_middleware.js` file (and depedencies). Since edge function runtime do not allow them, the build is aborted.
The use of `Function.bind` is considered invalid, while it is legit. A customer using `@aws-sdk/client-s3` reported it.
This PR fixes it.
Please note that this check is too strict: some dynamic code may be in the bundle (despite treeshaking), but may never be used (because of code branches). Since this point is under discussion, this PR adds tests covering some false positives (`@apollo/react-hook`, `qs` and `has`), but does not change the behavior (consider them as errors).
## Notes to reviewer
I looked for test facilities allowing to download the required 3rd party modules. `createNext()` in production context made my day, but showed two issues:
- `cliOutput` is not cleaned in between tests. While clearance during `stop()` would be annoying, I hope that clearance during `start()` is better.
- if `start()` fails while building, the created instance can never be stopped. This is because we don't clear `childProcess` after `build`.
## Bug
- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
## Feature
- [ ] 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`
- [ ] 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`
## Documentation / Examples
- [x] Make sure the linting passes by running `yarn lint`
This PR brings some significant refactoring in preparation for upcoming middleware changes. Each commit can be reviewed independently, here is a summary of what each one does and the reasoning behind it:
- [Move pagesDir to next-dev-server](f2fe154c00) simply moves the `pagesDir` property to the dev server which is the only place where it is needed. Having it for every server is misleading.
- [Move (de)normalize page path utils to a file page-path-utils.ts](27cedf0871) Moves the functions to normalize and denormalize page paths to a single file that is intended to hold every utility function that transforms page paths. Since those are complementary it makes sense to have them together. I also added explanatory comments on why they are not idempotent and examples for input -> output that I find very useful.
- [Extract removePagePathTail](6b121332aa) This extracts a function to remove the tail on a page path (absolute or relative). I'm sure there will be other contexts where we can use it.
- [Extract getPagePaths and refactor findPageFile](cf2c7b842e) This extracts a function `getPagePaths` that is used to generate an array of paths to inspect when looking for a page file from `findPageFile`. Then it refactors such function to use it parallelizing lookups. This will allow us to print every path we look at when looking for a file which can be useful for debugging. It also adds a `flatten` helper.
- [Refactor onDemandEntryHandler](4be685c37e) I've found this one quite difficult to understand so it is refactored to use some of the previously mentioned functions and make it easier to read.
- [Extract absolutePagePath util](3bc0783474) Extracts yet another util from the `next-dev-server` that transforms an absolute path into a page name. Of course it adds comments, parameters and examples.
- [Refactor MiddlewarePlugin](c595a2cc62) This is the most significant change. The logic here was very hard to understand so it is totally redistributed with comments. This also removes a global variable `ssrEntries` that was deprecated in favour of module metadata added to Webpack from loaders keeping less dependencies. It also adds types and makes a clear distinction between phases where we statically analyze the code, find metadata and generate the manifest file cc @shuding @huozhi
EDIT:
- [Split page path utils](158fb002d0) After seeing one of the utils was being used by the client while it was defined originally in the server, with this PR we are splitting the util into multiple files and moving it to `shared/lib` in order to make explicit that those can be also imported from client.
This PR introduces a way to use WASM in middlewares.
Next.js will find all `.wasm` imports in middlewares and load them as `WebAssembly.Module` objects, which then can be later instantiated.
The metadata will be stored in `middleware-manifest.json`
## Bug
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
## Feature
- [ ] 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`
- [ ] 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`
## Documentation / Examples
- [ ] Make sure the linting passes by running `yarn lint`
## Feature
Follow up for #33770
* When page config specify runtime is "nodejs", remove runtime option in functions manifest;
* If user enable `concurrentFeatures` and filesystem api, use `runtime: "web"` for those pages;
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
## Feature
Reuse most of the part from manifest plugin to generate similar assets
Resolves#33667
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
Production middlewares will only expose env vars that are statically analyzable, as mentioned here: https://nextjs.org/docs/api-reference/next/server#how-do-i-access-environment-variables
This creates some incompatibility with `next dev` and `next start`, where all `process.env` data is shared and can lead to unexpected behavior in runtime.
This PR fixes it by limiting the data in `process.env` with the inferred env vars from the code usage. I believe the test speaks for itself 🕺
<!--
## Bug
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
## Feature
- [ ] 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`
- [ ] 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`
## Documentation / Examples
- [ ] Make sure the linting passes by running `yarn lint`
-->
After discussing with @sokra, seems that the proposed solution is split in two:
* We need to make sure that the `process` polyfill uses `global.process` if available. This is because middlewares are bundled using `browser` target and therefore `process.env.MY_ENV` gets shimmed into `require('process').env.MY_ENV`.
* Allow `process.env` to be statically analyzed for dependencies so they will be exported to the manifest.
Related issues:
* should fix#33043.
it should not leak into the client runtime
cc @javivelasco
## Bug
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
## Feature
- [ ] 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`
- [ ] 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`
## Documentation / Examples
- [ ] Make sure the linting passes by running `yarn lint`
1. Align `renderToReadableStream` with `renderToNodeStream`, resolve promise of `NodeWritablePiper` only when `onCompleteShell` is called.
2. update webpack to disable chunk loading for web runtime
Item 1 is the preparation for middleware-ssr-loader. Then we can do the following there
```js
try {
result = await renderToHTML(page)
} catch (e) {
result = await renderToHTML(errorPage)
}
result.pipe(renderResult)
```
## Bug
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
## Feature
- [ ] 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`
- [ ] 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`
## Documentation / Examples
- [ ] Make sure the linting passes by running `yarn lint`
When using the web runtime with SSR streaming, this PR significantly improves the build speed for large applications when there're large modules shared by most pages.
With another optimization, `react-dom` will now be excluded in the web runtime build if it's imported in the application. It will only take effect in the client bundle.
## Bug
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
## Feature
- [ ] 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`
- [ ] 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`
## Documentation / Examples
- [ ] Make sure the linting passes by running `yarn lint`
x-ref: https://github.com/vercel/next.js/issues/30424#issuecomment-955615781
This fix the custom 404 is not rendering properly and can’t be built in web runtime when `concurrentFeatures` is enabled. We force 404 page to be rendered outside of middleware ssr. Then it could be the real fallback 404 page in next-server when any routes is not macthed.
Will check 500 related after #31057 is landed.
## Bug
- [x] Related to #30989
- [x] Integration tests added
Co-authored-by: Tobias Koppers <sokra@users.noreply.github.com>
With this PR we are updating the way we check the usage of `eval` and other dynamic code evaluation (like `new Function`) for middleware. Now instead of simply showing a warning it will behave differently depending on if we are building or in development.
- Development: we replace the dynamic code with a wrapper so that we print a warning only when the code is used. We don't fail in this scenario as it is possible that once the application is built the code that uses `eval` is left out.
- Build: we detect with tree shaking if the code that will be bundled into the middleware includes any dynamic code and in such scenario we make the build fail as don't want to allow it for the production environment.
Closes#30674
## Bug
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
## Feature
- [ ] 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`
- [ ] 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`
## Documentation / Examples
- [ ] Make sure the linting passes by running `yarn lint`