mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 12:57:46 +00:00
Compare commits
84 Commits
vercel-plu
...
@vercel/bu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7039771ec9 | ||
|
|
38d643a8e6 | ||
|
|
9c171c413b | ||
|
|
b620c5343a | ||
|
|
f42391a1f5 | ||
|
|
0505f4e8bd | ||
|
|
ca433a4679 | ||
|
|
204b481c56 | ||
|
|
9265f78c52 | ||
|
|
783144e0d6 | ||
|
|
d563b96ff0 | ||
|
|
ecb4481226 | ||
|
|
347407b244 | ||
|
|
01ea7b4b2a | ||
|
|
475a227ba9 | ||
|
|
40ca92f2e9 | ||
|
|
465129e62e | ||
|
|
bf0d5a7f29 | ||
|
|
d3ef240f6e | ||
|
|
5b26ebc7b8 | ||
|
|
3427ad6ce0 | ||
|
|
4ab5e4326b | ||
|
|
d24a3ce3ab | ||
|
|
29a44db8d9 | ||
|
|
695f3a9212 | ||
|
|
3ff777b8ed | ||
|
|
d94b9806ab | ||
|
|
35c8fc2729 | ||
|
|
0a468fd6d7 | ||
|
|
d31ebbabe4 | ||
|
|
09c9b71adb | ||
|
|
5975db4d66 | ||
|
|
2c86ac654c | ||
|
|
ca5f066eb9 | ||
|
|
410ef86102 | ||
|
|
6792edf32a | ||
|
|
67de167a7e | ||
|
|
0c5c05d90b | ||
|
|
fe43c9c4b2 | ||
|
|
d6a5aa4f6d | ||
|
|
1c3701628d | ||
|
|
45689f22ab | ||
|
|
2c3ddffaac | ||
|
|
c3ea0195c2 | ||
|
|
5f5e50cff0 | ||
|
|
160f4d46d9 | ||
|
|
8d619bd7cc | ||
|
|
b94337d842 | ||
|
|
34f4222ca2 | ||
|
|
5de045edd7 | ||
|
|
5efd3b98de | ||
|
|
82c83312c7 | ||
|
|
5ccb983007 | ||
|
|
7a921399be | ||
|
|
3900f2f982 | ||
|
|
09939f1e07 | ||
|
|
fc3a3ca81f | ||
|
|
ba7bf2e4a6 | ||
|
|
00641037fc | ||
|
|
6f4a1b527b | ||
|
|
1b95576dd2 | ||
|
|
9227471aca | ||
|
|
bf060296eb | ||
|
|
9b3aa41f2e | ||
|
|
ae36585cdb | ||
|
|
e4c636ddd2 | ||
|
|
ae3b25be4b | ||
|
|
a64ed13a40 | ||
|
|
6c1c0e6676 | ||
|
|
82fdd5d121 | ||
|
|
8b40f4435e | ||
|
|
38c87602bb | ||
|
|
7aef3013e7 | ||
|
|
c18676ab4d | ||
|
|
df450c815d | ||
|
|
792ab38760 | ||
|
|
0bba3e76c1 | ||
|
|
3d961ffbb9 | ||
|
|
a3039f57bb | ||
|
|
5499fa9a04 | ||
|
|
b9fd64faff | ||
|
|
1202ff7b2b | ||
|
|
abd9f019f1 | ||
|
|
edb5eead81 |
40
.github/CODEOWNERS
vendored
40
.github/CODEOWNERS
vendored
@@ -4,24 +4,26 @@
|
||||
* @TooTallNate
|
||||
/.github/workflows @AndyBitz @styfle
|
||||
/packages/frameworks @AndyBitz
|
||||
/packages/cli/src/commands/dev @TooTallNate @styfle @AndyBitz
|
||||
/packages/cli/src/util/dev @TooTallNate @styfle @AndyBitz
|
||||
/packages/cli/src/commands/domains @javivelasco @mglagola @anatrajkovska
|
||||
/packages/cli/src/commands/certs @javivelasco @mglagola @anatrajkovska
|
||||
/packages/cli/src/commands/env @styfle @lucleray
|
||||
/packages/client @rdev @styfle @TooTallNate
|
||||
/packages/build-utils @styfle @AndyBitz @TooTallNate
|
||||
/packages/node @styfle @TooTallNate @lucleray
|
||||
/packages/node-bridge @styfle @TooTallNate @lucleray
|
||||
/packages/next @Timer @ijjk
|
||||
/packages/go @styfle @TooTallNate
|
||||
/packages/python @styfle @TooTallNate
|
||||
/packages/ruby @styfle @coetry @TooTallNate
|
||||
/packages/static-build @styfle @AndyBitz
|
||||
/packages/routing-utils @styfle @dav-is @ijjk
|
||||
/examples @mcsdevv @timothyis
|
||||
/packages/cli/src/commands/build @TooTallNate @styfle @AndyBitz @gdborton @jaredpalmer
|
||||
/packages/cli/src/commands/dev @TooTallNate @styfle @AndyBitz
|
||||
/packages/cli/src/util/dev @TooTallNate @styfle @AndyBitz
|
||||
/packages/cli/src/commands/domains @javivelasco @mglagola @anatrajkovska
|
||||
/packages/cli/src/commands/certs @javivelasco @mglagola @anatrajkovska
|
||||
/packages/cli/src/commands/env @styfle @lucleray
|
||||
/packages/client @styfle @TooTallNate
|
||||
/packages/build-utils @styfle @AndyBitz @TooTallNate
|
||||
/packages/middleware @gdborton @javivelasco
|
||||
/packages/node @styfle @TooTallNate @lucleray
|
||||
/packages/node-bridge @styfle @TooTallNate @lucleray
|
||||
/packages/next @Timer @ijjk
|
||||
/packages/go @styfle @TooTallNate
|
||||
/packages/python @styfle @TooTallNate
|
||||
/packages/ruby @styfle @TooTallNate
|
||||
/packages/static-build @styfle @AndyBitz
|
||||
/packages/routing-utils @styfle @dav-is @ijjk
|
||||
/examples @mcsdevv
|
||||
/examples/create-react-app @Timer
|
||||
/examples/nextjs @timneutkens @Timer
|
||||
/examples/hugo @mcsdevv @timothyis @styfle
|
||||
/examples/jekyll @mcsdevv @timothyis @styfle
|
||||
/examples/zola @mcsdevv @timothyis @styfle
|
||||
/examples/hugo @mcsdevv @styfle
|
||||
/examples/jekyll @mcsdevv @styfle
|
||||
/examples/zola @mcsdevv @styfle
|
||||
|
||||
26
.github/workflows/publish.yml
vendored
26
.github/workflows/publish.yml
vendored
@@ -12,21 +12,39 @@ jobs:
|
||||
name: Publish
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-go@v2
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
- name: Check Release
|
||||
id: check-release
|
||||
run: |
|
||||
tag="$(git describe --tags --exact-match 2> /dev/null || :)"
|
||||
if [[ -z "$tag" ]];
|
||||
then
|
||||
echo "::set-output name=IS_RELEASE::false"
|
||||
else
|
||||
echo "::set-output name=IS_RELEASE::true"
|
||||
fi
|
||||
- name: Setup Go
|
||||
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.13.15'
|
||||
- uses: actions/setup-node@v2
|
||||
- name: Setup Node
|
||||
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 12
|
||||
- uses: actions/checkout@v1
|
||||
node-version: 14
|
||||
- name: Install
|
||||
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
|
||||
run: yarn install --check-files --frozen-lockfile --network-timeout 1000000
|
||||
- name: Build
|
||||
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
|
||||
run: yarn build
|
||||
env:
|
||||
GA_TRACKING_ID: ${{ secrets.GA_TRACKING_ID }}
|
||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||
- name: Publish
|
||||
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
|
||||
run: yarn publish-from-github
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN_ELEVATED }}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"description": "API for the vercel/vercel repo",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"vercel-build": "yarn --cwd .. && node ../utils/run.js build all"
|
||||
"vercel-build": "node ../utils/run.js build all"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/node": "5.11.1",
|
||||
|
||||
9
errors/no-single-file-deployments.md
Normal file
9
errors/no-single-file-deployments.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# No Single File Deployments
|
||||
|
||||
#### Why This Error Occurred
|
||||
|
||||
You attempted to create a Vercel deployment where the input is a file, rather than a directory. Previously this was allowed, however this behavior has been removed as of Vercel CLI v24.0.0 because it exposed a potential security risk if the user accidentally created a deployment from a sensitive file.
|
||||
|
||||
#### Possible Ways to Fix It
|
||||
|
||||
- Run the `vercel deploy` command against a directory, instead of a file.
|
||||
10
examples/README.md
vendored
10
examples/README.md
vendored
@@ -14,9 +14,9 @@ Vercel is a cloud platform for static frontends and serverless functions. It ena
|
||||
|
||||
This repository consists of multiple examples, created for use with the [Vercel](https://vercel.com) platform. In addition to this, it also contains:
|
||||
|
||||
- [Code of Conduct](https://github.com/vercel/vercel/blob/master/.github/CODE_OF_CONDUCT.md) - our Code of Conduct, adapted from the [Contributor Covenant](http://contributor-covenant.org)
|
||||
- [Contributing Guidelines](https://github.com/vercel/vercel/blob/master/.github/CONTRIBUTING.md) - a guide on how to contribute to the examples repository
|
||||
- [License](https://github.com/vercel/vercel/blob/master/LICENSE) - the standard MIT license under which these examples are published
|
||||
- [Code of Conduct](https://github.com/vercel/vercel/blob/main/.github/CODE_OF_CONDUCT.md) - our Code of Conduct, adapted from the [Contributor Covenant](http://contributor-covenant.org)
|
||||
- [Contributing Guidelines](https://github.com/vercel/vercel/blob/main/.github/CONTRIBUTING.md) - a guide on how to contribute to the examples repository
|
||||
- [License](https://github.com/vercel/vercel/blob/main/LICENSE) - the standard MIT license under which these examples are published
|
||||
|
||||
We recommend familiarizing yourself with the above sections, particularly if you are looking to make a contribution.
|
||||
|
||||
@@ -60,7 +60,7 @@ If you would like to upgrade a project to take advantage of zero configuration,
|
||||
|
||||
## How to Contribute
|
||||
|
||||
Contributing examples should be an enjoyable experience, as such we have created a set of [contributing guidelines](https://github.com/vercel/vercel/blob/master/.github/CONTRIBUTING.md) to help you do so.
|
||||
Contributing examples should be an enjoyable experience, as such we have created a set of [contributing guidelines](https://github.com/vercel/vercel/blob/main/.github/CONTRIBUTING.md) to help you do so.
|
||||
|
||||
The guidelines cover important information such as the requirements for new examples and where to get help if you have any questions.
|
||||
|
||||
@@ -76,7 +76,7 @@ When submitting an issue, please thoroughly and concisely describe the problem y
|
||||
|
||||
## License
|
||||
|
||||
This repository is an open source project. See the [License](https://github.com/vercel/vercel/blob/master/LICENSE).
|
||||
This repository is an open source project. See the [License](https://github.com/vercel/vercel/blob/main/LICENSE).
|
||||
|
||||
## Get In Touch
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# Angular Example
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# Blitz.js Example
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# React Example
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# Docusaurus Example
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# Eleventy Example
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# Ember Example
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# Gatsby Example
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# Gridsome Example
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# Hexo Example
|
||||
|
||||
|
||||
15787
examples/nextjs/package-lock.json
generated
Normal file
15787
examples/nextjs/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# Polymer Example
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# Preact Example
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# RedwoodJS Example
|
||||
|
||||
|
||||
2
examples/remix/.gitignore
vendored
2
examples/remix/.gitignore
vendored
@@ -5,4 +5,4 @@ node_modules
|
||||
.output
|
||||
|
||||
public/build
|
||||
api/build
|
||||
api/_build
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { createRequestHandler } = require("@remix-run/vercel");
|
||||
|
||||
module.exports = createRequestHandler({
|
||||
build: require("./build")
|
||||
build: require("./_build")
|
||||
});
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* You probably want to just delete this file; it's just for the demo pages.
|
||||
*/
|
||||
.remix-app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
min-height: calc(100vh - env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.remix-app > * {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.remix-app__header {
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.remix-app__header-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.remix-app__header-home-link {
|
||||
width: 106px;
|
||||
height: 30px;
|
||||
color: var(--color-foreground);
|
||||
}
|
||||
|
||||
.remix-app__header-nav ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.5em;
|
||||
}
|
||||
|
||||
.remix-app__header-nav li {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.remix-app__main {
|
||||
flex: 1 1 100%;
|
||||
}
|
||||
|
||||
.remix-app__footer {
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
border-top: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.remix-app__footer-content {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.remix__page {
|
||||
--gap: 1rem;
|
||||
--space: 2rem;
|
||||
display: grid;
|
||||
grid-auto-rows: min-content;
|
||||
gap: var(--gap);
|
||||
padding-top: var(--space);
|
||||
padding-bottom: var(--space);
|
||||
}
|
||||
|
||||
@media print, screen and (min-width: 640px) {
|
||||
.remix__page {
|
||||
--gap: 2rem;
|
||||
grid-auto-rows: unset;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1024px) {
|
||||
.remix__page {
|
||||
--gap: 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.remix__page > main > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.remix__page > main > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.remix__page > aside {
|
||||
margin: 0;
|
||||
padding: 1.5ch 2ch;
|
||||
border: solid 1px var(--color-border);
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.remix__page > aside > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.remix__page > aside > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.remix__form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.remix__form > * {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
8345
examples/remix/package-lock.json
generated
Normal file
8345
examples/remix/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -9,15 +9,15 @@
|
||||
"postinstall": "remix setup node"
|
||||
},
|
||||
"dependencies": {
|
||||
"@remix-run/react": "^1.0.5",
|
||||
"@remix-run/react": "^1.0.6",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"remix": "^1.0.5",
|
||||
"@remix-run/serve": "^1.0.5",
|
||||
"@remix-run/vercel": "^1.0.5"
|
||||
"remix": "^1.0.6",
|
||||
"@remix-run/serve": "^1.0.6",
|
||||
"@remix-run/vercel": "^1.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@remix-run/dev": "^1.0.5",
|
||||
"@remix-run/dev": "^1.0.6",
|
||||
"@types/react": "^17.0.24",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"typescript": "^4.1.2"
|
||||
|
||||
@@ -5,5 +5,5 @@ module.exports = {
|
||||
appDirectory: "app",
|
||||
browserBuildDirectory: "public/build",
|
||||
publicPath: "/build/",
|
||||
serverBuildDirectory: "api/build"
|
||||
serverBuildDirectory: "api/_build"
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# Saber Example
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# Scully Example
|
||||
|
||||
|
||||
22
examples/solidstart/.gitignore
vendored
Normal file
22
examples/solidstart/.gitignore
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
dist
|
||||
worker
|
||||
.solid
|
||||
.vercel
|
||||
.output
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
*.launch
|
||||
.settings/
|
||||
|
||||
# Temp
|
||||
gitignore
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
28
examples/solidstart/README.md
Normal file
28
examples/solidstart/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||

|
||||
|
||||
# SolidStart
|
||||
|
||||
Everything you need to build a Solid project, powered by [`solid-start`](https://github.com/ryansolid/solid-start/tree/main/packages/start);
|
||||
|
||||
## Deploy Your Own
|
||||
|
||||
[](https://vercel.com/new/clone?repository-url=https://github.com/vercel/vercel/tree/main/examples/solidstart&template=solidstart)
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
This uses the [Vercel Adapter](https://github.com/solidjs/solid-start/tree/main/packages/start-vercel) for SolidStart.
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
9
examples/solidstart/jsconfig.json
Normal file
9
examples/solidstart/jsconfig.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "solid-js",
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
20
examples/solidstart/package.json
Normal file
20
examples/solidstart/package.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "solid-start dev",
|
||||
"build": "solid-start build",
|
||||
"start": "solid-start start"
|
||||
},
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"solid-app-router": "^0.1.14",
|
||||
"solid-js": "^1.2.6",
|
||||
"solid-meta": "^0.27.2",
|
||||
"solid-start": "next",
|
||||
"solid-start-vercel": "next",
|
||||
"vite": "^2.7.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
}
|
||||
BIN
examples/solidstart/public/favicon.ico
Normal file
BIN
examples/solidstart/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 664 B |
20
examples/solidstart/src/components/Counter.css
Normal file
20
examples/solidstart/src/components/Counter.css
Normal file
@@ -0,0 +1,20 @@
|
||||
.increment {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
padding: 1em 2em;
|
||||
color: #335d92;
|
||||
background-color: rgba(68, 107, 158, 0.1);
|
||||
border-radius: 2em;
|
||||
border: 2px solid rgba(68, 107, 158, 0);
|
||||
outline: none;
|
||||
width: 200px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.increment:focus {
|
||||
border: 2px solid #335d92;
|
||||
}
|
||||
|
||||
.increment:active {
|
||||
background-color: rgba(68, 107, 158, 0.2);
|
||||
}
|
||||
11
examples/solidstart/src/components/Counter.jsx
Normal file
11
examples/solidstart/src/components/Counter.jsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { createSignal } from "solid-js";
|
||||
import "./Counter.css";
|
||||
|
||||
export default function Counter() {
|
||||
const [count, setCount] = createSignal(0);
|
||||
return (
|
||||
<button class="increment" onClick={() => setCount(count() + 1)}>
|
||||
Clicks: {count}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
36
examples/solidstart/src/pages/index.css
Normal file
36
examples/solidstart/src/pages/index.css
Normal file
@@ -0,0 +1,36 @@
|
||||
body {
|
||||
font-family: Gordita, Roboto, Oxygen, Ubuntu, Cantarell,
|
||||
'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
}
|
||||
|
||||
main {
|
||||
text-align: center;
|
||||
padding: 1em;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #335d92;
|
||||
text-transform: uppercase;
|
||||
font-size: 4rem;
|
||||
font-weight: 100;
|
||||
line-height: 1.1;
|
||||
margin: 4rem auto;
|
||||
max-width: 14rem;
|
||||
}
|
||||
|
||||
p {
|
||||
max-width: 14rem;
|
||||
margin: 2rem auto;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
@media (min-width: 480px) {
|
||||
h1 {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
p {
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
18
examples/solidstart/src/pages/index.jsx
Normal file
18
examples/solidstart/src/pages/index.jsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import Counter from "~/components/Counter";
|
||||
import "./index.css";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main>
|
||||
<h1>Hello world!</h1>
|
||||
<Counter />
|
||||
<p>
|
||||
Visit{" "}
|
||||
<a href="https://solidjs.com" target="_blank">
|
||||
solidjs.com
|
||||
</a>{" "}
|
||||
to learn how to build Solid apps.
|
||||
</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
21
examples/solidstart/src/root.jsx
Normal file
21
examples/solidstart/src/root.jsx
Normal file
@@ -0,0 +1,21 @@
|
||||
// @refresh reload
|
||||
import { Links, Meta, Outlet, Scripts } from "solid-start/components";
|
||||
|
||||
export default function Root({ Start }) {
|
||||
return (
|
||||
<Start>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<Meta />
|
||||
<Links />
|
||||
</head>
|
||||
<body>
|
||||
<Outlet />
|
||||
<Scripts />
|
||||
</body>
|
||||
</html>
|
||||
</Start>
|
||||
);
|
||||
}
|
||||
7
examples/solidstart/vite.config.js
Normal file
7
examples/solidstart/vite.config.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import { defineConfig } from "vite";
|
||||
import solid from "solid-start";
|
||||
import vercel from "solid-start-vercel"
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [solid({ adapter: vercel() })]
|
||||
});
|
||||
934
examples/solidstart/yarn.lock
Normal file
934
examples/solidstart/yarn.lock
Normal file
@@ -0,0 +1,934 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@babel/code-frame@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431"
|
||||
integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==
|
||||
dependencies:
|
||||
"@babel/highlight" "^7.16.0"
|
||||
|
||||
"@babel/compat-data@^7.16.0":
|
||||
version "7.16.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e"
|
||||
integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==
|
||||
|
||||
"@babel/core@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.0.tgz#c4ff44046f5fe310525cc9eb4ef5147f0c5374d4"
|
||||
integrity sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.16.0"
|
||||
"@babel/generator" "^7.16.0"
|
||||
"@babel/helper-compilation-targets" "^7.16.0"
|
||||
"@babel/helper-module-transforms" "^7.16.0"
|
||||
"@babel/helpers" "^7.16.0"
|
||||
"@babel/parser" "^7.16.0"
|
||||
"@babel/template" "^7.16.0"
|
||||
"@babel/traverse" "^7.16.0"
|
||||
"@babel/types" "^7.16.0"
|
||||
convert-source-map "^1.7.0"
|
||||
debug "^4.1.0"
|
||||
gensync "^1.0.0-beta.2"
|
||||
json5 "^2.1.2"
|
||||
semver "^6.3.0"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/generator@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2"
|
||||
integrity sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew==
|
||||
dependencies:
|
||||
"@babel/types" "^7.16.0"
|
||||
jsesc "^2.5.1"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/helper-annotate-as-pure@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz#9a1f0ebcda53d9a2d00108c4ceace6a5d5f1f08d"
|
||||
integrity sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg==
|
||||
dependencies:
|
||||
"@babel/types" "^7.16.0"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.16.0":
|
||||
version "7.16.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz#5b480cd13f68363df6ec4dc8ac8e2da11363cbf0"
|
||||
integrity sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA==
|
||||
dependencies:
|
||||
"@babel/compat-data" "^7.16.0"
|
||||
"@babel/helper-validator-option" "^7.14.5"
|
||||
browserslist "^4.17.5"
|
||||
semver "^6.3.0"
|
||||
|
||||
"@babel/helper-create-class-features-plugin@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.0.tgz#090d4d166b342a03a9fec37ef4fd5aeb9c7c6a4b"
|
||||
integrity sha512-XLwWvqEaq19zFlF5PTgOod4bUA+XbkR4WLQBct1bkzmxJGB0ZEJaoKF4c8cgH9oBtCDuYJ8BP5NB9uFiEgO5QA==
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure" "^7.16.0"
|
||||
"@babel/helper-function-name" "^7.16.0"
|
||||
"@babel/helper-member-expression-to-functions" "^7.16.0"
|
||||
"@babel/helper-optimise-call-expression" "^7.16.0"
|
||||
"@babel/helper-replace-supers" "^7.16.0"
|
||||
"@babel/helper-split-export-declaration" "^7.16.0"
|
||||
|
||||
"@babel/helper-function-name@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481"
|
||||
integrity sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog==
|
||||
dependencies:
|
||||
"@babel/helper-get-function-arity" "^7.16.0"
|
||||
"@babel/template" "^7.16.0"
|
||||
"@babel/types" "^7.16.0"
|
||||
|
||||
"@babel/helper-get-function-arity@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa"
|
||||
integrity sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ==
|
||||
dependencies:
|
||||
"@babel/types" "^7.16.0"
|
||||
|
||||
"@babel/helper-hoist-variables@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a"
|
||||
integrity sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg==
|
||||
dependencies:
|
||||
"@babel/types" "^7.16.0"
|
||||
|
||||
"@babel/helper-member-expression-to-functions@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4"
|
||||
integrity sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ==
|
||||
dependencies:
|
||||
"@babel/types" "^7.16.0"
|
||||
|
||||
"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3"
|
||||
integrity sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==
|
||||
dependencies:
|
||||
"@babel/types" "^7.16.0"
|
||||
|
||||
"@babel/helper-module-transforms@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5"
|
||||
integrity sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.16.0"
|
||||
"@babel/helper-replace-supers" "^7.16.0"
|
||||
"@babel/helper-simple-access" "^7.16.0"
|
||||
"@babel/helper-split-export-declaration" "^7.16.0"
|
||||
"@babel/helper-validator-identifier" "^7.15.7"
|
||||
"@babel/template" "^7.16.0"
|
||||
"@babel/traverse" "^7.16.0"
|
||||
"@babel/types" "^7.16.0"
|
||||
|
||||
"@babel/helper-optimise-call-expression@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338"
|
||||
integrity sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw==
|
||||
dependencies:
|
||||
"@babel/types" "^7.16.0"
|
||||
|
||||
"@babel/helper-plugin-utils@^7.14.5":
|
||||
version "7.14.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9"
|
||||
integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==
|
||||
|
||||
"@babel/helper-replace-supers@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17"
|
||||
integrity sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA==
|
||||
dependencies:
|
||||
"@babel/helper-member-expression-to-functions" "^7.16.0"
|
||||
"@babel/helper-optimise-call-expression" "^7.16.0"
|
||||
"@babel/traverse" "^7.16.0"
|
||||
"@babel/types" "^7.16.0"
|
||||
|
||||
"@babel/helper-simple-access@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz#21d6a27620e383e37534cf6c10bba019a6f90517"
|
||||
integrity sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw==
|
||||
dependencies:
|
||||
"@babel/types" "^7.16.0"
|
||||
|
||||
"@babel/helper-split-export-declaration@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438"
|
||||
integrity sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw==
|
||||
dependencies:
|
||||
"@babel/types" "^7.16.0"
|
||||
|
||||
"@babel/helper-validator-identifier@^7.15.7":
|
||||
version "7.15.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389"
|
||||
integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==
|
||||
|
||||
"@babel/helper-validator-option@^7.14.5":
|
||||
version "7.14.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3"
|
||||
integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==
|
||||
|
||||
"@babel/helpers@^7.16.0":
|
||||
version "7.16.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.3.tgz#27fc64f40b996e7074dc73128c3e5c3e7f55c43c"
|
||||
integrity sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w==
|
||||
dependencies:
|
||||
"@babel/template" "^7.16.0"
|
||||
"@babel/traverse" "^7.16.3"
|
||||
"@babel/types" "^7.16.0"
|
||||
|
||||
"@babel/highlight@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a"
|
||||
integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.15.7"
|
||||
chalk "^2.0.0"
|
||||
js-tokens "^4.0.0"
|
||||
|
||||
"@babel/parser@^7.16.0", "@babel/parser@^7.16.3":
|
||||
version "7.16.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e"
|
||||
integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng==
|
||||
|
||||
"@babel/plugin-syntax-jsx@^7.10.4":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.0.tgz#f9624394317365a9a88c82358d3f8471154698f1"
|
||||
integrity sha512-8zv2+xiPHwly31RK4RmnEYY5zziuF3O7W2kIDW+07ewWDh6Oi0dRq8kwvulRkFgt6DB97RlKs5c1y068iPlCUg==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.14.5"
|
||||
|
||||
"@babel/plugin-syntax-typescript@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.0.tgz#2feeb13d9334cc582ea9111d3506f773174179bb"
|
||||
integrity sha512-Xv6mEXqVdaqCBfJFyeab0fH2DnUoMsDmhamxsSi4j8nLd4Vtw213WMJr55xxqipC/YVWyPY3K0blJncPYji+dQ==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.14.5"
|
||||
|
||||
"@babel/plugin-transform-typescript@^7.16.0":
|
||||
version "7.16.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.1.tgz#cc0670b2822b0338355bc1b3d2246a42b8166409"
|
||||
integrity sha512-NO4XoryBng06jjw/qWEU2LhcLJr1tWkhpMam/H4eas/CDKMX/b2/Ylb6EI256Y7+FVPCawwSM1rrJNOpDiz+Lg==
|
||||
dependencies:
|
||||
"@babel/helper-create-class-features-plugin" "^7.16.0"
|
||||
"@babel/helper-plugin-utils" "^7.14.5"
|
||||
"@babel/plugin-syntax-typescript" "^7.16.0"
|
||||
|
||||
"@babel/preset-typescript@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.0.tgz#b0b4f105b855fb3d631ec036cdc9d1ffd1fa5eac"
|
||||
integrity sha512-txegdrZYgO9DlPbv+9QOVpMnKbOtezsLHWsnsRF4AjbSIsVaujrq1qg8HK0mxQpWv0jnejt0yEoW1uWpvbrDTg==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.14.5"
|
||||
"@babel/helper-validator-option" "^7.14.5"
|
||||
"@babel/plugin-transform-typescript" "^7.16.0"
|
||||
|
||||
"@babel/template@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6"
|
||||
integrity sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.16.0"
|
||||
"@babel/parser" "^7.16.0"
|
||||
"@babel/types" "^7.16.0"
|
||||
|
||||
"@babel/traverse@^7.16.0", "@babel/traverse@^7.16.3":
|
||||
version "7.16.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.3.tgz#f63e8a938cc1b780f66d9ed3c54f532ca2d14787"
|
||||
integrity sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.16.0"
|
||||
"@babel/generator" "^7.16.0"
|
||||
"@babel/helper-function-name" "^7.16.0"
|
||||
"@babel/helper-hoist-variables" "^7.16.0"
|
||||
"@babel/helper-split-export-declaration" "^7.16.0"
|
||||
"@babel/parser" "^7.16.3"
|
||||
"@babel/types" "^7.16.0"
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/types@^7.11.5", "@babel/types@^7.16.0":
|
||||
version "7.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba"
|
||||
integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.15.7"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@rollup/plugin-commonjs@^19.0.1":
|
||||
version "19.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-19.0.2.tgz#1ccc3d63878d1bc9846f8969f09dd3b3e4ecc244"
|
||||
integrity sha512-gBjarfqlC7qs0AutpRW/hrFNm+cd2/QKxhwyFa+srbg1oX7rDsEU3l+W7LAUhsAp9mPJMAkXDhLbQaVwEaE8bA==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^3.1.0"
|
||||
commondir "^1.0.1"
|
||||
estree-walker "^2.0.1"
|
||||
glob "^7.1.6"
|
||||
is-reference "^1.2.1"
|
||||
magic-string "^0.25.7"
|
||||
resolve "^1.17.0"
|
||||
|
||||
"@rollup/plugin-json@^4.1.0":
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-json/-/plugin-json-4.1.0.tgz#54e09867ae6963c593844d8bd7a9c718294496f3"
|
||||
integrity sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^3.0.8"
|
||||
|
||||
"@rollup/plugin-node-resolve@^13.0.2":
|
||||
version "13.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.0.6.tgz#29629070bb767567be8157f575cfa8f2b8e9ef77"
|
||||
integrity sha512-sFsPDMPd4gMqnh2gS0uIxELnoRUp5kBl5knxD2EO0778G1oOJv4G1vyT2cpWz75OU2jDVcXhjVUuTAczGyFNKA==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^3.1.0"
|
||||
"@types/resolve" "1.17.1"
|
||||
builtin-modules "^3.1.0"
|
||||
deepmerge "^4.2.2"
|
||||
is-module "^1.0.0"
|
||||
resolve "^1.19.0"
|
||||
|
||||
"@rollup/pluginutils@^3.0.8", "@rollup/pluginutils@^3.1.0":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b"
|
||||
integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==
|
||||
dependencies:
|
||||
"@types/estree" "0.0.39"
|
||||
estree-walker "^1.0.1"
|
||||
picomatch "^2.2.2"
|
||||
|
||||
"@types/estree@*":
|
||||
version "0.0.50"
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83"
|
||||
integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==
|
||||
|
||||
"@types/estree@0.0.39":
|
||||
version "0.0.39"
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
|
||||
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
|
||||
|
||||
"@types/node@*":
|
||||
version "16.11.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.12.tgz#ac7fb693ac587ee182c3780c26eb65546a1a3c10"
|
||||
integrity sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==
|
||||
|
||||
"@types/resolve@1.17.1":
|
||||
version "1.17.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
|
||||
integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
ansi-styles@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
|
||||
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
|
||||
dependencies:
|
||||
color-convert "^1.9.0"
|
||||
|
||||
babel-plugin-jsx-dom-expressions@^0.30.9:
|
||||
version "0.30.9"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.30.9.tgz#7942a3d92ffade734f3ac807ed2453d889db18ef"
|
||||
integrity sha512-FdfgH5IgB5vUCHGQtj65uZ4uiW42VPN2h2KgRwRkINL9/vHRPw0bsGKL+2CaI/LmLKvot9IXhqjSV/HhD0KDWA==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.10.4"
|
||||
"@babel/plugin-syntax-jsx" "^7.10.4"
|
||||
"@babel/types" "^7.11.5"
|
||||
html-entities "2.3.2"
|
||||
|
||||
babel-preset-solid@^1.2.6:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/babel-preset-solid/-/babel-preset-solid-1.2.6.tgz#8907d23b8d9293bac18d16d8cb4ec761031f4270"
|
||||
integrity sha512-rFl9Sv/llx5fbE1zfx9QlQMsJz3q/nQZds2xq5Atnayop1NOyK9l/ychF2g3DWXoN9MbAR+ZxZqxzsPnOXAV+A==
|
||||
dependencies:
|
||||
babel-plugin-jsx-dom-expressions "^0.30.9"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
browserslist@^4.17.5:
|
||||
version "4.18.1"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.18.1.tgz#60d3920f25b6860eb917c6c7b185576f4d8b017f"
|
||||
integrity sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ==
|
||||
dependencies:
|
||||
caniuse-lite "^1.0.30001280"
|
||||
electron-to-chromium "^1.3.896"
|
||||
escalade "^3.1.1"
|
||||
node-releases "^2.0.1"
|
||||
picocolors "^1.0.0"
|
||||
|
||||
builtin-modules@^3.1.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887"
|
||||
integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==
|
||||
|
||||
caniuse-lite@^1.0.30001280:
|
||||
version "1.0.30001286"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001286.tgz#3e9debad420419618cfdf52dc9b6572b28a8fff6"
|
||||
integrity sha512-zaEMRH6xg8ESMi2eQ3R4eZ5qw/hJiVsO/HlLwniIwErij0JDr9P+8V4dtx1l+kLq6j3yy8l8W4fst1lBnat5wQ==
|
||||
|
||||
chalk@^2.0.0:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||
dependencies:
|
||||
ansi-styles "^3.2.1"
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
color-convert@^1.9.0:
|
||||
version "1.9.3"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
|
||||
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
|
||||
dependencies:
|
||||
color-name "1.1.3"
|
||||
|
||||
color-name@1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
|
||||
|
||||
commondir@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
|
||||
integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
convert-source-map@^1.7.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
|
||||
integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
|
||||
dependencies:
|
||||
safe-buffer "~5.1.1"
|
||||
|
||||
debug@^4.1.0:
|
||||
version "4.3.3"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
|
||||
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
|
||||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
deepmerge@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
||||
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
|
||||
|
||||
electron-to-chromium@^1.3.896:
|
||||
version "1.4.14"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.14.tgz#b0aa41fbfbf2eff8c2c6f7a871c03075250f8956"
|
||||
integrity sha512-RsGkAN9JEAYMObS72kzUsPPcPGMqX1rBqGuXi9aa4TBKLzICoLf+DAAtd0fVFzrniJqYzpby47gthCUoObfs0Q==
|
||||
|
||||
esbuild-android-arm64@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.13.15.tgz#3fc3ff0bab76fe35dd237476b5d2b32bb20a3d44"
|
||||
integrity sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==
|
||||
|
||||
esbuild-darwin-64@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.13.15.tgz#8e9169c16baf444eacec60d09b24d11b255a8e72"
|
||||
integrity sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==
|
||||
|
||||
esbuild-darwin-arm64@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.15.tgz#1b07f893b632114f805e188ddfca41b2b778229a"
|
||||
integrity sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==
|
||||
|
||||
esbuild-freebsd-64@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.15.tgz#0b8b7eca1690c8ec94c75680c38c07269c1f4a85"
|
||||
integrity sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==
|
||||
|
||||
esbuild-freebsd-arm64@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.15.tgz#2e1a6c696bfdcd20a99578b76350b41db1934e52"
|
||||
integrity sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==
|
||||
|
||||
esbuild-linux-32@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.13.15.tgz#6fd39f36fc66dd45b6b5f515728c7bbebc342a69"
|
||||
integrity sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==
|
||||
|
||||
esbuild-linux-64@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.13.15.tgz#9cb8e4bcd7574e67946e4ee5f1f1e12386bb6dd3"
|
||||
integrity sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==
|
||||
|
||||
esbuild-linux-arm64@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.15.tgz#3891aa3704ec579a1b92d2a586122e5b6a2bfba1"
|
||||
integrity sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==
|
||||
|
||||
esbuild-linux-arm@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.13.15.tgz#8a00e99e6a0c6c9a6b7f334841364d8a2b4aecfe"
|
||||
integrity sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==
|
||||
|
||||
esbuild-linux-mips64le@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.15.tgz#36b07cc47c3d21e48db3bb1f4d9ef8f46aead4f7"
|
||||
integrity sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==
|
||||
|
||||
esbuild-linux-ppc64le@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.15.tgz#f7e6bba40b9a11eb9dcae5b01550ea04670edad2"
|
||||
integrity sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==
|
||||
|
||||
esbuild-netbsd-64@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.15.tgz#a2fedc549c2b629d580a732d840712b08d440038"
|
||||
integrity sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==
|
||||
|
||||
esbuild-openbsd-64@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.15.tgz#b22c0e5806d3a1fbf0325872037f885306b05cd7"
|
||||
integrity sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==
|
||||
|
||||
esbuild-sunos-64@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.13.15.tgz#d0b6454a88375ee8d3964daeff55c85c91c7cef4"
|
||||
integrity sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==
|
||||
|
||||
esbuild-windows-32@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.13.15.tgz#c96d0b9bbb52f3303322582ef8e4847c5ad375a7"
|
||||
integrity sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==
|
||||
|
||||
esbuild-windows-64@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.13.15.tgz#1f79cb9b1e1bb02fb25cd414cb90d4ea2892c294"
|
||||
integrity sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==
|
||||
|
||||
esbuild-windows-arm64@0.13.15:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.15.tgz#482173070810df22a752c686509c370c3be3b3c3"
|
||||
integrity sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==
|
||||
|
||||
esbuild@^0.13.12:
|
||||
version "0.13.15"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.13.15.tgz#db56a88166ee373f87dbb2d8798ff449e0450cdf"
|
||||
integrity sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==
|
||||
optionalDependencies:
|
||||
esbuild-android-arm64 "0.13.15"
|
||||
esbuild-darwin-64 "0.13.15"
|
||||
esbuild-darwin-arm64 "0.13.15"
|
||||
esbuild-freebsd-64 "0.13.15"
|
||||
esbuild-freebsd-arm64 "0.13.15"
|
||||
esbuild-linux-32 "0.13.15"
|
||||
esbuild-linux-64 "0.13.15"
|
||||
esbuild-linux-arm "0.13.15"
|
||||
esbuild-linux-arm64 "0.13.15"
|
||||
esbuild-linux-mips64le "0.13.15"
|
||||
esbuild-linux-ppc64le "0.13.15"
|
||||
esbuild-netbsd-64 "0.13.15"
|
||||
esbuild-openbsd-64 "0.13.15"
|
||||
esbuild-sunos-64 "0.13.15"
|
||||
esbuild-windows-32 "0.13.15"
|
||||
esbuild-windows-64 "0.13.15"
|
||||
esbuild-windows-arm64 "0.13.15"
|
||||
|
||||
escalade@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
||||
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
|
||||
|
||||
escape-string-regexp@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
|
||||
estree-walker@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
|
||||
integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
|
||||
|
||||
estree-walker@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
|
||||
integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||
|
||||
fsevents@~2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
||||
|
||||
function-bind@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
||||
|
||||
gensync@^1.0.0-beta.2:
|
||||
version "1.0.0-beta.2"
|
||||
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
||||
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
|
||||
|
||||
glob@^7.1.6:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
|
||||
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.4"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
globals@^11.1.0:
|
||||
version "11.12.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
|
||||
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
|
||||
|
||||
has-flag@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
||||
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
|
||||
|
||||
has@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
|
||||
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
|
||||
html-entities@2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.2.tgz#760b404685cb1d794e4f4b744332e3b00dcfe488"
|
||||
integrity sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
|
||||
dependencies:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
is-core-module@^2.2.0:
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548"
|
||||
integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==
|
||||
dependencies:
|
||||
has "^1.0.3"
|
||||
|
||||
is-module@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
|
||||
integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=
|
||||
|
||||
is-reference@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7"
|
||||
integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==
|
||||
dependencies:
|
||||
"@types/estree" "*"
|
||||
|
||||
is-what@^3.14.1:
|
||||
version "3.14.1"
|
||||
resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1"
|
||||
integrity sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==
|
||||
|
||||
js-tokens@^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==
|
||||
|
||||
jsesc@^2.5.1:
|
||||
version "2.5.2"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
|
||||
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
|
||||
|
||||
json5@^2.1.2:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
|
||||
integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
|
||||
dependencies:
|
||||
minimist "^1.2.5"
|
||||
|
||||
magic-string@^0.25.7:
|
||||
version "0.25.7"
|
||||
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
|
||||
integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==
|
||||
dependencies:
|
||||
sourcemap-codec "^1.4.4"
|
||||
|
||||
merge-anything@^4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/merge-anything/-/merge-anything-4.0.2.tgz#cb61fdd4e0604e254ff571f90869fa1af2d39e7f"
|
||||
integrity sha512-YxLHKgX8jN5xfKIxcwVNzQ2HpS0r9eUSqifgGhVARoZEW31Jwu95OQzX7qlFPBPQdCmNBhCYaqJzOcwAKi2Elg==
|
||||
dependencies:
|
||||
is-what "^3.14.1"
|
||||
ts-toolbelt "^9.6.0"
|
||||
|
||||
minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimist@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
|
||||
mri@^1.1.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
|
||||
integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==
|
||||
|
||||
ms@2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
nanoid@^3.1.30:
|
||||
version "3.1.30"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362"
|
||||
integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==
|
||||
|
||||
node-fetch@^2.6.6:
|
||||
version "2.6.6"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89"
|
||||
integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-releases@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5"
|
||||
integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==
|
||||
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
path-is-absolute@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
|
||||
|
||||
path-parse@^1.0.6:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
||||
|
||||
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==
|
||||
|
||||
picomatch@^2.2.2:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
|
||||
integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
|
||||
|
||||
postcss@^8.3.11:
|
||||
version "8.4.4"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.4.tgz#d53d4ec6a75fd62557a66bb41978bf47ff0c2869"
|
||||
integrity sha512-joU6fBsN6EIer28Lj6GDFoC/5yOZzLCfn0zHAn/MYXI7aPt4m4hK5KC5ovEZXy+lnCjmYIbQWngvju2ddyEr8Q==
|
||||
dependencies:
|
||||
nanoid "^3.1.30"
|
||||
picocolors "^1.0.0"
|
||||
source-map-js "^1.0.1"
|
||||
|
||||
resolve@^1.17.0, resolve@^1.19.0, resolve@^1.20.0:
|
||||
version "1.20.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
|
||||
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
|
||||
dependencies:
|
||||
is-core-module "^2.2.0"
|
||||
path-parse "^1.0.6"
|
||||
|
||||
rollup-route-manifest@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/rollup-route-manifest/-/rollup-route-manifest-1.0.0.tgz#74a7e910694583f1206e62e70b478af74a1a7ce8"
|
||||
integrity sha512-3CmcMmCLAzJDUXiO3z6386/Pt8/k9xTZv8gIHyXI8hYGoAInnYdOsFXiGGzQRMy6TXR1jUZme2qbdwjH2nFMjg==
|
||||
dependencies:
|
||||
route-sort "^1.0.0"
|
||||
|
||||
rollup@^2.53.3, rollup@^2.59.0:
|
||||
version "2.61.0"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.61.0.tgz#ccd927bcd6cc0c78a4689c918627a717977208f4"
|
||||
integrity sha512-teQ+T1mUYbyvGyUavCodiyA9hD4DxwYZJwr/qehZGhs1Z49vsmzelMVYMxGU4ZhGRKxYPupHuz5yzm/wj7VpWA==
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
route-sort@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/route-sort/-/route-sort-1.0.0.tgz#078149c8d2d2de8b8563adf139ec58476835c94b"
|
||||
integrity sha512-SFgmvjoIhp5S4iBEDW3XnbT+7PRuZ55oRuNjY+CDB1SGZkyCG9bqQ3/dhaZTctTBYMAvDxd2Uy9dStuaUfgJqQ==
|
||||
|
||||
sade@^1.7.4:
|
||||
version "1.7.4"
|
||||
resolved "https://registry.yarnpkg.com/sade/-/sade-1.7.4.tgz#ea681e0c65d248d2095c90578c03ca0bb1b54691"
|
||||
integrity sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==
|
||||
dependencies:
|
||||
mri "^1.1.0"
|
||||
|
||||
safe-buffer@~5.1.1:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
semver@^6.3.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
|
||||
solid-app-router@^0.1.14:
|
||||
version "0.1.14"
|
||||
resolved "https://registry.yarnpkg.com/solid-app-router/-/solid-app-router-0.1.14.tgz#2ffb1bfbb7db7d9d1cd81be5aec1eb786b961573"
|
||||
integrity sha512-fnX+jCB5sDMbjq3od9qGtQNdlvHP2c6DG5STvMHVXyNuSEN+MdO7WJtZ58OpVpq6zWS4FYeYAh7NMEa7C2CcOA==
|
||||
|
||||
solid-js@^1.2.6:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/solid-js/-/solid-js-1.2.6.tgz#54e91ecb78bb6cc78efea2f05f979f6aa71b25ef"
|
||||
integrity sha512-NvPHJ5Vj5f+ZJWIioickrC55seovSkDtm5NzSpnoUk3z4tATv0STpy5iuGNEn51ZORUcwpZzrMAtOCGziXU1XA==
|
||||
|
||||
solid-meta@^0.27.2:
|
||||
version "0.27.2"
|
||||
resolved "https://registry.yarnpkg.com/solid-meta/-/solid-meta-0.27.2.tgz#873205fb7658bc67207b5feda5e360942fb63bad"
|
||||
integrity sha512-t4rotsA99LMhiSI6C0pfN1fR8+bApl2ouOqIpOgxHtapJ+fgBIv7cVnI3nLMMzjiiML+vb83l9xes6/OLSCNtw==
|
||||
|
||||
solid-refresh@^0.3.2:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/solid-refresh/-/solid-refresh-0.3.2.tgz#feb0a1a4ebb2b2e8467f6b7fbd5de940e1f4c0f0"
|
||||
integrity sha512-7lg3EjenGoxQvGoZnTD3d480wBxbpAiAsyk0dhoGq6hjcaAQ3vnsBGxvXV0LBTzeQcGmIRz1GeSsw/64YyNr+g==
|
||||
dependencies:
|
||||
"@babel/generator" "^7.16.0"
|
||||
"@babel/helper-module-imports" "^7.16.0"
|
||||
"@babel/types" "^7.16.0"
|
||||
|
||||
solid-ssr@^1.2.6:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/solid-ssr/-/solid-ssr-1.2.6.tgz#9bcc913051d6e711e82cfc88c6abbbaf2c440239"
|
||||
integrity sha512-129iBio60LT+0xXCB2AEecGmFyxooC9VFnjOGan/fLZnBbLE5I6HGYyFBFc8CvVv/SHzjI+XsEgGj9iQCpw7RQ==
|
||||
|
||||
solid-start-vercel@next:
|
||||
version "0.1.0-alpha.45"
|
||||
resolved "https://registry.yarnpkg.com/solid-start-vercel/-/solid-start-vercel-0.1.0-alpha.45.tgz#78859d4845be87f890165b9f6362a80c16ae115c"
|
||||
integrity sha512-VZNGAxBf8sL/8aYEUwpxynur7u+Ul6++nfUsIaqWyfzluQizA6FKqqkLf9K8g453Oi1/WbNjS4dWKgzRF4H+wA==
|
||||
dependencies:
|
||||
"@rollup/plugin-commonjs" "^19.0.1"
|
||||
"@rollup/plugin-json" "^4.1.0"
|
||||
"@rollup/plugin-node-resolve" "^13.0.2"
|
||||
rollup "^2.53.3"
|
||||
|
||||
solid-start@next:
|
||||
version "0.1.0-alpha.45"
|
||||
resolved "https://registry.yarnpkg.com/solid-start/-/solid-start-0.1.0-alpha.45.tgz#ac24c933d12ccd22325abe7a30f6bb24ec55bc63"
|
||||
integrity sha512-hrFcMcrpJN5lvnt/Z/EqcP+VT8VeKJ1h4bcs9LVQV6NRuSPlpEmK3Cm5VjM+7RPRBWRcIvtbgtyDJALOnDTm8A==
|
||||
dependencies:
|
||||
node-fetch "^2.6.6"
|
||||
rollup-route-manifest "^1.0.0"
|
||||
sade "^1.7.4"
|
||||
solid-ssr "^1.2.6"
|
||||
vite-plugin-solid "^2.1.4"
|
||||
|
||||
source-map-js@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf"
|
||||
integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==
|
||||
|
||||
source-map@^0.5.0:
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
|
||||
|
||||
sourcemap-codec@^1.4.4:
|
||||
version "1.4.8"
|
||||
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
|
||||
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
|
||||
|
||||
supports-color@^5.3.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
|
||||
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
|
||||
dependencies:
|
||||
has-flag "^3.0.0"
|
||||
|
||||
to-fast-properties@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
||||
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
|
||||
|
||||
tr46@~0.0.3:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||
integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=
|
||||
|
||||
ts-toolbelt@^9.6.0:
|
||||
version "9.6.0"
|
||||
resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz#50a25426cfed500d4a09bd1b3afb6f28879edfd5"
|
||||
integrity sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==
|
||||
|
||||
vite-plugin-solid@^2.1.4:
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/vite-plugin-solid/-/vite-plugin-solid-2.1.4.tgz#20cc3d03b6dc2c7dc57ee54ccd6da061886f6e6a"
|
||||
integrity sha512-lhEPlDf4PB+KKu5ExaT3zaENqC8shpJ4H74a2R0qbr1MCiFvhE/AooWvIlclpHzBtDK6MmUKv25qSFoSC1EaXQ==
|
||||
dependencies:
|
||||
"@babel/core" "^7.16.0"
|
||||
"@babel/preset-typescript" "^7.16.0"
|
||||
babel-preset-solid "^1.2.6"
|
||||
merge-anything "^4.0.1"
|
||||
solid-js "^1.2.6"
|
||||
solid-refresh "^0.3.2"
|
||||
vite "^2.7.1"
|
||||
|
||||
vite@^2.7.1:
|
||||
version "2.7.1"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-2.7.1.tgz#be50ad13214290ecbebbe5ad389ed423cb5f137e"
|
||||
integrity sha512-TDXXhcu5lyQ6uosK4ZWaOyB4VzOiizk0biitRzDzaEtgSUi8rVYPc4k1xgOjLSf0OuceDJmojFKXHOX9DB1WuQ==
|
||||
dependencies:
|
||||
esbuild "^0.13.12"
|
||||
postcss "^8.3.11"
|
||||
resolve "^1.20.0"
|
||||
rollup "^2.59.0"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
webidl-conversions@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||
integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=
|
||||
|
||||
whatwg-url@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
|
||||
integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0=
|
||||
dependencies:
|
||||
tr46 "~0.0.3"
|
||||
webidl-conversions "^3.0.0"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# UmiJS Example
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
# Vue.js Example
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "2.12.3-canary.25",
|
||||
"version": "2.13.0",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
"homepage": "https://github.com/vercel/vercel/blob/master/DEVELOPING_A_RUNTIME.md",
|
||||
"homepage": "https://github.com/vercel/vercel/blob/main/DEVELOPING_A_RUNTIME.md",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vercel/vercel.git",
|
||||
@@ -30,7 +30,7 @@
|
||||
"@types/node-fetch": "^2.1.6",
|
||||
"@types/semver": "6.0.0",
|
||||
"@types/yazl": "^2.4.1",
|
||||
"@vercel/frameworks": "0.5.1-canary.15",
|
||||
"@vercel/frameworks": "0.5.1-canary.19",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"aggregate-error": "3.0.1",
|
||||
"async-retry": "1.2.3",
|
||||
|
||||
@@ -1,127 +1,296 @@
|
||||
import fs from 'fs-extra';
|
||||
import { join, dirname, relative } from 'path';
|
||||
import { join, parse, relative, dirname, basename, extname } from 'path';
|
||||
import glob from './fs/glob';
|
||||
import { normalizePath } from './fs/normalize-path';
|
||||
import { FILES_SYMBOL, getLambdaOptionsFromFunction, Lambda } from './lambda';
|
||||
import type FileBlob from './file-blob';
|
||||
import type { BuilderFunctions, BuildOptions, Files } from './types';
|
||||
import minimatch from 'minimatch';
|
||||
import { FILES_SYMBOL, Lambda } from './lambda';
|
||||
import type { BuildOptions, Files } from './types';
|
||||
import { debug, getIgnoreFilter } from '.';
|
||||
|
||||
// `.output` was already created by the Build Command, so we have
|
||||
// to ensure its contents don't get bundled into the Lambda. Similarily,
|
||||
// we don't want to bundle anything from `.vercel` either. Lastly,
|
||||
// Builders/Runtimes didn't have `vercel.json` or `now.json`.
|
||||
const ignoredPaths = ['.output', '.vercel', 'vercel.json', 'now.json'];
|
||||
|
||||
const shouldIgnorePath = (
|
||||
file: string,
|
||||
ignoreFilter: any,
|
||||
ignoreFile: boolean
|
||||
) => {
|
||||
const isNative = ignoredPaths.some(item => {
|
||||
return file.startsWith(item);
|
||||
});
|
||||
|
||||
if (!ignoreFile) {
|
||||
return isNative;
|
||||
}
|
||||
|
||||
return isNative || ignoreFilter(file);
|
||||
};
|
||||
|
||||
const getSourceFiles = async (workPath: string, ignoreFilter: any) => {
|
||||
const list = await glob('**', {
|
||||
cwd: workPath,
|
||||
});
|
||||
|
||||
// We're not passing this as an `ignore` filter to the `glob` function above,
|
||||
// so that we can re-use exactly the same `getIgnoreFilter` method that the
|
||||
// Build Step uses (literally the same code). Note that this exclusion only applies
|
||||
// when deploying. Locally, another exclusion is needed, which is handled
|
||||
// further below in the `convertRuntimeToPlugin` function.
|
||||
for (const file in list) {
|
||||
if (shouldIgnorePath(file, ignoreFilter, true)) {
|
||||
delete list[file];
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert legacy Runtime to a Plugin.
|
||||
* @param buildRuntime - a legacy build() function from a Runtime
|
||||
* @param packageName - the name of the package, for example `vercel-plugin-python`
|
||||
* @param ext - the file extension, for example `.py`
|
||||
*/
|
||||
export function convertRuntimeToPlugin(
|
||||
export function _experimental_convertRuntimeToPlugin(
|
||||
buildRuntime: (options: BuildOptions) => Promise<{ output: Lambda }>,
|
||||
packageName: string,
|
||||
ext: string
|
||||
) {
|
||||
// This `build()` signature should match `plugin.build()` signature in `vercel build`.
|
||||
return async function build({
|
||||
vercelConfig,
|
||||
workPath,
|
||||
}: {
|
||||
vercelConfig: {
|
||||
functions?: BuilderFunctions;
|
||||
regions?: string[];
|
||||
};
|
||||
workPath: string;
|
||||
}) {
|
||||
const opts = { cwd: workPath };
|
||||
const files = await glob('**', opts);
|
||||
delete files['vercel.json']; // Builders/Runtimes didn't have vercel.json
|
||||
const entrypoints = await glob(`api/**/*${ext}`, opts);
|
||||
return async function build({ workPath }: { workPath: string }) {
|
||||
// We also don't want to provide any files to Runtimes that were ignored
|
||||
// through `.vercelignore` or `.nowignore`, because the Build Step does the same.
|
||||
const ignoreFilter = await getIgnoreFilter(workPath);
|
||||
|
||||
// Retrieve the files that are currently available on the File System,
|
||||
// before the Legacy Runtime has even started to build.
|
||||
const sourceFilesPreBuild = await getSourceFiles(workPath, ignoreFilter);
|
||||
|
||||
// Instead of doing another `glob` to get all the matching source files,
|
||||
// we'll filter the list of existing files down to only the ones
|
||||
// that are matching the entrypoint pattern, so we're first creating
|
||||
// a clean new list to begin.
|
||||
const entrypoints = Object.assign({}, sourceFilesPreBuild);
|
||||
|
||||
const entrypointMatch = new RegExp(`^api/.*${ext}$`);
|
||||
|
||||
// Up next, we'll strip out the files from the list of entrypoints
|
||||
// that aren't actually considered entrypoints.
|
||||
for (const file in entrypoints) {
|
||||
if (!entrypointMatch.test(file)) {
|
||||
delete entrypoints[file];
|
||||
}
|
||||
}
|
||||
|
||||
const pages: { [key: string]: any } = {};
|
||||
const { functions = {} } = vercelConfig;
|
||||
const traceDir = join(workPath, '.output', 'runtime-traced-files');
|
||||
const pluginName = packageName.replace('vercel-plugin-', '');
|
||||
const outputPath = join(workPath, '.output');
|
||||
|
||||
const traceDir = join(
|
||||
outputPath,
|
||||
`inputs`,
|
||||
// Legacy Runtimes can only provide API Routes, so that's
|
||||
// why we can use this prefix for all of them. Here, we have to
|
||||
// make sure to not use a cryptic hash name, because people
|
||||
// need to be able to easily inspect the output.
|
||||
`api-routes-${pluginName}`
|
||||
);
|
||||
|
||||
await fs.ensureDir(traceDir);
|
||||
|
||||
for (const entrypoint of Object.keys(entrypoints)) {
|
||||
const key =
|
||||
Object.keys(functions).find(
|
||||
src => src === entrypoint || minimatch(entrypoint, src)
|
||||
) || '';
|
||||
const config = functions[key] || {};
|
||||
const entryRoot = join(outputPath, 'server', 'pages');
|
||||
|
||||
for (const entrypoint of Object.keys(entrypoints)) {
|
||||
const { output } = await buildRuntime({
|
||||
files,
|
||||
files: sourceFilesPreBuild,
|
||||
entrypoint,
|
||||
workPath,
|
||||
config: {
|
||||
zeroConfig: true,
|
||||
includeFiles: config.includeFiles,
|
||||
excludeFiles: config.excludeFiles,
|
||||
},
|
||||
meta: {
|
||||
avoidTopLevelInstall: true,
|
||||
skipDownload: true,
|
||||
},
|
||||
});
|
||||
|
||||
pages[entrypoint] = {
|
||||
handler: output.handler,
|
||||
// @ts-ignore This symbol is a private API
|
||||
const lambdaFiles: Files = output[FILES_SYMBOL];
|
||||
|
||||
// When deploying, the `files` that are passed to the Legacy Runtimes already
|
||||
// have certain files that are ignored stripped, but locally, that list of
|
||||
// files isn't used by the Legacy Runtimes, so we need to apply the filters
|
||||
// to the outputs that they are returning instead.
|
||||
for (const file in lambdaFiles) {
|
||||
if (shouldIgnorePath(file, ignoreFilter, false)) {
|
||||
delete lambdaFiles[file];
|
||||
}
|
||||
}
|
||||
|
||||
let handlerFileBase = output.handler;
|
||||
let handlerFile = lambdaFiles[handlerFileBase];
|
||||
let handlerHasImport = false;
|
||||
|
||||
const { handler } = output;
|
||||
const handlerMethod = handler.split('.').pop();
|
||||
const handlerFileName = handler.replace(`.${handlerMethod}`, '');
|
||||
|
||||
// For compiled languages, the launcher file for the Lambda generated
|
||||
// by the Legacy Runtime matches the `handler` defined for it, but for
|
||||
// interpreted languages, the `handler` consists of the launcher file name
|
||||
// without an extension, plus the name of the method inside of that file
|
||||
// that should be invoked, so we have to construct the file path explicitly.
|
||||
if (!handlerFile) {
|
||||
handlerFileBase = handlerFileName + ext;
|
||||
handlerFile = lambdaFiles[handlerFileBase];
|
||||
handlerHasImport = true;
|
||||
}
|
||||
|
||||
if (!handlerFile || !handlerFile.fsPath) {
|
||||
throw new Error(
|
||||
`Could not find a handler file. Please ensure that \`files\` for the returned \`Lambda\` contains an \`FileFsRef\` named "${handlerFileBase}" with a valid \`fsPath\`.`
|
||||
);
|
||||
}
|
||||
|
||||
const handlerExtName = extname(handlerFile.fsPath);
|
||||
|
||||
const entryBase = basename(entrypoint).replace(ext, handlerExtName);
|
||||
const entryPath = join(dirname(entrypoint), entryBase);
|
||||
const entry = join(entryRoot, entryPath);
|
||||
|
||||
// Create the parent directory of the API Route that will be created
|
||||
// for the current entrypoint inside of `.output/server/pages/api`.
|
||||
await fs.ensureDir(dirname(entry));
|
||||
|
||||
// For compiled languages, the launcher file will be binary and therefore
|
||||
// won't try to import a user-provided request handler (instead, it will
|
||||
// contain it). But for interpreted languages, the launcher might try to
|
||||
// load a user-provided request handler from the source file instead of bundling
|
||||
// it, so we have to adjust the import statement inside the launcher to point
|
||||
// to the respective source file. Previously, Legacy Runtimes simply expected
|
||||
// the user-provided request-handler to be copied right next to the launcher,
|
||||
// but with the new File System API, files won't be moved around unnecessarily.
|
||||
if (handlerHasImport) {
|
||||
const { fsPath } = handlerFile;
|
||||
const encoding = 'utf-8';
|
||||
|
||||
// This is the true directory of the user-provided request handler in the
|
||||
// source files, so that's what we will use as an import path in the launcher.
|
||||
const locationPrefix = relative(entry, outputPath);
|
||||
|
||||
let handlerContent = await fs.readFile(fsPath, encoding);
|
||||
|
||||
const importPaths = [
|
||||
// This is the full entrypoint path, like `./api/test.py`. In our tests
|
||||
// Python didn't support importing from a parent directory without using different
|
||||
// code in the launcher that registers it as a location for modules and then changing
|
||||
// the importing syntax, but continuing to import it like before seems to work. If
|
||||
// other languages need this, we should consider excluding Python explicitly.
|
||||
// `./${entrypoint}`,
|
||||
|
||||
// This is the entrypoint path without extension, like `api/test`
|
||||
entrypoint.slice(0, -ext.length),
|
||||
];
|
||||
|
||||
// Generate a list of regular expressions that we can use for
|
||||
// finding matches, but only allow matches if the import path is
|
||||
// wrapped inside single (') or double quotes (").
|
||||
const patterns = importPaths.map(path => {
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
return new RegExp(`('|")(${path.replace(/\./g, '\\.')})('|")`, 'g');
|
||||
});
|
||||
|
||||
let replacedMatch = null;
|
||||
|
||||
for (const pattern of patterns) {
|
||||
const newContent = handlerContent.replace(
|
||||
pattern,
|
||||
(_, p1, p2, p3) => {
|
||||
return `${p1}${join(locationPrefix, p2)}${p3}`;
|
||||
}
|
||||
);
|
||||
|
||||
if (newContent !== handlerContent) {
|
||||
debug(
|
||||
`Replaced "${pattern}" inside "${entry}" to ensure correct import of user-provided request handler`
|
||||
);
|
||||
|
||||
handlerContent = newContent;
|
||||
replacedMatch = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!replacedMatch) {
|
||||
new Error(
|
||||
`No replacable matches for "${importPaths[0]}" or "${importPaths[1]}" found in "${fsPath}"`
|
||||
);
|
||||
}
|
||||
|
||||
await fs.writeFile(entry, handlerContent, encoding);
|
||||
} else {
|
||||
await fs.copy(handlerFile.fsPath, entry);
|
||||
}
|
||||
|
||||
// Legacy Runtimes based on interpreted languages will create a new launcher file
|
||||
// for every entrypoint, but they will create each one inside `workPath`, which means that
|
||||
// the launcher for one entrypoint will overwrite the launcher provided for the previous
|
||||
// entrypoint. That's why, above, we copy the file contents into the new destination (and
|
||||
// optionally transform them along the way), instead of linking. We then also want to remove
|
||||
// the copy origin right here, so that the `workPath` doesn't contain a useless launcher file
|
||||
// once the build has finished running.
|
||||
await fs.remove(handlerFile.fsPath);
|
||||
debug(`Removed temporary file "${handlerFile.fsPath}"`);
|
||||
|
||||
const nft = `${entry}.nft.json`;
|
||||
|
||||
const json = JSON.stringify({
|
||||
version: 2,
|
||||
files: Object.keys(lambdaFiles)
|
||||
.map(file => {
|
||||
const { fsPath } = lambdaFiles[file];
|
||||
|
||||
if (!fsPath) {
|
||||
throw new Error(
|
||||
`File "${file}" is missing valid \`fsPath\` property`
|
||||
);
|
||||
}
|
||||
|
||||
// The handler was already moved into position above.
|
||||
if (file === handlerFileBase) {
|
||||
return;
|
||||
}
|
||||
|
||||
return normalizePath(relative(dirname(nft), fsPath));
|
||||
})
|
||||
.filter(Boolean),
|
||||
});
|
||||
|
||||
await fs.writeFile(nft, json);
|
||||
|
||||
// Add an entry that will later on be added to the `functions-manifest.json`
|
||||
// file that is placed inside of the `.output` directory.
|
||||
pages[normalizePath(entryPath)] = {
|
||||
// Because the underlying file used as a handler was placed
|
||||
// inside `.output/server/pages/api`, it no longer has the name it originally
|
||||
// had and is now named after the API Route that it's responsible for,
|
||||
// so we have to adjust the name of the Lambda handler accordingly.
|
||||
handler: handler.replace(handlerFileName, parse(entry).name),
|
||||
runtime: output.runtime,
|
||||
memory: output.memory,
|
||||
maxDuration: output.maxDuration,
|
||||
environment: output.environment,
|
||||
allowQuery: output.allowQuery,
|
||||
//regions: output.regions,
|
||||
};
|
||||
|
||||
// @ts-ignore This symbol is a private API
|
||||
const lambdaFiles: Files = output[FILES_SYMBOL];
|
||||
|
||||
const entry = join(workPath, '.output', 'server', 'pages', entrypoint);
|
||||
await fs.ensureDir(dirname(entry));
|
||||
await linkOrCopy(files[entrypoint].fsPath, entry);
|
||||
|
||||
const tracedFiles: {
|
||||
absolutePath: string;
|
||||
relativePath: string;
|
||||
}[] = [];
|
||||
|
||||
Object.entries(lambdaFiles).forEach(async ([relPath, file]) => {
|
||||
const newPath = join(traceDir, relPath);
|
||||
tracedFiles.push({ absolutePath: newPath, relativePath: relPath });
|
||||
if (file.fsPath) {
|
||||
await linkOrCopy(file.fsPath, newPath);
|
||||
} else if (file.type === 'FileBlob') {
|
||||
const { data, mode } = file as FileBlob;
|
||||
await fs.writeFile(newPath, data, { mode });
|
||||
} else {
|
||||
throw new Error(`Unknown file type: ${file.type}`);
|
||||
}
|
||||
});
|
||||
|
||||
const nft = join(
|
||||
workPath,
|
||||
'.output',
|
||||
'server',
|
||||
'pages',
|
||||
`${entrypoint}.nft.json`
|
||||
);
|
||||
const json = JSON.stringify({
|
||||
version: 1,
|
||||
files: tracedFiles.map(f => ({
|
||||
input: normalizePath(relative(nft, f.absolutePath)),
|
||||
output: normalizePath(f.relativePath),
|
||||
})),
|
||||
});
|
||||
|
||||
await fs.ensureDir(dirname(nft));
|
||||
await fs.writeFile(nft, json);
|
||||
}
|
||||
|
||||
await updateFunctionsManifest({ vercelConfig, workPath, pages });
|
||||
// Add any Serverless Functions that were exposed by the Legacy Runtime
|
||||
// to the `functions-manifest.json` file provided in `.output`.
|
||||
await _experimental_updateFunctionsManifest({ workPath, pages });
|
||||
};
|
||||
}
|
||||
|
||||
async function linkOrCopy(existingPath: string, newPath: string) {
|
||||
try {
|
||||
await fs.createLink(existingPath, newPath);
|
||||
} catch (err: any) {
|
||||
if (err.code !== 'EEXIST') {
|
||||
await fs.copyFile(existingPath, newPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function readJson(filePath: string): Promise<{ [key: string]: any }> {
|
||||
try {
|
||||
const str = await fs.readFile(filePath, 'utf8');
|
||||
@@ -136,15 +305,12 @@ async function readJson(filePath: string): Promise<{ [key: string]: any }> {
|
||||
|
||||
/**
|
||||
* If `.output/functions-manifest.json` exists, append to the pages
|
||||
* property. Otherwise write a new file. This will also read `vercel.json`
|
||||
* and apply relevant `functions` property config.
|
||||
* property. Otherwise write a new file.
|
||||
*/
|
||||
export async function updateFunctionsManifest({
|
||||
vercelConfig,
|
||||
export async function _experimental_updateFunctionsManifest({
|
||||
workPath,
|
||||
pages,
|
||||
}: {
|
||||
vercelConfig: { functions?: BuilderFunctions; regions?: string[] };
|
||||
workPath: string;
|
||||
pages: { [key: string]: any };
|
||||
}) {
|
||||
@@ -155,20 +321,11 @@ export async function updateFunctionsManifest({
|
||||
);
|
||||
const functionsManifest = await readJson(functionsManifestPath);
|
||||
|
||||
if (!functionsManifest.version) functionsManifest.version = 1;
|
||||
if (!functionsManifest.version) functionsManifest.version = 2;
|
||||
if (!functionsManifest.pages) functionsManifest.pages = {};
|
||||
|
||||
for (const [pageKey, pageConfig] of Object.entries(pages)) {
|
||||
const fnConfig = await getLambdaOptionsFromFunction({
|
||||
sourceFile: pageKey,
|
||||
config: vercelConfig,
|
||||
});
|
||||
functionsManifest.pages[pageKey] = {
|
||||
...pageConfig,
|
||||
memory: fnConfig.memory || pageConfig.memory,
|
||||
maxDuration: fnConfig.maxDuration || pageConfig.maxDuration,
|
||||
regions: vercelConfig.regions || pageConfig.regions,
|
||||
};
|
||||
functionsManifest.pages[pageKey] = { ...pageConfig };
|
||||
}
|
||||
|
||||
await fs.writeFile(functionsManifestPath, JSON.stringify(functionsManifest));
|
||||
@@ -178,7 +335,7 @@ export async function updateFunctionsManifest({
|
||||
* Append routes to the `routes-manifest.json` file.
|
||||
* If the file does not exist, it will be created.
|
||||
*/
|
||||
export async function updateRoutesManifest({
|
||||
export async function _experimental_updateRoutesManifest({
|
||||
workPath,
|
||||
redirects,
|
||||
rewrites,
|
||||
|
||||
@@ -3,7 +3,13 @@ import { valid as validSemver } from 'semver';
|
||||
import { parse as parsePath, extname } from 'path';
|
||||
import { Route, Source } from '@vercel/routing-utils';
|
||||
import frameworkList, { Framework } from '@vercel/frameworks';
|
||||
import { PackageJson, Builder, Config, BuilderFunctions } from './types';
|
||||
import {
|
||||
PackageJson,
|
||||
Builder,
|
||||
Config,
|
||||
BuilderFunctions,
|
||||
ProjectSettings,
|
||||
} from './types';
|
||||
import { isOfficialRuntime } from './';
|
||||
const slugToFramework = new Map<string | null, Framework>(
|
||||
frameworkList.map(f => [f.slug, f])
|
||||
@@ -20,14 +26,7 @@ interface Options {
|
||||
tag?: 'canary' | 'latest' | string;
|
||||
functions?: BuilderFunctions;
|
||||
ignoreBuildScript?: boolean;
|
||||
projectSettings?: {
|
||||
framework?: string | null;
|
||||
devCommand?: string | null;
|
||||
installCommand?: string | null;
|
||||
buildCommand?: string | null;
|
||||
outputDirectory?: string | null;
|
||||
createdAt?: number;
|
||||
};
|
||||
projectSettings?: ProjectSettings;
|
||||
cleanUrls?: boolean;
|
||||
trailingSlash?: boolean;
|
||||
featHandleMiss?: boolean;
|
||||
|
||||
237
packages/build-utils/src/detect-file-system-api.ts
Normal file
237
packages/build-utils/src/detect-file-system-api.ts
Normal file
@@ -0,0 +1,237 @@
|
||||
import semver from 'semver';
|
||||
import { isOfficialRuntime } from './';
|
||||
import type {
|
||||
Builder,
|
||||
BuilderFunctions,
|
||||
PackageJson,
|
||||
ProjectSettings,
|
||||
} from './types';
|
||||
|
||||
interface Metadata {
|
||||
plugins: string[];
|
||||
hasDotOutput: boolean;
|
||||
hasMiddleware: boolean;
|
||||
}
|
||||
|
||||
const enableFileSystemApiFrameworks = new Set(['solidstart']);
|
||||
|
||||
/**
|
||||
* If the Deployment can be built with the new File System API,
|
||||
* return the new Builder. Otherwise an "Exclusion Condition"
|
||||
* was hit so return `null` builder with a `reason` for exclusion.
|
||||
*/
|
||||
export async function detectFileSystemAPI({
|
||||
files,
|
||||
projectSettings,
|
||||
builders,
|
||||
vercelConfig,
|
||||
pkg,
|
||||
tag,
|
||||
enableFlag = false,
|
||||
}: {
|
||||
files: { [relPath: string]: any };
|
||||
projectSettings: ProjectSettings;
|
||||
builders: Builder[];
|
||||
vercelConfig:
|
||||
| { builds?: Builder[]; functions?: BuilderFunctions }
|
||||
| null
|
||||
| undefined;
|
||||
pkg: PackageJson | null | undefined;
|
||||
tag: string | undefined;
|
||||
enableFlag: boolean | undefined;
|
||||
}): Promise<
|
||||
| { metadata: Metadata; fsApiBuilder: Builder; reason: null }
|
||||
| { metadata: Metadata; fsApiBuilder: null; reason: string }
|
||||
> {
|
||||
const framework = projectSettings.framework || '';
|
||||
const deps = Object.assign({}, pkg?.dependencies, pkg?.devDependencies);
|
||||
const plugins = Object.keys(deps).filter(dep =>
|
||||
dep.startsWith('vercel-plugin-')
|
||||
);
|
||||
const hasDotOutput = Object.keys(files).some(file =>
|
||||
file.startsWith('.output/')
|
||||
);
|
||||
const hasMiddleware = Boolean(
|
||||
files['_middleware.js'] || files['_middleware.ts']
|
||||
);
|
||||
|
||||
const metadata: Metadata = {
|
||||
plugins,
|
||||
hasDotOutput,
|
||||
hasMiddleware,
|
||||
};
|
||||
|
||||
const isEnabled =
|
||||
enableFlag ||
|
||||
hasMiddleware ||
|
||||
hasDotOutput ||
|
||||
enableFileSystemApiFrameworks.has(framework);
|
||||
if (!isEnabled) {
|
||||
return { metadata, fsApiBuilder: null, reason: 'Flag not enabled.' };
|
||||
}
|
||||
|
||||
if (vercelConfig?.builds && vercelConfig.builds.length > 0) {
|
||||
return {
|
||||
metadata,
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected `builds` in vercel.json. Please remove it in favor of CLI plugins.',
|
||||
};
|
||||
}
|
||||
|
||||
if (Object.values(vercelConfig?.functions || {}).some(fn => !!fn.runtime)) {
|
||||
return {
|
||||
metadata,
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected `functions.runtime` in vercel.json. Please remove it in favor of CLI plugins.',
|
||||
};
|
||||
}
|
||||
|
||||
if (process.env.HUGO_VERSION) {
|
||||
return {
|
||||
metadata,
|
||||
fsApiBuilder: null,
|
||||
reason: 'Detected `HUGO_VERSION` environment variable. Please remove it.',
|
||||
};
|
||||
}
|
||||
|
||||
if (process.env.ZOLA_VERSION) {
|
||||
return {
|
||||
metadata,
|
||||
fsApiBuilder: null,
|
||||
reason: 'Detected `ZOLA_VERSION` environment variable. Please remove it.',
|
||||
};
|
||||
}
|
||||
|
||||
if (process.env.GUTENBERG_VERSION) {
|
||||
return {
|
||||
metadata,
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected `GUTENBERG_VERSION` environment variable. Please remove it.',
|
||||
};
|
||||
}
|
||||
|
||||
const invalidBuilder = builders.find(({ use }) => {
|
||||
const valid =
|
||||
isOfficialRuntime('go', use) ||
|
||||
isOfficialRuntime('python', use) ||
|
||||
isOfficialRuntime('ruby', use) ||
|
||||
isOfficialRuntime('node', use) ||
|
||||
isOfficialRuntime('next', use) ||
|
||||
isOfficialRuntime('static', use) ||
|
||||
isOfficialRuntime('static-build', use);
|
||||
return !valid;
|
||||
});
|
||||
|
||||
if (invalidBuilder) {
|
||||
return {
|
||||
metadata,
|
||||
fsApiBuilder: null,
|
||||
reason: `Detected \`${invalidBuilder.use}\` in vercel.json. Please remove it in favor of CLI plugins.`,
|
||||
};
|
||||
}
|
||||
|
||||
for (const lang of ['go', 'python', 'ruby']) {
|
||||
for (const { use } of builders) {
|
||||
const plugin = 'vercel-plugin-' + lang;
|
||||
if (isOfficialRuntime(lang, use) && !deps[plugin]) {
|
||||
return {
|
||||
metadata,
|
||||
fsApiBuilder: null,
|
||||
reason: `Detected \`${lang}\` Serverless Function usage without plugin \`${plugin}\`. Please run \`npm i ${plugin}\`.`,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
framework === 'nuxtjs' ||
|
||||
framework === 'sveltekit' ||
|
||||
framework === 'redwoodjs'
|
||||
) {
|
||||
return {
|
||||
metadata,
|
||||
fsApiBuilder: null,
|
||||
reason: `Detected framework \`${framework}\` that only supports legacy File System API. Please contact the framework author.`,
|
||||
};
|
||||
}
|
||||
|
||||
if (framework === 'nextjs' && !hasDotOutput) {
|
||||
// Use the old pipeline if a custom output directory was specified for Next.js
|
||||
// because `vercel build` cannot ensure that the directory will be in the same
|
||||
// location as `.output`, which can break imports (not just nft.json files).
|
||||
if (projectSettings?.outputDirectory) {
|
||||
return {
|
||||
metadata,
|
||||
fsApiBuilder: null,
|
||||
reason: `Detected Next.js with Output Directory \`${projectSettings.outputDirectory}\` override. Please change it back to the default.`,
|
||||
};
|
||||
}
|
||||
const nextVersion = deps['next'];
|
||||
if (!nextVersion) {
|
||||
return {
|
||||
metadata,
|
||||
fsApiBuilder: null,
|
||||
reason: `Detected Next.js in Project Settings but missing \`next\` package.json dependencies. Please run \`npm i next\`.`,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Read version from lockfile instead of package.json
|
||||
if (nextVersion !== 'latest' && nextVersion !== 'canary') {
|
||||
const fixedVersion = semver.valid(semver.coerce(nextVersion) || '');
|
||||
|
||||
if (!fixedVersion || !semver.gte(fixedVersion, '12.0.0')) {
|
||||
return {
|
||||
metadata,
|
||||
fsApiBuilder: null,
|
||||
reason: `Detected legacy Next.js version "${nextVersion}" in package.json. Please run \`npm i next@latest\` to upgrade.`,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasDotOutput) {
|
||||
// TODO: Read version from lockfile instead of package.json
|
||||
const vercelCliVersion = deps['vercel'];
|
||||
if (
|
||||
vercelCliVersion &&
|
||||
vercelCliVersion !== 'latest' &&
|
||||
vercelCliVersion !== 'canary'
|
||||
) {
|
||||
const fixedVersion = semver.valid(semver.coerce(vercelCliVersion) || '');
|
||||
// TODO: we might want to use '24.0.0' once its released
|
||||
if (!fixedVersion || !semver.gte(fixedVersion, '23.1.3-canary.68')) {
|
||||
return {
|
||||
metadata,
|
||||
fsApiBuilder: null,
|
||||
reason: `Detected legacy Vercel CLI version "${vercelCliVersion}" in package.json. Please run \`npm i vercel@latest\` to upgrade.`,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const frontendBuilder = builders.find(
|
||||
({ use }) =>
|
||||
isOfficialRuntime('next', use) ||
|
||||
isOfficialRuntime('static', use) ||
|
||||
isOfficialRuntime('static-build', use)
|
||||
);
|
||||
const config = frontendBuilder?.config || {};
|
||||
const withTag = tag ? `@${tag}` : '';
|
||||
|
||||
const fsApiBuilder = {
|
||||
use: `@vercelruntimes/file-system-api${withTag}`,
|
||||
src: '**',
|
||||
config: {
|
||||
...config,
|
||||
fileSystemAPI: true,
|
||||
framework: config.framework || framework || null,
|
||||
projectSettings,
|
||||
hasMiddleware,
|
||||
hasDotOutput,
|
||||
},
|
||||
};
|
||||
return { metadata, fsApiBuilder, reason: null };
|
||||
}
|
||||
84
packages/build-utils/src/get-ignore-filter.ts
Normal file
84
packages/build-utils/src/get-ignore-filter.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import ignore from 'ignore';
|
||||
|
||||
interface CodedError extends Error {
|
||||
code: string;
|
||||
}
|
||||
|
||||
function isCodedError(error: unknown): error is CodedError {
|
||||
return (
|
||||
error !== null &&
|
||||
error !== undefined &&
|
||||
(error as CodedError).code !== undefined
|
||||
);
|
||||
}
|
||||
|
||||
function clearRelative(s: string) {
|
||||
return s.replace(/(\n|^)\.\//g, '$1');
|
||||
}
|
||||
|
||||
export default async function (
|
||||
downloadPath: string,
|
||||
rootDirectory?: string | undefined
|
||||
) {
|
||||
const readFile = async (p: string) => {
|
||||
try {
|
||||
return await fs.readFile(p, 'utf8');
|
||||
} catch (error: any) {
|
||||
if (
|
||||
error.code === 'ENOENT' ||
|
||||
(error instanceof Error && error.message.includes('ENOENT'))
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const vercelIgnorePath = path.join(
|
||||
downloadPath,
|
||||
rootDirectory || '',
|
||||
'.vercelignore'
|
||||
);
|
||||
const nowIgnorePath = path.join(
|
||||
downloadPath,
|
||||
rootDirectory || '',
|
||||
'.nowignore'
|
||||
);
|
||||
const ignoreContents = [];
|
||||
|
||||
try {
|
||||
ignoreContents.push(
|
||||
...(
|
||||
await Promise.all([readFile(vercelIgnorePath), readFile(nowIgnorePath)])
|
||||
).filter(Boolean)
|
||||
);
|
||||
} catch (error) {
|
||||
if (isCodedError(error) && error.code === 'ENOTDIR') {
|
||||
console.log(`Warning: Cannot read ignore file from ${vercelIgnorePath}`);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (ignoreContents.length === 2) {
|
||||
throw new Error(
|
||||
'Cannot use both a `.vercelignore` and `.nowignore` file. Please delete the `.nowignore` file.'
|
||||
);
|
||||
}
|
||||
|
||||
if (ignoreContents.length === 0) {
|
||||
return () => false;
|
||||
}
|
||||
|
||||
const ignoreFilter: any = ignore().add(clearRelative(ignoreContents[0]!));
|
||||
|
||||
return function (p: string) {
|
||||
// we should not ignore now.json and vercel.json if it asked to.
|
||||
// we depend on these files for building the app with sourceless
|
||||
if (p === 'now.json' || p === 'vercel.json') return false;
|
||||
return ignoreFilter.test(p).ignored;
|
||||
};
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import { NowBuildError } from './errors';
|
||||
import streamToBuffer from './fs/stream-to-buffer';
|
||||
import shouldServe from './should-serve';
|
||||
import debug from './debug';
|
||||
import getIgnoreFilter from './get-ignore-filter';
|
||||
|
||||
export {
|
||||
FileBlob,
|
||||
@@ -70,6 +71,7 @@ export {
|
||||
isSymbolicLink,
|
||||
getLambdaOptionsFromFunction,
|
||||
scanParentDirs,
|
||||
getIgnoreFilter,
|
||||
};
|
||||
|
||||
export {
|
||||
@@ -78,14 +80,15 @@ export {
|
||||
detectApiDirectory,
|
||||
detectApiExtensions,
|
||||
} from './detect-builders';
|
||||
export { detectFileSystemAPI } from './detect-file-system-api';
|
||||
export { detectFramework } from './detect-framework';
|
||||
export { DetectorFilesystem } from './detectors/filesystem';
|
||||
export { readConfigFile } from './fs/read-config-file';
|
||||
export { normalizePath } from './fs/normalize-path';
|
||||
export {
|
||||
convertRuntimeToPlugin,
|
||||
updateFunctionsManifest,
|
||||
updateRoutesManifest,
|
||||
_experimental_convertRuntimeToPlugin,
|
||||
_experimental_updateFunctionsManifest,
|
||||
_experimental_updateRoutesManifest,
|
||||
} from './convert-runtime-to-plugin';
|
||||
|
||||
export * from './schemas';
|
||||
|
||||
@@ -29,7 +29,9 @@ export interface Config {
|
||||
| number
|
||||
| { [key: string]: string }
|
||||
| BuilderFunctions
|
||||
| undefined;
|
||||
| ProjectSettings
|
||||
| undefined
|
||||
| null;
|
||||
maxLambdaSize?: string;
|
||||
includeFiles?: string | string[];
|
||||
excludeFiles?: string | string[];
|
||||
@@ -41,11 +43,12 @@ export interface Config {
|
||||
zeroConfig?: boolean;
|
||||
import?: { [key: string]: string };
|
||||
functions?: BuilderFunctions;
|
||||
projectSettings?: ProjectSettings;
|
||||
outputDirectory?: string;
|
||||
installCommand?: string;
|
||||
buildCommand?: string;
|
||||
devCommand?: string;
|
||||
framework?: string;
|
||||
framework?: string | null;
|
||||
nodeVersion?: string;
|
||||
}
|
||||
|
||||
@@ -58,6 +61,7 @@ export interface Meta {
|
||||
filesRemoved?: string[];
|
||||
env?: Env;
|
||||
buildEnv?: Env;
|
||||
avoidTopLevelInstall?: boolean;
|
||||
}
|
||||
|
||||
export interface AnalyzeOptions {
|
||||
@@ -350,3 +354,17 @@ export interface BuilderFunctions {
|
||||
excludeFiles?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ProjectSettings {
|
||||
framework?: string | null;
|
||||
devCommand?: string | null;
|
||||
installCommand?: string | null;
|
||||
buildCommand?: string | null;
|
||||
outputDirectory?: string | null;
|
||||
rootDirectory?: string | null;
|
||||
createdAt?: number;
|
||||
autoExposeSystemEnvs?: boolean;
|
||||
sourceFilesOutsideRootDirectory?: boolean;
|
||||
directoryListing?: boolean;
|
||||
gitForkProtection?: boolean;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { join } from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import { BuildOptions, createLambda } from '../src';
|
||||
import { convertRuntimeToPlugin } from '../src/convert-runtime-to-plugin';
|
||||
import { BuildOptions, createLambda, FileFsRef } from '../src';
|
||||
import { _experimental_convertRuntimeToPlugin } from '../src/convert-runtime-to-plugin';
|
||||
|
||||
async function fsToJson(dir: string, output: Record<string, any> = {}) {
|
||||
const files = await fs.readdir(dir);
|
||||
@@ -32,9 +32,13 @@ describe('convert-runtime-to-plugin', () => {
|
||||
});
|
||||
|
||||
it('should create correct fileystem for python', async () => {
|
||||
const ext = '.py';
|
||||
const workPath = pythonApiWorkpath;
|
||||
const handlerName = 'vc__handler__python';
|
||||
const handlerFileName = handlerName + ext;
|
||||
|
||||
const lambdaOptions = {
|
||||
handler: 'index.handler',
|
||||
handler: `${handlerName}.vc_handler`,
|
||||
runtime: 'python3.9',
|
||||
memory: 512,
|
||||
maxDuration: 5,
|
||||
@@ -42,6 +46,15 @@ describe('convert-runtime-to-plugin', () => {
|
||||
};
|
||||
|
||||
const buildRuntime = async (opts: BuildOptions) => {
|
||||
const handlerPath = join(workPath, handlerFileName);
|
||||
|
||||
// This is the usual time at which a Legacy Runtime writes its Lambda launcher.
|
||||
await fs.writeFile(handlerPath, '# handler');
|
||||
|
||||
opts.files[handlerFileName] = new FileFsRef({
|
||||
fsPath: handlerPath,
|
||||
});
|
||||
|
||||
const lambda = await createLambda({
|
||||
files: opts.files,
|
||||
...lambdaOptions,
|
||||
@@ -49,26 +62,28 @@ describe('convert-runtime-to-plugin', () => {
|
||||
return { output: lambda };
|
||||
};
|
||||
|
||||
const lambdaFiles = await fsToJson(workPath);
|
||||
const vercelConfig = JSON.parse(lambdaFiles['vercel.json']);
|
||||
delete lambdaFiles['vercel.json'];
|
||||
const build = await convertRuntimeToPlugin(buildRuntime, '.py');
|
||||
const packageName = 'vercel-plugin-python';
|
||||
const build = await _experimental_convertRuntimeToPlugin(
|
||||
buildRuntime,
|
||||
packageName,
|
||||
ext
|
||||
);
|
||||
|
||||
await build({ vercelConfig, workPath });
|
||||
await build({ workPath });
|
||||
|
||||
const output = await fsToJson(join(workPath, '.output'));
|
||||
|
||||
expect(output).toMatchObject({
|
||||
'functions-manifest.json': expect.stringContaining('{'),
|
||||
'runtime-traced-files': lambdaFiles,
|
||||
server: {
|
||||
pages: {
|
||||
api: {
|
||||
'index.py': expect.stringContaining('index'),
|
||||
'index.py': expect.stringContaining('handler'),
|
||||
'index.py.nft.json': expect.stringContaining('{'),
|
||||
users: {
|
||||
'get.py': expect.stringContaining('get'),
|
||||
'get.py': expect.stringContaining('handler'),
|
||||
'get.py.nft.json': expect.stringContaining('{'),
|
||||
'post.py': expect.stringContaining('post'),
|
||||
'post.py': expect.stringContaining('handler'),
|
||||
'post.py.nft.json': expect.stringContaining('{'),
|
||||
},
|
||||
},
|
||||
@@ -78,51 +93,30 @@ describe('convert-runtime-to-plugin', () => {
|
||||
|
||||
const funcManifest = JSON.parse(output['functions-manifest.json']);
|
||||
expect(funcManifest).toMatchObject({
|
||||
version: 1,
|
||||
version: 2,
|
||||
pages: {
|
||||
'api/index.py': lambdaOptions,
|
||||
'api/users/get.py': lambdaOptions,
|
||||
'api/users/post.py': { ...lambdaOptions, memory: 3008 },
|
||||
'api/index.py': { ...lambdaOptions, handler: 'index.vc_handler' },
|
||||
'api/users/get.py': { ...lambdaOptions, handler: 'get.vc_handler' },
|
||||
'api/users/post.py': {
|
||||
...lambdaOptions,
|
||||
handler: 'post.vc_handler',
|
||||
memory: 512,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const indexJson = JSON.parse(output.server.pages.api['index.py.nft.json']);
|
||||
expect(indexJson).toMatchObject({
|
||||
version: 1,
|
||||
version: 2,
|
||||
files: [
|
||||
{
|
||||
input: '../../../../runtime-traced-files/api/db/[id].py',
|
||||
output: 'api/db/[id].py',
|
||||
},
|
||||
{
|
||||
input: '../../../../runtime-traced-files/api/index.py',
|
||||
output: 'api/index.py',
|
||||
},
|
||||
{
|
||||
input:
|
||||
'../../../../runtime-traced-files/api/project/[aid]/[bid]/index.py',
|
||||
output: 'api/project/[aid]/[bid]/index.py',
|
||||
},
|
||||
{
|
||||
input: '../../../../runtime-traced-files/api/users/get.py',
|
||||
output: 'api/users/get.py',
|
||||
},
|
||||
{
|
||||
input: '../../../../runtime-traced-files/api/users/post.py',
|
||||
output: 'api/users/post.py',
|
||||
},
|
||||
{
|
||||
input: '../../../../runtime-traced-files/file.txt',
|
||||
output: 'file.txt',
|
||||
},
|
||||
{
|
||||
input: '../../../../runtime-traced-files/util/date.py',
|
||||
output: 'util/date.py',
|
||||
},
|
||||
{
|
||||
input: '../../../../runtime-traced-files/util/math.py',
|
||||
output: 'util/math.py',
|
||||
},
|
||||
'../../../../api/db/[id].py',
|
||||
'../../../../api/index.py',
|
||||
'../../../../api/project/[aid]/[bid]/index.py',
|
||||
'../../../../api/users/get.py',
|
||||
'../../../../api/users/post.py',
|
||||
'../../../../file.txt',
|
||||
'../../../../util/date.py',
|
||||
'../../../../util/math.py',
|
||||
],
|
||||
});
|
||||
|
||||
@@ -130,41 +124,16 @@ describe('convert-runtime-to-plugin', () => {
|
||||
output.server.pages.api.users['get.py.nft.json']
|
||||
);
|
||||
expect(getJson).toMatchObject({
|
||||
version: 1,
|
||||
version: 2,
|
||||
files: [
|
||||
{
|
||||
input: '../../../../../runtime-traced-files/api/db/[id].py',
|
||||
output: 'api/db/[id].py',
|
||||
},
|
||||
{
|
||||
input: '../../../../../runtime-traced-files/api/index.py',
|
||||
output: 'api/index.py',
|
||||
},
|
||||
{
|
||||
input:
|
||||
'../../../../../runtime-traced-files/api/project/[aid]/[bid]/index.py',
|
||||
output: 'api/project/[aid]/[bid]/index.py',
|
||||
},
|
||||
{
|
||||
input: '../../../../../runtime-traced-files/api/users/get.py',
|
||||
output: 'api/users/get.py',
|
||||
},
|
||||
{
|
||||
input: '../../../../../runtime-traced-files/api/users/post.py',
|
||||
output: 'api/users/post.py',
|
||||
},
|
||||
{
|
||||
input: '../../../../../runtime-traced-files/file.txt',
|
||||
output: 'file.txt',
|
||||
},
|
||||
{
|
||||
input: '../../../../../runtime-traced-files/util/date.py',
|
||||
output: 'util/date.py',
|
||||
},
|
||||
{
|
||||
input: '../../../../../runtime-traced-files/util/math.py',
|
||||
output: 'util/math.py',
|
||||
},
|
||||
'../../../../../api/db/[id].py',
|
||||
'../../../../../api/index.py',
|
||||
'../../../../../api/project/[aid]/[bid]/index.py',
|
||||
'../../../../../api/users/get.py',
|
||||
'../../../../../api/users/post.py',
|
||||
'../../../../../file.txt',
|
||||
'../../../../../util/date.py',
|
||||
'../../../../../util/math.py',
|
||||
],
|
||||
});
|
||||
|
||||
@@ -172,41 +141,16 @@ describe('convert-runtime-to-plugin', () => {
|
||||
output.server.pages.api.users['post.py.nft.json']
|
||||
);
|
||||
expect(postJson).toMatchObject({
|
||||
version: 1,
|
||||
version: 2,
|
||||
files: [
|
||||
{
|
||||
input: '../../../../../runtime-traced-files/api/db/[id].py',
|
||||
output: 'api/db/[id].py',
|
||||
},
|
||||
{
|
||||
input: '../../../../../runtime-traced-files/api/index.py',
|
||||
output: 'api/index.py',
|
||||
},
|
||||
{
|
||||
input:
|
||||
'../../../../../runtime-traced-files/api/project/[aid]/[bid]/index.py',
|
||||
output: 'api/project/[aid]/[bid]/index.py',
|
||||
},
|
||||
{
|
||||
input: '../../../../../runtime-traced-files/api/users/get.py',
|
||||
output: 'api/users/get.py',
|
||||
},
|
||||
{
|
||||
input: '../../../../../runtime-traced-files/api/users/post.py',
|
||||
output: 'api/users/post.py',
|
||||
},
|
||||
{
|
||||
input: '../../../../../runtime-traced-files/file.txt',
|
||||
output: 'file.txt',
|
||||
},
|
||||
{
|
||||
input: '../../../../../runtime-traced-files/util/date.py',
|
||||
output: 'util/date.py',
|
||||
},
|
||||
{
|
||||
input: '../../../../../runtime-traced-files/util/math.py',
|
||||
output: 'util/math.py',
|
||||
},
|
||||
'../../../../../api/db/[id].py',
|
||||
'../../../../../api/index.py',
|
||||
'../../../../../api/project/[aid]/[bid]/index.py',
|
||||
'../../../../../api/users/get.py',
|
||||
'../../../../../api/users/post.py',
|
||||
'../../../../../file.txt',
|
||||
'../../../../../util/date.py',
|
||||
'../../../../../util/math.py',
|
||||
],
|
||||
});
|
||||
|
||||
|
||||
445
packages/build-utils/test/unit.detect-file-system-api.test.ts
vendored
Normal file
445
packages/build-utils/test/unit.detect-file-system-api.test.ts
vendored
Normal file
@@ -0,0 +1,445 @@
|
||||
import { detectFileSystemAPI } from '../src/detect-file-system-api';
|
||||
|
||||
describe('Test `detectFileSystemAPI`', () => {
|
||||
it('should error when builds in vercel.json', async () => {
|
||||
const vercelConfig = {
|
||||
builds: [{ use: '@vercel/node', src: 'api/**/*.js' }],
|
||||
};
|
||||
const files = {
|
||||
'vercel.json': JSON.stringify(vercelConfig),
|
||||
'api/foo.js': 'console.log("foo")',
|
||||
};
|
||||
const result = await detectFileSystemAPI({
|
||||
files,
|
||||
projectSettings: {},
|
||||
builders: vercelConfig.builds,
|
||||
vercelConfig,
|
||||
pkg: null,
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected `builds` in vercel.json. Please remove it in favor of CLI plugins.',
|
||||
metadata: { hasDotOutput: false, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
});
|
||||
|
||||
it('should error when functions.runtimes in vercel.json', async () => {
|
||||
const vercelConfig = {
|
||||
functions: {
|
||||
'api/**/*.rs': {
|
||||
runtime: 'vercel-rust@latest',
|
||||
},
|
||||
},
|
||||
};
|
||||
const files = {
|
||||
'vercel.json': JSON.stringify(vercelConfig),
|
||||
'api/foo.rs': 'println!("foo")',
|
||||
};
|
||||
const result = await detectFileSystemAPI({
|
||||
files,
|
||||
projectSettings: {},
|
||||
builders: [],
|
||||
vercelConfig,
|
||||
pkg: null,
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected `functions.runtime` in vercel.json. Please remove it in favor of CLI plugins.',
|
||||
metadata: { hasDotOutput: false, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
});
|
||||
|
||||
it('should error when HUGO_VERSION env var used', async () => {
|
||||
process.env.HUGO_VERSION = 'v0.58.2';
|
||||
const files = { 'foo.html': '<h1>Foo</h1>' };
|
||||
const result = await detectFileSystemAPI({
|
||||
files,
|
||||
projectSettings: {},
|
||||
builders: [],
|
||||
vercelConfig: null,
|
||||
pkg: null,
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: null,
|
||||
reason: 'Detected `HUGO_VERSION` environment variable. Please remove it.',
|
||||
metadata: { hasDotOutput: false, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
delete process.env.HUGO_VERSION;
|
||||
});
|
||||
|
||||
it('should error when ZOLA_VERSION env var used', async () => {
|
||||
process.env.ZOLA_VERSION = 'v0.0.1';
|
||||
const files = { 'foo.html': '<h1>Foo</h1>' };
|
||||
const result = await detectFileSystemAPI({
|
||||
files,
|
||||
projectSettings: {},
|
||||
builders: [],
|
||||
vercelConfig: null,
|
||||
pkg: null,
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: null,
|
||||
reason: 'Detected `ZOLA_VERSION` environment variable. Please remove it.',
|
||||
metadata: { hasDotOutput: false, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
delete process.env.ZOLA_VERSION;
|
||||
});
|
||||
|
||||
it('should error when GUTENBERG_VERSION env var used', async () => {
|
||||
process.env.GUTENBERG_VERSION = 'v0.0.1';
|
||||
const files = { 'foo.html': '<h1>Foo</h1>' };
|
||||
const result = await detectFileSystemAPI({
|
||||
files,
|
||||
projectSettings: {},
|
||||
builders: [],
|
||||
vercelConfig: null,
|
||||
pkg: null,
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected `GUTENBERG_VERSION` environment variable. Please remove it.',
|
||||
metadata: { hasDotOutput: false, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
delete process.env.GUTENBERG_VERSION;
|
||||
});
|
||||
|
||||
it('should error when Go detected without corresponding plugin', async () => {
|
||||
const result = await detectFileSystemAPI({
|
||||
files: { 'api/foo.go': 'print("foo")' },
|
||||
projectSettings: {},
|
||||
builders: [{ use: '@vercel/go', src: 'api/**/*.go' }],
|
||||
vercelConfig: null,
|
||||
pkg: null,
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected `go` Serverless Function usage without plugin `vercel-plugin-go`. Please run `npm i vercel-plugin-go`.',
|
||||
metadata: { hasDotOutput: false, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
});
|
||||
|
||||
it('should error when Python detected without corresponding plugin', async () => {
|
||||
const result = await detectFileSystemAPI({
|
||||
files: { 'api/foo.py': 'print("foo")' },
|
||||
projectSettings: {},
|
||||
builders: [{ use: '@vercel/python', src: 'api/**/*.py' }],
|
||||
vercelConfig: null,
|
||||
pkg: null,
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected `python` Serverless Function usage without plugin `vercel-plugin-python`. Please run `npm i vercel-plugin-python`.',
|
||||
metadata: { hasDotOutput: false, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
});
|
||||
|
||||
it('should error when Ruby detected without corresponding plugin', async () => {
|
||||
const result = await detectFileSystemAPI({
|
||||
files: { 'api/foo.rb': 'print("foo")' },
|
||||
projectSettings: {},
|
||||
builders: [{ use: '@vercel/ruby', src: 'api/**/*.rb' }],
|
||||
vercelConfig: null,
|
||||
pkg: null,
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected `ruby` Serverless Function usage without plugin `vercel-plugin-ruby`. Please run `npm i vercel-plugin-ruby`.',
|
||||
metadata: { hasDotOutput: false, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
});
|
||||
|
||||
it('should succeed when Go detected with corresponding plugin', async () => {
|
||||
const result = await detectFileSystemAPI({
|
||||
files: { 'api/foo.go': 'print("foo")' },
|
||||
projectSettings: {},
|
||||
builders: [{ use: '@vercel/go', src: 'api/**/*.go' }],
|
||||
vercelConfig: null,
|
||||
pkg: { dependencies: { 'vercel-plugin-go': '^1.0.0' } },
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: {
|
||||
use: '@vercelruntimes/file-system-api',
|
||||
src: '**',
|
||||
config: {
|
||||
fileSystemAPI: true,
|
||||
framework: null,
|
||||
hasDotOutput: false,
|
||||
hasMiddleware: false,
|
||||
projectSettings: {},
|
||||
},
|
||||
},
|
||||
reason: null,
|
||||
metadata: {
|
||||
hasDotOutput: false,
|
||||
hasMiddleware: false,
|
||||
plugins: ['vercel-plugin-go'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should succeed when Python detected with corresponding plugin', async () => {
|
||||
const result = await detectFileSystemAPI({
|
||||
files: { 'api/foo.py': 'print("foo")' },
|
||||
projectSettings: {},
|
||||
builders: [{ use: '@vercel/python', src: 'api/**/*.py' }],
|
||||
vercelConfig: null,
|
||||
pkg: { dependencies: { 'vercel-plugin-python': '^1.0.0' } },
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: {
|
||||
use: '@vercelruntimes/file-system-api',
|
||||
src: '**',
|
||||
config: {
|
||||
fileSystemAPI: true,
|
||||
framework: null,
|
||||
hasDotOutput: false,
|
||||
hasMiddleware: false,
|
||||
projectSettings: {},
|
||||
},
|
||||
},
|
||||
reason: null,
|
||||
metadata: {
|
||||
hasDotOutput: false,
|
||||
hasMiddleware: false,
|
||||
plugins: ['vercel-plugin-python'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should succeed when Ruby detected with corresponding plugin', async () => {
|
||||
const result = await detectFileSystemAPI({
|
||||
files: { 'api/foo.rb': 'print("foo")' },
|
||||
projectSettings: {},
|
||||
builders: [{ use: '@vercel/ruby', src: 'api/**/*.rb' }],
|
||||
vercelConfig: null,
|
||||
pkg: { dependencies: { 'vercel-plugin-ruby': '^1.0.0' } },
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: {
|
||||
use: '@vercelruntimes/file-system-api',
|
||||
src: '**',
|
||||
config: {
|
||||
fileSystemAPI: true,
|
||||
framework: null,
|
||||
hasDotOutput: false,
|
||||
hasMiddleware: false,
|
||||
projectSettings: {},
|
||||
},
|
||||
},
|
||||
reason: null,
|
||||
metadata: {
|
||||
hasDotOutput: false,
|
||||
hasMiddleware: false,
|
||||
plugins: ['vercel-plugin-ruby'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should error when framework is nuxtjs', async () => {
|
||||
const result = await detectFileSystemAPI({
|
||||
files: { 'api/foo.js': 'console.log("foo")' },
|
||||
projectSettings: { framework: 'nuxtjs' },
|
||||
builders: [{ use: '@vercel/node', src: 'api/**/*.js' }],
|
||||
vercelConfig: null,
|
||||
pkg: null,
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected framework `nuxtjs` that only supports legacy File System API. Please contact the framework author.',
|
||||
metadata: { hasDotOutput: false, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
});
|
||||
|
||||
it('should error when framework is sveltekit', async () => {
|
||||
const result = await detectFileSystemAPI({
|
||||
files: { 'api/foo.js': 'console.log("foo")' },
|
||||
projectSettings: { framework: 'sveltekit' },
|
||||
builders: [{ use: '@vercel/node', src: 'api/**/*.js' }],
|
||||
vercelConfig: null,
|
||||
pkg: null,
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected framework `sveltekit` that only supports legacy File System API. Please contact the framework author.',
|
||||
metadata: { hasDotOutput: false, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
});
|
||||
|
||||
it('should error when framework is redwoodjs', async () => {
|
||||
const result = await detectFileSystemAPI({
|
||||
files: { 'api/foo.js': 'console.log("foo")' },
|
||||
projectSettings: { framework: 'redwoodjs' },
|
||||
builders: [{ use: '@vercel/node', src: 'api/**/*.js' }],
|
||||
vercelConfig: null,
|
||||
pkg: null,
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected framework `redwoodjs` that only supports legacy File System API. Please contact the framework author.',
|
||||
metadata: { hasDotOutput: false, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
});
|
||||
|
||||
it('should error when framework is nextjs and has output dir', async () => {
|
||||
const result = await detectFileSystemAPI({
|
||||
files: { 'pages/foo.js': 'console.log("foo")' },
|
||||
projectSettings: { framework: 'nextjs', outputDirectory: 'dist' },
|
||||
builders: [{ use: '@vercel/next', src: 'package.json' }],
|
||||
vercelConfig: null,
|
||||
pkg: { dependencies: { next: '^12.0.0' } },
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected Next.js with Output Directory `dist` override. Please change it back to the default.',
|
||||
metadata: { hasDotOutput: false, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
});
|
||||
|
||||
it('should error when framework is nextjs but missing from dependencies', async () => {
|
||||
const result = await detectFileSystemAPI({
|
||||
files: { 'pages/foo.js': 'console.log("foo")' },
|
||||
projectSettings: { framework: 'nextjs' },
|
||||
builders: [{ use: '@vercel/next', src: 'package.json' }],
|
||||
vercelConfig: null,
|
||||
pkg: { dependencies: { 'not-next': '^12.0.0' } },
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected Next.js in Project Settings but missing `next` package.json dependencies. Please run `npm i next`.',
|
||||
metadata: { hasDotOutput: false, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
});
|
||||
|
||||
it('should error when framework is nextjs but dependency is older version', async () => {
|
||||
const result = await detectFileSystemAPI({
|
||||
files: { 'pages/foo.js': 'console.log("foo")' },
|
||||
projectSettings: { framework: 'nextjs' },
|
||||
builders: [{ use: '@vercel/next', src: 'package.json' }],
|
||||
vercelConfig: null,
|
||||
pkg: { dependencies: { next: '^9.0.0' } },
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected legacy Next.js version "^9.0.0" in package.json. Please run `npm i next@latest` to upgrade.',
|
||||
metadata: { hasDotOutput: false, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
});
|
||||
|
||||
it('should error when vercel cli is older version', async () => {
|
||||
const result = await detectFileSystemAPI({
|
||||
files: { 'pages/foo.js': 'console.log("foo")' },
|
||||
projectSettings: { framework: 'nextjs' },
|
||||
builders: [{ use: '@vercel/next', src: 'package.json' }],
|
||||
vercelConfig: null,
|
||||
pkg: { dependencies: { next: '^12.1.0', vercel: '^23.1.1' } },
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: null,
|
||||
reason:
|
||||
'Detected legacy Vercel CLI version "^23.1.1" in package.json. Please run `npm i vercel@latest` to upgrade.',
|
||||
metadata: { hasDotOutput: false, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
});
|
||||
|
||||
it('should succeed when middleware detected', async () => {
|
||||
const result = await detectFileSystemAPI({
|
||||
files: { '_middleware.js': 'print("foo")' },
|
||||
projectSettings: {},
|
||||
builders: [{ use: '@vercel/static-build', src: 'package.json' }],
|
||||
vercelConfig: null,
|
||||
pkg: null,
|
||||
tag: '',
|
||||
enableFlag: false,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: {
|
||||
use: '@vercelruntimes/file-system-api',
|
||||
src: '**',
|
||||
config: {
|
||||
fileSystemAPI: true,
|
||||
framework: null,
|
||||
hasDotOutput: false,
|
||||
hasMiddleware: true,
|
||||
projectSettings: {},
|
||||
},
|
||||
},
|
||||
reason: null,
|
||||
metadata: { hasDotOutput: false, hasMiddleware: true, plugins: [] },
|
||||
});
|
||||
});
|
||||
|
||||
it('should succeed when .output detected', async () => {
|
||||
const result = await detectFileSystemAPI({
|
||||
files: { '.output/routes-manifest.json': '{}' },
|
||||
projectSettings: { framework: 'remix' },
|
||||
builders: [{ use: '@vercel/static-build', src: 'package.json' }],
|
||||
vercelConfig: null,
|
||||
pkg: null,
|
||||
tag: '',
|
||||
enableFlag: false,
|
||||
});
|
||||
expect(result).toEqual({
|
||||
fsApiBuilder: {
|
||||
use: '@vercelruntimes/file-system-api',
|
||||
src: '**',
|
||||
config: {
|
||||
fileSystemAPI: true,
|
||||
framework: 'remix',
|
||||
hasDotOutput: true,
|
||||
hasMiddleware: false,
|
||||
projectSettings: { framework: 'remix' },
|
||||
},
|
||||
},
|
||||
reason: null,
|
||||
metadata: { hasDotOutput: true, hasMiddleware: false, plugins: [] },
|
||||
});
|
||||
});
|
||||
});
|
||||
8
packages/build-utils/test/unit.test.ts
vendored
8
packages/build-utils/test/unit.test.ts
vendored
@@ -285,6 +285,14 @@ it('should support require by path for legacy builders', () => {
|
||||
it(
|
||||
'should have correct $PATH when running `runPackageJsonScript()` with yarn',
|
||||
async () => {
|
||||
if (process.platform === 'win32') {
|
||||
console.log('Skipping test on windows');
|
||||
return;
|
||||
}
|
||||
if (process.platform === 'darwin') {
|
||||
console.log('Skipping test on macOS');
|
||||
return;
|
||||
}
|
||||
const fixture = path.join(__dirname, 'fixtures', '19-yarn-v2');
|
||||
await runNpmInstall(fixture);
|
||||
await runPackageJsonScript(fixture, 'env');
|
||||
|
||||
@@ -34,7 +34,7 @@ Finally, [connect your Git repository to Vercel](https://vercel.com/docs/git) an
|
||||
|
||||
## Documentation
|
||||
|
||||
For details on how to use Vercel CLI, check out our [documentation](https://vercel.com/docs).
|
||||
For details on how to use Vercel CLI, check out our [documentation](https://vercel.com/docs/cli).
|
||||
|
||||
## Local Development
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel",
|
||||
"version": "23.1.3-canary.43",
|
||||
"version": "23.1.3-canary.72",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Vercel",
|
||||
@@ -43,14 +43,14 @@
|
||||
"node": ">= 12"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.12.3-canary.25",
|
||||
"@vercel/build-utils": "2.13.0",
|
||||
"@vercel/go": "1.2.4-canary.4",
|
||||
"@vercel/node": "1.12.2-canary.7",
|
||||
"@vercel/python": "2.1.2-canary.0",
|
||||
"@vercel/ruby": "1.2.8-canary.4",
|
||||
"@vercel/python": "2.1.2-canary.2",
|
||||
"@vercel/ruby": "1.2.10-canary.0",
|
||||
"update-notifier": "4.1.0",
|
||||
"vercel-plugin-middleware": "0.0.0-canary.7",
|
||||
"vercel-plugin-node": "1.12.2-canary.16"
|
||||
"vercel-plugin-middleware": "0.0.0-canary.24",
|
||||
"vercel-plugin-node": "1.12.2-canary.39"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/env": "11.1.2",
|
||||
@@ -90,7 +90,8 @@
|
||||
"@types/update-notifier": "5.1.0",
|
||||
"@types/which": "1.3.2",
|
||||
"@types/write-json-file": "2.2.1",
|
||||
"@vercel/frameworks": "0.5.1-canary.15",
|
||||
"@vercel/client": "10.2.3-canary.50",
|
||||
"@vercel/frameworks": "0.5.1-canary.19",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@vercel/nft": "0.17.0",
|
||||
"@zeit/fun": "0.11.2",
|
||||
|
||||
@@ -5,20 +5,24 @@ import {
|
||||
GlobOptions,
|
||||
scanParentDirs,
|
||||
spawnAsync,
|
||||
glob as buildUtilsGlob,
|
||||
detectFileSystemAPI,
|
||||
detectBuilders,
|
||||
PackageJson,
|
||||
} from '@vercel/build-utils';
|
||||
import { nodeFileTrace } from '@vercel/nft';
|
||||
import Sema from 'async-sema';
|
||||
import chalk from 'chalk';
|
||||
import { SpawnOptions } from 'child_process';
|
||||
import { assert } from 'console';
|
||||
import { createHash } from 'crypto';
|
||||
import fs from 'fs-extra';
|
||||
import ogGlob from 'glob';
|
||||
import { dirname, isAbsolute, join, parse, relative, resolve } from 'path';
|
||||
import { dirname, isAbsolute, join, parse, relative } from 'path';
|
||||
import pluralize from 'pluralize';
|
||||
import Client from '../util/client';
|
||||
import { VercelConfig } from '../util/dev/types';
|
||||
import { emoji, prependEmoji } from '../util/emoji';
|
||||
import { CantParseJSONFile } from '../util/errors-ts';
|
||||
import getArgs from '../util/get-args';
|
||||
import handleError from '../util/handle-error';
|
||||
import confirm from '../util/input/confirm';
|
||||
@@ -32,6 +36,7 @@ import { loadCliPlugins } from '../util/plugins';
|
||||
import { findFramework } from '../util/projects/find-framework';
|
||||
import { VERCEL_DIR } from '../util/projects/link';
|
||||
import { readProjectSettings } from '../util/projects/project-settings';
|
||||
import readJSONFile from '../util/read-json-file';
|
||||
import pull from './pull';
|
||||
|
||||
const sema = new Sema(16, {
|
||||
@@ -146,6 +151,36 @@ export default async function main(client: Client) {
|
||||
|
||||
process.chdir(cwd);
|
||||
|
||||
const pkg = await readJSONFile<PackageJson>('./package.json');
|
||||
if (pkg instanceof CantParseJSONFile) {
|
||||
throw pkg;
|
||||
}
|
||||
const vercelConfig = await readJSONFile<VercelConfig>('./vercel.json');
|
||||
if (vercelConfig instanceof CantParseJSONFile) {
|
||||
throw vercelConfig;
|
||||
}
|
||||
|
||||
if (!process.env.NOW_BUILDER) {
|
||||
// This validation is only necessary when
|
||||
// a user runs `vercel build` locally.
|
||||
const globFiles = await buildUtilsGlob('**', { cwd });
|
||||
const zeroConfig = await detectBuilders(Object.keys(globFiles), pkg);
|
||||
const { reason } = await detectFileSystemAPI({
|
||||
files: globFiles,
|
||||
projectSettings: project.settings,
|
||||
builders: zeroConfig.builders || [],
|
||||
pkg,
|
||||
vercelConfig,
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
|
||||
if (reason) {
|
||||
client.output.error(`${cmd(`${getPkgName()} build`)} failed: ${reason}`);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
const framework = findFramework(project.settings.framework);
|
||||
// If this is undefined, we bail. If it is null, then findFramework should return "Other",
|
||||
// so this should really never happen, but just in case....
|
||||
@@ -298,6 +333,9 @@ export default async function main(client: Client) {
|
||||
}
|
||||
}
|
||||
|
||||
// Required for Next.js to produce the correct `.nft.json` files.
|
||||
spawnOpts.env.NEXT_PRIVATE_OUTPUT_TRACE_ROOT = baseDir;
|
||||
|
||||
// Yarn v2 PnP mode may be activated, so force
|
||||
// "node-modules" linker style
|
||||
const env = {
|
||||
@@ -350,13 +388,19 @@ export default async function main(client: Client) {
|
||||
}
|
||||
|
||||
// We cannot rely on the `framework` alone, as it might be a static export,
|
||||
// and the current build might use a differnt project that's not in the settings.
|
||||
// and the current build might use a different project that's not in the settings.
|
||||
const isNextOutput = Boolean(dotNextDir);
|
||||
const outputDir = isNextOutput ? OUTPUT_DIR : join(OUTPUT_DIR, 'static');
|
||||
const nextExport = await getNextExportStatus(dotNextDir);
|
||||
const outputDir =
|
||||
isNextOutput && !nextExport ? OUTPUT_DIR : join(OUTPUT_DIR, 'static');
|
||||
const getDistDir = framework.getFsOutputDir || framework.getOutputDirName;
|
||||
const distDir =
|
||||
(nextExport?.exportDetail.outDirectory
|
||||
? relative(cwd, nextExport.exportDetail.outDirectory)
|
||||
: false) ||
|
||||
dotNextDir ||
|
||||
userOutputDirectory ||
|
||||
(await framework.getFsOutputDir(cwd));
|
||||
(await getDistDir(cwd));
|
||||
|
||||
await fs.ensureDir(join(cwd, outputDir));
|
||||
|
||||
@@ -440,7 +484,53 @@ export default async function main(client: Client) {
|
||||
}
|
||||
|
||||
// Special Next.js processing.
|
||||
if (isNextOutput) {
|
||||
if (nextExport) {
|
||||
client.output.debug('Found `next export` output.');
|
||||
|
||||
const htmlFiles = await buildUtilsGlob(
|
||||
'**/*.html',
|
||||
join(cwd, OUTPUT_DIR, 'static')
|
||||
);
|
||||
|
||||
if (nextExport.exportDetail.success !== true) {
|
||||
client.output.error(
|
||||
`Export of Next.js app failed. Please check your build logs.`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await fs.mkdirp(join(cwd, OUTPUT_DIR, 'server', 'pages'));
|
||||
await fs.mkdirp(join(cwd, OUTPUT_DIR, 'static'));
|
||||
|
||||
await Promise.all(
|
||||
Object.keys(htmlFiles).map(async fileName => {
|
||||
await sema.acquire();
|
||||
|
||||
const input = join(cwd, OUTPUT_DIR, 'static', fileName);
|
||||
const target = join(cwd, OUTPUT_DIR, 'server', 'pages', fileName);
|
||||
|
||||
await fs.mkdirp(dirname(target));
|
||||
|
||||
await fs.promises.rename(input, target).finally(() => {
|
||||
sema.release();
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
for (const file of [
|
||||
'BUILD_ID',
|
||||
'images-manifest.json',
|
||||
'routes-manifest.json',
|
||||
'build-manifest.json',
|
||||
]) {
|
||||
const input = join(nextExport.dotNextDir, file);
|
||||
|
||||
if (fs.existsSync(input)) {
|
||||
// Do not use `smartCopy`, since we want to overwrite if they already exist.
|
||||
await fs.copyFile(input, join(OUTPUT_DIR, file));
|
||||
}
|
||||
}
|
||||
} else if (isNextOutput) {
|
||||
// The contents of `.output/static` should be placed inside of `.output/static/_next/static`
|
||||
const tempStatic = '___static';
|
||||
await fs.rename(
|
||||
@@ -581,58 +671,42 @@ export default async function main(client: Client) {
|
||||
],
|
||||
});
|
||||
fileList.delete(relative(cwd, f));
|
||||
await resolveNftToOutput({
|
||||
client,
|
||||
baseDir,
|
||||
outputDir: OUTPUT_DIR,
|
||||
nftFileName: f.replace(ext, '.js.nft.json'),
|
||||
distDir,
|
||||
nft: {
|
||||
version: 1,
|
||||
files: Array.from(fileList).map(fileListEntry =>
|
||||
relative(dir, fileListEntry)
|
||||
),
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
for (let f of nftFiles) {
|
||||
const json = await fs.readJson(f);
|
||||
await resolveNftToOutput({
|
||||
client,
|
||||
baseDir,
|
||||
outputDir: OUTPUT_DIR,
|
||||
nftFileName: f,
|
||||
nft: json,
|
||||
distDir,
|
||||
|
||||
const nftFileName = f.replace(ext, '.js.nft.json');
|
||||
client.output.debug(`Creating ${nftFileName}`);
|
||||
|
||||
await fs.writeJSON(nftFileName, {
|
||||
version: 2,
|
||||
files: Array.from(fileList).map(fileListEntry =>
|
||||
relative(dir, fileListEntry)
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
client.output.debug(`Resolve ${param('required-server-files.json')}.`);
|
||||
const requiredServerFilesPath = join(
|
||||
OUTPUT_DIR,
|
||||
'required-server-files.json'
|
||||
);
|
||||
const requiredServerFilesJson = await fs.readJSON(
|
||||
requiredServerFilesPath
|
||||
);
|
||||
await fs.writeJSON(requiredServerFilesPath, {
|
||||
...requiredServerFilesJson,
|
||||
appDir: '.',
|
||||
files: requiredServerFilesJson.files.map((i: string) => {
|
||||
const originalPath = join(dirname(distDir), i);
|
||||
const relPath = join(OUTPUT_DIR, relative(distDir, originalPath));
|
||||
|
||||
const absolutePath = join(cwd, relPath);
|
||||
const output = relative(baseDir, absolutePath);
|
||||
if (fs.existsSync(requiredServerFilesPath)) {
|
||||
client.output.debug(`Resolve ${param('required-server-files.json')}.`);
|
||||
|
||||
return {
|
||||
input: relPath,
|
||||
output,
|
||||
};
|
||||
}),
|
||||
});
|
||||
const requiredServerFilesJson = await fs.readJSON(
|
||||
requiredServerFilesPath
|
||||
);
|
||||
|
||||
await fs.writeJSON(requiredServerFilesPath, {
|
||||
...requiredServerFilesJson,
|
||||
appDir: '.',
|
||||
files: requiredServerFilesJson.files.map((i: string) => {
|
||||
const originalPath = join(requiredServerFilesJson.appDir, i);
|
||||
const relPath = join(OUTPUT_DIR, relative(distDir, originalPath));
|
||||
|
||||
return relPath;
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -787,83 +861,51 @@ async function glob(pattern: string, options: GlobOptions): Promise<string[]> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a hash for the given buf.
|
||||
*
|
||||
* @param {Buffer} file data
|
||||
* @return {String} hex digest
|
||||
* Files will only exist when `next export` was used.
|
||||
*/
|
||||
function hash(buf: Buffer): string {
|
||||
return createHash('sha1').update(buf).digest('hex');
|
||||
}
|
||||
|
||||
interface NftFile {
|
||||
version: number;
|
||||
files: (string | { input: string; output: string })[];
|
||||
}
|
||||
|
||||
// resolveNftToOutput takes nft file and moves all of its trace files
|
||||
// into the specified directory + `inputs`, (renaming them to their hash + ext) and
|
||||
// subsequently updating the original nft file accordingly. This is done
|
||||
// to make the `.output` directory be self-contained, so that it works
|
||||
// properly with `vc --prebuilt`.
|
||||
async function resolveNftToOutput({
|
||||
client,
|
||||
baseDir,
|
||||
outputDir,
|
||||
nftFileName,
|
||||
distDir,
|
||||
nft,
|
||||
}: {
|
||||
client: Client;
|
||||
baseDir: string;
|
||||
outputDir: string;
|
||||
nftFileName: string;
|
||||
distDir: string;
|
||||
nft: NftFile;
|
||||
}) {
|
||||
client.output.debug(`Processing and resolving ${nftFileName}`);
|
||||
await fs.ensureDir(join(outputDir, 'inputs'));
|
||||
const newFilesList: NftFile['files'] = [];
|
||||
|
||||
// If `distDir` is a subdirectory, then the input has to be resolved to where the `.output` directory will be.
|
||||
const relNftFileName = relative(outputDir, nftFileName);
|
||||
const origNftFilename = join(distDir, relNftFileName);
|
||||
|
||||
if (relNftFileName.startsWith('cache/')) {
|
||||
// No need to process the `cache/` directory.
|
||||
// Paths in it might also not be relative to `cache` itself.
|
||||
return;
|
||||
async function getNextExportStatus(dotNextDir: string | null) {
|
||||
if (!dotNextDir) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (let fileEntity of nft.files) {
|
||||
const relativeInput =
|
||||
typeof fileEntity === 'string' ? fileEntity : fileEntity.input;
|
||||
const fullInput = resolve(join(parse(origNftFilename).dir, relativeInput));
|
||||
const exportDetail: {
|
||||
success: boolean;
|
||||
outDirectory: string;
|
||||
} | null = await fs
|
||||
.readJson(join(dotNextDir, 'export-detail.json'))
|
||||
.catch(error => {
|
||||
if (error.code === 'ENOENT') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if the resolved path is NOT in the .output directory we move in it there
|
||||
if (!fullInput.includes(distDir)) {
|
||||
const { ext } = parse(fullInput);
|
||||
const raw = await fs.readFile(fullInput);
|
||||
const newFilePath = join(outputDir, 'inputs', hash(raw) + ext);
|
||||
smartCopy(client, fullInput, newFilePath);
|
||||
throw error;
|
||||
});
|
||||
|
||||
// We have to use `baseDir` instead of `cwd`, because we want to
|
||||
// mount everything from there (especially `node_modules`).
|
||||
// This is important for NPM Workspaces where `node_modules` is not
|
||||
// in the directory of the workspace.
|
||||
const output = relative(baseDir, fullInput).replace('.output', '.next');
|
||||
|
||||
newFilesList.push({
|
||||
input: relative(parse(nftFileName).dir, newFilePath),
|
||||
output,
|
||||
});
|
||||
} else {
|
||||
newFilesList.push(relativeInput);
|
||||
}
|
||||
if (!exportDetail) {
|
||||
return null;
|
||||
}
|
||||
// Update the .nft.json with new input and output mapping
|
||||
await fs.writeJSON(nftFileName, {
|
||||
...nft,
|
||||
files: newFilesList,
|
||||
});
|
||||
|
||||
const exportMarker: {
|
||||
version: 1;
|
||||
exportTrailingSlash: boolean;
|
||||
hasExportPathMap: boolean;
|
||||
} | null = await fs
|
||||
.readJSON(join(dotNextDir, 'export-marker.json'))
|
||||
.catch(error => {
|
||||
if (error.code === 'ENOENT') {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw error;
|
||||
});
|
||||
|
||||
return {
|
||||
dotNextDir,
|
||||
exportDetail,
|
||||
exportMarker: {
|
||||
trailingSlash: exportMarker?.hasExportPathMap
|
||||
? exportMarker.exportTrailingSlash
|
||||
: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -166,8 +166,8 @@ export default async (client: Client) => {
|
||||
return pathValidation.exitCode;
|
||||
}
|
||||
|
||||
const { isFile, path } = pathValidation;
|
||||
const autoConfirm = argv['--confirm'] || isFile;
|
||||
const { path } = pathValidation;
|
||||
const autoConfirm = argv['--confirm'];
|
||||
|
||||
// deprecate --name
|
||||
if (argv['--name']) {
|
||||
@@ -192,7 +192,7 @@ export default async (client: Client) => {
|
||||
|
||||
let newProjectName = null;
|
||||
let rootDirectory = project ? project.rootDirectory : null;
|
||||
let sourceFilesOutsideRootDirectory = true;
|
||||
let sourceFilesOutsideRootDirectory: boolean | undefined = true;
|
||||
|
||||
if (status === 'not_linked') {
|
||||
const shouldStartSetup =
|
||||
@@ -229,8 +229,7 @@ export default async (client: Client) => {
|
||||
// user input.
|
||||
const detectedProjectName = getProjectName({
|
||||
argv,
|
||||
nowConfig: localConfig || {},
|
||||
isFile,
|
||||
nowConfig: localConfig,
|
||||
paths,
|
||||
});
|
||||
|
||||
@@ -447,9 +446,9 @@ export default async (client: Client) => {
|
||||
forceNew: argv['--force'],
|
||||
withCache: argv['--with-cache'],
|
||||
prebuilt: argv['--prebuilt'],
|
||||
rootDirectory,
|
||||
quiet,
|
||||
wantsPublic: argv['--public'] || localConfig.public,
|
||||
isFile,
|
||||
type: null,
|
||||
nowConfig: localConfig,
|
||||
regions,
|
||||
@@ -471,7 +470,7 @@ export default async (client: Client) => {
|
||||
[sourcePath],
|
||||
createArgs,
|
||||
org,
|
||||
!project && !isFile,
|
||||
!project,
|
||||
path
|
||||
);
|
||||
|
||||
@@ -654,8 +653,7 @@ export default async (client: Client) => {
|
||||
client,
|
||||
deployment,
|
||||
deployStamp,
|
||||
!argv['--no-clipboard'],
|
||||
isFile
|
||||
!argv['--no-clipboard']
|
||||
);
|
||||
};
|
||||
|
||||
@@ -790,8 +788,7 @@ const printDeploymentStatus = async (
|
||||
};
|
||||
},
|
||||
deployStamp: () => string,
|
||||
isClipboardEnabled: boolean,
|
||||
isFile: boolean
|
||||
isClipboardEnabled: boolean
|
||||
) => {
|
||||
indications = indications || [];
|
||||
const isProdDeployment = target === 'production';
|
||||
@@ -813,7 +810,7 @@ const printDeploymentStatus = async (
|
||||
// print preview/production url
|
||||
let previewUrl: string;
|
||||
let isWildcard: boolean;
|
||||
if (!isFile && Array.isArray(aliasList) && aliasList.length > 0) {
|
||||
if (Array.isArray(aliasList) && aliasList.length > 0) {
|
||||
const previewUrlInfo = await getPreferredPreviewURL(client, aliasList);
|
||||
if (previewUrlInfo) {
|
||||
isWildcard = previewUrlInfo.isWildcard;
|
||||
|
||||
@@ -11,9 +11,10 @@ import logo from '../../util/output/logo';
|
||||
import cmd from '../../util/output/cmd';
|
||||
import highlight from '../../util/output/highlight';
|
||||
import dev from './dev';
|
||||
import readPackage from '../../util/read-package';
|
||||
import readConfig from '../../util/config/read-config';
|
||||
import readJSONFile from '../../util/read-json-file';
|
||||
import { getPkgName, getCommandName } from '../../util/pkg-name';
|
||||
import { CantParseJSONFile } from '../../util/errors-ts';
|
||||
|
||||
const COMMAND_CONFIG = {
|
||||
dev: ['dev'],
|
||||
@@ -96,33 +97,34 @@ export default async function main(client: Client) {
|
||||
|
||||
const [dir = '.'] = args;
|
||||
|
||||
const nowJson = await readConfig(dir);
|
||||
// @ts-ignore: Because `nowJson` could be one of three different types
|
||||
const hasBuilds = nowJson && nowJson.builds && nowJson.builds.length > 0;
|
||||
const vercelConfig = await readConfig(dir);
|
||||
|
||||
if (!nowJson || !hasBuilds) {
|
||||
const pkg = await readPackage(path.join(dir, 'package.json'));
|
||||
const hasBuilds =
|
||||
vercelConfig &&
|
||||
'builds' in vercelConfig &&
|
||||
vercelConfig.builds &&
|
||||
vercelConfig.builds.length > 0;
|
||||
|
||||
if (pkg) {
|
||||
const { scripts } = pkg as PackageJson;
|
||||
if (!vercelConfig || !hasBuilds) {
|
||||
const pkg = await readJSONFile<PackageJson>(path.join(dir, 'package.json'));
|
||||
|
||||
if (
|
||||
scripts &&
|
||||
scripts.dev &&
|
||||
/\b(now|vercel)\b\W+\bdev\b/.test(scripts.dev)
|
||||
) {
|
||||
client.output.error(
|
||||
`${cmd(
|
||||
`${getPkgName()} dev`
|
||||
)} must not recursively invoke itself. Check the Development Command in the Project Settings or the ${cmd(
|
||||
'dev'
|
||||
)} script in ${cmd('package.json')}`
|
||||
);
|
||||
client.output.error(
|
||||
`Learn More: https://vercel.link/recursive-invocation-of-commands`
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
if (pkg instanceof CantParseJSONFile) {
|
||||
client.output.error('Could not parse package.json');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (/\b(now|vercel)\b\W+\bdev\b/.test(pkg?.scripts?.dev || '')) {
|
||||
client.output.error(
|
||||
`${cmd(
|
||||
`${getPkgName()} dev`
|
||||
)} must not recursively invoke itself. Check the Development Command in the Project Settings or the ${cmd(
|
||||
'dev'
|
||||
)} script in ${cmd('package.json')}`
|
||||
);
|
||||
client.output.error(
|
||||
`Learn More: https://vercel.link/recursive-invocation-of-commands`
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export type ProjectSettings = import('@vercel/build-utils').ProjectSettings;
|
||||
|
||||
export type Primitive =
|
||||
| bigint
|
||||
| boolean
|
||||
@@ -239,16 +241,6 @@ export interface ProjectEnvVariable {
|
||||
gitBranch?: string;
|
||||
}
|
||||
|
||||
export interface ProjectSettings {
|
||||
framework?: string | null;
|
||||
devCommand?: string | null;
|
||||
buildCommand?: string | null;
|
||||
outputDirectory?: string | null;
|
||||
rootDirectory?: string | null;
|
||||
autoExposeSystemEnvs?: boolean;
|
||||
directoryListing?: boolean;
|
||||
}
|
||||
|
||||
export interface Project extends ProjectSettings {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -260,8 +252,6 @@ export interface Project extends ProjectSettings {
|
||||
framework?: string | null;
|
||||
rootDirectory?: string | null;
|
||||
latestDeployments?: Partial<Deployment>[];
|
||||
autoExposeSystemEnvs?: boolean;
|
||||
sourceFilesOutsideRootDirectory: boolean;
|
||||
}
|
||||
|
||||
export interface Org {
|
||||
|
||||
@@ -6,14 +6,14 @@ import getLocalConfigPath from './local-path';
|
||||
|
||||
export default async function readConfig(dir: string) {
|
||||
const pkgFilePath = getLocalConfigPath(join(process.cwd(), dir));
|
||||
const result = await readJSONFile(pkgFilePath);
|
||||
const result = await readJSONFile<VercelConfig>(pkgFilePath);
|
||||
|
||||
if (result instanceof CantParseJSONFile) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
return result as VercelConfig;
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -52,6 +52,7 @@ export default async function processDeployment({
|
||||
isSettingUpProject: boolean;
|
||||
skipAutoDetectionConfirmation?: boolean;
|
||||
cwd?: string;
|
||||
rootDirectory?: string;
|
||||
}) {
|
||||
let {
|
||||
now,
|
||||
@@ -64,6 +65,7 @@ export default async function processDeployment({
|
||||
nowConfig,
|
||||
quiet,
|
||||
prebuilt,
|
||||
rootDirectory,
|
||||
} = args;
|
||||
|
||||
const { debug } = output;
|
||||
@@ -86,6 +88,7 @@ export default async function processDeployment({
|
||||
force,
|
||||
withCache,
|
||||
prebuilt,
|
||||
rootDirectory,
|
||||
skipAutoDetectionConfirmation,
|
||||
};
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import {
|
||||
detectApiExtensions,
|
||||
spawnCommand,
|
||||
isOfficialRuntime,
|
||||
detectFileSystemAPI,
|
||||
} from '@vercel/build-utils';
|
||||
import frameworkList from '@vercel/frameworks';
|
||||
|
||||
@@ -599,6 +600,32 @@ export default class DevServer {
|
||||
);
|
||||
}
|
||||
|
||||
const { reason, metadata } = await detectFileSystemAPI({
|
||||
files,
|
||||
builders: builders || [],
|
||||
projectSettings: projectSettings || this.projectSettings || {},
|
||||
vercelConfig,
|
||||
pkg,
|
||||
tag: '',
|
||||
enableFlag: true,
|
||||
});
|
||||
|
||||
if (reason) {
|
||||
if (metadata.hasMiddleware) {
|
||||
this.output.error(
|
||||
`Detected middleware usage which requires the latest API. ${reason}`
|
||||
);
|
||||
await this.exit();
|
||||
} else if (metadata.plugins.length > 0) {
|
||||
this.output.error(
|
||||
`Detected CLI plugins which requires the latest API. ${reason}`
|
||||
);
|
||||
await this.exit();
|
||||
} else {
|
||||
this.output.warn(`Unable to use latest API. ${reason}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (builders) {
|
||||
if (this.devCommand) {
|
||||
builders = builders.filter(filterFrontendBuilds);
|
||||
@@ -968,7 +995,7 @@ export default class DevServer {
|
||||
socket.destroy();
|
||||
return;
|
||||
}
|
||||
const target = `http://localhost:${this.devProcessPort}`;
|
||||
const target = `http://127.0.0.1:${this.devProcessPort}`;
|
||||
this.output.debug(`Detected "upgrade" event, proxying to ${target}`);
|
||||
this.proxy.ws(req, socket, head, { target });
|
||||
});
|
||||
@@ -1663,7 +1690,7 @@ export default class DevServer {
|
||||
if (!match) {
|
||||
// If the dev command is started, then proxy to it
|
||||
if (this.devProcessPort) {
|
||||
const upstream = `http://localhost:${this.devProcessPort}`;
|
||||
const upstream = `http://127.0.0.1:${this.devProcessPort}`;
|
||||
debug(`Proxying to frontend dev server: ${upstream}`);
|
||||
|
||||
// Add the Vercel platform proxy request headers
|
||||
@@ -1810,7 +1837,7 @@ export default class DevServer {
|
||||
return proxyPass(
|
||||
req,
|
||||
res,
|
||||
`http://localhost:${port}`,
|
||||
`http://127.0.0.1:${port}`,
|
||||
this,
|
||||
requestId,
|
||||
false
|
||||
@@ -1847,7 +1874,7 @@ export default class DevServer {
|
||||
return proxyPass(
|
||||
req,
|
||||
res,
|
||||
`http://localhost:${this.devProcessPort}`,
|
||||
`http://127.0.0.1:${this.devProcessPort}`,
|
||||
this,
|
||||
requestId,
|
||||
false
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
} from './errors-ts';
|
||||
import humanizePath from './humanize-path';
|
||||
import readJSONFile from './read-json-file';
|
||||
import readPackage from './read-package';
|
||||
import { VercelConfig } from './dev/types';
|
||||
import { Output } from './output';
|
||||
|
||||
@@ -39,12 +38,12 @@ export default async function getConfig(
|
||||
output.debug(
|
||||
`Found config in provided --local-config path ${localFilePath}`
|
||||
);
|
||||
const localConfig = await readJSONFile(localFilePath);
|
||||
const localConfig = await readJSONFile<VercelConfig>(localFilePath);
|
||||
if (localConfig instanceof CantParseJSONFile) {
|
||||
return localConfig;
|
||||
}
|
||||
if (localConfig !== null) {
|
||||
config = localConfig as VercelConfig;
|
||||
config = localConfig;
|
||||
config[fileNameSymbol] = configFile;
|
||||
return config;
|
||||
}
|
||||
@@ -54,8 +53,8 @@ export default async function getConfig(
|
||||
const vercelFilePath = path.resolve(localPath, 'vercel.json');
|
||||
const nowFilePath = path.resolve(localPath, 'now.json');
|
||||
const [vercelConfig, nowConfig] = await Promise.all([
|
||||
readJSONFile(vercelFilePath),
|
||||
readJSONFile(nowFilePath),
|
||||
readJSONFile<VercelConfig>(vercelFilePath),
|
||||
readJSONFile<VercelConfig>(nowFilePath),
|
||||
]);
|
||||
if (vercelConfig instanceof CantParseJSONFile) {
|
||||
return vercelConfig;
|
||||
@@ -68,41 +67,17 @@ export default async function getConfig(
|
||||
}
|
||||
if (vercelConfig !== null) {
|
||||
output.debug(`Found config in file "${vercelFilePath}"`);
|
||||
config = vercelConfig as VercelConfig;
|
||||
config = vercelConfig;
|
||||
config[fileNameSymbol] = 'vercel.json';
|
||||
return config;
|
||||
}
|
||||
if (nowConfig !== null) {
|
||||
output.debug(`Found config in file "${nowFilePath}"`);
|
||||
config = nowConfig as VercelConfig;
|
||||
config = nowConfig;
|
||||
config[fileNameSymbol] = 'now.json';
|
||||
return config;
|
||||
}
|
||||
|
||||
// Finally try with the package
|
||||
const pkgFilePath = path.resolve(localPath, 'package.json');
|
||||
const pkgConfig = await readConfigFromPackage(pkgFilePath);
|
||||
if (pkgConfig instanceof CantParseJSONFile) {
|
||||
return pkgConfig;
|
||||
}
|
||||
if (pkgConfig) {
|
||||
output.debug(`Found config in package ${pkgFilePath}`);
|
||||
config = pkgConfig as VercelConfig;
|
||||
config[fileNameSymbol] = 'package.json';
|
||||
return config;
|
||||
}
|
||||
|
||||
// If we couldn't find the config anywhere return error
|
||||
return new CantFindConfig(
|
||||
[vercelFilePath, nowFilePath, pkgFilePath].map(humanizePath)
|
||||
);
|
||||
}
|
||||
|
||||
async function readConfigFromPackage(file: string) {
|
||||
const result = await readPackage(file);
|
||||
if (result instanceof CantParseJSONFile) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return result !== null ? result.now : null;
|
||||
return new CantFindConfig([vercelFilePath, nowFilePath].map(humanizePath));
|
||||
}
|
||||
|
||||
@@ -4,14 +4,12 @@ import { VercelConfig } from '@vercel/client';
|
||||
export interface GetProjectNameOptions {
|
||||
argv: { '--name'?: string };
|
||||
nowConfig?: VercelConfig;
|
||||
isFile?: boolean;
|
||||
paths?: string[];
|
||||
}
|
||||
|
||||
export default function getProjectName({
|
||||
argv,
|
||||
nowConfig = {},
|
||||
isFile = false,
|
||||
paths = [],
|
||||
}: GetProjectNameOptions) {
|
||||
const nameCli = argv['--name'];
|
||||
@@ -24,10 +22,6 @@ export default function getProjectName({
|
||||
return nowConfig.name;
|
||||
}
|
||||
|
||||
if (isFile || paths.length > 1) {
|
||||
return 'files';
|
||||
}
|
||||
|
||||
// Otherwise, use the name of the directory
|
||||
return basename(paths[0] || '');
|
||||
}
|
||||
|
||||
@@ -30,13 +30,13 @@ export interface NowOptions {
|
||||
export interface CreateOptions {
|
||||
// Legacy
|
||||
nowConfig?: VercelConfig;
|
||||
isFile?: boolean;
|
||||
|
||||
// Latest
|
||||
name: string;
|
||||
project?: string;
|
||||
wantsPublic: boolean;
|
||||
prebuilt?: boolean;
|
||||
rootDirectory?: string;
|
||||
meta: Dictionary<string>;
|
||||
regions?: string[];
|
||||
quiet?: boolean;
|
||||
@@ -113,6 +113,7 @@ export default class Now extends EventEmitter {
|
||||
name,
|
||||
project,
|
||||
prebuilt = false,
|
||||
rootDirectory,
|
||||
wantsPublic,
|
||||
meta,
|
||||
regions,
|
||||
@@ -168,6 +169,7 @@ export default class Now extends EventEmitter {
|
||||
skipAutoDetectionConfirmation,
|
||||
cwd,
|
||||
prebuilt,
|
||||
rootDirectory,
|
||||
});
|
||||
|
||||
if (deployment && deployment.warnings) {
|
||||
|
||||
@@ -11,7 +11,7 @@ export default async function inputProject(
|
||||
client: Client,
|
||||
org: Org,
|
||||
detectedProjectName: string,
|
||||
autoConfirm: boolean
|
||||
autoConfirm = false
|
||||
): Promise<Project | string> {
|
||||
const { output } = client;
|
||||
const slugifiedName = slugify(detectedProjectName);
|
||||
|
||||
@@ -7,7 +7,7 @@ import { validateRootDirectory } from '../validate-paths';
|
||||
export async function inputRootDirectory(
|
||||
cwd: string,
|
||||
output: Output,
|
||||
autoConfirm: boolean
|
||||
autoConfirm = false
|
||||
) {
|
||||
if (autoConfirm) {
|
||||
return null;
|
||||
|
||||
@@ -158,7 +158,6 @@ export default async function setupAndLink(
|
||||
withCache: undefined,
|
||||
quiet,
|
||||
wantsPublic: localConfig?.public || false,
|
||||
isFile,
|
||||
nowConfig: localConfig,
|
||||
regions: undefined,
|
||||
meta: {},
|
||||
@@ -179,7 +178,7 @@ export default async function setupAndLink(
|
||||
[sourcePath],
|
||||
createArgs,
|
||||
org,
|
||||
!isFile,
|
||||
true,
|
||||
path
|
||||
);
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import fs from 'fs-extra';
|
||||
import { CantParseJSONFile } from './errors-ts';
|
||||
|
||||
export default async function readJSONFile(
|
||||
export default async function readJSONFile<T>(
|
||||
file: string
|
||||
): Promise<Object | null | CantParseJSONFile> {
|
||||
): Promise<T | null | CantParseJSONFile> {
|
||||
const content = await readFileSafe(file);
|
||||
if (content === null) {
|
||||
return content;
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import path from 'path';
|
||||
import { CantParseJSONFile } from './errors-ts';
|
||||
import readJSONFile from './read-json-file';
|
||||
import { VercelConfig } from './dev/types';
|
||||
import { PackageJson } from '@vercel/build-utils';
|
||||
|
||||
interface CustomPackage extends PackageJson {
|
||||
now?: VercelConfig;
|
||||
}
|
||||
|
||||
export default async function readPackage(file?: string) {
|
||||
const pkgFilePath = file || path.resolve(process.cwd(), 'package.json');
|
||||
const result = await readJSONFile(pkgFilePath);
|
||||
|
||||
if (result instanceof CantParseJSONFile) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
return result as CustomPackage;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import { Output } from './output';
|
||||
import chalk from 'chalk';
|
||||
import { homedir } from 'os';
|
||||
import confirm from './input/confirm';
|
||||
import { prependEmoji, emoji } from './emoji';
|
||||
import toHumanPath from './humanize-path';
|
||||
|
||||
const stat = promisify(lstatRaw);
|
||||
@@ -54,10 +53,7 @@ export async function validateRootDirectory(
|
||||
export default async function validatePaths(
|
||||
output: Output,
|
||||
paths: string[]
|
||||
): Promise<
|
||||
| { valid: true; path: string; isFile: boolean }
|
||||
| { valid: false; exitCode: number }
|
||||
> {
|
||||
): Promise<{ valid: true; path: string } | { valid: false; exitCode: number }> {
|
||||
// can't deploy more than 1 path
|
||||
if (paths.length > 1) {
|
||||
output.print(`${chalk.red('Error!')} Can't deploy more than one path.\n`);
|
||||
@@ -78,14 +74,12 @@ export default async function validatePaths(
|
||||
return { valid: false, exitCode: 1 };
|
||||
}
|
||||
|
||||
const isFile = pathStat && !pathStat.isDirectory();
|
||||
if (isFile) {
|
||||
output.print(
|
||||
`${prependEmoji(
|
||||
'Deploying files with Vercel is deprecated (https://vercel.link/faq-deploy-file)',
|
||||
emoji('warning')
|
||||
)}\n`
|
||||
);
|
||||
if (!pathStat.isDirectory()) {
|
||||
output.prettyError({
|
||||
message: 'Support for single file deployments has been removed.',
|
||||
link: 'https://vercel.link/no-single-file-deployments',
|
||||
});
|
||||
return { valid: false, exitCode: 1 };
|
||||
}
|
||||
|
||||
// ask confirmation if the directory is home
|
||||
@@ -101,5 +95,5 @@ export default async function validatePaths(
|
||||
}
|
||||
}
|
||||
|
||||
return { valid: true, path, isFile };
|
||||
return { valid: true, path };
|
||||
}
|
||||
|
||||
60
packages/cli/test/commands/deploy.test.ts
Normal file
60
packages/cli/test/commands/deploy.test.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { join } from 'path';
|
||||
import { fileNameSymbol } from '@vercel/client';
|
||||
import { client } from '../mocks/client';
|
||||
import deploy from '../../src/commands/deploy';
|
||||
|
||||
describe('deploy', () => {
|
||||
it('should reject deploying a single file', async () => {
|
||||
client.setArgv('deploy', __filename);
|
||||
const exitCode = await deploy(client);
|
||||
expect(exitCode).toEqual(1);
|
||||
expect(client.outputBuffer).toEqual(
|
||||
`Error! Support for single file deployments has been removed.\nLearn More: https://vercel.link/no-single-file-deployments\n`
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject deploying multiple files', async () => {
|
||||
client.setArgv('deploy', __filename, join(__dirname, 'inspect.test.ts'));
|
||||
const exitCode = await deploy(client);
|
||||
expect(exitCode).toEqual(1);
|
||||
expect(client.outputBuffer).toEqual(
|
||||
`Error! Can't deploy more than one path.\n`
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject deploying a directory that does not exist', async () => {
|
||||
client.setArgv('deploy', 'does-not-exists');
|
||||
const exitCode = await deploy(client);
|
||||
expect(exitCode).toEqual(1);
|
||||
expect(client.outputBuffer).toEqual(
|
||||
`Error! The specified file or directory "does-not-exists" does not exist.\n`
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject deploying "version: 1"', async () => {
|
||||
client.setArgv('deploy');
|
||||
client.localConfig = {
|
||||
[fileNameSymbol]: 'vercel.json',
|
||||
version: 1,
|
||||
};
|
||||
const exitCode = await deploy(client);
|
||||
expect(exitCode).toEqual(1);
|
||||
expect(client.outputBuffer).toEqual(
|
||||
'Error! The value of the `version` property within vercel.json can only be `2`.\n'
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject deploying "version: {}"', async () => {
|
||||
client.setArgv('deploy');
|
||||
client.localConfig = {
|
||||
[fileNameSymbol]: 'vercel.json',
|
||||
// @ts-ignore
|
||||
version: {},
|
||||
};
|
||||
const exitCode = await deploy(client);
|
||||
expect(exitCode).toEqual(1);
|
||||
expect(client.outputBuffer).toEqual(
|
||||
'Error! The `version` property inside your vercel.json file must be a number.\n'
|
||||
);
|
||||
});
|
||||
});
|
||||
6
packages/cli/test/fixtures/unit/edge-middleware-strict/_middleware.ts
vendored
Normal file
6
packages/cli/test/fixtures/unit/edge-middleware-strict/_middleware.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
export default function (req) {
|
||||
const isStrict = (function () {
|
||||
return !this;
|
||||
})();
|
||||
return new Response('is strict mode? ' + (isStrict ? 'yes' : 'no'));
|
||||
}
|
||||
53
packages/cli/test/integration.js
vendored
53
packages/cli/test/integration.js
vendored
@@ -1913,59 +1913,6 @@ test('create a production deployment', async t => {
|
||||
t.is(deployment.target, 'production', JSON.stringify(deployment, null, 2));
|
||||
});
|
||||
|
||||
test('deploying a file should not show prompts and display deprecation', async t => {
|
||||
const file = fixture('static-single-file/first.png');
|
||||
|
||||
const output = await execute([file], {
|
||||
reject: false,
|
||||
});
|
||||
|
||||
const { stdout, stderr, exitCode } = output;
|
||||
|
||||
// Ensure the exit code is right
|
||||
t.is(exitCode, 0, formatOutput(output));
|
||||
t.true(stderr.includes('Deploying files with Vercel is deprecated'));
|
||||
|
||||
// Ensure `.vercel` was not created
|
||||
t.is(
|
||||
await exists(path.join(path.dirname(file), '.vercel')),
|
||||
false,
|
||||
'.vercel should not exists'
|
||||
);
|
||||
|
||||
// Test if the output is really a URL
|
||||
const { href, host } = new URL(stdout);
|
||||
t.is(host.split('-')[0], 'files');
|
||||
|
||||
// Send a test request to the deployment
|
||||
const response = await fetch(href);
|
||||
const contentType = response.headers.get('content-type');
|
||||
|
||||
t.is(contentType, 'image/png');
|
||||
t.deepEqual(await readFile(file), await response.buffer());
|
||||
});
|
||||
|
||||
test('deploying more than 1 path should fail', async t => {
|
||||
const file1 = fixture('static-multiple-files/first.png');
|
||||
const file2 = fixture('static-multiple-files/second.png');
|
||||
|
||||
const { stdout, stderr, exitCode } = await execa(
|
||||
binaryPath,
|
||||
[file1, file2, '--public', '--name', session, ...defaultArgs, '--confirm'],
|
||||
{
|
||||
reject: false,
|
||||
}
|
||||
);
|
||||
|
||||
console.log(stderr);
|
||||
console.log(stdout);
|
||||
console.log(exitCode);
|
||||
|
||||
// Ensure the exit code is right
|
||||
t.is(exitCode, 1);
|
||||
t.true(stderr.trim().endsWith(`Can't deploy more than one path.`));
|
||||
});
|
||||
|
||||
test('use build-env', async t => {
|
||||
const directory = fixture('build-env');
|
||||
|
||||
|
||||
@@ -385,4 +385,13 @@ describe('DevServer', () => {
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
it(
|
||||
'should run middleware in strict mode',
|
||||
testFixture('edge-middleware-strict', async server => {
|
||||
const response = await fetch(`${server.address}/index.html`);
|
||||
const body = await response.text();
|
||||
expect(body).toStrictEqual('is strict mode? yes');
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ describe('getProjectName', () => {
|
||||
expect(project).toEqual('abc');
|
||||
});
|
||||
|
||||
it('should work with now.json', () => {
|
||||
it('should work with `vercel.json` config', () => {
|
||||
const project = getProjectName({
|
||||
argv: {},
|
||||
nowConfig: { name: 'abc' },
|
||||
@@ -18,24 +18,6 @@ describe('getProjectName', () => {
|
||||
expect(project).toEqual('abc');
|
||||
});
|
||||
|
||||
it('should work with a file', () => {
|
||||
const project = getProjectName({
|
||||
argv: {},
|
||||
nowConfig: {},
|
||||
isFile: true,
|
||||
});
|
||||
expect(project).toEqual('files');
|
||||
});
|
||||
|
||||
it('should work with a multiple files', () => {
|
||||
const project = getProjectName({
|
||||
argv: {},
|
||||
nowConfig: {},
|
||||
paths: ['/tmp/aa/abc.png', '/tmp/aa/bbc.png'],
|
||||
});
|
||||
expect(project).toEqual('files');
|
||||
});
|
||||
|
||||
it('should work with a directory', () => {
|
||||
const project = getProjectName({
|
||||
argv: {},
|
||||
|
||||
2
packages/client/.gitignore
vendored
2
packages/client/.gitignore
vendored
@@ -6,3 +6,5 @@ node_modules
|
||||
!tests/fixtures/nowignore/node_modules
|
||||
!tests/fixtures/vercelignore-allow-nodemodules/node_modules
|
||||
!tests/fixtures/vercelignore-allow-nodemodules/sub/node_modules
|
||||
!tests/fixtures/file-system-api/.output
|
||||
!tests/fixtures/file-system-api-root-directory/**/.output
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/client",
|
||||
"version": "10.2.3-canary.26",
|
||||
"version": "10.2.3-canary.50",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"homepage": "https://vercel.com",
|
||||
@@ -40,7 +40,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.12.3-canary.25",
|
||||
"@vercel/build-utils": "2.13.0",
|
||||
"@zeit/fetch": "5.2.0",
|
||||
"async-retry": "1.2.3",
|
||||
"async-sema": "3.0.0",
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { lstatSync } from 'fs-extra';
|
||||
|
||||
import { relative, isAbsolute } from 'path';
|
||||
import hashes, { mapToObject } from './utils/hashes';
|
||||
import { hashes, mapToObject, resolveNftJsonFiles } from './utils/hashes';
|
||||
import { upload } from './upload';
|
||||
import { buildFileTree, createDebug, parseVercelConfig } from './utils';
|
||||
import { DeploymentError } from './errors';
|
||||
import {
|
||||
NowConfig,
|
||||
VercelConfig,
|
||||
VercelClientOptions,
|
||||
DeploymentOptions,
|
||||
DeploymentEventType,
|
||||
@@ -16,7 +16,7 @@ export default function buildCreateDeployment() {
|
||||
return async function* createDeployment(
|
||||
clientOptions: VercelClientOptions,
|
||||
deploymentOptions: DeploymentOptions = {},
|
||||
nowConfig: NowConfig = {}
|
||||
nowConfig: VercelConfig = {}
|
||||
): AsyncIterableIterator<{ type: DeploymentEventType; payload: any }> {
|
||||
const { path } = clientOptions;
|
||||
|
||||
@@ -74,12 +74,7 @@ export default function buildCreateDeployment() {
|
||||
debug(`Provided 'path' is a single file`);
|
||||
}
|
||||
|
||||
let { fileList } = await buildFileTree(
|
||||
path,
|
||||
clientOptions.isDirectory,
|
||||
debug,
|
||||
clientOptions.prebuilt
|
||||
);
|
||||
let { fileList } = await buildFileTree(path, clientOptions, debug);
|
||||
|
||||
let configPath: string | undefined;
|
||||
if (!nowConfig) {
|
||||
@@ -114,7 +109,11 @@ export default function buildCreateDeployment() {
|
||||
};
|
||||
}
|
||||
|
||||
const files = await hashes(fileList);
|
||||
const hashedFileMap = await hashes(fileList);
|
||||
const nftFileList = clientOptions.prebuilt
|
||||
? await resolveNftJsonFiles(hashedFileMap)
|
||||
: [];
|
||||
const files = await hashes(nftFileList, hashedFileMap);
|
||||
|
||||
debug(`Yielding a 'hashes-calculated' event with ${files.size} hashes`);
|
||||
yield { type: 'hashes-calculated', payload: mapToObject(files) };
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { Builder, BuilderFunctions } from '@vercel/build-utils';
|
||||
import {
|
||||
Builder,
|
||||
BuilderFunctions,
|
||||
ProjectSettings,
|
||||
} from '@vercel/build-utils';
|
||||
import { Header, Route, Redirect, Rewrite } from '@vercel/routing-utils';
|
||||
|
||||
export { DeploymentEventType } from './utils';
|
||||
@@ -15,6 +19,7 @@ export interface VercelClientOptions {
|
||||
apiUrl?: string;
|
||||
force?: boolean;
|
||||
prebuilt?: boolean;
|
||||
rootDirectory?: string;
|
||||
withCache?: boolean;
|
||||
userAgent?: string;
|
||||
defaultName?: string;
|
||||
@@ -123,12 +128,7 @@ export interface VercelConfig {
|
||||
scope?: string;
|
||||
alias?: string | string[];
|
||||
regions?: string[];
|
||||
projectSettings?: {
|
||||
devCommand?: string | null;
|
||||
buildCommand?: string | null;
|
||||
outputDirectory?: string | null;
|
||||
framework?: string | null;
|
||||
};
|
||||
projectSettings?: ProjectSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,9 +154,5 @@ export interface DeploymentOptions {
|
||||
name?: string;
|
||||
public?: boolean;
|
||||
meta?: Dictionary<string>;
|
||||
projectSettings?: {
|
||||
devCommand?: string | null;
|
||||
buildCommand?: string | null;
|
||||
outputDirectory?: string | null;
|
||||
};
|
||||
projectSettings?: ProjectSettings;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createHash } from 'crypto';
|
||||
import fs from 'fs-extra';
|
||||
import { Sema } from 'async-sema';
|
||||
import { join, dirname } from 'path';
|
||||
|
||||
export interface DeploymentFile {
|
||||
names: string[];
|
||||
@@ -15,9 +16,7 @@ export interface DeploymentFile {
|
||||
* @return {String} hex digest
|
||||
*/
|
||||
function hash(buf: Buffer): string {
|
||||
return createHash('sha1')
|
||||
.update(buf)
|
||||
.digest('hex');
|
||||
return createHash('sha1').update(buf).digest('hex');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,34 +38,68 @@ export const mapToObject = (
|
||||
/**
|
||||
* Computes hashes for the contents of each file given.
|
||||
*
|
||||
* @param {Array} of {String} full paths
|
||||
* @return {Map}
|
||||
* @param files - absolute file paths
|
||||
* @param map - optional map of files to append
|
||||
* @return Map of hash digest to file object
|
||||
*/
|
||||
async function hashes(files: string[]): Promise<Map<string, DeploymentFile>> {
|
||||
const map = new Map<string, DeploymentFile>();
|
||||
export async function hashes(
|
||||
files: string[],
|
||||
map = new Map<string, DeploymentFile>()
|
||||
): Promise<Map<string, DeploymentFile>> {
|
||||
const semaphore = new Sema(100);
|
||||
|
||||
await Promise.all(
|
||||
files.map(
|
||||
async (name: string): Promise<void> => {
|
||||
await semaphore.acquire();
|
||||
const data = await fs.readFile(name);
|
||||
const { mode } = await fs.stat(name);
|
||||
files.map(async (name: string): Promise<void> => {
|
||||
await semaphore.acquire();
|
||||
const data = await fs.readFile(name);
|
||||
const { mode } = await fs.stat(name);
|
||||
|
||||
const h = hash(data);
|
||||
const entry = map.get(h);
|
||||
const h = hash(data);
|
||||
const entry = map.get(h);
|
||||
|
||||
if (entry) {
|
||||
entry.names.push(name);
|
||||
} else {
|
||||
map.set(h, { names: [name], data, mode });
|
||||
}
|
||||
|
||||
semaphore.release();
|
||||
if (entry) {
|
||||
const names = new Set(entry.names);
|
||||
names.add(name);
|
||||
entry.names = [...names];
|
||||
} else {
|
||||
map.set(h, { names: [name], data, mode });
|
||||
}
|
||||
)
|
||||
|
||||
semaphore.release();
|
||||
})
|
||||
);
|
||||
return map;
|
||||
}
|
||||
|
||||
export default hashes;
|
||||
export async function resolveNftJsonFiles(
|
||||
hashedFiles: Map<string, DeploymentFile>
|
||||
): Promise<string[]> {
|
||||
const semaphore = new Sema(100);
|
||||
const existingFiles = Array.from(hashedFiles.values());
|
||||
const resolvedFiles = new Set<string>();
|
||||
|
||||
await Promise.all(
|
||||
existingFiles.map(async file => {
|
||||
await semaphore.acquire();
|
||||
const fsPath = file.names[0];
|
||||
if (fsPath.endsWith('.nft.json')) {
|
||||
const json = file.data.toString('utf8');
|
||||
const { version, files } = JSON.parse(json) as {
|
||||
version: number;
|
||||
files: string[] | { input: string; output: string }[];
|
||||
};
|
||||
if (version === 1 || version === 2) {
|
||||
for (let f of files) {
|
||||
const relPath = typeof f === 'string' ? f : f.input;
|
||||
resolvedFiles.add(join(dirname(fsPath), relPath));
|
||||
}
|
||||
} else {
|
||||
console.error(`Invalid nft.json version: ${version}`);
|
||||
}
|
||||
}
|
||||
semaphore.release();
|
||||
})
|
||||
);
|
||||
|
||||
return Array.from(resolvedFiles);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DeploymentFile } from './hashes';
|
||||
import { FetchOptions } from '@zeit/fetch';
|
||||
import { nodeFetch, zeitFetch } from './fetch';
|
||||
import { join, sep, relative } from 'path';
|
||||
import { join, sep, relative, posix } from 'path';
|
||||
import { URL } from 'url';
|
||||
import ignore from 'ignore';
|
||||
type Ignore = ReturnType<typeof ignore>;
|
||||
@@ -81,13 +81,16 @@ const maybeRead = async function <T>(path: string, default_: T) {
|
||||
|
||||
export async function buildFileTree(
|
||||
path: string | string[],
|
||||
isDirectory: boolean,
|
||||
debug: Debug,
|
||||
prebuilt?: boolean
|
||||
{
|
||||
isDirectory,
|
||||
prebuilt,
|
||||
rootDirectory,
|
||||
}: Pick<VercelClientOptions, 'isDirectory' | 'prebuilt' | 'rootDirectory'>,
|
||||
debug: Debug
|
||||
): Promise<{ fileList: string[]; ignoreList: string[] }> {
|
||||
const ignoreList: string[] = [];
|
||||
let fileList: string[];
|
||||
let { ig, ignores } = await getVercelIgnore(path, prebuilt);
|
||||
let { ig, ignores } = await getVercelIgnore(path, prebuilt, rootDirectory);
|
||||
|
||||
debug(`Found ${ignores.length} rules in .vercelignore`);
|
||||
debug('Building file tree...');
|
||||
@@ -119,37 +122,50 @@ export async function buildFileTree(
|
||||
|
||||
export async function getVercelIgnore(
|
||||
cwd: string | string[],
|
||||
prebuilt?: boolean
|
||||
prebuilt?: boolean,
|
||||
rootDirectory?: string
|
||||
): Promise<{ ig: Ignore; ignores: string[] }> {
|
||||
const ignores: string[] = prebuilt
|
||||
? ['*', '!.output', '!.output/**']
|
||||
: [
|
||||
'.hg',
|
||||
'.git',
|
||||
'.gitmodules',
|
||||
'.svn',
|
||||
'.cache',
|
||||
'.next',
|
||||
'.now',
|
||||
'.vercel',
|
||||
'.npmignore',
|
||||
'.dockerignore',
|
||||
'.gitignore',
|
||||
'.*.swp',
|
||||
'.DS_Store',
|
||||
'.wafpicke-*',
|
||||
'.lock-wscript',
|
||||
'.env.local',
|
||||
'.env.*.local',
|
||||
'.venv',
|
||||
'npm-debug.log',
|
||||
'config.gypi',
|
||||
'node_modules',
|
||||
'__pycache__',
|
||||
'venv',
|
||||
'CVS',
|
||||
'.output',
|
||||
];
|
||||
let ignores: string[] = [];
|
||||
|
||||
const outputDir = posix.join(rootDirectory || '', '.output');
|
||||
|
||||
if (prebuilt) {
|
||||
ignores.push('*');
|
||||
const parts = outputDir.split('/');
|
||||
parts.forEach((_, i) => {
|
||||
const level = parts.slice(0, i + 1).join('/');
|
||||
ignores.push(`!${level}`);
|
||||
});
|
||||
ignores.push(`!${outputDir}/**`);
|
||||
} else {
|
||||
ignores = [
|
||||
'.hg',
|
||||
'.git',
|
||||
'.gitmodules',
|
||||
'.svn',
|
||||
'.cache',
|
||||
'.next',
|
||||
'.now',
|
||||
'.vercel',
|
||||
'.npmignore',
|
||||
'.dockerignore',
|
||||
'.gitignore',
|
||||
'.*.swp',
|
||||
'.DS_Store',
|
||||
'.wafpicke-*',
|
||||
'.lock-wscript',
|
||||
'.env.local',
|
||||
'.env.*.local',
|
||||
'.venv',
|
||||
'npm-debug.log',
|
||||
'config.gypi',
|
||||
'node_modules',
|
||||
'__pycache__',
|
||||
'venv',
|
||||
'CVS',
|
||||
`.output`,
|
||||
];
|
||||
}
|
||||
const cwds = Array.isArray(cwd) ? cwd : [cwd];
|
||||
|
||||
const files = await Promise.all(
|
||||
@@ -250,39 +266,31 @@ export const prepareFiles = (
|
||||
files: Map<string, DeploymentFile>,
|
||||
clientOptions: VercelClientOptions
|
||||
): PreparedFile[] => {
|
||||
const preparedFiles = [...files.keys()].reduce(
|
||||
(acc: PreparedFile[], sha: string): PreparedFile[] => {
|
||||
const next = [...acc];
|
||||
const preparedFiles: PreparedFile[] = [];
|
||||
for (const [sha, file] of files) {
|
||||
for (const name of file.names) {
|
||||
let fileName: string;
|
||||
|
||||
const file = files.get(sha) as DeploymentFile;
|
||||
|
||||
for (const name of file.names) {
|
||||
let fileName: string;
|
||||
|
||||
if (clientOptions.isDirectory) {
|
||||
// Directory
|
||||
fileName =
|
||||
typeof clientOptions.path === 'string'
|
||||
? relative(clientOptions.path, name)
|
||||
: name;
|
||||
} else {
|
||||
// Array of files or single file
|
||||
const segments = name.split(sep);
|
||||
fileName = segments[segments.length - 1];
|
||||
}
|
||||
|
||||
next.push({
|
||||
file: isWin ? fileName.replace(/\\/g, '/') : fileName,
|
||||
size: file.data.byteLength || file.data.length,
|
||||
mode: file.mode,
|
||||
sha,
|
||||
});
|
||||
if (clientOptions.isDirectory) {
|
||||
// Directory
|
||||
fileName =
|
||||
typeof clientOptions.path === 'string'
|
||||
? relative(clientOptions.path, name)
|
||||
: name;
|
||||
} else {
|
||||
// Array of files or single file
|
||||
const segments = name.split(sep);
|
||||
fileName = segments[segments.length - 1];
|
||||
}
|
||||
|
||||
return next;
|
||||
},
|
||||
[]
|
||||
);
|
||||
preparedFiles.push({
|
||||
file: isWin ? fileName.replace(/\\/g, '/') : fileName,
|
||||
size: file.data.byteLength || file.data.length,
|
||||
mode: file.mode,
|
||||
sha,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return preparedFiles;
|
||||
};
|
||||
|
||||
1
packages/client/tests/fixtures/file-system-api-root-directory/foo.txt
vendored
Normal file
1
packages/client/tests/fixtures/file-system-api-root-directory/foo.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
foo
|
||||
1
packages/client/tests/fixtures/file-system-api-root-directory/root/.output/baz.txt
vendored
Normal file
1
packages/client/tests/fixtures/file-system-api-root-directory/root/.output/baz.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
baz
|
||||
1
packages/client/tests/fixtures/file-system-api-root-directory/root/.output/sub/qux.txt
vendored
Normal file
1
packages/client/tests/fixtures/file-system-api-root-directory/root/.output/sub/qux.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
qux
|
||||
1
packages/client/tests/fixtures/file-system-api-root-directory/root/bar.txt
vendored
Normal file
1
packages/client/tests/fixtures/file-system-api-root-directory/root/bar.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
bar
|
||||
1
packages/client/tests/fixtures/file-system-api-root-directory/someother/.output/baz.txt
vendored
Normal file
1
packages/client/tests/fixtures/file-system-api-root-directory/someother/.output/baz.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
baz
|
||||
1
packages/client/tests/fixtures/file-system-api-root-directory/someother/.output/sub/qux.txt
vendored
Normal file
1
packages/client/tests/fixtures/file-system-api-root-directory/someother/.output/sub/qux.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
qux
|
||||
1
packages/client/tests/fixtures/file-system-api-root-directory/someother/bar.txt
vendored
Normal file
1
packages/client/tests/fixtures/file-system-api-root-directory/someother/bar.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
bar
|
||||
1
packages/client/tests/fixtures/file-system-api/.output/baz.txt
vendored
Normal file
1
packages/client/tests/fixtures/file-system-api/.output/baz.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
baz
|
||||
1
packages/client/tests/fixtures/file-system-api/.output/sub/qux.txt
vendored
Normal file
1
packages/client/tests/fixtures/file-system-api/.output/sub/qux.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
qux
|
||||
1
packages/client/tests/fixtures/file-system-api/foo.txt
vendored
Normal file
1
packages/client/tests/fixtures/file-system-api/foo.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
foo
|
||||
1
packages/client/tests/fixtures/file-system-api/sub/bar.txt
vendored
Normal file
1
packages/client/tests/fixtures/file-system-api/sub/bar.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
bar
|
||||
4
packages/client/tests/tsconfig.json
Normal file
4
packages/client/tests/tsconfig.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"include": ["*.test.ts"]
|
||||
}
|
||||
@@ -17,7 +17,11 @@ const toAbsolutePaths = (cwd: string, files: string[]) =>
|
||||
describe('buildFileTree()', () => {
|
||||
it('should exclude files using `.nowignore` blocklist', async () => {
|
||||
const cwd = fixture('nowignore');
|
||||
const { fileList, ignoreList } = await buildFileTree(cwd, true, noop);
|
||||
const { fileList, ignoreList } = await buildFileTree(
|
||||
cwd,
|
||||
{ isDirectory: true },
|
||||
noop
|
||||
);
|
||||
|
||||
const expectedFileList = toAbsolutePaths(cwd, ['.nowignore', 'index.txt']);
|
||||
expect(normalizeWindowsPaths(expectedFileList).sort()).toEqual(
|
||||
@@ -36,7 +40,11 @@ describe('buildFileTree()', () => {
|
||||
|
||||
it('should include the node_modules using `.vercelignore` allowlist', async () => {
|
||||
const cwd = fixture('vercelignore-allow-nodemodules');
|
||||
const { fileList, ignoreList } = await buildFileTree(cwd, true, noop);
|
||||
const { fileList, ignoreList } = await buildFileTree(
|
||||
cwd,
|
||||
{ isDirectory: true },
|
||||
noop
|
||||
);
|
||||
|
||||
const expected = toAbsolutePaths(cwd, [
|
||||
'node_modules/one.txt',
|
||||
@@ -54,4 +62,90 @@ describe('buildFileTree()', () => {
|
||||
normalizeWindowsPaths(ignoreList).sort()
|
||||
);
|
||||
});
|
||||
|
||||
it('should find root files but ignore .output files when prebuilt=false', async () => {
|
||||
const cwd = fixture('file-system-api');
|
||||
const { fileList, ignoreList } = await buildFileTree(
|
||||
cwd,
|
||||
{ isDirectory: true, prebuilt: false },
|
||||
noop
|
||||
);
|
||||
|
||||
const expectedFileList = toAbsolutePaths(cwd, ['foo.txt', 'sub/bar.txt']);
|
||||
expect(normalizeWindowsPaths(expectedFileList).sort()).toEqual(
|
||||
normalizeWindowsPaths(fileList).sort()
|
||||
);
|
||||
|
||||
const expectedIgnoreList = ['.output'];
|
||||
expect(normalizeWindowsPaths(expectedIgnoreList).sort()).toEqual(
|
||||
normalizeWindowsPaths(ignoreList).sort()
|
||||
);
|
||||
});
|
||||
|
||||
it('should find .output files but ignore other files when prebuilt=true', async () => {
|
||||
const cwd = fixture('file-system-api');
|
||||
const { fileList, ignoreList } = await buildFileTree(
|
||||
cwd,
|
||||
{ isDirectory: true, prebuilt: true },
|
||||
noop
|
||||
);
|
||||
|
||||
const expectedFileList = toAbsolutePaths(cwd, [
|
||||
'.output/baz.txt',
|
||||
'.output/sub/qux.txt',
|
||||
]);
|
||||
expect(normalizeWindowsPaths(expectedFileList).sort()).toEqual(
|
||||
normalizeWindowsPaths(fileList).sort()
|
||||
);
|
||||
|
||||
const expectedIgnoreList = ['foo.txt', 'sub'];
|
||||
expect(normalizeWindowsPaths(expectedIgnoreList).sort()).toEqual(
|
||||
normalizeWindowsPaths(ignoreList).sort()
|
||||
);
|
||||
});
|
||||
|
||||
it('should find root files but ignore all .output files when prebuilt=false and rootDirectory=root', async () => {
|
||||
const cwd = fixture('file-system-api-root-directory');
|
||||
const { fileList, ignoreList } = await buildFileTree(
|
||||
cwd,
|
||||
{ isDirectory: true, prebuilt: false, rootDirectory: 'root' },
|
||||
noop
|
||||
);
|
||||
|
||||
const expectedFileList = toAbsolutePaths(cwd, [
|
||||
'foo.txt',
|
||||
'root/bar.txt',
|
||||
'someother/bar.txt',
|
||||
]);
|
||||
expect(normalizeWindowsPaths(expectedFileList).sort()).toEqual(
|
||||
normalizeWindowsPaths(fileList).sort()
|
||||
);
|
||||
|
||||
const expectedIgnoreList = ['root/.output', 'someother/.output'];
|
||||
expect(normalizeWindowsPaths(expectedIgnoreList).sort()).toEqual(
|
||||
normalizeWindowsPaths(ignoreList).sort()
|
||||
);
|
||||
});
|
||||
|
||||
it('should find root/.output files but ignore other files when prebuilt=true and rootDirectory=root', async () => {
|
||||
const cwd = fixture('file-system-api-root-directory');
|
||||
const { fileList, ignoreList } = await buildFileTree(
|
||||
cwd,
|
||||
{ isDirectory: true, prebuilt: true, rootDirectory: 'root' },
|
||||
noop
|
||||
);
|
||||
|
||||
const expectedFileList = toAbsolutePaths(cwd, [
|
||||
'root/.output/baz.txt',
|
||||
'root/.output/sub/qux.txt',
|
||||
]);
|
||||
expect(normalizeWindowsPaths(expectedFileList).sort()).toEqual(
|
||||
normalizeWindowsPaths(fileList).sort()
|
||||
);
|
||||
|
||||
const expectedIgnoreList = ['foo.txt', 'root/bar.txt', 'someother'];
|
||||
expect(normalizeWindowsPaths(expectedIgnoreList).sort()).toEqual(
|
||||
normalizeWindowsPaths(ignoreList).sort()
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
6
packages/frameworks/logos/remix.svg
Normal file
6
packages/frameworks/logos/remix.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg viewBox="0 0 800 800" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M700 0H100C44.772 0 0 44.772 0 100v600c0 55.228 44.772 100 100 100h600c55.228 0 100-44.772 100-100V100C800 44.772 755.228 0 700 0Z" fill="#212121"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M587.947 527.768c4.254 54.65 4.254 80.268 4.254 108.232H465.756c0-6.091.109-11.663.219-17.313.342-17.564.699-35.88-2.147-72.868-3.761-54.152-27.08-66.185-69.957-66.185H195v-98.525h204.889c54.16 0 81.241-16.476 81.241-60.098 0-38.357-27.081-61.601-81.241-61.601H195V163h227.456C545.069 163 606 220.912 606 313.42c0 69.193-42.877 114.319-100.799 121.84 48.895 9.777 77.48 37.605 82.746 92.508Z" fill="#fff"/>
|
||||
<path d="M195 636v-73.447h133.697c22.332 0 27.181 16.563 27.181 26.441V636H195Z" fill="#fff"/>
|
||||
<path d="M194.5 636v.5h161.878v-47.506c0-5.006-1.226-11.734-5.315-17.224-4.108-5.515-11.059-9.717-22.366-9.717H194.5V636Z" stroke="#fff" stroke-opacity=".8"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 958 B |
1
packages/frameworks/logos/solid.svg
Normal file
1
packages/frameworks/logos/solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 166 155.3"><defs><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="27.5" y1="3" x2="152" y2="63.5"><stop offset=".1" stop-color="#76b3e1"/><stop offset=".3" stop-color="#dcf2fd"/><stop offset="1" stop-color="#76b3e1"/></linearGradient><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="95.8" y1="32.6" x2="74" y2="105.2"><stop offset="0" stop-color="#76b3e1"/><stop offset=".5" stop-color="#4377bb"/><stop offset="1" stop-color="#1f3b77"/></linearGradient><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="18.4" y1="64.2" x2="144.3" y2="149.8"><stop offset="0" stop-color="#315aa9"/><stop offset=".5" stop-color="#518ac8"/><stop offset="1" stop-color="#315aa9"/></linearGradient><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="75.2" y1="74.5" x2="24.4" y2="260.8"><stop offset="0" stop-color="#4377bb"/><stop offset=".5" stop-color="#1a336b"/><stop offset="1" stop-color="#1a336b"/></linearGradient></defs><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" fill="#76b3e1"/><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" opacity=".3" fill="url(#a)"/><path d="M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" fill="#518ac8"/><path d="M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" opacity=".3" fill="url(#b)"/><path d="M134 80a45 45 0 00-48-15L24 85 4 120l112 19 20-36c4-7 3-15-2-23z" fill="url(#c)"/><path d="M114 115a45 45 0 00-48-15L4 120s53 40 94 30l3-1c17-5 23-21 13-34z" fill="url(#d)"/></svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/frameworks",
|
||||
"version": "0.5.1-canary.15",
|
||||
"version": "0.5.1-canary.19",
|
||||
"main": "./dist/frameworks.js",
|
||||
"types": "./dist/frameworks.d.ts",
|
||||
"files": [
|
||||
|
||||
@@ -141,7 +141,6 @@ export const frameworks = [
|
||||
},
|
||||
dependency: 'gatsby',
|
||||
getOutputDirName: async () => 'public',
|
||||
getFsOutputDir: async () => 'public',
|
||||
defaultRoutes: async (dirPrefix: string) => {
|
||||
// This file could be generated by gatsby-plugin-now or gatsby-plugin-zeit-now
|
||||
try {
|
||||
@@ -226,7 +225,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: 'remix',
|
||||
getFsOutputDir: async () => 'public',
|
||||
getOutputDirName: async () => 'public',
|
||||
defaultRoutes: [
|
||||
{
|
||||
@@ -254,10 +252,13 @@ export const frameworks = [
|
||||
source: '/build/(.*)',
|
||||
regex: '/build/(.*)',
|
||||
headers: [
|
||||
{ key: 'cache-control', value: 'public, max-age=31536000, immutable' },
|
||||
{
|
||||
key: 'cache-control',
|
||||
value: 'public, max-age=31536000, immutable',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Hexo',
|
||||
@@ -294,7 +295,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: 'hexo',
|
||||
getFsOutputDir: async () => 'public',
|
||||
getOutputDirName: async () => 'public',
|
||||
},
|
||||
{
|
||||
@@ -332,7 +332,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: '@11ty/eleventy',
|
||||
getFsOutputDir: async () => '_site',
|
||||
getOutputDirName: async () => '_site',
|
||||
cachePattern: '.cache/**',
|
||||
},
|
||||
@@ -372,22 +371,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: '@docusaurus/core',
|
||||
getFsOutputDir: async (dirPrefix: string) => {
|
||||
const base = 'build';
|
||||
try {
|
||||
const location = join(dirPrefix, base);
|
||||
const content = await readdir(location, { withFileTypes: true });
|
||||
|
||||
// If there is only one file in it that is a dir we'll use it as dist dir
|
||||
if (content.length === 1 && content[0].isDirectory()) {
|
||||
return join(base, content[0].name);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error detecting output directory: `, error);
|
||||
}
|
||||
|
||||
return base;
|
||||
},
|
||||
getOutputDirName: async (dirPrefix: string) => {
|
||||
const base = 'build';
|
||||
try {
|
||||
@@ -527,21 +510,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: 'docusaurus',
|
||||
getFsOutputDir: async (dirPrefix: string) => {
|
||||
const base = 'build';
|
||||
try {
|
||||
const location = join(dirPrefix, base);
|
||||
const content = await readdir(location, { withFileTypes: true });
|
||||
|
||||
// If there is only one file in it that is a dir we'll use it as dist dir
|
||||
if (content.length === 1 && content[0].isDirectory()) {
|
||||
return join(base, content[0].name);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error detecting output directory: `, error);
|
||||
}
|
||||
return base;
|
||||
},
|
||||
getOutputDirName: async (dirPrefix: string) => {
|
||||
const base = 'build';
|
||||
try {
|
||||
@@ -593,7 +561,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: 'preact-cli',
|
||||
getFsOutputDir: async () => 'build',
|
||||
getOutputDirName: async () => 'build',
|
||||
defaultRoutes: [
|
||||
{
|
||||
@@ -612,6 +579,46 @@ export const frameworks = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'SolidStart',
|
||||
slug: 'solidstart',
|
||||
demo: 'https://solidstart.examples.vercel.com',
|
||||
logo: 'https://raw.githubusercontent.com/vercel/vercel/main/packages/frameworks/logos/solid.svg',
|
||||
tagline: 'Simple and performant reactivity for building user interfaces.',
|
||||
description: 'A Solid app, created with SolidStart.',
|
||||
website: 'https://solidjs.com',
|
||||
envPrefix: 'VITE_',
|
||||
detectors: {
|
||||
every: [
|
||||
{
|
||||
path: 'package.json',
|
||||
matchContent:
|
||||
'"(dev)?(d|D)ependencies":\\s*{[^}]*"solid-js":\\s*".+?"[^}]*}',
|
||||
},
|
||||
{
|
||||
path: 'package.json',
|
||||
matchContent:
|
||||
'"(dev)?(d|D)ependencies":\\s*{[^}]*"solid-start":\\s*".+?"[^}]*}',
|
||||
},
|
||||
],
|
||||
},
|
||||
settings: {
|
||||
installCommand: {
|
||||
placeholder: '`yarn install` or `npm install`',
|
||||
},
|
||||
buildCommand: {
|
||||
placeholder: '`npm run build` or `solid-start build`',
|
||||
value: 'solid-start build',
|
||||
},
|
||||
devCommand: {
|
||||
value: 'solid-start dev',
|
||||
},
|
||||
outputDirectory: {
|
||||
value: '.output',
|
||||
},
|
||||
},
|
||||
getOutputDirName: async () => '.output',
|
||||
},
|
||||
{
|
||||
name: 'Dojo',
|
||||
slug: 'dojo',
|
||||
@@ -650,7 +657,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: '@dojo/cli',
|
||||
getFsOutputDir: async () => 'output/dist',
|
||||
getOutputDirName: async () => join('output', 'dist'),
|
||||
defaultRoutes: [
|
||||
{
|
||||
@@ -717,7 +723,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: 'ember-cli',
|
||||
getFsOutputDir: async () => 'dist',
|
||||
getOutputDirName: async () => 'dist',
|
||||
defaultRoutes: [
|
||||
{
|
||||
@@ -772,7 +777,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: '@vue/cli-service',
|
||||
getFsOutputDir: async () => 'dist',
|
||||
getOutputDirName: async () => 'dist',
|
||||
defaultRoutes: [
|
||||
{
|
||||
@@ -849,7 +853,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: '@scullyio/init',
|
||||
getFsOutputDir: async () => 'dist',
|
||||
getOutputDirName: async () => 'dist/static',
|
||||
},
|
||||
{
|
||||
@@ -886,7 +889,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: '@ionic/angular',
|
||||
getFsOutputDir: async () => 'www',
|
||||
getOutputDirName: async () => 'www',
|
||||
defaultRoutes: [
|
||||
{
|
||||
@@ -940,7 +942,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: '@angular/cli',
|
||||
getFsOutputDir: async () => 'dist',
|
||||
getOutputDirName: async (dirPrefix: string) => {
|
||||
const base = 'dist';
|
||||
try {
|
||||
@@ -1008,7 +1009,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: 'polymer-cli',
|
||||
getFsOutputDir: async () => 'build',
|
||||
getOutputDirName: async (dirPrefix: string) => {
|
||||
const base = 'build';
|
||||
try {
|
||||
@@ -1078,7 +1078,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: 'sirv-cli',
|
||||
getFsOutputDir: async () => 'public',
|
||||
getOutputDirName: async () => 'public',
|
||||
defaultRoutes: [
|
||||
{
|
||||
@@ -1106,6 +1105,7 @@ export const frameworks = [
|
||||
'SvelteKit is a framework for building web applications of all sizes.',
|
||||
description: 'A SvelteKit app optimized to work for serverless.',
|
||||
website: 'https://kit.svelte.dev',
|
||||
envPrefix: 'VITE_',
|
||||
detectors: {
|
||||
every: [
|
||||
{
|
||||
@@ -1128,10 +1128,9 @@ export const frameworks = [
|
||||
placeholder: 'svelte-kit dev',
|
||||
},
|
||||
outputDirectory: {
|
||||
placeholder: 'public',
|
||||
value: 'public',
|
||||
},
|
||||
},
|
||||
getFsOutputDir: async () => '.output',
|
||||
getOutputDirName: async () => 'public',
|
||||
},
|
||||
{
|
||||
@@ -1168,7 +1167,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: '@ionic/react',
|
||||
getFsOutputDir: async () => 'build',
|
||||
getOutputDirName: async () => 'build',
|
||||
defaultRoutes: [
|
||||
{
|
||||
@@ -1276,7 +1274,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: 'react-scripts',
|
||||
getFsOutputDir: async () => 'build',
|
||||
getOutputDirName: async () => 'build',
|
||||
defaultRoutes: [
|
||||
{
|
||||
@@ -1378,7 +1375,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: 'gridsome',
|
||||
getFsOutputDir: async () => 'dist',
|
||||
getOutputDirName: async () => 'dist',
|
||||
},
|
||||
{
|
||||
@@ -1416,7 +1412,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: 'umi',
|
||||
getFsOutputDir: async () => 'dist',
|
||||
getOutputDirName: async () => 'dist',
|
||||
defaultRoutes: [
|
||||
{
|
||||
@@ -1470,7 +1465,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: 'sapper',
|
||||
getFsOutputDir: async () => '__sapper__/export',
|
||||
getOutputDirName: async () => '__sapper__/export',
|
||||
},
|
||||
{
|
||||
@@ -1508,7 +1502,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: 'saber',
|
||||
getFsOutputDir: async () => 'public',
|
||||
getOutputDirName: async () => 'public',
|
||||
defaultRoutes: [
|
||||
{
|
||||
@@ -1577,7 +1570,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: '@stencil/core',
|
||||
getFsOutputDir: async () => 'www',
|
||||
getOutputDirName: async () => 'www',
|
||||
defaultRoutes: [
|
||||
{
|
||||
@@ -1666,7 +1658,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: 'nuxt',
|
||||
getFsOutputDir: async () => '.output',
|
||||
getOutputDirName: async () => 'dist',
|
||||
cachePattern: '.nuxt/**',
|
||||
defaultRoutes: [
|
||||
@@ -1724,7 +1715,6 @@ export const frameworks = [
|
||||
placeholder: 'RedwoodJS default',
|
||||
},
|
||||
},
|
||||
getFsOutputDir: async () => 'public',
|
||||
getOutputDirName: async () => 'public',
|
||||
},
|
||||
{
|
||||
@@ -1768,16 +1758,6 @@ export const frameworks = [
|
||||
placeholder: '`public` or `publishDir` from the `config` file',
|
||||
},
|
||||
},
|
||||
getFsOutputDir: async (dirPrefix: string): Promise<string> => {
|
||||
type HugoConfig = { publishDir?: string };
|
||||
const config = await readConfigFile<HugoConfig>(
|
||||
['config.json', 'config.yaml', 'config.toml'].map(fileName => {
|
||||
return join(dirPrefix, fileName);
|
||||
})
|
||||
);
|
||||
|
||||
return (config && config.publishDir) || 'public';
|
||||
},
|
||||
getOutputDirName: async (dirPrefix: string): Promise<string> => {
|
||||
type HugoConfig = { publishDir?: string };
|
||||
const config = await readConfigFile<HugoConfig>(
|
||||
@@ -1822,13 +1802,6 @@ export const frameworks = [
|
||||
placeholder: '`_site` or `destination` from `_config.yml`',
|
||||
},
|
||||
},
|
||||
getFsOutputDir: async (dirPrefix: string): Promise<string> => {
|
||||
type JekyllConfig = { destination?: string };
|
||||
const config = await readConfigFile<JekyllConfig>(
|
||||
join(dirPrefix, '_config.yml')
|
||||
);
|
||||
return (config && config.destination) || '_site';
|
||||
},
|
||||
getOutputDirName: async (dirPrefix: string): Promise<string> => {
|
||||
type JekyllConfig = { destination?: string };
|
||||
const config = await readConfigFile<JekyllConfig>(
|
||||
@@ -1870,7 +1843,6 @@ export const frameworks = [
|
||||
value: 'public',
|
||||
},
|
||||
},
|
||||
getFsOutputDir: async () => 'public',
|
||||
getOutputDirName: async () => 'public',
|
||||
},
|
||||
{
|
||||
@@ -1905,7 +1877,6 @@ export const frameworks = [
|
||||
value: 'build',
|
||||
},
|
||||
},
|
||||
getFsOutputDir: async () => 'build',
|
||||
getOutputDirName: async () => 'build',
|
||||
cachePattern: '{vendor/bin,vendor/cache,vendor/bundle}/**',
|
||||
},
|
||||
@@ -1940,7 +1911,6 @@ export const frameworks = [
|
||||
value: 'public',
|
||||
},
|
||||
},
|
||||
getFsOutputDir: async () => 'public',
|
||||
getOutputDirName: async () => 'public',
|
||||
defaultVersion: '0.13.0',
|
||||
},
|
||||
@@ -1980,7 +1950,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: 'vite',
|
||||
getFsOutputDir: async () => 'dist',
|
||||
getOutputDirName: async () => 'dist',
|
||||
},
|
||||
{
|
||||
@@ -2018,7 +1987,6 @@ export const frameworks = [
|
||||
},
|
||||
},
|
||||
dependency: 'parcel',
|
||||
getFsOutputDir: async () => 'dist',
|
||||
getOutputDirName: async () => 'dist',
|
||||
defaultRoutes: [
|
||||
{
|
||||
|
||||
@@ -162,9 +162,9 @@ export interface Framework {
|
||||
dependency?: string;
|
||||
/**
|
||||
* Function that returns the name of the directory that the framework outputs
|
||||
* its build results to. In some cases this is read from a configuration file.
|
||||
* its File System API build results to, usually called `.output`.
|
||||
*/
|
||||
getFsOutputDir: (dirPrefix: string) => Promise<string>;
|
||||
getFsOutputDir?: (dirPrefix: string) => Promise<string>;
|
||||
/**
|
||||
* Function that returns the name of the directory that the framework outputs
|
||||
* its STATIC build results to. In some cases this is read from a configuration file.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel-plugin-middleware",
|
||||
"version": "0.0.0-canary.7",
|
||||
"version": "0.0.0-canary.24",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "",
|
||||
@@ -30,6 +30,7 @@
|
||||
"@types/node-fetch": "^2",
|
||||
"@types/ua-parser-js": "0.7.36",
|
||||
"@types/uuid": "8.3.1",
|
||||
"@vercel/build-utils": "2.13.0",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"cookie": "0.4.1",
|
||||
"formdata-node": "4.3.1",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as middleware from './_middleware';
|
||||
import * as middleware from './_temp_middleware';
|
||||
_ENTRIES = typeof _ENTRIES === 'undefined' ? {} : _ENTRIES;
|
||||
_ENTRIES['middleware_pages/_middleware'] = {
|
||||
default: async function (ev) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user