Compare commits

...

26 Commits

Author SHA1 Message Date
Steven
05c534d855 Publish Canary
- @vercel/frameworks@0.1.1-canary.0
 - @vercel/build-utils@2.5.1-canary.1
 - vercel@20.0.1-canary.2
 - @vercel/client@9.0.1-canary.1
 - @vercel/go@1.1.6-canary.0
 - @vercel/node@1.8.1-canary.0
 - @vercel/python@1.2.3-canary.0
 - @vercel/ruby@1.2.4-canary.0
 - @vercel/static-build@0.17.8-canary.0
 - @vercel/redwood@0.1.1-canary.0
2020-08-27 19:39:21 -04:00
Shu Ding
910169dba7 [cli] Add support for the sourceFilesOutsideRootDirectory option (#5113)
If the value is set to `true` in the project settings, we don't cd into `rootDirectory`. 
We default it to `true` for new projects.
2020-08-27 23:37:50 +00:00
Steven
0fc74feddc [all] Bump ncc to 0.24.0 (#5103)
- Bump ncc to [0.24.0](https://github.com/vercel/ncc/releases/tag/0.24.0)
- Install ncc in each package that depends on it
2020-08-26 11:03:34 -04:00
Naoyuki Kanezawa
a9ea294514 fix framework names (#5104) 2020-08-26 22:14:39 +09:00
Steven
42e0450d87 Publish Canary
- vercel@20.0.1-canary.1
 - @vercel/next@2.6.24-canary.0
2020-08-25 22:13:26 -04:00
Guy Bedford
08c0feb58a [cli] Improve startup perf - disable source maps and minification (#5100)
Currently on my machine, vercel --version takes 850ms to run. With this change, that execution time is reduced to ~550ms.

The reason is that source maps seem to significantly slow down Node.js execution, compounded by the size of the source map, even if it is not used.

I believe the benefits of this perf improvement outweigh the direct source maps and minification benefits.

If it is felt that direct per-file source maps are necessary for internal errors, then reducing the source map size should be investigated further to improve the runtime performance here.
2020-08-25 22:12:25 -04:00
Mark Glagola
60aaf76ed2 [cli] Fix vc domains ls pagination (#5099)
Fixes pagination for vercel cli `domains ls --next <timestamp>`
2020-08-25 19:39:34 -04:00
Matthew Sweeney
bd706beba5 [examples] Update README Files (#5092)
This PR updates the `README.md` files with the following changes:

- Removal of CLI deployment.
- Amends Blitz.js to be in line with other `README.md` formats.
2020-08-25 14:51:46 -04:00
JJ Kasper
b85a0a349a [next] Add test case for root optional revalidate params (#5072)
This adds test cases from https://github.com/vercel/next.js/pull/16451 which are currently failing and will pass after a new canary of Next.js has been published
2020-08-24 16:32:30 +00:00
Steven
a97bc2af6d Publish Canary
- @vercel/build-utils@2.5.1-canary.0
 - vercel@20.0.1-canary.0
 - @vercel/client@9.0.1-canary.0
2020-08-24 11:19:44 -04:00
Steven
a5dc90c8cd Revert "[build-utils] Use handle: error for api 404" (#5088)
* Revert "[build-utils] Use `handle: error` for api 404 (#5064)"

This reverts commit 02e1c921ac.

* Re-enable cli changes

* Re-enable redwood changes

* Minor cleanup
2020-08-24 11:16:32 -04:00
Steven
e90521b5a4 Publish Stable
- @vercel/frameworks@0.1.0
 - @vercel/build-utils@2.5.0
 - vercel@20.0.0
 - @vercel/client@9.0.0
 - @vercel/go@1.1.5
 - @vercel/next@2.6.23
 - @vercel/node@1.8.0
 - @vercel/routing-utils@1.8.4
 - @vercel/static-build@0.17.7
 - @vercel/redwood@0.1.0
2020-08-24 08:25:30 -04:00
Steven
10c598834a Publish Canary
- @vercel/build-utils@2.4.3-canary.5
 - vercel@20.0.0-canary.26
 - @vercel/client@8.2.2-canary.10
2020-08-21 17:53:14 -04:00
Steven
e58b34b82c [build-utils] Fix framework "Other" with Next.js for old projects (#5074)
Since released PR #5009, we had some users that depend on the broken behavior. This adds an arbitrary date so that old projects will use the old broken behavior, and new projects will use the new behavior from #5009.

The reason for the date is that we don't want to force users to create new projects who noticed this broken behavior months ago like this discussion: https://github.com/vercel/vercel/discussions/4138

Its better to be a bit aggressive and set the date far back because users with that want the old behavior have a workaround: select Next.js in the framework dropdown. However, users that want the new behavior with an old project will be stuck without a solution.
2020-08-21 21:51:40 +00:00
Steven
02e1c921ac [cli][build-utils] Use handle: error for api 404 (#5064)
This PR does a few things:

- Consolidates build-utils to use both 404 routes in `handle: error` phase
- Fixes `vc dev` to process `handle: error` phase after the `handle: filesystem` phase
- Updates `/api` 404 route to be excluded for frameworks like RedwoodJS which use their own functions
2020-08-21 20:29:39 +00:00
Steven
fcb14fa70e Publish Canary
- @vercel/redwood@0.0.2-canary.8
2020-08-19 18:26:12 -04:00
Steven
46e18128c7 [redwood] Add support for functions and apiProxyPath config (#5063)
This PR adds two missing features to `@vercel/redwood`:

1. Support for [`functions`](https://vercel.com/docs/configuration#project/functions) in `vercel.json`
2. Support for [`apiProxyPath`](https://redwoodjs.com/docs/app-configuration-redwood-toml#apiproxypath) in `redwood.toml`
3. Support for caching yarn workspaces which has `node_modules` outside the root directory
2020-08-19 22:16:53 +00:00
dav-is
e06d5247ef Publish Canary
- vercel@20.0.0-canary.25
 - @vercel/client@8.2.2-canary.9
2020-08-19 16:40:45 -04:00
Connor Davis
02195b92a7 [client][cli] Add Learn More Option to Warnings (#5022)
The deployment API might return a learn more link to address warnings, tips, or notices

CH-568

```
HTTP/2 200
...
x-vercel-warning-bad-error: Something went wrong
x-vercel-link-bad-error: https://vercel.link/bad-error

x-vercel-notice-low-funds: You are low on funds
x-vercel-link-low-funds: https://vercel.link/increase-funds
...
```

Should output as:
```
Warning: Something went wrong
Learn More: https://vercel.link/bad-error

Notice: You are low on funds
Learn More: https://vercel.link/increase-funds
```
2020-08-19 20:19:28 +00:00
Andy Bitz
7945155a0f Publish Canary
- vercel@20.0.0-canary.24
 - @vercel/next@2.6.23-canary.0
 - @vercel/node@1.7.5-canary.2
 - @vercel/routing-utils@1.8.4-canary.5
2020-08-19 15:01:35 +02:00
Andy
edb6043c2c [cli] Always show renewal price for domains inspect (#5060)
* [cli] Always show renwal price for `domains inspect`

* Update test
2020-08-19 15:00:33 +02:00
Markoz Peña
971481ba51 [node] Add res.redirect() helper method (#4947)
This pull request adds a method redirect, the behavior will be the same as that of Next.js with `pages/api`. This PR takes into account the change that is being made in Next.js with redirect due to the [error that was reported](https://github.com/vercel/next.js/issues/15594) a few hours ago.

Co-authored-by: Steven <steven@ceriously.com>
2020-08-18 18:58:54 -04:00
JJ Kasper
db8e456603 Publish canary
- @vercel/routing-utils@1.8.4-canary.4
2020-08-18 12:37:22 -05:00
JJ Kasper
d1b4f24a4a Publish Stable
- @vercel/next@2.6.22
2020-08-18 12:25:16 -05:00
JJ Kasper
4eb39ed53b Publish Canary
- @vercel/next@2.6.22-canary.1
- @vercel/routing-utils@1.8.4-canary.3
2020-08-18 12:19:58 -05:00
JJ Kasper
6c7236ffd5 [routing-utils] Attempt normal path-to-regexp replacing before custom (#5053)
This corrects behavior that was changed when switching to use `safelyCompile` which caused some `path-to-regexp` replacing behavior to be changed like not removing brackets `{}` around params which are removed in Next.js. This updates to first attempt to use the normal replacing behavior from `path-to-regexp` falling back to the safe compiling logic added when that fails. 

Additional tests have been added to ensure the brackets are stripped as expected when compiling with `path-to-regexp`
2020-08-18 16:57:38 +00:00
104 changed files with 15381 additions and 386 deletions

View File

@@ -17,11 +17,3 @@ To get started deploying AMP with Vercel, you can use the [Vercel CLI](https://v
```shell
$ vercel init amp
```
### Deploying From Your Terminal
You can deploy your new AMP project with a single command from your terminal using Vercel CLI:
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ To get started with Angular, you can use the [Angular CLI](https://cli.angular.i
```shell
$ ng new
```
### Deploying From Your Terminal
You can deploy your new Angular project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -1,21 +1,19 @@
![Blitz Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/blitz.svg)
This is a [Blitz.js](https://blitzjs.com/) project bootstrapped with `npx blitz new`.
# Blitz.js Example
## Getting Started
This directory is a brief example of a [Blitz.js](https://blitzjs.com/) project that can be deployed with Vercel and zero configuration.
First, run the development server:
## Deploy Your Own
```bash
npx blitz start
Deploy your own Blitz.js project with Vercel by viewing the [documentation on deploying to Vercel](https://blitzjs.com/docs/deploy-vercel)
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/vercel/vercel/tree/master/examples/blitzjs)
### How We Created This Example
To get started with Blitz.js, you can use [npx](https://www.npmjs.com/package/npx) to initialize the project:
```shell
$ npx blitz new
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
## Learn More
To learn more about Blitz.js, view [Blitzjs.com](https://blitzjs.com)
## Deploy on Vercel
View the [documentation on deploying to Vercel](https://blitzjs.com/docs/deploy-vercel)

View File

@@ -17,11 +17,3 @@ To get started deploying Brunch with Vercel, you can use the [Brunch CLI](https:
```shell
$ brunch new project-name -s es6
```
### Deploying From Your Terminal
You can deploy your new Brunch project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ To get started with React, along with [Serverless Functions](https://vercel.com/
```shell
$ npx create-react-app my-app
```
### Deploying From Your Terminal
You can deploy your new React project, along with [Serverless Functions](https://vercel.com/docs/v2/serverless-functions/introduction), with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -17,11 +17,3 @@ To get started deploying a Custom Built project with Vercel, you can use the [Ve
```shell
$ vercel init custom-build
```
### Deploying From Your Terminal
You can deploy your new Custom Built project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -15,11 +15,3 @@ To get started with Docusaurus on Vercel, you can use the [Docusaurus CLI](https
```shell
$ npx @docusaurus/init@next init my-website classic
```
### Deploying From Your Terminal
You can deploy your new Docusaurus project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ To get started with Docusaurus for deployment with Vercel, you can use the [Docu
```shell
$ docusaurus-init
```
### Deploying From Your Terminal
You can deploy your new Docusaurus project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -15,11 +15,3 @@ To get started with Dojo on Vercel, you can use the [Dojo CLI](https://github.co
```shell
$ vercel init dojo
```
### Deploying From Your Terminal
You can deploy your new Dojo project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ To get started with Eleventy for deployment with Vercel, you can use [npx](https
```shell
$ npx degit 11ty/eleventy-base-blog my-11ty-project
```
### Deploying From Your Terminal
You can deploy your new Eleventy project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ To get started with Ember for deployment with Vercel, you can use the [Ember CLI
```shell
$ npx ember-cli new ember-project
```
### Deploying From Your Terminal
You can deploy your new Ember project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ To get started with Gatsby on Vercel, you can use the [Gatsby CLI](https://www.g
```shell
$ gatsby new gatsby-site
```
### Deploying From Your Terminal
You can deploy your new Gatsby project, along with [Serverless Functions](https://vercel.com/docs/v2/serverless-functions/introduction), with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ To get started with Gridsome for deployment with Vercel, you can use the [Gridso
```shell
$ gridsome create my-website
```
### Deploying From Your Terminal
You can deploy your new Gridsome project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ To get started with Hexo for deployment with Vercel, you can use the [Hexo CLI](
```shell
$ hexo init project-name
```
### Deploying From Your Terminal
You can deploy your new Hexo project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -17,11 +17,3 @@ To get started with Hugo for deployment with Vercel, you can use the [Hugo CLI](
```shell
$ hugo new site project-name
```
### Deploying From Your Terminal
You can deploy your new Hugo project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -17,11 +17,3 @@ To get started with Ionic Angular deployed with Vercel, you can use the [Ionic C
```shell
$ npx @ionic/cli start [project-name] conference --type angular && cd [project-name]
```
### Deploying From Your Terminal
You can deploy your new Ionic Angular project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -17,11 +17,3 @@ To get started with Ionic React deployed with Vercel, you can use the [Ionic CLI
```shell
$ npx ionic start [project-name] conference --type react && cd [project-name]
```
### Deploying From Your Terminal
You can deploy your new Ionic React project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -17,11 +17,3 @@ To get started with Jekyll for deployment with Vercel, you can use the [Jekyll C
```shell
$ jekyll new my-blog
```
### Deploying From Your Terminal
You can deploy your new Jekyll project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -17,11 +17,3 @@ To get started with Middleman for deployment with Vercel, you can use the [Middl
```shell
$ middleman init project-name
```
### Deploying From Your Terminal
You can deploy your new Middleman project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ $ npx create-nuxt-app my-app
```
> The only change made is to amend the output directory in `nuxt.config.js` to `"/public"`.
### Deploying From Your Terminal
You can deploy your new Nuxt.js project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ To get started with Polymer deployed with Vercel, you can use the [Polymer CLI](
```shell
$ polymer init
```
### Deploying From Your Terminal
You can deploy your new Polymer project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ To get started with Preact for deployment with Vercel, you can use the [Preact C
```shell
$ preact create default my-project
```
### Deploying From Your Terminal
You can deploy your new Preact project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ To get started with RedwoodJS on Vercel, you can [use Yarn to initialize](https:
```shell
$ yarn create redwood-app ./my-redwood-app
```
### Deploying From Your Terminal
You can deploy your new RedwoodJS project, along with [Serverless Functions](https://vercel.com/docs/v2/serverless-functions/introduction), with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ To get started with Saber on Vercel, you can use [`npm init`](https://docs.npmjs
```shell
$ npm init site my-saber-site
```
### Deploying From Your Terminal
You can deploy your new Saber project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ $ npx degit "sveltejs/sapper-template#webpack" my-sapper-app
```
> The only change made is to change the build script in `package.json` to be `"sapper export"`.
### Deploying From Your Terminal
You can deploy your new Sapper project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ To get started deploying Scully with Vercel, you can use the [Vercel CLI](https:
```shell
$ vercel init scully
```
### Deploying From Your Terminal
You can deploy your new Scully project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -17,11 +17,3 @@ To get started with Stencil deployed with Vercel, you can use the [Stencil proje
```shell
$ npm init stencil
```
### Deploying From Your Terminal
You can deploy your new Stencil project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -17,11 +17,3 @@ To get started with Svelte, along with [Serverless Functions](https://vercel.com
```shell
$ npx degit sveltejs/template my-svelte-project
```
### Deploying From Your Terminal
You can deploy your new Svelte project, along with [Serverless Functions](https://vercel.com/docs/v2/serverless-functions/introduction), with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -19,11 +19,3 @@ To get started with UmiJS deployed with Vercel, you can use the [Umi CLI](https:
```shell
$ yarn create umi app-name
```
### Deploying From Your Terminal
You can deploy your new UmiJS project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):
```shell
$ vercel
```

View File

@@ -17,7 +17,7 @@
"devDependencies": {
"@typescript-eslint/eslint-plugin": "2.0.0",
"@typescript-eslint/parser": "2.0.0",
"@zeit/ncc": "0.20.4",
"@vercel/ncc": "0.24.0",
"async-retry": "1.2.3",
"buffer-replace": "1.0.0",
"cheerio": "1.0.0-rc.3",

View File

@@ -59,7 +59,7 @@
}
},
{
"name": "Gatsby",
"name": "Gatsby.js",
"slug": "gatsby",
"demo": "https://gatsby.now-examples.now.sh",
"logo": "https://raw.githubusercontent.com/vercel/vercel/master/packages/frameworks/logos/gatsby.svg",
@@ -261,7 +261,7 @@
}
},
{
"name": "Ember",
"name": "Ember.js",
"slug": "ember",
"demo": "https://ember.now-examples.now.sh",
"logo": "https://raw.githubusercontent.com/vercel/vercel/master/packages/frameworks/logos/ember.svg",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/frameworks",
"version": "0.0.18-canary.5",
"version": "0.1.1-canary.0",
"main": "frameworks.json",
"license": "UNLICENSED",
"scripts": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/build-utils",
"version": "2.4.3-canary.4",
"version": "2.5.1-canary.1",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",
@@ -29,7 +29,8 @@
"@types/node-fetch": "^2.1.6",
"@types/semver": "6.0.0",
"@types/yazl": "^2.4.1",
"@vercel/frameworks": "0.0.18-canary.5",
"@vercel/frameworks": "0.1.1-canary.0",
"@vercel/ncc": "0.24.0",
"aggregate-error": "3.0.1",
"async-retry": "1.2.3",
"async-sema": "2.1.4",

View File

@@ -26,6 +26,7 @@ interface Options {
devCommand?: string | null;
buildCommand?: string | null;
outputDirectory?: string | null;
createdAt?: number;
};
cleanUrls?: boolean;
trailingSlash?: boolean;
@@ -434,6 +435,7 @@ function detectFrontBuilder(
): Builder {
const { tag, projectSettings = {} } = options;
const withTag = tag ? `@${tag}` : '';
const { createdAt = 0 } = projectSettings;
let { framework } = projectSettings;
const config: Config = {
@@ -456,7 +458,7 @@ function detectFrontBuilder(
config.outputDirectory = projectSettings.outputDirectory;
}
if (pkg && framework !== null) {
if (pkg && (framework !== null || createdAt < Date.parse('2020-03-01'))) {
const deps: PackageJson['dependencies'] = {
...pkg.dependencies,
...pkg.devDependencies,
@@ -929,11 +931,10 @@ function getRouteResult(
const redirectRoutes: Route[] = [];
const rewriteRoutes: Route[] = [];
const errorRoutes: Route[] = [];
const isNextjs =
frontendBuilder &&
((frontendBuilder.use && frontendBuilder.use.startsWith('@vercel/next')) ||
(frontendBuilder.config &&
frontendBuilder.config.framework === 'nextjs'));
const framework = frontendBuilder?.config?.framework || '';
const use = frontendBuilder?.use || '';
const isNextjs = framework === 'nextjs' || use.startsWith('@vercel/next');
const ignoreRuntimes = slugToFramework.get(framework)?.ignoreRuntimes;
if (apiRoutes && apiRoutes.length > 0) {
if (options.featHandleMiss) {
@@ -971,11 +972,18 @@ function getRouteResult(
}
rewriteRoutes.push(...dynamicRoutes);
rewriteRoutes.push({
src: '^/api(/.*)?$',
status: 404,
continue: true,
});
if (typeof ignoreRuntimes === 'undefined') {
// This route is only necessary to hide the directory listing
// to avoid enumerating serverless function names.
// But it causes issues in `vc dev` for frameworks that handle
// their own functions such as redwood, so we ignore.
rewriteRoutes.push({
src: '^/api(/.*)?$',
status: 404,
continue: true,
});
}
} else {
defaultRoutes.push(...apiRoutes);

View File

@@ -1080,7 +1080,7 @@ describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
expect(errorRoutes).toStrictEqual([]);
});
it('Using "Other" framework with Storybook should NOT autodetect Next.js', async () => {
it('Using "Other" framework with Storybook should NOT autodetect Next.js for new projects', async () => {
const pkg = {
scripts: {
dev: 'next dev',
@@ -1104,6 +1104,7 @@ describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
const projectSettings = {
framework: null, // Selected "Other" framework
buildCommand: 'yarn build-storybook',
createdAt: Date.parse('2020-07-01'),
};
const { builders, errorRoutes } = await detectBuilders(files, pkg, {
@@ -1125,6 +1126,41 @@ describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
expect((errorRoutes![0] as Source).status).toBe(404);
});
it('Using "Other" framework should autodetect Next.js for old projects', async () => {
const pkg = {
scripts: {
dev: 'next dev',
build: 'next build',
},
dependencies: {
next: '9.3.5',
react: '16.13.1',
'react-dom': '16.13.1',
},
};
const files = ['package.json', 'pages/api/foo.js', 'index.html'];
const projectSettings = {
framework: null, // Selected "Other" framework
createdAt: Date.parse('2020-02-01'),
};
const { builders, errorRoutes } = await detectBuilders(files, pkg, {
projectSettings,
featHandleMiss,
});
expect(builders).toEqual([
{
use: '@vercel/next',
src: 'package.json',
config: {
zeroConfig: true,
},
},
]);
expect(errorRoutes).toStrictEqual([]);
});
it('api + raw static', async () => {
const files = ['api/endpoint.js', 'index.html', 'favicon.ico'];
@@ -1905,7 +1941,7 @@ describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
]);
});
it('RedwoodJS should allow usage of non-js API', async () => {
it('RedwoodJS should allow usage of non-js API and not add 404 api route', async () => {
const files = [...redwoodFiles, 'api/golang.go', 'api/python.py'].sort();
const projectSettings = {
framework: 'redwoodjs',
@@ -1953,13 +1989,7 @@ describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
check: true,
},
]);
expect(rewriteRoutes).toStrictEqual([
{
status: 404,
src: '^/api(/.*)?$',
continue: true,
},
]);
expect(rewriteRoutes).toStrictEqual([]);
expect(errorRoutes).toStrictEqual([
{
status: 404,

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "20.0.0-canary.23",
"version": "20.0.1-canary.2",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Vercel",
@@ -61,11 +61,11 @@
"node": ">= 10"
},
"dependencies": {
"@vercel/build-utils": "2.4.3-canary.4",
"@vercel/go": "1.1.5-canary.0",
"@vercel/node": "1.7.5-canary.1",
"@vercel/python": "1.2.2",
"@vercel/ruby": "1.2.3",
"@vercel/build-utils": "2.5.1-canary.1",
"@vercel/go": "1.1.6-canary.0",
"@vercel/node": "1.8.1-canary.0",
"@vercel/python": "1.2.3-canary.0",
"@vercel/ruby": "1.2.4-canary.0",
"update-notifier": "4.1.0"
},
"devDependencies": {
@@ -100,9 +100,9 @@
"@types/universal-analytics": "0.4.2",
"@types/which": "1.3.2",
"@types/write-json-file": "2.2.1",
"@vercel/frameworks": "0.0.18-canary.5",
"@vercel/frameworks": "0.1.1-canary.0",
"@vercel/ncc": "0.24.0",
"@zeit/fun": "0.11.2",
"@zeit/ncc": "0.18.5",
"@zeit/source-map-support": "0.6.2",
"ajv": "6.12.2",
"alpha-sort": "2.0.1",

View File

@@ -49,18 +49,12 @@ async function main() {
// Do the initial `ncc` build
console.log();
const src = join(dirRoot, 'src');
const args = [
'@zeit/ncc',
'build',
'--source-map',
'--external',
'update-notifier',
];
if (!isDev) {
args.push('--minify');
const args = ['ncc', 'build', '--external', 'update-notifier'];
if (isDev) {
args.push('--source-map');
}
args.push(src);
await execa('npx', args, { stdio: 'inherit' });
await execa('yarn', args, { stdio: 'inherit' });
// `ncc` has some issues with `@zeit/fun`'s runtime files:
// - Executable bits on the `bootstrap` files appear to be lost:

View File

@@ -162,7 +162,11 @@ const printDeploymentStatus = async (
prependEmoji(
`${chalk.dim(indication.payload)}`,
emoji(indication.type)
) + `\n`
) +
`\n` +
(indication.link
? `${indication.action || 'Learn More'}: ${indication.link}\n\n`
: '')
);
}
}
@@ -272,6 +276,7 @@ export default async function main(
let { org, project, status } = link;
let newProjectName = null;
let rootDirectory = project ? project.rootDirectory : null;
let sourceFilesOutsideRootDirectory = true;
if (status === 'not_linked') {
const shouldStartSetup =
@@ -329,6 +334,7 @@ export default async function main(
} else {
project = projectOrNewProjectName;
rootDirectory = project.rootDirectory;
sourceFilesOutsideRootDirectory = project.sourceFilesOutsideRootDirectory;
// we can already link the project
await linkFolderToProject(
@@ -345,7 +351,12 @@ export default async function main(
}
}
const sourcePath = rootDirectory ? join(path, rootDirectory) : path;
// if we have `sourceFilesOutsideRootDirectory` set to `true`, we use the current path
// and upload the entire directory.
const sourcePath =
rootDirectory && !sourceFilesOutsideRootDirectory
? join(path, rootDirectory)
: path;
if (
rootDirectory &&
@@ -364,7 +375,7 @@ export default async function main(
// If Root Directory is used we'll try to read the config
// from there instead and use it if it exists.
if (rootDirectory) {
const rootDirectoryConfig = readLocalConfig(sourcePath);
const rootDirectoryConfig = readLocalConfig(join(path, rootDirectory));
if (rootDirectoryConfig) {
debug(`Read local config from root directory (${rootDirectory})`);
@@ -521,6 +532,11 @@ export default async function main(
skipAutoDetectionConfirmation: autoConfirm,
};
if (!localConfig.builds || localConfig.builds.length === 0) {
// Only add projectSettings for zero config deployments
createArgs.projectSettings = { sourceFilesOutsideRootDirectory };
}
deployment = await createDeploy(
output,
now,
@@ -542,6 +558,10 @@ export default async function main(
projectSettings.rootDirectory = rootDirectory;
}
if (typeof sourceFilesOutsideRootDirectory !== 'undefined') {
projectSettings.sourceFilesOutsideRootDirectory = sourceFilesOutsideRootDirectory;
}
const settings = await editProjectSettings(
output,
projectSettings,

View File

@@ -111,12 +111,11 @@ export default async function inspect(
` ${chalk.cyan('Created At')}\t\t\t${formatDate(domain.createdAt)}\n`
);
output.print(` ${chalk.cyan('Edge Network')}\t\tyes\n`);
if (renewalPrice && domain.boughtAt) {
output.print(
` ${chalk.cyan('Renewal Price')}\t\t$${renewalPrice} USD\n`
);
}
output.print(
` ${chalk.cyan('Renewal Price')}\t\t${
domain.boughtAt && renewalPrice ? `$${renewalPrice} USD` : chalk.gray('-')
}\n`
);
output.print('\n');

View File

@@ -66,7 +66,10 @@ export default async function ls(
const cancelWait = wait(`Fetching Domains under ${chalk.bold(contextName)}`);
const { domains, pagination } = await getDomains(client).finally(() => {
const { domains, pagination } = await getDomains(
client,
nextTimestamp
).finally(() => {
cancelWait();
});

View File

@@ -1475,34 +1475,6 @@ export default class DevServer {
routeResult.status = prevStatus;
}
if (!match && errorRoutes.length > 0) {
// error phase
const routeResultForError = await devRouter(
getReqUrl(routeResult),
req.method,
errorRoutes,
this,
nowConfig,
routeResult.headers,
[],
'error'
);
const matchForError = await findBuildMatch(
this.buildMatches,
this.files,
routeResultForError.dest,
this,
nowConfig
);
if (matchForError) {
// error phase only applies if the file was found
routeResult = routeResultForError;
match = matchForError;
}
}
statusCode = routeResult.status;
if (match) {
@@ -1511,6 +1483,52 @@ export default class DevServer {
}
}
if (!match && routeResult && errorRoutes.length > 0) {
// error phase
const routeResultForError = await devRouter(
getReqUrl(routeResult),
req.method,
errorRoutes,
this,
nowConfig,
routeResult.headers,
[],
'error'
);
const { matched_route } = routeResultForError;
const matchForError = await findBuildMatch(
this.buildMatches,
this.files,
routeResultForError.dest,
this,
nowConfig
);
if (matchForError) {
debug(`Route match detected in error phase, breaking loop`);
routeResult = routeResultForError;
statusCode = routeResultForError.status;
match = matchForError;
} else if (matched_route && matched_route.src && !matched_route.dest) {
debug(
'Route without `dest` detected in error phase, attempting to exit early'
);
if (
await this.exitWithStatus(
matchForError,
routeResultForError,
'error',
req,
res,
nowRequestId
)
) {
return;
}
}
}
if (!routeResult) {
throw new Error('Expected Route Result but none was found.');
}

View File

@@ -59,6 +59,7 @@ export default async function setupAndLink(
const isTTY = process.stdout.isTTY;
const quiet = !isTTY;
let rootDirectory: string | null = null;
let sourceFilesOutsideRootDirectory = true;
let newProjectName: string;
let org;
@@ -129,7 +130,13 @@ export default async function setupAndLink(
);
return { status: 'linked', org, project };
}
const sourcePath = rootDirectory ? join(path, rootDirectory) : path;
// if we have `sourceFilesOutsideRootDirectory` set to `true`, we use the current path
// and upload the entire directory.
const sourcePath =
rootDirectory && !sourceFilesOutsideRootDirectory
? join(path, rootDirectory)
: path;
if (
rootDirectory &&
@@ -174,6 +181,11 @@ export default async function setupAndLink(
skipAutoDetectionConfirmation: false,
};
if (!localConfig.builds || localConfig.builds.length === 0) {
// Only add projectSettings for zero config deployments
createArgs.projectSettings = { sourceFilesOutsideRootDirectory };
}
const deployment = await createDeploy(
output,
now,

View File

@@ -241,6 +241,24 @@ module.exports = async function prepare(session) {
},
}),
},
'zero-config-next-js-functions-warning': {
'pages/index.js':
'export default () => <div><h1>Vercel CLI test</h1><p>Zero-config + Next.js</p></div>',
'vercel.json':
'{"version":2,"functions":{"pages/index.js":{"runtime": "@vercel/php@0.1.0"}}}',
'package.json': JSON.stringify({
scripts: {
dev: 'next',
start: 'next start',
build: 'next build',
},
dependencies: {
next: 'latest',
react: 'latest',
'react-dom': 'latest',
},
}),
},
'lambda-with-128-memory': {
'api/memory.js': `
module.exports = (req, res) => {

View File

@@ -1052,7 +1052,7 @@ test('domains inspect', async t => {
}
);
t.true(!stderr.includes(`Renewal Price`));
t.true(stderr.includes(`Renewal Price`));
t.is(exitCode, 0, formatOutput({ stdout, stderr }));
{
@@ -2219,6 +2219,33 @@ test('create zero-config deployment', async t => {
);
});
test('next unsupported functions config shows warning link', async t => {
const fixturePath = fixture('zero-config-next-js-functions-warning');
const output = await execute([
fixturePath,
'--force',
'--public',
'--confirm',
]);
console.log('isCanary', isCanary);
console.log(output.stderr);
console.log(output.stdout);
console.log(output.exitCode);
t.is(output.exitCode, 0, formatOutput(output));
t.regex(
output.stderr,
/Ignoring function property `runtime`\. When using Next\.js, only `memory` and `maxDuration` can be used\./gm,
formatOutput(output)
);
t.regex(
output.stderr,
/Learn More: https:\/\/vercel\.link\/functions-property-next/gm,
formatOutput(output)
);
});
test('vercel secret add', async t => {
context.secretName = `my-secret-${Date.now().toString(36)}`;
const value = 'https://my-secret-endpoint.com';

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/client",
"version": "8.2.2-canary.8",
"version": "9.0.1-canary.1",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"homepage": "https://vercel.com",
@@ -26,7 +26,6 @@
"@types/node": "12.0.4",
"@types/node-fetch": "2.5.4",
"@types/recursive-readdir": "2.2.0",
"@zeit/ncc": "0.18.5",
"typescript": "3.9.3"
},
"jest": {
@@ -38,7 +37,7 @@
]
},
"dependencies": {
"@vercel/build-utils": "2.4.3-canary.4",
"@vercel/build-utils": "2.5.1-canary.1",
"@zeit/fetch": "5.2.0",
"async-retry": "1.2.3",
"async-sema": "3.0.0",

View File

@@ -19,7 +19,12 @@ async function* postDeployment(
files: Map<string, DeploymentFile>,
clientOptions: NowClientOptions,
deploymentOptions: DeploymentOptions
): AsyncIterableIterator<{ type: DeploymentEventType; payload: any }> {
): AsyncIterableIterator<{
type: DeploymentEventType;
payload: any;
action?: string;
link?: string;
}> {
const debug = createDebug(clientOptions.debug);
const preparedFiles = prepareFiles(files, clientOptions);
const apiDeployments = getApiDeploymentsUrl(deploymentOptions);
@@ -63,19 +68,19 @@ async function* postDeployment(
};
}
for (const [name, value] of response.headers.entries()) {
if (name.startsWith('x-now-warning-')) {
debug('Deployment created with a warning:', value);
yield { type: 'warning', payload: value };
}
const indications = new Set(['warning', 'notice', 'tip']);
const regex = /^x-(?:vercel|now)-(warning|notice|tip)-(.*)$/;
for (const [name, payload] of response.headers.entries()) {
const match = name.match(regex);
if (match) {
const [, type, identifier] = match;
const action = response.headers.get(`x-vercel-action-${identifier}`);
const link = response.headers.get(`x-vercel-link-${identifier}`);
if (name.startsWith('x-now-notice-')) {
debug('Deployment created with a notice:', value);
yield { type: 'notice', payload: value };
}
if (name.startsWith('x-now-tip-')) {
debug('Deployment created with a tip:', value);
yield { type: 'tip', payload: value };
if (indications.has(type)) {
debug(`Deployment created with a ${type}: `, payload);
yield { type, payload, action, link };
}
}
}
yield { type: 'created', payload: deployment };

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/go",
"version": "1.1.5-canary.0",
"version": "1.1.6-canary.0",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
@@ -25,6 +25,7 @@
"@types/fs-extra": "^5.0.5",
"@types/node-fetch": "^2.3.0",
"@types/tar": "^4.0.0",
"@vercel/ncc": "0.24.0",
"async-retry": "1.3.1",
"execa": "^1.0.0",
"fs-extra": "^7.0.0",

View File

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

View File

@@ -0,0 +1,52 @@
/* eslint-env jest */
const fetch = require('node-fetch');
const cheerio = require('cheerio');
const waitFor = ms => new Promise(resolve => setTimeout(resolve, ms));
module.exports = function (ctx) {
const getProps = async path => {
const html = await fetch(`${ctx.deploymentUrl}/${path}`).then(res =>
res.text()
);
const $ = cheerio.load(html);
return JSON.parse($('#props').text());
};
it('should render / correctly', async () => {
const props = await getProps('/', { params: {} });
expect(props.params).toEqual({});
await waitFor(2000);
await getProps('/');
const newProps = await getProps('/', { params: {} });
expect(newProps.params).toEqual({});
expect(props.random).not.toBe(newProps.random);
});
it('should render /a correctly', async () => {
const props = await getProps('/a');
expect(props.params).toEqual({ slug: ['a'] });
await waitFor(2000);
await getProps('/a');
const newProps = await getProps('/a');
expect(newProps.params).toEqual({ slug: ['a'] });
expect(props.random).not.toBe(newProps.random);
});
it('should render /hello/world correctly', async () => {
const props = await getProps('/hello/world');
expect(props.params).toEqual({ slug: ['hello', 'world'] });
await waitFor(2000);
await getProps('/hello/world');
const newProps = await getProps('/hello/world');
expect(newProps.params).toEqual({ slug: ['hello', 'world'] });
expect(props.random).not.toBe(newProps.random);
});
};

View File

@@ -0,0 +1,15 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/next"
}
],
"probes": [
{
"path": "/non-existent",
"status": 404
}
]
}

View File

@@ -0,0 +1,7 @@
{
"dependencies": {
"next": "canary",
"react": "^16.8.6",
"react-dom": "^16.8.6"
}
}

View File

@@ -0,0 +1,24 @@
export default function Home(props) {
return <pre id="props">{JSON.stringify(props)}</pre>;
}
export async function getStaticPaths() {
return {
paths: [
{ params: { slug: false } },
{ params: { slug: ['a'] } },
{ params: { slug: ['hello', 'world'] } },
],
fallback: false,
};
}
export async function getStaticProps({ params }) {
return {
props: {
params,
random: Math.random(),
},
revalidate: 1,
};
}

View File

@@ -40,6 +40,6 @@ declare namespace ncc {
}
}
declare module '@zeit/ncc' {
declare module '@vercel/ncc' {
export = ncc;
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/node",
"version": "1.7.5-canary.1",
"version": "1.8.1-canary.0",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
@@ -32,7 +32,7 @@
"@types/cookie": "0.3.3",
"@types/etag": "1.8.0",
"@types/test-listen": "1.1.0",
"@zeit/ncc": "0.20.4",
"@vercel/ncc": "0.24.0",
"@zeit/node-file-trace": "0.8.2",
"content-type": "1.0.4",
"cookie": "0.4.0",

View File

@@ -73,6 +73,24 @@ function status(res: NowResponse, statusCode: number): NowResponse {
return res;
}
function redirect(
res: NowResponse,
statusOrUrl: string | number,
url?: string
): NowResponse {
if (typeof statusOrUrl === 'string') {
url = statusOrUrl;
statusOrUrl = 307;
}
if (typeof statusOrUrl !== 'number' || typeof url !== 'string') {
throw new Error(
`Invalid redirect arguments. Please use a single argument URL, e.g. res.redirect('/destination') or use a status code and URL, e.g. res.redirect(307, '/destination').`
);
}
res.writeHead(statusOrUrl, { Location: url }).end();
return res;
}
function setCharset(type: string, charset: string) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { parse, format } = require('content-type');
@@ -261,6 +279,7 @@ export function createServerWithHelpers(
setLazyProp<NowRequestBody>(req, 'body', getBodyParser(req, event.body));
res.status = statusCode => status(res, statusCode);
res.redirect = (statusOrUrl, url) => redirect(res, statusOrUrl, url);
res.send = body => send(req, res, body);
res.json = jsonBody => json(req, res, jsonBody);

View File

@@ -14,9 +14,7 @@ export type NowResponse = ServerResponse & {
send: (body: any) => NowResponse;
json: (jsonBody: any) => NowResponse;
status: (statusCode: number) => NowResponse;
redirect: (statusOrUrl: string | number, url?: string) => NowResponse;
};
export type NowApiHandler = (
req: NowRequest,
res: NowResponse
) => void;
export type NowApiHandler = (req: NowRequest, res: NowResponse) => void;

View File

@@ -65,6 +65,7 @@ describe('all helpers', () => {
['cookies', 0],
['body', 0],
['status', 1],
['redirect', 1],
['send', 1],
['json', 1],
];
@@ -307,6 +308,59 @@ describe('res.status', () => {
});
});
describe('res.redirect', () => {
test('should redirect to login', async () => {
mockListener.mockImplementation((req, res) => {
res.redirect('/login');
res.end();
});
const res = await fetchWithProxyReq(url, { redirect: 'manual' });
expect(res.status).toBe(307);
expect(res.headers.get('location')).toBe(url + '/login');
});
test('should redirect with status code 301', async () => {
mockListener.mockImplementation((req, res) => {
res.redirect(301, '/login');
res.end();
});
const res = await fetchWithProxyReq(url, { redirect: 'manual' });
expect(res.status).toBe(301);
expect(res.headers.get('location')).toBe(url + '/login');
});
test('should show friendly error for invalid redirect', async () => {
let error;
mockListener.mockImplementation((req, res) => {
try {
res.redirect(307);
} catch (err) {
error = err;
}
res.end();
});
await fetchWithProxyReq(url, { redirect: 'manual' });
expect(error.message).toBe(
`Invalid redirect arguments. Please use a single argument URL, e.g. res.redirect('/destination') or use a status code and URL, e.g. res.redirect(307, '/destination').`
);
});
test('should show friendly error in case of passing null as first argument redirect', async () => {
let error;
mockListener.mockImplementation((req, res) => {
try {
res.redirect(null);
} catch (err) {
error = err;
}
res.end();
});
await fetchWithProxyReq(url, { redirect: 'manual' });
expect(error.message).toBe(
`Invalid redirect arguments. Please use a single argument URL, e.g. res.redirect('/destination') or use a status code and URL, e.g. res.redirect(307, '/destination').`
);
});
});
// tests based on expressjs test suite
// see https://github.com/expressjs/express/blob/master/test/res.send.js
describe('res.send', () => {

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/python",
"version": "1.2.2",
"version": "1.2.3-canary.0",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
@@ -20,6 +20,7 @@
},
"devDependencies": {
"@types/execa": "^0.9.0",
"@vercel/ncc": "0.24.0",
"execa": "^1.0.0",
"typescript": "3.9.3"
}

View File

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

View File

@@ -201,13 +201,13 @@ function replaceSegments(
.filter(val => typeof val === 'string') as string[]
);
pathname = safelyCompile(pathname, indexes);
hash = hash ? safelyCompile(hash, indexes) : null;
pathname = safelyCompile(pathname, indexes, true);
hash = hash ? safelyCompile(hash, indexes, true) : null;
for (const [key, strOrArray] of Object.entries(query)) {
let value = Array.isArray(strOrArray) ? strOrArray[0] : strOrArray;
if (value) {
value = safelyCompile(value, indexes);
value = safelyCompile(value, indexes, true);
}
query[key] = value;
}
@@ -242,12 +242,24 @@ function replaceSegments(
function safelyCompile(
value: string,
indexes: { [k: string]: string }
indexes: { [k: string]: string },
attemptDirectCompile?: boolean
): string {
if (!value) {
return value;
}
if (attemptDirectCompile) {
try {
// Attempt compiling normally with path-to-regexp first and fall back
// to safely compiling to handle edge cases if path-to-regexp compile
// fails
return compile(value, { validate: false })(indexes);
} catch (e) {
// non-fatal, we continue to safely compile
}
}
for (const key of Object.keys(indexes)) {
if (value.includes(`:${key}`)) {
value = value

View File

@@ -190,6 +190,14 @@ test('convertRedirects', () => {
source: '/optional/:id?',
destination: '/api/optional/:id?',
},
{
source: '/feature-{:slug}',
destination: '/blog-{:slug}',
},
{
source: '/hello/:world',
destination: '/somewhere?else={:world}',
},
]);
const expected = [
@@ -266,6 +274,20 @@ test('convertRedirects', () => {
headers: { Location: '/api/optional/$1' },
status: 308,
},
{
headers: {
Location: '/blog-$1',
},
src: '^\\/feature-([^\\/]+?)$',
status: 308,
},
{
headers: {
Location: '/somewhere?else=$1',
},
src: '^\\/hello(?:\\/([^\\/]+?))$',
status: 308,
},
];
deepEqual(actual, expected);
@@ -285,6 +307,8 @@ test('convertRedirects', () => {
['/hello/world', '/hello/another/world'],
['/external/1', '/external/2'],
['/optional', '/optional/1'],
['/feature-first', '/feature-second'],
['/hello/world', '/hello/again'],
];
const mustNotMatch = [
@@ -302,6 +326,8 @@ test('convertRedirects', () => {
['/not-this-one', '/helloo'],
['/externalnope', '/externally'],
['/optionalnope', '/optionally'],
['/feature/first', '/feature'],
['/hello', '/hello/another/one'],
];
assertRegexMatches(actual, mustMatch, mustNotMatch);
@@ -350,6 +376,14 @@ test('convertRewrites', () => {
{ source: '/:path', destination: '/test?path=:path' },
{ source: '/:path/:two', destination: '/test?path=:path' },
{ source: '/(.*)-:id(\\d+).html', destination: '/blog/:id' },
{
source: '/feature-{:slug}',
destination: '/blog-{:slug}',
},
{
source: '/hello/:world',
destination: '/somewhere?else={:world}',
},
]);
const expected = [
@@ -426,6 +460,16 @@ test('convertRewrites', () => {
src: '^(?:\\/([^\\/]+?))(?:\\/([^\\/]+?))$',
},
{ check: true, dest: '/blog/$2', src: '^(?:\\/(.*))-(\\d+)\\.html$' },
{
dest: '/blog-$1',
src: '^\\/feature-([^\\/]+?)$',
check: true,
},
{
dest: '/somewhere?else=$1&world=$1',
src: '^\\/hello(?:\\/([^\\/]+?))$',
check: true,
},
];
deepEqual(actual, expected);
@@ -447,6 +491,8 @@ test('convertRewrites', () => {
['/first', '/another'],
['/first/second', '/one/two'],
['/hello/post-123.html', '/post-123.html'],
['/feature-first', '/feature-second'],
['/hello/world', '/hello/again'],
];
const mustNotMatch = [
@@ -466,6 +512,8 @@ test('convertRewrites', () => {
['/another/one'],
['/not', '/these'],
['/hello/post.html'],
['/feature/first', '/feature'],
['/hello', '/hello/another/one'],
];
assertRegexMatches(actual, mustMatch, mustNotMatch);

View File

@@ -1,7 +1,7 @@
{
"name": "@vercel/ruby",
"author": "Nathan Cahill <nathan@nathancahill.com>",
"version": "1.2.3",
"version": "1.2.4-canary.0",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby",
@@ -22,6 +22,7 @@
"devDependencies": {
"@types/fs-extra": "8.0.0",
"@types/semver": "6.0.0",
"@vercel/ncc": "0.24.0",
"execa": "2.0.4",
"fs-extra": "^7.0.1",
"semver": "6.1.1",

View File

@@ -1,9 +1,9 @@
{
"name": "@vercel/static-build",
"version": "0.17.7-canary.3",
"version": "0.17.8-canary.0",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/static-builds",
"homepage": "https://vercel.com/docs/build-step",
"files": [
"dist"
],
@@ -23,6 +23,7 @@
"@types/ms": "0.7.31",
"@types/node-fetch": "2.5.4",
"@types/promise-timeout": "1.3.0",
"@vercel/ncc": "0.24.0",
"get-port": "5.0.0",
"is-port-reachable": "2.0.1",
"ms": "2.1.2",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/redwood",
"version": "0.0.2-canary.7",
"version": "0.1.1-canary.0",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://vercel.com/docs",
@@ -19,7 +19,7 @@
},
"dependencies": {
"@netlify/zip-it-and-ship-it": "1.2.0",
"@vercel/frameworks": "0.0.18-canary.5"
"@vercel/frameworks": "0.1.1-canary.0"
},
"devDependencies": {
"@types/aws-lambda": "8.10.19",

View File

@@ -1,5 +1,4 @@
import { join, dirname, relative, parse as parsePath, sep } from 'path';
import { readFileSync } from 'fs';
import {
BuildOptions,
Lambda,
@@ -18,6 +17,8 @@ import {
FileFsRef,
PackageJson,
NowBuildError,
getLambdaOptionsFromFunction,
readConfigFile,
} from '@vercel/build-utils';
import { makeAwsLauncher } from './launcher';
import _frameworks, { Framework } from '@vercel/frameworks';
@@ -32,6 +33,12 @@ const BRIDGE_FILENAME = '___vc_bridge';
const HELPERS_FILENAME = '___vc_helpers';
const SOURCEMAP_SUPPORT_FILENAME = '__vc_sourcemap_support';
interface RedwoodToml {
web: { port?: number; apiProxyPath?: string };
api: { port?: number };
browser: { open?: boolean };
}
export const version = 2;
export async function build({
@@ -67,8 +74,11 @@ export async function build({
const { buildCommand } = config;
const frmwrkCmd = frameworks.find(f => f.slug === 'redwoodjs')?.settings
.buildCommand;
const pkgPath = join(workPath, 'package.json');
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as PackageJson;
const pkg = await readConfigFile<PackageJson>(join(workPath, 'package.json'));
const toml = await readConfigFile<RedwoodToml>(
join(workPath, 'redwood.toml')
);
if (buildCommand) {
debug(`Executing build command "${buildCommand}"`);
await execCommand(buildCommand, {
@@ -98,6 +108,7 @@ export async function build({
});
}
const apiDir = toml?.web?.apiProxyPath?.replace(/^\//, '') ?? 'api';
const apiDistPath = join(workPath, 'api', 'dist', 'functions');
const webDistPath = join(workPath, 'web', 'dist');
const lambdaOutputs: { [filePath: string]: Lambda } = {};
@@ -107,7 +118,7 @@ export async function build({
const functionFiles = await glob('*.js', apiDistPath);
for (const [funcName, fileFsRef] of Object.entries(functionFiles)) {
const outputName = join('api', parsePath(funcName).name); // remove `.js` extension
const outputName = join(apiDir, parsePath(funcName).name); // remove `.js` extension
const absEntrypoint = fileFsRef.fsPath;
const dependencies: string[] = await getDependencies(
absEntrypoint,
@@ -115,6 +126,7 @@ export async function build({
);
const relativeEntrypoint = relative(workPath, absEntrypoint);
const awsLambdaHandler = getAWSLambdaHandler(relativeEntrypoint, 'handler');
const sourceFile = relativeEntrypoint.replace('/dist/', '/src/');
const lambdaFiles: Files = {
[`${LAUNCHER_FILENAME}.js`]: new FileBlob({
@@ -141,11 +153,18 @@ export async function build({
lambdaFiles[relative(workPath, fileFsRef.fsPath)] = fileFsRef;
const { memory, maxDuration } = await getLambdaOptionsFromFunction({
sourceFile,
config,
});
const lambda = await createLambda({
files: lambdaFiles,
handler: `${LAUNCHER_FILENAME}.launcher`,
runtime: nodeVersion.runtime,
environment: {},
memory,
maxDuration,
});
lambdaOutputs[outputName] = lambda;
}
@@ -162,7 +181,7 @@ function getAWSLambdaHandler(filePath: string, handlerName: string) {
return `${dir}${dir ? sep : ''}${name}.${handlerName}`;
}
function hasScript(scriptName: string, pkg: PackageJson) {
function hasScript(scriptName: string, pkg: PackageJson | null) {
const scripts = (pkg && pkg.scripts) || {};
return typeof scripts[scriptName] === 'string';
}
@@ -170,6 +189,6 @@ function hasScript(scriptName: string, pkg: PackageJson) {
export async function prepareCache({
workPath,
}: PrepareCacheOptions): Promise<Files> {
const cache = await glob('node_modules/**', workPath);
const cache = await glob('**/node_modules/**', workPath);
return cache;
}

View File

@@ -0,0 +1,9 @@
async function handler() {
return {
statusCode: 200,
headers: {},
body: `Memory is: ${process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE}`,
}
}
module.exports = { handler }

View File

@@ -1,6 +1,19 @@
{
"version": 2,
"builds": [{ "src": "package.json", "use": "@vercel/redwood" }],
"builds": [
{
"src": "package.json",
"use": "@vercel/redwood",
"config": {
"zeroConfig": true,
"functions": {
"api/src/functions/memory.js": {
"memory": 128
}
}
}
}
],
"probes": [
{ "path": "/", "mustContain": "<div id=\"redwood-app\">" },
{ "path": "/about", "mustContain": "<div id=\"redwood-app\">" },
@@ -19,6 +32,10 @@
{
"path": "/api/permission",
"mustContain": "File is executable: true"
},
{
"path": "/api/memory",
"mustContain": "Memory is: 128"
}
]
}

View File

@@ -1,15 +1,6 @@
# This file contains the configuration settings for your Redwood app.
# This file is also what makes your Redwood app a Redwood app.
# If you remove it and try to run `yarn rw dev`, you'll get an error.
#
# For the full list of options, see the "App Configuration: redwood.toml" doc:
# https://redwoodjs.com/docs/app-configuration-redwood-toml
#
# By default, a Redwood app's apiProxyPath is the same as Netlify's.
[web]
port = 8910
apiProxyPath = "/api/functions"
apiProxyPath = "/api"
[api]
port = 8911
[browser]

View File

@@ -0,0 +1,10 @@
# These environment variables will be used by default if you do not create any
# yourself in .env. This file should be safe to check into your version control
# system. Any custom values should go in .env and .env should *not* be checked
# into version control.
# schema.prisma defaults
DATABASE_URL=file:./dev.db
# disables Prisma CLI update notifier
PRISMA_HIDE_UPDATE_MESSAGE=true

View File

@@ -0,0 +1,10 @@
.idea
.DS_Store
.env
.netlify
dev.db
dist
dist-babel
node_modules
yarn-error.log
web/public/mockServiceWorker.js

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Redwood
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,25 @@
# Redwood
> **WARNING:** RedwoodJS software has not reached a stable version 1.0 and should not be considered suitable for production use. In the "make it work; make it right; make it fast" paradigm, Redwood is in the later stages of the "make it work" phase.
## Getting Started
- [Tutorial](https://redwoodjs.com/tutorial/welcome-to-redwood): getting started and complete overview guide.
- [Docs](https://redwoodjs.com/docs/introduction): using the Redwood Router, handling assets and files, list of command-line tools, and more.
- [Redwood Community](https://community.redwoodjs.com): get help, share tips and tricks, and collaborate on everything about RedwoodJS.
### Setup
We use Yarn as our package manager. To get the dependencies installed, just do this in the root directory:
```terminal
yarn install
```
### Fire it up
```terminal
yarn redwood dev
```
Your browser should open automatically to `http://localhost:8910` to see the web app. Lambda functions run on `http://localhost:8911` and are also proxied to `http://localhost:8910/.redwood/functions/*`.

View File

@@ -0,0 +1 @@
module.exports = { extends: '../babel.config.js' }

View File

@@ -0,0 +1,6 @@
const { getConfig } = require('@redwoodjs/core')
const config = getConfig({ type: 'jest', target: 'node' })
config.displayName.name = 'api'
module.exports = config

View File

@@ -0,0 +1,9 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"src/*": ["./src/*"]
}
},
"include": ["src/**/*"]
}

View File

@@ -0,0 +1,8 @@
{
"name": "api",
"version": "0.0.0",
"private": true,
"dependencies": {
"@redwoodjs/api": "^0.16.0"
}
}

View File

@@ -0,0 +1,20 @@
datasource DS {
// optionally set multiple providers
// example: provider = ["sqlite", "postgresql"]
provider = "sqlite"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
binaryTargets = "native"
}
// Define your own datamodels here and run `yarn redwood db save` to create
// migrations for them.
// TODO: Please remove the following example:
model UserExample {
id Int @id @default(autoincrement())
email String @unique
name String?
}

View File

@@ -0,0 +1,26 @@
/* eslint-disable no-console */
const { PrismaClient } = require('@prisma/client')
const dotenv = require('dotenv')
dotenv.config()
const db = new PrismaClient()
async function main() {
// Seed data is database data that needs to exist for your app to run.
// Ideally this file should be idempotent: running it multiple times
// will result in the same database state (usually by checking for the
// existence of a record before trying to create it). For example:
//
// const existing = await db.user.findMany({ where: { email: 'admin@email.com' }})
// if (!existing.length) {
// await db.user.create({ data: { name: 'Admin', email: 'admin@email.com' }})
// }
console.info('No data to seed. See api/prisma/seeds.js for info.')
}
main()
.catch((e) => console.error(e))
.finally(async () => {
await db.disconnect()
})

View File

@@ -0,0 +1,17 @@
import {
createGraphQLHandler,
makeMergedSchema,
makeServices,
} from '@redwoodjs/api'
import schemas from 'src/graphql/**/*.{js,ts}'
import services from 'src/services/**/*.{js,ts}'
import { db } from 'src/lib/db'
export const handler = createGraphQLHandler({
schema: makeMergedSchema({
schemas,
services: makeServices({ services }),
}),
db,
})

View File

@@ -0,0 +1,6 @@
// See https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/constructor
// for options.
import { PrismaClient } from '@prisma/client'
export const db = new PrismaClient()

View File

@@ -0,0 +1,3 @@
module.exports = {
presets: ['@redwoodjs/core/config/babel-preset'],
}

View File

@@ -0,0 +1,16 @@
{
"private": true,
"workspaces": {
"packages": [
"api",
"web"
]
},
"devDependencies": {
"@redwoodjs/core": "^0.16.0"
},
"engines": {
"node": ">=12",
"yarn": ">=1.15"
}
}

View File

@@ -0,0 +1,9 @@
// https://prettier.io/docs/en/options.html
module.exports = {
trailingComma: 'es5',
bracketSpacing: true,
tabWidth: 2,
semi: false,
singleQuote: true,
arrowParens: 'always',
}

View File

@@ -0,0 +1,14 @@
# This file contains the configuration settings for your Redwood app.
# This file is also what makes your Redwood app a Redwood app.
# If you remove it and try to run `yarn rw dev`, you'll get an error.
#
# For the full list of options, see the "App Configuration: redwood.toml" doc:
# https://redwoodjs.com/docs/app-configuration-redwood-toml
[web]
port = 8910
apiProxyPath = "/.redwood/functions"
[api]
port = 8911
[browser]
open = true

View File

@@ -0,0 +1,19 @@
{
"version": 2,
"builds": [{ "src": "package.json", "use": "@vercel/redwood" }],
"probes": [
{ "path": "/", "mustContain": "<div id=\"redwood-app\">" },
{
"path": "/.redwood/functions/graphql",
"headers": { "Accept": "text/html" },
"mustContain": "<title>GraphQL Playground</title>"
},
{
"path": "/.redwood/functions/graphql",
"method": "POST",
"headers": { "Accept": "application/json" },
"body": { "query": "{ redwood { version } }" },
"mustContain": "0.16.0"
}
]
}

View File

@@ -0,0 +1 @@
module.exports = { extends: '../babel.config.js' }

View File

@@ -0,0 +1,6 @@
const { getConfig } = require('@redwoodjs/core')
const config = getConfig({ type: 'jest', target: 'browser' })
config.displayName.name = 'web'
module.exports = config

View File

@@ -0,0 +1,10 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"src/*": ["./src/*"]
},
"jsx": "preserve"
},
"include": ["src/**/*"]
}

View File

@@ -0,0 +1,15 @@
{
"name": "web",
"version": "0.0.0",
"private": true,
"browserslist": [
"defaults"
],
"dependencies": {
"@redwoodjs/router": "^0.16.0",
"@redwoodjs/web": "^0.16.0",
"prop-types": "^15.7.2",
"react": "^16.13.1",
"react-dom": "^16.13.1"
}
}

View File

@@ -0,0 +1,45 @@
# Static Assets
Use this folder to add static files directly to your app. All included files and folders will be copied directly into the `/dist` folder (created when Webpack builds for production). They will also be available during development when you run `yarn rw dev`.
> Note: files will _not_ hot reload while the development server is running. You'll need to manually stop/start to access file changes.
### Example Use
A file like `favicon.png` will be copied to `/dist/favicon.png`. A folder containing a file such as `static-files/my-logo.jpg` will be copied to `/dist/static-files/my-logo.jpg`. These can be referenced in your code directly without any special handling, e.g.
```
<link rel="icon" type="image/png" href="/favicon.png" />
```
and
```
<img src="/static-files/my-logo.jpg"> alt="Logo" />
```
Behind the scenes, we are using Webpack's ["copy-webpack-plugin"](https://github.com/webpack-contrib/copy-webpack-plugin).
## Best Practices
Because assets in this folder are bypassing the javascript module system, **this folder should be used sparingly** for assets such as favicons, robots.txt, manifests, libraries incompatible with Webpack, etc.
In general, it's best to import files directly into a template, page, or component. This allows Webpack to include that file in the bundle, which ensures Webpack will correctly process and move assets into the distribution folder, providing error checks and correct paths along the way.
### Example Asset Import with Webpack
Instead of handling our logo image as a static file per the example above, we can do the following:
```
import React from "react"
import logo from "./my-logo.jpg"
function Header() {
return <img src={logo} alt="Logo" />
}
export default Header
```
Behind the scenes, we are using Webpack's ["file-loader"](https://webpack.js.org/loaders/file-loader/) and ["url-loader](https://webpack.js.org/loaders/url-loader/) (for files smaller than 10kb).

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,2 @@
User-agent: *
Disallow:

View File

@@ -0,0 +1,20 @@
// In this file, all Page components from 'src/pages` are auto-imported. Nested
// directories are supported, and should be uppercase. Each subdirectory will be
// prepended onto the component name.
//
// Examples:
//
// 'src/pages/HomePage/HomePage.js' -> HomePage
// 'src/pages/Admin/BooksPage/BooksPage.js' -> AdminBooksPage
import { Router, Route } from '@redwoodjs/router'
const Routes = () => {
return (
<Router>
<Route notfound page={NotFoundPage} />
</Router>
)
}
export default Routes

View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/png" href="/favicon.png" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="redwood-app"></div>
</body>
</html>

View File

@@ -0,0 +1,16 @@
import ReactDOM from 'react-dom'
import { RedwoodProvider, FatalErrorBoundary } from '@redwoodjs/web'
import FatalErrorPage from 'src/pages/FatalErrorPage'
import Routes from 'src/Routes'
import './index.css'
ReactDOM.render(
<FatalErrorBoundary page={FatalErrorPage}>
<RedwoodProvider>
<Routes />
</RedwoodProvider>
</FatalErrorBoundary>,
document.getElementById('redwood-app')
)

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