Compare commits

..

42 Commits

Author SHA1 Message Date
Nathan Rajlich
fc614a7a92 Publish Stable
- vercel@28.16.12
 - @vercel/remix@1.5.1
2023-03-02 09:00:40 -08:00
Nathan Rajlich
6e4ea0774e [remix] Make symlink logic of @remix-run/dev work in monorepos (#9591)
Utilize `require.resolve()` to determine the correct location of
`@remix-run/dev`, instead of assuming it's in
"node_modules/@remix-run/dev" relative to the project work path.

Fixes https://github.com/orgs/vercel/discussions/1671.

Manually tested with yarn and pnpm on this template:
https://github.com/remix-run/examples/tree/main/turborepo-vercel
2023-03-02 08:58:00 -08:00
Nathan Rajlich
cfc1c9e818 Publish Stable
- vercel@28.16.11
 - @vercel/next@3.6.3
 - @vercel/remix@1.5.0
2023-03-01 17:24:34 -08:00
Vercel Release Bot
62a872fc0e [remix] Upgrade @remix-run/dev to version 1.13.0-patch.2 (#9589)
This auto-generated PR updates @remix-run/dev to version 1.13.0-patch.2
2023-03-02 00:10:12 +00:00
Vercel Release Bot
03b5bfbaa2 [examples] Upgrade Next.js to version 13.2.3 (#9586)
This auto-generated PR updates Next.js to version 13.2.3
2023-03-01 23:34:51 +00:00
Nathan Rajlich
aa305e5c66 [remix] Add better error message when server build directory is missing (#9584)
Show a more helpful message instead of showing a cryptic error messsage:

> Error: ENOENT: no such file or directory, copyfile
'/var/task/node_modules/@vercel/remix/server-node.mjs' ->
'/vercel/path0/packages/web/build/server-node.mjs'

This is probably due to a bad user configuration (i.e. with Turbo), but
tell them to contact support anyways in case there is a different cause
that we would need to address.
2023-03-01 15:08:44 -08:00
Ethan Arrowood
2309c43fce add vercel/remix-run-dev updater workflow (#9588)
Adds a github workflow and javascript updater script that will update
the `@remix-run/dev` version to the latest release of
`@vercel/remix-run-dev`
2023-03-01 13:50:23 -08:00
Nathan Rajlich
0bbb06daa7 [remix] Support "regions", "memory" and "maxDuration" in static config (#9442)
Apply the `regions` configuration (for both Edge and Node) and `memory`/`maxDuration` (only for Node) in a page's static config export, i.e.

```js
export const config = { runtime: 'edge', regions: ['iad1'] }

// or for Node
export const config = { runtime: 'nodejs', regions: ['iad1'], maxDuration: 5, memory: 3008 }
```

Similar to `runtime`, these config values can be inherited from a parent layout route to apply to all sub-routes. Routes with common config settings get placed into a common server bundle, meaning that there may now be more than 2 functions created (previously was one Edge, one Node), allowing for more granularity between the server build bundles.
2023-03-01 21:45:10 +00:00
Nathan Rajlich
61de63d285 [remix] Split Edge and Node server builds using serverBundles config (#9504)
Utilize the [`serverBundles`](https://github.com/remix-run/remix/pull/5479) config option to generate two server bundle builds. One contains only the routes that should run in Node.js, and the other contains only the routes that should run in the Edge runtime. In the future we could update this configuration to generate more than two bundles to be more granular and allow for infinite scalability.

Because the `serverBundles` PR is not yet merged, this PR introduces usage of a forked version of `@remix-run/dev` which incorporates our changes. Hopefully usage of a fork is temporary, but it gets us unblocked for now.
2023-03-01 03:10:42 +00:00
Steven
1ca3704297 [next] Fix incorrect 404 when i18n and appDir configured (#9582)
Fix incorrect 404 when visiting the `/` route with `i18n` and `appDir` configured
2023-03-01 02:02:55 +00:00
Nathan Rajlich
ae4180b287 [tests] Use probes.json instead of vercel.json for e2e tests (#9556)
Makes it easier to test fixtures directly via CLI deployments.

Coincidentally, this also revealed that auto-detection of Remix apps wasn't working correctly if there's a `remix.config.mjs` file. So `@vercel/frameworks` is updated to account for that case as well.
2023-03-01 01:02:43 +00:00
Steven
40081cb319 Publish Stable
- vercel@28.16.10
 - @vercel/remix@1.4.3
2023-02-28 19:12:33 -05:00
Steven
9200be61d2 [tests] Publish with npm@9 (#9583)
https://vercel.slack.com/archives/C04DUD7EB1B/p1676488464681929
2023-03-01 00:09:40 +00:00
Nathan Rajlich
1390f6d2ee [remix] Gracefully handle symlink creation when updating Remix packages (#9569)
Fixes an edge-case error when changing the version of Remix and then making a deployment to Vercel when there is already an existing build cache:

> Error: EEXIST: file already exists, symlink '../.pnpm/@remix-run+server-runtime@1.5.0_biqbaboplfbrettd7655fr4n2y/node_modules/@remix-run/server-runtime' -> '/vercel/path0/node_modules/@remix-run/server-runtime'

This would happen because the symlink was created in a previous run, but no longer points to a valid path because it's a different version. To fix we'll delete the previous symlink when the target value does not match.
2023-02-28 22:51:58 +00:00
Nathan Rajlich
b78cfc9ba5 [remix] Set framework property on Lambda / EdgeFunction (#9579) 2023-02-28 22:16:05 +00:00
Chris Barber
803a9363f9 Publish Stable
- vercel@28.16.9
 - @vercel/gatsby-plugin-vercel-analytics@1.0.8
 - @vercel/gatsby-plugin-vercel-builder@1.1.11
 - @vercel/node-bridge@3.1.14
 - @vercel/node@2.9.10
 - @vercel/static-build@1.3.14
2023-02-28 15:32:23 -06:00
Chris Barber
4a0a3b64a2 [node] Added middlewareRawSrc to BOA route config (#9435)
Blocked by https://github.com/vercel/vercel/pull/9564

The build output's route configuration contains a compiled `src` from the list of `matchers` in middleware config, however we need to also save the original inputs so that we can render something meaningful in the web UI. The new prop added to the route is called `middlewareRawSrc` of type `string[]`.

This PR depends on https://github.com/vercel/api/pull/17231.

Linear: https://linear.app/vercel/issue/VCCLI-411/display-uncompressed-edge-middleware-matcher-show-the-list-of-matches
2023-02-28 21:26:26 +00:00
Mehul Kar
347c2de3a2 [tests] Adopt Workspace Configurations from turbo@1.8 (#9573) 2023-02-28 20:49:28 +00:00
Ethan Arrowood
a05cc11719 [tests] Fix gatsby cron job script - git diff operation (#9577)
as titled
2023-02-28 13:13:57 -07:00
Ethan Arrowood
55b999ea9b [tests] add missing -w option for pnpm in gatsby cron job script (#9575)
as titled
2023-02-28 13:05:31 -07:00
Ethan Arrowood
8babc3694f [tests] Fix gatsby cron job (#9574)
Changes logic so its a single npm call instead of multiple
2023-02-28 11:59:58 -08:00
Ethan Arrowood
6dc0321216 [tests] add missing __dirname from gatsby cron job script (#9572)
as titled
2023-02-28 11:40:05 -08:00
Ethan Arrowood
3df8c05792 [tests] Add cron job to update gatsby fixtures (#9510)
PR to add a cron job and script that automatically updates gatsby
fixture versions.
2023-02-28 11:32:00 -08:00
Sean Massa
e0f8bc9820 Publish Stable
- @vercel/build-utils@6.3.2
 - vercel@28.16.8
 - @vercel/client@12.4.2
 - @vercel/edge@0.3.1
 - @vercel/frameworks@1.3.2
 - @vercel/fs-detectors@3.8.2
 - @vercel/gatsby-plugin-vercel-builder@1.1.10
 - @vercel/go@2.3.9
 - @vercel/hydrogen@0.0.55
 - @vercel/next@3.6.2
 - @vercel/node-bridge@3.1.13
 - @vercel/node@2.9.9
 - @vercel/python@3.1.51
 - @vercel/redwood@1.1.7
 - @vercel/remix@1.4.2
 - @vercel/routing-utils@2.1.10
 - @vercel/ruby@1.3.68
 - @vercel/static-build@1.3.13
2023-02-28 10:26:29 -06:00
Chris Barber
ebd2e1822c [routing-utils] Add missing 'middlewareRawSrc' to route schema (#9564)
Need to add `middlewareRawSrc` to route schema so the build container will accept the new property.

This PR blocks https://github.com/vercel/vercel/pull/9435.

Linear: https://linear.app/vercel/issue/VCCLI-411/display-uncompressed-edge-middleware-matcher-show-the-list-of-matches
2023-02-28 03:59:06 +00:00
Steven
31bc2581f3 [cli] Remove unncessary warning when monorepo setting override (#9565)
This warning is not actionable by the user so this PR removes it.
2023-02-27 16:23:49 -05:00
Steven
96759a9fda [hydrogen] Add missing envPrefix (#9551)
- Follow up to #9326
2023-02-27 20:01:05 +00:00
Jimmy Lai
ad2864bca5 [next] add support for the integration hook file tracing (#9562)
Adds support for bundling properly the dependencies used by the experimental instrumentation hook file, `instrumentation.js`, by adding the generated nft file to the list of server deps

fixes NEXT-631
2023-02-27 18:58:12 +00:00
Sean Massa
40fbc993d7 [tests] extract noisey setup to make test clearer (#9509)
Clarify dev server tests with a small function extraction.
2023-02-27 17:05:27 +00:00
Sean Massa
1f30e56a6d [cli][dev] remove link to 404 FAQ (#9508) 2023-02-27 10:37:57 -06:00
Nathan Rajlich
58d6268899 [frameworks] Check for remix.config.mjs for "remix" auto-detection (#9558)
Moving this to a separate PR based on this comment:
https://github.com/vercel/vercel/pull/9556#discussion_r1117939290

This will need to be merged and released before the relevant E2E test in
#9556 will pass.

Co-authored-by: Steven <steven@ceriously.com>
2023-02-27 10:07:32 -05:00
Nathan Rajlich
4e6659ace7 [remix] Fix sending multiple response headers with the same name with Node.js (#9533)
i.e. `Set-Cookie`. Right now only one will be sent and others will be lost. This update matches the code being used in `@remix-run/vercel`.
2023-02-27 07:19:58 +00:00
Nathan Rajlich
769234b6a6 [remix] Inject Edge entrypoint into @remix-run/vercel during Edge Function creation (#9553)
There's [a PR](https://github.com/remix-run/remix/pull/5537) opened on
Remix to add an Edge compatible entrypoint to `@remix-run/vercel`. This
is only really needed specifically for projects that have a custom
server.js entrypoint file, which is not strictly necessary anymore, but
there are some edge cases where a project might still want to have one.
So this PR is necessary for those kinds of projects to be able to use
Edge runtime.

Even when they merge the PR, it would be good to leave this injection
code around for some time to continue support for older
`@remix-run/vercel` versions in existing projects.
2023-02-25 00:53:30 -08:00
JJ Kasper
53cab61e88 [next] Fix deploying with cached build (#9555)
This leverages the relative app dir field in the required files manifest when available so that we don't rely on absolute paths from a cached build since the cache can be restored in a separate context where the value no longer applies.

x-ref: https://github.com/vercel/next.js/pull/45864
x-ref: https://github.com/vercel/next.js/pull/46393
x-ref: https://github.com/vercel/next.js/discussions/39432#discussioncomment-4914549
x-ref: [slack thread](https://vercel.slack.com/archives/C03S8ED1DKM/p1675821643786319)
2023-02-25 02:46:06 +00:00
Nathan Rajlich
3a65acfb32 [remix] Don't create output for Pathless Layout Routes without any child routes at the root level (#9539)
Fixes https://github.com/vercel/community/discussions/1587.
2023-02-25 01:17:01 +00:00
Nathan Rajlich
48eed7532a [tests] Properly test for multiple headers with same name in probes (#9538)
Updates the `responseHeaders` probe checks to properly test for multiple headers with the same name.

Previously the probes were using `headers.get()` which concats multiple headers into a single string, which results in the test not really checking if there are in fact multiple headers with the same name. Using `headers.raw()` allows us to properly test for that.

A couple of Python tests that were already checking for multiple `set-cookie` headers needed to be updated to match the full value, since the check now properly validates the full string match of each header (before it was basically just doing a `string.includes()` check).

This is a precursor for https://github.com/vercel/vercel/pull/9533.
2023-02-24 22:07:00 +00:00
Cody Olsen
f09d6fce85 [frameworks] add envPrefix to hydrogen framework (#9326)
Hydrogen uses the `PUBLIC_` env prefix, [it also supports
`VITE_`](8168cd2dd8/packages/hydrogen/src/framework/plugins/vite-plugin-hydrogen-config.ts (L127))
but [the docs only talk about
`PUBLIC_`](https://shopify.dev/custom-storefronts/hydrogen/environment-variables#public-variables).
2023-02-24 15:40:55 -05:00
Chris Barber
cc82c499db [cli] Added fetch dist-tags http status validation (#9549)
If for some reason the `get-latest-worker.js` fails to get the dist-tags, it doesn't check the status code and proceeds to `JSON.parse()` the response. If for example npm returns 401 Unauthorized, you get a cryptic JSON parse error message.
2023-02-24 20:14:53 +00:00
Steven
f0bc207717 [build-utils] Handle error during readConfigFile() (#9542)
This fixes a confusing error:

```
$ vercel build
Vercel CLI 28.16.6
Error: duplicated mapping key in "/vercel/path0/pnpm-lock.yaml" at line 1215, column -164:
      /@react-dnd/asap/4.0.1:
      ^
```
2023-02-24 18:02:35 +00:00
Steven
151c7f99ee [tests] Pass token to cron github actions (#9544)
https://github.com/actions/github-script#using-a-separate-github-token
2023-02-24 11:14:17 -05:00
Steven
61c2c494bf Revert "[tests] Update cron with token in git checkout" (#9543)
Reverts vercel/vercel#9541
2023-02-24 11:07:29 -05:00
Steven
7f49816129 [tests] Update cron with token in git checkout (#9541)
Hopefully this will fix the issue where actions do not run against the
automated PR.
2023-02-24 10:51:03 -05:00
121 changed files with 49927 additions and 38810 deletions

View File

@@ -0,0 +1,31 @@
name: Cron Update Gatsby Fixtures
on:
# Allow manual runs
workflow_dispatch:
# Run once a week https://crontab.guru/once-a-week
schedule:
- cron: '0 0 * * 0'
jobs:
create-pull-request:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
# 0 means fetch all commits so we can commit and push in the script below
with:
fetch-depth: 0
- name: Enable corepack
run: corepack enable pnpm
- name: Create Pull Request
uses: actions/github-script@v6
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
# See https://github.com/actions/github-script#run-a-separate-file-with-an-async-function
with:
github-token: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
script: |
const script = require('./utils/update-gatsby-fixtures.js')
await script({ github, context })

View File

@@ -25,6 +25,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
# See https://github.com/actions/github-script#run-a-separate-file-with-an-async-function
with:
github-token: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
script: |
const script = require('./utils/update-next.js')
await script({ github, context })

View File

@@ -25,6 +25,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
# See https://github.com/actions/github-script#run-a-separate-file-with-an-async-function
with:
github-token: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
script: |
const script = require('./utils/update-turbo.js')
await script({ github, context })

View File

@@ -16,6 +16,9 @@ jobs:
publish:
name: Publish
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v3
@@ -41,6 +44,8 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: 16
- name: install npm@9
run: npm i -g npm@9
- name: install pnpm@7.24.2
run: npm i -g pnpm@7.24.2
- name: Install

View File

@@ -0,0 +1,28 @@
name: Update @remix-run/dev
on:
workflow_dispatch:
inputs:
new-version:
type: string
description: "Optional version to update @remix-run/dev to inside of @vercel/remix"
jobs:
update-remix-run-dev:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup node
uses: actions/setup-node@v3
- name: Enable corepack
run: corepack enable pnpm
- name: Update @remix-run/dev
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GH_TOKEN_PULL_REQUESTS }}
script: |
const script = require('./utils/update-remix-run-dev.js')
await script({ github, context }, "${{ inputs.new-version }}")

1
.npmrc
View File

@@ -1,3 +1,4 @@
provenance=true
save-exact=true
hoist-pattern[]=!"**/@types/**"
hoist-pattern[]=!"**/typedoc"

View File

@@ -1,6 +1,5 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./*"]
}

View File

@@ -8,9 +8,9 @@
"name": "nextjs",
"version": "0.1.0",
"dependencies": {
"eslint": "8.34.0",
"eslint-config-next": "13.2.1",
"next": "13.2.1",
"eslint": "8.35.0",
"eslint-config-next": "13.2.3",
"next": "13.2.3",
"react": "18.2.0",
"react-dom": "18.2.0"
}
@@ -27,9 +27,9 @@
}
},
"node_modules/@eslint/eslintrc": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
"integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.0.tgz",
"integrity": "sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A==",
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
@@ -48,6 +48,14 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@eslint/js": {
"version": "8.35.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.35.0.tgz",
"integrity": "sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw==",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.8",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
@@ -79,22 +87,22 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
},
"node_modules/@next/env": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.2.1.tgz",
"integrity": "sha512-Hq+6QZ6kgmloCg8Kgrix+4F0HtvLqVK3FZAnlAoS0eonaDemHe1Km4kwjSWRE3JNpJNcKxFHF+jsZrYo0SxWoQ=="
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.2.3.tgz",
"integrity": "sha512-FN50r/E+b8wuqyRjmGaqvqNDuWBWYWQiigfZ50KnSFH0f+AMQQyaZl+Zm2+CIpKk0fL9QxhLxOpTVA3xFHgFow=="
},
"node_modules/@next/eslint-plugin-next": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.2.1.tgz",
"integrity": "sha512-r0i5rcO6SMAZtqiGarUVMr3k256X0R0j6pEkKg4PxqUW+hG0qgMxRVAJsuoRG5OBFkCOlSfWZJ0mP9fQdCcyNg==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.2.3.tgz",
"integrity": "sha512-QmMPItnU7VeojI1KnuwL9SLFWEwmaNHNlnOGpoTwdLoSiP9sc8KYiAHWEc4/44L+cAdCxcZYvn7frcRNP5l84Q==",
"dependencies": {
"glob": "7.1.7"
}
},
"node_modules/@next/swc-android-arm-eabi": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.2.1.tgz",
"integrity": "sha512-Yua7mUpEd1wzIT6Jjl3dpRizIfGp9NR4F2xeRuQv+ae+SDI1Em2WyM9m46UL+oeW5GpMiEHoaBagr47RScZFmQ==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.2.3.tgz",
"integrity": "sha512-mykdVaAXX/gm+eFO2kPeVjnOCKwanJ9mV2U0lsUGLrEdMUifPUjiXKc6qFAIs08PvmTMOLMNnUxqhGsJlWGKSw==",
"cpu": [
"arm"
],
@@ -107,9 +115,9 @@
}
},
"node_modules/@next/swc-android-arm64": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.2.1.tgz",
"integrity": "sha512-Bifcr2f6VwInOdq1uH/9lp8fH7Nf7XGkIx4XceVd32LPJqG2c6FZU8ZRBvTdhxzXVpt5TPtuXhOP4Ij9UPqsVw==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.2.3.tgz",
"integrity": "sha512-8XwHPpA12gdIFtope+n9xCtJZM3U4gH4vVTpUwJ2w1kfxFmCpwQ4xmeGSkR67uOg80yRMuF0h9V1ueo05sws5w==",
"cpu": [
"arm64"
],
@@ -122,9 +130,9 @@
}
},
"node_modules/@next/swc-darwin-arm64": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.2.1.tgz",
"integrity": "sha512-gvqm+fGMYxAkwBapH0Vvng5yrb6HTkIvZfY4oEdwwYrwuLdkjqnJygCMgpNqIFmAHSXgtlWxfYv1VC8sjN81Kw==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.2.3.tgz",
"integrity": "sha512-TXOubiFdLpMfMtaRu1K5d1I9ipKbW5iS2BNbu8zJhoqrhk3Kp7aRKTxqFfWrbliAHhWVE/3fQZUYZOWSXVQi1w==",
"cpu": [
"arm64"
],
@@ -137,9 +145,9 @@
}
},
"node_modules/@next/swc-darwin-x64": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.2.1.tgz",
"integrity": "sha512-HGqVqmaZWj6zomqOZUVbO5NhlABL0iIaxTmd0O5B0MoMa5zpDGoaHSG+fxgcWMXcGcxmUNchv1NfNOYiTKoHOg==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.2.3.tgz",
"integrity": "sha512-GZctkN6bJbpjlFiS5pylgB2pifHvgkqLAPumJzxnxkf7kqNm6rOGuNjsROvOWVWXmKhrzQkREO/WPS2aWsr/yw==",
"cpu": [
"x64"
],
@@ -152,9 +160,9 @@
}
},
"node_modules/@next/swc-freebsd-x64": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.2.1.tgz",
"integrity": "sha512-N/a4JarAq+E+g+9K2ywJUmDIgU2xs2nA+BBldH0oq4zYJMRiUhL0iaN9G4e72VmGOJ61L/3W6VN8RIUOwTLoqQ==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.2.3.tgz",
"integrity": "sha512-rK6GpmMt/mU6MPuav0/M7hJ/3t8HbKPCELw/Uqhi4732xoq2hJ2zbo2FkYs56y6w0KiXrIp4IOwNB9K8L/q62g==",
"cpu": [
"x64"
],
@@ -167,9 +175,9 @@
}
},
"node_modules/@next/swc-linux-arm-gnueabihf": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.2.1.tgz",
"integrity": "sha512-WaFoerF/eRbhbE57TaIGJXbQAERADZ/RZ45u6qox9beb5xnWsyYgzX+WuN7Tkhyvga0/aMuVYFzS9CEay7D+bw==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.2.3.tgz",
"integrity": "sha512-yeiCp/Odt1UJ4KUE89XkeaaboIDiVFqKP4esvoLKGJ0fcqJXMofj4ad3tuQxAMs3F+qqrz9MclqhAHkex1aPZA==",
"cpu": [
"arm"
],
@@ -182,9 +190,9 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.2.1.tgz",
"integrity": "sha512-R+Jhc1/RJTnncE9fkePboHDNOCm1WJ8daanWbjKhfPySMyeniKYRwGn5SLYW3S8YlRS0QVdZaaszDSZWgUcsmA==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.2.3.tgz",
"integrity": "sha512-/miIopDOUsuNlvjBjTipvoyjjaxgkOuvlz+cIbbPcm1eFvzX2ltSfgMgty15GuOiR8Hub4FeTSiq3g2dmCkzGA==",
"cpu": [
"arm64"
],
@@ -197,9 +205,9 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.2.1.tgz",
"integrity": "sha512-oI1UfZPidGAVddlL2eOTmfsuKV9EaT1aktIzVIxIAgxzQSdwsV371gU3G55ggkurzfdlgF3GThFePDWF0d8dmw==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.2.3.tgz",
"integrity": "sha512-sujxFDhMMDjqhruup8LLGV/y+nCPi6nm5DlFoThMJFvaaKr/imhkXuk8uCTq4YJDbtRxnjydFv2y8laBSJVC2g==",
"cpu": [
"arm64"
],
@@ -212,9 +220,9 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.2.1.tgz",
"integrity": "sha512-PCygPwrQmS+7WUuAWWioWMZCzZm4PG91lfRxToLDg7yIm/3YfAw5N2EK2TaM9pzlWdvHQAqRMX/oLvv027xUiA==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.2.3.tgz",
"integrity": "sha512-w5MyxPknVvC9LVnMenAYMXMx4KxPwXuJRMQFvY71uXg68n7cvcas85U5zkdrbmuZ+JvsO5SIG8k36/6X3nUhmQ==",
"cpu": [
"x64"
],
@@ -227,9 +235,9 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.2.1.tgz",
"integrity": "sha512-sUAKxo7CFZYGHNxheGh9nIBElLYBM6md/liEGfOTwh/xna4/GTTcmkGWkF7PdnvaYNgcPIQgHIMYiAa6yBKAVw==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.2.3.tgz",
"integrity": "sha512-CTeelh8OzSOVqpzMFMFnVRJIFAFQoTsI9RmVJWW/92S4xfECGcOzgsX37CZ8K982WHRzKU7exeh7vYdG/Eh4CA==",
"cpu": [
"x64"
],
@@ -242,9 +250,9 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.2.1.tgz",
"integrity": "sha512-qDmyEjDBpl/vBXxuOOKKWmPQOcARcZIMach1s7kjzaien0SySut/PHRlj56sosa81Wt4hTGhfhZ1R7g1n7+B8w==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.2.3.tgz",
"integrity": "sha512-7N1KBQP5mo4xf52cFCHgMjzbc9jizIlkTepe9tMa2WFvEIlKDfdt38QYcr9mbtny17yuaIw02FXOVEytGzqdOQ==",
"cpu": [
"arm64"
],
@@ -257,9 +265,9 @@
}
},
"node_modules/@next/swc-win32-ia32-msvc": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.2.1.tgz",
"integrity": "sha512-2joqFQ81ZYPg6DcikIzQn3DgjKglNhPAozx6dL5sCNkr1CPMD0YIkJgT3CnYyMHQ04Qi3Npv0XX3MD6LJO8OCA==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.2.3.tgz",
"integrity": "sha512-LzWD5pTSipUXTEMRjtxES/NBYktuZdo7xExJqGDMnZU8WOI+v9mQzsmQgZS/q02eIv78JOCSemqVVKZBGCgUvA==",
"cpu": [
"ia32"
],
@@ -272,9 +280,9 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.2.1.tgz",
"integrity": "sha512-r3+0fSaIZT6N237iMzwUhfNwjhAFvXjqB+4iuW+wcpxW+LHm1g/IoxN8eSRcb8jPItC86JxjAxpke0QL97qd6g==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.2.3.tgz",
"integrity": "sha512-aLG2MaFs4y7IwaMTosz2r4mVbqRyCnMoFqOcmfTi7/mAS+G4IMH0vJp4oLdbshqiVoiVuKrAfqtXj55/m7Qu1Q==",
"cpu": [
"x64"
],
@@ -356,13 +364,13 @@
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
},
"node_modules/@typescript-eslint/parser": {
"version": "5.53.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.53.0.tgz",
"integrity": "sha512-MKBw9i0DLYlmdOb3Oq/526+al20AJZpANdT6Ct9ffxcV8nKCHz63t/S0IhlTFNsBIHJv+GY5SFJ0XfqVeydQrQ==",
"version": "5.54.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.0.tgz",
"integrity": "sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ==",
"dependencies": {
"@typescript-eslint/scope-manager": "5.53.0",
"@typescript-eslint/types": "5.53.0",
"@typescript-eslint/typescript-estree": "5.53.0",
"@typescript-eslint/scope-manager": "5.54.0",
"@typescript-eslint/types": "5.54.0",
"@typescript-eslint/typescript-estree": "5.54.0",
"debug": "^4.3.4"
},
"engines": {
@@ -382,12 +390,12 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "5.53.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.53.0.tgz",
"integrity": "sha512-Opy3dqNsp/9kBBeCPhkCNR7fmdSQqA+47r21hr9a14Bx0xnkElEQmhoHga+VoaoQ6uDHjDKmQPIYcUcKJifS7w==",
"version": "5.54.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.54.0.tgz",
"integrity": "sha512-VTPYNZ7vaWtYna9M4oD42zENOBrb+ZYyCNdFs949GcN8Miwn37b8b7eMj+EZaq7VK9fx0Jd+JhmkhjFhvnovhg==",
"dependencies": {
"@typescript-eslint/types": "5.53.0",
"@typescript-eslint/visitor-keys": "5.53.0"
"@typescript-eslint/types": "5.54.0",
"@typescript-eslint/visitor-keys": "5.54.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -398,9 +406,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "5.53.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.53.0.tgz",
"integrity": "sha512-5kcDL9ZUIP756K6+QOAfPkigJmCPHcLN7Zjdz76lQWWDdzfOhZDTj1irs6gPBKiXx5/6O3L0+AvupAut3z7D2A==",
"version": "5.54.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.54.0.tgz",
"integrity": "sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ==",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
@@ -410,12 +418,12 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "5.53.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.53.0.tgz",
"integrity": "sha512-eKmipH7QyScpHSkhbptBBYh9v8FxtngLquq292YTEQ1pxVs39yFBlLC1xeIZcPPz1RWGqb7YgERJRGkjw8ZV7w==",
"version": "5.54.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.0.tgz",
"integrity": "sha512-X2rJG97Wj/VRo5YxJ8Qx26Zqf0RRKsVHd4sav8NElhbZzhpBI8jU54i6hfo9eheumj4oO4dcRN1B/zIVEqR/MQ==",
"dependencies": {
"@typescript-eslint/types": "5.53.0",
"@typescript-eslint/visitor-keys": "5.53.0",
"@typescript-eslint/types": "5.54.0",
"@typescript-eslint/visitor-keys": "5.54.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@@ -436,11 +444,11 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "5.53.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.53.0.tgz",
"integrity": "sha512-JqNLnX3leaHFZEN0gCh81sIvgrp/2GOACZNgO4+Tkf64u51kTpAyWFOY8XHx8XuXr3N2C9zgPPHtcpMg6z1g0w==",
"version": "5.54.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.0.tgz",
"integrity": "sha512-xu4wT7aRCakGINTLGeyGqDn+78BwFlggwBjnHa1ar/KaGagnmwLYmlrXIrgAaQ3AE1Vd6nLfKASm7LrFHNbKGA==",
"dependencies": {
"@typescript-eslint/types": "5.53.0",
"@typescript-eslint/types": "5.54.0",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
@@ -670,9 +678,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001457",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001457.tgz",
"integrity": "sha512-SDIV6bgE1aVbK6XyxdURbUE89zY7+k1BBBaOwYwkNCglXlel/E7mELiHC64HQ+W0xSKlqWhV9Wh7iHxUjMs4fA==",
"version": "1.0.30001458",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001458.tgz",
"integrity": "sha512-lQ1VlUUq5q9ro9X+5gOEyH7i3vm+AYVT1WDCVB69XOZ17KZRhnZ9J0Sqz7wTHQaLBJccNCHq8/Ww5LlOIZbB0w==",
"funding": [
{
"type": "opencollective",
@@ -967,11 +975,12 @@
}
},
"node_modules/eslint": {
"version": "8.34.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz",
"integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==",
"version": "8.35.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.35.0.tgz",
"integrity": "sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw==",
"dependencies": {
"@eslint/eslintrc": "^1.4.1",
"@eslint/eslintrc": "^2.0.0",
"@eslint/js": "8.35.0",
"@humanwhocodes/config-array": "^0.11.8",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@@ -985,7 +994,7 @@
"eslint-utils": "^3.0.0",
"eslint-visitor-keys": "^3.3.0",
"espree": "^9.4.0",
"esquery": "^1.4.0",
"esquery": "^1.4.2",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
"file-entry-cache": "^6.0.1",
@@ -1022,11 +1031,11 @@
}
},
"node_modules/eslint-config-next": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.2.1.tgz",
"integrity": "sha512-2GAx7EjSiCzJN6H2L/v1kbYrNiwQxzkyjy6eWSjuhAKt+P6d3nVNHGy9mON8ZcYd72w/M8kyMjm4UB9cvijgrw==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.2.3.tgz",
"integrity": "sha512-kPulHiQEHGei9hIaaNGygHRc0UzlWM+3euOmYbxNkd2Nbhci5rrCDeMBMPSV8xgUssphDGmwDHWbk4VZz3rlZQ==",
"dependencies": {
"@next/eslint-plugin-next": "13.2.1",
"@next/eslint-plugin-next": "13.2.3",
"@rushstack/eslint-patch": "^1.1.3",
"@typescript-eslint/parser": "^5.42.0",
"eslint-import-resolver-node": "^0.3.6",
@@ -2317,11 +2326,11 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="
},
"node_modules/next": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/next/-/next-13.2.1.tgz",
"integrity": "sha512-qhgJlDtG0xidNViJUPeQHLGJJoT4zDj/El7fP3D3OzpxJDUfxsm16cK4WTMyvSX1ciIfAq05u+0HqFAa+VJ+Hg==",
"version": "13.2.3",
"resolved": "https://registry.npmjs.org/next/-/next-13.2.3.tgz",
"integrity": "sha512-nKFJC6upCPN7DWRx4+0S/1PIOT7vNlCT157w9AzbXEgKy6zkiPKEt5YyRUsRZkmpEqBVrGgOqNfwecTociyg+w==",
"dependencies": {
"@next/env": "13.2.1",
"@next/env": "13.2.3",
"@swc/helpers": "0.4.14",
"caniuse-lite": "^1.0.30001406",
"postcss": "8.4.14",
@@ -2334,19 +2343,19 @@
"node": ">=14.6.0"
},
"optionalDependencies": {
"@next/swc-android-arm-eabi": "13.2.1",
"@next/swc-android-arm64": "13.2.1",
"@next/swc-darwin-arm64": "13.2.1",
"@next/swc-darwin-x64": "13.2.1",
"@next/swc-freebsd-x64": "13.2.1",
"@next/swc-linux-arm-gnueabihf": "13.2.1",
"@next/swc-linux-arm64-gnu": "13.2.1",
"@next/swc-linux-arm64-musl": "13.2.1",
"@next/swc-linux-x64-gnu": "13.2.1",
"@next/swc-linux-x64-musl": "13.2.1",
"@next/swc-win32-arm64-msvc": "13.2.1",
"@next/swc-win32-ia32-msvc": "13.2.1",
"@next/swc-win32-x64-msvc": "13.2.1"
"@next/swc-android-arm-eabi": "13.2.3",
"@next/swc-android-arm64": "13.2.3",
"@next/swc-darwin-arm64": "13.2.3",
"@next/swc-darwin-x64": "13.2.3",
"@next/swc-freebsd-x64": "13.2.3",
"@next/swc-linux-arm-gnueabihf": "13.2.3",
"@next/swc-linux-arm64-gnu": "13.2.3",
"@next/swc-linux-arm64-musl": "13.2.3",
"@next/swc-linux-x64-gnu": "13.2.3",
"@next/swc-linux-x64-musl": "13.2.3",
"@next/swc-win32-arm64-msvc": "13.2.3",
"@next/swc-win32-ia32-msvc": "13.2.3",
"@next/swc-win32-x64-msvc": "13.2.3"
},
"peerDependencies": {
"@opentelemetry/api": "^1.4.0",
@@ -3074,12 +3083,12 @@
}
},
"node_modules/tsconfig-paths": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
"integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==",
"version": "3.14.2",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
"integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==",
"dependencies": {
"@types/json5": "^0.0.29",
"json5": "^1.0.1",
"json5": "^1.0.2",
"minimist": "^1.2.6",
"strip-bom": "^3.0.0"
}

View File

@@ -9,9 +9,9 @@
"lint": "next lint"
},
"dependencies": {
"eslint": "8.34.0",
"eslint-config-next": "13.2.1",
"next": "13.2.1",
"eslint": "8.35.0",
"eslint-config-next": "13.2.3",
"next": "13.2.3",
"react": "18.2.0",
"react-dom": "18.2.0"
}

View File

@@ -32,7 +32,7 @@
"source-map-support": "0.5.12",
"ts-eager": "2.0.2",
"ts-jest": "28.0.5",
"turbo": "1.7.4"
"turbo": "1.8.2"
},
"scripts": {
"lerna": "lerna",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/build-utils",
"version": "6.3.1",
"version": "6.3.2",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",

View File

@@ -25,12 +25,16 @@ export async function readConfigFile<T>(
if (data) {
const str = data.toString('utf8');
if (name.endsWith('.json')) {
return JSON.parse(str) as T;
} else if (name.endsWith('.toml')) {
return (toml.parse(str) as unknown) as T;
} else if (name.endsWith('.yaml') || name.endsWith('.yml')) {
return yaml.safeLoad(str, { filename: name }) as T;
try {
if (name.endsWith('.json')) {
return JSON.parse(str) as T;
} else if (name.endsWith('.toml')) {
return toml.parse(str) as unknown as T;
} else if (name.endsWith('.yaml') || name.endsWith('.yml')) {
return yaml.safeLoad(str, { filename: name }) as T;
}
} catch (error: unknown) {
console.log(`Error while parsing config file: "${name}"`);
}
}
}

View File

@@ -0,0 +1,77 @@
import { join } from 'path';
import { writeFile, rm } from 'fs/promises';
import { readConfigFile } from '../src';
describe('Test `readConfigFile()`', () => {
let logMessages: string[];
const originalConsoleLog = console.log;
beforeEach(() => {
logMessages = [];
console.log = m => {
logMessages.push(m);
};
});
afterEach(() => {
console.log = originalConsoleLog;
});
const doesnotexist = join(__dirname, 'does-not-exist.json');
const tsconfig = join(__dirname, '../tsconfig.json');
const invalid = join(__dirname, 'invalid.json');
it('should return null when file does not exist', async () => {
expect(await readConfigFile(doesnotexist)).toBeNull();
expect(logMessages).toEqual([]);
});
it('should return parsed object when file exists', async () => {
expect(await readConfigFile(tsconfig)).toMatchObject({
compilerOptions: {
strict: true,
},
});
expect(logMessages).toEqual([]);
});
it('should return parsed object when at least one file exists', async () => {
const files = [doesnotexist, tsconfig];
expect(await readConfigFile(files)).toMatchObject({
compilerOptions: {
strict: true,
},
});
expect(logMessages).toEqual([]);
});
it('should return null when parse fails', async () => {
try {
await writeFile(invalid, 'borked');
expect(await readConfigFile(invalid)).toBeNull();
} finally {
await rm(invalid);
}
expect(logMessages.length).toBe(1);
expect(logMessages[0]).toMatch(
/^Error while parsing config file.+invalid.json/
);
});
it('should return parsed object when at least one file is valid', async () => {
try {
await writeFile(invalid, 'borked');
expect(await readConfigFile([invalid, tsconfig])).toMatchObject({
compilerOptions: {
strict: true,
},
});
} finally {
await rm(invalid);
}
expect(logMessages.length).toBe(1);
expect(logMessages[0]).toMatch(
/^Error while parsing config file.+invalid.json/
);
});
});

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "28.16.7",
"version": "28.16.12",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Vercel",
@@ -41,16 +41,16 @@
"node": ">= 14"
},
"dependencies": {
"@vercel/build-utils": "6.3.1",
"@vercel/go": "2.3.8",
"@vercel/hydrogen": "0.0.54",
"@vercel/next": "3.6.1",
"@vercel/node": "2.9.8",
"@vercel/python": "3.1.50",
"@vercel/redwood": "1.1.6",
"@vercel/remix": "1.4.1",
"@vercel/ruby": "1.3.67",
"@vercel/static-build": "1.3.12"
"@vercel/build-utils": "6.3.2",
"@vercel/go": "2.3.9",
"@vercel/hydrogen": "0.0.55",
"@vercel/next": "3.6.3",
"@vercel/node": "2.9.10",
"@vercel/python": "3.1.51",
"@vercel/redwood": "1.1.7",
"@vercel/remix": "1.5.1",
"@vercel/ruby": "1.3.68",
"@vercel/static-build": "1.3.14"
},
"devDependencies": {
"@alex_neo/jest-expect-message": "1.0.5",
@@ -93,13 +93,13 @@
"@types/which": "1.3.2",
"@types/write-json-file": "2.2.1",
"@types/yauzl-promise": "2.1.0",
"@vercel/client": "12.4.1",
"@vercel/client": "12.4.2",
"@vercel/error-utils": "1.0.8",
"@vercel/frameworks": "1.3.1",
"@vercel/fs-detectors": "3.8.1",
"@vercel/frameworks": "1.3.2",
"@vercel/fs-detectors": "3.8.2",
"@vercel/fun": "1.0.4",
"@vercel/ncc": "0.24.0",
"@vercel/routing-utils": "2.1.9",
"@vercel/routing-utils": "2.1.10",
"@zeit/source-map-support": "0.6.2",
"ajv": "6.12.2",
"alpha-sort": "2.0.1",

View File

@@ -9,6 +9,7 @@ import { ProjectLinkAndSettings } from '../projects/project-settings';
import { Output } from '../output';
import title from 'title';
import { PartialProjectSettings } from '../input/edit-project-settings';
import { debug } from '@vercel/build-utils';
export async function setMonorepoDefaultSettings(
cwd: string,
@@ -26,8 +27,8 @@ export async function setMonorepoDefaultSettings(
value: string
) => {
if (projectSettings[command]) {
output.warn(
`Cannot automatically assign ${command} as it is already set via project settings or configuration overrides.`
debug(
`Skipping auto-assignment of ${command} as it is already set via project settings or configuration overrides.`
);
} else {
projectSettings[command] = value;

View File

@@ -6,6 +6,4 @@
{{?}}
<span class="devinfo-line">ID: <code>{{! it.request_id }}</code>
</p>
<a href="https://vercel.link/404"><div class="note">Click here to learn more about this error.</div></a>
</main>

View File

@@ -247,6 +247,14 @@ async function fetchDistTags(name) {
});
res.on('end', () => {
try {
if (res.statusCode && res.statusCode >= 400) {
return reject(
new Error(
`Fetch dist-tags failed ${res.statusCode} ${res.statusMessage}`
)
);
}
resolve(JSON.parse(buf));
} catch (err) {
reject(err);

View File

@@ -484,6 +484,7 @@ describe('build', () => {
{
src: '^/.*$',
middlewarePath: 'middleware',
middlewareRawSrc: [],
override: true,
continue: true,
},
@@ -548,6 +549,7 @@ describe('build', () => {
{
src: '^/.*$',
middlewarePath: 'middleware',
middlewareRawSrc: [],
override: true,
continue: true,
},
@@ -612,6 +614,7 @@ describe('build', () => {
{
src: '^\\/about(?:\\/((?:[^\\/#\\?]+?)(?:\\/(?:[^\\/#\\?]+?))*))?[\\/#\\?]?$|^\\/dashboard(?:\\/((?:[^\\/#\\?]+?)(?:\\/(?:[^\\/#\\?]+?))*))?[\\/#\\?]?$',
middlewarePath: 'middleware',
middlewareRawSrc: ['/about/:path*', '/dashboard/:path*'],
override: true,
continue: true,
},

13
packages/cli/turbo.json Normal file
View File

@@ -0,0 +1,13 @@
{
"$schema": "https://turborepo.org/schema.json",
"extends": ["//"],
"pipeline": {
"build": {
"outputs": [
"dist/**",
"src/util/constants.ts",
"src/util/dev/templates/*.ts"
]
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/client",
"version": "12.4.1",
"version": "12.4.2",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"homepage": "https://vercel.com",
@@ -43,8 +43,8 @@
]
},
"dependencies": {
"@vercel/build-utils": "6.3.1",
"@vercel/routing-utils": "2.1.9",
"@vercel/build-utils": "6.3.2",
"@vercel/routing-utils": "2.1.10",
"@zeit/fetch": "5.2.0",
"async-retry": "1.2.3",
"async-sema": "3.0.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/edge",
"version": "0.3.0",
"version": "0.3.1",
"license": "MIT",
"main": "dist/index.js",
"module": "dist/index.mjs",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/frameworks",
"version": "1.3.1",
"version": "1.3.2",
"main": "./dist/frameworks.js",
"types": "./dist/frameworks.d.ts",
"files": [
@@ -21,7 +21,7 @@
"@types/js-yaml": "3.12.1",
"@types/node": "14.18.33",
"@types/node-fetch": "2.5.8",
"@vercel/routing-utils": "2.1.9",
"@vercel/routing-utils": "2.1.10",
"ajv": "6.12.2",
"typescript": "4.3.4"
}

View File

@@ -202,12 +202,13 @@ export const frameworks = [
useRuntime: { src: 'package.json', use: '@vercel/remix' },
ignoreRuntimes: ['@vercel/node'],
detectors: {
every: [
// Intentionally does not detect a package name
// https://github.com/vercel/vercel/pull/7761
some: [
{
path: 'remix.config.js',
},
{
path: 'remix.config.mjs',
},
],
},
settings: {
@@ -1698,6 +1699,7 @@ export const frameworks = [
description: 'React framework for headless commerce',
website: 'https://hydrogen.shopify.dev',
useRuntime: { src: 'package.json', use: '@vercel/hydrogen' },
envPrefix: 'PUBLIC_',
detectors: {
some: [
{

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/fs-detectors",
"version": "3.8.1",
"version": "3.8.2",
"description": "Vercel filesystem detectors",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -20,8 +20,8 @@
},
"dependencies": {
"@vercel/error-utils": "1.0.8",
"@vercel/frameworks": "1.3.1",
"@vercel/routing-utils": "2.1.9",
"@vercel/frameworks": "1.3.2",
"@vercel/routing-utils": "2.1.10",
"glob": "8.0.3",
"js-yaml": "4.1.0",
"json5": "2.2.2",
@@ -35,7 +35,7 @@
"@types/minimatch": "3.0.5",
"@types/node": "14.18.33",
"@types/semver": "7.3.10",
"@vercel/build-utils": "6.3.1",
"@vercel/build-utils": "6.3.2",
"typescript": "4.3.4"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/gatsby-plugin-vercel-analytics",
"version": "1.0.7",
"version": "1.0.8",
"description": "Track Core Web Vitals in Gatsby projects with Vercel Analytics.",
"main": "index.js",
"files": [

View File

@@ -0,0 +1,9 @@
{
"$schema": "https://turborepo.org/schema.json",
"extends": ["//"],
"pipeline": {
"build": {
"outputs": ["gatsby-browser.js", "web-vitals.js", "index.js"]
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/gatsby-plugin-vercel-builder",
"version": "1.1.9",
"version": "1.1.11",
"main": "dist/index.js",
"files": [
"dist",
@@ -14,9 +14,9 @@
"build:src": "tsc -p tsconfig.src.json"
},
"dependencies": {
"@vercel/build-utils": "6.3.1",
"@vercel/node": "2.9.8",
"@vercel/routing-utils": "2.1.9",
"@vercel/build-utils": "6.3.2",
"@vercel/node": "2.9.10",
"@vercel/routing-utils": "2.1.10",
"ajv": "8.12.0",
"esbuild": "0.14.47",
"etag": "1.8.1",

View File

@@ -0,0 +1,9 @@
{
"$schema": "https://turborepo.org/schema.json",
"extends": ["//"],
"pipeline": {
"build": {
"outputs": ["dist/**", "gatsby-node.js"]
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/go",
"version": "2.3.8",
"version": "2.3.9",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
@@ -36,7 +36,7 @@
"@types/node": "14.18.33",
"@types/node-fetch": "^2.3.0",
"@types/tar": "^4.0.0",
"@vercel/build-utils": "6.3.1",
"@vercel/build-utils": "6.3.2",
"@vercel/ncc": "0.24.0",
"async-retry": "1.3.1",
"execa": "^1.0.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/hydrogen",
"version": "0.0.54",
"version": "0.0.55",
"license": "MIT",
"main": "./dist/index.js",
"homepage": "https://vercel.com/docs",
@@ -21,7 +21,7 @@
"devDependencies": {
"@types/jest": "27.5.1",
"@types/node": "14.18.33",
"@vercel/build-utils": "6.3.1",
"@vercel/build-utils": "6.3.2",
"@vercel/static-config": "2.0.13",
"execa": "3.2.0",
"fs-extra": "11.1.0",

View File

@@ -7,6 +7,7 @@ import {
execCommand,
getEnvForPackageManager,
getNodeVersion,
getPrefixedEnvVars,
getSpawnOptions,
glob,
readConfigFile,
@@ -29,6 +30,15 @@ export const build: BuildV2 = async ({
await download(files, workPath, meta);
const prefixedEnvs = getPrefixedEnvVars({
envPrefix: 'PUBLIC_',
envs: process.env,
});
for (const [key, value] of Object.entries(prefixedEnvs)) {
process.env[key] = value;
}
const mountpoint = dirname(entrypoint);
const entrypointDir = join(workPath, mountpoint);

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/next",
"version": "3.6.1",
"version": "3.6.3",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
@@ -45,9 +45,9 @@
"@types/semver": "6.0.0",
"@types/text-table": "0.2.1",
"@types/webpack-sources": "3.2.0",
"@vercel/build-utils": "6.3.1",
"@vercel/build-utils": "6.3.2",
"@vercel/nft": "0.22.5",
"@vercel/routing-utils": "2.1.9",
"@vercel/routing-utils": "2.1.10",
"async-sema": "3.0.1",
"buffer-crc32": "0.2.13",
"bytes": "3.1.2",

View File

@@ -150,6 +150,10 @@ export async function serverBuild({
nextVersion,
EMPTY_ALLOW_QUERY_FOR_PRERENDERED_VERSION
);
const projectDir = requiredServerFilesManifest.relativeAppDir
? path.join(baseDir, requiredServerFilesManifest.relativeAppDir)
: requiredServerFilesManifest.appDir || entryPath;
let appBuildTraces: UnwrapPromise<ReturnType<typeof glob>> = {};
let appDir: string | null = null;
@@ -269,9 +273,10 @@ export async function serverBuild({
let initialFileList: string[];
let initialFileReasons: NodeFileTraceReasons;
let nextServerBuildTrace;
let instrumentationHookBuildTrace;
const nextServerFile = resolveFrom(
requiredServerFilesManifest.appDir || entryPath,
projectDir,
`${getNextServerPath(nextVersion)}/next-server.js`
);
@@ -287,6 +292,22 @@ export async function serverBuild({
// if the trace is unavailable we trace inside the runtime
}
try {
instrumentationHookBuildTrace = JSON.parse(
await fs.readFile(
path.join(
entryPath,
outputDirectory,
'server',
'instrumentation.js.nft.json'
),
'utf8'
)
);
} catch (_) {
// if the trace is unavailable it means `instrumentation.js` wasn't used
}
if (nextServerBuildTrace) {
initialFileList = nextServerBuildTrace.files.map((file: string) => {
return path.relative(
@@ -321,6 +342,18 @@ export async function serverBuild({
initialFileReasons = result.reasons;
}
if (instrumentationHookBuildTrace) {
initialFileList = initialFileList.concat(
instrumentationHookBuildTrace.files.map((file: string) => {
return path.relative(
baseDir,
path.join(entryPath, outputDirectory, 'server', file)
);
})
);
debug('Using instrumentation.js.nft.json trace from build');
}
debug('collecting initial Next.js server files');
await Promise.all(
initialFileList.map(
@@ -437,8 +470,8 @@ export async function serverBuild({
file
);
if (requiredServerFilesManifest.appDir) {
fsPath = path.join(requiredServerFilesManifest.appDir, file);
if (projectDir) {
fsPath = path.join(projectDir, file);
}
const relativePath = path.relative(baseDir, fsPath);
@@ -516,7 +549,7 @@ export async function serverBuild({
`conf: ${JSON.stringify({
...requiredServerFilesManifest.config,
distDir: path.relative(
requiredServerFilesManifest.appDir || entryPath,
projectDir,
path.join(entryPath, outputDirectory)
),
compress: false,
@@ -543,10 +576,8 @@ export async function serverBuild({
}
const launcherFiles: { [name: string]: FileFsRef | FileBlob } = {
[path.join(
path.relative(baseDir, requiredServerFilesManifest.appDir || entryPath),
'___next_launcher.cjs'
)]: new FileBlob({ data: launcher }),
[path.join(path.relative(baseDir, projectDir), '___next_launcher.cjs')]:
new FileBlob({ data: launcher }),
};
const pageTraces: {
[page: string]: { [key: string]: FileFsRef };
@@ -594,7 +625,7 @@ export async function serverBuild({
traceResult = await nodeFileTrace(pathsToTrace, {
base: baseDir,
cache: traceCache,
processCwd: requiredServerFilesManifest.appDir || entryPath,
processCwd: projectDir,
});
traceResult.esmFileList.forEach(file => traceResult?.fileList.add(file));
parentFilesMap = getFilesMapFromReasons(
@@ -703,7 +734,7 @@ export async function serverBuild({
const pageExtensions = requiredServerFilesManifest.config?.pageExtensions;
const pageLambdaGroups = await getPageLambdaGroups({
entryPath: requiredServerFilesManifest.appDir || entryPath,
entryPath: projectDir,
config,
pages: nonApiPages,
prerenderRoutes,
@@ -718,7 +749,7 @@ export async function serverBuild({
});
const streamingPageLambdaGroups = await getPageLambdaGroups({
entryPath: requiredServerFilesManifest.appDir || entryPath,
entryPath: projectDir,
config,
pages: streamingPages,
prerenderRoutes,
@@ -739,7 +770,7 @@ export async function serverBuild({
}
const apiLambdaGroups = await getPageLambdaGroups({
entryPath: requiredServerFilesManifest.appDir || entryPath,
entryPath: projectDir,
config,
pages: apiPages,
prerenderRoutes,
@@ -873,10 +904,7 @@ export async function serverBuild({
},
layers: [group.pseudoLayer, groupPageFiles],
handler: path.join(
path.relative(
baseDir,
requiredServerFilesManifest.appDir || entryPath
),
path.relative(baseDir, projectDir),
'___next_launcher.cjs'
),
operationType,
@@ -1528,7 +1556,7 @@ export async function serverBuild({
{
src: `^${path.posix.join('/', entryDirectory)}/?(?:${i18n.locales
.map(locale => escapeStringRegexp(locale))
.join('|')})/(.*)`,
.join('|')})/?(.*)`,
dest: `${path.posix.join('/', entryDirectory, '/')}$1`,
check: true,
},

View File

@@ -811,6 +811,7 @@ export async function createLambdaFromPseudoLayers({
export type NextRequiredServerFilesManifest = {
appDir?: string;
relativeAppDir?: string;
files: string[];
ignore: string[];
config: Record<string, any>;
@@ -954,6 +955,7 @@ export async function getRequiredServerFilesManifest(
ignore: [],
config: {},
appDir: manifestData.appDir,
relativeAppDir: manifestData.relativeAppDir,
};
switch (manifestData.version) {

View File

@@ -0,0 +1 @@
.vercel

View File

@@ -0,0 +1,3 @@
export default function Page() {
return <p>My Enter Page</p>;
}

View File

@@ -0,0 +1,10 @@
export default function Root({ children }) {
return (
<html lang="en">
<head>
<title>My Title</title>
</head>
<body>{children}</body>
</html>
);
}

View File

@@ -0,0 +1,3 @@
export default function Page() {
return <p>My Other Page</p>;
}

View File

@@ -0,0 +1,3 @@
export default function Page() {
return <p>My Index Page</p>;
}

View File

@@ -0,0 +1,12 @@
/* eslint-env jest */
const path = require('path');
const { deployAndTest } = require('../../utils');
const ctx = {};
describe(`${__dirname.split(path.sep).pop()}`, () => {
it('should deploy and pass probe checks', async () => {
const info = await deployAndTest(__dirname);
Object.assign(ctx, info);
});
});

View File

@@ -0,0 +1,9 @@
module.exports = {
experimental: {
appDir: true,
},
i18n: {
locales: ['en'],
defaultLocale: 'en',
},
};

View File

@@ -0,0 +1,13 @@
{
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "canary",
"react": "experimental",
"react-dom": "experimental"
}
}

View File

@@ -0,0 +1,34 @@
{
"probes": [
{
"fetchOptions": { "redirect": "manual" },
"path": "/",
"status": 200,
"mustContain": "My Index Page"
},
{
"fetchOptions": { "redirect": "manual" },
"path": "/en",
"status": 200,
"mustContain": "My Index Page"
},
{
"fetchOptions": { "redirect": "manual" },
"path": "/enter",
"status": 200,
"mustContain": "My Enter Page"
},
{
"fetchOptions": { "redirect": "manual" },
"path": "/other",
"status": 200,
"mustContain": "My Other Page"
},
{
"fetchOptions": { "redirect": "manual" },
"path": "/en/other",
"status": 200,
"mustContain": "My Other Page"
}
]
}

View File

@@ -0,0 +1 @@
.vercel

View File

@@ -0,0 +1,7 @@
{
"name": "web",
"private": true,
"scripts": {
"build": "next build && rm -rf .next/cache && node post-build.js"
}
}

View File

@@ -0,0 +1,3 @@
export default function Page() {
return <p>index page</p>;
}

View File

@@ -0,0 +1,12 @@
export default function Page() {
return <p>ssg page</p>;
}
export function getStaticProps() {
return {
props: {
now: Date.now(),
},
revalidate: 3,
};
}

View File

@@ -0,0 +1,11 @@
export default function Page() {
return <p>ssp page</p>;
}
export function getServerSideProps() {
return {
props: {
now: Date.now(),
},
};
}

View File

@@ -0,0 +1,19 @@
const fs = require('fs');
const path = require('path');
const requiredFilesManifestPath = path.join(
__dirname,
'.next/required-server-files.json'
);
const requiredFilesManifest = JSON.parse(
fs.readFileSync(requiredFilesManifestPath, 'utf8')
);
fs.writeFileSync(
requiredFilesManifestPath,
JSON.stringify({
...requiredFilesManifest,
appDir: '/non-existent/apps/web',
})
);

View File

@@ -0,0 +1,12 @@
/* eslint-env jest */
const path = require('path');
const { deployAndTest } = require('../../utils');
const ctx = {};
describe(`${__dirname.split(path.sep).pop()}`, () => {
it('should deploy and pass probe checks', async () => {
const info = await deployAndTest(__dirname, { skipForceNew: true });
Object.assign(ctx, info);
});
});

View File

@@ -0,0 +1,15 @@
{
"workspaces": [
"apps/*"
],
"private": true,
"dependencies": {
"next": "13.2.2-canary.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"turbo": "1.8.2"
},
"scripts": {
"build": "turbo build --cache-dir=turbo-cache"
}
}

View File

@@ -0,0 +1 @@
{ "hash": "3d4a11a80ae91055", "duration": 5510 }

View File

@@ -0,0 +1,8 @@
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**"]
}
}
}

View File

@@ -0,0 +1,30 @@
{
"builds": [
{
"src": "package.json",
"use": "@vercel/next",
"config": {
"rootDirectory": "apps/web",
"buildCommand": "cd ../../ && yarn build",
"installCommand": "yarn"
}
}
],
"probes": [
{
"path": "/",
"status": 200,
"mustContain": "index page"
},
{
"path": "/ssg",
"status": 200,
"mustContain": "ssg page"
},
{
"path": "/ssp",
"status": 200,
"mustContain": "ssp page"
}
]
}

View File

@@ -0,0 +1,227 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@next/env@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/env/-/env-13.2.2-canary.0.tgz#0f843ef602ff25441f17f10d09a93942baa8232b"
integrity sha512-EDy4UF4oXGmWgMq9w8P7Wg7JoYbrGY7EVnZcNoyMDU8o9KeiviYjK2IR3yFBulG0/1I2UbVu2wIM1xPYsQIonQ==
"@next/swc-android-arm-eabi@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.2.2-canary.0.tgz#62510cc5b11b677a63363788848efdc8aeda9cf8"
integrity sha512-/si1jk3wtrarhdVPQloSubTJjLeuTpgT7V2R2w+acWzvBBsrs2ThhZodLz0fJRKcYKmeDZebhtYGUkxkcm48Tw==
"@next/swc-android-arm64@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-13.2.2-canary.0.tgz#967fe8a63d59bdd22f57056ef83005242b559c1a"
integrity sha512-MKImVjggMFvPJju48fvz/KqjiqXaKoimGz3Vmc3c12WaSIEa5O1sevw0dQKPI6sv+1Mf5MuP7XlLQ9bWJo+72Q==
"@next/swc-darwin-arm64@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.2.2-canary.0.tgz#1250cf70dc129b765ae11bc596cd4d298a129afe"
integrity sha512-Sj+hCut5c6K2lOIJpV9KDsDJNe1dVacAE8WWmvotoeu4ab1W0//axZOxksq0S3240oF9CJ8QPZo+q5lPV6Gn2Q==
"@next/swc-darwin-x64@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.2.2-canary.0.tgz#13dde75f037194d46799542111608679c73dc8dc"
integrity sha512-/lv1J5ts5UhQ5V2V0PpIkQJw8kJywMgvPegZ/yf0fy9QOOdGCAw1dXtZsKUISrJmuzPcCZo0F56Zjbyb6lCLsw==
"@next/swc-freebsd-x64@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.2.2-canary.0.tgz#f9709e88c60207fb17244895cfe23a4a2d40b099"
integrity sha512-ECQyYOYd1AKu/oTNeI5pWDXebgKTIWXCs84IN9rXsM7f+FOQmVU8V+gK6Oisw3jya68B1vmfMqLDGQClDDIMAg==
"@next/swc-linux-arm-gnueabihf@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.2.2-canary.0.tgz#bdcef78c71820ff64c1225796dc383c8d72fcaed"
integrity sha512-/UQf0yoIwJJhgV8dpDmgWq/Q3/IxqFRsUHfBiy2M6kGVYwB9CnsjZzHwUKmg7sASdv+atW+oc4PIXXN6W9CCgg==
"@next/swc-linux-arm64-gnu@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.2.2-canary.0.tgz#e77b30092c22eb0af16a7a6c150d51fa84f0ceb0"
integrity sha512-pv0m+4hnKyq0MwEVAvrJScoYme4GKoPieP0Tj32oRK6P1gafFK4uJxF6zMVPlO0D/tGI7EkoHZjv/7sU5pSYSA==
"@next/swc-linux-arm64-musl@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.2.2-canary.0.tgz#779514bb2d0e7feced48fac1da0bc344180c8511"
integrity sha512-Bpc7nLJoP6dVPG9lOqCGqWkfiMo143YRx7+cvxSl1FVupkGP7Ntldvl3zS/m2CnU/5egQEjC2C5jEgQRY92Zhw==
"@next/swc-linux-x64-gnu@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.2.2-canary.0.tgz#d9022f44e0b243d32d39eeac683b1f189ff41487"
integrity sha512-2RPr5AxawTUVaQGrkhWWpjVdExPiA8wEJL6E1itI2gNav8LU3FEsIr9juQURv47Xn2KE286fw8214D6+D0RExg==
"@next/swc-linux-x64-musl@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.2.2-canary.0.tgz#8868f650f11594862fa183e0a0dac66d9c72973b"
integrity sha512-gKr5tJoJKGSlmDdpmoO1fe6oUeVMz2TluspKPM4ulc0rqyXjrRmQ9pd/oqEoypUKTUkqL49lt4hTL98MkhvXWg==
"@next/swc-win32-arm64-msvc@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.2.2-canary.0.tgz#29faaa4b760128c648f153964e94a8191bb0b2d7"
integrity sha512-0N7+lcV8ycqzgJIye40+Vl0iUk/mu3919T2kfnt20WU7gP+rpRJkPfP44yxBdt7U7XYtnqldM2Ox969y+0qJVw==
"@next/swc-win32-ia32-msvc@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.2.2-canary.0.tgz#078350e676d1a146442dbc7b1f5c4e03cb1345a5"
integrity sha512-vqdsKfJcfvf37P7YcJeIaPP5E7iSR7yTaHwgBpvY6Q0tDRxPv0gr4nRXElBs/V1VcxMaSx9PyyiQkKYB6UzEhg==
"@next/swc-win32-x64-msvc@13.2.2-canary.0":
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.2.2-canary.0.tgz#7ca59776b5440e6de3aee341d571a8a4f7cbb40a"
integrity sha512-Hf1XQaP/hpi9ddS128u8+npotRzX5EOt9y4nxzHRKn6BmjgAKY7CEBsFQMsjVHWqit2Jt3jXspgaCVIFOCE9Ng==
"@swc/helpers@0.4.14":
version "0.4.14"
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.14.tgz#1352ac6d95e3617ccb7c1498ff019654f1e12a74"
integrity sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==
dependencies:
tslib "^2.4.0"
caniuse-lite@^1.0.30001406:
version "1.0.30001457"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001457.tgz#6af34bb5d720074e2099432aa522c21555a18301"
integrity sha512-SDIV6bgE1aVbK6XyxdURbUE89zY7+k1BBBaOwYwkNCglXlel/E7mELiHC64HQ+W0xSKlqWhV9Wh7iHxUjMs4fA==
client-only@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1"
integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
loose-envify@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
nanoid@^3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
next@13.2.2-canary.0:
version "13.2.2-canary.0"
resolved "https://registry.yarnpkg.com/next/-/next-13.2.2-canary.0.tgz#7b8c9e2391d947fb66636fe988af644f2e930db2"
integrity sha512-sAzQCPI06df+TY7NI6txOkc7sOC7sErnOGF7vXA28GcQ0r4V09s4GDe8XTlPckxJ7o2Ky4OU1eN4NJ3vnDCcZQ==
dependencies:
"@next/env" "13.2.2-canary.0"
"@swc/helpers" "0.4.14"
caniuse-lite "^1.0.30001406"
postcss "8.4.14"
styled-jsx "5.1.1"
optionalDependencies:
"@next/swc-android-arm-eabi" "13.2.2-canary.0"
"@next/swc-android-arm64" "13.2.2-canary.0"
"@next/swc-darwin-arm64" "13.2.2-canary.0"
"@next/swc-darwin-x64" "13.2.2-canary.0"
"@next/swc-freebsd-x64" "13.2.2-canary.0"
"@next/swc-linux-arm-gnueabihf" "13.2.2-canary.0"
"@next/swc-linux-arm64-gnu" "13.2.2-canary.0"
"@next/swc-linux-arm64-musl" "13.2.2-canary.0"
"@next/swc-linux-x64-gnu" "13.2.2-canary.0"
"@next/swc-linux-x64-musl" "13.2.2-canary.0"
"@next/swc-win32-arm64-msvc" "13.2.2-canary.0"
"@next/swc-win32-ia32-msvc" "13.2.2-canary.0"
"@next/swc-win32-x64-msvc" "13.2.2-canary.0"
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
postcss@8.4.14:
version "8.4.14"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
dependencies:
nanoid "^3.3.4"
picocolors "^1.0.0"
source-map-js "^1.0.2"
react-dom@18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
dependencies:
loose-envify "^1.1.0"
scheduler "^0.23.0"
react@18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
dependencies:
loose-envify "^1.1.0"
scheduler@^0.23.0:
version "0.23.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
dependencies:
loose-envify "^1.1.0"
source-map-js@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
styled-jsx@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f"
integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==
dependencies:
client-only "0.0.1"
tslib@^2.4.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
turbo-darwin-64@1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/turbo-darwin-64/-/turbo-darwin-64-1.8.2.tgz#14c52e97d128c63fd3c7b2f15963123f02b9aa0e"
integrity sha512-j77U0uOeppENexFsIvvzExADSqMBEeCHnm+6LSNQfaajHSrbUVSTsuD6ZMYHamT6bslc+ZZm21jdecWkwZFBbw==
turbo-darwin-arm64@1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/turbo-darwin-arm64/-/turbo-darwin-arm64-1.8.2.tgz#ae5efdb89cbdd667feacd3fe8e9c8110691a4d95"
integrity sha512-1NoAvjlwt2wycsAFJouauy9epn9DptSMy6BoGqxJVc4jiibsLepp9qYc4f1/ln0zjd3FR1IvhGOiBfdpqMN7hg==
turbo-linux-64@1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/turbo-linux-64/-/turbo-linux-64-1.8.2.tgz#02442a48104db83c1e53409c85744fdeacbded56"
integrity sha512-TcT3CRYnBYA46kLGGbGC2jDyCEAvMgVpUdpIZGTmod48EKpZaEfVgTkpa4GJde8W68yRFogPZjPVL3yJHFpXSA==
turbo-linux-arm64@1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/turbo-linux-arm64/-/turbo-linux-arm64-1.8.2.tgz#890ad0691671cb252e756dcd56295895f61d369a"
integrity sha512-Mb9+KBy4YJzPMZ6WGoMzMVZ6EtueCSvOvgmNpVFgkwbtabfBuaBOvN+irtg4RRSWvJQTDTziLABieocEEXZImQ==
turbo-windows-64@1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/turbo-windows-64/-/turbo-windows-64-1.8.2.tgz#a57b902cdccdb69d1efa18772bee9e277e079583"
integrity sha512-/+R5ikRrw2w2w38JtNPubGLIQHgUC70m783DI9aPgaM5c8P5D/Y0k6HgjuC/uXgiaz2h3R7p7YWlr+2/E0bqyA==
turbo-windows-arm64@1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/turbo-windows-arm64/-/turbo-windows-arm64-1.8.2.tgz#0f976a2c6b8a46447fc277d5a9f7d8615792bdde"
integrity sha512-s07viz5nXSx4kyiksuPM4FGLRkoaGMaw0BpwFjdRQsl1p+WclUN1IPdokVPKOmFpu5pNCVYlG/raP/mXAEzDCg==
turbo@1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/turbo/-/turbo-1.8.2.tgz#869e674a524cde4f449ae4458f4651818e2ffe00"
integrity sha512-G/uJx6bZK5RwTWHsRN/MP0MvXFznmCaL3MQXdSf+OG/q0o8GE7+yivyyWEplWI1Asc8AEN909A/wlIkoz2FKTg==
optionalDependencies:
turbo-darwin-64 "1.8.2"
turbo-darwin-arm64 "1.8.2"
turbo-linux-64 "1.8.2"
turbo-linux-arm64 "1.8.2"
turbo-windows-64 "1.8.2"
turbo-windows-arm64 "1.8.2"

View File

@@ -0,0 +1,8 @@
const path = require('path');
const { deployAndTest } = require('../../utils');
describe(`${__dirname.split(path.sep).pop()}`, () => {
it('should deploy and pass probe checks', async () => {
await deployAndTest(__dirname);
});
});

View File

@@ -0,0 +1,3 @@
export function register() {
globalThis.isOdd = require('is-odd');
}

View File

@@ -0,0 +1,5 @@
module.exports = {
experimental: {
instrumentationHook: true,
},
};

View File

@@ -0,0 +1,16 @@
{
"name": "instrumentation-hook",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "canary",
"react": "latest",
"react-dom": "latest",
"is-odd": "3.0.1"
}
}

View File

@@ -0,0 +1,5 @@
export default async (req, res) => {
res.status(200).json({
payload: `isOdd: ${globalThis.isOdd(3)}`,
});
};

View File

@@ -0,0 +1,11 @@
export default function Home(props) {
return `isOdd: ${props.isOdd}`;
}
export async function getServerSideProps() {
return {
props: {
isOdd: globalThis.isOdd(2),
},
};
}

View File

@@ -0,0 +1,14 @@
{
"probes": [
{
"path": "/",
"status": 200,
"mustContain": "isOdd: false"
},
{
"path": "/api/hello",
"status": 200,
"mustContain": "isOdd: true"
}
]
}

View File

@@ -71,8 +71,11 @@ export const createLoggerServer = async (): Promise<LoggerServer> => {
process.env.NEXT_TELEMETRY_DISABLED = '1';
export async function deployAndTest(fixtureDir) {
const { deploymentId, deploymentUrl } = await testDeployment(fixtureDir);
export async function deployAndTest(fixtureDir, opts) {
const { deploymentId, deploymentUrl } = await testDeployment(
fixtureDir,
opts
);
return {
deploymentId,

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/node-bridge",
"version": "3.1.12",
"version": "3.1.14",
"license": "MIT",
"main": "./index.js",
"repository": {

View File

@@ -0,0 +1,9 @@
{
"$schema": "https://turborepo.org/schema.json",
"extends": ["//"],
"pipeline": {
"build": {
"outputs": ["helpers.js", "source-map-support.js"]
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/node",
"version": "2.9.8",
"version": "2.9.10",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
@@ -31,8 +31,8 @@
"dependencies": {
"@edge-runtime/vm": "2.0.0",
"@types/node": "14.18.33",
"@vercel/build-utils": "6.3.1",
"@vercel/node-bridge": "3.1.12",
"@vercel/build-utils": "6.3.2",
"@vercel/node-bridge": "3.1.14",
"@vercel/static-config": "2.0.13",
"edge-runtime": "2.0.0",
"esbuild": "0.14.47",

View File

@@ -449,9 +449,19 @@ export const build: BuildV3 = async ({
// Middleware is a catch-all for all paths unless a `matcher` property is defined
const src = getRegExpFromMatchers(staticConfig?.matcher);
const middlewareRawSrc: string[] = [];
if (staticConfig?.matcher) {
if (Array.isArray(staticConfig.matcher)) {
middlewareRawSrc.push(...staticConfig.matcher);
} else {
middlewareRawSrc.push(staticConfig.matcher as string);
}
}
routes = [
{
src,
middlewareRawSrc,
middlewarePath: outputPath,
continue: true,
override: true,

View File

@@ -1,22 +1,29 @@
import { forkDevServer, readMessage } from '../src/fork-dev-server';
import { resolve } from 'path';
import { resolve, extname } from 'path';
import fetch from 'node-fetch';
jest.setTimeout(10 * 1000);
test('runs a mjs endpoint', async () => {
const child = forkDevServer({
function testForkDevServer(entrypoint: string) {
const ext = extname(entrypoint);
const isTypeScript = ext === '.ts';
const isEsm = ext === '.mjs';
return forkDevServer({
maybeTranspile: true,
config: {},
isEsm: true,
isTypeScript: false,
isEsm,
isTypeScript,
meta: {},
require_: require,
tsConfig: undefined,
workPath: resolve(__dirname, './dev-fixtures'),
entrypoint: './esm-module.mjs',
entrypoint,
devServerPath: resolve(__dirname, '../dist/dev-server.js'),
});
}
test('runs a mjs endpoint', async () => {
const child = testForkDevServer('./esm-module.mjs');
try {
const result = await readMessage(child);
@@ -44,18 +51,7 @@ test('runs a mjs endpoint', async () => {
});
test('runs a esm typescript endpoint', async () => {
const child = forkDevServer({
maybeTranspile: true,
config: {},
isEsm: true,
isTypeScript: true,
meta: {},
require_: require,
tsConfig: undefined,
workPath: resolve(__dirname, './dev-fixtures'),
entrypoint: './esm-module.ts',
devServerPath: resolve(__dirname, '../dist/dev-server.js'),
});
const child = testForkDevServer('./esm-module.ts');
try {
const result = await readMessage(child);

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/python",
"version": "3.1.50",
"version": "3.1.51",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
@@ -23,7 +23,7 @@
"@types/execa": "^0.9.0",
"@types/jest": "27.4.1",
"@types/node": "14.18.33",
"@vercel/build-utils": "6.3.1",
"@vercel/build-utils": "6.3.2",
"@vercel/ncc": "0.24.0",
"execa": "^1.0.0",
"typescript": "4.3.4"

View File

@@ -17,7 +17,7 @@
{
"path": "/cookie_wsgi.py",
"responseHeaders": {
"set-cookie": ["one=first", "two=second"]
"set-cookie": ["one=first; Path=/", "two=second; Path=/"]
}
}
]

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/redwood",
"version": "1.1.6",
"version": "1.1.7",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://vercel.com/docs",
@@ -20,14 +20,14 @@
},
"dependencies": {
"@vercel/nft": "0.22.5",
"@vercel/routing-utils": "2.1.9",
"@vercel/routing-utils": "2.1.10",
"semver": "6.1.1"
},
"devDependencies": {
"@types/aws-lambda": "8.10.19",
"@types/node": "14.18.33",
"@types/semver": "6.0.0",
"@vercel/build-utils": "6.3.1",
"@vercel/build-utils": "6.3.2",
"execa": "3.2.0",
"fs-extra": "11.1.0",
"typescript": "4.3.4"

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/remix",
"version": "1.4.1",
"version": "1.5.1",
"license": "MIT",
"main": "./dist/index.js",
"homepage": "https://vercel.com/docs",
@@ -18,10 +18,11 @@
"files": [
"dist",
"server-node.mjs",
"server-edge.mjs"
"server-edge.mjs",
"vercel-edge-entrypoint.js"
],
"dependencies": {
"@remix-run/dev": "1.13.0",
"@remix-run/dev": "npm:@vercel/remix-run-dev@1.13.0-patch.2",
"@vercel/nft": "0.22.5",
"@vercel/static-config": "2.0.13",
"path-to-regexp": "6.2.1",
@@ -30,7 +31,7 @@
"devDependencies": {
"@types/jest": "27.5.1",
"@types/node": "14.18.33",
"@vercel/build-utils": "6.3.1",
"@vercel/build-utils": "6.3.2",
"typescript": "4.9.4"
}
}

View File

@@ -1,3 +1,3 @@
import { createRequestHandler } from '@remix-run/server-runtime';
import build from './index.js';
import build from '@remix-run/dev/server-build';
export default createRequestHandler(build);

View File

@@ -9,7 +9,7 @@ import {
installGlobals();
import build from './index.js';
import build from '@remix-run/dev/server-build';
const handleRequest = createRemixRequestHandler(build, process.env.NODE_ENV);
@@ -54,11 +54,13 @@ function createRemixRequest(req, res) {
}
async function sendRemixResponse(res, nodeResponse) {
res.statusCode = nodeResponse.status;
res.statusMessage = nodeResponse.statusText;
for (const [name, value] of nodeResponse.headers.entries()) {
res.setHeader(name, value);
}
let multiValueHeaders = nodeResponse.headers.raw();
res.writeHead(
nodeResponse.status,
nodeResponse.statusText,
multiValueHeaders
);
if (nodeResponse.body) {
await writeReadableStreamToWritable(nodeResponse.body, res);

View File

@@ -5,6 +5,7 @@ import {
debug,
download,
execCommand,
FileBlob,
FileFsRef,
getEnvForPackageManager,
getNodeVersion,
@@ -18,7 +19,7 @@ import {
scanParentDirs,
walkParentDirs,
} from '@vercel/build-utils';
import { getConfig, BaseFunctionConfig } from '@vercel/static-config';
import { getConfig } from '@vercel/static-config';
import { nodeFileTrace } from '@vercel/nft';
import { readConfig } from '@remix-run/dev/dist/config';
import type {
@@ -28,18 +29,36 @@ import type {
PackageJson,
BuildResultV2Typical,
} from '@vercel/build-utils';
import type { BaseFunctionConfig } from '@vercel/static-config';
import type { RemixConfig } from '@remix-run/dev/dist/config';
import type { ConfigRoute } from '@remix-run/dev/dist/config/routes';
import {
calculateRouteConfigHash,
findConfig,
getPathFromRoute,
getRegExpFromPath,
getRouteIterator,
getResolvedRouteConfig,
isLayoutRoute,
ResolvedRouteConfig,
ResolvedNodeRouteConfig,
ResolvedEdgeRouteConfig,
} from './utils';
const _require: typeof require = eval('require');
const REMIX_RUN_DEV_PATH = dirname(
_require.resolve('@remix-run/dev/package.json')
);
const edgeServerSrcPromise = fs.readFile(
join(__dirname, '../server-edge.mjs'),
'utf-8'
);
const nodeServerSrcPromise = fs.readFile(
join(__dirname, '../server-node.mjs'),
'utf-8'
);
export const build: BuildV2 = async ({
entrypoint,
files,
@@ -92,19 +111,88 @@ export const build: BuildV2 = async ({
await runNpmInstall(entrypointFsDirname, [], spawnOpts, meta, nodeVersion);
}
const remixDevPackageJsonPath = _require.resolve(
'@remix-run/dev/package.json',
{ paths: [entrypointFsDirname] }
);
const remixVersion = JSON.parse(
await fs.readFile(remixDevPackageJsonPath, 'utf8')
).version;
// Make our version of `remix` CLI available to the project's build
// command by creating a symlink to the copy in our node modules,
// so that `serverBundles` works: https://github.com/remix-run/remix/pull/5479
const remixRunDevPath = await ensureResolvable(
entrypointFsDirname,
repoRootPath,
'@remix-run/dev'
);
const backupRemixRunDevPath = `${remixRunDevPath}.__vercel_backup`;
await fs.rename(remixRunDevPath, backupRemixRunDevPath);
await fs.symlink(REMIX_RUN_DEV_PATH, remixRunDevPath);
// Make `remix build` output production mode
spawnOpts.env.NODE_ENV = 'production';
const remixConfig = await chdirAndReadConfig(entrypointFsDirname);
const remixRoutes = Object.values(remixConfig.routes);
// Read the `export const config` (if any) for each route
const project = new Project();
const staticConfigsMap = new Map<ConfigRoute, BaseFunctionConfig | null>();
for (const route of remixRoutes) {
const routePath = join(remixConfig.appDirectory, route.file);
const staticConfig = getConfig(project, routePath);
staticConfigsMap.set(route, staticConfig);
}
const resolvedConfigsMap = new Map<ConfigRoute, ResolvedRouteConfig>();
for (const route of remixRoutes) {
const config = getResolvedRouteConfig(
route,
remixConfig.routes,
staticConfigsMap
);
resolvedConfigsMap.set(route, config);
}
// Figure out which routes belong to which server bundles
// based on having common static config properties
const serverBundlesMap = new Map<string, ConfigRoute[]>();
for (const route of remixRoutes) {
if (isLayoutRoute(route.id, remixRoutes)) continue;
const config = resolvedConfigsMap.get(route);
if (!config) {
throw new Error(`Expected resolved config for "${route.id}"`);
}
const hash = calculateRouteConfigHash(config);
let routesForHash = serverBundlesMap.get(hash);
if (!Array.isArray(routesForHash)) {
routesForHash = [];
serverBundlesMap.set(hash, routesForHash);
}
routesForHash.push(route);
}
const serverBundles = Array.from(serverBundlesMap.entries()).map(
([hash, routes]) => {
const runtime = resolvedConfigsMap.get(routes[0])?.runtime ?? 'nodejs';
return {
serverBuildPath: `build/build-${runtime}-${hash}.js`,
routes: routes.map(r => r.id),
};
}
);
// We need to patch the `remix.config.js` file to force some values necessary
// for a build that works on either Node.js or the Edge runtime
const remixConfigPath = findConfig(entrypointFsDirname, 'remix.config');
const renamedRemixConfigPath = remixConfigPath
? `${remixConfigPath}.original${extname(remixConfigPath)}`
: undefined;
const serverBuildPath = 'build/index.js';
if (remixConfigPath && renamedRemixConfigPath) {
await fs.rename(remixConfigPath, renamedRemixConfigPath);
@@ -124,7 +212,8 @@ export const build: BuildV2 = async ({
config.serverBuildTarget = undefined;
config.serverModuleFormat = 'cjs';
config.serverPlatform = 'node';
config.serverBuildPath = ${JSON.stringify(serverBuildPath)}
config.serverBuildPath = undefined;
config.serverBundles = ${JSON.stringify(serverBundles)};
export default config;`;
} else {
patchedConfig = `const config = require('./${basename(
@@ -133,7 +222,8 @@ export default config;`;
config.serverBuildTarget = undefined;
config.serverModuleFormat = 'cjs';
config.serverPlatform = 'node';
config.serverBuildPath = ${JSON.stringify(serverBuildPath)}
config.serverBuildPath = undefined;
config.serverBundles = ${JSON.stringify(serverBundles)};
module.exports = config;`;
}
await fs.writeFile(remixConfigPath, patchedConfig);
@@ -173,21 +263,10 @@ module.exports = config;`;
if (remixConfigPath && renamedRemixConfigPath) {
await fs.rename(renamedRemixConfigPath, remixConfigPath);
}
}
// Figure out which pages should be edge functions
let hasEdgeRoute = false;
const staticConfigsMap = new Map<ConfigRoute, BaseFunctionConfig>();
const project = new Project();
for (const route of remixRoutes) {
const routePath = join(remixConfig.appDirectory, route.file);
const staticConfig = getConfig(project, routePath);
if (staticConfig) {
staticConfigsMap.set(route, staticConfig);
}
if (staticConfig?.runtime && isEdgeRuntime(staticConfig.runtime)) {
hasEdgeRoute = true;
}
// Remove `@remix-run/dev` symlink
await fs.unlink(remixRunDevPath);
await fs.rename(backupRemixRunDevPath, remixRunDevPath);
}
// This needs to happen before we run NFT to create the Node/Edge functions
@@ -200,23 +279,35 @@ module.exports = config;`;
ensureResolvable(entrypointFsDirname, repoRootPath, '@remix-run/node'),
]);
const [staticFiles, nodeFunction, edgeFunction] = await Promise.all([
const [staticFiles, ...functions] = await Promise.all([
glob('**', join(entrypointFsDirname, 'public')),
createRenderNodeFunction(
entrypointFsDirname,
repoRootPath,
join(entrypointFsDirname, serverBuildPath),
remixConfig.serverEntryPoint,
nodeVersion
),
hasEdgeRoute
? createRenderEdgeFunction(
...serverBundles.map(bundle => {
const firstRoute = remixConfig.routes[bundle.routes[0]];
const config = resolvedConfigsMap.get(firstRoute) ?? {
runtime: 'nodejs',
};
if (config.runtime === 'edge') {
return createRenderEdgeFunction(
entrypointFsDirname,
repoRootPath,
join(entrypointFsDirname, serverBuildPath),
remixConfig.serverEntryPoint
)
: undefined,
join(entrypointFsDirname, bundle.serverBuildPath),
remixConfig.serverEntryPoint,
remixVersion,
config
);
}
return createRenderNodeFunction(
nodeVersion,
entrypointFsDirname,
repoRootPath,
join(entrypointFsDirname, bundle.serverBuildPath),
remixConfig.serverEntryPoint,
remixVersion,
config
);
}),
]);
const output: BuildResultV2Typical['output'] = staticFiles;
@@ -237,27 +328,32 @@ module.exports = config;`;
const path = getPathFromRoute(route, remixConfig.routes);
let isEdge = false;
for (const currentRoute of getRouteIterator(route, remixConfig.routes)) {
const staticConfig = staticConfigsMap.get(currentRoute);
if (staticConfig?.runtime) {
isEdge = isEdgeRuntime(staticConfig.runtime);
break;
}
// If the route is a pathless layout route (at the root level)
// and doesn't have any sub-routes, then a function should not be created.
if (!path) {
continue;
}
const fn =
isEdge && edgeFunction
const funcIndex = serverBundles.findIndex(bundle => {
return bundle.routes.includes(route.id);
});
const func = functions[funcIndex];
if (!func) {
throw new Error(`Could not determine server bundle for "${route.id}"`);
}
output[path] =
func instanceof EdgeFunction
? // `EdgeFunction` currently requires the "name" property to be set.
// Ideally this property will be removed, at which point we can
// return the same `edgeFunction` instance instead of creating a
// new one for each page.
new EdgeFunction({
...edgeFunction,
...func,
name: path,
})
: nodeFunction;
output[path] = fn;
: func;
// If this is a dynamic route then add a Vercel route
const re = getRegExpFromPath(path);
@@ -270,11 +366,20 @@ module.exports = config;`;
}
// Add a 404 path for not found pages to be server-side rendered by Remix.
// Use the edge function if one was generated, otherwise use Node.js.
// Use an edge function bundle if one was generated, otherwise use Node.js.
if (!output['404']) {
output['404'] = edgeFunction
? new EdgeFunction({ ...edgeFunction, name: '404' })
: nodeFunction;
const edgeFunctionIndex = Array.from(serverBundlesMap.values()).findIndex(
routes => {
const runtime = resolvedConfigsMap.get(routes[0])?.runtime;
return runtime === 'edge';
}
);
const func =
edgeFunctionIndex !== -1 ? functions[edgeFunctionIndex] : functions[0];
output['404'] =
func instanceof EdgeFunction
? new EdgeFunction({ ...func, name: '404' })
: func;
}
routes.push({
src: '/(.*)',
@@ -290,23 +395,33 @@ function hasScript(scriptName: string, pkg: PackageJson | null) {
}
async function createRenderNodeFunction(
nodeVersion: NodeVersion,
entrypointDir: string,
rootDir: string,
serverBuildPath: string,
serverEntryPoint: string | undefined,
nodeVersion: NodeVersion
remixVersion: string,
config: ResolvedNodeRouteConfig
): Promise<NodejsLambda> {
const files: Files = {};
let handler = relative(rootDir, serverBuildPath);
let handlerPath = join(rootDir, handler);
if (!serverEntryPoint) {
handler = join(dirname(handler), 'server-node.mjs');
const baseServerBuildPath = basename(serverBuildPath, '.js');
handler = join(dirname(handler), `server-${baseServerBuildPath}.mjs`);
handlerPath = join(rootDir, handler);
// Copy the `server-node.mjs` file into the "build" directory
const sourceHandlerPath = join(__dirname, '../server-node.mjs');
await fs.copyFile(sourceHandlerPath, handlerPath);
const nodeServerSrc = await nodeServerSrcPromise;
await writeEntrypointFile(
handlerPath,
nodeServerSrc.replace(
'@remix-run/dev/server-build',
`./${baseServerBuildPath}.js`
),
rootDir
);
}
// Trace the handler with `@vercel/nft`
@@ -331,6 +446,13 @@ async function createRenderNodeFunction(
shouldAddSourcemapSupport: false,
operationType: 'SSR',
experimentalResponseStreaming: true,
regions: config.regions,
memory: config.memory,
maxDuration: config.maxDuration,
framework: {
slug: 'remix',
version: remixVersion,
},
});
return fn;
@@ -340,21 +462,33 @@ async function createRenderEdgeFunction(
entrypointDir: string,
rootDir: string,
serverBuildPath: string,
serverEntryPoint: string | undefined
serverEntryPoint: string | undefined,
remixVersion: string,
config: ResolvedEdgeRouteConfig
): Promise<EdgeFunction> {
const files: Files = {};
let handler = relative(rootDir, serverBuildPath);
let handlerPath = join(rootDir, handler);
if (!serverEntryPoint) {
handler = join(dirname(handler), 'server-edge.mjs');
const baseServerBuildPath = basename(serverBuildPath, '.js');
handler = join(dirname(handler), `server-${baseServerBuildPath}.mjs`);
handlerPath = join(rootDir, handler);
// Copy the `server-edge.mjs` file into the "build" directory
const sourceHandlerPath = join(__dirname, '../server-edge.mjs');
await fs.copyFile(sourceHandlerPath, handlerPath);
const edgeServerSrc = await edgeServerSrcPromise;
await writeEntrypointFile(
handlerPath,
edgeServerSrc.replace(
'@remix-run/dev/server-build',
`./${baseServerBuildPath}.js`
),
rootDir
);
}
let remixRunVercelPkgJson: string | undefined;
// Trace the handler with `@vercel/nft`
const trace = await nodeFileTrace([handlerPath], {
base: rootDir,
@@ -373,6 +507,35 @@ async function createRenderEdgeFunction(
if (basename(fsPath) === 'package.json') {
// For Edge Functions, patch "main" field to prefer "browser" or "module"
const pkgJson = JSON.parse(source.toString());
// When `@remix-run/vercel` is detected, we need to modify the `package.json`
// to include the "browser" field so that the proper Edge entrypoint file
// is used. This is a temporary stop gap until this PR is merged:
// https://github.com/remix-run/remix/pull/5537
if (pkgJson.name === '@remix-run/vercel') {
pkgJson.browser = 'dist/edge.js';
pkgJson.dependencies['@remix-run/server-runtime'] =
pkgJson.dependencies['@remix-run/node'];
if (!remixRunVercelPkgJson) {
remixRunVercelPkgJson = JSON.stringify(pkgJson, null, 2) + '\n';
// Copy in the edge entrypoint so that NFT can properly resolve it
const vercelEdgeEntrypointPath = join(
__dirname,
'../vercel-edge-entrypoint.js'
);
const vercelEdgeEntrypointDest = join(
dirname(fsPath),
'dist/edge.js'
);
await fs.copyFile(
vercelEdgeEntrypointPath,
vercelEdgeEntrypointDest
);
}
}
for (const prop of ['browser', 'module']) {
const val = pkgJson[prop];
if (typeof val === 'string') {
@@ -393,7 +556,15 @@ async function createRenderEdgeFunction(
}
for (const file of trace.fileList) {
files[file] = await FileFsRef.fromFsPath({ fsPath: join(rootDir, file) });
if (
remixRunVercelPkgJson &&
file.endsWith(`@remix-run${sep}vercel${sep}package.json`)
) {
// Use the modified `@remix-run/vercel` package.json which contains "browser" field
files[file] = new FileBlob({ data: remixRunVercelPkgJson });
} else {
files[file] = await FileFsRef.fromFsPath({ fsPath: join(rootDir, file) });
}
}
const fn = new EdgeFunction({
@@ -401,18 +572,30 @@ async function createRenderEdgeFunction(
deploymentTarget: 'v8-worker',
name: 'render',
entrypoint: handler,
regions: config.regions,
framework: {
slug: 'remix',
version: remixVersion,
},
});
return fn;
}
async function ensureResolvable(start: string, base: string, pkgName: string) {
async function ensureResolvable(
start: string,
base: string,
pkgName: string
): Promise<string> {
try {
const resolvedPath = _require.resolve(pkgName, { paths: [start] });
const resolvedPkgPath = _require.resolve(`${pkgName}/package.json`, {
paths: [start],
});
const resolvedPath = dirname(resolvedPkgPath);
if (!relative(base, resolvedPath).startsWith(`..${sep}`)) {
// Resolved path is within the root of the project, so all good
debug(`"${pkgName}" resolved to '${resolvedPath}'`);
return;
return resolvedPath;
}
} catch (err: any) {
if (err.code !== 'MODULE_NOT_FOUND') {
@@ -435,15 +618,8 @@ async function ensureResolvable(start: string, base: string, pkgName: string) {
const match = packages.find(p => p.startsWith(prefix));
if (match) {
const pkgDir = join(pnpmDir, match, 'node_modules', pkgName);
const symlinkPath = join(pnpmDir, '..', pkgName);
const symlinkDir = dirname(symlinkPath);
const symlinkTarget = relative(symlinkDir, pkgDir);
await fs.mkdir(symlinkDir, { recursive: true });
await fs.symlink(symlinkTarget, symlinkPath);
console.warn(
`WARN: Created symlink for "${pkgName}". To silence this warning, add "${pkgName}" to "dependencies" in your \`package.json\` file.`
);
return;
await ensureSymlink(pkgDir, join(pnpmDir, '..'), pkgName);
return pkgDir;
}
}
@@ -460,15 +636,8 @@ async function ensureResolvable(start: string, base: string, pkgName: string) {
const match = packages.find(p => p.startsWith(prefix));
if (match) {
const pkgDir = join(prefixDir, match, 'node_modules', pkgName);
const symlinkPath = join(npmDir, '..', pkgName);
const symlinkDir = dirname(symlinkPath);
const symlinkTarget = relative(symlinkDir, pkgDir);
await fs.mkdir(symlinkDir, { recursive: true });
await fs.symlink(symlinkTarget, symlinkPath);
console.warn(
`WARN: Created symlink for "${pkgName}". To silence this warning, add "${pkgName}" to "dependencies" in your \`package.json\` file.`
);
return;
await ensureSymlink(pkgDir, join(npmDir, '..'), pkgName);
return pkgDir;
}
}
@@ -477,8 +646,35 @@ async function ensureResolvable(start: string, base: string, pkgName: string) {
);
}
function isEdgeRuntime(runtime: string): boolean {
return runtime === 'edge' || runtime === 'experimental-edge';
async function ensureSymlink(
target: string,
nodeModulesDir: string,
pkgName: string
) {
const symlinkPath = join(nodeModulesDir, pkgName);
const symlinkDir = dirname(symlinkPath);
const relativeTarget = relative(symlinkDir, target);
try {
const existingTarget = await fs.readlink(symlinkPath);
if (existingTarget === relativeTarget) {
// Symlink is already the expected value, so do nothing
return;
} else {
// If a symlink already exists then delete it if the target doesn't match
await fs.unlink(symlinkPath);
}
} catch (err: any) {
// Ignore when path does not exist or is not a symlink
if (err.code !== 'ENOENT' && err.code !== 'EINVAL') {
throw err;
}
}
await fs.symlink(relativeTarget, symlinkPath);
console.warn(
`WARN: Created symlink for "${pkgName}". To silence this warning, add "${pkgName}" to "dependencies" in your \`package.json\` file.`
);
}
async function chdirAndReadConfig(dir: string) {
@@ -492,3 +688,23 @@ async function chdirAndReadConfig(dir: string) {
}
return remixConfig;
}
async function writeEntrypointFile(
path: string,
data: string,
rootDir: string
) {
try {
await fs.writeFile(path, data);
} catch (err: any) {
if (err.code === 'ENOENT') {
throw new Error(
`The "${relative(
rootDir,
dirname(path)
)}" directory does not exist. Please contact support@vercel.com.`
);
}
throw err;
}
}

View File

@@ -5,6 +5,22 @@ import type {
ConfigRoute,
RouteManifest,
} from '@remix-run/dev/dist/config/routes';
import type { BaseFunctionConfig } from '@vercel/static-config';
export interface ResolvedNodeRouteConfig {
runtime: 'nodejs';
regions?: string[];
maxDuration?: number;
memory?: number;
}
export interface ResolvedEdgeRouteConfig {
runtime: 'edge';
regions?: BaseFunctionConfig['regions'];
}
export type ResolvedRouteConfig =
| ResolvedNodeRouteConfig
| ResolvedEdgeRouteConfig;
const configExts = ['.js', '.cjs', '.mjs'];
@@ -18,6 +34,60 @@ export function findConfig(dir: string, basename: string): string | undefined {
return undefined;
}
function isEdgeRuntime(runtime: string): boolean {
return runtime === 'edge' || runtime === 'experimental-edge';
}
export function getResolvedRouteConfig(
route: ConfigRoute,
routes: RouteManifest,
configs: Map<ConfigRoute, BaseFunctionConfig | null>
): ResolvedRouteConfig {
let runtime: ResolvedRouteConfig['runtime'] | undefined;
let regions: ResolvedRouteConfig['regions'];
let maxDuration: ResolvedNodeRouteConfig['maxDuration'];
let memory: ResolvedNodeRouteConfig['memory'];
for (const currentRoute of getRouteIterator(route, routes)) {
const staticConfig = configs.get(currentRoute);
if (staticConfig) {
if (typeof runtime === 'undefined' && staticConfig.runtime) {
runtime = isEdgeRuntime(staticConfig.runtime) ? 'edge' : 'nodejs';
}
if (typeof regions === 'undefined') {
regions = staticConfig.regions;
}
if (typeof maxDuration === 'undefined') {
maxDuration = staticConfig.maxDuration;
}
if (typeof memory === 'undefined') {
memory = staticConfig.memory;
}
}
}
if (Array.isArray(regions)) {
regions = Array.from(new Set(regions)).sort();
}
if (runtime === 'edge') {
return { runtime, regions };
}
if (regions && !Array.isArray(regions)) {
throw new Error(
`"regions" for route "${route.id}" must be an array of strings`
);
}
return { runtime: 'nodejs', regions, maxDuration, memory };
}
export function calculateRouteConfigHash(config: ResolvedRouteConfig): string {
const str = JSON.stringify(config);
return Buffer.from(str).toString('base64url');
}
export function isLayoutRoute(
routeId: string,
routes: Pick<ConfigRoute, 'id' | 'parentId'>[]
@@ -41,9 +111,15 @@ export function getPathFromRoute(
route: ConfigRoute,
routes: RouteManifest
): string {
if (
route.id === 'root' ||
(route.parentId === 'root' && !route.path && route.index)
) {
return 'index';
}
const pathParts: string[] = [];
for (const currentRoute of getRouteIterator(route, routes)) {
if (currentRoute.index) pathParts.push('index');
if (currentRoute.path) pathParts.push(currentRoute.path);
}
const path = pathParts.reverse().join('/');

View File

@@ -0,0 +1,20 @@
// Edge functions can not use child processes, but this is route
// uses Node.js. So this is here to verify that bundle splitting
// is working correctly (because this route should not exist in
// the Edge bundle).
import { exec } from 'child_process';
import { json } from '@remix-run/node';
export async function loader() {
const hi = await new Promise<string>((resolve, reject) => {
exec(
`echo hi from the B page running in ${process.env.VERCEL_REGION}`,
(err, stdout) => {
if (err) return reject(err);
resolve(stdout);
}
);
});
return json({ hi });
}

View File

@@ -0,0 +1,4 @@
// This is a pathless layout route at the root level,
// but there are no child routes, so a function should
// not be created for this route.
export default () => <div>pathless layout route</div>;

View File

@@ -1,7 +1,16 @@
import { loader } from '~/b.server';
import { useLoaderData } from '@remix-run/react';
export const config = { regions: ['sfo1'] };
export { loader };
export default function B() {
const { hi } = useLoaderData<typeof loader>();
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>B page</h1>
<p>{hi}</p>
</div>
);
}

View File

@@ -1,6 +1,4 @@
export const config = {
runtime: 'edge'
};
export const config = { runtime: 'edge' };
export default function Edge() {
return (

View File

@@ -0,0 +1,3 @@
// This is a pathless layout route without any child routes,
// but Remix will serve this since its not at the root level.
export default () => <div>nested2 pathless layout route</div>;

View File

@@ -0,0 +1,10 @@
import type { LoaderFunction } from '@remix-run/server-runtime';
export const config = { runtime: 'edge' };
export const loader: LoaderFunction = () => {
const headers = new Headers();
headers.append('Set-Cookie', 'hello=world');
headers.append('Set-Cookie', 'foo=bar');
return new Response(null, { headers });
};

View File

@@ -0,0 +1,8 @@
import type { LoaderFunction } from '@remix-run/server-runtime';
export const loader: LoaderFunction = () => {
const headers = new Headers();
headers.append('Set-Cookie', 'hello=world');
headers.append('Set-Cookie', 'foo=bar');
return new Response(null, { headers });
};

View File

@@ -0,0 +1,42 @@
{
"probes": [
{ "path": "/", "mustContain": "Welcome to Remix" },
{ "path": "/edge", "mustContain": "Welcome to Remix@Edge" },
{ "path": "/b", "mustContain": "hi from the B page running in sfo1" },
{ "path": "/nested", "mustContain": "Nested index page" },
{ "path": "/nested/another", "mustContain": "Nested another page" },
{ "path": "/nested/index", "status": 404, "mustContain": "Not Found" },
{ "path": "/asdf", "status": 404, "mustContain": "Not Found" },
{ "path": "/instanceof", "mustContain": "InstanceOfRequest: true" },
{ "path": "/projects/edge", "mustContain": "\"isEdge\":true" },
{ "path": "/projects/node", "mustContain": "\"isEdge\":false" },
{
"path": "/__pathless",
"status": 404,
"mustContain": "Not Found"
},
{
"path": "/nested2",
"mustContain": "nested2 pathless layout route"
},
{
"path": "/nested2/__pathless",
"status": 404,
"mustContain": "Not Found"
},
{
"path": "/set-cookie-edge",
"status": 200,
"responseHeaders": {
"set-cookie": ["hello=world", "foo=bar"]
}
},
{
"path": "/set-cookie-node",
"status": 200,
"responseHeaders": {
"set-cookie": ["hello=world", "foo=bar"]
}
}
]
}

View File

@@ -1,24 +0,0 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/remix",
"config": {
"zeroConfig": true
}
}
],
"probes": [
{ "path": "/", "mustContain": "Welcome to Remix" },
{ "path": "/edge", "mustContain": "Welcome to Remix@Edge" },
{ "path": "/b", "mustContain": "B page" },
{ "path": "/nested", "mustContain": "Nested index page" },
{ "path": "/nested/another", "mustContain": "Nested another page" },
{ "path": "/nested/index", "mustContain": "Not Found" },
{ "path": "/asdf", "mustContain": "Not Found" },
{ "path": "/instanceof", "mustContain": "InstanceOfRequest: true" },
{ "path": "/projects/edge", "mustContain": "\"isEdge\":true" },
{ "path": "/projects/node", "mustContain": "\"isEdge\":false" }
]
}

View File

@@ -0,0 +1,9 @@
export const config = { runtime: 'edge' };
export default function Edge() {
return (
<div style={{ fontFamily: 'system-ui, sans-serif', lineHeight: '1.4' }}>
<h1>Welcome to Remix@Edge</h1>
</div>
);
}

View File

@@ -1,4 +1,4 @@
import { json, LoaderFunction } from "@remix-run/node";
import { json, LoaderFunction } from "@remix-run/server-runtime";
export const loader: LoaderFunction = ({ context }) => {
return json(context);

View File

@@ -0,0 +1,7 @@
{
"probes": [
{ "path": "/", "mustContain": "Welcome to Remix" },
{ "path": "/edge", "mustContain": "Welcome to Remix@Edge" },
{ "path": "/load-context", "mustContain": "{\"nodeLoadContext\":true}" }
]
}

View File

@@ -1,16 +0,0 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/remix",
"config": {
"zeroConfig": true
}
}
],
"probes": [
{ "path": "/", "mustContain": "Welcome to Remix" },
{ "path": "/load-context", "mustContain": "{\"nodeLoadContext\":true}" }
]
}

View File

@@ -10,13 +10,13 @@
"start": "remix-serve build"
},
"dependencies": {
"@remix-run/react": "^1.7.4",
"@remix-run/serve": "^1.7.4",
"@remix-run/react": "1.5.0",
"@remix-run/serve": "1.5.0",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@remix-run/dev": "^1.7.4",
"@remix-run/dev": "1.5.0",
"@types/react": "^17.0.45",
"@types/react-dom": "^17.0.17",
"typescript": "^4.6.4"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
{
"probes": [
{
"path": "/",
"mustContain": "Welcome to Remix",
"logMustContain": "WARN: Created symlink for \"@remix-run/node\". To silence this warning, add \"@remix-run/node\" to \"dependencies\" in your `package.json` file"
},
{
"path": "/edge",
"mustContain": "Welcome to Remix@Edge",
"logMustContain": "WARN: Created symlink for \"@remix-run/server-runtime\". To silence this warning, add \"@remix-run/server-runtime\" to \"dependencies\" in your `package.json` file"
},
{ "path": "/b", "mustContain": "B page" },
{ "path": "/nested", "mustContain": "Nested index page" },
{ "path": "/nested/another", "mustContain": "Nested another page" },
{ "path": "/nested/index", "mustContain": "<div>nested/index</div>" },
{ "path": "/asdf", "mustContain": "<div>asdf</div>" }
]
}

View File

@@ -1,21 +0,0 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/remix",
"config": {
"zeroConfig": true
}
}
],
"probes": [
{ "path": "/", "mustContain": "Welcome to Remix" },
{ "path": "/edge", "mustContain": "Welcome to Remix@Edge" },
{ "path": "/b", "mustContain": "B page" },
{ "path": "/nested", "mustContain": "Nested index page" },
{ "path": "/nested/another", "mustContain": "Nested another page" },
{ "path": "/nested/index", "mustContain": "<div>nested/index</div>" },
{ "path": "/asdf", "mustContain": "<div>asdf</div>" }
]
}

View File

@@ -0,0 +1,19 @@
{
"probes": [
{
"path": "/",
"mustContain": "Welcome to Remix",
"logMustContain": "WARN: Created symlink for \"@remix-run/node\". To silence this warning, add \"@remix-run/node\" to \"dependencies\" in your `package.json` file"
},
{
"path": "/edge",
"mustContain": "Welcome to Remix@Edge",
"logMustContain": "WARN: Created symlink for \"@remix-run/server-runtime\". To silence this warning, add \"@remix-run/server-runtime\" to \"dependencies\" in your `package.json` file"
},
{ "path": "/b", "mustContain": "B page" },
{ "path": "/nested", "mustContain": "Nested index page" },
{ "path": "/nested/another", "mustContain": "Nested another page" },
{ "path": "/nested/index", "mustContain": "Not Found" },
{ "path": "/asdf", "mustContain": "Not Found" }
]
}

View File

@@ -1,27 +1,8 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/remix",
"config": {
"installCommand": "npm install --install-strategy=linked",
"zeroConfig": true
}
}
],
"installCommand": "npm install --install-strategy=linked && ln -sf broken 'node_modules/@remix-run/server-runtime'",
"build": {
"env": {
"ENABLE_EXPERIMENTAL_COREPACK": "1"
}
},
"probes": [
{ "path": "/", "mustContain": "Welcome to Remix" },
{ "path": "/edge", "mustContain": "Welcome to Remix@Edge" },
{ "path": "/b", "mustContain": "B page" },
{ "path": "/nested", "mustContain": "Nested index page" },
{ "path": "/nested/another", "mustContain": "Nested another page" },
{ "path": "/nested/index", "mustContain": "Not Found" },
{ "path": "/asdf", "mustContain": "Not Found" }
]
}
}

View File

@@ -4,6 +4,12 @@ import type { RouteManifest } from '@remix-run/dev/dist/config/routes';
describe('getPathFromRoute()', () => {
const routes: RouteManifest = {
root: { path: '', id: 'root', file: 'root.tsx' },
'routes/__pathless': {
path: undefined,
id: 'routes/__pathless',
parentId: 'root',
file: 'routes/__pathless.tsx',
},
'routes/$foo.$bar.$baz': {
path: ':foo/:bar/:baz',
id: 'routes/$foo.$bar.$baz',
@@ -22,12 +28,24 @@ describe('getPathFromRoute()', () => {
parentId: 'root',
file: 'routes/projects.tsx',
},
'routes/projects/__pathless': {
path: undefined,
id: 'routes/projects/__pathless',
parentId: 'routes/projects',
file: 'routes/projects/__pathless.tsx',
},
'routes/projects/index': {
path: undefined,
index: true,
id: 'routes/projects/indexx',
id: 'routes/projects/index',
parentId: 'routes/projects',
file: 'routes/projects/indexx.tsx',
file: 'routes/projects/index.tsx',
},
'routes/projects/create': {
path: 'create',
id: 'routes/projects/create',
parentId: 'routes/projects',
file: 'routes/projects/create.tsx',
},
'routes/projects/$': {
path: '*',
@@ -54,14 +72,26 @@ describe('getPathFromRoute()', () => {
parentId: 'root',
file: 'routes/$.tsx',
},
'routes/nested/index': {
path: 'nested',
index: true,
caseSensitive: undefined,
id: 'routes/nested/index',
parentId: 'root',
file: 'routes/nested/index.tsx',
},
};
it.each([
{ id: 'root', expected: '' },
{ id: 'root', expected: 'index' },
{ id: 'routes/__pathless', expected: '' },
{ id: 'routes/index', expected: 'index' },
{ id: 'routes/api.hello', expected: 'api/hello' },
{ id: 'routes/nested/index', expected: 'nested' },
{ id: 'routes/projects', expected: 'projects' },
{ id: 'routes/projects/index', expected: 'projects/index' },
{ id: 'routes/projects/__pathless', expected: 'projects' },
{ id: 'routes/projects/index', expected: 'projects' },
{ id: 'routes/projects/create', expected: 'projects/create' },
{ id: 'routes/projects/$', expected: 'projects/*' },
{ id: 'routes/$foo.$bar.$baz', expected: ':foo/:bar/:baz' },
{ id: 'routes/node', expected: 'node' },

View File

@@ -0,0 +1,76 @@
import { getResolvedRouteConfig } from '../src/utils';
import type {
ConfigRoute,
RouteManifest,
} from '@remix-run/dev/dist/config/routes';
import type { BaseFunctionConfig } from '@vercel/static-config';
describe('getResolvedRouteConfig()', () => {
const staticConfigsMap = new Map<ConfigRoute, BaseFunctionConfig | null>([
[{ id: 'root', file: 'root.tsx' }, null],
[
{ id: 'routes/edge', file: 'routes/edge.tsx', parentId: 'root' },
{ runtime: 'edge' },
],
[
{
id: 'routes/edge/sfo1',
file: 'routes/edge/sfo1.tsx',
parentId: 'routes/edge',
},
{ regions: ['sfo1'] },
],
[
{
id: 'routes/edge/iad1',
file: 'routes/edge/iad1.tsx',
parentId: 'routes/edge',
},
{ regions: ['iad1'] },
],
[
{ id: 'routes/node', file: 'routes/node.tsx' },
{ runtime: 'nodejs', regions: ['sfo1'] },
],
[
{
id: 'routes/node/mem',
file: 'routes/node/mem.tsx',
parentId: 'routes/node',
},
{ maxDuration: 5, memory: 3008 },
],
]);
const routes: RouteManifest = {};
for (const route of staticConfigsMap.keys()) {
routes[route.id] = route;
}
it.each([
{ id: 'root', expected: { runtime: 'nodejs' } },
{ id: 'routes/edge', expected: { runtime: 'edge' } },
{
id: 'routes/edge/sfo1',
expected: { runtime: 'edge', regions: ['sfo1'] },
},
{
id: 'routes/edge/iad1',
expected: { runtime: 'edge', regions: ['iad1'] },
},
{ id: 'routes/node', expected: { runtime: 'nodejs', regions: ['sfo1'] } },
{
id: 'routes/node/mem',
expected: {
runtime: 'nodejs',
regions: ['sfo1'],
maxDuration: 5,
memory: 3008,
},
},
])('should resolve config for "$id" route', ({ id, expected }) => {
const route = routes[id];
const config = getResolvedRouteConfig(route, routes, staticConfigsMap);
expect(config).toMatchObject(expected);
});
});

View File

@@ -0,0 +1,21 @@
/**
* Edge runtime entrypoint for `@remix-run/vercel`.
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var serverRuntime = require('@remix-run/server-runtime');
/**
* Returns a request handler for the Vercel Edge runtime that serves
* the Remix SSR response.
*/
function createRequestHandler({ build, mode }) {
let handleRequest = serverRuntime.createRequestHandler(build, mode);
return request => {
return handleRequest(request);
};
}
exports.createRequestHandler = createRequestHandler;

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/routing-utils",
"version": "2.1.9",
"version": "2.1.10",
"description": "Vercel routing utilities",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",

Some files were not shown because too many files have changed in this diff Show More