mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-12 04:22:14 +00:00
Compare commits
73 Commits
backup
...
@vercel/py
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a26cbd8199 | ||
|
|
3eb9d8c892 | ||
|
|
83741a0eb9 | ||
|
|
9db0298981 | ||
|
|
af29e9be49 | ||
|
|
c9d53d4e3e | ||
|
|
a26ea7bf12 | ||
|
|
866d0c173d | ||
|
|
5f561f8cfa | ||
|
|
139e8cdb17 | ||
|
|
6529a9ab9c | ||
|
|
61e6af3740 | ||
|
|
8e44ef5b9d | ||
|
|
fe9e27c459 | ||
|
|
8a6dc204fd | ||
|
|
73e558913a | ||
|
|
464cb26255 | ||
|
|
80e0bab0ec | ||
|
|
f900ca8daf | ||
|
|
9ee7d31957 | ||
|
|
1eb76a3ae7 | ||
|
|
ccd7eb1fb7 | ||
|
|
41c44d6594 | ||
|
|
446ac49e2b | ||
|
|
d3c1267e24 | ||
|
|
b09d7b6130 | ||
|
|
f78b315a50 | ||
|
|
ad69454352 | ||
|
|
14059906d3 | ||
|
|
1682ad43d0 | ||
|
|
423630a168 | ||
|
|
2f7a6ed5f9 | ||
|
|
67afc26085 | ||
|
|
c224fb1d2e | ||
|
|
5014b1e82a | ||
|
|
6a8a84907b | ||
|
|
722adf0e10 | ||
|
|
bc5fd41158 | ||
|
|
e87d4c14d0 | ||
|
|
bc95d764b4 | ||
|
|
1b5ce5644f | ||
|
|
18d1703d5b | ||
|
|
5c6f9c0b66 | ||
|
|
809740b385 | ||
|
|
bf9acd023d | ||
|
|
f4ba9cdcf8 | ||
|
|
11584b0e9b | ||
|
|
3023122d4e | ||
|
|
0e774b6be0 | ||
|
|
119f80e961 | ||
|
|
9fe92d7de0 | ||
|
|
0817527f9e | ||
|
|
6476f4f786 | ||
|
|
a5ea04154b | ||
|
|
5a532a5b94 | ||
|
|
c1d8522950 | ||
|
|
50fc27ba57 | ||
|
|
3101d2497f | ||
|
|
4b0716b556 | ||
|
|
124846a3e6 | ||
|
|
30cd0ec898 | ||
|
|
dc974b6797 | ||
|
|
58c6755e0c | ||
|
|
f18575fcd0 | ||
|
|
d6412be6bc | ||
|
|
52e435aa5d | ||
|
|
303256343a | ||
|
|
88f3a816d9 | ||
|
|
3420ba0153 | ||
|
|
3fb97d1d27 | ||
|
|
f11c7024c4 | ||
|
|
5eb4cc6f5d | ||
|
|
b1adaf76ec |
4
.github/CODEOWNERS
vendored
4
.github/CODEOWNERS
vendored
@@ -5,13 +5,13 @@
|
|||||||
* @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads
|
* @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads
|
||||||
/.github/workflows @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @ijjk
|
/.github/workflows @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @ijjk
|
||||||
/packages/fs-detectors @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @agadzik @chloetedder
|
/packages/fs-detectors @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @agadzik @chloetedder
|
||||||
/packages/next @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @timneutkens @ijjk @ztanner @huozhi @Ethan-Arrowood @styfle
|
/packages/next @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @timneutkens @ijjk @ztanner @huozhi @Ethan-Arrowood
|
||||||
/packages/routing-utils @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @ijjk
|
/packages/routing-utils @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @ijjk
|
||||||
/packages/static-build @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads
|
/packages/static-build @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads
|
||||||
/packages/edge @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @vercel/compute
|
/packages/edge @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @vercel/compute
|
||||||
/examples @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @leerob
|
/examples @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @leerob
|
||||||
/examples/create-react-app @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @Timer
|
/examples/create-react-app @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @Timer
|
||||||
/examples/nextjs @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @timneutkens @ijjk @ztanner @huozhi @Ethan-Arrowood @styfle
|
/examples/nextjs @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @timneutkens @ijjk @ztanner @huozhi @Ethan-Arrowood
|
||||||
/packages/node @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @Kikobeats
|
/packages/node @TooTallNate @EndangeredMassa @trek @onsclom @jeffsee55 @erikareads @Kikobeats
|
||||||
|
|
||||||
# Unrestricted Paths
|
# Unrestricted Paths
|
||||||
|
|||||||
5
.github/dependabot.yml
vendored
5
.github/dependabot.yml
vendored
@@ -63,16 +63,21 @@ updates:
|
|||||||
allow:
|
allow:
|
||||||
- dependency-name: '@remix-run*'
|
- dependency-name: '@remix-run*'
|
||||||
- dependency-name: '@shopify*'
|
- dependency-name: '@shopify*'
|
||||||
|
- dependency-name: 'remix*'
|
||||||
ignore:
|
ignore:
|
||||||
- dependency-name: '@remix-run*'
|
- dependency-name: '@remix-run*'
|
||||||
update-types:
|
update-types:
|
||||||
['version-update:semver-major', 'version-update:semver-patch']
|
['version-update:semver-major', 'version-update:semver-patch']
|
||||||
|
- dependency-name: 'remix*'
|
||||||
|
update-types:
|
||||||
|
['version-update:semver-major', 'version-update:semver-patch']
|
||||||
- dependency-name: '@shopify*'
|
- dependency-name: '@shopify*'
|
||||||
update-types:
|
update-types:
|
||||||
['version-update:semver-major', 'version-update:semver-patch']
|
['version-update:semver-major', 'version-update:semver-patch']
|
||||||
groups:
|
groups:
|
||||||
core:
|
core:
|
||||||
patterns:
|
patterns:
|
||||||
|
- 'remix*'
|
||||||
- '@remix-run*'
|
- '@remix-run*'
|
||||||
- '@shopify*'
|
- '@shopify*'
|
||||||
update-types:
|
update-types:
|
||||||
|
|||||||
124
.github/workflows/test-18.yml
vendored
Normal file
124
.github/workflows/test-18.yml
vendored
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
name: Tests Node.js v18
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
tags:
|
||||||
|
- '!*'
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
env:
|
||||||
|
NODE_VERSION: '18'
|
||||||
|
TURBO_REMOTE_ONLY: 'true'
|
||||||
|
TURBO_TEAM: 'vercel'
|
||||||
|
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
setup:
|
||||||
|
name: Find Changes
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
tests: ${{ steps['set-tests'].outputs['tests'] }}
|
||||||
|
dplUrl: ${{ steps.waitForTarball.outputs.url }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
- name: install pnpm@8.3.1
|
||||||
|
run: npm i -g pnpm@8.3.1
|
||||||
|
- run: pnpm install
|
||||||
|
- id: set-tests
|
||||||
|
run: |
|
||||||
|
TESTS_ARRAY=$(node utils/chunk-tests-18.js $SCRIPT_NAME)
|
||||||
|
echo "Files to test:"
|
||||||
|
echo "$TESTS_ARRAY"
|
||||||
|
echo "tests=$TESTS_ARRAY" >> $GITHUB_OUTPUT
|
||||||
|
- uses: patrickedqvist/wait-for-vercel-preview@bfdff514ff78a669f2536e9f4dd4ef5813a704a2
|
||||||
|
id: waitForTarball
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
max_timeout: 360
|
||||||
|
check_interval: 5
|
||||||
|
test:
|
||||||
|
timeout-minutes: 120
|
||||||
|
runs-on: ${{ matrix.runner }}
|
||||||
|
name: ${{matrix.scriptName}} (${{matrix.packageName}}, ${{matrix.chunkNumber}}, ${{ matrix.runner }})
|
||||||
|
if: ${{ needs.setup.outputs['tests'] != '[]' }}
|
||||||
|
needs:
|
||||||
|
- setup
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include: ${{ fromJson(needs.setup.outputs['tests']) }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.nodeVersion || env.NODE_VERSION }}
|
||||||
|
|
||||||
|
# yarn 1.22.21 introduced a Corepack bug when running tests.
|
||||||
|
# this can be removed once https://github.com/yarnpkg/yarn/issues/9015 is resolved
|
||||||
|
- name: install yarn@1.22.19
|
||||||
|
run: npm i -g yarn@1.22.19
|
||||||
|
|
||||||
|
- name: install pnpm@8.3.1
|
||||||
|
run: npm i -g pnpm@8.3.1
|
||||||
|
|
||||||
|
- run: pnpm install
|
||||||
|
|
||||||
|
- name: Build ${{matrix.packageName}} and all its dependencies
|
||||||
|
run: node utils/gen.js && node_modules/.bin/turbo run build --cache-dir=".turbo" --log-order=stream --scope=${{matrix.packageName}} --include-dependencies --no-deps
|
||||||
|
env:
|
||||||
|
FORCE_COLOR: '1'
|
||||||
|
- name: Test ${{matrix.packageName}}
|
||||||
|
run: node utils/gen.js && node_modules/.bin/turbo run ${{matrix.testScript}} --summarize --cache-dir=".turbo" --log-order=stream --scope=${{matrix.packageName}} --no-deps -- ${{ join(matrix.testPaths, ' ') }}
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
JEST_JUNIT_OUTPUT_FILE: ${{github.workspace}}/.junit-reports/${{matrix.scriptName}}-${{matrix.packageName}}-${{matrix.chunkNumber}}-${{ matrix.runner }}.xml
|
||||||
|
VERCEL_CLI_VERSION: ${{ needs.setup.outputs.dplUrl }}/tarballs/vercel.tgz
|
||||||
|
VERCEL_TEST_TOKEN: ${{ secrets.VERCEL_TEST_TOKEN }}
|
||||||
|
VERCEL_TEST_REGISTRATION_URL: ${{ secrets.VERCEL_TEST_REGISTRATION_URL }}
|
||||||
|
FORCE_COLOR: '1'
|
||||||
|
- name: 'Determine Turbo HIT or MISS'
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
id: turbo-summary
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
TURBO_MISS_COUNT=`node utils/determine-turbo-hit-or-miss.js`
|
||||||
|
echo "MISS COUNT: $TURBO_MISS_COUNT"
|
||||||
|
echo "misses=$TURBO_MISS_COUNT" >> $GITHUB_OUTPUT
|
||||||
|
- name: 'Upload Test Report to Datadog'
|
||||||
|
if: ${{ steps['turbo-summary'].outputs.misses != '0' && !cancelled() }}
|
||||||
|
run: 'npx @datadog/datadog-ci@2.18.1 junit upload --service vercel-cli .junit-reports'
|
||||||
|
env:
|
||||||
|
DATADOG_API_KEY: ${{secrets.DATADOG_API_KEY_CLI}}
|
||||||
|
DD_ENV: ci
|
||||||
|
|
||||||
|
summary:
|
||||||
|
name: Summary
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 5
|
||||||
|
if: always()
|
||||||
|
needs:
|
||||||
|
- test
|
||||||
|
steps:
|
||||||
|
- name: Check All
|
||||||
|
run: |-
|
||||||
|
for status in ${{ join(needs.*.result, ' ') }}
|
||||||
|
do
|
||||||
|
if [ "$status" != "success" ] && [ "$status" != "skipped" ]
|
||||||
|
then
|
||||||
|
echo "Some checks failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: Tests
|
name: Tests Node.js v16
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -99,7 +99,7 @@ jobs:
|
|||||||
echo "misses=$TURBO_MISS_COUNT" >> $GITHUB_OUTPUT
|
echo "misses=$TURBO_MISS_COUNT" >> $GITHUB_OUTPUT
|
||||||
- name: 'Upload Test Report to Datadog'
|
- name: 'Upload Test Report to Datadog'
|
||||||
if: ${{ steps['turbo-summary'].outputs.misses != '0' && !cancelled() }}
|
if: ${{ steps['turbo-summary'].outputs.misses != '0' && !cancelled() }}
|
||||||
run: 'npx @datadog/datadog-ci@2.18.1 junit upload --service vercel-cli .junit-reports'
|
run: 'npx @datadog/datadog-ci@2.36.0 junit upload --service vercel-cli .junit-reports'
|
||||||
env:
|
env:
|
||||||
DATADOG_API_KEY: ${{secrets.DATADOG_API_KEY_CLI}}
|
DATADOG_API_KEY: ${{secrets.DATADOG_API_KEY_CLI}}
|
||||||
DD_ENV: ci
|
DD_ENV: ci
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ You can use the `dev` script to run local changes as if you were invoking Vercel
|
|||||||
|
|
||||||
When contributing to this repository, please first discuss the change you wish to make via [GitHub Discussions](https://github.com/vercel/vercel/discussions/new) with the owners of this repository before submitting a Pull Request.
|
When contributing to this repository, please first discuss the change you wish to make via [GitHub Discussions](https://github.com/vercel/vercel/discussions/new) with the owners of this repository before submitting a Pull Request.
|
||||||
|
|
||||||
Please read our [Code of Conduct](CODE_OF_CONDUCT.md) and follow it in all your interactions with the project.
|
Please read our [Code of Conduct](./.github/CODE_OF_CONDUCT.md) and follow it in all your interactions with the project.
|
||||||
|
|
||||||
### Local development
|
### Local development
|
||||||
|
|
||||||
|
|||||||
2
examples/package.json
vendored
2
examples/package.json
vendored
@@ -9,7 +9,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "27.4.1",
|
"@types/jest": "27.4.1",
|
||||||
"@vercel/build-utils": "8.0.0",
|
"@vercel/build-utils": "8.2.1",
|
||||||
"@vercel/frameworks": "3.0.2"
|
"@vercel/frameworks": "3.0.2"
|
||||||
},
|
},
|
||||||
"version": null
|
"version": null
|
||||||
|
|||||||
@@ -9,18 +9,18 @@
|
|||||||
"typecheck": "tsc"
|
"typecheck": "tsc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@remix-run/node": "^2.8.0",
|
"@remix-run/node": "^2.9.2",
|
||||||
"@remix-run/react": "^2.8.0",
|
"@remix-run/react": "^2.9.2",
|
||||||
"@remix-run/server-runtime": "^2.8.0",
|
"@remix-run/server-runtime": "^2.9.2",
|
||||||
"@vercel/analytics": "^1.2.2",
|
"@vercel/analytics": "^1.2.2",
|
||||||
"@vercel/remix": "^2.8.0",
|
"@vercel/remix": "2.9.2-patch.2",
|
||||||
"isbot": "^4",
|
"isbot": "^4",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@remix-run/dev": "^2.8.0",
|
"@remix-run/dev": "^2.9.2",
|
||||||
"@remix-run/eslint-config": "^2.8.0",
|
"@remix-run/eslint-config": "^2.9.2",
|
||||||
"@types/react": "^18.2.20",
|
"@types/react": "^18.2.20",
|
||||||
"@types/react-dom": "^18.2.7",
|
"@types/react-dom": "^18.2.7",
|
||||||
"eslint": "^8.38.0",
|
"eslint": "^8.38.0",
|
||||||
|
|||||||
@@ -1,5 +1,47 @@
|
|||||||
# @vercel-internals/types
|
# @vercel-internals/types
|
||||||
|
|
||||||
|
## 1.0.37
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`83741a0eb`](https://github.com/vercel/vercel/commit/83741a0eb9e44457b083e8790a11eb89984e6357)]:
|
||||||
|
- @vercel/build-utils@8.2.1
|
||||||
|
|
||||||
|
## 1.0.36
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`d3c1267e2`](https://github.com/vercel/vercel/commit/d3c1267e24082789ea6382cf6af81dd40df288ff), [`ccd7eb1fb`](https://github.com/vercel/vercel/commit/ccd7eb1fb78f7ac9effdbe1935de3bda82c97fe3)]:
|
||||||
|
- @vercel/build-utils@8.2.0
|
||||||
|
|
||||||
|
## 1.0.35
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`ad6945435`](https://github.com/vercel/vercel/commit/ad69454352b519b2b0ed326f245c779530554bf2)]:
|
||||||
|
- @vercel/build-utils@8.1.3
|
||||||
|
|
||||||
|
## 1.0.34
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`1682ad43d`](https://github.com/vercel/vercel/commit/1682ad43d0064b22b1248a7e946746b838f00076)]:
|
||||||
|
- @vercel/build-utils@8.1.2
|
||||||
|
|
||||||
|
## 1.0.33
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`2f7a6ed5f`](https://github.com/vercel/vercel/commit/2f7a6ed5f92d454000f92247d3b6548e2064f4e6)]:
|
||||||
|
- @vercel/build-utils@8.1.1
|
||||||
|
|
||||||
|
## 1.0.32
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`5014b1e82`](https://github.com/vercel/vercel/commit/5014b1e82a46181baeb727ffe6d14000b6a4b1d7)]:
|
||||||
|
- @vercel/build-utils@8.1.0
|
||||||
|
|
||||||
## 1.0.31
|
## 1.0.31
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"name": "@vercel-internals/types",
|
"name": "@vercel-internals/types",
|
||||||
"version": "1.0.31",
|
"version": "1.0.37",
|
||||||
"types": "index.d.ts",
|
"types": "index.d.ts",
|
||||||
"main": "index.d.ts",
|
"main": "index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "14.14.31",
|
"@types/node": "14.14.31",
|
||||||
"@vercel-internals/constants": "1.0.4",
|
"@vercel-internals/constants": "1.0.4",
|
||||||
"@vercel/build-utils": "8.0.0",
|
"@vercel/build-utils": "8.2.1",
|
||||||
"@vercel/routing-utils": "3.1.0"
|
"@vercel/routing-utils": "3.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1,5 +1,46 @@
|
|||||||
# @vercel/build-utils
|
# @vercel/build-utils
|
||||||
|
|
||||||
|
## 8.2.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- [node] update node@16 deprecation day ([#11671](https://github.com/vercel/vercel/pull/11671))
|
||||||
|
|
||||||
|
## 8.2.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- fix corepack detection for package manager version determination ([#11596](https://github.com/vercel/vercel/pull/11596))
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Fix triggering of ignored project settings node version warning ([#11550](https://github.com/vercel/vercel/pull/11550))
|
||||||
|
|
||||||
|
## 8.1.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- [build-utils] log more around package manager detection ([#11594](https://github.com/vercel/vercel/pull/11594))
|
||||||
|
|
||||||
|
## 8.1.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- add log to package manager version detection ([#11592](https://github.com/vercel/vercel/pull/11592))
|
||||||
|
|
||||||
|
## 8.1.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- [build-utils] pnpm lockfile testing and fixing ([#11591](https://github.com/vercel/vercel/pull/11591))
|
||||||
|
|
||||||
|
## 8.1.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- Update pnpm version detection logic ([#11445](https://github.com/vercel/vercel/pull/11445))
|
||||||
|
Add support for pnpm 9
|
||||||
|
|
||||||
## 8.0.0
|
## 8.0.0
|
||||||
|
|
||||||
### Major Changes
|
### Major Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/build-utils",
|
"name": "@vercel/build-utils",
|
||||||
"version": "8.0.0",
|
"version": "8.2.1",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"types": "./dist/index.d.js",
|
"types": "./dist/index.d.js",
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const NODE_VERSIONS: NodeVersion[] = [
|
|||||||
major: 16,
|
major: 16,
|
||||||
range: '16.x',
|
range: '16.x',
|
||||||
runtime: 'nodejs16.x',
|
runtime: 'nodejs16.x',
|
||||||
discontinueDate: new Date('2024-06-15'),
|
discontinueDate: new Date('2025-02-28'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
major: 14,
|
major: 14,
|
||||||
|
|||||||
@@ -240,38 +240,51 @@ export function getSpawnOptions(
|
|||||||
|
|
||||||
export async function getNodeVersion(
|
export async function getNodeVersion(
|
||||||
destPath: string,
|
destPath: string,
|
||||||
nodeVersionFallback = process.env.VERCEL_PROJECT_SETTINGS_NODE_VERSION,
|
fallbackVersion = process.env.VERCEL_PROJECT_SETTINGS_NODE_VERSION,
|
||||||
config: Config = {},
|
config: Config = {},
|
||||||
meta: Meta = {},
|
meta: Meta = {},
|
||||||
availableVersions = getAvailableNodeVersions()
|
availableVersions = getAvailableNodeVersions()
|
||||||
): Promise<NodeVersion> {
|
): Promise<NodeVersion> {
|
||||||
const latest = getLatestNodeVersion(availableVersions);
|
const latestVersion = getLatestNodeVersion(availableVersions);
|
||||||
if (meta.isDev) {
|
if (meta.isDev) {
|
||||||
// Use the system-installed version of `node` in PATH for `vercel dev`
|
// Use the system-installed version of `node` in PATH for `vercel dev`
|
||||||
return { ...latest, runtime: 'nodejs' };
|
return { ...latestVersion, runtime: 'nodejs' };
|
||||||
}
|
}
|
||||||
const { packageJson } = await scanParentDirs(destPath, true);
|
const { packageJson } = await scanParentDirs(destPath, true);
|
||||||
let nodeVersion = config.nodeVersion || nodeVersionFallback;
|
const configuredVersion = config.nodeVersion || fallbackVersion;
|
||||||
let isAuto = true;
|
|
||||||
|
const packageJsonVersion = packageJson?.engines?.node;
|
||||||
|
const supportedNodeVersion = await getSupportedNodeVersion(
|
||||||
|
packageJsonVersion || configuredVersion,
|
||||||
|
!packageJsonVersion,
|
||||||
|
availableVersions
|
||||||
|
);
|
||||||
|
|
||||||
if (packageJson?.engines?.node) {
|
if (packageJson?.engines?.node) {
|
||||||
const { node } = packageJson.engines;
|
const { node } = packageJson.engines;
|
||||||
if (nodeVersion && validRange(node) && !intersects(nodeVersion, node)) {
|
if (
|
||||||
|
configuredVersion &&
|
||||||
|
!intersects(configuredVersion, supportedNodeVersion.range)
|
||||||
|
) {
|
||||||
console.warn(
|
console.warn(
|
||||||
`Warning: Due to "engines": { "node": "${node}" } in your \`package.json\` file, the Node.js Version defined in your Project Settings ("${nodeVersion}") will not apply. Learn More: http://vercel.link/node-version`
|
`Warning: Due to "engines": { "node": "${node}" } in your \`package.json\` file, the Node.js Version defined in your Project Settings ("${configuredVersion}") will not apply. Learn More: http://vercel.link/node-version`
|
||||||
);
|
);
|
||||||
} else if (coerce(node)?.raw === node) {
|
}
|
||||||
|
|
||||||
|
if (coerce(node)?.raw === node) {
|
||||||
console.warn(
|
console.warn(
|
||||||
`Warning: Detected "engines": { "node": "${node}" } in your \`package.json\` with major.minor.patch, but only major Node.js Version can be selected. Learn More: http://vercel.link/node-version`
|
`Warning: Detected "engines": { "node": "${node}" } in your \`package.json\` with major.minor.patch, but only major Node.js Version can be selected. Learn More: http://vercel.link/node-version`
|
||||||
);
|
);
|
||||||
} else if (validRange(node) && intersects(`${latest.major + 1}.x`, node)) {
|
} else if (
|
||||||
|
validRange(node) &&
|
||||||
|
intersects(`${latestVersion.major + 1}.x`, node)
|
||||||
|
) {
|
||||||
console.warn(
|
console.warn(
|
||||||
`Warning: Detected "engines": { "node": "${node}" } in your \`package.json\` that will automatically upgrade when a new major Node.js Version is released. Learn More: http://vercel.link/node-version`
|
`Warning: Detected "engines": { "node": "${node}" } in your \`package.json\` that will automatically upgrade when a new major Node.js Version is released. Learn More: http://vercel.link/node-version`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
nodeVersion = node;
|
|
||||||
isAuto = false;
|
|
||||||
}
|
}
|
||||||
return getSupportedNodeVersion(nodeVersion, isAuto, availableVersions);
|
return supportedNodeVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function scanParentDirs(
|
export async function scanParentDirs(
|
||||||
@@ -413,9 +426,8 @@ export async function runNpmInstall(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await runNpmInstallSema.acquire();
|
await runNpmInstallSema.acquire();
|
||||||
const { cliType, packageJsonPath, lockfileVersion } = await scanParentDirs(
|
const { cliType, packageJsonPath, packageJson, lockfileVersion } =
|
||||||
destPath
|
await scanParentDirs(destPath, true);
|
||||||
);
|
|
||||||
|
|
||||||
if (!packageJsonPath) {
|
if (!packageJsonPath) {
|
||||||
debug(
|
debug(
|
||||||
@@ -450,6 +462,7 @@ export async function runNpmInstall(
|
|||||||
opts.env = getEnvForPackageManager({
|
opts.env = getEnvForPackageManager({
|
||||||
cliType,
|
cliType,
|
||||||
lockfileVersion,
|
lockfileVersion,
|
||||||
|
packageJsonPackageManager: packageJson?.packageManager,
|
||||||
nodeVersion,
|
nodeVersion,
|
||||||
env,
|
env,
|
||||||
});
|
});
|
||||||
@@ -534,40 +547,54 @@ export async function runNpmInstall(
|
|||||||
export function getEnvForPackageManager({
|
export function getEnvForPackageManager({
|
||||||
cliType,
|
cliType,
|
||||||
lockfileVersion,
|
lockfileVersion,
|
||||||
|
packageJsonPackageManager,
|
||||||
nodeVersion,
|
nodeVersion,
|
||||||
env,
|
env,
|
||||||
}: {
|
}: {
|
||||||
cliType: CliType;
|
cliType: CliType;
|
||||||
lockfileVersion: number | undefined;
|
lockfileVersion: number | undefined;
|
||||||
|
packageJsonPackageManager?: string | undefined;
|
||||||
nodeVersion: NodeVersion | undefined;
|
nodeVersion: NodeVersion | undefined;
|
||||||
env: { [x: string]: string | undefined };
|
env: { [x: string]: string | undefined };
|
||||||
}) {
|
}) {
|
||||||
|
const corepackFlagged = env.ENABLE_EXPERIMENTAL_COREPACK === '1';
|
||||||
|
const corepackEnabled = corepackFlagged && Boolean(packageJsonPackageManager);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
detectedLockfile,
|
detectedLockfile,
|
||||||
detectedPackageManager,
|
detectedPackageManager,
|
||||||
path: newPath,
|
path: newPath,
|
||||||
yarnNodeLinker,
|
} = getPathOverrideForPackageManager({
|
||||||
} = getPathForPackageManager({
|
|
||||||
cliType,
|
cliType,
|
||||||
lockfileVersion,
|
lockfileVersion,
|
||||||
|
corepackEnabled,
|
||||||
nodeVersion,
|
nodeVersion,
|
||||||
env,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (corepackEnabled) {
|
||||||
|
debug(
|
||||||
|
`Detected corepack use for "${packageJsonPackageManager}". Not overriding package manager version.`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
debug(
|
||||||
|
`Detected ${detectedPackageManager}. Added "${newPath}" to path. Based on assumed package manager "${cliType}", lockfile "${detectedLockfile}", and lockfileVersion "${lockfileVersion}"`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const newEnv: { [x: string]: string | undefined } = {
|
const newEnv: { [x: string]: string | undefined } = {
|
||||||
...env,
|
...env,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (newPath) {
|
const alreadyInPath = (newPath: string) => {
|
||||||
|
const oldPath = env.PATH ?? '';
|
||||||
|
return oldPath.split(path.delimiter).includes(newPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (newPath && !alreadyInPath(newPath)) {
|
||||||
// Ensure that the binaries of the detected package manager are at the
|
// Ensure that the binaries of the detected package manager are at the
|
||||||
// beginning of the `$PATH`.
|
// beginning of the `$PATH`.
|
||||||
const oldPath = env.PATH + '';
|
const oldPath = env.PATH + '';
|
||||||
newEnv.PATH = `${newPath}${path.delimiter}${oldPath}`;
|
newEnv.PATH = `${newPath}${path.delimiter}${oldPath}`;
|
||||||
}
|
|
||||||
|
|
||||||
if (yarnNodeLinker) {
|
|
||||||
newEnv.YARN_NODE_LINKER = yarnNodeLinker;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (detectedLockfile && detectedPackageManager) {
|
if (detectedLockfile && detectedPackageManager) {
|
||||||
// For pnpm we also show the version of the lockfile we found
|
// For pnpm we also show the version of the lockfile we found
|
||||||
@@ -584,14 +611,153 @@ export function getEnvForPackageManager({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cliType === 'yarn' && !env.YARN_NODE_LINKER) {
|
||||||
|
newEnv.YARN_NODE_LINKER = 'node-modules';
|
||||||
|
}
|
||||||
|
|
||||||
return newEnv;
|
return newEnv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DetectedPnpmVersion =
|
||||||
|
| 'not found'
|
||||||
|
| 'pnpm 6'
|
||||||
|
| 'pnpm 7'
|
||||||
|
| 'pnpm 8'
|
||||||
|
| 'pnpm 9'
|
||||||
|
| 'corepack_enabled';
|
||||||
|
|
||||||
|
function detectPnpmVersion(
|
||||||
|
lockfileVersion: number | undefined,
|
||||||
|
corepackEnabled: boolean
|
||||||
|
): DetectedPnpmVersion {
|
||||||
|
switch (true) {
|
||||||
|
case corepackEnabled:
|
||||||
|
return 'corepack_enabled';
|
||||||
|
case lockfileVersion === undefined:
|
||||||
|
return 'not found';
|
||||||
|
case lockfileVersion === 5.3:
|
||||||
|
return 'pnpm 6';
|
||||||
|
case lockfileVersion === 5.4:
|
||||||
|
return 'pnpm 7';
|
||||||
|
case lockfileVersion === 6.0 || lockfileVersion === 6.1:
|
||||||
|
return 'pnpm 8';
|
||||||
|
case lockfileVersion === 7.0 || lockfileVersion === 9.0:
|
||||||
|
return 'pnpm 9';
|
||||||
|
default:
|
||||||
|
return 'not found';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldUseNpm7(
|
||||||
|
lockfileVersion: number | undefined,
|
||||||
|
nodeVersion: NodeVersion | undefined
|
||||||
|
): boolean {
|
||||||
|
if (lockfileVersion === undefined) return false;
|
||||||
|
return lockfileVersion >= 2 && (nodeVersion?.major || 0) < 16;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to get the binary paths that link to the used package manager.
|
* Helper to get the binary paths that link to the used package manager.
|
||||||
* Note: Make sure it doesn't contain any `console.log` calls.
|
* Note: Make sure it doesn't contain any `console.log` calls.
|
||||||
*/
|
*/
|
||||||
|
export function getPathOverrideForPackageManager({
|
||||||
|
cliType,
|
||||||
|
lockfileVersion,
|
||||||
|
corepackEnabled,
|
||||||
|
nodeVersion,
|
||||||
|
}: {
|
||||||
|
cliType: CliType;
|
||||||
|
lockfileVersion: number | undefined;
|
||||||
|
corepackEnabled: boolean;
|
||||||
|
nodeVersion: NodeVersion | undefined;
|
||||||
|
}): {
|
||||||
|
/**
|
||||||
|
* Which lockfile was detected.
|
||||||
|
*/
|
||||||
|
detectedLockfile: string | undefined;
|
||||||
|
/**
|
||||||
|
* Detected package manager that generated the found lockfile.
|
||||||
|
*/
|
||||||
|
detectedPackageManager: string | undefined;
|
||||||
|
/**
|
||||||
|
* Value of $PATH that includes the binaries for the detected package manager.
|
||||||
|
* Undefined if no $PATH are necessary.
|
||||||
|
*/
|
||||||
|
path: string | undefined;
|
||||||
|
} {
|
||||||
|
const no_override = {
|
||||||
|
detectedLockfile: undefined,
|
||||||
|
detectedPackageManager: undefined,
|
||||||
|
path: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (cliType) {
|
||||||
|
case 'npm':
|
||||||
|
switch (true) {
|
||||||
|
case corepackEnabled:
|
||||||
|
return no_override;
|
||||||
|
case shouldUseNpm7(lockfileVersion, nodeVersion):
|
||||||
|
return {
|
||||||
|
path: '/node16/bin-npm7',
|
||||||
|
detectedLockfile: 'package-lock.json',
|
||||||
|
detectedPackageManager: 'npm 7+',
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return no_override;
|
||||||
|
}
|
||||||
|
case 'pnpm':
|
||||||
|
switch (detectPnpmVersion(lockfileVersion, corepackEnabled)) {
|
||||||
|
case 'corepack_enabled':
|
||||||
|
return no_override;
|
||||||
|
case 'pnpm 7':
|
||||||
|
// pnpm 7
|
||||||
|
return {
|
||||||
|
path: '/pnpm7/node_modules/.bin',
|
||||||
|
detectedLockfile: 'pnpm-lock.yaml',
|
||||||
|
detectedPackageManager: 'pnpm 7',
|
||||||
|
};
|
||||||
|
case 'pnpm 8':
|
||||||
|
// pnpm 8
|
||||||
|
return {
|
||||||
|
path: '/pnpm8/node_modules/.bin',
|
||||||
|
detectedLockfile: 'pnpm-lock.yaml',
|
||||||
|
detectedPackageManager: 'pnpm 8',
|
||||||
|
};
|
||||||
|
case 'pnpm 9':
|
||||||
|
// pnpm 9
|
||||||
|
return {
|
||||||
|
path: '/pnpm9/node_modules/.bin',
|
||||||
|
detectedLockfile: 'pnpm-lock.yaml',
|
||||||
|
detectedPackageManager: 'pnpm 9',
|
||||||
|
};
|
||||||
|
case 'pnpm 6':
|
||||||
|
default:
|
||||||
|
return no_override;
|
||||||
|
}
|
||||||
|
case 'bun':
|
||||||
|
switch (true) {
|
||||||
|
case corepackEnabled:
|
||||||
|
return no_override;
|
||||||
|
default:
|
||||||
|
// Bun 1
|
||||||
|
return {
|
||||||
|
path: '/bun1',
|
||||||
|
detectedLockfile: 'bun.lockb',
|
||||||
|
detectedPackageManager: 'Bun',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'yarn':
|
||||||
|
return no_override;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to get the binary paths that link to the used package manager.
|
||||||
|
* Note: Make sure it doesn't contain any `console.log` calls.
|
||||||
|
* @deprecated use `getEnvForPackageManager` instead
|
||||||
|
*/
|
||||||
export function getPathForPackageManager({
|
export function getPathForPackageManager({
|
||||||
cliType,
|
cliType,
|
||||||
lockfileVersion,
|
lockfileVersion,
|
||||||
@@ -622,70 +788,36 @@ export function getPathForPackageManager({
|
|||||||
*/
|
*/
|
||||||
yarnNodeLinker: string | undefined;
|
yarnNodeLinker: string | undefined;
|
||||||
} {
|
} {
|
||||||
let detectedLockfile: string | undefined;
|
// This is not the correct check for whether or not corepack is being used. For that, you'd have to check
|
||||||
let detectedPackageManager: string | undefined;
|
// the package.json's `packageManager` property. However, this deprecated function is keeping it's old,
|
||||||
let pathValue: string | undefined;
|
// broken behavior.
|
||||||
let yarnNodeLinker: string | undefined;
|
|
||||||
const oldPath = env.PATH + '';
|
|
||||||
const npm7 = '/node16/bin-npm7';
|
|
||||||
const pnpm7 = '/pnpm7/node_modules/.bin';
|
|
||||||
const pnpm8 = '/pnpm8/node_modules/.bin';
|
|
||||||
const bun1 = '/bun1';
|
|
||||||
const corepackEnabled = env.ENABLE_EXPERIMENTAL_COREPACK === '1';
|
const corepackEnabled = env.ENABLE_EXPERIMENTAL_COREPACK === '1';
|
||||||
if (cliType === 'npm') {
|
|
||||||
if (
|
const overrides = getPathOverrideForPackageManager({
|
||||||
typeof lockfileVersion === 'number' &&
|
cliType,
|
||||||
lockfileVersion >= 2 &&
|
lockfileVersion,
|
||||||
(nodeVersion?.major || 0) < 16 &&
|
corepackEnabled,
|
||||||
!oldPath.includes(npm7) &&
|
nodeVersion,
|
||||||
!corepackEnabled
|
});
|
||||||
) {
|
|
||||||
// npm 7
|
const alreadyInPath = (newPath: string) => {
|
||||||
pathValue = npm7;
|
const oldPath = env.PATH ?? '';
|
||||||
detectedLockfile = 'package-lock.json';
|
return oldPath.split(path.delimiter).includes(newPath);
|
||||||
detectedPackageManager = 'npm 7+';
|
|
||||||
}
|
|
||||||
} else if (cliType === 'pnpm') {
|
|
||||||
if (
|
|
||||||
typeof lockfileVersion === 'number' &&
|
|
||||||
lockfileVersion === 5.4 &&
|
|
||||||
!oldPath.includes(pnpm7) &&
|
|
||||||
!corepackEnabled
|
|
||||||
) {
|
|
||||||
// pnpm 7
|
|
||||||
pathValue = pnpm7;
|
|
||||||
detectedLockfile = 'pnpm-lock.yaml';
|
|
||||||
detectedPackageManager = 'pnpm 7';
|
|
||||||
} else if (
|
|
||||||
typeof lockfileVersion === 'number' &&
|
|
||||||
lockfileVersion >= 6 &&
|
|
||||||
!oldPath.includes(pnpm8) &&
|
|
||||||
!corepackEnabled
|
|
||||||
) {
|
|
||||||
// pnpm 8
|
|
||||||
pathValue = pnpm8;
|
|
||||||
detectedLockfile = 'pnpm-lock.yaml';
|
|
||||||
detectedPackageManager = 'pnpm 8';
|
|
||||||
}
|
|
||||||
} else if (cliType === 'bun') {
|
|
||||||
if (!oldPath.includes(bun1) && !corepackEnabled) {
|
|
||||||
// Bun 1
|
|
||||||
pathValue = bun1;
|
|
||||||
detectedLockfile = 'bun.lockb';
|
|
||||||
detectedPackageManager = 'Bun';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Yarn v2 PnP mode may be activated, so force "node-modules" linker style
|
|
||||||
if (!env.YARN_NODE_LINKER) {
|
|
||||||
yarnNodeLinker = 'node-modules';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
detectedLockfile,
|
|
||||||
detectedPackageManager,
|
|
||||||
path: pathValue,
|
|
||||||
yarnNodeLinker,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
switch (true) {
|
||||||
|
case cliType === 'yarn' && !env.YARN_NODE_LINKER:
|
||||||
|
return { ...overrides, yarnNodeLinker: 'node-modules' };
|
||||||
|
case alreadyInPath(overrides.path ?? ''):
|
||||||
|
return {
|
||||||
|
detectedLockfile: undefined,
|
||||||
|
detectedPackageManager: undefined,
|
||||||
|
path: undefined,
|
||||||
|
yarnNodeLinker: undefined,
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return { ...overrides, yarnNodeLinker: undefined };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runCustomInstallCommand({
|
export async function runCustomInstallCommand({
|
||||||
@@ -700,10 +832,14 @@ export async function runCustomInstallCommand({
|
|||||||
spawnOpts?: SpawnOptions;
|
spawnOpts?: SpawnOptions;
|
||||||
}) {
|
}) {
|
||||||
console.log(`Running "install" command: \`${installCommand}\`...`);
|
console.log(`Running "install" command: \`${installCommand}\`...`);
|
||||||
const { cliType, lockfileVersion } = await scanParentDirs(destPath);
|
const { cliType, lockfileVersion, packageJson } = await scanParentDirs(
|
||||||
|
destPath,
|
||||||
|
true
|
||||||
|
);
|
||||||
const env = getEnvForPackageManager({
|
const env = getEnvForPackageManager({
|
||||||
cliType,
|
cliType,
|
||||||
lockfileVersion,
|
lockfileVersion,
|
||||||
|
packageJsonPackageManager: packageJson?.packageManager,
|
||||||
nodeVersion,
|
nodeVersion,
|
||||||
env: spawnOpts?.env || {},
|
env: spawnOpts?.env || {},
|
||||||
});
|
});
|
||||||
@@ -741,6 +877,7 @@ export async function runPackageJsonScript(
|
|||||||
env: getEnvForPackageManager({
|
env: getEnvForPackageManager({
|
||||||
cliType,
|
cliType,
|
||||||
lockfileVersion,
|
lockfileVersion,
|
||||||
|
packageJsonPackageManager: packageJson?.packageManager,
|
||||||
nodeVersion: undefined,
|
nodeVersion: undefined,
|
||||||
env: cloneEnv(process.env, spawnOpts?.env),
|
env: cloneEnv(process.env, spawnOpts?.env),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"probes": [
|
"probes": [
|
||||||
{
|
{
|
||||||
"path": "/",
|
"path": "/",
|
||||||
"mustContain": "pnpm version: 6",
|
"mustContain": "pnpm version: 7",
|
||||||
"logMustContain": "pnpm run build"
|
"logMustContain": "pnpm run build"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { delimiter } from 'path';
|
import { delimiter } from 'path';
|
||||||
import { getEnvForPackageManager, getPathForPackageManager } from '../src';
|
import { getEnvForPackageManager, getPathForPackageManager } from '../src';
|
||||||
|
import { getPathOverrideForPackageManager } from '../src/fs/run-user-scripts';
|
||||||
|
|
||||||
describe('Test `getEnvForPackageManager()`', () => {
|
describe('Test `getEnvForPackageManager()`', () => {
|
||||||
let consoleLogSpy: jest.SpyInstance;
|
let consoleLogSpy: jest.SpyInstance;
|
||||||
@@ -34,6 +35,7 @@ describe('Test `getEnvForPackageManager()`', () => {
|
|||||||
args: {
|
args: {
|
||||||
cliType: 'npm',
|
cliType: 'npm',
|
||||||
nodeVersion: { major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
nodeVersion: { major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
lockfileVersion: 1,
|
lockfileVersion: 1,
|
||||||
env: {
|
env: {
|
||||||
FOO: 'bar',
|
FOO: 'bar',
|
||||||
@@ -50,6 +52,7 @@ describe('Test `getEnvForPackageManager()`', () => {
|
|||||||
args: {
|
args: {
|
||||||
cliType: 'npm',
|
cliType: 'npm',
|
||||||
nodeVersion: { major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
nodeVersion: { major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
lockfileVersion: 2,
|
lockfileVersion: 2,
|
||||||
env: {
|
env: {
|
||||||
FOO: 'bar',
|
FOO: 'bar',
|
||||||
@@ -68,6 +71,7 @@ describe('Test `getEnvForPackageManager()`', () => {
|
|||||||
args: {
|
args: {
|
||||||
cliType: 'npm',
|
cliType: 'npm',
|
||||||
nodeVersion: { major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
nodeVersion: { major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
||||||
|
packageJsonPackageManager: 'pnpm@latest',
|
||||||
lockfileVersion: 2,
|
lockfileVersion: 2,
|
||||||
env: {
|
env: {
|
||||||
FOO: 'bar',
|
FOO: 'bar',
|
||||||
@@ -86,6 +90,7 @@ describe('Test `getEnvForPackageManager()`', () => {
|
|||||||
args: {
|
args: {
|
||||||
cliType: 'npm',
|
cliType: 'npm',
|
||||||
nodeVersion: { major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
nodeVersion: { major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
lockfileVersion: 2,
|
lockfileVersion: 2,
|
||||||
env: {
|
env: {
|
||||||
FOO: 'bar',
|
FOO: 'bar',
|
||||||
@@ -104,6 +109,7 @@ describe('Test `getEnvForPackageManager()`', () => {
|
|||||||
args: {
|
args: {
|
||||||
cliType: 'npm',
|
cliType: 'npm',
|
||||||
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
lockfileVersion: 2,
|
lockfileVersion: 2,
|
||||||
env: {
|
env: {
|
||||||
FOO: 'bar',
|
FOO: 'bar',
|
||||||
@@ -122,6 +128,7 @@ describe('Test `getEnvForPackageManager()`', () => {
|
|||||||
args: {
|
args: {
|
||||||
cliType: 'yarn',
|
cliType: 'yarn',
|
||||||
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
lockfileVersion: 2,
|
lockfileVersion: 2,
|
||||||
env: {
|
env: {
|
||||||
FOO: 'bar',
|
FOO: 'bar',
|
||||||
@@ -139,6 +146,7 @@ describe('Test `getEnvForPackageManager()`', () => {
|
|||||||
args: {
|
args: {
|
||||||
cliType: 'yarn',
|
cliType: 'yarn',
|
||||||
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
lockfileVersion: 2,
|
lockfileVersion: 2,
|
||||||
env: {
|
env: {
|
||||||
FOO: 'bar',
|
FOO: 'bar',
|
||||||
@@ -157,6 +165,7 @@ describe('Test `getEnvForPackageManager()`', () => {
|
|||||||
args: {
|
args: {
|
||||||
cliType: 'pnpm',
|
cliType: 'pnpm',
|
||||||
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
lockfileVersion: 5.4,
|
lockfileVersion: 5.4,
|
||||||
env: {
|
env: {
|
||||||
FOO: 'bar',
|
FOO: 'bar',
|
||||||
@@ -171,11 +180,52 @@ describe('Test `getEnvForPackageManager()`', () => {
|
|||||||
'Detected `pnpm-lock.yaml` version 5.4 generated by pnpm 7',
|
'Detected `pnpm-lock.yaml` version 5.4 generated by pnpm 7',
|
||||||
consoleWarnOutput: null,
|
consoleWarnOutput: null,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'should set path if pnpm 8 is detected',
|
||||||
|
args: {
|
||||||
|
cliType: 'pnpm',
|
||||||
|
nodeVersion: { major: 18, range: '18.x', runtime: 'nodejs18.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
|
lockfileVersion: 6.0,
|
||||||
|
env: {
|
||||||
|
FOO: 'bar',
|
||||||
|
PATH: 'foo',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {
|
||||||
|
FOO: 'bar',
|
||||||
|
PATH: `/pnpm8/node_modules/.bin${delimiter}foo`,
|
||||||
|
},
|
||||||
|
consoleLogOutput:
|
||||||
|
'Detected `pnpm-lock.yaml` version 6 generated by pnpm 8',
|
||||||
|
consoleWarnOutput: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should set path if pnpm 8 is detected',
|
||||||
|
args: {
|
||||||
|
cliType: 'pnpm',
|
||||||
|
nodeVersion: { major: 18, range: '18.x', runtime: 'nodejs18.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
|
lockfileVersion: 9.0,
|
||||||
|
env: {
|
||||||
|
FOO: 'bar',
|
||||||
|
PATH: 'foo',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {
|
||||||
|
FOO: 'bar',
|
||||||
|
PATH: `/pnpm9/node_modules/.bin${delimiter}foo`,
|
||||||
|
},
|
||||||
|
consoleLogOutput:
|
||||||
|
'Detected `pnpm-lock.yaml` version 9 generated by pnpm 9',
|
||||||
|
consoleWarnOutput: null,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'should set path if bun v1 is detected',
|
name: 'should set path if bun v1 is detected',
|
||||||
args: {
|
args: {
|
||||||
cliType: 'bun',
|
cliType: 'bun',
|
||||||
nodeVersion: { major: 18, range: '18.x', runtime: 'nodejs18.x' },
|
nodeVersion: { major: 18, range: '18.x', runtime: 'nodejs18.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
lockfileVersion: 0,
|
lockfileVersion: 0,
|
||||||
env: {
|
env: {
|
||||||
FOO: 'bar',
|
FOO: 'bar',
|
||||||
@@ -195,6 +245,7 @@ describe('Test `getEnvForPackageManager()`', () => {
|
|||||||
args: {
|
args: {
|
||||||
cliType: 'pnpm',
|
cliType: 'pnpm',
|
||||||
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
||||||
|
packageJsonPackageManager: 'npm@latest',
|
||||||
lockfileVersion: 5.4,
|
lockfileVersion: 5.4,
|
||||||
env: {
|
env: {
|
||||||
FOO: 'bar',
|
FOO: 'bar',
|
||||||
@@ -213,6 +264,7 @@ describe('Test `getEnvForPackageManager()`', () => {
|
|||||||
args: {
|
args: {
|
||||||
cliType: 'pnpm',
|
cliType: 'pnpm',
|
||||||
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
lockfileVersion: 5.4,
|
lockfileVersion: 5.4,
|
||||||
env: {
|
env: {
|
||||||
FOO: 'bar',
|
FOO: 'bar',
|
||||||
@@ -226,27 +278,12 @@ describe('Test `getEnvForPackageManager()`', () => {
|
|||||||
consoleLogOutput: null,
|
consoleLogOutput: null,
|
||||||
consoleWarnOutput: null,
|
consoleWarnOutput: null,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'should not set path if pnpm 6 is detected',
|
|
||||||
args: {
|
|
||||||
cliType: 'pnpm',
|
|
||||||
nodeVersion: { major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
|
||||||
lockfileVersion: 5.3,
|
|
||||||
env: {
|
|
||||||
FOO: 'bar',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
want: {
|
|
||||||
FOO: 'bar',
|
|
||||||
},
|
|
||||||
consoleLogOutput: null,
|
|
||||||
consoleWarnOutput: null,
|
|
||||||
},
|
|
||||||
])('$name', ({ args, want, consoleLogOutput, consoleWarnOutput }) => {
|
])('$name', ({ args, want, consoleLogOutput, consoleWarnOutput }) => {
|
||||||
expect(
|
expect(
|
||||||
getEnvForPackageManager({
|
getEnvForPackageManager({
|
||||||
cliType: args.cliType,
|
cliType: args.cliType,
|
||||||
lockfileVersion: args.lockfileVersion,
|
lockfileVersion: args.lockfileVersion,
|
||||||
|
packageJsonPackageManager: args.packageJsonPackageManager,
|
||||||
nodeVersion: args.nodeVersion,
|
nodeVersion: args.nodeVersion,
|
||||||
env: args.env,
|
env: args.env,
|
||||||
})
|
})
|
||||||
@@ -268,11 +305,210 @@ describe('Test `getEnvForPackageManager()`', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Test `getPathForPackageManager()`', () => {
|
describe('Test `getPathOverrideForPackageManager()`', () => {
|
||||||
test.each<{
|
test.each<{
|
||||||
name: string;
|
name: string;
|
||||||
args: Parameters<typeof getEnvForPackageManager>[0];
|
args: Parameters<typeof getEnvForPackageManager>[0];
|
||||||
want: unknown;
|
want: unknown;
|
||||||
|
}>([
|
||||||
|
{
|
||||||
|
name: 'should do nothing to env for npm < 6 and node < 16',
|
||||||
|
args: {
|
||||||
|
cliType: 'npm',
|
||||||
|
nodeVersion: { major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
|
lockfileVersion: 1,
|
||||||
|
env: {
|
||||||
|
FOO: 'bar',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {
|
||||||
|
detectedLockfile: undefined,
|
||||||
|
detectedPackageManager: undefined,
|
||||||
|
path: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should set path if npm 7+ is detected and node < 16',
|
||||||
|
args: {
|
||||||
|
cliType: 'npm',
|
||||||
|
nodeVersion: { major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
|
lockfileVersion: 2,
|
||||||
|
env: {
|
||||||
|
FOO: 'bar',
|
||||||
|
PATH: 'foo',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {
|
||||||
|
detectedLockfile: 'package-lock.json',
|
||||||
|
detectedPackageManager: 'npm 7+',
|
||||||
|
path: '/node16/bin-npm7',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should not set npm path if corepack enabled',
|
||||||
|
args: {
|
||||||
|
cliType: 'npm',
|
||||||
|
nodeVersion: { major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
||||||
|
packageJsonPackageManager: 'pnpm@latest',
|
||||||
|
lockfileVersion: 2,
|
||||||
|
env: {
|
||||||
|
FOO: 'bar',
|
||||||
|
ENABLE_EXPERIMENTAL_COREPACK: '1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {
|
||||||
|
detectedLockfile: undefined,
|
||||||
|
detectedPackageManager: undefined,
|
||||||
|
path: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'should not set path if node is 16 and npm 7+ is detected',
|
||||||
|
args: {
|
||||||
|
cliType: 'npm',
|
||||||
|
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
|
lockfileVersion: 2,
|
||||||
|
env: {
|
||||||
|
FOO: 'bar',
|
||||||
|
PATH: 'foo',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {
|
||||||
|
detectedLockfile: undefined,
|
||||||
|
detectedPackageManager: undefined,
|
||||||
|
path: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should not set path if pnpm 6 is detected',
|
||||||
|
args: {
|
||||||
|
cliType: 'pnpm',
|
||||||
|
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
|
lockfileVersion: 5.3, // detects as pnpm@6, which is the default
|
||||||
|
env: {
|
||||||
|
FOO: 'bar',
|
||||||
|
PATH: 'foo',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {
|
||||||
|
detectedLockfile: undefined,
|
||||||
|
detectedPackageManager: undefined,
|
||||||
|
path: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should set path if pnpm 7+ is detected',
|
||||||
|
args: {
|
||||||
|
cliType: 'pnpm',
|
||||||
|
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
|
lockfileVersion: 5.4,
|
||||||
|
env: {
|
||||||
|
FOO: 'bar',
|
||||||
|
PATH: 'foo',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {
|
||||||
|
detectedLockfile: 'pnpm-lock.yaml',
|
||||||
|
detectedPackageManager: 'pnpm 7',
|
||||||
|
path: '/pnpm7/node_modules/.bin',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should set path if pnpm 8 is detected',
|
||||||
|
args: {
|
||||||
|
cliType: 'pnpm',
|
||||||
|
nodeVersion: { major: 18, range: '18.x', runtime: 'nodejs18.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
|
lockfileVersion: 6.1,
|
||||||
|
env: {
|
||||||
|
FOO: 'bar',
|
||||||
|
PATH: 'foo',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {
|
||||||
|
detectedLockfile: 'pnpm-lock.yaml',
|
||||||
|
detectedPackageManager: 'pnpm 8',
|
||||||
|
path: '/pnpm8/node_modules/.bin',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should set path if pnpm 9 is detected',
|
||||||
|
args: {
|
||||||
|
cliType: 'pnpm',
|
||||||
|
nodeVersion: { major: 18, range: '18.x', runtime: 'nodejs18.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
|
lockfileVersion: 7.0,
|
||||||
|
env: {
|
||||||
|
FOO: 'bar',
|
||||||
|
PATH: 'foo',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {
|
||||||
|
detectedLockfile: 'pnpm-lock.yaml',
|
||||||
|
detectedPackageManager: 'pnpm 9',
|
||||||
|
path: '/pnpm9/node_modules/.bin',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should set path if bun v1 is detected',
|
||||||
|
args: {
|
||||||
|
cliType: 'bun',
|
||||||
|
nodeVersion: { major: 18, range: '18.x', runtime: 'nodejs18.x' },
|
||||||
|
packageJsonPackageManager: undefined,
|
||||||
|
lockfileVersion: 0,
|
||||||
|
env: {
|
||||||
|
FOO: 'bar',
|
||||||
|
PATH: '/usr/local/bin',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {
|
||||||
|
detectedLockfile: 'bun.lockb',
|
||||||
|
detectedPackageManager: 'Bun',
|
||||||
|
path: '/bun1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'should not set pnpm path if corepack is enabled',
|
||||||
|
args: {
|
||||||
|
cliType: 'pnpm',
|
||||||
|
nodeVersion: { major: 16, range: '16.x', runtime: 'nodejs16.x' },
|
||||||
|
packageJsonPackageManager: 'npm@latest',
|
||||||
|
lockfileVersion: 5.4,
|
||||||
|
env: {
|
||||||
|
FOO: 'bar',
|
||||||
|
ENABLE_EXPERIMENTAL_COREPACK: '1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: {
|
||||||
|
detectedLockfile: undefined,
|
||||||
|
detectedPackageManager: undefined,
|
||||||
|
path: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])('$name', ({ args, want }) => {
|
||||||
|
expect(
|
||||||
|
getPathOverrideForPackageManager({
|
||||||
|
cliType: args.cliType,
|
||||||
|
lockfileVersion: args.lockfileVersion,
|
||||||
|
// naive assumption that enabling corepack as a feature means it's used, but this is fine for tests
|
||||||
|
corepackEnabled: Boolean(args.env.ENABLE_EXPERIMENTAL_COREPACK),
|
||||||
|
nodeVersion: args.nodeVersion,
|
||||||
|
})
|
||||||
|
).toStrictEqual(want);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Test `getPathForPackageManager()`', () => {
|
||||||
|
test.each<{
|
||||||
|
name: string;
|
||||||
|
args: Parameters<typeof getPathForPackageManager>[0];
|
||||||
|
want: unknown;
|
||||||
}>([
|
}>([
|
||||||
{
|
{
|
||||||
name: 'should do nothing to env for npm < 6 and node < 16',
|
name: 'should do nothing to env for npm < 6 and node < 16',
|
||||||
@@ -470,23 +706,6 @@ describe('Test `getPathForPackageManager()`', () => {
|
|||||||
yarnNodeLinker: undefined,
|
yarnNodeLinker: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'should not set path if pnpm 6 is detected',
|
|
||||||
args: {
|
|
||||||
cliType: 'pnpm',
|
|
||||||
nodeVersion: { major: 14, range: '14.x', runtime: 'nodejs14.x' },
|
|
||||||
lockfileVersion: 5.3,
|
|
||||||
env: {
|
|
||||||
FOO: 'bar',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
want: {
|
|
||||||
detectedLockfile: undefined,
|
|
||||||
detectedPackageManager: undefined,
|
|
||||||
path: undefined,
|
|
||||||
yarnNodeLinker: undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
])('$name', ({ args, want }) => {
|
])('$name', ({ args, want }) => {
|
||||||
expect(
|
expect(
|
||||||
getPathForPackageManager({
|
getPathForPackageManager({
|
||||||
|
|||||||
21
packages/build-utils/test/unit.test.ts
vendored
21
packages/build-utils/test/unit.test.ts
vendored
@@ -221,6 +221,21 @@ it('should warn when package.json engines is greater than', async () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should warn when project settings gets overrided', async () => {
|
||||||
|
expect(
|
||||||
|
await getNodeVersion(
|
||||||
|
path.join(__dirname, 'pkg-engine-node-greaterthan'),
|
||||||
|
undefined,
|
||||||
|
{ nodeVersion: '16.x' },
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
).toHaveProperty('range', '20.x');
|
||||||
|
expect(warningMessages).toStrictEqual([
|
||||||
|
'Warning: Due to "engines": { "node": ">=16" } in your `package.json` file, the Node.js Version defined in your Project Settings ("16.x") will not apply. Learn More: http://vercel.link/node-version',
|
||||||
|
'Warning: Detected "engines": { "node": ">=16" } in your `package.json` that will automatically upgrade when a new major Node.js Version is released. Learn More: http://vercel.link/node-version',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('should not warn when package.json engines matches project setting from config', async () => {
|
it('should not warn when package.json engines matches project setting from config', async () => {
|
||||||
expect(
|
expect(
|
||||||
await getNodeVersion(
|
await getNodeVersion(
|
||||||
@@ -271,7 +286,7 @@ it('should throw for discontinued versions', async () => {
|
|||||||
// Mock a future date so that Node 16 becomes discontinued
|
// Mock a future date so that Node 16 becomes discontinued
|
||||||
const realDateNow = Date.now;
|
const realDateNow = Date.now;
|
||||||
try {
|
try {
|
||||||
global.Date.now = () => new Date('2024-07-16').getTime();
|
global.Date.now = () => new Date('2025-03-01').getTime();
|
||||||
|
|
||||||
expect(getSupportedNodeVersion('8.10.x', false)).rejects.toThrow();
|
expect(getSupportedNodeVersion('8.10.x', false)).rejects.toThrow();
|
||||||
expect(getSupportedNodeVersion('8.10.x', true)).rejects.toThrow();
|
expect(getSupportedNodeVersion('8.10.x', true)).rejects.toThrow();
|
||||||
@@ -341,8 +356,8 @@ it('should warn for deprecated versions, soon to be discontinued', async () => {
|
|||||||
'Error: Node.js version 12.x has reached End-of-Life. Deployments created on or after 2022-10-03 will fail to build. Please set Node.js Version to 20.x in your Project Settings to use Node.js 20.',
|
'Error: Node.js version 12.x has reached End-of-Life. Deployments created on or after 2022-10-03 will fail to build. Please set Node.js Version to 20.x in your Project Settings to use Node.js 20.',
|
||||||
'Error: Node.js version 14.x has reached End-of-Life. Deployments created on or after 2023-08-15 will fail to build. Please set "engines": { "node": "20.x" } in your `package.json` file to use Node.js 20.',
|
'Error: Node.js version 14.x has reached End-of-Life. Deployments created on or after 2023-08-15 will fail to build. Please set "engines": { "node": "20.x" } in your `package.json` file to use Node.js 20.',
|
||||||
'Error: Node.js version 14.x has reached End-of-Life. Deployments created on or after 2023-08-15 will fail to build. Please set Node.js Version to 20.x in your Project Settings to use Node.js 20.',
|
'Error: Node.js version 14.x has reached End-of-Life. Deployments created on or after 2023-08-15 will fail to build. Please set Node.js Version to 20.x in your Project Settings to use Node.js 20.',
|
||||||
'Error: Node.js version 16.x has reached End-of-Life. Deployments created on or after 2024-06-15 will fail to build. Please set "engines": { "node": "20.x" } in your `package.json` file to use Node.js 20.',
|
'Error: Node.js version 16.x has reached End-of-Life. Deployments created on or after 2025-02-28 will fail to build. Please set "engines": { "node": "20.x" } in your `package.json` file to use Node.js 20.',
|
||||||
'Error: Node.js version 16.x has reached End-of-Life. Deployments created on or after 2024-06-15 will fail to build. Please set Node.js Version to 20.x in your Project Settings to use Node.js 20.',
|
'Error: Node.js version 16.x has reached End-of-Life. Deployments created on or after 2025-02-28 will fail to build. Please set Node.js Version to 20.x in your Project Settings to use Node.js 20.',
|
||||||
]);
|
]);
|
||||||
} finally {
|
} finally {
|
||||||
global.Date.now = realDateNow;
|
global.Date.now = realDateNow;
|
||||||
|
|||||||
@@ -1,5 +1,134 @@
|
|||||||
# vercel
|
# vercel
|
||||||
|
|
||||||
|
## 34.2.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`3eb9d8c89`](https://github.com/vercel/vercel/commit/3eb9d8c8929592960d88e0395e2a2443f7304d6b), [`83741a0eb`](https://github.com/vercel/vercel/commit/83741a0eb9e44457b083e8790a11eb89984e6357)]:
|
||||||
|
- @vercel/python@4.3.0
|
||||||
|
- @vercel/build-utils@8.2.1
|
||||||
|
- @vercel/node@3.1.6
|
||||||
|
- @vercel/static-build@2.5.10
|
||||||
|
|
||||||
|
## 34.2.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Don't create streaming lambdas for pages router routes ([#11660](https://github.com/vercel/vercel/pull/11660))
|
||||||
|
|
||||||
|
- Updated dependencies [[`c9d53d4e3`](https://github.com/vercel/vercel/commit/c9d53d4e3e4591b9b6bde86100564c9ee4c6d1d4), [`5f561f8cf`](https://github.com/vercel/vercel/commit/5f561f8cfa4720801a5cf4598f193ab34539abb9)]:
|
||||||
|
- @vercel/next@4.2.14
|
||||||
|
|
||||||
|
## 34.2.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Fix related to erroring when a prefetch route is not provided but the route is PPR enabled ([#11638](https://github.com/vercel/vercel/pull/11638))
|
||||||
|
|
||||||
|
- Updated dependencies [[`8e44ef5b9`](https://github.com/vercel/vercel/commit/8e44ef5b9d2cdbe743c7f1e3534f182465fed9bf), [`61e6af374`](https://github.com/vercel/vercel/commit/61e6af3740296c11015d0c3da84ee205020b0ea6)]:
|
||||||
|
- @vercel/next@4.2.13
|
||||||
|
|
||||||
|
## 34.2.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Support incremental PPR for large applications ([#11625](https://github.com/vercel/vercel/pull/11625))
|
||||||
|
|
||||||
|
- Updated dependencies [[`73e558913`](https://github.com/vercel/vercel/commit/73e558913ab30ba097d7536a12fa8a7c967479f0)]:
|
||||||
|
- @vercel/next@4.2.12
|
||||||
|
|
||||||
|
## 34.2.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- Stop sending system environment variables in dev ([#11526](https://github.com/vercel/vercel/pull/11526))
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`d3c1267e2`](https://github.com/vercel/vercel/commit/d3c1267e24082789ea6382cf6af81dd40df288ff), [`ccd7eb1fb`](https://github.com/vercel/vercel/commit/ccd7eb1fb78f7ac9effdbe1935de3bda82c97fe3)]:
|
||||||
|
- @vercel/build-utils@8.2.0
|
||||||
|
- @vercel/node@3.1.5
|
||||||
|
- @vercel/static-build@2.5.9
|
||||||
|
|
||||||
|
## 34.1.14
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`ad6945435`](https://github.com/vercel/vercel/commit/ad69454352b519b2b0ed326f245c779530554bf2)]:
|
||||||
|
- @vercel/build-utils@8.1.3
|
||||||
|
- @vercel/node@3.1.4
|
||||||
|
- @vercel/static-build@2.5.8
|
||||||
|
|
||||||
|
## 34.1.13
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`1682ad43d`](https://github.com/vercel/vercel/commit/1682ad43d0064b22b1248a7e946746b838f00076)]:
|
||||||
|
- @vercel/build-utils@8.1.2
|
||||||
|
- @vercel/node@3.1.3
|
||||||
|
- @vercel/static-build@2.5.7
|
||||||
|
|
||||||
|
## 34.1.12
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`67afc2608`](https://github.com/vercel/vercel/commit/67afc26085e2ebdaa33a8cbce112afec4cb1c4f5), [`2f7a6ed5f`](https://github.com/vercel/vercel/commit/2f7a6ed5f92d454000f92247d3b6548e2064f4e6)]:
|
||||||
|
- @vercel/next@4.2.11
|
||||||
|
- @vercel/build-utils@8.1.1
|
||||||
|
- @vercel/node@3.1.2
|
||||||
|
- @vercel/static-build@2.5.6
|
||||||
|
|
||||||
|
## 34.1.11
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`5014b1e82`](https://github.com/vercel/vercel/commit/5014b1e82a46181baeb727ffe6d14000b6a4b1d7), [`18d1703d5`](https://github.com/vercel/vercel/commit/18d1703d5b4f2adc61fd56011f874c393fa57d0d), [`e87d4c14d`](https://github.com/vercel/vercel/commit/e87d4c14d0e718281f9ba91c9ec1cc6e142d383d), [`bc5fd4115`](https://github.com/vercel/vercel/commit/bc5fd41158ec9f36e5db1fe749589adcbaec6950)]:
|
||||||
|
- @vercel/build-utils@8.1.0
|
||||||
|
- @vercel/next@4.2.10
|
||||||
|
- @vercel/redwood@2.0.9
|
||||||
|
- @vercel/remix-builder@2.1.6
|
||||||
|
- @vercel/node@3.1.1
|
||||||
|
- @vercel/static-build@2.5.5
|
||||||
|
|
||||||
|
## 34.1.10
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`119f80e96`](https://github.com/vercel/vercel/commit/119f80e9611a7a5a755aa689502dcdab323194aa), [`11584b0e9`](https://github.com/vercel/vercel/commit/11584b0e9b55f312f34d0d6467ab498e472ac9df), [`3023122d4`](https://github.com/vercel/vercel/commit/3023122d4e0dd292340d9e9e61ef232baf6e610d), [`0e774b6be`](https://github.com/vercel/vercel/commit/0e774b6be0c832213a64124e1f4fc6d150e87d9f)]:
|
||||||
|
- @vercel/next@4.2.9
|
||||||
|
- @vercel/static-build@2.5.4
|
||||||
|
|
||||||
|
## 34.1.9
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`5a532a5b9`](https://github.com/vercel/vercel/commit/5a532a5b948994ba04783ac560357eed9f94a3f3), [`50fc27ba5`](https://github.com/vercel/vercel/commit/50fc27ba5773870956300bbbaffbe387d549bc12), [`c1d852295`](https://github.com/vercel/vercel/commit/c1d85229509dd319a1f11beb940a759113564d33), [`a5ea04154`](https://github.com/vercel/vercel/commit/a5ea04154ba26ee4e635d8953aa4f0d9d82d3a96)]:
|
||||||
|
- @vercel/next@4.2.8
|
||||||
|
- @vercel/node@3.1.0
|
||||||
|
|
||||||
|
## 34.1.8
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`52e435aa5`](https://github.com/vercel/vercel/commit/52e435aa5d7b4014d19477969ad5cbfbe94aa76f), [`124846a3e`](https://github.com/vercel/vercel/commit/124846a3e65a3bf1ae82327fd4ba2b132674fb39), [`dc974b679`](https://github.com/vercel/vercel/commit/dc974b6797de0b6e90373c92e1f2bbdafcfc6687), [`58c6755e0`](https://github.com/vercel/vercel/commit/58c6755e0c12cae2ce55978b7bf8722133151196)]:
|
||||||
|
- @vercel/next@4.2.7
|
||||||
|
- @vercel/static-build@2.5.3
|
||||||
|
|
||||||
|
## 34.1.7
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`3420ba015`](https://github.com/vercel/vercel/commit/3420ba0153dcabffef7114ba2361fb0f3c43a7b3)]:
|
||||||
|
- @vercel/next@4.2.6
|
||||||
|
|
||||||
|
## 34.1.6
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`b1adaf76e`](https://github.com/vercel/vercel/commit/b1adaf76ec17d1bbfe30a2bf65405bd886fa9bcf), [`3fb97d1d2`](https://github.com/vercel/vercel/commit/3fb97d1d270e835ce34a687bd234ea53dfe446a2)]:
|
||||||
|
- @vercel/next@4.2.5
|
||||||
|
- @vercel/static-build@2.5.2
|
||||||
|
|
||||||
## 34.1.5
|
## 34.1.5
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vercel",
|
"name": "vercel",
|
||||||
"version": "34.1.5",
|
"version": "34.2.4",
|
||||||
"preferGlobal": true,
|
"preferGlobal": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"description": "The command-line interface for Vercel",
|
"description": "The command-line interface for Vercel",
|
||||||
@@ -12,8 +12,8 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jest --reporters=default --reporters=jest-junit --env node --verbose --bail",
|
"test": "jest --reporters=default --reporters=jest-junit --env node --verbose --bail",
|
||||||
"vitest-unit-run": "pnpm vitest",
|
"vitest-run": "vitest",
|
||||||
"vitest-unit": "pnpm jest test/unit/ --listTests",
|
"vitest-unit": "jest test/unit/ --listTests",
|
||||||
"test-e2e": "rimraf test/fixtures/integration && pnpm test test/integration-1.test.ts test/integration-2.test.ts test/integration-3.test.ts",
|
"test-e2e": "rimraf test/fixtures/integration && pnpm test test/integration-1.test.ts test/integration-2.test.ts test/integration-3.test.ts",
|
||||||
"test-dev": "pnpm test test/dev/",
|
"test-dev": "pnpm test test/dev/",
|
||||||
"coverage": "codecov",
|
"coverage": "codecov",
|
||||||
@@ -32,17 +32,17 @@
|
|||||||
"node": ">= 16"
|
"node": ">= 16"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/build-utils": "8.0.0",
|
"@vercel/build-utils": "8.2.1",
|
||||||
"@vercel/fun": "1.1.0",
|
"@vercel/fun": "1.1.0",
|
||||||
"@vercel/go": "3.1.1",
|
"@vercel/go": "3.1.1",
|
||||||
"@vercel/hydrogen": "1.0.2",
|
"@vercel/hydrogen": "1.0.2",
|
||||||
"@vercel/next": "4.2.4",
|
"@vercel/next": "4.2.14",
|
||||||
"@vercel/node": "3.0.28",
|
"@vercel/node": "3.1.6",
|
||||||
"@vercel/python": "4.2.0",
|
"@vercel/python": "4.3.0",
|
||||||
"@vercel/redwood": "2.0.8",
|
"@vercel/redwood": "2.0.9",
|
||||||
"@vercel/remix-builder": "2.1.5",
|
"@vercel/remix-builder": "2.1.6",
|
||||||
"@vercel/ruby": "2.1.0",
|
"@vercel/ruby": "2.1.0",
|
||||||
"@vercel/static-build": "2.5.1",
|
"@vercel/static-build": "2.5.10",
|
||||||
"chokidar": "3.3.1"
|
"chokidar": "3.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -92,8 +92,8 @@
|
|||||||
"@types/yauzl-promise": "2.1.0",
|
"@types/yauzl-promise": "2.1.0",
|
||||||
"@vercel-internals/constants": "1.0.4",
|
"@vercel-internals/constants": "1.0.4",
|
||||||
"@vercel-internals/get-package-json": "1.0.0",
|
"@vercel-internals/get-package-json": "1.0.0",
|
||||||
"@vercel-internals/types": "1.0.31",
|
"@vercel-internals/types": "1.0.37",
|
||||||
"@vercel/client": "13.2.2",
|
"@vercel/client": "13.2.8",
|
||||||
"@vercel/error-utils": "2.0.2",
|
"@vercel/error-utils": "2.0.2",
|
||||||
"@vercel/frameworks": "3.0.2",
|
"@vercel/frameworks": "3.0.2",
|
||||||
"@vercel/fs-detectors": "5.2.3",
|
"@vercel/fs-detectors": "5.2.3",
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export const buildCommand: Command = {
|
|||||||
name: 'prod',
|
name: 'prod',
|
||||||
description: 'Build a production deployment',
|
description: 'Build a production deployment',
|
||||||
shorthand: null,
|
shorthand: null,
|
||||||
type: String,
|
type: Boolean,
|
||||||
deprecated: false,
|
deprecated: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ import type { VercelConfig } from '@vercel/client';
|
|||||||
import pull from '../pull';
|
import pull from '../pull';
|
||||||
import { staticFiles as getFiles } from '../../util/get-files';
|
import { staticFiles as getFiles } from '../../util/get-files';
|
||||||
import Client from '../../util/client';
|
import Client from '../../util/client';
|
||||||
import getArgs from '../../util/get-args';
|
import { parseArguments } from '../../util/get-args';
|
||||||
import cmd from '../../util/output/cmd';
|
import cmd from '../../util/output/cmd';
|
||||||
import * as cli from '../../util/pkg-name';
|
import * as cli from '../../util/pkg-name';
|
||||||
import cliPkg from '../../util/pkg';
|
import cliPkg from '../../util/pkg';
|
||||||
@@ -66,12 +66,13 @@ import {
|
|||||||
import { importBuilders } from '../../util/build/import-builders';
|
import { importBuilders } from '../../util/build/import-builders';
|
||||||
import { initCorepack, cleanupCorepack } from '../../util/build/corepack';
|
import { initCorepack, cleanupCorepack } from '../../util/build/corepack';
|
||||||
import { sortBuilders } from '../../util/build/sort-builders';
|
import { sortBuilders } from '../../util/build/sort-builders';
|
||||||
import { toEnumerableError } from '../../util/error';
|
import { handleError, toEnumerableError } from '../../util/error';
|
||||||
import { validateConfig } from '../../util/validate-config';
|
import { validateConfig } from '../../util/validate-config';
|
||||||
import { setMonorepoDefaultSettings } from '../../util/build/monorepo';
|
import { setMonorepoDefaultSettings } from '../../util/build/monorepo';
|
||||||
import { help } from '../help';
|
import { help } from '../help';
|
||||||
import { buildCommand } from './command';
|
import { buildCommand } from './command';
|
||||||
import { scrubArgv } from '../../util/build/scrub-argv';
|
import { scrubArgv } from '../../util/build/scrub-argv';
|
||||||
|
import { getFlagsSpecification } from '../../util/get-flags-specification';
|
||||||
|
|
||||||
type BuildResult = BuildResultV2 | BuildResultV3;
|
type BuildResult = BuildResultV2 | BuildResultV3;
|
||||||
|
|
||||||
@@ -133,22 +134,26 @@ export default async function main(client: Client): Promise<number> {
|
|||||||
process.env.__VERCEL_BUILD_RUNNING = '1';
|
process.env.__VERCEL_BUILD_RUNNING = '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse CLI args
|
let parsedArgs = null;
|
||||||
const argv = getArgs(client.argv.slice(2), {
|
|
||||||
'--output': String,
|
|
||||||
'--prod': Boolean,
|
|
||||||
'--yes': Boolean,
|
|
||||||
'-y': '--yes',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (argv['--help']) {
|
const flagsSpecification = getFlagsSpecification(buildCommand.options);
|
||||||
|
|
||||||
|
// Parse CLI args
|
||||||
|
try {
|
||||||
|
parsedArgs = parseArguments(client.argv.slice(2), flagsSpecification);
|
||||||
|
} catch (error) {
|
||||||
|
handleError(error);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedArgs.flags['--help']) {
|
||||||
output.print(help(buildCommand, { columns: client.stderr.columns }));
|
output.print(help(buildCommand, { columns: client.stderr.columns }));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build `target` influences which environment variables will be used
|
// Build `target` influences which environment variables will be used
|
||||||
const target = argv['--prod'] ? 'production' : 'preview';
|
const target = parsedArgs.flags['--prod'] ? 'production' : 'preview';
|
||||||
const yes = Boolean(argv['--yes']);
|
const yes = Boolean(parsedArgs.flags['--yes']);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await validateNpmrc(cwd);
|
await validateNpmrc(cwd);
|
||||||
@@ -213,8 +218,8 @@ export default async function main(client: Client): Promise<number> {
|
|||||||
|
|
||||||
// Delete output directory from potential previous build
|
// Delete output directory from potential previous build
|
||||||
const defaultOutputDir = join(cwd, projectRootDirectory, OUTPUT_DIR);
|
const defaultOutputDir = join(cwd, projectRootDirectory, OUTPUT_DIR);
|
||||||
const outputDir = argv['--output']
|
const outputDir = parsedArgs.flags['--output']
|
||||||
? resolve(argv['--output'])
|
? resolve(parsedArgs.flags['--output'])
|
||||||
: defaultOutputDir;
|
: defaultOutputDir;
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
fs.remove(outputDir),
|
fs.remove(outputDir),
|
||||||
|
|||||||
2
packages/cli/src/util/env/get-env-records.ts
vendored
2
packages/cli/src/util/env/get-env-records.ts
vendored
@@ -70,7 +70,7 @@ export async function pullEnvRecords(
|
|||||||
);
|
);
|
||||||
const query = new URLSearchParams();
|
const query = new URLSearchParams();
|
||||||
|
|
||||||
let url = `/v1/env/pull/${projectId}`;
|
let url = `/v2/env/pull/${projectId}`;
|
||||||
|
|
||||||
if (target) {
|
if (target) {
|
||||||
url += `/${encodeURIComponent(target)}`;
|
url += `/${encodeURIComponent(target)}`;
|
||||||
|
|||||||
32
packages/cli/test/fixtures/e2e/cli-extension-exit-code/package-lock.json
generated
vendored
Normal file
32
packages/cli/test/fixtures/e2e/cli-extension-exit-code/package-lock.json
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "cli-extension-exit-code",
|
||||||
|
"lockfileVersion": 2,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"dependencies": {
|
||||||
|
"cli-extension-fail": "file:../cli-extension-fail"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../cli-extension-fail": {
|
||||||
|
"bin": {
|
||||||
|
"vercel-fail": "bin.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../cli-extension-whoami": {
|
||||||
|
"extraneous": true,
|
||||||
|
"bin": {
|
||||||
|
"vercel-mywhoami": "bin.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cli-extension-fail": {
|
||||||
|
"resolved": "../cli-extension-fail",
|
||||||
|
"link": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"cli-extension-fail": {
|
||||||
|
"version": "file:../cli-extension-fail"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
packages/cli/test/fixtures/e2e/cli-extension-exit-code/package.json
vendored
Normal file
6
packages/cli/test/fixtures/e2e/cli-extension-exit-code/package.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"cli-extension-fail": "file:../cli-extension-fail"
|
||||||
|
}
|
||||||
|
}
|
||||||
2
packages/cli/test/fixtures/e2e/cli-extension-fail/bin.js
vendored
Executable file
2
packages/cli/test/fixtures/e2e/cli-extension-fail/bin.js
vendored
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
process.exit(6);
|
||||||
6
packages/cli/test/fixtures/e2e/cli-extension-fail/package.json
vendored
Normal file
6
packages/cli/test/fixtures/e2e/cli-extension-fail/package.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "cli-extension-fail",
|
||||||
|
"bin": {
|
||||||
|
"vercel-fail": "bin.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
30
packages/cli/test/integration-1.test.ts
vendored
30
packages/cli/test/integration-1.test.ts
vendored
@@ -917,9 +917,9 @@ test('Deploy `api-env` fixture and test `vercel env` command', async () => {
|
|||||||
expect(homeJson['MY_STDIN_VAR']).toBe('{"expect":"quotes"}');
|
expect(homeJson['MY_STDIN_VAR']).toBe('{"expect":"quotes"}');
|
||||||
expect(homeJson['MY_DECRYPTABLE_SECRET_ENV']).toBe('decryptable value');
|
expect(homeJson['MY_DECRYPTABLE_SECRET_ENV']).toBe('decryptable value');
|
||||||
|
|
||||||
// system env vars are automatically exposed
|
// system env vars are hidden in dev
|
||||||
expect(apiJson['VERCEL']).toBe('1');
|
expect(apiJson['VERCEL']).toBeUndefined();
|
||||||
expect(homeJson['VERCEL']).toBe('1');
|
expect(homeJson['VERCEL']).toBeUndefined();
|
||||||
|
|
||||||
// sleep before kill, otherwise the dev process doesn't clean up and exit properly
|
// sleep before kill, otherwise the dev process doesn't clean up and exit properly
|
||||||
await sleep(100);
|
await sleep(100);
|
||||||
@@ -949,7 +949,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async () => {
|
|||||||
async function vcEnvPullFetchSystemVars() {
|
async function vcEnvPullFetchSystemVars() {
|
||||||
const { exitCode, stdout, stderr } = await execCli(
|
const { exitCode, stdout, stderr } = await execCli(
|
||||||
binaryPath,
|
binaryPath,
|
||||||
['env', 'pull', '-y'],
|
['env', 'pull', '-y', '--environment', 'production'],
|
||||||
{
|
{
|
||||||
cwd: target,
|
cwd: target,
|
||||||
}
|
}
|
||||||
@@ -963,7 +963,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async () => {
|
|||||||
|
|
||||||
expect(lines).toContain('VERCEL="1"');
|
expect(lines).toContain('VERCEL="1"');
|
||||||
expect(lines).toContain('VERCEL_URL=""');
|
expect(lines).toContain('VERCEL_URL=""');
|
||||||
expect(lines).toContain('VERCEL_ENV="development"');
|
expect(lines).toContain('VERCEL_ENV="production"');
|
||||||
expect(lines).toContain('VERCEL_GIT_PROVIDER=""');
|
expect(lines).toContain('VERCEL_GIT_PROVIDER=""');
|
||||||
expect(lines).toContain('VERCEL_GIT_REPO_SLUG=""');
|
expect(lines).toContain('VERCEL_GIT_REPO_SLUG=""');
|
||||||
}
|
}
|
||||||
@@ -980,22 +980,24 @@ test('Deploy `api-env` fixture and test `vercel env` command', async () => {
|
|||||||
const localhostNoProtocol = localhost[0].slice('http://'.length);
|
const localhostNoProtocol = localhost[0].slice('http://'.length);
|
||||||
|
|
||||||
const apiJson = await apiRes.json();
|
const apiJson = await apiRes.json();
|
||||||
expect(apiJson['VERCEL']).toBe('1');
|
// environment variables are not set in dev
|
||||||
|
expect(apiJson['VERCEL']).toBeUndefined();
|
||||||
|
expect(apiJson['VERCEL_ENV']).toBeUndefined();
|
||||||
|
expect(apiJson['VERCEL_GIT_PROVIDER']).toBeUndefined();
|
||||||
|
expect(apiJson['VERCEL_GIT_REPO_SLUG']).toBeUndefined();
|
||||||
|
// except for these because vc dev
|
||||||
expect(apiJson['VERCEL_URL']).toBe(localhostNoProtocol);
|
expect(apiJson['VERCEL_URL']).toBe(localhostNoProtocol);
|
||||||
expect(apiJson['VERCEL_ENV']).toBe('development');
|
|
||||||
expect(apiJson['VERCEL_REGION']).toBe('dev1');
|
expect(apiJson['VERCEL_REGION']).toBe('dev1');
|
||||||
expect(apiJson['VERCEL_GIT_PROVIDER']).toBe('');
|
|
||||||
expect(apiJson['VERCEL_GIT_REPO_SLUG']).toBe('');
|
|
||||||
|
|
||||||
const homeUrl = localhost[0];
|
const homeUrl = localhost[0];
|
||||||
const homeRes = await fetch(homeUrl);
|
const homeRes = await fetch(homeUrl);
|
||||||
const homeJson = await homeRes.json();
|
const homeJson = await homeRes.json();
|
||||||
expect(homeJson['VERCEL']).toBe('1');
|
expect(homeJson['VERCEL']).toBeUndefined();
|
||||||
expect(homeJson['VERCEL_URL']).toBe(localhostNoProtocol);
|
expect(homeJson['VERCEL_URL']).toBe(localhostNoProtocol);
|
||||||
expect(homeJson['VERCEL_ENV']).toBe('development');
|
expect(homeJson['VERCEL_ENV']).toBeUndefined();
|
||||||
expect(homeJson['VERCEL_REGION']).toBe(undefined);
|
expect(homeJson['VERCEL_REGION']).toBeUndefined();
|
||||||
expect(homeJson['VERCEL_GIT_PROVIDER']).toBe('');
|
expect(homeJson['VERCEL_GIT_PROVIDER']).toBeUndefined();
|
||||||
expect(homeJson['VERCEL_GIT_REPO_SLUG']).toBe('');
|
expect(homeJson['VERCEL_GIT_REPO_SLUG']).toBeUndefined();
|
||||||
|
|
||||||
// sleep before kill, otherwise the dev process doesn't clean up and exit properly
|
// sleep before kill, otherwise the dev process doesn't clean up and exit properly
|
||||||
await sleep(100);
|
await sleep(100);
|
||||||
|
|||||||
15
packages/cli/test/integration-3.test.ts
vendored
15
packages/cli/test/integration-3.test.ts
vendored
@@ -1255,7 +1255,7 @@ test('fail to deploy a Lambda with an incorrect value for maxDuration', async ()
|
|||||||
|
|
||||||
expect(output.exitCode, formatOutput(output)).toBe(1);
|
expect(output.exitCode, formatOutput(output)).toBe(1);
|
||||||
expect(output.stderr).toMatch(
|
expect(output.stderr).toMatch(
|
||||||
/maxDuration must be between 1 second and 10 seconds/gm
|
/maxDuration must be between \d+ second and \d+ seconds/gm
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1327,6 +1327,19 @@ test('should invoke CLI extension', async () => {
|
|||||||
expect(output.stdout, formatted).toContain(`Username: ${contextName}`);
|
expect(output.stdout, formatted).toContain(`Username: ${contextName}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should pass through exit code for CLI extension', async () => {
|
||||||
|
const fixture = path.join(__dirname, 'fixtures/e2e/cli-extension-exit-code');
|
||||||
|
|
||||||
|
// Ensure the `.bin` is populated in the fixture
|
||||||
|
await runNpmInstall(fixture);
|
||||||
|
|
||||||
|
const output = await execCli(binaryPath, ['fail'], {
|
||||||
|
cwd: fixture,
|
||||||
|
reject: false,
|
||||||
|
});
|
||||||
|
expect(output.exitCode).toEqual(6);
|
||||||
|
});
|
||||||
|
|
||||||
// NOTE: Order matters here. This must be the last test in the file.
|
// NOTE: Order matters here. This must be the last test in the file.
|
||||||
test('default command should prompt login with empty auth.json', async () => {
|
test('default command should prompt login with empty auth.json', async () => {
|
||||||
await clearAuthConfig();
|
await clearAuthConfig();
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ export function useProject(
|
|||||||
res.json(project);
|
res.json(project);
|
||||||
});
|
});
|
||||||
client.scenario.get(
|
client.scenario.get(
|
||||||
`/v1/env/pull/${project.id}/:target?/:gitBranch?`,
|
`/v2/env/pull/${project.id}/:target?/:gitBranch?`,
|
||||||
(req, res) => {
|
(req, res) => {
|
||||||
const target =
|
const target =
|
||||||
typeof req.params.target === 'string'
|
typeof req.params.target === 'string'
|
||||||
@@ -390,7 +390,7 @@ function exposeSystemEnvs(
|
|||||||
) {
|
) {
|
||||||
const envs: Env = {};
|
const envs: Env = {};
|
||||||
|
|
||||||
if (autoExposeSystemEnvs) {
|
if (autoExposeSystemEnvs && target !== 'development') {
|
||||||
envs['VERCEL'] = '1';
|
envs['VERCEL'] = '1';
|
||||||
envs['VERCEL_ENV'] = target || 'development';
|
envs['VERCEL_ENV'] = target || 'development';
|
||||||
|
|
||||||
|
|||||||
@@ -205,10 +205,17 @@ describe('env', () => {
|
|||||||
});
|
});
|
||||||
const cwd = setupUnitFixture('vercel-env-pull');
|
const cwd = setupUnitFixture('vercel-env-pull');
|
||||||
client.cwd = cwd;
|
client.cwd = cwd;
|
||||||
client.setArgv('env', 'pull', 'other.env', '--yes');
|
client.setArgv(
|
||||||
|
'env',
|
||||||
|
'pull',
|
||||||
|
'other.env',
|
||||||
|
'--yes',
|
||||||
|
'--environment',
|
||||||
|
'production'
|
||||||
|
);
|
||||||
const exitCodePromise = env(client);
|
const exitCodePromise = env(client);
|
||||||
await expect(client.stderr).toOutput(
|
await expect(client.stderr).toOutput(
|
||||||
'Downloading `development` Environment Variables for Project vercel-env-pull'
|
'Downloading `production` Environment Variables for Project vercel-env-pull'
|
||||||
);
|
);
|
||||||
await expect(client.stderr).toOutput('Created other.env file');
|
await expect(client.stderr).toOutput('Created other.env file');
|
||||||
await expect(client.stderr).not.toOutput('and added it to .gitignore');
|
await expect(client.stderr).not.toOutput('and added it to .gitignore');
|
||||||
@@ -218,10 +225,44 @@ describe('env', () => {
|
|||||||
|
|
||||||
const productionFileHasVercelEnv = rawDevEnv
|
const productionFileHasVercelEnv = rawDevEnv
|
||||||
.toString()
|
.toString()
|
||||||
.includes('VERCEL_ENV="development"');
|
.includes('VERCEL_ENV="production"');
|
||||||
expect(productionFileHasVercelEnv).toBeTruthy();
|
expect(productionFileHasVercelEnv).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not expose system env variables in dev', async () => {
|
||||||
|
useUser();
|
||||||
|
useTeams('team_dummy');
|
||||||
|
useProject({
|
||||||
|
...defaultProject,
|
||||||
|
id: 'vercel-env-pull',
|
||||||
|
name: 'vercel-env-pull',
|
||||||
|
autoExposeSystemEnvs: true,
|
||||||
|
});
|
||||||
|
const cwd = setupUnitFixture('vercel-env-pull');
|
||||||
|
client.cwd = cwd;
|
||||||
|
client.setArgv('env', 'pull', 'other.env', '--yes');
|
||||||
|
const exitCodePromise = env(client);
|
||||||
|
await expect(client.stderr).toOutput(
|
||||||
|
'Downloading `development` Environment Variables for Project vercel-env-pull'
|
||||||
|
);
|
||||||
|
await expect(client.stderr).toOutput('Created other.env file');
|
||||||
|
await expect(client.stderr).not.toOutput('and added it to .gitignore');
|
||||||
|
await expect(exitCodePromise).resolves.toEqual(0);
|
||||||
|
|
||||||
|
const devEnv = (
|
||||||
|
await fs.readFile(path.join(cwd, 'other.env'))
|
||||||
|
).toString();
|
||||||
|
|
||||||
|
const devFileHasVercelEnv = [
|
||||||
|
'VERCEL',
|
||||||
|
'VERCEL_ENV',
|
||||||
|
'VERCEL_URL',
|
||||||
|
'VERCEL_REGION',
|
||||||
|
'VERCEL_DEPLOYMENT_ID',
|
||||||
|
].some(envVar => devEnv.includes(envVar));
|
||||||
|
expect(devFileHasVercelEnv).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
it('should show a delta string', async () => {
|
it('should show a delta string', async () => {
|
||||||
const cwd = setupUnitFixture('vercel-env-pull-delta');
|
const cwd = setupUnitFixture('vercel-env-pull-delta');
|
||||||
client.cwd = cwd;
|
client.cwd = cwd;
|
||||||
|
|||||||
@@ -1,5 +1,47 @@
|
|||||||
# @vercel/client
|
# @vercel/client
|
||||||
|
|
||||||
|
## 13.2.8
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`83741a0eb`](https://github.com/vercel/vercel/commit/83741a0eb9e44457b083e8790a11eb89984e6357)]:
|
||||||
|
- @vercel/build-utils@8.2.1
|
||||||
|
|
||||||
|
## 13.2.7
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`d3c1267e2`](https://github.com/vercel/vercel/commit/d3c1267e24082789ea6382cf6af81dd40df288ff), [`ccd7eb1fb`](https://github.com/vercel/vercel/commit/ccd7eb1fb78f7ac9effdbe1935de3bda82c97fe3)]:
|
||||||
|
- @vercel/build-utils@8.2.0
|
||||||
|
|
||||||
|
## 13.2.6
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`ad6945435`](https://github.com/vercel/vercel/commit/ad69454352b519b2b0ed326f245c779530554bf2)]:
|
||||||
|
- @vercel/build-utils@8.1.3
|
||||||
|
|
||||||
|
## 13.2.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`1682ad43d`](https://github.com/vercel/vercel/commit/1682ad43d0064b22b1248a7e946746b838f00076)]:
|
||||||
|
- @vercel/build-utils@8.1.2
|
||||||
|
|
||||||
|
## 13.2.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`2f7a6ed5f`](https://github.com/vercel/vercel/commit/2f7a6ed5f92d454000f92247d3b6548e2064f4e6)]:
|
||||||
|
- @vercel/build-utils@8.1.1
|
||||||
|
|
||||||
|
## 13.2.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`5014b1e82`](https://github.com/vercel/vercel/commit/5014b1e82a46181baeb727ffe6d14000b6a4b1d7)]:
|
||||||
|
- @vercel/build-utils@8.1.0
|
||||||
|
|
||||||
## 13.2.2
|
## 13.2.2
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/client",
|
"name": "@vercel/client",
|
||||||
"version": "13.2.2",
|
"version": "13.2.8",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist/index.d.ts",
|
||||||
"homepage": "https://vercel.com",
|
"homepage": "https://vercel.com",
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
"typescript": "4.9.5"
|
"typescript": "4.9.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/build-utils": "8.0.0",
|
"@vercel/build-utils": "8.2.1",
|
||||||
"@vercel/error-utils": "2.0.2",
|
"@vercel/error-utils": "2.0.2",
|
||||||
"@vercel/routing-utils": "3.1.0",
|
"@vercel/routing-utils": "3.1.0",
|
||||||
"@zeit/fetch": "5.2.0",
|
"@zeit/fetch": "5.2.0",
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
"@types/minimatch": "3.0.5",
|
"@types/minimatch": "3.0.5",
|
||||||
"@types/node": "14.18.33",
|
"@types/node": "14.18.33",
|
||||||
"@types/semver": "7.3.10",
|
"@types/semver": "7.3.10",
|
||||||
"@vercel/build-utils": "8.0.0",
|
"@vercel/build-utils": "8.2.1",
|
||||||
"jest-junit": "16.0.0",
|
"jest-junit": "16.0.0",
|
||||||
"typescript": "4.9.5"
|
"typescript": "4.9.5"
|
||||||
}
|
}
|
||||||
|
|||||||
19
packages/functions/CHANGELOG.md
Normal file
19
packages/functions/CHANGELOG.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# @vercel/functions
|
||||||
|
|
||||||
|
## 1.0.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Convert package to CommonJS ([#11569](https://github.com/vercel/vercel/pull/11569))
|
||||||
|
|
||||||
|
## 1.0.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Don't throw error if context is missing ([`0817527f9`](https://github.com/vercel/vercel/commit/0817527f9e9d0d5fceb73f21e695089349a96d3e))
|
||||||
|
|
||||||
|
## 1.0.0
|
||||||
|
|
||||||
|
### Major Changes
|
||||||
|
|
||||||
|
- Initial release ([#11553](https://github.com/vercel/vercel/pull/11553))
|
||||||
17
packages/functions/index.d.ts
vendored
Normal file
17
packages/functions/index.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* Extends the lifetime of the request handler for the lifetime of the given {@link Promise}
|
||||||
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/ExtendableEvent/waitUntil
|
||||||
|
*
|
||||||
|
* @param promise The promise to wait for.
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* import { waitUntil } from '@vercel/functions';
|
||||||
|
*
|
||||||
|
* export function GET(request) {
|
||||||
|
* waitUntil(fetch('https://vercel.com'));
|
||||||
|
* return new Response('OK');
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function waitUntil(promise: Promise<unknown>): void;
|
||||||
16
packages/functions/index.js
Normal file
16
packages/functions/index.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/* global globalThis */
|
||||||
|
|
||||||
|
exports.waitUntil = promise => {
|
||||||
|
if (
|
||||||
|
promise === null ||
|
||||||
|
typeof promise !== 'object' ||
|
||||||
|
typeof promise.then !== 'function'
|
||||||
|
) {
|
||||||
|
throw new TypeError(
|
||||||
|
`waitUntil can only be called with a Promise, got ${typeof promise}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = globalThis[Symbol.for('@vercel/request-context')]?.get?.() ?? {};
|
||||||
|
ctx.waitUntil?.(promise);
|
||||||
|
};
|
||||||
42
packages/functions/index.test.js
Normal file
42
packages/functions/index.test.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/* global globalThis */
|
||||||
|
|
||||||
|
import { vi, expect, test } from 'vitest';
|
||||||
|
|
||||||
|
import { waitUntil } from '.';
|
||||||
|
|
||||||
|
test.each([
|
||||||
|
{},
|
||||||
|
() => {},
|
||||||
|
function () {},
|
||||||
|
NaN,
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
undefined,
|
||||||
|
null,
|
||||||
|
[],
|
||||||
|
'▲',
|
||||||
|
])('waitUntil throws when called with %s', input => {
|
||||||
|
expect(() => waitUntil(input)).toThrow(TypeError);
|
||||||
|
expect(() => waitUntil(input)).toThrow(
|
||||||
|
`waitUntil can only be called with a Promise, got ${typeof input}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.each([null, undefined, {}])(
|
||||||
|
'waitUntil does not throw an error when context is %s',
|
||||||
|
input => {
|
||||||
|
const promise = Promise.resolve();
|
||||||
|
globalThis[Symbol.for('@vercel/request-context')] = input;
|
||||||
|
expect(() => waitUntil(promise)).not.toThrow();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
test('waitUntil calls ctx.waitUntil when available', async () => {
|
||||||
|
const promise = Promise.resolve();
|
||||||
|
const waitUntilMock = vi.fn().mockReturnValue(promise);
|
||||||
|
globalThis[Symbol.for('@vercel/request-context')] = {
|
||||||
|
get: () => ({ waitUntil: waitUntilMock }),
|
||||||
|
};
|
||||||
|
waitUntil(promise);
|
||||||
|
expect(waitUntilMock).toHaveBeenCalledWith(promise);
|
||||||
|
});
|
||||||
33
packages/functions/package.json
Normal file
33
packages/functions/package.json
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "@vercel/functions",
|
||||||
|
"description": "Runtime functions to be used with your Vercel Functions",
|
||||||
|
"homepage": "https://vercel.com",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"types": "index.d.ts",
|
||||||
|
"main": "index.js",
|
||||||
|
"repository": {
|
||||||
|
"directory": "packages/functions",
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/vercel/vercel.git"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/vercel/vercel/issues"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"vitest": "1.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 16"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"index.d.ts",
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"test": "vitest"
|
||||||
|
},
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,47 @@
|
|||||||
# @vercel/gatsby-plugin-vercel-builder
|
# @vercel/gatsby-plugin-vercel-builder
|
||||||
|
|
||||||
|
## 2.0.32
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`83741a0eb`](https://github.com/vercel/vercel/commit/83741a0eb9e44457b083e8790a11eb89984e6357)]:
|
||||||
|
- @vercel/build-utils@8.2.1
|
||||||
|
|
||||||
|
## 2.0.31
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`d3c1267e2`](https://github.com/vercel/vercel/commit/d3c1267e24082789ea6382cf6af81dd40df288ff), [`ccd7eb1fb`](https://github.com/vercel/vercel/commit/ccd7eb1fb78f7ac9effdbe1935de3bda82c97fe3)]:
|
||||||
|
- @vercel/build-utils@8.2.0
|
||||||
|
|
||||||
|
## 2.0.30
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`ad6945435`](https://github.com/vercel/vercel/commit/ad69454352b519b2b0ed326f245c779530554bf2)]:
|
||||||
|
- @vercel/build-utils@8.1.3
|
||||||
|
|
||||||
|
## 2.0.29
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`1682ad43d`](https://github.com/vercel/vercel/commit/1682ad43d0064b22b1248a7e946746b838f00076)]:
|
||||||
|
- @vercel/build-utils@8.1.2
|
||||||
|
|
||||||
|
## 2.0.28
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`2f7a6ed5f`](https://github.com/vercel/vercel/commit/2f7a6ed5f92d454000f92247d3b6548e2064f4e6)]:
|
||||||
|
- @vercel/build-utils@8.1.1
|
||||||
|
|
||||||
|
## 2.0.27
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`5014b1e82`](https://github.com/vercel/vercel/commit/5014b1e82a46181baeb727ffe6d14000b6a4b1d7)]:
|
||||||
|
- @vercel/build-utils@8.1.0
|
||||||
|
|
||||||
## 2.0.26
|
## 2.0.26
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/gatsby-plugin-vercel-builder",
|
"name": "@vercel/gatsby-plugin-vercel-builder",
|
||||||
"version": "2.0.26",
|
"version": "2.0.32",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"files": [
|
"files": [
|
||||||
"dist",
|
"dist",
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sinclair/typebox": "0.25.24",
|
"@sinclair/typebox": "0.25.24",
|
||||||
"@vercel/build-utils": "8.0.0",
|
"@vercel/build-utils": "8.2.1",
|
||||||
"@vercel/routing-utils": "3.1.0",
|
"@vercel/routing-utils": "3.1.0",
|
||||||
"esbuild": "0.14.47",
|
"esbuild": "0.14.47",
|
||||||
"etag": "1.8.1",
|
"etag": "1.8.1",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
"@types/node-fetch": "^2.3.0",
|
"@types/node-fetch": "^2.3.0",
|
||||||
"@types/tar": "6.1.5",
|
"@types/tar": "6.1.5",
|
||||||
"@types/yauzl-promise": "2.1.0",
|
"@types/yauzl-promise": "2.1.0",
|
||||||
"@vercel/build-utils": "8.0.0",
|
"@vercel/build-utils": "8.2.1",
|
||||||
"async-retry": "1.3.3",
|
"async-retry": "1.3.3",
|
||||||
"execa": "^1.0.0",
|
"execa": "^1.0.0",
|
||||||
"fs-extra": "^7.0.0",
|
"fs-extra": "^7.0.0",
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "27.5.1",
|
"@types/jest": "27.5.1",
|
||||||
"@types/node": "14.18.33",
|
"@types/node": "14.18.33",
|
||||||
"@vercel/build-utils": "8.0.0",
|
"@vercel/build-utils": "8.2.1",
|
||||||
"execa": "3.2.0",
|
"execa": "3.2.0",
|
||||||
"fs-extra": "11.1.0",
|
"fs-extra": "11.1.0",
|
||||||
"jest-junit": "16.0.0"
|
"jest-junit": "16.0.0"
|
||||||
|
|||||||
@@ -51,11 +51,15 @@ export const build: BuildV2 = async ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const spawnOpts = getSpawnOptions(meta, nodeVersion);
|
const spawnOpts = getSpawnOptions(meta, nodeVersion);
|
||||||
const { cliType, lockfileVersion } = await scanParentDirs(entrypointDir);
|
const { cliType, lockfileVersion, packageJson } = await scanParentDirs(
|
||||||
|
entrypointDir,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
spawnOpts.env = getEnvForPackageManager({
|
spawnOpts.env = getEnvForPackageManager({
|
||||||
cliType,
|
cliType,
|
||||||
lockfileVersion,
|
lockfileVersion,
|
||||||
|
packageJsonPackageManager: packageJson?.packageManager,
|
||||||
nodeVersion,
|
nodeVersion,
|
||||||
env: spawnOpts.env || {},
|
env: spawnOpts.env || {},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,83 @@
|
|||||||
# @vercel/next
|
# @vercel/next
|
||||||
|
|
||||||
|
## 4.2.14
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Don't create streaming lambdas for pages router routes ([#11660](https://github.com/vercel/vercel/pull/11660))
|
||||||
|
|
||||||
|
- Ensure user rewrites still match to action outputs ([#11628](https://github.com/vercel/vercel/pull/11628))
|
||||||
|
|
||||||
|
## 4.2.13
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Fix static case for detecting when a page supports PPR ([#11635](https://github.com/vercel/vercel/pull/11635))
|
||||||
|
|
||||||
|
- Fix related to erroring when a prefetch route is not provided but the route is PPR enabled ([#11638](https://github.com/vercel/vercel/pull/11638))
|
||||||
|
|
||||||
|
## 4.2.12
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Support incremental PPR for large applications ([#11625](https://github.com/vercel/vercel/pull/11625))
|
||||||
|
|
||||||
|
## 4.2.11
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- normalize source file locations for special metadata files ([#11579](https://github.com/vercel/vercel/pull/11579))
|
||||||
|
|
||||||
|
## 4.2.10
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- skip action rewrites for RSC requests ([#11576](https://github.com/vercel/vercel/pull/11576))
|
||||||
|
|
||||||
|
- Bump `@vercel/nft@0.27.0` ([#11580](https://github.com/vercel/vercel/pull/11580))
|
||||||
|
|
||||||
|
## 4.2.9
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Support incremental partial prerendering ([#11560](https://github.com/vercel/vercel/pull/11560))
|
||||||
|
|
||||||
|
- ensure `.action` outputs are created for edge functions ([#11568](https://github.com/vercel/vercel/pull/11568))
|
||||||
|
|
||||||
|
- ([#11566](https://github.com/vercel/vercel/pull/11566))
|
||||||
|
|
||||||
|
## 4.2.8
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Fix missing initial RSC headers ([#11552](https://github.com/vercel/vercel/pull/11552))
|
||||||
|
|
||||||
|
- Remove .prefetch.rsc rewrites for non-PPR ([#11540](https://github.com/vercel/vercel/pull/11540))
|
||||||
|
|
||||||
|
- [next] rename middleware manifest env ([#11549](https://github.com/vercel/vercel/pull/11549))
|
||||||
|
|
||||||
|
## 4.2.7
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Fix missing .rsc outputs for pages prerenders ([#11503](https://github.com/vercel/vercel/pull/11503))
|
||||||
|
|
||||||
|
- Fix base path app index RSC handling ([#11528](https://github.com/vercel/vercel/pull/11528))
|
||||||
|
|
||||||
|
- Fix interception routes PPR route handling ([#11527](https://github.com/vercel/vercel/pull/11527))
|
||||||
|
|
||||||
|
## 4.2.6
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- [next] Update test fixture version ([#11514](https://github.com/vercel/vercel/pull/11514))
|
||||||
|
|
||||||
|
## 4.2.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Only rewrite next-action requests to `.action` handlers ([#11504](https://github.com/vercel/vercel/pull/11504))
|
||||||
|
|
||||||
## 4.2.4
|
## 4.2.4
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@vercel/next",
|
"name": "@vercel/next",
|
||||||
"version": "4.2.4",
|
"version": "4.2.14",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"main": "./dist/index",
|
"main": "./dist/index",
|
||||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
"dist"
|
"dist"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/nft": "0.26.4"
|
"@vercel/nft": "0.27.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/aws-lambda": "8.10.19",
|
"@types/aws-lambda": "8.10.19",
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
"@types/semver": "6.0.0",
|
"@types/semver": "6.0.0",
|
||||||
"@types/text-table": "0.2.1",
|
"@types/text-table": "0.2.1",
|
||||||
"@types/webpack-sources": "3.2.0",
|
"@types/webpack-sources": "3.2.0",
|
||||||
"@vercel/build-utils": "8.0.0",
|
"@vercel/build-utils": "8.2.1",
|
||||||
"@vercel/routing-utils": "3.1.0",
|
"@vercel/routing-utils": "3.1.0",
|
||||||
"async-sema": "3.0.1",
|
"async-sema": "3.0.1",
|
||||||
"buffer-crc32": "0.2.13",
|
"buffer-crc32": "0.2.13",
|
||||||
|
|||||||
@@ -257,10 +257,15 @@ export const build: BuildV2 = async ({
|
|||||||
const nextVersionRange = await getNextVersionRange(entryPath);
|
const nextVersionRange = await getNextVersionRange(entryPath);
|
||||||
const nodeVersion = await getNodeVersion(entryPath, undefined, config, meta);
|
const nodeVersion = await getNodeVersion(entryPath, undefined, config, meta);
|
||||||
const spawnOpts = getSpawnOptions(meta, nodeVersion);
|
const spawnOpts = getSpawnOptions(meta, nodeVersion);
|
||||||
const { cliType, lockfileVersion } = await scanParentDirs(entryPath);
|
const { cliType, lockfileVersion, packageJson } = await scanParentDirs(
|
||||||
|
entryPath,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
spawnOpts.env = getEnvForPackageManager({
|
spawnOpts.env = getEnvForPackageManager({
|
||||||
cliType,
|
cliType,
|
||||||
lockfileVersion,
|
lockfileVersion,
|
||||||
|
packageJsonPackageManager: packageJson?.packageManager,
|
||||||
nodeVersion,
|
nodeVersion,
|
||||||
env: spawnOpts.env || {},
|
env: spawnOpts.env || {},
|
||||||
});
|
});
|
||||||
@@ -1353,6 +1358,11 @@ export const build: BuildV2 = async ({
|
|||||||
experimentalPPRRoutes.add(route);
|
experimentalPPRRoutes.add(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isAppPPREnabled = requiredServerFilesManifest
|
||||||
|
? requiredServerFilesManifest.config.experimental?.ppr === true ||
|
||||||
|
requiredServerFilesManifest.config.experimental?.ppr === 'incremental'
|
||||||
|
: false;
|
||||||
|
|
||||||
if (requiredServerFilesManifest) {
|
if (requiredServerFilesManifest) {
|
||||||
if (!routesManifest) {
|
if (!routesManifest) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -1408,6 +1418,7 @@ export const build: BuildV2 = async ({
|
|||||||
hasIsr500Page,
|
hasIsr500Page,
|
||||||
variantsManifest,
|
variantsManifest,
|
||||||
experimentalPPRRoutes,
|
experimentalPPRRoutes,
|
||||||
|
isAppPPREnabled,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1927,7 +1938,8 @@ export const build: BuildV2 = async ({
|
|||||||
canUsePreviewMode,
|
canUsePreviewMode,
|
||||||
bypassToken: prerenderManifest.bypassToken || '',
|
bypassToken: prerenderManifest.bypassToken || '',
|
||||||
isServerMode,
|
isServerMode,
|
||||||
experimentalPPRRoutes,
|
isAppPPREnabled: false,
|
||||||
|
hasActionOutputSupport: false,
|
||||||
}).then(arr =>
|
}).then(arr =>
|
||||||
localizeDynamicRoutes(
|
localizeDynamicRoutes(
|
||||||
arr,
|
arr,
|
||||||
@@ -1957,7 +1969,8 @@ export const build: BuildV2 = async ({
|
|||||||
canUsePreviewMode,
|
canUsePreviewMode,
|
||||||
bypassToken: prerenderManifest.bypassToken || '',
|
bypassToken: prerenderManifest.bypassToken || '',
|
||||||
isServerMode,
|
isServerMode,
|
||||||
experimentalPPRRoutes,
|
isAppPPREnabled: false,
|
||||||
|
hasActionOutputSupport: false,
|
||||||
}).then(arr =>
|
}).then(arr =>
|
||||||
arr.map(route => {
|
arr.map(route => {
|
||||||
route.src = route.src.replace('^', `^${dynamicPrefix}`);
|
route.src = route.src.replace('^', `^${dynamicPrefix}`);
|
||||||
@@ -2155,6 +2168,7 @@ export const build: BuildV2 = async ({
|
|||||||
appPathRoutesManifest,
|
appPathRoutesManifest,
|
||||||
isSharedLambdas,
|
isSharedLambdas,
|
||||||
canUsePreviewMode,
|
canUsePreviewMode,
|
||||||
|
isAppPPREnabled: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import {
|
|||||||
normalizePrefetches,
|
normalizePrefetches,
|
||||||
CreateLambdaFromPseudoLayersOptions,
|
CreateLambdaFromPseudoLayersOptions,
|
||||||
getPostponeResumePathname,
|
getPostponeResumePathname,
|
||||||
|
LambdaGroup,
|
||||||
MAX_UNCOMPRESSED_LAMBDA_SIZE,
|
MAX_UNCOMPRESSED_LAMBDA_SIZE,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import {
|
import {
|
||||||
@@ -68,6 +69,7 @@ const CORRECT_NOT_FOUND_ROUTES_VERSION = 'v12.0.1';
|
|||||||
const CORRECT_MIDDLEWARE_ORDER_VERSION = 'v12.1.7-canary.29';
|
const CORRECT_MIDDLEWARE_ORDER_VERSION = 'v12.1.7-canary.29';
|
||||||
const NEXT_DATA_MIDDLEWARE_RESOLVING_VERSION = 'v12.1.7-canary.33';
|
const NEXT_DATA_MIDDLEWARE_RESOLVING_VERSION = 'v12.1.7-canary.33';
|
||||||
const EMPTY_ALLOW_QUERY_FOR_PRERENDERED_VERSION = 'v12.2.0';
|
const EMPTY_ALLOW_QUERY_FOR_PRERENDERED_VERSION = 'v12.2.0';
|
||||||
|
const ACTION_OUTPUT_SUPPORT_VERSION = 'v14.2.2';
|
||||||
const CORRECTED_MANIFESTS_VERSION = 'v12.2.0';
|
const CORRECTED_MANIFESTS_VERSION = 'v12.2.0';
|
||||||
|
|
||||||
// Ideally this should be in a Next.js manifest so we can change it in
|
// Ideally this should be in a Next.js manifest so we can change it in
|
||||||
@@ -142,6 +144,7 @@ export async function serverBuild({
|
|||||||
requiredServerFilesManifest,
|
requiredServerFilesManifest,
|
||||||
variantsManifest,
|
variantsManifest,
|
||||||
experimentalPPRRoutes,
|
experimentalPPRRoutes,
|
||||||
|
isAppPPREnabled,
|
||||||
}: {
|
}: {
|
||||||
appPathRoutesManifest?: Record<string, string>;
|
appPathRoutesManifest?: Record<string, string>;
|
||||||
dynamicPages: string[];
|
dynamicPages: string[];
|
||||||
@@ -183,7 +186,15 @@ export async function serverBuild({
|
|||||||
requiredServerFilesManifest: NextRequiredServerFilesManifest;
|
requiredServerFilesManifest: NextRequiredServerFilesManifest;
|
||||||
variantsManifest: VariantsManifest | null;
|
variantsManifest: VariantsManifest | null;
|
||||||
experimentalPPRRoutes: ReadonlySet<string>;
|
experimentalPPRRoutes: ReadonlySet<string>;
|
||||||
|
isAppPPREnabled: boolean;
|
||||||
}): Promise<BuildResult> {
|
}): Promise<BuildResult> {
|
||||||
|
if (isAppPPREnabled) {
|
||||||
|
debug(
|
||||||
|
'experimentalPPRRoutes',
|
||||||
|
JSON.stringify(Array.from(experimentalPPRRoutes))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
lambdaPages = Object.assign({}, lambdaPages, lambdaAppPaths);
|
lambdaPages = Object.assign({}, lambdaPages, lambdaAppPaths);
|
||||||
|
|
||||||
const experimentalAllowBundling = Boolean(
|
const experimentalAllowBundling = Boolean(
|
||||||
@@ -199,6 +210,9 @@ export async function serverBuild({
|
|||||||
nextVersion,
|
nextVersion,
|
||||||
EMPTY_ALLOW_QUERY_FOR_PRERENDERED_VERSION
|
EMPTY_ALLOW_QUERY_FOR_PRERENDERED_VERSION
|
||||||
);
|
);
|
||||||
|
const hasActionOutputSupport =
|
||||||
|
semver.gte(nextVersion, ACTION_OUTPUT_SUPPORT_VERSION) &&
|
||||||
|
Boolean(process.env.NEXT_EXPERIMENTAL_STREAMING_ACTIONS);
|
||||||
const projectDir = requiredServerFilesManifest.relativeAppDir
|
const projectDir = requiredServerFilesManifest.relativeAppDir
|
||||||
? path.join(baseDir, requiredServerFilesManifest.relativeAppDir)
|
? path.join(baseDir, requiredServerFilesManifest.relativeAppDir)
|
||||||
: requiredServerFilesManifest.appDir || entryPath;
|
: requiredServerFilesManifest.appDir || entryPath;
|
||||||
@@ -212,10 +226,6 @@ export async function serverBuild({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const experimental = {
|
|
||||||
ppr: requiredServerFilesManifest.config.experimental?.ppr === true,
|
|
||||||
};
|
|
||||||
|
|
||||||
let appRscPrefetches: UnwrapPromise<ReturnType<typeof glob>> = {};
|
let appRscPrefetches: UnwrapPromise<ReturnType<typeof glob>> = {};
|
||||||
let appBuildTraces: UnwrapPromise<ReturnType<typeof glob>> = {};
|
let appBuildTraces: UnwrapPromise<ReturnType<typeof glob>> = {};
|
||||||
let appDir: string | null = null;
|
let appDir: string | null = null;
|
||||||
@@ -223,9 +233,7 @@ export async function serverBuild({
|
|||||||
if (appPathRoutesManifest) {
|
if (appPathRoutesManifest) {
|
||||||
appDir = path.join(pagesDir, '../app');
|
appDir = path.join(pagesDir, '../app');
|
||||||
appBuildTraces = await glob('**/*.js.nft.json', appDir);
|
appBuildTraces = await glob('**/*.js.nft.json', appDir);
|
||||||
|
appRscPrefetches = isAppPPREnabled
|
||||||
// TODO: maybe?
|
|
||||||
appRscPrefetches = experimental.ppr
|
|
||||||
? {}
|
? {}
|
||||||
: await glob(`**/*${RSC_PREFETCH_SUFFIX}`, appDir);
|
: await glob(`**/*${RSC_PREFETCH_SUFFIX}`, appDir);
|
||||||
|
|
||||||
@@ -244,9 +252,19 @@ export async function serverBuild({
|
|||||||
|
|
||||||
for (const rewrite of afterFilesRewrites) {
|
for (const rewrite of afterFilesRewrites) {
|
||||||
if (rewrite.src && rewrite.dest) {
|
if (rewrite.src && rewrite.dest) {
|
||||||
|
// ensures that userland rewrites are still correctly matched to their special outputs
|
||||||
|
// PPR should match .prefetch.rsc, .rsc, and .action
|
||||||
|
// non-PPR should match .rsc and .action
|
||||||
|
// we only add `.action` handling to the regex if flagged on in the build
|
||||||
|
const rscSuffix = isAppPPREnabled
|
||||||
|
? `(\\.prefetch)?\\.rsc${hasActionOutputSupport ? '|\\.action' : ''}`
|
||||||
|
: hasActionOutputSupport
|
||||||
|
? '(\\.action|\\.rsc)'
|
||||||
|
: '\\.rsc';
|
||||||
|
|
||||||
rewrite.src = rewrite.src.replace(
|
rewrite.src = rewrite.src.replace(
|
||||||
/\/?\(\?:\/\)\?/,
|
/\/?\(\?:\/\)\?/,
|
||||||
'(?<rscsuff>(\\.prefetch)?\\.rsc)?(?:/)?'
|
`(?<rscsuff>${rscSuffix})?(?:/)?`
|
||||||
);
|
);
|
||||||
let destQueryIndex = rewrite.dest.indexOf('?');
|
let destQueryIndex = rewrite.dest.indexOf('?');
|
||||||
|
|
||||||
@@ -926,11 +944,24 @@ export async function serverBuild({
|
|||||||
inversedAppPathManifest,
|
inversedAppPathManifest,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const appRouterStreamingActionLambdaGroups: LambdaGroup[] = [];
|
||||||
|
|
||||||
for (const group of appRouterLambdaGroups) {
|
for (const group of appRouterLambdaGroups) {
|
||||||
if (!group.isPrerenders || group.isExperimentalPPR) {
|
if (!group.isPrerenders || group.isExperimentalPPR) {
|
||||||
group.isStreaming = true;
|
group.isStreaming = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
group.isAppRouter = true;
|
group.isAppRouter = true;
|
||||||
|
|
||||||
|
// We create a streaming variant of the Prerender lambda group
|
||||||
|
// to support actions that are part of a Prerender
|
||||||
|
if (hasActionOutputSupport) {
|
||||||
|
appRouterStreamingActionLambdaGroups.push({
|
||||||
|
...group,
|
||||||
|
isActionLambda: true,
|
||||||
|
isStreaming: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const group of appRouteHandlersLambdaGroups) {
|
for (const group of appRouteHandlersLambdaGroups) {
|
||||||
@@ -967,18 +998,33 @@ export async function serverBuild({
|
|||||||
apiLambdaGroups: apiLambdaGroups.map(group => ({
|
apiLambdaGroups: apiLambdaGroups.map(group => ({
|
||||||
pages: group.pages,
|
pages: group.pages,
|
||||||
isPrerender: group.isPrerenders,
|
isPrerender: group.isPrerenders,
|
||||||
|
isStreaming: group.isStreaming,
|
||||||
|
isExperimentalPPR: group.isExperimentalPPR,
|
||||||
pseudoLayerBytes: group.pseudoLayerBytes,
|
pseudoLayerBytes: group.pseudoLayerBytes,
|
||||||
uncompressedLayerBytes: group.pseudoLayerUncompressedBytes,
|
uncompressedLayerBytes: group.pseudoLayerUncompressedBytes,
|
||||||
})),
|
})),
|
||||||
pageLambdaGroups: pageLambdaGroups.map(group => ({
|
pageLambdaGroups: pageLambdaGroups.map(group => ({
|
||||||
pages: group.pages,
|
pages: group.pages,
|
||||||
isPrerender: group.isPrerenders,
|
isPrerender: group.isPrerenders,
|
||||||
|
isStreaming: group.isStreaming,
|
||||||
|
isExperimentalPPR: group.isExperimentalPPR,
|
||||||
pseudoLayerBytes: group.pseudoLayerBytes,
|
pseudoLayerBytes: group.pseudoLayerBytes,
|
||||||
uncompressedLayerBytes: group.pseudoLayerUncompressedBytes,
|
uncompressedLayerBytes: group.pseudoLayerUncompressedBytes,
|
||||||
})),
|
})),
|
||||||
appRouterLambdaGroups: appRouterLambdaGroups.map(group => ({
|
appRouterLambdaGroups: appRouterLambdaGroups.map(group => ({
|
||||||
pages: group.pages,
|
pages: group.pages,
|
||||||
isPrerender: group.isPrerenders,
|
isPrerender: group.isPrerenders,
|
||||||
|
isStreaming: group.isStreaming,
|
||||||
|
isExperimentalPPR: group.isExperimentalPPR,
|
||||||
|
pseudoLayerBytes: group.pseudoLayerBytes,
|
||||||
|
uncompressedLayerBytes: group.pseudoLayerUncompressedBytes,
|
||||||
|
})),
|
||||||
|
appRouterStreamingPrerenderLambdaGroups:
|
||||||
|
appRouterStreamingActionLambdaGroups.map(group => ({
|
||||||
|
pages: group.pages,
|
||||||
|
isPrerender: group.isPrerenders,
|
||||||
|
isStreaming: group.isStreaming,
|
||||||
|
isExperimentalPPR: group.isExperimentalPPR,
|
||||||
pseudoLayerBytes: group.pseudoLayerBytes,
|
pseudoLayerBytes: group.pseudoLayerBytes,
|
||||||
uncompressedLayerBytes: group.pseudoLayerUncompressedBytes,
|
uncompressedLayerBytes: group.pseudoLayerUncompressedBytes,
|
||||||
})),
|
})),
|
||||||
@@ -986,6 +1032,8 @@ export async function serverBuild({
|
|||||||
group => ({
|
group => ({
|
||||||
pages: group.pages,
|
pages: group.pages,
|
||||||
isPrerender: group.isPrerenders,
|
isPrerender: group.isPrerenders,
|
||||||
|
isStreaming: group.isStreaming,
|
||||||
|
isExperimentalPPR: group.isExperimentalPPR,
|
||||||
pseudoLayerBytes: group.pseudoLayerBytes,
|
pseudoLayerBytes: group.pseudoLayerBytes,
|
||||||
uncompressedLayerBytes: group.pseudoLayerUncompressedBytes,
|
uncompressedLayerBytes: group.pseudoLayerUncompressedBytes,
|
||||||
})
|
})
|
||||||
@@ -999,6 +1047,7 @@ export async function serverBuild({
|
|||||||
const combinedGroups = [
|
const combinedGroups = [
|
||||||
...pageLambdaGroups,
|
...pageLambdaGroups,
|
||||||
...appRouterLambdaGroups,
|
...appRouterLambdaGroups,
|
||||||
|
...appRouterStreamingActionLambdaGroups,
|
||||||
...apiLambdaGroups,
|
...apiLambdaGroups,
|
||||||
...appRouteHandlersLambdaGroups,
|
...appRouteHandlersLambdaGroups,
|
||||||
];
|
];
|
||||||
@@ -1164,15 +1213,10 @@ export async function serverBuild({
|
|||||||
|
|
||||||
const lambda = await createLambdaFromPseudoLayers(options);
|
const lambda = await createLambdaFromPseudoLayers(options);
|
||||||
|
|
||||||
// This is a PPR lambda if it's an App Page with the PPR experimental flag
|
|
||||||
// enabled.
|
|
||||||
const isPPR =
|
|
||||||
experimental.ppr && group.isAppRouter && !group.isAppRouteHandler;
|
|
||||||
|
|
||||||
// If PPR is enabled and this is an App Page, create the non-streaming
|
// If PPR is enabled and this is an App Page, create the non-streaming
|
||||||
// lambda for the page for revalidation.
|
// lambda for the page for revalidation.
|
||||||
let revalidate: NodejsLambda | undefined;
|
let revalidate: NodejsLambda | undefined;
|
||||||
if (isPPR) {
|
if (group.isExperimentalPPR) {
|
||||||
if (!options.isStreaming) {
|
if (!options.isStreaming) {
|
||||||
throw new Error("Invariant: PPR lambda isn't streaming");
|
throw new Error("Invariant: PPR lambda isn't streaming");
|
||||||
}
|
}
|
||||||
@@ -1189,14 +1233,11 @@ export async function serverBuild({
|
|||||||
// This is the name of the page, where the root is `index`.
|
// This is the name of the page, where the root is `index`.
|
||||||
const pageName = pageFilename.replace(/\.js$/, '');
|
const pageName = pageFilename.replace(/\.js$/, '');
|
||||||
|
|
||||||
// This is the name of the page prefixed with a `/`, where the root is
|
|
||||||
// `/index`.
|
|
||||||
const pagePath = path.posix.join('/', pageName);
|
|
||||||
|
|
||||||
// This is the routable pathname for the page, where the root is `/`.
|
// This is the routable pathname for the page, where the root is `/`.
|
||||||
const pagePathname = pagePath === '/index' ? '/' : pagePath;
|
const pagePathname = normalizePage(pageName);
|
||||||
|
|
||||||
let isPrerender = prerenderRoutes.has(pagePathname);
|
let isPrerender = prerenderRoutes.has(pagePathname);
|
||||||
|
const isRoutePPREnabled = experimentalPPRRoutes.has(pagePathname);
|
||||||
|
|
||||||
if (!isPrerender && routesManifest?.i18n) {
|
if (!isPrerender && routesManifest?.i18n) {
|
||||||
isPrerender = routesManifest.i18n.locales.some(locale => {
|
isPrerender = routesManifest.i18n.locales.some(locale => {
|
||||||
@@ -1208,8 +1249,13 @@ export async function serverBuild({
|
|||||||
|
|
||||||
let outputName = path.posix.join(entryDirectory, pageName);
|
let outputName = path.posix.join(entryDirectory, pageName);
|
||||||
|
|
||||||
|
if (group.isActionLambda) {
|
||||||
|
// give the streaming prerenders a .action suffix
|
||||||
|
outputName = `${outputName}.action`;
|
||||||
|
}
|
||||||
|
|
||||||
// If this is a PPR page, then we should prefix the output name.
|
// If this is a PPR page, then we should prefix the output name.
|
||||||
if (isPPR) {
|
if (isRoutePPREnabled) {
|
||||||
if (!revalidate) {
|
if (!revalidate) {
|
||||||
throw new Error("Invariant: PPR lambda isn't set");
|
throw new Error("Invariant: PPR lambda isn't set");
|
||||||
}
|
}
|
||||||
@@ -1290,6 +1336,13 @@ export async function serverBuild({
|
|||||||
console.timeEnd(lambdaCreationLabel);
|
console.timeEnd(lambdaCreationLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isAppPPREnabled) {
|
||||||
|
debug(
|
||||||
|
'experimentalStreamingLambdaPaths',
|
||||||
|
JSON.stringify(Array.from(experimentalStreamingLambdaPaths))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const prerenderRoute = onPrerenderRoute({
|
const prerenderRoute = onPrerenderRoute({
|
||||||
appDir,
|
appDir,
|
||||||
pagesDir,
|
pagesDir,
|
||||||
@@ -1309,6 +1362,7 @@ export async function serverBuild({
|
|||||||
hasPages404: routesManifest.pages404,
|
hasPages404: routesManifest.pages404,
|
||||||
isCorrectNotFoundRoutes,
|
isCorrectNotFoundRoutes,
|
||||||
isEmptyAllowQueryForPrendered,
|
isEmptyAllowQueryForPrendered,
|
||||||
|
isAppPPREnabled,
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@@ -1377,7 +1431,8 @@ export async function serverBuild({
|
|||||||
bypassToken: prerenderManifest.bypassToken || '',
|
bypassToken: prerenderManifest.bypassToken || '',
|
||||||
isServerMode: true,
|
isServerMode: true,
|
||||||
dynamicMiddlewareRouteMap: middleware.dynamicRouteMap,
|
dynamicMiddlewareRouteMap: middleware.dynamicRouteMap,
|
||||||
experimentalPPRRoutes,
|
isAppPPREnabled,
|
||||||
|
hasActionOutputSupport,
|
||||||
}).then(arr =>
|
}).then(arr =>
|
||||||
localizeDynamicRoutes(
|
localizeDynamicRoutes(
|
||||||
arr,
|
arr,
|
||||||
@@ -1557,10 +1612,23 @@ export async function serverBuild({
|
|||||||
|
|
||||||
if (lambdas[pathname]) {
|
if (lambdas[pathname]) {
|
||||||
lambdas[`${pathname}.rsc`] = lambdas[pathname];
|
lambdas[`${pathname}.rsc`] = lambdas[pathname];
|
||||||
|
|
||||||
|
if (isAppPPREnabled) {
|
||||||
|
lambdas[`${pathname}${RSC_PREFETCH_SUFFIX}`] = lambdas[pathname];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (edgeFunctions[pathname]) {
|
if (edgeFunctions[pathname]) {
|
||||||
edgeFunctions[`${pathname}.rsc`] = edgeFunctions[pathname];
|
edgeFunctions[`${pathname}.rsc`] = edgeFunctions[pathname];
|
||||||
|
|
||||||
|
if (isAppPPREnabled) {
|
||||||
|
edgeFunctions[`${pathname}${RSC_PREFETCH_SUFFIX}`] =
|
||||||
|
edgeFunctions[pathname];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasActionOutputSupport) {
|
||||||
|
edgeFunctions[`${pathname}.action`] = edgeFunctions[pathname];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1572,7 +1640,7 @@ export async function serverBuild({
|
|||||||
'RSC, Next-Router-State-Tree, Next-Router-Prefetch';
|
'RSC, Next-Router-State-Tree, Next-Router-Prefetch';
|
||||||
const appNotFoundPath = path.posix.join('.', entryDirectory, '_not-found');
|
const appNotFoundPath = path.posix.join('.', entryDirectory, '_not-found');
|
||||||
|
|
||||||
if (experimental.ppr && !rscPrefetchHeader) {
|
if (isAppPPREnabled && !rscPrefetchHeader) {
|
||||||
throw new Error("Invariant: cannot use PPR without 'rsc.prefetchHeader'");
|
throw new Error("Invariant: cannot use PPR without 'rsc.prefetchHeader'");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1580,7 +1648,7 @@ export async function serverBuild({
|
|||||||
// all the routes that support it (and are listed) have configured lambdas.
|
// all the routes that support it (and are listed) have configured lambdas.
|
||||||
// This only applies to routes that do not have fallbacks enabled (these are
|
// This only applies to routes that do not have fallbacks enabled (these are
|
||||||
// routes that have `dynamicParams = false` defined.
|
// routes that have `dynamicParams = false` defined.
|
||||||
if (experimental.ppr) {
|
if (isAppPPREnabled) {
|
||||||
for (const { srcRoute, dataRoute, experimentalPPR } of Object.values(
|
for (const { srcRoute, dataRoute, experimentalPPR } of Object.values(
|
||||||
prerenderManifest.staticRoutes
|
prerenderManifest.staticRoutes
|
||||||
)) {
|
)) {
|
||||||
@@ -1863,7 +1931,7 @@ export async function serverBuild({
|
|||||||
|
|
||||||
...(appDir
|
...(appDir
|
||||||
? [
|
? [
|
||||||
...(rscPrefetchHeader
|
...(rscPrefetchHeader && isAppPPREnabled
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
src: `^${path.posix.join('/', entryDirectory, '/')}`,
|
src: `^${path.posix.join('/', entryDirectory, '/')}`,
|
||||||
@@ -1905,9 +1973,56 @@ export async function serverBuild({
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
|
...(hasActionOutputSupport
|
||||||
|
? [
|
||||||
|
// Create rewrites for streaming prerenders (.action routes)
|
||||||
|
// This contains separate rewrites for each possible "has" (action header, or content-type)
|
||||||
|
// Also includes separate handling for index routes which should match to /index.action.
|
||||||
|
// This follows the same pattern as the rewrites for .rsc files.
|
||||||
{
|
{
|
||||||
src: `^${path.posix.join('/', entryDirectory, '/')}`,
|
src: `^${path.posix.join('/', entryDirectory, '/?')}`,
|
||||||
|
dest: path.posix.join('/', entryDirectory, '/index.action'),
|
||||||
|
has: [
|
||||||
|
{
|
||||||
|
type: 'header',
|
||||||
|
key: 'next-action',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
missing: [
|
||||||
|
{
|
||||||
|
type: 'header',
|
||||||
|
key: rscHeader,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
continue: true,
|
||||||
|
override: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: `^${path.posix.join(
|
||||||
|
'/',
|
||||||
|
entryDirectory,
|
||||||
|
'/((?!.+\\.action).+?)(?:/)?$'
|
||||||
|
)}`,
|
||||||
|
dest: path.posix.join('/', entryDirectory, '/$1.action'),
|
||||||
|
has: [
|
||||||
|
{
|
||||||
|
type: 'header',
|
||||||
|
key: 'next-action',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
missing: [
|
||||||
|
{
|
||||||
|
type: 'header',
|
||||||
|
key: rscHeader,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
continue: true,
|
||||||
|
override: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
{
|
||||||
|
src: `^${path.posix.join('/', entryDirectory, '/?')}`,
|
||||||
has: [
|
has: [
|
||||||
{
|
{
|
||||||
type: 'header',
|
type: 'header',
|
||||||
@@ -1970,47 +2085,6 @@ export async function serverBuild({
|
|||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
|
|
||||||
...(rscPrefetchHeader && !experimental.ppr
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
src: path.posix.join(
|
|
||||||
'/',
|
|
||||||
entryDirectory,
|
|
||||||
`/__index${RSC_PREFETCH_SUFFIX}`
|
|
||||||
),
|
|
||||||
dest: path.posix.join('/', entryDirectory, '/index.rsc'),
|
|
||||||
has: [
|
|
||||||
{
|
|
||||||
type: 'header',
|
|
||||||
key: rscPrefetchHeader,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
continue: true,
|
|
||||||
override: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: `^${path.posix.join(
|
|
||||||
'/',
|
|
||||||
entryDirectory,
|
|
||||||
`/(.+?)${RSC_PREFETCH_SUFFIX}(?:/)?$`
|
|
||||||
)}`,
|
|
||||||
dest: path.posix.join(
|
|
||||||
'/',
|
|
||||||
entryDirectory,
|
|
||||||
`/$1${experimental.ppr ? RSC_PREFETCH_SUFFIX : '.rsc'}`
|
|
||||||
),
|
|
||||||
has: [
|
|
||||||
{
|
|
||||||
type: 'header',
|
|
||||||
key: rscPrefetchHeader,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
continue: true,
|
|
||||||
override: true,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
|
|
||||||
// These need to come before handle: miss or else they are grouped
|
// These need to come before handle: miss or else they are grouped
|
||||||
// with that routing section
|
// with that routing section
|
||||||
...afterFilesRewrites,
|
...afterFilesRewrites,
|
||||||
|
|||||||
@@ -192,8 +192,12 @@ function normalizePage(page: string): string {
|
|||||||
if (!page.startsWith('/')) {
|
if (!page.startsWith('/')) {
|
||||||
page = `/${page}`;
|
page = `/${page}`;
|
||||||
}
|
}
|
||||||
// remove '/index' from the end
|
|
||||||
page = page.replace(/\/index$/, '/');
|
// Replace the `/index` with `/`
|
||||||
|
if (page === '/index') {
|
||||||
|
page = '/';
|
||||||
|
}
|
||||||
|
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +324,8 @@ export async function getDynamicRoutes({
|
|||||||
bypassToken,
|
bypassToken,
|
||||||
isServerMode,
|
isServerMode,
|
||||||
dynamicMiddlewareRouteMap,
|
dynamicMiddlewareRouteMap,
|
||||||
experimentalPPRRoutes,
|
hasActionOutputSupport,
|
||||||
|
isAppPPREnabled,
|
||||||
}: {
|
}: {
|
||||||
entryPath: string;
|
entryPath: string;
|
||||||
entryDirectory: string;
|
entryDirectory: string;
|
||||||
@@ -332,7 +337,8 @@ export async function getDynamicRoutes({
|
|||||||
bypassToken?: string;
|
bypassToken?: string;
|
||||||
isServerMode?: boolean;
|
isServerMode?: boolean;
|
||||||
dynamicMiddlewareRouteMap?: ReadonlyMap<string, RouteWithSrc>;
|
dynamicMiddlewareRouteMap?: ReadonlyMap<string, RouteWithSrc>;
|
||||||
experimentalPPRRoutes: ReadonlySet<string>;
|
hasActionOutputSupport: boolean;
|
||||||
|
isAppPPREnabled: boolean;
|
||||||
}): Promise<RouteWithSrc[]> {
|
}): Promise<RouteWithSrc[]> {
|
||||||
if (routesManifest) {
|
if (routesManifest) {
|
||||||
switch (routesManifest.version) {
|
switch (routesManifest.version) {
|
||||||
@@ -406,7 +412,7 @@ export async function getDynamicRoutes({
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (experimentalPPRRoutes.has(page)) {
|
if (isAppPPREnabled) {
|
||||||
let dest = route.dest?.replace(/($|\?)/, '.prefetch.rsc$1');
|
let dest = route.dest?.replace(/($|\?)/, '.prefetch.rsc$1');
|
||||||
|
|
||||||
if (page === '/' || page === '/index') {
|
if (page === '/' || page === '/index') {
|
||||||
@@ -423,6 +429,16 @@ export async function getDynamicRoutes({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasActionOutputSupport) {
|
||||||
|
routes.push({
|
||||||
|
...route,
|
||||||
|
src: route.src.replace(
|
||||||
|
new RegExp(escapeStringRegexp('(?:/)?$')),
|
||||||
|
'(?<nxtsuffix>(?:\\.action|\\.rsc))(?:/)?$'
|
||||||
|
),
|
||||||
|
dest: route.dest?.replace(/($|\?)/, '$nxtsuffix$1'),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
routes.push({
|
routes.push({
|
||||||
...route,
|
...route,
|
||||||
src: route.src.replace(
|
src: route.src.replace(
|
||||||
@@ -431,6 +447,7 @@ export async function getDynamicRoutes({
|
|||||||
),
|
),
|
||||||
dest: route.dest?.replace(/($|\?)/, '.rsc$1'),
|
dest: route.dest?.replace(/($|\?)/, '.rsc$1'),
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
routes.push(route);
|
routes.push(route);
|
||||||
}
|
}
|
||||||
@@ -1426,6 +1443,13 @@ async function getSourceFilePathFromPage({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we got here, and didn't find a source not-found file, then it was the one injected
|
||||||
|
// by Next.js. There's no need to warn or return a source file in this case, as it won't have
|
||||||
|
// any configuration applied to it.
|
||||||
|
if (page === '/_not-found/page') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`WARNING: Unable to find source file for page ${page} with extensions: ${extensionsToTry.join(
|
`WARNING: Unable to find source file for page ${page} with extensions: ${extensionsToTry.join(
|
||||||
', '
|
', '
|
||||||
@@ -1485,8 +1509,9 @@ export type LambdaGroup = {
|
|||||||
isAppRouter?: boolean;
|
isAppRouter?: boolean;
|
||||||
isAppRouteHandler?: boolean;
|
isAppRouteHandler?: boolean;
|
||||||
isStreaming?: boolean;
|
isStreaming?: boolean;
|
||||||
isPrerenders?: boolean;
|
readonly isPrerenders: boolean;
|
||||||
isExperimentalPPR?: boolean;
|
readonly isExperimentalPPR: boolean;
|
||||||
|
isActionLambda?: boolean;
|
||||||
isPages?: boolean;
|
isPages?: boolean;
|
||||||
isApiLambda: boolean;
|
isApiLambda: boolean;
|
||||||
pseudoLayer: PseudoLayer;
|
pseudoLayer: PseudoLayer;
|
||||||
@@ -1551,15 +1576,13 @@ export async function getPageLambdaGroups({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config && config.functions) {
|
if (config && config.functions) {
|
||||||
// `pages` are normalized without route groups (e.g., /app/(group)/page.js).
|
|
||||||
// we keep track of that mapping in `inversedAppPathManifest`
|
|
||||||
// `getSourceFilePathFromPage` needs to use the path from source to properly match the config
|
|
||||||
const pageFromManifest = inversedAppPathManifest?.[routeName];
|
|
||||||
const sourceFile = await getSourceFilePathFromPage({
|
const sourceFile = await getSourceFilePathFromPage({
|
||||||
workPath: entryPath,
|
workPath: entryPath,
|
||||||
// since this function is used by both `pages` and `app`, the manifest might not be provided
|
page: normalizeSourceFilePageFromManifest(
|
||||||
// so fallback to normal behavior of just checking the `page`.
|
routeName,
|
||||||
page: pageFromManifest ?? page,
|
page,
|
||||||
|
inversedAppPathManifest
|
||||||
|
),
|
||||||
pageExtensions,
|
pageExtensions,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1643,6 +1666,43 @@ export async function getPageLambdaGroups({
|
|||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `pages` are normalized without route groups (e.g., /app/(group)/page.js).
|
||||||
|
// we keep track of that mapping in `inversedAppPathManifest`
|
||||||
|
// `getSourceFilePathFromPage` needs to use the path from source to properly match the config
|
||||||
|
function normalizeSourceFilePageFromManifest(
|
||||||
|
routeName: string,
|
||||||
|
page: string,
|
||||||
|
inversedAppPathManifest?: Record<string, string>
|
||||||
|
) {
|
||||||
|
const pageFromManifest = inversedAppPathManifest?.[routeName];
|
||||||
|
if (!pageFromManifest) {
|
||||||
|
// since this function is used by both `pages` and `app`, the manifest might not be provided
|
||||||
|
// so fallback to normal behavior of just checking the `page`.
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
const metadataConventions = [
|
||||||
|
'/favicon.',
|
||||||
|
'/icon.',
|
||||||
|
'/apple-icon.',
|
||||||
|
'/opengraph-image.',
|
||||||
|
'/twitter-image.',
|
||||||
|
'/sitemap.',
|
||||||
|
'/robots.',
|
||||||
|
];
|
||||||
|
|
||||||
|
// these special metadata files for will not contain `/route` or `/page` suffix, so return the routeName as-is.
|
||||||
|
const isSpecialFile = metadataConventions.some(convention =>
|
||||||
|
routeName.startsWith(convention)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isSpecialFile) {
|
||||||
|
return routeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pageFromManifest;
|
||||||
|
}
|
||||||
|
|
||||||
export const outputFunctionFileSizeInfo = (
|
export const outputFunctionFileSizeInfo = (
|
||||||
pages: string[],
|
pages: string[],
|
||||||
pseudoLayer: PseudoLayer,
|
pseudoLayer: PseudoLayer,
|
||||||
@@ -1892,6 +1952,7 @@ type OnPrerenderRouteArgs = {
|
|||||||
routesManifest?: RoutesManifest;
|
routesManifest?: RoutesManifest;
|
||||||
isCorrectNotFoundRoutes?: boolean;
|
isCorrectNotFoundRoutes?: boolean;
|
||||||
isEmptyAllowQueryForPrendered?: boolean;
|
isEmptyAllowQueryForPrendered?: boolean;
|
||||||
|
isAppPPREnabled: boolean;
|
||||||
};
|
};
|
||||||
let prerenderGroup = 1;
|
let prerenderGroup = 1;
|
||||||
|
|
||||||
@@ -1928,6 +1989,7 @@ export const onPrerenderRoute =
|
|||||||
routesManifest,
|
routesManifest,
|
||||||
isCorrectNotFoundRoutes,
|
isCorrectNotFoundRoutes,
|
||||||
isEmptyAllowQueryForPrendered,
|
isEmptyAllowQueryForPrendered,
|
||||||
|
isAppPPREnabled,
|
||||||
} = prerenderRouteArgs;
|
} = prerenderRouteArgs;
|
||||||
|
|
||||||
if (isBlocking && isFallback) {
|
if (isBlocking && isFallback) {
|
||||||
@@ -2163,22 +2225,6 @@ export const onPrerenderRoute =
|
|||||||
initialStatus = 404;
|
initialStatus = 404;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If the route key had an `/index` suffix added, we need to note it so we
|
|
||||||
* can remove it from the output path later accurately.
|
|
||||||
*/
|
|
||||||
let addedIndexSuffix = false;
|
|
||||||
|
|
||||||
if (isAppPathRoute) {
|
|
||||||
// for literal index routes we need to append an additional /index
|
|
||||||
// due to the proxy's normalizing for /index routes
|
|
||||||
if (routeKey !== '/index' && routeKey.endsWith('/index')) {
|
|
||||||
routeKey = `${routeKey}/index`;
|
|
||||||
routeFileNoExt = routeKey;
|
|
||||||
addedIndexSuffix = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let outputPathPage = path.posix.join(entryDirectory, routeFileNoExt);
|
let outputPathPage = path.posix.join(entryDirectory, routeFileNoExt);
|
||||||
|
|
||||||
if (!isAppPathRoute) {
|
if (!isAppPathRoute) {
|
||||||
@@ -2215,7 +2261,7 @@ export const onPrerenderRoute =
|
|||||||
|
|
||||||
let outputPathPrefetchData: null | string = null;
|
let outputPathPrefetchData: null | string = null;
|
||||||
if (prefetchDataRoute) {
|
if (prefetchDataRoute) {
|
||||||
if (!experimentalPPR) {
|
if (!isAppPPREnabled) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Invariant: prefetchDataRoute can't be set without PPR"
|
"Invariant: prefetchDataRoute can't be set without PPR"
|
||||||
);
|
);
|
||||||
@@ -2372,7 +2418,7 @@ export const onPrerenderRoute =
|
|||||||
// static route first, then try the srcRoute if it doesn't exist. If we
|
// static route first, then try the srcRoute if it doesn't exist. If we
|
||||||
// can't find it at all, this constitutes an error.
|
// can't find it at all, this constitutes an error.
|
||||||
experimentalStreamingLambdaPath = experimentalStreamingLambdaPaths.get(
|
experimentalStreamingLambdaPath = experimentalStreamingLambdaPaths.get(
|
||||||
pathnameToOutputName(entryDirectory, routeKey, addedIndexSuffix)
|
pathnameToOutputName(entryDirectory, routeKey)
|
||||||
);
|
);
|
||||||
if (!experimentalStreamingLambdaPath && srcRoute) {
|
if (!experimentalStreamingLambdaPath && srcRoute) {
|
||||||
experimentalStreamingLambdaPath =
|
experimentalStreamingLambdaPath =
|
||||||
@@ -2451,6 +2497,7 @@ export const onPrerenderRoute =
|
|||||||
...(rscEnabled
|
...(rscEnabled
|
||||||
? {
|
? {
|
||||||
initialHeaders: {
|
initialHeaders: {
|
||||||
|
...initialHeaders,
|
||||||
'content-type': rscContentTypeHeader,
|
'content-type': rscContentTypeHeader,
|
||||||
vary: rscVaryHeader,
|
vary: rscVaryHeader,
|
||||||
// If it contains a pre-render, then it was postponed.
|
// If it contains a pre-render, then it was postponed.
|
||||||
@@ -2463,6 +2510,22 @@ export const onPrerenderRoute =
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we need to ensure all prerenders have a matching .rsc output
|
||||||
|
// otherwise routing could fall through unexpectedly for the
|
||||||
|
// fallback: false case as it doesn't have a dynamic route
|
||||||
|
// to catch the `.rsc` request for app -> pages routing
|
||||||
|
if (outputPrerenderPathData?.endsWith('.json') && appDir) {
|
||||||
|
const dummyOutput = new FileBlob({
|
||||||
|
data: '{}',
|
||||||
|
contentType: 'application/json',
|
||||||
|
});
|
||||||
|
const rscKey = `${outputPathPage}.rsc`;
|
||||||
|
const prefetchRscKey = `${outputPathPage}${RSC_PREFETCH_SUFFIX}`;
|
||||||
|
|
||||||
|
prerenders[rscKey] = dummyOutput;
|
||||||
|
prerenders[prefetchRscKey] = dummyOutput;
|
||||||
|
}
|
||||||
|
|
||||||
++prerenderGroup;
|
++prerenderGroup;
|
||||||
|
|
||||||
if (routesManifest?.i18n && isBlocking) {
|
if (routesManifest?.i18n && isBlocking) {
|
||||||
@@ -2616,19 +2679,10 @@ export function getNextServerPath(nextVersion: string) {
|
|||||||
: 'next/dist/next-server/server';
|
: 'next/dist/next-server/server';
|
||||||
}
|
}
|
||||||
|
|
||||||
function pathnameToOutputName(
|
function pathnameToOutputName(entryDirectory: string, pathname: string) {
|
||||||
entryDirectory: string,
|
|
||||||
pathname: string,
|
|
||||||
addedIndexSuffix = false
|
|
||||||
) {
|
|
||||||
if (pathname === '/') {
|
if (pathname === '/') {
|
||||||
pathname = '/index';
|
pathname = '/index';
|
||||||
}
|
}
|
||||||
// If the `/index` was added for a route that ended in `/index` we need to
|
|
||||||
// strip the second one off before joining it with the entryDirectory.
|
|
||||||
else if (addedIndexSuffix) {
|
|
||||||
pathname = pathname.replace(/\/index$/, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
return path.posix.join(entryDirectory, pathname);
|
return path.posix.join(entryDirectory, pathname);
|
||||||
}
|
}
|
||||||
@@ -2754,7 +2808,7 @@ interface EdgeFunctionInfoV2 extends BaseEdgeFunctionInfo {
|
|||||||
|
|
||||||
interface EdgeFunctionInfoV3 extends BaseEdgeFunctionInfo {
|
interface EdgeFunctionInfoV3 extends BaseEdgeFunctionInfo {
|
||||||
matchers: EdgeFunctionMatcher[];
|
matchers: EdgeFunctionMatcher[];
|
||||||
environments: Record<string, string>;
|
env: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EdgeFunctionMatcher {
|
interface EdgeFunctionMatcher {
|
||||||
@@ -2989,7 +3043,7 @@ export async function getMiddlewareBundle({
|
|||||||
slug: 'nextjs',
|
slug: 'nextjs',
|
||||||
version: nextVersion,
|
version: nextVersion,
|
||||||
},
|
},
|
||||||
environment: edgeFunction.environments,
|
environment: edgeFunction.env,
|
||||||
});
|
});
|
||||||
})(),
|
})(),
|
||||||
routeMatchers: getRouteMatchers(edgeFunction, routesManifest),
|
routeMatchers: getRouteMatchers(edgeFunction, routesManifest),
|
||||||
@@ -3169,7 +3223,7 @@ export function upgradeMiddlewareManifestV1(
|
|||||||
return {
|
return {
|
||||||
...rest,
|
...rest,
|
||||||
matchers: [{ regexp }],
|
matchers: [{ regexp }],
|
||||||
environments: {},
|
env: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3197,7 +3251,7 @@ export function upgradeMiddlewareManifestV2(
|
|||||||
const { ...rest } = v2Info;
|
const { ...rest } = v2Info;
|
||||||
return {
|
return {
|
||||||
...rest,
|
...rest,
|
||||||
environments: {},
|
env: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/actions.js
vendored
Normal file
6
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/actions.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
'use server';
|
||||||
|
|
||||||
|
export async function increment(value) {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
|
return value + 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { increment } from '../../../actions';
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
async function updateCount() {
|
||||||
|
const newCount = await increment(count);
|
||||||
|
setCount(newCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={updateCount}>
|
||||||
|
<div id="count">{count}</div>
|
||||||
|
<button>Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export const dynamic = 'force-dynamic';
|
||||||
|
|
||||||
|
export default function Layout({ children }) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { increment } from '../../../actions';
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
async function updateCount() {
|
||||||
|
const newCount = await increment(count);
|
||||||
|
setCount(newCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={updateCount}>
|
||||||
|
<div id="count">{count}</div>
|
||||||
|
<button>Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export const dynamic = 'force-static';
|
||||||
|
|
||||||
|
export default function Layout({ children }) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
19
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/client/static/page.js
vendored
Normal file
19
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/client/static/page.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { increment } from '../../actions';
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
async function updateCount() {
|
||||||
|
const newCount = await increment(count);
|
||||||
|
setCount(newCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={updateCount}>
|
||||||
|
<div id="count">{count}</div>
|
||||||
|
<button>Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { increment } from '../../../../actions';
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
async function updateCount() {
|
||||||
|
const newCount = await increment(count);
|
||||||
|
setCount(newCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={updateCount}>
|
||||||
|
<div id="count">{count}</div>
|
||||||
|
<button>Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export const dynamic = 'force-dynamic';
|
||||||
|
|
||||||
|
export default function Layout({ children }) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { increment } from '../../../../actions';
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
async function updateCount() {
|
||||||
|
const newCount = await increment(count);
|
||||||
|
setCount(newCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={updateCount}>
|
||||||
|
<div id="count">{count}</div>
|
||||||
|
<button>Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export const dynamic = 'force-static';
|
||||||
|
|
||||||
|
export default function Layout({ children }) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { increment } from '../../../actions';
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
async function updateCount() {
|
||||||
|
const newCount = await increment(count);
|
||||||
|
setCount(newCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={updateCount}>
|
||||||
|
<div id="count">{count}</div>
|
||||||
|
<button>Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
5
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/edge/layout.js
vendored
Normal file
5
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/edge/layout.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export const runtime = 'edge';
|
||||||
|
|
||||||
|
export default function Layout({ children }) {
|
||||||
|
return <div>{children}</div>;
|
||||||
|
}
|
||||||
45
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/edge/other/page.js
vendored
Normal file
45
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/edge/other/page.js
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
|
function request(method) {
|
||||||
|
return fetch('/api/test', {
|
||||||
|
method,
|
||||||
|
headers: {
|
||||||
|
'content-type': 'multipart/form-data;.*',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
const [result, setResult] = useState('Press submit');
|
||||||
|
const onClick = useCallback(async method => {
|
||||||
|
const res = await request(method);
|
||||||
|
const text = await res.text();
|
||||||
|
|
||||||
|
setResult(res.ok ? `${method} ${text}` : 'Error: ' + res.status);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex flex-col items-center justify-center h-screen">
|
||||||
|
<div className="flex flex-row space-x-2 items-center justify-center">
|
||||||
|
<button
|
||||||
|
className="border border-white rounded-sm p-4 mb-4"
|
||||||
|
onClick={() => onClick('GET')}
|
||||||
|
>
|
||||||
|
Submit GET
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="border border-white rounded-sm p-4 mb-4"
|
||||||
|
onClick={() => onClick('POST')}
|
||||||
|
>
|
||||||
|
Submit POST
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="text-white">{result}</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export const dynamic = 'force-dynamic';
|
||||||
|
|
||||||
|
export default function Layout({ children }) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { revalidatePath } from 'next/cache';
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
async function serverAction() {
|
||||||
|
'use server';
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
revalidatePath('/dynamic');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={serverAction}>
|
||||||
|
<button>Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { revalidatePath } from 'next/cache';
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
async function serverAction() {
|
||||||
|
'use server';
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
revalidatePath('/dynamic');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={serverAction}>
|
||||||
|
<button>Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { revalidatePath } from 'next/cache';
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
async function serverAction() {
|
||||||
|
'use server';
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
revalidatePath('/dynamic');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={serverAction}>
|
||||||
|
<button>Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return [{ slug: 'pre-generated' }];
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export const dynamic = 'force-static';
|
||||||
|
|
||||||
|
export default function Layout({ children }) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { revalidatePath } from 'next/cache'
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
async function serverAction() {
|
||||||
|
'use server';
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
revalidatePath('/dynamic');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={serverAction}>
|
||||||
|
<button>Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
10
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/layout.js
vendored
Normal file
10
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/layout.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export default function Root({ children }) {
|
||||||
|
return (
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Hello World</title>
|
||||||
|
</head>
|
||||||
|
<body>{children}</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
45
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/other/page.js
vendored
Normal file
45
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/other/page.js
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
|
function request(method) {
|
||||||
|
return fetch('/api/test', {
|
||||||
|
method,
|
||||||
|
headers: {
|
||||||
|
'content-type': 'multipart/form-data;.*',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
const [result, setResult] = useState('Press submit');
|
||||||
|
const onClick = useCallback(async method => {
|
||||||
|
const res = await request(method);
|
||||||
|
const text = await res.text();
|
||||||
|
|
||||||
|
setResult(res.ok ? `${method} ${text}` : 'Error: ' + res.status);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex flex-col items-center justify-center h-screen">
|
||||||
|
<div className="flex flex-row space-x-2 items-center justify-center">
|
||||||
|
<button
|
||||||
|
className="border border-white rounded-sm p-4 mb-4"
|
||||||
|
onClick={() => onClick('GET')}
|
||||||
|
>
|
||||||
|
Submit GET
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="border border-white rounded-sm p-4 mb-4"
|
||||||
|
onClick={() => onClick('POST')}
|
||||||
|
>
|
||||||
|
Submit POST
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="text-white">{result}</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export const dynamic = 'force-dynamic';
|
||||||
|
|
||||||
|
export default function Layout({ children }) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
15
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/rsc/dynamic/page.js
vendored
Normal file
15
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/rsc/dynamic/page.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { revalidatePath } from 'next/cache';
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
async function serverAction() {
|
||||||
|
'use server';
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
revalidatePath('/dynamic');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={serverAction}>
|
||||||
|
<button>Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { revalidatePath } from 'next/cache';
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
async function serverAction() {
|
||||||
|
'use server';
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
revalidatePath('/dynamic');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={serverAction}>
|
||||||
|
<button>Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { revalidatePath } from 'next/cache';
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
async function serverAction() {
|
||||||
|
'use server';
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
revalidatePath('/dynamic');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={serverAction}>
|
||||||
|
<button>Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return [{ slug: 'pre-generated' }];
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export const dynamic = 'force-static';
|
||||||
|
|
||||||
|
export default function Layout({ children }) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
15
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/rsc/static/page.js
vendored
Normal file
15
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/app/rsc/static/page.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { revalidatePath } from 'next/cache'
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
async function serverAction() {
|
||||||
|
'use server';
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
revalidatePath('/dynamic');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form action={serverAction}>
|
||||||
|
<button>Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
324
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/index.test.js
vendored
Normal file
324
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/index.test.js
vendored
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
/* eslint-env jest */
|
||||||
|
const path = require('path');
|
||||||
|
const { deployAndTest } = require('../../utils');
|
||||||
|
const fetch = require('../../../../../test/lib/deployment/fetch-retry');
|
||||||
|
|
||||||
|
const ctx = {};
|
||||||
|
|
||||||
|
function findActionId(page, runtime) {
|
||||||
|
page = `app${page}/page`; // add /app prefix and /page suffix
|
||||||
|
|
||||||
|
for (const [actionId, details] of Object.entries(
|
||||||
|
ctx.actionManifest[runtime]
|
||||||
|
)) {
|
||||||
|
if (details.workers[page]) {
|
||||||
|
return actionId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateFormDataPayload(actionId) {
|
||||||
|
return {
|
||||||
|
method: 'POST',
|
||||||
|
body: `------WebKitFormBoundaryHcVuFa30AN0QV3uZ\r\nContent-Disposition: form-data; name=\"1_$ACTION_ID_${actionId}\"\r\n\r\n\r\n------WebKitFormBoundaryHcVuFa30AN0QV3uZ\r\nContent-Disposition: form-data; name=\"0\"\r\n\r\n[\"$K1\"]\r\n------WebKitFormBoundaryHcVuFa30AN0QV3uZ--\r\n`,
|
||||||
|
headers: {
|
||||||
|
'Content-Type':
|
||||||
|
'multipart/form-data; boundary=----WebKitFormBoundaryHcVuFa30AN0QV3uZ',
|
||||||
|
'Next-Action': actionId,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe(`${__dirname.split(path.sep).pop()}`, () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
const info = await deployAndTest(__dirname);
|
||||||
|
|
||||||
|
const actionManifest = await fetch(
|
||||||
|
`${info.deploymentUrl}/server-reference-manifest.json`
|
||||||
|
).then(res => res.json());
|
||||||
|
|
||||||
|
ctx.actionManifest = actionManifest;
|
||||||
|
|
||||||
|
Object.assign(ctx, info);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.each(['node', 'edge'])('runtime: %s', runtime => {
|
||||||
|
const basePath = runtime === 'edge' ? '/edge' : '';
|
||||||
|
describe('client component', () => {
|
||||||
|
it('should bypass the static cache for a server action', async () => {
|
||||||
|
const path = `${basePath}/client/static`;
|
||||||
|
const actionId = findActionId(path, runtime);
|
||||||
|
|
||||||
|
const res = await fetch(`${ctx.deploymentUrl}${path}`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify([1337]),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/plain;charset=UTF-8',
|
||||||
|
'Next-Action': actionId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
const body = await res.text();
|
||||||
|
expect(body).toContain('1338');
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe(path + '.action');
|
||||||
|
if (runtime === 'node') {
|
||||||
|
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
||||||
|
} else {
|
||||||
|
// in edge runtime, x-vercel-cache is not returned on MISSes for some reason.
|
||||||
|
// this checks to ensure it was routed to the edge function instead.
|
||||||
|
expect(res.headers.get('x-edge-runtime')).toBe('1');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should bypass the static cache for a server action on a page with dynamic params', async () => {
|
||||||
|
const path = `${basePath}/client/static/[dynamic-static]`;
|
||||||
|
const actionId = findActionId(path, runtime);
|
||||||
|
|
||||||
|
const res = await fetch(`${ctx.deploymentUrl}${path}`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify([1337]),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/plain;charset=UTF-8',
|
||||||
|
'Next-Action': actionId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
const body = await res.text();
|
||||||
|
expect(body).toContain('1338');
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe(path + '.action');
|
||||||
|
if (runtime === 'node') {
|
||||||
|
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
||||||
|
} else {
|
||||||
|
expect(res.headers.get('x-edge-runtime')).toBe('1');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should bypass the static cache for a multipart request (no action header)', async () => {
|
||||||
|
const path = `${basePath}/client/static`;
|
||||||
|
const actionId = findActionId(path, runtime);
|
||||||
|
|
||||||
|
const res = await fetch(`${ctx.deploymentUrl}${path}`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: `------WebKitFormBoundaryHcVuFa30AN0QV3uZ\r\nContent-Disposition: form-data; name=\"1_$ACTION_ID_${actionId}\"\r\n\r\n\r\n------WebKitFormBoundaryHcVuFa30AN0QV3uZ\r\nContent-Disposition: form-data; name=\"0\"\r\n\r\n[\"$K1\"]\r\n------WebKitFormBoundaryHcVuFa30AN0QV3uZ--\r\n`,
|
||||||
|
headers: {
|
||||||
|
'Content-Type':
|
||||||
|
'multipart/form-data; boundary=----WebKitFormBoundaryHcVuFa30AN0QV3uZ',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
expect(res.headers.get('content-type')).toBe(
|
||||||
|
'text/html; charset=utf-8'
|
||||||
|
);
|
||||||
|
if (runtime === 'node') {
|
||||||
|
// This is a "BYPASS" because no action ID was provided, so it'll fall back to
|
||||||
|
// `experimentalBypassFor` handling.
|
||||||
|
expect(res.headers.get('x-vercel-cache')).toBe('BYPASS');
|
||||||
|
} else {
|
||||||
|
expect(res.headers.get('x-edge-runtime')).toBe('1');
|
||||||
|
}
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe(path);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should properly invoke the action on a dynamic page', async () => {
|
||||||
|
const path = `${basePath}/client/dynamic/[id]`;
|
||||||
|
const actionId = findActionId(path, runtime);
|
||||||
|
|
||||||
|
const res = await fetch(`${ctx.deploymentUrl}${path}`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify([1337]),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/plain;charset=UTF-8',
|
||||||
|
'Next-Action': actionId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
const body = await res.text();
|
||||||
|
expect(body).toContain('1338');
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe(path + '.action');
|
||||||
|
if (runtime === 'node') {
|
||||||
|
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
||||||
|
} else {
|
||||||
|
expect(res.headers.get('x-edge-runtime')).toBe('1');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('server component', () => {
|
||||||
|
it('should bypass the static cache for a server action', async () => {
|
||||||
|
const path = `${basePath}/rsc/static`;
|
||||||
|
const actionId = findActionId(path, runtime);
|
||||||
|
|
||||||
|
const res = await fetch(
|
||||||
|
`${ctx.deploymentUrl}${path}`,
|
||||||
|
generateFormDataPayload(actionId)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe(path + '.action');
|
||||||
|
expect(res.headers.get('content-type')).toBe('text/x-component');
|
||||||
|
if (runtime === 'node') {
|
||||||
|
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
||||||
|
} else {
|
||||||
|
expect(res.headers.get('x-edge-runtime')).toBe('1');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should bypass the static cache for a server action on a page with dynamic params', async () => {
|
||||||
|
const path = `${basePath}/rsc/static/[dynamic-static]`;
|
||||||
|
const actionId = findActionId(path, runtime);
|
||||||
|
|
||||||
|
const res = await fetch(
|
||||||
|
`${ctx.deploymentUrl}${path}`,
|
||||||
|
generateFormDataPayload(actionId)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe(path + '.action');
|
||||||
|
expect(res.headers.get('content-type')).toBe('text/x-component');
|
||||||
|
if (runtime === 'node') {
|
||||||
|
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
||||||
|
} else {
|
||||||
|
expect(res.headers.get('x-edge-runtime')).toBe('1');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should properly invoke the action on a dynamic page', async () => {
|
||||||
|
const path = `${basePath}/rsc/dynamic`;
|
||||||
|
const actionId = findActionId(path, runtime);
|
||||||
|
|
||||||
|
const res = await fetch(
|
||||||
|
`${ctx.deploymentUrl}${path}`,
|
||||||
|
generateFormDataPayload(actionId)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe(path + '.action');
|
||||||
|
expect(res.headers.get('content-type')).toBe('text/x-component');
|
||||||
|
if (runtime === 'node') {
|
||||||
|
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
||||||
|
} else {
|
||||||
|
expect(res.headers.get('x-edge-runtime')).toBe('1');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('generateStaticParams', () => {
|
||||||
|
it('should bypass the static cache for a server action when pre-generated', async () => {
|
||||||
|
const path = `${basePath}/rsc/static/generate-static-params/pre-generated`;
|
||||||
|
const dynamicPath = `${basePath}/rsc/static/generate-static-params/[slug]`;
|
||||||
|
const actionId = findActionId(dynamicPath, runtime);
|
||||||
|
|
||||||
|
const res = await fetch(
|
||||||
|
`${ctx.deploymentUrl}${path}`,
|
||||||
|
generateFormDataPayload(actionId)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe(
|
||||||
|
dynamicPath + '.action'
|
||||||
|
);
|
||||||
|
expect(res.headers.get('content-type')).toBe('text/x-component');
|
||||||
|
if (runtime === 'node') {
|
||||||
|
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
||||||
|
} else {
|
||||||
|
expect(res.headers.get('x-edge-runtime')).toBe('1');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should bypass the static cache for a server action when not pre-generated', async () => {
|
||||||
|
const page = `${basePath}/rsc/static/generate-static-params/[slug]`;
|
||||||
|
const actionId = findActionId(page, runtime);
|
||||||
|
|
||||||
|
const res = await fetch(
|
||||||
|
`${ctx.deploymentUrl}/${basePath}/rsc/static/generate-static-params/not-pre-generated`,
|
||||||
|
generateFormDataPayload(actionId)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe(page + '.action');
|
||||||
|
expect(res.headers.get('content-type')).toBe('text/x-component');
|
||||||
|
if (runtime === 'node') {
|
||||||
|
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
||||||
|
} else {
|
||||||
|
expect(res.headers.get('x-edge-runtime')).toBe('1');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not match to an action output when the RSC header is present', async () => {
|
||||||
|
const canonicalPath = `${basePath}/client/dynamic/1`;
|
||||||
|
const pagePath = `${basePath}/client/dynamic/[id]`;
|
||||||
|
const actionId = findActionId(pagePath, runtime);
|
||||||
|
|
||||||
|
const res = await fetch(`${ctx.deploymentUrl}${canonicalPath}`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify([1337]),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/plain;charset=UTF-8',
|
||||||
|
'Next-Action': actionId,
|
||||||
|
'Next-Response': 'rsc',
|
||||||
|
RSC: '1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe(pagePath + '.rsc');
|
||||||
|
expect(res.headers.get('content-type')).toBe('text/x-component');
|
||||||
|
const body = await res.text();
|
||||||
|
expect(body).toContain(JSON.stringify(['id', '1', 'd']));
|
||||||
|
expect(body).not.toContain(JSON.stringify(['id', '1.action', 'd']));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work when a rewrite targets an action', async () => {
|
||||||
|
const targetPath = `${basePath}/rsc/static`;
|
||||||
|
const canonicalPath = `/rewrite/${basePath}/rsc/static`;
|
||||||
|
const actionId = findActionId(targetPath, runtime);
|
||||||
|
|
||||||
|
const res = await fetch(
|
||||||
|
`${ctx.deploymentUrl}${canonicalPath}`,
|
||||||
|
generateFormDataPayload(actionId)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe(targetPath + '.action');
|
||||||
|
expect(res.headers.get('content-type')).toBe('text/x-component');
|
||||||
|
if (runtime === 'node') {
|
||||||
|
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
||||||
|
} else {
|
||||||
|
expect(res.headers.get('x-edge-runtime')).toBe('1');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('pages', () => {
|
||||||
|
it('should not attempt to rewrite the action path for a server action (POST)', async () => {
|
||||||
|
const res = await fetch(`${ctx.deploymentUrl}/api/test`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type':
|
||||||
|
'multipart/form-data; boundary=----WebKitFormBoundaryHcVuFa30AN0QV3uZ',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe('/api/test');
|
||||||
|
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
||||||
|
const body = await res.json();
|
||||||
|
expect(body).toEqual({ message: 'Hello from Next.js!' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not attempt to rewrite the action path for a server action (GET)', async () => {
|
||||||
|
const res = await fetch(`${ctx.deploymentUrl}/api/test`);
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe('/api/test');
|
||||||
|
const body = await res.json();
|
||||||
|
expect(body).toEqual({ message: 'Hello from Next.js!' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
14
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/next.config.js
vendored
Normal file
14
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/next.config.js
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
module.exports = {
|
||||||
|
rewrites() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: '/rewrite/rsc/static',
|
||||||
|
destination: '/rsc/static',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
source: '/rewrite/edge/rsc/static',
|
||||||
|
destination: '/edge/rsc/static',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
};
|
||||||
9
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/package.json
vendored
Normal file
9
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/package.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"next": "canary"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "next build && cp .next/server/server-reference-manifest.json public/"
|
||||||
|
},
|
||||||
|
"ignoreNextjsUpdates": true
|
||||||
|
}
|
||||||
3
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/pages/api/test.js
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/pages/api/test.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export default function handler(req, res) {
|
||||||
|
res.status(200).json({ message: 'Hello from Next.js!' });
|
||||||
|
}
|
||||||
0
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/public/.keep
vendored
Normal file
0
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/public/.keep
vendored
Normal file
14
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/vercel.json
vendored
Normal file
14
packages/next/test/fixtures/00-app-dir-actions-experimental-streaming/vercel.json
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"builds": [
|
||||||
|
{
|
||||||
|
"src": "package.json",
|
||||||
|
"use": "@vercel/next"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"build": {
|
||||||
|
"env": {
|
||||||
|
"NEXT_EXPERIMENTAL_STREAMING_ACTIONS": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"probes": []
|
||||||
|
}
|
||||||
45
packages/next/test/fixtures/00-app-dir-actions/app/other/page.js
vendored
Normal file
45
packages/next/test/fixtures/00-app-dir-actions/app/other/page.js
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
|
function request(method) {
|
||||||
|
return fetch('/api/test', {
|
||||||
|
method,
|
||||||
|
headers: {
|
||||||
|
'content-type': 'multipart/form-data;.*',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
const [result, setResult] = useState('Press submit');
|
||||||
|
const onClick = useCallback(async method => {
|
||||||
|
const res = await request(method);
|
||||||
|
const text = await res.text();
|
||||||
|
|
||||||
|
setResult(res.ok ? `${method} ${text}` : 'Error: ' + res.status);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex flex-col items-center justify-center h-screen">
|
||||||
|
<div className="flex flex-row space-x-2 items-center justify-center">
|
||||||
|
<button
|
||||||
|
className="border border-white rounded-sm p-4 mb-4"
|
||||||
|
onClick={() => onClick('GET')}
|
||||||
|
>
|
||||||
|
Submit GET
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="border border-white rounded-sm p-4 mb-4"
|
||||||
|
onClick={() => onClick('POST')}
|
||||||
|
>
|
||||||
|
Submit POST
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="text-white">{result}</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -37,6 +37,7 @@ describe(`${__dirname.split(path.sep).pop()}`, () => {
|
|||||||
).then(res => res.json());
|
).then(res => res.json());
|
||||||
|
|
||||||
ctx.actionManifest = actionManifest;
|
ctx.actionManifest = actionManifest;
|
||||||
|
|
||||||
Object.assign(ctx, info);
|
Object.assign(ctx, info);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -81,6 +82,25 @@ describe(`${__dirname.split(path.sep).pop()}`, () => {
|
|||||||
expect(res.headers.get('x-vercel-cache')).toBe('BYPASS');
|
expect(res.headers.get('x-vercel-cache')).toBe('BYPASS');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should bypass the static cache for a multipart request (no action header)', async () => {
|
||||||
|
const path = '/client/static';
|
||||||
|
const actionId = findActionId(path);
|
||||||
|
|
||||||
|
const res = await fetch(`${ctx.deploymentUrl}${path}`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: `------WebKitFormBoundaryHcVuFa30AN0QV3uZ\r\nContent-Disposition: form-data; name=\"1_$ACTION_ID_${actionId}\"\r\n\r\n\r\n------WebKitFormBoundaryHcVuFa30AN0QV3uZ\r\nContent-Disposition: form-data; name=\"0\"\r\n\r\n[\"$K1\"]\r\n------WebKitFormBoundaryHcVuFa30AN0QV3uZ--\r\n`,
|
||||||
|
headers: {
|
||||||
|
'Content-Type':
|
||||||
|
'multipart/form-data; boundary=----WebKitFormBoundaryHcVuFa30AN0QV3uZ',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
expect(res.headers.get('content-type')).toBe('text/html; charset=utf-8');
|
||||||
|
expect(res.headers.get('x-vercel-cache')).toBe('BYPASS');
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe(path);
|
||||||
|
});
|
||||||
|
|
||||||
it('should properly invoke the action on a dynamic page', async () => {
|
it('should properly invoke the action on a dynamic page', async () => {
|
||||||
const path = '/client/dynamic/[id]';
|
const path = '/client/dynamic/[id]';
|
||||||
const actionId = findActionId(path);
|
const actionId = findActionId(path);
|
||||||
@@ -98,6 +118,7 @@ describe(`${__dirname.split(path.sep).pop()}`, () => {
|
|||||||
const body = await res.text();
|
const body = await res.text();
|
||||||
expect(body).toContain('1338');
|
expect(body).toContain('1338');
|
||||||
expect(res.headers.get('x-matched-path')).toBe(path);
|
expect(res.headers.get('x-matched-path')).toBe(path);
|
||||||
|
// This isn't a "BYPASS" because the action wasn't part of a static prerender
|
||||||
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -145,6 +166,7 @@ describe(`${__dirname.split(path.sep).pop()}`, () => {
|
|||||||
expect(res.status).toEqual(200);
|
expect(res.status).toEqual(200);
|
||||||
expect(res.headers.get('x-matched-path')).toBe(path);
|
expect(res.headers.get('x-matched-path')).toBe(path);
|
||||||
expect(res.headers.get('content-type')).toBe('text/x-component');
|
expect(res.headers.get('content-type')).toBe('text/x-component');
|
||||||
|
// This isn't a "BYPASS" because the action wasn't part of a static prerender
|
||||||
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -161,7 +183,9 @@ describe(`${__dirname.split(path.sep).pop()}`, () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(res.status).toEqual(200);
|
expect(res.status).toEqual(200);
|
||||||
expect(res.headers.get('x-matched-path')).toBe(path);
|
expect(res.headers.get('x-matched-path')).toBe(
|
||||||
|
'/rsc/static/generate-static-params/pre-generated'
|
||||||
|
);
|
||||||
expect(res.headers.get('content-type')).toBe('text/x-component');
|
expect(res.headers.get('content-type')).toBe('text/x-component');
|
||||||
expect(res.headers.get('x-vercel-cache')).toBe('BYPASS');
|
expect(res.headers.get('x-vercel-cache')).toBe('BYPASS');
|
||||||
});
|
});
|
||||||
@@ -178,8 +202,36 @@ describe(`${__dirname.split(path.sep).pop()}`, () => {
|
|||||||
expect(res.status).toEqual(200);
|
expect(res.status).toEqual(200);
|
||||||
expect(res.headers.get('x-matched-path')).toBe(page);
|
expect(res.headers.get('x-matched-path')).toBe(page);
|
||||||
expect(res.headers.get('content-type')).toBe('text/x-component');
|
expect(res.headers.get('content-type')).toBe('text/x-component');
|
||||||
|
// This isn't a "BYPASS" because the action wasn't part of a static prerender
|
||||||
expect(res.headers.get('x-vercel-cache')).toBe('BYPASS');
|
expect(res.headers.get('x-vercel-cache')).toBe('BYPASS');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('pages', () => {
|
||||||
|
it('should not attempt to rewrite the action path for a server action (POST)', async () => {
|
||||||
|
const res = await fetch(`${ctx.deploymentUrl}/api/test`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type':
|
||||||
|
'multipart/form-data; boundary=----WebKitFormBoundaryHcVuFa30AN0QV3uZ',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe('/api/test');
|
||||||
|
expect(res.headers.get('x-vercel-cache')).toBe('MISS');
|
||||||
|
const body = await res.json();
|
||||||
|
expect(body).toEqual({ message: 'Hello from Next.js!' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not attempt to rewrite the action path for a server action (GET)', async () => {
|
||||||
|
const res = await fetch(`${ctx.deploymentUrl}/api/test`);
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
expect(res.headers.get('x-matched-path')).toBe('/api/test');
|
||||||
|
const body = await res.json();
|
||||||
|
expect(body).toEqual({ message: 'Hello from Next.js!' });
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
1
packages/next/test/fixtures/00-app-dir-actions/next.config.js
vendored
Normal file
1
packages/next/test/fixtures/00-app-dir-actions/next.config.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
module.exports = {};
|
||||||
3
packages/next/test/fixtures/00-app-dir-actions/pages/api/test.js
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir-actions/pages/api/test.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export default function handler(req, res) {
|
||||||
|
res.status(200).json({ message: 'Hello from Next.js!' });
|
||||||
|
}
|
||||||
@@ -18,6 +18,31 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"probes": [
|
"probes": [
|
||||||
|
{
|
||||||
|
"path": "/hello/world",
|
||||||
|
"status": 200,
|
||||||
|
"mustContain": "index app page"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/hello/world",
|
||||||
|
"status": 200,
|
||||||
|
"mustContain": "index app page",
|
||||||
|
"mustNotContain": "<html",
|
||||||
|
"headers": {
|
||||||
|
"RSC": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/hello/world",
|
||||||
|
"status": 200,
|
||||||
|
"mustContain": ":",
|
||||||
|
"mustNotContain": "<html",
|
||||||
|
"headers": {
|
||||||
|
"RSC": 1,
|
||||||
|
"Next-Router-Prefetch": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"path": "/hello/world/dashboard/hello",
|
"path": "/hello/world/dashboard/hello",
|
||||||
"status": 200,
|
"status": 200,
|
||||||
@@ -42,14 +67,14 @@
|
|||||||
"status": 200,
|
"status": 200,
|
||||||
"mustContain": "hello from /ssg",
|
"mustContain": "hello from /ssg",
|
||||||
"responseHeaders": {
|
"responseHeaders": {
|
||||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url"
|
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "/hello/world/ssg",
|
"path": "/hello/world/ssg",
|
||||||
"status": 200,
|
"status": 200,
|
||||||
"responseHeaders": {
|
"responseHeaders": {
|
||||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url"
|
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||||
},
|
},
|
||||||
"headers": {
|
"headers": {
|
||||||
"RSC": "1"
|
"RSC": "1"
|
||||||
@@ -82,14 +107,14 @@
|
|||||||
"status": 200,
|
"status": 200,
|
||||||
"mustContain": "hello from app/dashboard/deployments/[id]/settings",
|
"mustContain": "hello from app/dashboard/deployments/[id]/settings",
|
||||||
"responseHeaders": {
|
"responseHeaders": {
|
||||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url"
|
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "/hello/world/dashboard/deployments/123/settings",
|
"path": "/hello/world/dashboard/deployments/123/settings",
|
||||||
"status": 200,
|
"status": 200,
|
||||||
"responseHeaders": {
|
"responseHeaders": {
|
||||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url"
|
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||||
},
|
},
|
||||||
"headers": {
|
"headers": {
|
||||||
"RSC": "1"
|
"RSC": "1"
|
||||||
@@ -102,14 +127,14 @@
|
|||||||
"status": 200,
|
"status": 200,
|
||||||
"mustContain": "catchall",
|
"mustContain": "catchall",
|
||||||
"responseHeaders": {
|
"responseHeaders": {
|
||||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url"
|
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "/hello/world/dashboard/deployments/catchall/something",
|
"path": "/hello/world/dashboard/deployments/catchall/something",
|
||||||
"status": 200,
|
"status": 200,
|
||||||
"responseHeaders": {
|
"responseHeaders": {
|
||||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url"
|
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||||
},
|
},
|
||||||
"headers": {
|
"headers": {
|
||||||
"RSC": "1"
|
"RSC": "1"
|
||||||
@@ -122,7 +147,7 @@
|
|||||||
"status": 200,
|
"status": 200,
|
||||||
"mustContain": "hello from app/dashboard",
|
"mustContain": "hello from app/dashboard",
|
||||||
"responseHeaders": {
|
"responseHeaders": {
|
||||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url"
|
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -142,7 +167,7 @@
|
|||||||
},
|
},
|
||||||
"responseHeaders": {
|
"responseHeaders": {
|
||||||
"content-type": "text/x-component",
|
"content-type": "text/x-component",
|
||||||
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url"
|
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "canary",
|
"next": "canary",
|
||||||
"react": "experimental",
|
"react": "19.0.0-rc-f994737d14-20240522",
|
||||||
"react-dom": "experimental"
|
"react-dom": "19.0.0-rc-f994737d14-20240522"
|
||||||
},
|
},
|
||||||
"ignoreNextjsUpdates": true
|
"ignoreNextjsUpdates": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "canary",
|
"next": "canary",
|
||||||
"react": "experimental",
|
"react": "19.0.0-rc-f994737d14-20240522",
|
||||||
"react-dom": "experimental"
|
"react-dom": "19.0.0-rc-f994737d14-20240522"
|
||||||
},
|
},
|
||||||
"ignoreNextjsUpdates": true,
|
"ignoreNextjsUpdates": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "canary",
|
"next": "canary",
|
||||||
"react": "experimental",
|
"react": "19.0.0-rc-f994737d14-20240522",
|
||||||
"react-dom": "experimental"
|
"react-dom": "19.0.0-rc-f994737d14-20240522"
|
||||||
},
|
},
|
||||||
"ignoreNextjsUpdates": true
|
"ignoreNextjsUpdates": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "canary",
|
"next": "canary",
|
||||||
"react": "experimental",
|
"react": "19.0.0-rc-f994737d14-20240522",
|
||||||
"react-dom": "experimental"
|
"react-dom": "19.0.0-rc-f994737d14-20240522"
|
||||||
},
|
},
|
||||||
"ignoreNextjsUpdates": true
|
"ignoreNextjsUpdates": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "canary",
|
"next": "canary",
|
||||||
"react": "experimental",
|
"react": "19.0.0-rc-f994737d14-20240522",
|
||||||
"react-dom": "experimental"
|
"react-dom": "19.0.0-rc-f994737d14-20240522"
|
||||||
},
|
},
|
||||||
"ignoreNextjsUpdates": true
|
"ignoreNextjsUpdates": true
|
||||||
}
|
}
|
||||||
|
|||||||
3
packages/next/test/fixtures/00-app-dir-incremental-ppr/app/disabled/page.jsx
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir-incremental-ppr/app/disabled/page.jsx
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export { default } from '../page';
|
||||||
|
|
||||||
|
export const experimental_ppr = false;
|
||||||
7
packages/next/test/fixtures/00-app-dir-incremental-ppr/app/layout.jsx
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir-incremental-ppr/app/layout.jsx
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function Layout({ children }) {
|
||||||
|
return (
|
||||||
|
<html>
|
||||||
|
<body>{children}</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
17
packages/next/test/fixtures/00-app-dir-incremental-ppr/app/page.jsx
vendored
Normal file
17
packages/next/test/fixtures/00-app-dir-incremental-ppr/app/page.jsx
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { unstable_noStore } from 'next/cache';
|
||||||
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
|
export const experimental_ppr = true;
|
||||||
|
|
||||||
|
function Dynamic() {
|
||||||
|
unstable_noStore();
|
||||||
|
return <div id="sentinel:dynamic">Dynamic</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<div id="sentinel:loading">Loading...</div>}>
|
||||||
|
<Dynamic />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
3
packages/next/test/fixtures/00-app-dir-incremental-ppr/app/static/page.jsx
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir-incremental-ppr/app/static/page.jsx
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export default function Page() {
|
||||||
|
return <div id="sentinel:static">Static</div>;
|
||||||
|
}
|
||||||
13
packages/next/test/fixtures/00-app-dir-incremental-ppr/index.test.js
vendored
Normal file
13
packages/next/test/fixtures/00-app-dir-incremental-ppr/index.test.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/* eslint-env jest */
|
||||||
|
const path = require('path');
|
||||||
|
const { deployAndTest } = require('../../utils');
|
||||||
|
|
||||||
|
const ctx = {};
|
||||||
|
|
||||||
|
// TODO: investigate invariant
|
||||||
|
describe.skip(`${__dirname.split(path.sep).pop()}`, () => {
|
||||||
|
it('should deploy and pass probe checks', async () => {
|
||||||
|
const info = await deployAndTest(__dirname);
|
||||||
|
Object.assign(ctx, info);
|
||||||
|
});
|
||||||
|
});
|
||||||
5
packages/next/test/fixtures/00-app-dir-incremental-ppr/next.config.js
vendored
Normal file
5
packages/next/test/fixtures/00-app-dir-incremental-ppr/next.config.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
experimental: {
|
||||||
|
ppr: 'incremental',
|
||||||
|
},
|
||||||
|
};
|
||||||
8
packages/next/test/fixtures/00-app-dir-incremental-ppr/package.json
vendored
Normal file
8
packages/next/test/fixtures/00-app-dir-incremental-ppr/package.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"next": "canary",
|
||||||
|
"react": "19.0.0-rc-f994737d14-20240522",
|
||||||
|
"react-dom": "19.0.0-rc-f994737d14-20240522"
|
||||||
|
},
|
||||||
|
"ignoreNextjsUpdates": true
|
||||||
|
}
|
||||||
82
packages/next/test/fixtures/00-app-dir-incremental-ppr/vercel.json
vendored
Normal file
82
packages/next/test/fixtures/00-app-dir-incremental-ppr/vercel.json
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
{
|
||||||
|
"builds": [
|
||||||
|
{
|
||||||
|
"src": "package.json",
|
||||||
|
"use": "@vercel/next",
|
||||||
|
"config": {
|
||||||
|
"functions": {
|
||||||
|
"app/**/*": {
|
||||||
|
"maxDuration": 5,
|
||||||
|
"memory": 512
|
||||||
|
},
|
||||||
|
"pages/api/**/*": {
|
||||||
|
"maxDuration": 5,
|
||||||
|
"memory": 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"probes": [
|
||||||
|
{
|
||||||
|
"path": "/",
|
||||||
|
"status": 200,
|
||||||
|
"mustContain": "sentinel:loading"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/",
|
||||||
|
"status": 200,
|
||||||
|
"mustContain": "sentinel:dynamic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/",
|
||||||
|
"headers": {
|
||||||
|
"RSC": "1",
|
||||||
|
"Next-Router-Prefetch": "1"
|
||||||
|
},
|
||||||
|
"status": 200,
|
||||||
|
"mustContain": "sentinel:loading",
|
||||||
|
"mustNotContain": "sentinel:dynamic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/",
|
||||||
|
"headers": {
|
||||||
|
"RSC": "1"
|
||||||
|
},
|
||||||
|
"status": 200,
|
||||||
|
"mustContain": "sentinel:dynamic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/disabled",
|
||||||
|
"status": 200,
|
||||||
|
"mustContain": "sentinel:loading"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/disabled",
|
||||||
|
"status": 200,
|
||||||
|
"mustContain": "sentinel:dynamic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/static",
|
||||||
|
"status": 200,
|
||||||
|
"mustContain": "sentinel:static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/disabled",
|
||||||
|
"headers": {
|
||||||
|
"RSC": "1",
|
||||||
|
"Next-Router-Prefetch": "1"
|
||||||
|
},
|
||||||
|
"status": 200,
|
||||||
|
"mustContain": "sentinel:dynamic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/disabled",
|
||||||
|
"headers": {
|
||||||
|
"RSC": "1"
|
||||||
|
},
|
||||||
|
"status": 200,
|
||||||
|
"mustContain": "sentinel:dynamic"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "canary",
|
"next": "canary",
|
||||||
"react": "experimental",
|
"react": "19.0.0-rc-f994737d14-20240522",
|
||||||
"react-dom": "experimental"
|
"react-dom": "19.0.0-rc-f994737d14-20240522"
|
||||||
},
|
},
|
||||||
"ignoreNextjsUpdates": true
|
"ignoreNextjsUpdates": true
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
packages/next/test/fixtures/00-app-dir-no-ppr/app/apple-icon.png
vendored
Normal file
BIN
packages/next/test/fixtures/00-app-dir-no-ppr/app/apple-icon.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user