Compare commits

...

29 Commits

Author SHA1 Message Date
Steven
7039771ec9 Publish Stable
- @vercel/build-utils@2.13.0
2021-12-15 09:21:03 -05:00
Steven
38d643a8e6 Publish Canary
- @vercel/build-utils@2.12.3-canary.47
 - vercel@23.1.3-canary.72
 - @vercel/client@10.2.3-canary.50
 - vercel-plugin-middleware@0.0.0-canary.24
 - vercel-plugin-go@1.0.0-canary.35
 - vercel-plugin-node@1.12.2-canary.39
 - vercel-plugin-python@1.0.0-canary.36
 - vercel-plugin-ruby@1.0.0-canary.35
2021-12-14 19:16:20 -05:00
Steven
9c171c413b [build-utils] Add _experimental_ prefix to exported experimental functions (#7190) 2021-12-14 19:15:43 -05:00
Steven
b620c5343a Publish Canary
- @vercel/build-utils@2.12.3-canary.46
 - vercel@23.1.3-canary.71
 - @vercel/client@10.2.3-canary.49
 - @vercel/frameworks@0.5.1-canary.19
 - vercel-plugin-middleware@0.0.0-canary.23
 - vercel-plugin-go@1.0.0-canary.34
 - vercel-plugin-node@1.12.2-canary.38
 - vercel-plugin-python@1.0.0-canary.35
 - vercel-plugin-ruby@1.0.0-canary.34
2021-12-14 09:02:29 -05:00
Dom Eccleston
f42391a1f5 Add 'VITE_' prefix to SvelteKit framework (#6821) 2021-12-13 19:12:56 -08:00
Steven
0505f4e8bd [cli] Major: remove "now" prop from package.json (#7186) 2021-12-13 19:10:42 -05:00
Steven
ca433a4679 Publish Canary
- @vercel/build-utils@2.12.3-canary.45
 - vercel@23.1.3-canary.70
 - @vercel/client@10.2.3-canary.48
 - @vercel/frameworks@0.5.1-canary.18
 - vercel-plugin-middleware@0.0.0-canary.22
 - vercel-plugin-go@1.0.0-canary.33
 - vercel-plugin-node@1.12.2-canary.37
 - vercel-plugin-python@1.0.0-canary.34
 - vercel-plugin-ruby@1.0.0-canary.33
2021-12-13 16:31:46 -05:00
Steven
204b481c56 [examples] Rename master to main (#7184) 2021-12-13 16:30:58 -05:00
Ryan Carniato
9265f78c52 [frameworks][examples] Add solidstart template (#6984)
* add solid/solidstart templates

* remove solid entry, add readme logos

* remove legacy config, add yarn.lock, fix gitignore

* remove solid example

* update deps, remove FS dir

Co-authored-by: Steven <steven@ceriously.com>
2021-12-13 15:38:28 -05:00
Steven
783144e0d6 [test] Skip runPackageJsonScript() on windows and macOS (#7176)
This test is flaky on windows and macOS but its never actually run on those OS's so there is no need to test it there.
2021-12-10 18:37:49 -05:00
Steven
d563b96ff0 [ci] Speed up GH publish skip (#7175)
This is following a similar pattern to Next.js workflows so that the publish step is skipped and reduces the time it takes GH Actions to run since we don't need to build to know that it should be skipped.
2021-12-10 23:34:19 +00:00
Steven
ecb4481226 Publish Canary
- @vercel/build-utils@2.12.3-canary.44
 - vercel@23.1.3-canary.69
 - @vercel/client@10.2.3-canary.47
 - vercel-plugin-middleware@0.0.0-canary.21
 - vercel-plugin-go@1.0.0-canary.32
 - vercel-plugin-node@1.12.2-canary.36
 - vercel-plugin-python@1.0.0-canary.33
 - vercel-plugin-ruby@1.0.0-canary.32
2021-12-10 14:45:46 -05:00
Steven
347407b244 [build-utils] Add exclusion condition for vercel cli version (#7174)
Fixes https://github.com/vercel/runtimes/issues/295
2021-12-10 19:43:31 +00:00
Steven
01ea7b4b2a Publish Canary
- @vercel/build-utils@2.12.3-canary.43
 - vercel@23.1.3-canary.68
 - @vercel/client@10.2.3-canary.46
 - vercel-plugin-middleware@0.0.0-canary.20
 - vercel-plugin-go@1.0.0-canary.31
 - vercel-plugin-node@1.12.2-canary.35
 - vercel-plugin-python@1.0.0-canary.32
 - vercel-plugin-ruby@1.0.0-canary.31
2021-12-09 19:56:30 -05:00
Steven
475a227ba9 [build-utils][cli] Detect file system api usage, abort on "Exclusion Conditions" (#7158) 2021-12-09 19:54:39 -05:00
Nathan Rajlich
40ca92f2e9 [client] Use a Set to prevent duplicates in hashes() function (#7159)
Follow-up to #7150 to use a Set instead of assuming the conflicting entry is at index 0, which is not always the case.
2021-12-09 03:10:48 +00:00
Nathan Rajlich
465129e62e [cli] Remove support for single file deployments (#6652)
Deploying a single file has printed a deprecation warning for a long time. Let's finally remove that behavior.
2021-12-08 19:45:06 +00:00
Steven
bf0d5a7f29 [cli] Add @vercel/client as a devDependency (#7154) 2021-12-08 10:17:20 -05:00
Leo Lamprecht
d3ef240f6e Publish Canary
- @vercel/build-utils@2.12.3-canary.42
 - vercel@23.1.3-canary.67
 - @vercel/client@10.2.3-canary.45
 - vercel-plugin-middleware@0.0.0-canary.19
 - vercel-plugin-go@1.0.0-canary.30
 - vercel-plugin-node@1.12.2-canary.34
 - vercel-plugin-python@1.0.0-canary.31
 - vercel-plugin-ruby@1.0.0-canary.30
 - @vercel/python@2.1.2-canary.2
2021-12-08 15:53:14 +01:00
Leo Lamprecht
5b26ebc7b8 Make Python CLI Plugin work (#7155) 2021-12-08 15:52:43 +01:00
Leo Lamprecht
3427ad6ce0 Publish Canary
- vercel@23.1.3-canary.66
2021-12-08 12:50:58 +01:00
Leo Lamprecht
4ab5e4326b Improved Vercel CLI link (#7151) 2021-12-08 12:50:27 +01:00
Leo Lamprecht
d24a3ce3ab Publish Canary
- @vercel/client@10.2.3-canary.44
2021-12-08 12:10:44 +01:00
Steven
29a44db8d9 [client] Fix duplicate files when analyzing nft.json (#7150)
This PR fixes a regression from #7144 where a duplicate file was added if `nft.json` referenced an existing file.

I also refactored the prepared files logic to avoid cloning the array in every loop iteration.

Review [without whitespace](https://github.com/vercel/vercel/pull/7150/files?diff=split&w=1) will make it easier to understand.

- Related to https://github.com/vercel/runtimes/issues/304
2021-12-08 01:40:49 +00:00
Steven
695f3a9212 Publish Canary
- vercel@23.1.3-canary.65
 - @vercel/client@10.2.3-canary.43
 - vercel-plugin-middleware@0.0.0-canary.18
2021-12-07 18:25:02 -05:00
Steven
3ff777b8ed [client] Resolve .nft.json files when vc deploy --prebuilt (#7144)
This ensures that using `vc deploy --prebuilt` will also upload any files that `.output/**/.nft.json` points to and also handle the Root Directory correctly since `vc build` emits `rootdir/.output`.

- Related to https://github.com/vercel/runtimes/issues/304.
2021-12-07 18:17:58 -05:00
Tommaso De Rossi
d94b9806ab [middleware] Define env vars when building _middleware.js with esbuild (#7087)
### Related Issues

> Fixes #7086
> Related to #7086

### 📋 Checklist

<!--
  Please keep your PR as a Draft until the checklist is complete
-->

#### Tests

- [x] The code changed/added as part of this PR has been covered with tests
- [x] All tests pass locally with `yarn test-unit`

#### Code Review

- [x] This PR has a concise title and thorough description useful to a reviewer
- [ ] Issue from task tracker has a link to this PR
2021-12-07 22:16:46 +00:00
Leo Lamprecht
35c8fc2729 Publish Canary
- @vercel/build-utils@2.12.3-canary.41
 - vercel@23.1.3-canary.64
 - @vercel/client@10.2.3-canary.42
 - vercel-plugin-middleware@0.0.0-canary.17
 - vercel-plugin-go@1.0.0-canary.29
 - vercel-plugin-node@1.12.2-canary.33
 - vercel-plugin-python@1.0.0-canary.30
 - vercel-plugin-ruby@1.0.0-canary.29
2021-12-07 21:13:41 +01:00
Leo Lamprecht
0a468fd6d7 Correctly clean up files for CLI Plugins (#7149)
* Correctly clean up files for CLI Plugins

* Cleaned up the code
2021-12-07 21:13:29 +01:00
98 changed files with 2557 additions and 518 deletions

View File

@@ -12,21 +12,39 @@ jobs:
name: Publish name: Publish
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: 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: with:
go-version: '1.13.15' 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: with:
node-version: 12 node-version: 14
- uses: actions/checkout@v1
- name: Install - name: Install
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
run: yarn install --check-files --frozen-lockfile --network-timeout 1000000 run: yarn install --check-files --frozen-lockfile --network-timeout 1000000
- name: Build - name: Build
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
run: yarn build run: yarn build
env: env:
GA_TRACKING_ID: ${{ secrets.GA_TRACKING_ID }} GA_TRACKING_ID: ${{ secrets.GA_TRACKING_ID }}
SENTRY_DSN: ${{ secrets.SENTRY_DSN }} SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
- name: Publish - name: Publish
if: ${{ steps.check-release.outputs.IS_RELEASE == 'true' }}
run: yarn publish-from-github run: yarn publish-from-github
env: env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN_ELEVATED }} NPM_TOKEN: ${{ secrets.NPM_TOKEN_ELEVATED }}

View 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
View File

@@ -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: 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) - [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/master/.github/CONTRIBUTING.md) - a guide on how to contribute to the examples repository - [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/master/LICENSE) - the standard MIT license under which these examples are published - [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. 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 ## 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. 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 ## 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 ## Get In Touch

View File

@@ -1,4 +1,4 @@
![Angular Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/angular.svg) ![Angular Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/angular.svg)
# Angular Example # Angular Example

View File

@@ -1,4 +1,4 @@
![Blitz Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/blitz.svg) ![Blitz Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/blitz.svg)
# Blitz.js Example # Blitz.js Example

View File

@@ -1,4 +1,4 @@
![React Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/react.svg) ![React Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/react.svg)
# React Example # React Example

View File

@@ -1,4 +1,4 @@
![Docusaurus Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/docusaurus.svg) ![Docusaurus Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/docusaurus.svg)
# Docusaurus Example # Docusaurus Example

View File

@@ -1,4 +1,4 @@
![Eleventy Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/eleventy.svg) ![Eleventy Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/eleventy.svg)
# Eleventy Example # Eleventy Example

View File

@@ -1,4 +1,4 @@
![Ember Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/ember.svg) ![Ember Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/ember.svg)
# Ember Example # Ember Example

View File

@@ -1,4 +1,4 @@
![Gatsby Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/gatsby.svg) ![Gatsby Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/gatsby.svg)
# Gatsby Example # Gatsby Example

View File

@@ -1,4 +1,4 @@
![Gridsome Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/gridsome.svg) ![Gridsome Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/gridsome.svg)
# Gridsome Example # Gridsome Example

View File

@@ -1,4 +1,4 @@
![Hexo Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/hexo.svg) ![Hexo Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/hexo.svg)
# Hexo Example # Hexo Example

View File

@@ -1,4 +1,4 @@
![Polymer Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/polymer.svg) ![Polymer Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/polymer.svg)
# Polymer Example # Polymer Example

View File

@@ -1,4 +1,4 @@
![Preact Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/preact.svg) ![Preact Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/preact.svg)
# Preact Example # Preact Example

View File

@@ -1,4 +1,4 @@
![RedwoodJS Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/redwoodjs.svg) ![RedwoodJS Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/redwoodjs.svg)
# RedwoodJS Example # RedwoodJS Example

View File

@@ -1,4 +1,4 @@
![Saber Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/saber.svg) ![Saber Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/saber.svg)
# Saber Example # Saber Example

View File

@@ -1,4 +1,4 @@
![Scully Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/scully.svg) ![Scully Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/scully.svg)
# Scully Example # Scully Example

22
examples/solidstart/.gitignore vendored Normal file
View 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

View File

@@ -0,0 +1,28 @@
![Solid Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/solid.svg)
# 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
[![Deploy with Vercel](https://vercel.com/button)](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
```

View File

@@ -0,0 +1,9 @@
{
"compilerOptions": {
"jsx": "preserve",
"jsxImportSource": "solid-js",
"paths": {
"~/*": ["./src/*"]
}
}
}

View 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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

View 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);
}

View 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>
);
}

View 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;
}
}

View 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>
);
}

View 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>
);
}

View 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() })]
});

View 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=

View File

@@ -1,4 +1,4 @@
![UmiJS Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/umi.svg) ![UmiJS Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/umi.svg)
# UmiJS Example # UmiJS Example

View File

@@ -1,4 +1,4 @@
![Vue.js Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/vue.svg) ![Vue.js Logo](https://github.com/vercel/vercel/blob/main/packages/frameworks/logos/vue.svg)
# Vue.js Example # Vue.js Example

View File

@@ -1,10 +1,10 @@
{ {
"name": "@vercel/build-utils", "name": "@vercel/build-utils",
"version": "2.12.3-canary.40", "version": "2.13.0",
"license": "MIT", "license": "MIT",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "./dist/index.d.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": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/vercel/vercel.git", "url": "https://github.com/vercel/vercel.git",
@@ -30,7 +30,7 @@
"@types/node-fetch": "^2.1.6", "@types/node-fetch": "^2.1.6",
"@types/semver": "6.0.0", "@types/semver": "6.0.0",
"@types/yazl": "^2.4.1", "@types/yazl": "^2.4.1",
"@vercel/frameworks": "0.5.1-canary.17", "@vercel/frameworks": "0.5.1-canary.19",
"@vercel/ncc": "0.24.0", "@vercel/ncc": "0.24.0",
"aggregate-error": "3.0.1", "aggregate-error": "3.0.1",
"async-retry": "1.2.3", "async-retry": "1.2.3",

View File

@@ -53,7 +53,7 @@ const getSourceFiles = async (workPath: string, ignoreFilter: any) => {
* @param packageName - the name of the package, for example `vercel-plugin-python` * @param packageName - the name of the package, for example `vercel-plugin-python`
* @param ext - the file extension, for example `.py` * @param ext - the file extension, for example `.py`
*/ */
export function convertRuntimeToPlugin( export function _experimental_convertRuntimeToPlugin(
buildRuntime: (options: BuildOptions) => Promise<{ output: Lambda }>, buildRuntime: (options: BuildOptions) => Promise<{ output: Lambda }>,
packageName: string, packageName: string,
ext: string ext: string
@@ -100,8 +100,6 @@ export function convertRuntimeToPlugin(
await fs.ensureDir(traceDir); await fs.ensureDir(traceDir);
let newPathsRuntime: Set<string> = new Set();
const entryRoot = join(outputPath, 'server', 'pages'); const entryRoot = join(outputPath, 'server', 'pages');
for (const entrypoint of Object.keys(entrypoints)) { for (const entrypoint of Object.keys(entrypoints)) {
@@ -118,17 +116,6 @@ export function convertRuntimeToPlugin(
}, },
}); });
// Legacy Runtimes tend to pollute the `workPath` with compiled results,
// because the `workPath` used to be a place that was a place where they could
// just put anything, but nowadays it's the working directory of the `vercel build`
// command, which is the place where the developer keeps their source files,
// so we don't want to pollute this space unnecessarily. That means we have to clean
// up files that were created by the build, which is done further below.
const sourceFilesAfterBuild = await getSourceFiles(
workPath,
ignoreFilter
);
// @ts-ignore This symbol is a private API // @ts-ignore This symbol is a private API
const lambdaFiles: Files = output[FILES_SYMBOL]; const lambdaFiles: Files = output[FILES_SYMBOL];
@@ -173,12 +160,9 @@ export function convertRuntimeToPlugin(
const entryPath = join(dirname(entrypoint), entryBase); const entryPath = join(dirname(entrypoint), entryBase);
const entry = join(entryRoot, entryPath); const entry = join(entryRoot, entryPath);
// We never want to link here, only copy, because the launcher // Create the parent directory of the API Route that will be created
// file often has the same name for every entrypoint, which means that // for the current entrypoint inside of `.output/server/pages/api`.
// every build for every entrypoint overwrites the launcher of the previous
// one, so linking would end with a broken reference.
await fs.ensureDir(dirname(entry)); await fs.ensureDir(dirname(entry));
await fs.copy(handlerFile.fsPath, entry);
// For compiled languages, the launcher file will be binary and therefore // For compiled languages, the launcher file will be binary and therefore
// won't try to import a user-provided request handler (instead, it will // won't try to import a user-provided request handler (instead, it will
@@ -199,8 +183,13 @@ export function convertRuntimeToPlugin(
let handlerContent = await fs.readFile(fsPath, encoding); let handlerContent = await fs.readFile(fsPath, encoding);
const importPaths = [ const importPaths = [
// This is the full entrypoint path, like `./api/test.py` // This is the full entrypoint path, like `./api/test.py`. In our tests
`./${entrypoint}`, // 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` // This is the entrypoint path without extension, like `api/test`
entrypoint.slice(0, -ext.length), entrypoint.slice(0, -ext.length),
]; ];
@@ -244,57 +233,15 @@ export function convertRuntimeToPlugin(
await fs.copy(handlerFile.fsPath, entry); await fs.copy(handlerFile.fsPath, entry);
} }
const newFilesEntrypoint: Array<string> = []; // Legacy Runtimes based on interpreted languages will create a new launcher file
const newDirectoriesEntrypoint: Array<string> = []; // 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
const preBuildFiles = Object.values(sourceFilesPreBuild).map(file => { // entrypoint. That's why, above, we copy the file contents into the new destination (and
return file.fsPath; // 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.
// Generate a list of directories and files that weren't present await fs.remove(handlerFile.fsPath);
// before the entrypoint was processed by the Legacy Runtime, so debug(`Removed temporary file "${handlerFile.fsPath}"`);
// that we can perform a cleanup later. We need to divide into files
// and directories because only cleaning up files might leave empty
// directories, and listing directories separately also speeds up the
// build because we can just delete them, which wipes all of their nested
// paths, instead of iterating through all files that should be deleted.
for (const file in sourceFilesAfterBuild) {
if (!sourceFilesPreBuild[file]) {
const path = sourceFilesAfterBuild[file].fsPath;
const dirPath = dirname(path);
// If none of the files that were present before the entrypoint
// was processed are contained within the directory we're looking
// at right now, then we know it's a newly added directory
// and it can therefore be removed later on.
const isNewDir = !preBuildFiles.some(filePath => {
return dirname(filePath).startsWith(dirPath);
});
// Check out the list of tracked directories that were
// newly added and see if one of them contains the path
// we're looking at.
const hasParentDir = newDirectoriesEntrypoint.some(dir => {
return path.startsWith(dir);
});
// If we have already tracked a directory that was newly
// added that sits above the file or directory that we're
// looking at, we don't need to add more entries to the list
// because when the parent will get removed in the future,
// all of its children (and therefore the path we're looking at)
// will automatically get removed anyways.
if (hasParentDir) {
continue;
}
if (isNewDir) {
newDirectoriesEntrypoint.push(dirPath);
} else {
newFilesEntrypoint.push(path);
}
}
}
const nft = `${entry}.nft.json`; const nft = `${entry}.nft.json`;
@@ -320,18 +267,8 @@ export function convertRuntimeToPlugin(
.filter(Boolean), .filter(Boolean),
}); });
await fs.ensureDir(dirname(nft));
await fs.writeFile(nft, json); await fs.writeFile(nft, json);
// Extend the list of directories and files that were created by the
// Legacy Runtime with the list of directories and files that were
// created for the entrypoint that was just processed above.
newPathsRuntime = new Set([
...newPathsRuntime,
...newFilesEntrypoint,
...newDirectoriesEntrypoint,
]);
// Add an entry that will later on be added to the `functions-manifest.json` // Add an entry that will later on be added to the `functions-manifest.json`
// file that is placed inside of the `.output` directory. // file that is placed inside of the `.output` directory.
pages[normalizePath(entryPath)] = { pages[normalizePath(entryPath)] = {
@@ -348,23 +285,9 @@ export function convertRuntimeToPlugin(
}; };
} }
// A list of all the files that were created by the Legacy Runtime,
// which we'd like to remove from the File System.
const toRemove = Array.from(newPathsRuntime).map(path => {
debug(`Removing ${path} as part of cleanup`);
return fs.remove(path);
});
// Once all the entrypoints have been processed, we'd like to
// remove all the files from `workPath` that originally weren't present
// before the Legacy Runtime began running, because the `workPath`
// is nowadays the directory in which the user keeps their source code, since
// we're no longer running separate parallel builds for every Legacy Runtime.
await Promise.all(toRemove);
// Add any Serverless Functions that were exposed by the Legacy Runtime // Add any Serverless Functions that were exposed by the Legacy Runtime
// to the `functions-manifest.json` file provided in `.output`. // to the `functions-manifest.json` file provided in `.output`.
await updateFunctionsManifest({ workPath, pages }); await _experimental_updateFunctionsManifest({ workPath, pages });
}; };
} }
@@ -384,7 +307,7 @@ async function readJson(filePath: string): Promise<{ [key: string]: any }> {
* If `.output/functions-manifest.json` exists, append to the pages * If `.output/functions-manifest.json` exists, append to the pages
* property. Otherwise write a new file. * property. Otherwise write a new file.
*/ */
export async function updateFunctionsManifest({ export async function _experimental_updateFunctionsManifest({
workPath, workPath,
pages, pages,
}: { }: {
@@ -412,7 +335,7 @@ export async function updateFunctionsManifest({
* Append routes to the `routes-manifest.json` file. * Append routes to the `routes-manifest.json` file.
* If the file does not exist, it will be created. * If the file does not exist, it will be created.
*/ */
export async function updateRoutesManifest({ export async function _experimental_updateRoutesManifest({
workPath, workPath,
redirects, redirects,
rewrites, rewrites,

View File

@@ -3,7 +3,13 @@ import { valid as validSemver } from 'semver';
import { parse as parsePath, extname } from 'path'; import { parse as parsePath, extname } from 'path';
import { Route, Source } from '@vercel/routing-utils'; import { Route, Source } from '@vercel/routing-utils';
import frameworkList, { Framework } from '@vercel/frameworks'; import frameworkList, { Framework } from '@vercel/frameworks';
import { PackageJson, Builder, Config, BuilderFunctions } from './types'; import {
PackageJson,
Builder,
Config,
BuilderFunctions,
ProjectSettings,
} from './types';
import { isOfficialRuntime } from './'; import { isOfficialRuntime } from './';
const slugToFramework = new Map<string | null, Framework>( const slugToFramework = new Map<string | null, Framework>(
frameworkList.map(f => [f.slug, f]) frameworkList.map(f => [f.slug, f])
@@ -20,14 +26,7 @@ interface Options {
tag?: 'canary' | 'latest' | string; tag?: 'canary' | 'latest' | string;
functions?: BuilderFunctions; functions?: BuilderFunctions;
ignoreBuildScript?: boolean; ignoreBuildScript?: boolean;
projectSettings?: { projectSettings?: ProjectSettings;
framework?: string | null;
devCommand?: string | null;
installCommand?: string | null;
buildCommand?: string | null;
outputDirectory?: string | null;
createdAt?: number;
};
cleanUrls?: boolean; cleanUrls?: boolean;
trailingSlash?: boolean; trailingSlash?: boolean;
featHandleMiss?: boolean; featHandleMiss?: boolean;

View 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 };
}

View File

@@ -1,4 +1,3 @@
import { createHash } from 'crypto';
import FileBlob from './file-blob'; import FileBlob from './file-blob';
import FileFsRef from './file-fs-ref'; import FileFsRef from './file-fs-ref';
import FileRef from './file-ref'; import FileRef from './file-ref';
@@ -81,14 +80,15 @@ export {
detectApiDirectory, detectApiDirectory,
detectApiExtensions, detectApiExtensions,
} from './detect-builders'; } from './detect-builders';
export { detectFileSystemAPI } from './detect-file-system-api';
export { detectFramework } from './detect-framework'; export { detectFramework } from './detect-framework';
export { DetectorFilesystem } from './detectors/filesystem'; export { DetectorFilesystem } from './detectors/filesystem';
export { readConfigFile } from './fs/read-config-file'; export { readConfigFile } from './fs/read-config-file';
export { normalizePath } from './fs/normalize-path'; export { normalizePath } from './fs/normalize-path';
export { export {
convertRuntimeToPlugin, _experimental_convertRuntimeToPlugin,
updateFunctionsManifest, _experimental_updateFunctionsManifest,
updateRoutesManifest, _experimental_updateRoutesManifest,
} from './convert-runtime-to-plugin'; } from './convert-runtime-to-plugin';
export * from './schemas'; export * from './schemas';
@@ -135,11 +135,3 @@ export const getPlatformEnv = (name: string): string | undefined => {
} }
return n; return n;
}; };
/**
* Helper function for generating file or directories names in `.output/inputs`
* for dependencies of files provided to the File System API.
*/
export const getInputHash = (source: Buffer | string): string => {
return createHash('sha1').update(source).digest('hex');
};

View File

@@ -29,7 +29,9 @@ export interface Config {
| number | number
| { [key: string]: string } | { [key: string]: string }
| BuilderFunctions | BuilderFunctions
| undefined; | ProjectSettings
| undefined
| null;
maxLambdaSize?: string; maxLambdaSize?: string;
includeFiles?: string | string[]; includeFiles?: string | string[];
excludeFiles?: string | string[]; excludeFiles?: string | string[];
@@ -41,11 +43,12 @@ export interface Config {
zeroConfig?: boolean; zeroConfig?: boolean;
import?: { [key: string]: string }; import?: { [key: string]: string };
functions?: BuilderFunctions; functions?: BuilderFunctions;
projectSettings?: ProjectSettings;
outputDirectory?: string; outputDirectory?: string;
installCommand?: string; installCommand?: string;
buildCommand?: string; buildCommand?: string;
devCommand?: string; devCommand?: string;
framework?: string; framework?: string | null;
nodeVersion?: string; nodeVersion?: string;
} }
@@ -351,3 +354,17 @@ export interface BuilderFunctions {
excludeFiles?: string; 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;
}

View File

@@ -1,7 +1,7 @@
import { join } from 'path'; import { join } from 'path';
import fs from 'fs-extra'; import fs from 'fs-extra';
import { BuildOptions, createLambda, FileFsRef } from '../src'; import { BuildOptions, createLambda, FileFsRef } from '../src';
import { convertRuntimeToPlugin } from '../src/convert-runtime-to-plugin'; import { _experimental_convertRuntimeToPlugin } from '../src/convert-runtime-to-plugin';
async function fsToJson(dir: string, output: Record<string, any> = {}) { async function fsToJson(dir: string, output: Record<string, any> = {}) {
const files = await fs.readdir(dir); const files = await fs.readdir(dir);
@@ -63,7 +63,11 @@ describe('convert-runtime-to-plugin', () => {
}; };
const packageName = 'vercel-plugin-python'; const packageName = 'vercel-plugin-python';
const build = await convertRuntimeToPlugin(buildRuntime, packageName, ext); const build = await _experimental_convertRuntimeToPlugin(
buildRuntime,
packageName,
ext
);
await build({ workPath }); await build({ workPath });

View 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: [] },
});
});
});

View File

@@ -285,6 +285,14 @@ it('should support require by path for legacy builders', () => {
it( it(
'should have correct $PATH when running `runPackageJsonScript()` with yarn', 'should have correct $PATH when running `runPackageJsonScript()` with yarn',
async () => { 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'); const fixture = path.join(__dirname, 'fixtures', '19-yarn-v2');
await runNpmInstall(fixture); await runNpmInstall(fixture);
await runPackageJsonScript(fixture, 'env'); await runPackageJsonScript(fixture, 'env');

View File

@@ -34,7 +34,7 @@ Finally, [connect your Git repository to Vercel](https://vercel.com/docs/git) an
## Documentation ## 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 ## Local Development

View File

@@ -1,6 +1,6 @@
{ {
"name": "vercel", "name": "vercel",
"version": "23.1.3-canary.63", "version": "23.1.3-canary.72",
"preferGlobal": true, "preferGlobal": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "The command-line interface for Vercel", "description": "The command-line interface for Vercel",
@@ -43,14 +43,14 @@
"node": ">= 12" "node": ">= 12"
}, },
"dependencies": { "dependencies": {
"@vercel/build-utils": "2.12.3-canary.40", "@vercel/build-utils": "2.13.0",
"@vercel/go": "1.2.4-canary.4", "@vercel/go": "1.2.4-canary.4",
"@vercel/node": "1.12.2-canary.7", "@vercel/node": "1.12.2-canary.7",
"@vercel/python": "2.1.2-canary.1", "@vercel/python": "2.1.2-canary.2",
"@vercel/ruby": "1.2.10-canary.0", "@vercel/ruby": "1.2.10-canary.0",
"update-notifier": "4.1.0", "update-notifier": "4.1.0",
"vercel-plugin-middleware": "0.0.0-canary.16", "vercel-plugin-middleware": "0.0.0-canary.24",
"vercel-plugin-node": "1.12.2-canary.32" "vercel-plugin-node": "1.12.2-canary.39"
}, },
"devDependencies": { "devDependencies": {
"@next/env": "11.1.2", "@next/env": "11.1.2",
@@ -90,7 +90,8 @@
"@types/update-notifier": "5.1.0", "@types/update-notifier": "5.1.0",
"@types/which": "1.3.2", "@types/which": "1.3.2",
"@types/write-json-file": "2.2.1", "@types/write-json-file": "2.2.1",
"@vercel/frameworks": "0.5.1-canary.17", "@vercel/client": "10.2.3-canary.50",
"@vercel/frameworks": "0.5.1-canary.19",
"@vercel/ncc": "0.24.0", "@vercel/ncc": "0.24.0",
"@vercel/nft": "0.17.0", "@vercel/nft": "0.17.0",
"@zeit/fun": "0.11.2", "@zeit/fun": "0.11.2",

View File

@@ -6,6 +6,9 @@ import {
scanParentDirs, scanParentDirs,
spawnAsync, spawnAsync,
glob as buildUtilsGlob, glob as buildUtilsGlob,
detectFileSystemAPI,
detectBuilders,
PackageJson,
} from '@vercel/build-utils'; } from '@vercel/build-utils';
import { nodeFileTrace } from '@vercel/nft'; import { nodeFileTrace } from '@vercel/nft';
import Sema from 'async-sema'; import Sema from 'async-sema';
@@ -19,6 +22,7 @@ import pluralize from 'pluralize';
import Client from '../util/client'; import Client from '../util/client';
import { VercelConfig } from '../util/dev/types'; import { VercelConfig } from '../util/dev/types';
import { emoji, prependEmoji } from '../util/emoji'; import { emoji, prependEmoji } from '../util/emoji';
import { CantParseJSONFile } from '../util/errors-ts';
import getArgs from '../util/get-args'; import getArgs from '../util/get-args';
import handleError from '../util/handle-error'; import handleError from '../util/handle-error';
import confirm from '../util/input/confirm'; import confirm from '../util/input/confirm';
@@ -32,6 +36,7 @@ import { loadCliPlugins } from '../util/plugins';
import { findFramework } from '../util/projects/find-framework'; import { findFramework } from '../util/projects/find-framework';
import { VERCEL_DIR } from '../util/projects/link'; import { VERCEL_DIR } from '../util/projects/link';
import { readProjectSettings } from '../util/projects/project-settings'; import { readProjectSettings } from '../util/projects/project-settings';
import readJSONFile from '../util/read-json-file';
import pull from './pull'; import pull from './pull';
const sema = new Sema(16, { const sema = new Sema(16, {
@@ -146,6 +151,36 @@ export default async function main(client: Client) {
process.chdir(cwd); 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); const framework = findFramework(project.settings.framework);
// If this is undefined, we bail. If it is null, then findFramework should return "Other", // 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.... // so this should really never happen, but just in case....

View File

@@ -166,8 +166,8 @@ export default async (client: Client) => {
return pathValidation.exitCode; return pathValidation.exitCode;
} }
const { isFile, path } = pathValidation; const { path } = pathValidation;
const autoConfirm = argv['--confirm'] || isFile; const autoConfirm = argv['--confirm'];
// deprecate --name // deprecate --name
if (argv['--name']) { if (argv['--name']) {
@@ -192,7 +192,7 @@ export default async (client: Client) => {
let newProjectName = null; let newProjectName = null;
let rootDirectory = project ? project.rootDirectory : null; let rootDirectory = project ? project.rootDirectory : null;
let sourceFilesOutsideRootDirectory = true; let sourceFilesOutsideRootDirectory: boolean | undefined = true;
if (status === 'not_linked') { if (status === 'not_linked') {
const shouldStartSetup = const shouldStartSetup =
@@ -229,8 +229,7 @@ export default async (client: Client) => {
// user input. // user input.
const detectedProjectName = getProjectName({ const detectedProjectName = getProjectName({
argv, argv,
nowConfig: localConfig || {}, nowConfig: localConfig,
isFile,
paths, paths,
}); });
@@ -447,9 +446,9 @@ export default async (client: Client) => {
forceNew: argv['--force'], forceNew: argv['--force'],
withCache: argv['--with-cache'], withCache: argv['--with-cache'],
prebuilt: argv['--prebuilt'], prebuilt: argv['--prebuilt'],
rootDirectory,
quiet, quiet,
wantsPublic: argv['--public'] || localConfig.public, wantsPublic: argv['--public'] || localConfig.public,
isFile,
type: null, type: null,
nowConfig: localConfig, nowConfig: localConfig,
regions, regions,
@@ -471,7 +470,7 @@ export default async (client: Client) => {
[sourcePath], [sourcePath],
createArgs, createArgs,
org, org,
!project && !isFile, !project,
path path
); );
@@ -654,8 +653,7 @@ export default async (client: Client) => {
client, client,
deployment, deployment,
deployStamp, deployStamp,
!argv['--no-clipboard'], !argv['--no-clipboard']
isFile
); );
}; };
@@ -790,8 +788,7 @@ const printDeploymentStatus = async (
}; };
}, },
deployStamp: () => string, deployStamp: () => string,
isClipboardEnabled: boolean, isClipboardEnabled: boolean
isFile: boolean
) => { ) => {
indications = indications || []; indications = indications || [];
const isProdDeployment = target === 'production'; const isProdDeployment = target === 'production';
@@ -813,7 +810,7 @@ const printDeploymentStatus = async (
// print preview/production url // print preview/production url
let previewUrl: string; let previewUrl: string;
let isWildcard: boolean; let isWildcard: boolean;
if (!isFile && Array.isArray(aliasList) && aliasList.length > 0) { if (Array.isArray(aliasList) && aliasList.length > 0) {
const previewUrlInfo = await getPreferredPreviewURL(client, aliasList); const previewUrlInfo = await getPreferredPreviewURL(client, aliasList);
if (previewUrlInfo) { if (previewUrlInfo) {
isWildcard = previewUrlInfo.isWildcard; isWildcard = previewUrlInfo.isWildcard;

View File

@@ -11,9 +11,10 @@ import logo from '../../util/output/logo';
import cmd from '../../util/output/cmd'; import cmd from '../../util/output/cmd';
import highlight from '../../util/output/highlight'; import highlight from '../../util/output/highlight';
import dev from './dev'; import dev from './dev';
import readPackage from '../../util/read-package';
import readConfig from '../../util/config/read-config'; import readConfig from '../../util/config/read-config';
import readJSONFile from '../../util/read-json-file';
import { getPkgName, getCommandName } from '../../util/pkg-name'; import { getPkgName, getCommandName } from '../../util/pkg-name';
import { CantParseJSONFile } from '../../util/errors-ts';
const COMMAND_CONFIG = { const COMMAND_CONFIG = {
dev: ['dev'], dev: ['dev'],
@@ -96,33 +97,34 @@ export default async function main(client: Client) {
const [dir = '.'] = args; const [dir = '.'] = args;
const nowJson = await readConfig(dir); const vercelConfig = await readConfig(dir);
// @ts-ignore: Because `nowJson` could be one of three different types
const hasBuilds = nowJson && nowJson.builds && nowJson.builds.length > 0;
if (!nowJson || !hasBuilds) { const hasBuilds =
const pkg = await readPackage(path.join(dir, 'package.json')); vercelConfig &&
'builds' in vercelConfig &&
vercelConfig.builds &&
vercelConfig.builds.length > 0;
if (pkg) { if (!vercelConfig || !hasBuilds) {
const { scripts } = pkg as PackageJson; const pkg = await readJSONFile<PackageJson>(path.join(dir, 'package.json'));
if ( if (pkg instanceof CantParseJSONFile) {
scripts && client.output.error('Could not parse package.json');
scripts.dev && return 1;
/\b(now|vercel)\b\W+\bdev\b/.test(scripts.dev) }
) {
client.output.error( if (/\b(now|vercel)\b\W+\bdev\b/.test(pkg?.scripts?.dev || '')) {
`${cmd( client.output.error(
`${getPkgName()} dev` `${cmd(
)} must not recursively invoke itself. Check the Development Command in the Project Settings or the ${cmd( `${getPkgName()} dev`
'dev' )} must not recursively invoke itself. Check the Development Command in the Project Settings or the ${cmd(
)} script in ${cmd('package.json')}` 'dev'
); )} script in ${cmd('package.json')}`
client.output.error( );
`Learn More: https://vercel.link/recursive-invocation-of-commands` client.output.error(
); `Learn More: https://vercel.link/recursive-invocation-of-commands`
return 1; );
} return 1;
} }
} }

View File

@@ -1,3 +1,5 @@
export type ProjectSettings = import('@vercel/build-utils').ProjectSettings;
export type Primitive = export type Primitive =
| bigint | bigint
| boolean | boolean
@@ -239,16 +241,6 @@ export interface ProjectEnvVariable {
gitBranch?: string; 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 { export interface Project extends ProjectSettings {
id: string; id: string;
name: string; name: string;
@@ -260,8 +252,6 @@ export interface Project extends ProjectSettings {
framework?: string | null; framework?: string | null;
rootDirectory?: string | null; rootDirectory?: string | null;
latestDeployments?: Partial<Deployment>[]; latestDeployments?: Partial<Deployment>[];
autoExposeSystemEnvs?: boolean;
sourceFilesOutsideRootDirectory: boolean;
} }
export interface Org { export interface Org {

View File

@@ -6,14 +6,14 @@ import getLocalConfigPath from './local-path';
export default async function readConfig(dir: string) { export default async function readConfig(dir: string) {
const pkgFilePath = getLocalConfigPath(join(process.cwd(), dir)); const pkgFilePath = getLocalConfigPath(join(process.cwd(), dir));
const result = await readJSONFile(pkgFilePath); const result = await readJSONFile<VercelConfig>(pkgFilePath);
if (result instanceof CantParseJSONFile) { if (result instanceof CantParseJSONFile) {
return result; return result;
} }
if (result) { if (result) {
return result as VercelConfig; return result;
} }
return null; return null;

View File

@@ -52,6 +52,7 @@ export default async function processDeployment({
isSettingUpProject: boolean; isSettingUpProject: boolean;
skipAutoDetectionConfirmation?: boolean; skipAutoDetectionConfirmation?: boolean;
cwd?: string; cwd?: string;
rootDirectory?: string;
}) { }) {
let { let {
now, now,
@@ -64,6 +65,7 @@ export default async function processDeployment({
nowConfig, nowConfig,
quiet, quiet,
prebuilt, prebuilt,
rootDirectory,
} = args; } = args;
const { debug } = output; const { debug } = output;
@@ -86,6 +88,7 @@ export default async function processDeployment({
force, force,
withCache, withCache,
prebuilt, prebuilt,
rootDirectory,
skipAutoDetectionConfirmation, skipAutoDetectionConfirmation,
}; };

View File

@@ -40,6 +40,7 @@ import {
detectApiExtensions, detectApiExtensions,
spawnCommand, spawnCommand,
isOfficialRuntime, isOfficialRuntime,
detectFileSystemAPI,
} from '@vercel/build-utils'; } from '@vercel/build-utils';
import frameworkList from '@vercel/frameworks'; 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 (builders) {
if (this.devCommand) { if (this.devCommand) {
builders = builders.filter(filterFrontendBuilds); builders = builders.filter(filterFrontendBuilds);

View File

@@ -8,7 +8,6 @@ import {
} from './errors-ts'; } from './errors-ts';
import humanizePath from './humanize-path'; import humanizePath from './humanize-path';
import readJSONFile from './read-json-file'; import readJSONFile from './read-json-file';
import readPackage from './read-package';
import { VercelConfig } from './dev/types'; import { VercelConfig } from './dev/types';
import { Output } from './output'; import { Output } from './output';
@@ -39,12 +38,12 @@ export default async function getConfig(
output.debug( output.debug(
`Found config in provided --local-config path ${localFilePath}` `Found config in provided --local-config path ${localFilePath}`
); );
const localConfig = await readJSONFile(localFilePath); const localConfig = await readJSONFile<VercelConfig>(localFilePath);
if (localConfig instanceof CantParseJSONFile) { if (localConfig instanceof CantParseJSONFile) {
return localConfig; return localConfig;
} }
if (localConfig !== null) { if (localConfig !== null) {
config = localConfig as VercelConfig; config = localConfig;
config[fileNameSymbol] = configFile; config[fileNameSymbol] = configFile;
return config; return config;
} }
@@ -54,8 +53,8 @@ export default async function getConfig(
const vercelFilePath = path.resolve(localPath, 'vercel.json'); const vercelFilePath = path.resolve(localPath, 'vercel.json');
const nowFilePath = path.resolve(localPath, 'now.json'); const nowFilePath = path.resolve(localPath, 'now.json');
const [vercelConfig, nowConfig] = await Promise.all([ const [vercelConfig, nowConfig] = await Promise.all([
readJSONFile(vercelFilePath), readJSONFile<VercelConfig>(vercelFilePath),
readJSONFile(nowFilePath), readJSONFile<VercelConfig>(nowFilePath),
]); ]);
if (vercelConfig instanceof CantParseJSONFile) { if (vercelConfig instanceof CantParseJSONFile) {
return vercelConfig; return vercelConfig;
@@ -68,41 +67,17 @@ export default async function getConfig(
} }
if (vercelConfig !== null) { if (vercelConfig !== null) {
output.debug(`Found config in file "${vercelFilePath}"`); output.debug(`Found config in file "${vercelFilePath}"`);
config = vercelConfig as VercelConfig; config = vercelConfig;
config[fileNameSymbol] = 'vercel.json'; config[fileNameSymbol] = 'vercel.json';
return config; return config;
} }
if (nowConfig !== null) { if (nowConfig !== null) {
output.debug(`Found config in file "${nowFilePath}"`); output.debug(`Found config in file "${nowFilePath}"`);
config = nowConfig as VercelConfig; config = nowConfig;
config[fileNameSymbol] = 'now.json'; config[fileNameSymbol] = 'now.json';
return config; 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 // If we couldn't find the config anywhere return error
return new CantFindConfig( return new CantFindConfig([vercelFilePath, nowFilePath].map(humanizePath));
[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;
} }

View File

@@ -4,14 +4,12 @@ import { VercelConfig } from '@vercel/client';
export interface GetProjectNameOptions { export interface GetProjectNameOptions {
argv: { '--name'?: string }; argv: { '--name'?: string };
nowConfig?: VercelConfig; nowConfig?: VercelConfig;
isFile?: boolean;
paths?: string[]; paths?: string[];
} }
export default function getProjectName({ export default function getProjectName({
argv, argv,
nowConfig = {}, nowConfig = {},
isFile = false,
paths = [], paths = [],
}: GetProjectNameOptions) { }: GetProjectNameOptions) {
const nameCli = argv['--name']; const nameCli = argv['--name'];
@@ -24,10 +22,6 @@ export default function getProjectName({
return nowConfig.name; return nowConfig.name;
} }
if (isFile || paths.length > 1) {
return 'files';
}
// Otherwise, use the name of the directory // Otherwise, use the name of the directory
return basename(paths[0] || ''); return basename(paths[0] || '');
} }

View File

@@ -30,13 +30,13 @@ export interface NowOptions {
export interface CreateOptions { export interface CreateOptions {
// Legacy // Legacy
nowConfig?: VercelConfig; nowConfig?: VercelConfig;
isFile?: boolean;
// Latest // Latest
name: string; name: string;
project?: string; project?: string;
wantsPublic: boolean; wantsPublic: boolean;
prebuilt?: boolean; prebuilt?: boolean;
rootDirectory?: string;
meta: Dictionary<string>; meta: Dictionary<string>;
regions?: string[]; regions?: string[];
quiet?: boolean; quiet?: boolean;
@@ -113,6 +113,7 @@ export default class Now extends EventEmitter {
name, name,
project, project,
prebuilt = false, prebuilt = false,
rootDirectory,
wantsPublic, wantsPublic,
meta, meta,
regions, regions,
@@ -168,6 +169,7 @@ export default class Now extends EventEmitter {
skipAutoDetectionConfirmation, skipAutoDetectionConfirmation,
cwd, cwd,
prebuilt, prebuilt,
rootDirectory,
}); });
if (deployment && deployment.warnings) { if (deployment && deployment.warnings) {

View File

@@ -11,7 +11,7 @@ export default async function inputProject(
client: Client, client: Client,
org: Org, org: Org,
detectedProjectName: string, detectedProjectName: string,
autoConfirm: boolean autoConfirm = false
): Promise<Project | string> { ): Promise<Project | string> {
const { output } = client; const { output } = client;
const slugifiedName = slugify(detectedProjectName); const slugifiedName = slugify(detectedProjectName);

View File

@@ -7,7 +7,7 @@ import { validateRootDirectory } from '../validate-paths';
export async function inputRootDirectory( export async function inputRootDirectory(
cwd: string, cwd: string,
output: Output, output: Output,
autoConfirm: boolean autoConfirm = false
) { ) {
if (autoConfirm) { if (autoConfirm) {
return null; return null;

View File

@@ -158,7 +158,6 @@ export default async function setupAndLink(
withCache: undefined, withCache: undefined,
quiet, quiet,
wantsPublic: localConfig?.public || false, wantsPublic: localConfig?.public || false,
isFile,
nowConfig: localConfig, nowConfig: localConfig,
regions: undefined, regions: undefined,
meta: {}, meta: {},
@@ -179,7 +178,7 @@ export default async function setupAndLink(
[sourcePath], [sourcePath],
createArgs, createArgs,
org, org,
!isFile, true,
path path
); );

View File

@@ -1,9 +1,9 @@
import fs from 'fs-extra'; import fs from 'fs-extra';
import { CantParseJSONFile } from './errors-ts'; import { CantParseJSONFile } from './errors-ts';
export default async function readJSONFile( export default async function readJSONFile<T>(
file: string file: string
): Promise<Object | null | CantParseJSONFile> { ): Promise<T | null | CantParseJSONFile> {
const content = await readFileSafe(file); const content = await readFileSafe(file);
if (content === null) { if (content === null) {
return content; return content;

View File

@@ -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;
}

View File

@@ -4,7 +4,6 @@ import { Output } from './output';
import chalk from 'chalk'; import chalk from 'chalk';
import { homedir } from 'os'; import { homedir } from 'os';
import confirm from './input/confirm'; import confirm from './input/confirm';
import { prependEmoji, emoji } from './emoji';
import toHumanPath from './humanize-path'; import toHumanPath from './humanize-path';
const stat = promisify(lstatRaw); const stat = promisify(lstatRaw);
@@ -54,10 +53,7 @@ export async function validateRootDirectory(
export default async function validatePaths( export default async function validatePaths(
output: Output, output: Output,
paths: string[] paths: string[]
): Promise< ): Promise<{ valid: true; path: string } | { valid: false; exitCode: number }> {
| { valid: true; path: string; isFile: boolean }
| { valid: false; exitCode: number }
> {
// can't deploy more than 1 path // can't deploy more than 1 path
if (paths.length > 1) { if (paths.length > 1) {
output.print(`${chalk.red('Error!')} Can't deploy more than one path.\n`); 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 }; return { valid: false, exitCode: 1 };
} }
const isFile = pathStat && !pathStat.isDirectory(); if (!pathStat.isDirectory()) {
if (isFile) { output.prettyError({
output.print( message: 'Support for single file deployments has been removed.',
`${prependEmoji( link: 'https://vercel.link/no-single-file-deployments',
'Deploying files with Vercel is deprecated (https://vercel.link/faq-deploy-file)', });
emoji('warning') return { valid: false, exitCode: 1 };
)}\n`
);
} }
// ask confirmation if the directory is home // 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 };
} }

View 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'
);
});
});

View File

@@ -1913,59 +1913,6 @@ test('create a production deployment', async t => {
t.is(deployment.target, 'production', JSON.stringify(deployment, null, 2)); 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 => { test('use build-env', async t => {
const directory = fixture('build-env'); const directory = fixture('build-env');

View File

@@ -10,7 +10,7 @@ describe('getProjectName', () => {
expect(project).toEqual('abc'); expect(project).toEqual('abc');
}); });
it('should work with now.json', () => { it('should work with `vercel.json` config', () => {
const project = getProjectName({ const project = getProjectName({
argv: {}, argv: {},
nowConfig: { name: 'abc' }, nowConfig: { name: 'abc' },
@@ -18,24 +18,6 @@ describe('getProjectName', () => {
expect(project).toEqual('abc'); 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', () => { it('should work with a directory', () => {
const project = getProjectName({ const project = getProjectName({
argv: {}, argv: {},

View File

@@ -6,3 +6,5 @@ node_modules
!tests/fixtures/nowignore/node_modules !tests/fixtures/nowignore/node_modules
!tests/fixtures/vercelignore-allow-nodemodules/node_modules !tests/fixtures/vercelignore-allow-nodemodules/node_modules
!tests/fixtures/vercelignore-allow-nodemodules/sub/node_modules !tests/fixtures/vercelignore-allow-nodemodules/sub/node_modules
!tests/fixtures/file-system-api/.output
!tests/fixtures/file-system-api-root-directory/**/.output

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/client", "name": "@vercel/client",
"version": "10.2.3-canary.41", "version": "10.2.3-canary.50",
"main": "dist/index.js", "main": "dist/index.js",
"typings": "dist/index.d.ts", "typings": "dist/index.d.ts",
"homepage": "https://vercel.com", "homepage": "https://vercel.com",
@@ -40,7 +40,7 @@
] ]
}, },
"dependencies": { "dependencies": {
"@vercel/build-utils": "2.12.3-canary.40", "@vercel/build-utils": "2.13.0",
"@zeit/fetch": "5.2.0", "@zeit/fetch": "5.2.0",
"async-retry": "1.2.3", "async-retry": "1.2.3",
"async-sema": "3.0.0", "async-sema": "3.0.0",

View File

@@ -1,12 +1,12 @@
import { lstatSync } from 'fs-extra'; import { lstatSync } from 'fs-extra';
import { relative, isAbsolute } from 'path'; import { relative, isAbsolute } from 'path';
import hashes, { mapToObject } from './utils/hashes'; import { hashes, mapToObject, resolveNftJsonFiles } from './utils/hashes';
import { upload } from './upload'; import { upload } from './upload';
import { buildFileTree, createDebug, parseVercelConfig } from './utils'; import { buildFileTree, createDebug, parseVercelConfig } from './utils';
import { DeploymentError } from './errors'; import { DeploymentError } from './errors';
import { import {
NowConfig, VercelConfig,
VercelClientOptions, VercelClientOptions,
DeploymentOptions, DeploymentOptions,
DeploymentEventType, DeploymentEventType,
@@ -16,7 +16,7 @@ export default function buildCreateDeployment() {
return async function* createDeployment( return async function* createDeployment(
clientOptions: VercelClientOptions, clientOptions: VercelClientOptions,
deploymentOptions: DeploymentOptions = {}, deploymentOptions: DeploymentOptions = {},
nowConfig: NowConfig = {} nowConfig: VercelConfig = {}
): AsyncIterableIterator<{ type: DeploymentEventType; payload: any }> { ): AsyncIterableIterator<{ type: DeploymentEventType; payload: any }> {
const { path } = clientOptions; const { path } = clientOptions;
@@ -74,12 +74,7 @@ export default function buildCreateDeployment() {
debug(`Provided 'path' is a single file`); debug(`Provided 'path' is a single file`);
} }
let { fileList } = await buildFileTree( let { fileList } = await buildFileTree(path, clientOptions, debug);
path,
clientOptions.isDirectory,
debug,
clientOptions.prebuilt
);
let configPath: string | undefined; let configPath: string | undefined;
if (!nowConfig) { 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`); debug(`Yielding a 'hashes-calculated' event with ${files.size} hashes`);
yield { type: 'hashes-calculated', payload: mapToObject(files) }; yield { type: 'hashes-calculated', payload: mapToObject(files) };

View File

@@ -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'; import { Header, Route, Redirect, Rewrite } from '@vercel/routing-utils';
export { DeploymentEventType } from './utils'; export { DeploymentEventType } from './utils';
@@ -15,6 +19,7 @@ export interface VercelClientOptions {
apiUrl?: string; apiUrl?: string;
force?: boolean; force?: boolean;
prebuilt?: boolean; prebuilt?: boolean;
rootDirectory?: string;
withCache?: boolean; withCache?: boolean;
userAgent?: string; userAgent?: string;
defaultName?: string; defaultName?: string;
@@ -123,12 +128,7 @@ export interface VercelConfig {
scope?: string; scope?: string;
alias?: string | string[]; alias?: string | string[];
regions?: string[]; regions?: string[];
projectSettings?: { projectSettings?: ProjectSettings;
devCommand?: string | null;
buildCommand?: string | null;
outputDirectory?: string | null;
framework?: string | null;
};
} }
/** /**
@@ -154,9 +154,5 @@ export interface DeploymentOptions {
name?: string; name?: string;
public?: boolean; public?: boolean;
meta?: Dictionary<string>; meta?: Dictionary<string>;
projectSettings?: { projectSettings?: ProjectSettings;
devCommand?: string | null;
buildCommand?: string | null;
outputDirectory?: string | null;
};
} }

View File

@@ -1,6 +1,7 @@
import { createHash } from 'crypto'; import { createHash } from 'crypto';
import fs from 'fs-extra'; import fs from 'fs-extra';
import { Sema } from 'async-sema'; import { Sema } from 'async-sema';
import { join, dirname } from 'path';
export interface DeploymentFile { export interface DeploymentFile {
names: string[]; names: string[];
@@ -15,9 +16,7 @@ export interface DeploymentFile {
* @return {String} hex digest * @return {String} hex digest
*/ */
function hash(buf: Buffer): string { function hash(buf: Buffer): string {
return createHash('sha1') return createHash('sha1').update(buf).digest('hex');
.update(buf)
.digest('hex');
} }
/** /**
@@ -39,34 +38,68 @@ export const mapToObject = (
/** /**
* Computes hashes for the contents of each file given. * Computes hashes for the contents of each file given.
* *
* @param {Array} of {String} full paths * @param files - absolute file paths
* @return {Map} * @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>> { export async function hashes(
const map = new Map<string, DeploymentFile>(); files: string[],
map = new Map<string, DeploymentFile>()
): Promise<Map<string, DeploymentFile>> {
const semaphore = new Sema(100); const semaphore = new Sema(100);
await Promise.all( await Promise.all(
files.map( files.map(async (name: string): Promise<void> => {
async (name: string): Promise<void> => { await semaphore.acquire();
await semaphore.acquire(); const data = await fs.readFile(name);
const data = await fs.readFile(name); const { mode } = await fs.stat(name);
const { mode } = await fs.stat(name);
const h = hash(data); const h = hash(data);
const entry = map.get(h); const entry = map.get(h);
if (entry) { if (entry) {
entry.names.push(name); const names = new Set(entry.names);
} else { names.add(name);
map.set(h, { names: [name], data, mode }); entry.names = [...names];
} } else {
map.set(h, { names: [name], data, mode });
semaphore.release();
} }
)
semaphore.release();
})
); );
return map; 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);
}

View File

@@ -1,7 +1,7 @@
import { DeploymentFile } from './hashes'; import { DeploymentFile } from './hashes';
import { FetchOptions } from '@zeit/fetch'; import { FetchOptions } from '@zeit/fetch';
import { nodeFetch, zeitFetch } from './fetch'; import { nodeFetch, zeitFetch } from './fetch';
import { join, sep, relative } from 'path'; import { join, sep, relative, posix } from 'path';
import { URL } from 'url'; import { URL } from 'url';
import ignore from 'ignore'; import ignore from 'ignore';
type Ignore = ReturnType<typeof ignore>; type Ignore = ReturnType<typeof ignore>;
@@ -81,13 +81,16 @@ const maybeRead = async function <T>(path: string, default_: T) {
export async function buildFileTree( export async function buildFileTree(
path: string | string[], path: string | string[],
isDirectory: boolean, {
debug: Debug, isDirectory,
prebuilt?: boolean prebuilt,
rootDirectory,
}: Pick<VercelClientOptions, 'isDirectory' | 'prebuilt' | 'rootDirectory'>,
debug: Debug
): Promise<{ fileList: string[]; ignoreList: string[] }> { ): Promise<{ fileList: string[]; ignoreList: string[] }> {
const ignoreList: string[] = []; const ignoreList: string[] = [];
let fileList: 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(`Found ${ignores.length} rules in .vercelignore`);
debug('Building file tree...'); debug('Building file tree...');
@@ -119,37 +122,50 @@ export async function buildFileTree(
export async function getVercelIgnore( export async function getVercelIgnore(
cwd: string | string[], cwd: string | string[],
prebuilt?: boolean prebuilt?: boolean,
rootDirectory?: string
): Promise<{ ig: Ignore; ignores: string[] }> { ): Promise<{ ig: Ignore; ignores: string[] }> {
const ignores: string[] = prebuilt let ignores: string[] = [];
? ['*', '!.output', '!.output/**']
: [ const outputDir = posix.join(rootDirectory || '', '.output');
'.hg',
'.git', if (prebuilt) {
'.gitmodules', ignores.push('*');
'.svn', const parts = outputDir.split('/');
'.cache', parts.forEach((_, i) => {
'.next', const level = parts.slice(0, i + 1).join('/');
'.now', ignores.push(`!${level}`);
'.vercel', });
'.npmignore', ignores.push(`!${outputDir}/**`);
'.dockerignore', } else {
'.gitignore', ignores = [
'.*.swp', '.hg',
'.DS_Store', '.git',
'.wafpicke-*', '.gitmodules',
'.lock-wscript', '.svn',
'.env.local', '.cache',
'.env.*.local', '.next',
'.venv', '.now',
'npm-debug.log', '.vercel',
'config.gypi', '.npmignore',
'node_modules', '.dockerignore',
'__pycache__', '.gitignore',
'venv', '.*.swp',
'CVS', '.DS_Store',
'.output', '.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 cwds = Array.isArray(cwd) ? cwd : [cwd];
const files = await Promise.all( const files = await Promise.all(
@@ -250,39 +266,31 @@ export const prepareFiles = (
files: Map<string, DeploymentFile>, files: Map<string, DeploymentFile>,
clientOptions: VercelClientOptions clientOptions: VercelClientOptions
): PreparedFile[] => { ): PreparedFile[] => {
const preparedFiles = [...files.keys()].reduce( const preparedFiles: PreparedFile[] = [];
(acc: PreparedFile[], sha: string): PreparedFile[] => { for (const [sha, file] of files) {
const next = [...acc]; for (const name of file.names) {
let fileName: string;
const file = files.get(sha) as DeploymentFile; if (clientOptions.isDirectory) {
// Directory
for (const name of file.names) { fileName =
let fileName: string; typeof clientOptions.path === 'string'
? relative(clientOptions.path, name)
if (clientOptions.isDirectory) { : name;
// Directory } else {
fileName = // Array of files or single file
typeof clientOptions.path === 'string' const segments = name.split(sep);
? relative(clientOptions.path, name) fileName = segments[segments.length - 1];
: 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,
});
} }
return next; preparedFiles.push({
}, file: isWin ? fileName.replace(/\\/g, '/') : fileName,
[] size: file.data.byteLength || file.data.length,
); mode: file.mode,
sha,
});
}
}
return preparedFiles; return preparedFiles;
}; };

View File

@@ -0,0 +1 @@
foo

View File

@@ -0,0 +1 @@
bar

View File

@@ -0,0 +1 @@
bar

View File

@@ -0,0 +1 @@
baz

View File

@@ -0,0 +1 @@
qux

View File

@@ -0,0 +1 @@
foo

View File

@@ -0,0 +1 @@
bar

View File

@@ -0,0 +1,4 @@
{
"extends": "../tsconfig.json",
"include": ["*.test.ts"]
}

View File

@@ -17,7 +17,11 @@ const toAbsolutePaths = (cwd: string, files: string[]) =>
describe('buildFileTree()', () => { describe('buildFileTree()', () => {
it('should exclude files using `.nowignore` blocklist', async () => { it('should exclude files using `.nowignore` blocklist', async () => {
const cwd = fixture('nowignore'); 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']); const expectedFileList = toAbsolutePaths(cwd, ['.nowignore', 'index.txt']);
expect(normalizeWindowsPaths(expectedFileList).sort()).toEqual( expect(normalizeWindowsPaths(expectedFileList).sort()).toEqual(
@@ -36,7 +40,11 @@ describe('buildFileTree()', () => {
it('should include the node_modules using `.vercelignore` allowlist', async () => { it('should include the node_modules using `.vercelignore` allowlist', async () => {
const cwd = fixture('vercelignore-allow-nodemodules'); 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, [ const expected = toAbsolutePaths(cwd, [
'node_modules/one.txt', 'node_modules/one.txt',
@@ -54,4 +62,90 @@ describe('buildFileTree()', () => {
normalizeWindowsPaths(ignoreList).sort() 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()
);
});
}); });

View 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

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/frameworks", "name": "@vercel/frameworks",
"version": "0.5.1-canary.17", "version": "0.5.1-canary.19",
"main": "./dist/frameworks.js", "main": "./dist/frameworks.js",
"types": "./dist/frameworks.d.ts", "types": "./dist/frameworks.d.ts",
"files": [ "files": [

View File

@@ -579,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', name: 'Dojo',
slug: 'dojo', slug: 'dojo',
@@ -1065,6 +1105,7 @@ export const frameworks = [
'SvelteKit is a framework for building web applications of all sizes.', 'SvelteKit is a framework for building web applications of all sizes.',
description: 'A SvelteKit app optimized to work for serverless.', description: 'A SvelteKit app optimized to work for serverless.',
website: 'https://kit.svelte.dev', website: 'https://kit.svelte.dev',
envPrefix: 'VITE_',
detectors: { detectors: {
every: [ every: [
{ {

View File

@@ -1,6 +1,6 @@
{ {
"name": "vercel-plugin-middleware", "name": "vercel-plugin-middleware",
"version": "0.0.0-canary.16", "version": "0.0.0-canary.24",
"license": "MIT", "license": "MIT",
"main": "./dist/index", "main": "./dist/index",
"homepage": "", "homepage": "",
@@ -30,7 +30,7 @@
"@types/node-fetch": "^2", "@types/node-fetch": "^2",
"@types/ua-parser-js": "0.7.36", "@types/ua-parser-js": "0.7.36",
"@types/uuid": "8.3.1", "@types/uuid": "8.3.1",
"@vercel/build-utils": "2.12.3-canary.40", "@vercel/build-utils": "2.13.0",
"@vercel/ncc": "0.24.0", "@vercel/ncc": "0.24.0",
"cookie": "0.4.1", "cookie": "0.4.1",
"formdata-node": "4.3.1", "formdata-node": "4.3.1",

View File

@@ -0,0 +1,52 @@
import path from 'path';
import * as esbuild from 'esbuild';
const processInjectFile = `
// envOverride is passed by esbuild plugin
const env = envOverride
function cwd() {
return '/'
}
function chdir(dir) {
throw new Error('process.chdir is not supported')
}
export const process = {
argv: [],
env,
chdir,
cwd,
};
`;
export function nodeProcessPolyfillPlugin({ env = {} } = {}): esbuild.Plugin {
return {
name: 'node-process-polyfill',
setup({ initialOptions, onResolve, onLoad }) {
onResolve({ filter: /_virtual-process-polyfill_\.js/ }, ({ path }) => {
return {
path,
sideEffects: false,
};
});
onLoad({ filter: /_virtual-process-polyfill_\.js/ }, () => {
const contents = `const envOverride = ${JSON.stringify(
env
)};\n${processInjectFile}`;
return {
loader: 'js',
contents,
};
});
const polyfills = [
path.resolve(__dirname, '_virtual-process-polyfill_.js'),
];
if (initialOptions.inject) {
initialOptions.inject.push(...polyfills);
} else {
initialOptions.inject = [...polyfills];
}
},
};
}

View File

@@ -5,7 +5,7 @@ import { promises as fsp } from 'fs';
import { IncomingMessage, ServerResponse } from 'http'; import { IncomingMessage, ServerResponse } from 'http';
import libGlob from 'glob'; import libGlob from 'glob';
import Proxy from 'http-proxy'; import Proxy from 'http-proxy';
import { updateFunctionsManifest } from '@vercel/build-utils'; import { _experimental_updateFunctionsManifest } from '@vercel/build-utils';
import { run } from './websandbox'; import { run } from './websandbox';
import type { FetchEventResult } from './websandbox/types'; import type { FetchEventResult } from './websandbox/types';
@@ -17,6 +17,7 @@ import {
UrlWithParsedQuery, UrlWithParsedQuery,
} from 'url'; } from 'url';
import { toNodeHeaders } from './websandbox/utils'; import { toNodeHeaders } from './websandbox/utils';
import { nodeProcessPolyfillPlugin } from './esbuild-plugins';
const glob = util.promisify(libGlob); const glob = util.promisify(libGlob);
const SUPPORTED_EXTENSIONS = ['.js', '.ts']; const SUPPORTED_EXTENSIONS = ['.js', '.ts'];
@@ -80,6 +81,7 @@ export async function build({ workPath }: { workPath: string }) {
banner: { banner: {
js: '"use strict";', js: '"use strict";',
}, },
plugins: [nodeProcessPolyfillPlugin({ env: process.env })],
format: 'cjs', format: 'cjs',
}); });
// Create `_ENTRIES` wrapper // Create `_ENTRIES` wrapper
@@ -108,7 +110,7 @@ export async function build({ workPath }: { workPath: string }) {
sortingIndex: 1, sortingIndex: 1,
}; };
await updateFunctionsManifest({ workPath, pages }); await _experimental_updateFunctionsManifest({ workPath, pages });
} }
const stringifyQuery = (req: IncomingMessage, query: ParsedUrlQuery) => { const stringifyQuery = (req: IncomingMessage, query: ParsedUrlQuery) => {

View File

@@ -63,6 +63,32 @@ describe('build()', () => {
).toEqual('1'); ).toEqual('1');
}); });
it('should build simple middleware with env vars', async () => {
const expectedEnvVar = 'expected-env-var';
const fixture = join(__dirname, 'fixtures/env');
process.env.ENV_VAR_SHOULD_BE_DEFINED = expectedEnvVar;
await build({
workPath: fixture,
});
// env var should be inlined in the output
delete process.env.ENV_VAR_SHOULD_BE_DEFINED;
const outputFile = join(fixture, '.output/server/pages/_middleware.js');
expect(await fsp.stat(outputFile)).toBeTruthy();
require(outputFile);
//@ts-ignore
const middleware = global._ENTRIES['middleware_pages/_middleware'].default;
expect(typeof middleware).toStrictEqual('function');
const handledResponse = await middleware({
request: {},
});
expect(String(handledResponse.response.body)).toEqual(expectedEnvVar);
expect(
(handledResponse.response as Response).headers.get('x-middleware-next')
).toEqual(null);
});
it('should create a middleware that runs in strict mode', async () => { it('should create a middleware that runs in strict mode', async () => {
const { middleware } = await setupFixture('use-strict'); const { middleware } = await setupFixture('use-strict');
const response = await middleware({ const response = await middleware({

View File

@@ -0,0 +1,3 @@
export default req => {
return new Response(process.env.ENV_VAR_SHOULD_BE_DEFINED);
};

View File

@@ -1,7 +1,7 @@
{ {
"private": false, "private": false,
"name": "vercel-plugin-go", "name": "vercel-plugin-go",
"version": "1.0.0-canary.28", "version": "1.0.0-canary.35",
"main": "dist/index.js", "main": "dist/index.js",
"license": "MIT", "license": "MIT",
"files": [ "files": [
@@ -17,7 +17,7 @@
"prepublishOnly": "tsc" "prepublishOnly": "tsc"
}, },
"dependencies": { "dependencies": {
"@vercel/build-utils": "2.12.3-canary.40", "@vercel/build-utils": "2.13.0",
"@vercel/go": "1.2.4-canary.4" "@vercel/go": "1.2.4-canary.4"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -1,6 +1,10 @@
import { convertRuntimeToPlugin } from '@vercel/build-utils'; import { _experimental_convertRuntimeToPlugin } from '@vercel/build-utils';
import * as go from '@vercel/go'; import * as go from '@vercel/go';
export const build = convertRuntimeToPlugin(go.build, 'vercel-plugin-go', '.go'); export const build = _experimental_convertRuntimeToPlugin(
go.build,
'vercel-plugin-go',
'.go'
);
export const startDevServer = go.startDevServer; export const startDevServer = go.startDevServer;

View File

@@ -1,6 +1,6 @@
{ {
"name": "vercel-plugin-node", "name": "vercel-plugin-node",
"version": "1.12.2-canary.32", "version": "1.12.2-canary.39",
"license": "MIT", "license": "MIT",
"main": "./dist/index", "main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js", "homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
@@ -34,7 +34,7 @@
"@types/node-fetch": "2", "@types/node-fetch": "2",
"@types/test-listen": "1.1.0", "@types/test-listen": "1.1.0",
"@types/yazl": "2.4.2", "@types/yazl": "2.4.2",
"@vercel/build-utils": "2.12.3-canary.40", "@vercel/build-utils": "2.13.0",
"@vercel/fun": "1.0.3", "@vercel/fun": "1.0.3",
"@vercel/ncc": "0.24.0", "@vercel/ncc": "0.24.0",
"@vercel/nft": "0.14.0", "@vercel/nft": "0.14.0",

View File

@@ -1,4 +1,5 @@
import { fork, spawn } from 'child_process'; import { fork, spawn } from 'child_process';
import { createHash } from 'crypto';
import { import {
createWriteStream, createWriteStream,
readFileSync, readFileSync,
@@ -35,12 +36,11 @@ import {
debug, debug,
isSymbolicLink, isSymbolicLink,
runNpmInstall, runNpmInstall,
updateFunctionsManifest, _experimental_updateFunctionsManifest,
updateRoutesManifest, _experimental_updateRoutesManifest,
walkParentDirs, walkParentDirs,
normalizePath, normalizePath,
runPackageJsonScript, runPackageJsonScript,
getInputHash,
} from '@vercel/build-utils'; } from '@vercel/build-utils';
import { FromSchema } from 'json-schema-to-ts'; import { FromSchema } from 'json-schema-to-ts';
import { getConfig, BaseFunctionConfigSchema } from '@vercel/static-config'; import { getConfig, BaseFunctionConfigSchema } from '@vercel/static-config';
@@ -428,7 +428,8 @@ export async function buildEntrypoint({
installedPaths?: Set<string>; installedPaths?: Set<string>;
}) { }) {
// Unique hash that will be used as directory name for `.output`. // Unique hash that will be used as directory name for `.output`.
const entrypointHash = 'api-routes-node-' + getInputHash(entrypoint); const entrypointHash =
'api-routes-node-' + createHash('sha1').update(entrypoint).digest('hex');
const outputDirPath = join(workPath, '.output'); const outputDirPath = join(workPath, '.output');
const { dir, name } = parsePath(entrypoint); const { dir, name } = parsePath(entrypoint);
@@ -548,12 +549,12 @@ export async function buildEntrypoint({
runtime: nodeVersion.runtime, runtime: nodeVersion.runtime,
}, },
}; };
await updateFunctionsManifest({ workPath, pages }); await _experimental_updateFunctionsManifest({ workPath, pages });
// Update the `routes-mainifest.json` file with the wildcard route // Update the `routes-mainifest.json` file with the wildcard route
// when the entrypoint is dynamic (i.e. `/api/[id].ts`). // when the entrypoint is dynamic (i.e. `/api/[id].ts`).
if (isDynamicRoute(entrypointWithoutExt)) { if (isDynamicRoute(entrypointWithoutExt)) {
await updateRoutesManifest({ await _experimental_updateRoutesManifest({
workPath, workPath,
dynamicRoutes: [pageToRoute(entrypointWithoutExt)], dynamicRoutes: [pageToRoute(entrypointWithoutExt)],
}); });

View File

@@ -1,7 +1,7 @@
{ {
"private": false, "private": false,
"name": "vercel-plugin-python", "name": "vercel-plugin-python",
"version": "1.0.0-canary.29", "version": "1.0.0-canary.36",
"main": "dist/index.js", "main": "dist/index.js",
"license": "MIT", "license": "MIT",
"files": [ "files": [
@@ -17,8 +17,8 @@
"prepublishOnly": "tsc" "prepublishOnly": "tsc"
}, },
"dependencies": { "dependencies": {
"@vercel/build-utils": "2.12.3-canary.40", "@vercel/build-utils": "2.13.0",
"@vercel/python": "2.1.2-canary.1" "@vercel/python": "2.1.2-canary.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "*", "@types/node": "*",

View File

@@ -1,6 +1,10 @@
import { convertRuntimeToPlugin } from '@vercel/build-utils'; import { _experimental_convertRuntimeToPlugin } from '@vercel/build-utils';
import * as python from '@vercel/python'; import * as python from '@vercel/python';
export const build = convertRuntimeToPlugin(python.build, 'vercel-plugin-python', '.py'); export const build = _experimental_convertRuntimeToPlugin(
python.build,
'vercel-plugin-python',
'.py'
);
//export const startDevServer = python.startDevServer; //export const startDevServer = python.startDevServer;

View File

@@ -1,7 +1,7 @@
{ {
"private": false, "private": false,
"name": "vercel-plugin-ruby", "name": "vercel-plugin-ruby",
"version": "1.0.0-canary.28", "version": "1.0.0-canary.35",
"main": "dist/index.js", "main": "dist/index.js",
"license": "MIT", "license": "MIT",
"files": [ "files": [
@@ -17,7 +17,7 @@
"prepublishOnly": "tsc" "prepublishOnly": "tsc"
}, },
"dependencies": { "dependencies": {
"@vercel/build-utils": "2.12.3-canary.40", "@vercel/build-utils": "2.13.0",
"@vercel/ruby": "1.2.10-canary.0" "@vercel/ruby": "1.2.10-canary.0"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -1,6 +1,10 @@
import { convertRuntimeToPlugin } from '@vercel/build-utils'; import { _experimental_convertRuntimeToPlugin } from '@vercel/build-utils';
import * as ruby from '@vercel/ruby'; import * as ruby from '@vercel/ruby';
export const build = convertRuntimeToPlugin(ruby.build, 'vercel-plugin-ruby', '.rb'); export const build = _experimental_convertRuntimeToPlugin(
ruby.build,
'vercel-plugin-ruby',
'.rb'
);
//export const startDevServer = ruby.startDevServer; //export const startDevServer = ruby.startDevServer;

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/python", "name": "@vercel/python",
"version": "2.1.2-canary.1", "version": "2.1.2-canary.2",
"main": "./dist/index.js", "main": "./dist/index.js",
"license": "MIT", "license": "MIT",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python", "homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",

View File

@@ -1,4 +1,3 @@
import { relative, basename } from 'path';
import execa from 'execa'; import execa from 'execa';
import { Meta, debug } from '@vercel/build-utils'; import { Meta, debug } from '@vercel/build-utils';
@@ -136,17 +135,10 @@ export async function installRequirementsFile({
meta, meta,
args = [], args = [],
}: InstallRequirementsFileArg) { }: InstallRequirementsFileArg) {
const fileAtRoot = relative(workPath, filePath) === basename(filePath); // The Vercel platform already handles `requirements.txt` for frontend projects,
// but the installation logic there is different, because it seems to install all
// If the `requirements.txt` file is located in the Root Directory of the project and // of the dependencies globally, whereas, for this Runtime, we want it to happen only
// the new File System API is used (`avoidTopLevelInstall`), the Install Command // locally, so we'll run a separate installation.
// will have already installed its dependencies, so we don't need to do it again.
if (meta.avoidTopLevelInstall && fileAtRoot) {
debug(
`Skipping requirements file installation, already installed by Install Command`
);
return;
}
if ( if (
meta.isDev && meta.isDev &&