mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-23 18:09:11 +00:00
Compare commits
26 Commits
vercel@20.
...
@vercel/py
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05c534d855 | ||
|
|
910169dba7 | ||
|
|
0fc74feddc | ||
|
|
a9ea294514 | ||
|
|
42e0450d87 | ||
|
|
08c0feb58a | ||
|
|
60aaf76ed2 | ||
|
|
bd706beba5 | ||
|
|
b85a0a349a | ||
|
|
a97bc2af6d | ||
|
|
a5dc90c8cd | ||
|
|
e90521b5a4 | ||
|
|
10c598834a | ||
|
|
e58b34b82c | ||
|
|
02e1c921ac | ||
|
|
fcb14fa70e | ||
|
|
46e18128c7 | ||
|
|
e06d5247ef | ||
|
|
02195b92a7 | ||
|
|
7945155a0f | ||
|
|
edb6043c2c | ||
|
|
971481ba51 | ||
|
|
db8e456603 | ||
|
|
d1b4f24a4a | ||
|
|
4eb39ed53b | ||
|
|
6c7236ffd5 |
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||

|
||||
|
||||
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)
|
||||
|
||||
[](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)
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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`
|
||||
` ${chalk.cyan('Renewal Price')}\t\t${
|
||||
domain.boughtAt && renewalPrice ? `$${renewalPrice} USD` : chalk.gray('-')
|
||||
}\n`
|
||||
);
|
||||
}
|
||||
|
||||
output.print('\n');
|
||||
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
|
||||
@@ -1475,7 +1475,15 @@ export default class DevServer {
|
||||
routeResult.status = prevStatus;
|
||||
}
|
||||
|
||||
if (!match && errorRoutes.length > 0) {
|
||||
statusCode = routeResult.status;
|
||||
|
||||
if (match) {
|
||||
// end the phase
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!match && routeResult && errorRoutes.length > 0) {
|
||||
// error phase
|
||||
const routeResultForError = await devRouter(
|
||||
getReqUrl(routeResult),
|
||||
@@ -1487,6 +1495,7 @@ export default class DevServer {
|
||||
[],
|
||||
'error'
|
||||
);
|
||||
const { matched_route } = routeResultForError;
|
||||
|
||||
const matchForError = await findBuildMatch(
|
||||
this.buildMatches,
|
||||
@@ -1497,18 +1506,27 @@ export default class DevServer {
|
||||
);
|
||||
|
||||
if (matchForError) {
|
||||
// error phase only applies if the file was found
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
statusCode = routeResult.status;
|
||||
|
||||
if (match) {
|
||||
// end the phase
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!routeResult) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
29
packages/now-cli/test/integration.js
vendored
29
packages/now-cli/test/integration.js
vendored
@@ -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';
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 (indications.has(type)) {
|
||||
debug(`Deployment created with a ${type}: `, payload);
|
||||
yield { type, payload, action, link };
|
||||
}
|
||||
if (name.startsWith('x-now-tip-')) {
|
||||
debug('Deployment created with a tip:', value);
|
||||
yield { type: 'tip', payload: value };
|
||||
}
|
||||
}
|
||||
yield { type: 'created', payload: deployment };
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
52
packages/now-next/test/fixtures/00-root-optional-revalidate/additional.js
vendored
Normal file
52
packages/now-next/test/fixtures/00-root-optional-revalidate/additional.js
vendored
Normal 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);
|
||||
});
|
||||
};
|
||||
15
packages/now-next/test/fixtures/00-root-optional-revalidate/now.json
vendored
Normal file
15
packages/now-next/test/fixtures/00-root-optional-revalidate/now.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@vercel/next"
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
{
|
||||
"path": "/non-existent",
|
||||
"status": 404
|
||||
}
|
||||
]
|
||||
}
|
||||
7
packages/now-next/test/fixtures/00-root-optional-revalidate/package.json
vendored
Normal file
7
packages/now-next/test/fixtures/00-root-optional-revalidate/package.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"next": "canary",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
}
|
||||
}
|
||||
24
packages/now-next/test/fixtures/00-root-optional-revalidate/pages/[[...slug]].js
vendored
Normal file
24
packages/now-next/test/fixtures/00-root-optional-revalidate/pages/[[...slug]].js
vendored
Normal 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,
|
||||
};
|
||||
}
|
||||
@@ -40,6 +40,6 @@ declare namespace ncc {
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@zeit/ncc' {
|
||||
declare module '@vercel/ncc' {
|
||||
export = ncc;
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
54
packages/now-node/test/helpers.test.js
vendored
54
packages/now-node/test/helpers.test.js
vendored
@@ -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', () => {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
9
packages/redwood/test/fixtures/01-create-redwood-app/api/src/functions/memory.js
vendored
Normal file
9
packages/redwood/test/fixtures/01-create-redwood-app/api/src/functions/memory.js
vendored
Normal 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 }
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
|
||||
10
packages/redwood/test/fixtures/16-create-redwood-app/.env.defaults
vendored
Normal file
10
packages/redwood/test/fixtures/16-create-redwood-app/.env.defaults
vendored
Normal 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
|
||||
10
packages/redwood/test/fixtures/16-create-redwood-app/.gitignore
vendored
Normal file
10
packages/redwood/test/fixtures/16-create-redwood-app/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
.idea
|
||||
.DS_Store
|
||||
.env
|
||||
.netlify
|
||||
dev.db
|
||||
dist
|
||||
dist-babel
|
||||
node_modules
|
||||
yarn-error.log
|
||||
web/public/mockServiceWorker.js
|
||||
21
packages/redwood/test/fixtures/16-create-redwood-app/LICENSE
vendored
Normal file
21
packages/redwood/test/fixtures/16-create-redwood-app/LICENSE
vendored
Normal 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.
|
||||
25
packages/redwood/test/fixtures/16-create-redwood-app/README.md
vendored
Normal file
25
packages/redwood/test/fixtures/16-create-redwood-app/README.md
vendored
Normal 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/*`.
|
||||
1
packages/redwood/test/fixtures/16-create-redwood-app/api/.babelrc.js
vendored
Normal file
1
packages/redwood/test/fixtures/16-create-redwood-app/api/.babelrc.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = { extends: '../babel.config.js' }
|
||||
6
packages/redwood/test/fixtures/16-create-redwood-app/api/jest.config.js
vendored
Normal file
6
packages/redwood/test/fixtures/16-create-redwood-app/api/jest.config.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
const { getConfig } = require('@redwoodjs/core')
|
||||
|
||||
const config = getConfig({ type: 'jest', target: 'node' })
|
||||
config.displayName.name = 'api'
|
||||
|
||||
module.exports = config
|
||||
9
packages/redwood/test/fixtures/16-create-redwood-app/api/jsconfig.json
vendored
Normal file
9
packages/redwood/test/fixtures/16-create-redwood-app/api/jsconfig.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"src/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
8
packages/redwood/test/fixtures/16-create-redwood-app/api/package.json
vendored
Normal file
8
packages/redwood/test/fixtures/16-create-redwood-app/api/package.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "api",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@redwoodjs/api": "^0.16.0"
|
||||
}
|
||||
}
|
||||
20
packages/redwood/test/fixtures/16-create-redwood-app/api/prisma/schema.prisma
vendored
Normal file
20
packages/redwood/test/fixtures/16-create-redwood-app/api/prisma/schema.prisma
vendored
Normal 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?
|
||||
}
|
||||
26
packages/redwood/test/fixtures/16-create-redwood-app/api/prisma/seeds.js
vendored
Normal file
26
packages/redwood/test/fixtures/16-create-redwood-app/api/prisma/seeds.js
vendored
Normal 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()
|
||||
})
|
||||
17
packages/redwood/test/fixtures/16-create-redwood-app/api/src/functions/graphql.js
vendored
Normal file
17
packages/redwood/test/fixtures/16-create-redwood-app/api/src/functions/graphql.js
vendored
Normal 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,
|
||||
})
|
||||
0
packages/redwood/test/fixtures/16-create-redwood-app/api/src/graphql/.keep
vendored
Normal file
0
packages/redwood/test/fixtures/16-create-redwood-app/api/src/graphql/.keep
vendored
Normal file
6
packages/redwood/test/fixtures/16-create-redwood-app/api/src/lib/db.js
vendored
Normal file
6
packages/redwood/test/fixtures/16-create-redwood-app/api/src/lib/db.js
vendored
Normal 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()
|
||||
0
packages/redwood/test/fixtures/16-create-redwood-app/api/src/services/.keep
vendored
Normal file
0
packages/redwood/test/fixtures/16-create-redwood-app/api/src/services/.keep
vendored
Normal file
3
packages/redwood/test/fixtures/16-create-redwood-app/babel.config.js
vendored
Normal file
3
packages/redwood/test/fixtures/16-create-redwood-app/babel.config.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
presets: ['@redwoodjs/core/config/babel-preset'],
|
||||
}
|
||||
16
packages/redwood/test/fixtures/16-create-redwood-app/package.json
vendored
Normal file
16
packages/redwood/test/fixtures/16-create-redwood-app/package.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"private": true,
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"api",
|
||||
"web"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@redwoodjs/core": "^0.16.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"yarn": ">=1.15"
|
||||
}
|
||||
}
|
||||
9
packages/redwood/test/fixtures/16-create-redwood-app/prettier.config.js
vendored
Normal file
9
packages/redwood/test/fixtures/16-create-redwood-app/prettier.config.js
vendored
Normal 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',
|
||||
}
|
||||
14
packages/redwood/test/fixtures/16-create-redwood-app/redwood.toml
vendored
Normal file
14
packages/redwood/test/fixtures/16-create-redwood-app/redwood.toml
vendored
Normal 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
|
||||
19
packages/redwood/test/fixtures/16-create-redwood-app/vercel.json
vendored
Normal file
19
packages/redwood/test/fixtures/16-create-redwood-app/vercel.json
vendored
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
1
packages/redwood/test/fixtures/16-create-redwood-app/web/.babelrc.js
vendored
Normal file
1
packages/redwood/test/fixtures/16-create-redwood-app/web/.babelrc.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = { extends: '../babel.config.js' }
|
||||
6
packages/redwood/test/fixtures/16-create-redwood-app/web/jest.config.js
vendored
Normal file
6
packages/redwood/test/fixtures/16-create-redwood-app/web/jest.config.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
const { getConfig } = require('@redwoodjs/core')
|
||||
|
||||
const config = getConfig({ type: 'jest', target: 'browser' })
|
||||
config.displayName.name = 'web'
|
||||
|
||||
module.exports = config
|
||||
10
packages/redwood/test/fixtures/16-create-redwood-app/web/jsconfig.json
vendored
Normal file
10
packages/redwood/test/fixtures/16-create-redwood-app/web/jsconfig.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"src/*": ["./src/*"]
|
||||
},
|
||||
"jsx": "preserve"
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
15
packages/redwood/test/fixtures/16-create-redwood-app/web/package.json
vendored
Normal file
15
packages/redwood/test/fixtures/16-create-redwood-app/web/package.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
||||
45
packages/redwood/test/fixtures/16-create-redwood-app/web/public/README.md
vendored
Normal file
45
packages/redwood/test/fixtures/16-create-redwood-app/web/public/README.md
vendored
Normal 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).
|
||||
BIN
packages/redwood/test/fixtures/16-create-redwood-app/web/public/favicon.png
vendored
Normal file
BIN
packages/redwood/test/fixtures/16-create-redwood-app/web/public/favicon.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
2
packages/redwood/test/fixtures/16-create-redwood-app/web/public/robots.txt
vendored
Normal file
2
packages/redwood/test/fixtures/16-create-redwood-app/web/public/robots.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
20
packages/redwood/test/fixtures/16-create-redwood-app/web/src/Routes.js
vendored
Normal file
20
packages/redwood/test/fixtures/16-create-redwood-app/web/src/Routes.js
vendored
Normal 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
|
||||
0
packages/redwood/test/fixtures/16-create-redwood-app/web/src/components/.keep
vendored
Normal file
0
packages/redwood/test/fixtures/16-create-redwood-app/web/src/components/.keep
vendored
Normal file
0
packages/redwood/test/fixtures/16-create-redwood-app/web/src/index.css
vendored
Normal file
0
packages/redwood/test/fixtures/16-create-redwood-app/web/src/index.css
vendored
Normal file
12
packages/redwood/test/fixtures/16-create-redwood-app/web/src/index.html
vendored
Normal file
12
packages/redwood/test/fixtures/16-create-redwood-app/web/src/index.html
vendored
Normal 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>
|
||||
16
packages/redwood/test/fixtures/16-create-redwood-app/web/src/index.js
vendored
Normal file
16
packages/redwood/test/fixtures/16-create-redwood-app/web/src/index.js
vendored
Normal 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')
|
||||
)
|
||||
0
packages/redwood/test/fixtures/16-create-redwood-app/web/src/layouts/.keep
vendored
Normal file
0
packages/redwood/test/fixtures/16-create-redwood-app/web/src/layouts/.keep
vendored
Normal file
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user