mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-24 19:00:03 +00:00
Compare commits
30 Commits
@vercel/ne
...
@vercel/ne
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b190f2e118 | ||
|
|
2389d3e936 | ||
|
|
0f4ed1965a | ||
|
|
e1e38ee536 | ||
|
|
dc1ff00610 | ||
|
|
5f31736603 | ||
|
|
9a57cc72dd | ||
|
|
9d9c5f3753 | ||
|
|
deeefc0c93 | ||
|
|
5c23b08bc1 | ||
|
|
7c4e25ccce | ||
|
|
1bfa310945 | ||
|
|
c96062266b | ||
|
|
5bea99c1d9 | ||
|
|
358be773a2 | ||
|
|
9ebf4e531d | ||
|
|
71e79258b7 | ||
|
|
1dfafe7040 | ||
|
|
78ed452a99 | ||
|
|
d408e2ef1a | ||
|
|
8ebb1fd9ce | ||
|
|
4eb5ad625c | ||
|
|
7164f6e58e | ||
|
|
a36d084b3e | ||
|
|
8a16447fed | ||
|
|
efda4ab6b9 | ||
|
|
16060a71a9 | ||
|
|
b18e0a7415 | ||
|
|
1251f11a97 | ||
|
|
07235e22f6 |
@@ -34,6 +34,7 @@ packages/now-node-bridge/bridge.*
|
||||
|
||||
# now-static-build
|
||||
packages/now-static-build/test/fixtures
|
||||
packages/now-static-build/test/build-fixtures
|
||||
|
||||
# redwood
|
||||
packages/redwood/test/fixtures
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "9.5.4",
|
||||
"react": "16.13.1",
|
||||
"react-dom": "16.13.1"
|
||||
"next": "10.0.0",
|
||||
"react": "17.0.1",
|
||||
"react-dom": "17.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `blitz build`"
|
||||
},
|
||||
@@ -47,6 +50,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `next build`"
|
||||
},
|
||||
@@ -82,6 +88,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `gatsby build`"
|
||||
},
|
||||
@@ -111,6 +120,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `hexo generate`"
|
||||
},
|
||||
@@ -140,6 +152,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `npx @11ty/eleventy`"
|
||||
},
|
||||
@@ -168,6 +183,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `docusaurus build`"
|
||||
},
|
||||
@@ -196,6 +214,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `docusaurus-build`"
|
||||
},
|
||||
@@ -224,6 +245,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `preact build`"
|
||||
},
|
||||
@@ -255,6 +279,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `dojo build`"
|
||||
},
|
||||
@@ -283,6 +310,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `ember build`"
|
||||
},
|
||||
@@ -311,6 +341,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `vue-cli-service build`"
|
||||
},
|
||||
@@ -339,6 +372,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `ng build && scully`"
|
||||
},
|
||||
@@ -367,6 +403,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `ng build`"
|
||||
},
|
||||
@@ -395,6 +434,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `ng build`"
|
||||
},
|
||||
@@ -423,6 +465,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `polymer build`"
|
||||
},
|
||||
@@ -451,6 +496,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `rollup -c`"
|
||||
},
|
||||
@@ -479,6 +527,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `react-scripts build`"
|
||||
},
|
||||
@@ -511,6 +562,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `react-scripts build`"
|
||||
},
|
||||
@@ -539,6 +593,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `gridsome build`"
|
||||
},
|
||||
@@ -567,6 +624,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `umi build`"
|
||||
},
|
||||
@@ -595,6 +655,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `sapper export`"
|
||||
},
|
||||
@@ -623,6 +686,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `saber build`"
|
||||
},
|
||||
@@ -651,6 +717,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `stencil build`"
|
||||
},
|
||||
@@ -679,6 +748,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `nuxt generate`"
|
||||
},
|
||||
@@ -709,6 +781,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"value": "yarn rw build && yarn rw db up --no-db-client --auto-approve && yarn rw dataMigrate up"
|
||||
},
|
||||
@@ -743,6 +818,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "None"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `hugo -D --gc`"
|
||||
},
|
||||
@@ -770,6 +848,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`bundle install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `jekyll build`"
|
||||
},
|
||||
@@ -797,6 +878,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run build` or `brunch build --production`"
|
||||
},
|
||||
@@ -824,6 +908,9 @@
|
||||
]
|
||||
},
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`bundle install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"value": "`npm run build` or `bundle exec middleman build`"
|
||||
},
|
||||
@@ -841,6 +928,9 @@
|
||||
"logo": "https://raw.githubusercontent.com/vercel/vercel/master/packages/frameworks/logos/other.svg",
|
||||
"description": "No framework or a unoptimized framework.",
|
||||
"settings": {
|
||||
"installCommand": {
|
||||
"placeholder": "`yarn install` or `npm install`"
|
||||
},
|
||||
"buildCommand": {
|
||||
"placeholder": "`npm run vercel-build` or `npm run build`"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/frameworks",
|
||||
"version": "0.1.2-canary.0",
|
||||
"version": "0.1.2-canary.1",
|
||||
"main": "frameworks.json",
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
|
||||
@@ -89,9 +89,15 @@ const Schema = {
|
||||
},
|
||||
settings: {
|
||||
type: 'object',
|
||||
required: ['buildCommand', 'devCommand', 'outputDirectory'],
|
||||
required: [
|
||||
'installCommand',
|
||||
'buildCommand',
|
||||
'devCommand',
|
||||
'outputDirectory',
|
||||
],
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
installCommand: SchemaSettings,
|
||||
buildCommand: SchemaSettings,
|
||||
devCommand: SchemaSettings,
|
||||
outputDirectory: SchemaSettings,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "2.5.5-canary.0",
|
||||
"version": "2.5.5-canary.1",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
@@ -29,7 +29,7 @@
|
||||
"@types/node-fetch": "^2.1.6",
|
||||
"@types/semver": "6.0.0",
|
||||
"@types/yazl": "^2.4.1",
|
||||
"@vercel/frameworks": "0.1.2-canary.0",
|
||||
"@vercel/frameworks": "0.1.2-canary.1",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"aggregate-error": "3.0.1",
|
||||
"async-retry": "1.2.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel",
|
||||
"version": "20.1.3-canary.0",
|
||||
"version": "20.1.3-canary.5",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Vercel",
|
||||
@@ -13,7 +13,7 @@
|
||||
"scripts": {
|
||||
"preinstall": "node ./scripts/preinstall.js",
|
||||
"test-unit": "nyc ava test/unit.js test/dev-builder.unit.js test/dev-router.unit.js test/dev-server.unit.js test/dev-validate.unit.js --serial --fail-fast --verbose",
|
||||
"test-integration-cli": "ava test/integration.js --serial --fail-fast --verbose",
|
||||
"test-integration-cli": "rimraf test/fixtures/integration && ava test/integration.js --serial --fail-fast --verbose",
|
||||
"test-integration-dev": "ava test/dev/integration.js --serial --fail-fast --verbose",
|
||||
"prepublishOnly": "yarn build",
|
||||
"coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
|
||||
@@ -61,7 +61,7 @@
|
||||
"node": ">= 10"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.5.5-canary.0",
|
||||
"@vercel/build-utils": "2.5.5-canary.1",
|
||||
"@vercel/go": "1.1.6",
|
||||
"@vercel/node": "1.8.4",
|
||||
"@vercel/python": "1.2.3",
|
||||
@@ -100,7 +100,7 @@
|
||||
"@types/universal-analytics": "0.4.2",
|
||||
"@types/which": "1.3.2",
|
||||
"@types/write-json-file": "2.2.1",
|
||||
"@vercel/frameworks": "0.1.2-canary.0",
|
||||
"@vercel/frameworks": "0.1.2-canary.1",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@zeit/fun": "0.11.2",
|
||||
"@zeit/source-map-support": "0.6.2",
|
||||
@@ -146,7 +146,6 @@
|
||||
"minimatch": "3.0.4",
|
||||
"mri": "1.1.5",
|
||||
"ms": "2.1.2",
|
||||
"nanoid": "3.0.2",
|
||||
"node-fetch": "2.6.1",
|
||||
"npm-package-arg": "6.1.0",
|
||||
"nyc": "13.2.0",
|
||||
@@ -158,6 +157,7 @@
|
||||
"psl": "1.1.31",
|
||||
"qr-image": "3.2.0",
|
||||
"raw-body": "2.4.1",
|
||||
"rimraf": "3.0.2",
|
||||
"semver": "5.5.0",
|
||||
"serve-handler": "6.1.1",
|
||||
"sinon": "4.4.2",
|
||||
|
||||
@@ -7,7 +7,7 @@ import getScope from '../../util/get-scope.ts';
|
||||
import removeAliasById from '../../util/alias/remove-alias-by-id';
|
||||
import stamp from '../../util/output/stamp.ts';
|
||||
import strlen from '../../util/strlen.ts';
|
||||
import promptBool from '../../util/prompt-bool';
|
||||
import confirm from '../../util/input/confirm';
|
||||
import { isValidName } from '../../util/is-valid-name';
|
||||
import findAliasByAliasOrId from '../../util/alias/find-alias-by-alias-or-id';
|
||||
import { getCommandName } from '../../util/pkg-name.ts';
|
||||
@@ -108,5 +108,5 @@ async function confirmAliasRemove(output, alias) {
|
||||
|
||||
output.log(`The following alias will be removed permanently`);
|
||||
output.print(` ${tbl}\n`);
|
||||
return promptBool(output, chalk.red('Are you sure?'));
|
||||
return confirm(chalk.red('Are you sure?'), false);
|
||||
}
|
||||
|
||||
125
packages/now-cli/src/commands/env/add.ts
vendored
125
packages/now-cli/src/commands/env/add.ts
vendored
@@ -1,6 +1,6 @@
|
||||
import chalk from 'chalk';
|
||||
import inquirer from 'inquirer';
|
||||
import { ProjectEnvTarget, Project } from '../../types';
|
||||
import { ProjectEnvTarget, Project, Secret, ProjectEnvType } from '../../types';
|
||||
import { Output } from '../../util/output';
|
||||
import Client from '../../util/client';
|
||||
import stamp from '../../util/output/stamp';
|
||||
@@ -11,12 +11,14 @@ import {
|
||||
getEnvTargetPlaceholder,
|
||||
getEnvTargetChoices,
|
||||
} from '../../util/env/env-target';
|
||||
import { isValidEnvType, getEnvTypePlaceholder } from '../../util/env/env-type';
|
||||
import readStandardInput from '../../util/input/read-standard-input';
|
||||
import param from '../../util/output/param';
|
||||
import withSpinner from '../../util/with-spinner';
|
||||
import { emoji, prependEmoji } from '../../util/emoji';
|
||||
import { isKnownError } from '../../util/env/known-error';
|
||||
import { getCommandName } from '../../util/pkg-name';
|
||||
import { SYSTEM_ENV_VALUES } from '../../util/env/system-env';
|
||||
|
||||
type Options = {
|
||||
'--debug': boolean;
|
||||
@@ -29,38 +31,71 @@ export default async function add(
|
||||
args: string[],
|
||||
output: Output
|
||||
) {
|
||||
const stdInput = await readStandardInput();
|
||||
let [envName, envTarget] = args;
|
||||
// improve the way we show inquirer prompts
|
||||
require('../../util/input/patch-inquirer');
|
||||
|
||||
if (args.length > 2) {
|
||||
const stdInput = await readStandardInput();
|
||||
let [envTypeArg, envName, envTargetArg] = args;
|
||||
|
||||
if (args.length > 3) {
|
||||
output.error(
|
||||
`Invalid number of arguments. Usage: ${getCommandName(
|
||||
`env add <name> ${getEnvTargetPlaceholder()}`
|
||||
`env add ${getEnvTypePlaceholder()} <name> ${getEnvTargetPlaceholder()}`
|
||||
)}`
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (stdInput && (!envName || !envTarget)) {
|
||||
if (stdInput && (!envTypeArg || !envName || !envTargetArg)) {
|
||||
output.error(
|
||||
`Invalid number of arguments. Usage: ${getCommandName(
|
||||
`env add <name> <target> < <file>`
|
||||
`env add ${getEnvTypePlaceholder()} <name> <target> < <file>`
|
||||
)}`
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
let envTargets: ProjectEnvTarget[] = [];
|
||||
if (envTarget) {
|
||||
if (!isValidEnvTarget(envTarget)) {
|
||||
if (envTargetArg) {
|
||||
if (!isValidEnvTarget(envTargetArg)) {
|
||||
output.error(
|
||||
`The Environment ${param(
|
||||
envTarget
|
||||
envTargetArg
|
||||
)} is invalid. It must be one of: ${getEnvTargetPlaceholder()}.`
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
envTargets.push(envTarget);
|
||||
envTargets.push(envTargetArg);
|
||||
}
|
||||
|
||||
let envType: ProjectEnvType;
|
||||
if (envTypeArg) {
|
||||
if (!isValidEnvType(envTypeArg)) {
|
||||
output.error(
|
||||
`The Environment Variable type ${param(
|
||||
envTypeArg
|
||||
)} is invalid. It must be one of: ${getEnvTypePlaceholder()}.`
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
envType = envTypeArg;
|
||||
} else {
|
||||
const answers = (await inquirer.prompt({
|
||||
name: 'inputEnvType',
|
||||
type: 'list',
|
||||
message: `Which type of Environment Variable do you want to add?`,
|
||||
choices: [
|
||||
{ name: 'Plaintext', value: ProjectEnvType.Plaintext },
|
||||
{
|
||||
name: `Secret (can be created using ${getCommandName('secret add')})`,
|
||||
value: ProjectEnvType.Secret,
|
||||
},
|
||||
{ name: 'Provided by System', value: ProjectEnvType.System },
|
||||
],
|
||||
})) as { inputEnvType: ProjectEnvType };
|
||||
|
||||
envType = answers.inputEnvType;
|
||||
}
|
||||
|
||||
while (!envName) {
|
||||
@@ -77,7 +112,7 @@ export default async function add(
|
||||
}
|
||||
}
|
||||
|
||||
const envs = await getEnvVariables(output, client, project.id, 4);
|
||||
const { envs } = await getEnvVariables(output, client, project.id);
|
||||
const existing = new Set(
|
||||
envs.filter(r => r.key === envName).map(r => r.target)
|
||||
);
|
||||
@@ -98,15 +133,59 @@ export default async function add(
|
||||
|
||||
if (stdInput) {
|
||||
envValue = stdInput;
|
||||
} else if (isSystemEnvVariable(envName)) {
|
||||
envValue = '';
|
||||
} else {
|
||||
} else if (envType === ProjectEnvType.Plaintext) {
|
||||
const { inputValue } = await inquirer.prompt({
|
||||
type: 'password',
|
||||
type: 'input',
|
||||
name: 'inputValue',
|
||||
message: `What’s the value of ${envName}?`,
|
||||
});
|
||||
|
||||
envValue = inputValue || '';
|
||||
} else if (envType === ProjectEnvType.Secret) {
|
||||
let secretId: string | null = null;
|
||||
|
||||
while (!secretId) {
|
||||
let { secretName } = await inquirer.prompt({
|
||||
type: 'input',
|
||||
name: 'secretName',
|
||||
message: `What’s the value of ${envName}?`,
|
||||
});
|
||||
|
||||
secretName = secretName || '';
|
||||
|
||||
if (secretName[0] === '@') {
|
||||
secretName = secretName.slice(1);
|
||||
}
|
||||
|
||||
try {
|
||||
const secret = await client.fetch<Secret>(
|
||||
`/v2/now/secrets/${encodeURIComponent(secretName)}`
|
||||
);
|
||||
|
||||
secretId = secret.uid;
|
||||
} catch (error) {
|
||||
if (error.status === 404) {
|
||||
output.error(
|
||||
`Please enter the name of an existing Secret (can be created with ${getCommandName(
|
||||
'secret add'
|
||||
)}).`
|
||||
);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
envValue = secretId;
|
||||
} else {
|
||||
const { systemEnvValue } = await inquirer.prompt({
|
||||
name: 'systemEnvValue',
|
||||
type: 'list',
|
||||
message: `What’s the value of ${envName}?`,
|
||||
choices: SYSTEM_ENV_VALUES.map(value => ({ name: value, value })),
|
||||
});
|
||||
|
||||
envValue = systemEnvValue;
|
||||
}
|
||||
|
||||
while (envTargets.length === 0) {
|
||||
@@ -127,7 +206,15 @@ export default async function add(
|
||||
const addStamp = stamp();
|
||||
try {
|
||||
await withSpinner('Saving', () =>
|
||||
addEnvRecord(output, client, project.id, envName, envValue, envTargets)
|
||||
addEnvRecord(
|
||||
output,
|
||||
client,
|
||||
project.id,
|
||||
envType,
|
||||
envName,
|
||||
envValue,
|
||||
envTargets
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
if (isKnownError(error) && error.serverMessage) {
|
||||
@@ -148,7 +235,3 @@ export default async function add(
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function isSystemEnvVariable(envName: string) {
|
||||
return envName.startsWith('VERCEL_');
|
||||
}
|
||||
|
||||
43
packages/now-cli/src/commands/env/index.ts
vendored
43
packages/now-cli/src/commands/env/index.ts
vendored
@@ -6,6 +6,7 @@ import getArgs from '../../util/get-args';
|
||||
import getSubcommand from '../../util/get-subcommand';
|
||||
import getInvalidSubcommand from '../../util/get-invalid-subcommand';
|
||||
import { getEnvTargetPlaceholder } from '../../util/env/env-target';
|
||||
import { getEnvTypePlaceholder } from '../../util/env/env-type';
|
||||
import { getLinkedProject } from '../../util/projects/link';
|
||||
import Client from '../../util/client';
|
||||
import handleError from '../../util/handle-error';
|
||||
@@ -18,16 +19,17 @@ import ls from './ls';
|
||||
import rm from './rm';
|
||||
|
||||
const help = () => {
|
||||
const placeholder = getEnvTargetPlaceholder();
|
||||
const typePlaceholder = getEnvTypePlaceholder();
|
||||
const targetPlaceholder = getEnvTargetPlaceholder();
|
||||
console.log(`
|
||||
${chalk.bold(`${logo} ${getPkgName()} env`)} [options] <command>
|
||||
|
||||
${chalk.dim('Commands:')}
|
||||
|
||||
ls [environment] List all variables for the specified Environment
|
||||
add [name] [environment] Add an Environment Variable (see examples below)
|
||||
rm [name] [environment] Remove an Environment Variable (see examples below)
|
||||
pull [filename] Pull all Development Environment Variables from the cloud and write to a file [.env]
|
||||
ls [environment] List all variables for the specified Environment
|
||||
add [type] [name] [environment] Add an Environment Variable (see examples below)
|
||||
rm [name] [environment] Remove an Environment Variable (see examples below)
|
||||
pull [filename] Pull all Development Environment Variables from the cloud and write to a file [.env]
|
||||
|
||||
${chalk.dim('Options:')}
|
||||
|
||||
@@ -42,27 +44,32 @@ const help = () => {
|
||||
-t ${chalk.bold.underline('TOKEN')}, --token=${chalk.bold.underline(
|
||||
'TOKEN'
|
||||
)} Login token
|
||||
-N, --next Show next page of results
|
||||
|
||||
${chalk.dim('Examples:')}
|
||||
|
||||
${chalk.gray('–')} Add a new variable to multiple Environments
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} env add <name>`)}
|
||||
${chalk.cyan(`$ ${getPkgName()} env add API_TOKEN`)}
|
||||
${chalk.cyan(`$ ${getPkgName()} env add ${typePlaceholder} <name>`)}
|
||||
${chalk.cyan(`$ ${getPkgName()} env add secret API_TOKEN`)}
|
||||
|
||||
${chalk.gray('–')} Add a new variable for a specific Environment
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} env add <name> ${placeholder}`)}
|
||||
${chalk.cyan(`$ ${getPkgName()} env add DB_CONNECTION production`)}
|
||||
${chalk.cyan(
|
||||
`$ ${getPkgName()} env add ${typePlaceholder} <name> ${targetPlaceholder}`
|
||||
)}
|
||||
${chalk.cyan(`$ ${getPkgName()} env add secret DB_PASS production`)}
|
||||
|
||||
${chalk.gray('–')} Add a new Environment Variable from stdin
|
||||
|
||||
${chalk.cyan(
|
||||
`$ cat <file> | ${getPkgName()} env add <name> ${placeholder}`
|
||||
`$ cat <file> | ${getPkgName()} env add ${typePlaceholder} <name> ${targetPlaceholder}`
|
||||
)}
|
||||
${chalk.cyan(
|
||||
`$ cat ~/.npmrc | ${getPkgName()} env add plain NPM_RC preview`
|
||||
)}
|
||||
${chalk.cyan(
|
||||
`$ ${getPkgName()} env add plain API_URL production < url.txt`
|
||||
)}
|
||||
${chalk.cyan(`$ cat ~/.npmrc | ${getPkgName()} env add NPM_RC preview`)}
|
||||
${chalk.cyan(`$ ${getPkgName()} env add DB_PASS production < secret.txt`)}
|
||||
|
||||
${chalk.gray('–')} Remove an variable from multiple Environments
|
||||
|
||||
@@ -71,14 +78,8 @@ const help = () => {
|
||||
|
||||
${chalk.gray('–')} Remove a variable from a specific Environment
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} env rm <name> ${placeholder}`)}
|
||||
${chalk.cyan(`$ ${getPkgName()} env rm <name> ${targetPlaceholder}`)}
|
||||
${chalk.cyan(`$ ${getPkgName()} env rm NPM_RC preview`)}
|
||||
|
||||
${chalk.gray('–')} Paginate results, where ${chalk.dim(
|
||||
'`1584722256178`'
|
||||
)} is the time in milliseconds since the UNIX epoch.
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} env ls --next 1584722256178`)}
|
||||
`);
|
||||
};
|
||||
|
||||
@@ -96,8 +97,6 @@ export default async function main(ctx: NowContext) {
|
||||
argv = getArgs(ctx.argv.slice(2), {
|
||||
'--yes': Boolean,
|
||||
'-y': '--yes',
|
||||
'--next': Number,
|
||||
'-N': '--next',
|
||||
});
|
||||
} catch (error) {
|
||||
handleError(error);
|
||||
|
||||
73
packages/now-cli/src/commands/env/ls.ts
vendored
73
packages/now-cli/src/commands/env/ls.ts
vendored
@@ -1,7 +1,12 @@
|
||||
import chalk from 'chalk';
|
||||
import ms from 'ms';
|
||||
import { Output } from '../../util/output';
|
||||
import { ProjectEnvVariable, ProjectEnvTarget, Project } from '../../types';
|
||||
import {
|
||||
ProjectEnvTarget,
|
||||
Project,
|
||||
ProjectEnvVariable,
|
||||
ProjectEnvType,
|
||||
} from '../../types';
|
||||
import Client from '../../util/client';
|
||||
import formatTable from '../../util/format-table';
|
||||
import getEnvVariables from '../../util/env/get-env-records';
|
||||
@@ -11,12 +16,13 @@ import {
|
||||
} from '../../util/env/env-target';
|
||||
import stamp from '../../util/output/stamp';
|
||||
import param from '../../util/output/param';
|
||||
import getCommandFlags from '../../util/get-command-flags';
|
||||
import { getCommandName } from '../../util/pkg-name';
|
||||
import ellipsis from '../../util/output/ellipsis';
|
||||
// @ts-ignore
|
||||
import title from 'title';
|
||||
|
||||
type Options = {
|
||||
'--debug': boolean;
|
||||
'--next'?: number;
|
||||
};
|
||||
|
||||
export default async function ls(
|
||||
@@ -26,8 +32,6 @@ export default async function ls(
|
||||
args: string[],
|
||||
output: Output
|
||||
) {
|
||||
const { '--next': nextTimestamp } = opts;
|
||||
|
||||
if (args.length > 1) {
|
||||
output.error(
|
||||
`Invalid number of arguments. Usage: ${getCommandName(
|
||||
@@ -50,42 +54,21 @@ export default async function ls(
|
||||
|
||||
const lsStamp = stamp();
|
||||
|
||||
if (typeof nextTimestamp !== 'undefined' && Number.isNaN(nextTimestamp)) {
|
||||
output.error('Please provide a number for flag --next');
|
||||
return 1;
|
||||
}
|
||||
const { envs } = await getEnvVariables(output, client, project.id, envTarget);
|
||||
|
||||
const data = await getEnvVariables(
|
||||
output,
|
||||
client,
|
||||
project.id,
|
||||
5,
|
||||
envTarget,
|
||||
nextTimestamp
|
||||
);
|
||||
const { envs: records, pagination } = data;
|
||||
output.log(
|
||||
`${
|
||||
records.length > 0 ? 'Environment Variables' : 'No Environment Variables'
|
||||
envs.length > 0 ? 'Environment Variables' : 'No Environment Variables'
|
||||
} found in Project ${chalk.bold(project.name)} ${chalk.gray(lsStamp())}`
|
||||
);
|
||||
console.log(getTable(records));
|
||||
|
||||
if (pagination && pagination.count === 20) {
|
||||
const flags = getCommandFlags(opts, ['_', '--next']);
|
||||
output.log(
|
||||
`To display the next page run ${getCommandName(
|
||||
`env ls${flags} --next ${pagination.next}`
|
||||
)}`
|
||||
);
|
||||
}
|
||||
console.log(getTable(envs));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getTable(records: ProjectEnvVariable[]) {
|
||||
return formatTable(
|
||||
['name', 'value', 'environment', 'created'],
|
||||
['name', 'value', 'environments', 'created'],
|
||||
['l', 'l', 'l', 'l', 'l'],
|
||||
[
|
||||
{
|
||||
@@ -96,17 +79,27 @@ function getTable(records: ProjectEnvVariable[]) {
|
||||
);
|
||||
}
|
||||
|
||||
function getRow({
|
||||
key,
|
||||
system = false,
|
||||
target,
|
||||
createdAt = 0,
|
||||
}: ProjectEnvVariable) {
|
||||
function getRow(env: ProjectEnvVariable) {
|
||||
let value: string;
|
||||
if (env.type === ProjectEnvType.Plaintext) {
|
||||
// replace space characters (line-break, etc.) with simple spaces
|
||||
// to make sure the displayed value is a single line
|
||||
const singleLineValue = env.value.replace(/\s/g, ' ');
|
||||
|
||||
value = chalk.gray(ellipsis(singleLineValue, 19));
|
||||
} else if (env.type === ProjectEnvType.System) {
|
||||
value = chalk.gray.italic(env.value);
|
||||
} else {
|
||||
value = chalk.gray.italic('Encrypted');
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
return [
|
||||
chalk.bold(key),
|
||||
chalk.gray(chalk.italic(system ? 'Populated by System' : 'Encrypted')),
|
||||
target || '',
|
||||
`${ms(now - createdAt)} ago`,
|
||||
chalk.bold(env.key),
|
||||
value,
|
||||
(Array.isArray(env.target) ? env.target : [env.target || ''])
|
||||
.map(title)
|
||||
.join(', '),
|
||||
env.createdAt ? `${ms(now - env.createdAt)} ago` : '',
|
||||
];
|
||||
}
|
||||
|
||||
8
packages/now-cli/src/commands/env/pull.ts
vendored
8
packages/now-cli/src/commands/env/pull.ts
vendored
@@ -1,7 +1,7 @@
|
||||
import chalk from 'chalk';
|
||||
import { ProjectEnvTarget, Project } from '../../types';
|
||||
import { Output } from '../../util/output';
|
||||
import promptBool from '../../util/prompt-bool';
|
||||
import confirm from '../../util/input/confirm';
|
||||
import Client from '../../util/client';
|
||||
import stamp from '../../util/output/stamp';
|
||||
import getDecryptedEnvRecords from '../../util/get-decrypted-env-records';
|
||||
@@ -68,9 +68,9 @@ export default async function pull(
|
||||
} else if (
|
||||
exists &&
|
||||
!skipConfirmation &&
|
||||
!(await promptBool(
|
||||
output,
|
||||
`Found existing file ${param(filename)}. Do you want to overwrite?`
|
||||
!(await confirm(
|
||||
`Found existing file ${param(filename)}. Do you want to overwrite?`,
|
||||
false
|
||||
))
|
||||
) {
|
||||
output.log('Aborted');
|
||||
|
||||
37
packages/now-cli/src/commands/env/rm.ts
vendored
37
packages/now-cli/src/commands/env/rm.ts
vendored
@@ -1,8 +1,8 @@
|
||||
import chalk from 'chalk';
|
||||
import inquirer from 'inquirer';
|
||||
import { ProjectEnvTarget, Project } from '../../types';
|
||||
import { ProjectEnvTarget, Project, ProjectEnvVariableV5 } from '../../types';
|
||||
import { Output } from '../../util/output';
|
||||
import promptBool from '../../util/prompt-bool';
|
||||
import confirm from '../../util/input/confirm';
|
||||
import removeEnvRecord from '../../util/env/remove-env-record';
|
||||
import getEnvVariables from '../../util/env/get-env-records';
|
||||
import {
|
||||
@@ -30,6 +30,9 @@ export default async function rm(
|
||||
args: string[],
|
||||
output: Output
|
||||
) {
|
||||
// improve the way we show inquirer prompts
|
||||
require('../../util/input/patch-inquirer');
|
||||
|
||||
if (args.length > 2) {
|
||||
output.error(
|
||||
`Invalid number of arguments. Usage: ${getCommandName(
|
||||
@@ -69,7 +72,20 @@ export default async function rm(
|
||||
envName = inputName;
|
||||
}
|
||||
|
||||
const envs = await getEnvVariables(output, client, project.id, 4);
|
||||
const data = await getEnvVariables(output, client, project.id);
|
||||
|
||||
// we expand env vars with multiple targets
|
||||
const envs: ProjectEnvVariableV5[] = [];
|
||||
for (let env of data.envs) {
|
||||
if (Array.isArray(env.target)) {
|
||||
for (let target of env.target) {
|
||||
envs.push({ ...env, target });
|
||||
}
|
||||
} else {
|
||||
envs.push({ ...env, target: env.target });
|
||||
}
|
||||
}
|
||||
|
||||
const existing = new Set(
|
||||
envs.filter(r => r.key === envName).map(r => r.target)
|
||||
);
|
||||
@@ -79,7 +95,7 @@ export default async function rm(
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (envTargets.length === 0) {
|
||||
while (envTargets.length === 0) {
|
||||
const choices = getEnvTargetChoices().filter(c => existing.has(c.value));
|
||||
if (choices.length === 0) {
|
||||
output.error(
|
||||
@@ -97,6 +113,13 @@ export default async function rm(
|
||||
message: `Remove ${envName} from which Environments (select multiple)?`,
|
||||
choices,
|
||||
});
|
||||
|
||||
if (inputTargets.length === 0) {
|
||||
output.error(
|
||||
'Please select an Environment to remove the Environment Variable from.'
|
||||
);
|
||||
}
|
||||
|
||||
envTargets = inputTargets;
|
||||
}
|
||||
}
|
||||
@@ -104,11 +127,11 @@ export default async function rm(
|
||||
const skipConfirmation = opts['--yes'];
|
||||
if (
|
||||
!skipConfirmation &&
|
||||
!(await promptBool(
|
||||
output,
|
||||
!(await confirm(
|
||||
`Removing Environment Variable ${param(
|
||||
envName
|
||||
)} from Project ${chalk.bold(project.name)}. Are you sure?`
|
||||
)} from Project ${chalk.bold(project.name)}. Are you sure?`,
|
||||
false
|
||||
))
|
||||
) {
|
||||
output.log('Aborted');
|
||||
|
||||
@@ -203,12 +203,23 @@ export enum ProjectEnvTarget {
|
||||
Development = 'development',
|
||||
}
|
||||
|
||||
export enum ProjectEnvType {
|
||||
Plaintext = 'plain',
|
||||
Secret = 'secret',
|
||||
System = 'system',
|
||||
}
|
||||
|
||||
export interface ProjectEnvVariable {
|
||||
key: string;
|
||||
value: string;
|
||||
type: ProjectEnvType;
|
||||
configurationId?: string | null;
|
||||
createdAt?: number;
|
||||
updatedAt?: number;
|
||||
target?: ProjectEnvTarget | ProjectEnvTarget[];
|
||||
}
|
||||
|
||||
export interface ProjectEnvVariableV5 extends ProjectEnvVariable {
|
||||
target?: ProjectEnvTarget;
|
||||
system?: boolean;
|
||||
}
|
||||
|
||||
57
packages/now-cli/src/util/env/add-env-record.ts
vendored
57
packages/now-cli/src/util/env/add-env-record.ts
vendored
@@ -1,60 +1,39 @@
|
||||
import { Output } from '../output';
|
||||
import Client from '../client';
|
||||
import { Secret, ProjectEnvTarget, ProjectEnvVariable } from '../../types';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import slugify from '@sindresorhus/slugify';
|
||||
import {
|
||||
Secret,
|
||||
ProjectEnvTarget,
|
||||
ProjectEnvVariableV5,
|
||||
ProjectEnvType,
|
||||
} from '../../types';
|
||||
|
||||
export default async function addEnvRecord(
|
||||
output: Output,
|
||||
client: Client,
|
||||
projectId: string,
|
||||
envName: string,
|
||||
envValue: string | undefined,
|
||||
type: ProjectEnvType,
|
||||
key: string,
|
||||
envValue: string,
|
||||
targets: ProjectEnvTarget[]
|
||||
): Promise<void> {
|
||||
output.debug(
|
||||
`Adding Environment Variable ${envName} to ${targets.length} targets`
|
||||
`Adding ${type} Environment Variable ${key} to ${targets.length} targets`
|
||||
);
|
||||
|
||||
let values: string[] | undefined;
|
||||
let value = envValue;
|
||||
|
||||
if (envValue) {
|
||||
const secrets = await Promise.all(
|
||||
targets.map(target =>
|
||||
client.fetch<Secret>('/v2/now/secrets', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
name: generateSecretName(envName, target),
|
||||
value: envValue,
|
||||
projectId: projectId,
|
||||
decryptable: target === ProjectEnvTarget.Development,
|
||||
}),
|
||||
})
|
||||
)
|
||||
if (type === ProjectEnvType.Secret) {
|
||||
const secret = await client.fetch<Secret>(
|
||||
`/v2/now/secrets/${encodeURIComponent(envValue)}`
|
||||
);
|
||||
values = secrets.map(secret => secret.uid);
|
||||
value = secret.uid;
|
||||
}
|
||||
|
||||
const body = targets.map((target, i) => ({
|
||||
key: envName,
|
||||
value: values ? values[i] : '',
|
||||
target,
|
||||
}));
|
||||
const body = { type, key, value, target: targets };
|
||||
|
||||
const urlProject = `/v4/projects/${projectId}/env`;
|
||||
await client.fetch<ProjectEnvVariable>(urlProject, {
|
||||
const urlProject = `/v6/projects/${projectId}/env`;
|
||||
await client.fetch<ProjectEnvVariableV5>(urlProject, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
}
|
||||
|
||||
const randomSecretSuffix = customAlphabet(
|
||||
'123456789abcdefghijklmnopqrstuvwxyz',
|
||||
4
|
||||
);
|
||||
|
||||
function generateSecretName(envName: string, target: ProjectEnvTarget) {
|
||||
return `${
|
||||
slugify(envName).substring(0, 80) // we truncate because the max secret length is 100
|
||||
}-${target}-${randomSecretSuffix()}`;
|
||||
}
|
||||
|
||||
15
packages/now-cli/src/util/env/env-type.ts
vendored
Normal file
15
packages/now-cli/src/util/env/env-type.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { ProjectEnvType } from '../../types';
|
||||
|
||||
function envTypes(): string[] {
|
||||
return Object.values(ProjectEnvType);
|
||||
}
|
||||
|
||||
export function isValidEnvType(
|
||||
type?: string
|
||||
): type is ProjectEnvType | undefined {
|
||||
return typeof type === 'undefined' || envTypes().includes(type);
|
||||
}
|
||||
|
||||
export function getEnvTypePlaceholder() {
|
||||
return `<${envTypes().join(' | ')}>`;
|
||||
}
|
||||
51
packages/now-cli/src/util/env/get-env-records.ts
vendored
51
packages/now-cli/src/util/env/get-env-records.ts
vendored
@@ -1,69 +1,24 @@
|
||||
import { Output } from '../output';
|
||||
import Client from '../client';
|
||||
import {
|
||||
ProjectEnvVariable,
|
||||
ProjectEnvTarget,
|
||||
PaginationOptions,
|
||||
} from '../../types';
|
||||
import { ProjectEnvVariable, ProjectEnvTarget } from '../../types';
|
||||
import { URLSearchParams } from 'url';
|
||||
|
||||
type ApiVersion = 4 | 5;
|
||||
|
||||
type APIV4Response = ProjectEnvVariable[];
|
||||
|
||||
interface APIV5Response {
|
||||
pagination: PaginationOptions;
|
||||
envs: ProjectEnvVariable[];
|
||||
}
|
||||
|
||||
export default async function getEnvVariables(
|
||||
output: Output,
|
||||
client: Client,
|
||||
projectId: string,
|
||||
apiVersion: 4,
|
||||
target?: ProjectEnvTarget
|
||||
): Promise<APIV4Response>;
|
||||
|
||||
export default async function getEnvVariables(
|
||||
output: Output,
|
||||
client: Client,
|
||||
projectId: string,
|
||||
apiVersion: 5,
|
||||
target?: ProjectEnvTarget,
|
||||
next?: number
|
||||
): Promise<APIV5Response>;
|
||||
|
||||
export default async function getEnvVariables<V extends ApiVersion>(
|
||||
output: Output,
|
||||
client: Client,
|
||||
projectId: string,
|
||||
apiVersion: V,
|
||||
target?: ProjectEnvTarget,
|
||||
next?: number
|
||||
) {
|
||||
output.debug(
|
||||
`Fetching Environment Variables of project ${projectId} and target ${target}`
|
||||
);
|
||||
const query = new URLSearchParams();
|
||||
if (apiVersion >= 5) {
|
||||
query.set('limit', String(20));
|
||||
}
|
||||
|
||||
if (target) {
|
||||
query.set('target', target);
|
||||
}
|
||||
|
||||
if (next) {
|
||||
query.set('until', String(next));
|
||||
}
|
||||
const url = `/v6/projects/${projectId}/env?${query}`;
|
||||
|
||||
const url = `/v${apiVersion}/projects/${projectId}/env?${query}`;
|
||||
|
||||
if (apiVersion === 5) {
|
||||
return client.fetch<APIV5Response>(url);
|
||||
} else if (apiVersion === 4) {
|
||||
return client.fetch<APIV4Response>(url);
|
||||
} else {
|
||||
throw new Error('Unknown version: ' + apiVersion);
|
||||
}
|
||||
return client.fetch<{ envs: ProjectEnvVariable[] }>(url);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Output } from '../output';
|
||||
import Client from '../client';
|
||||
import { ProjectEnvTarget, Secret, ProjectEnvVariable } from '../../types';
|
||||
import { ProjectEnvTarget, Secret, ProjectEnvVariableV5 } from '../../types';
|
||||
|
||||
export default async function removeEnvRecord(
|
||||
output: Output,
|
||||
@@ -18,7 +18,7 @@ export default async function removeEnvRecord(
|
||||
envName
|
||||
)}${qs}`;
|
||||
|
||||
const env = await client.fetch<ProjectEnvVariable>(urlProject, {
|
||||
const env = await client.fetch<ProjectEnvVariableV5>(urlProject, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
|
||||
|
||||
32
packages/now-cli/src/util/env/system-env.ts
vendored
Normal file
32
packages/now-cli/src/util/env/system-env.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
export const SYSTEM_ENV_VALUES = [
|
||||
'VERCEL_URL',
|
||||
'VERCEL_GITHUB_COMMIT_ORG',
|
||||
'VERCEL_GITHUB_COMMIT_REF',
|
||||
'VERCEL_GITHUB_ORG',
|
||||
'VERCEL_GITHUB_DEPLOYMENT',
|
||||
'VERCEL_GITHUB_COMMIT_REPO',
|
||||
'VERCEL_GITHUB_REPO',
|
||||
'VERCEL_GITHUB_COMMIT_AUTHOR_LOGIN',
|
||||
'VERCEL_GITHUB_COMMIT_AUTHOR_NAME',
|
||||
'VERCEL_GITHUB_COMMIT_SHA',
|
||||
'VERCEL_GITLAB_DEPLOYMENT',
|
||||
'VERCEL_GITLAB_PROJECT_NAMESPACE',
|
||||
'VERCEL_GITLAB_PROJECT_NAME',
|
||||
'VERCEL_GITLAB_PROJECT_ID',
|
||||
'VERCEL_GITLAB_PROJECT_PATH',
|
||||
'VERCEL_GITLAB_COMMIT_REF',
|
||||
'VERCEL_GITLAB_COMMIT_SHA',
|
||||
'VERCEL_GITLAB_COMMIT_MESSAGE',
|
||||
'VERCEL_GITLAB_COMMIT_AUTHOR_LOGIN',
|
||||
'VERCEL_GITLAB_COMMIT_AUTHOR_NAME',
|
||||
'VERCEL_BITBUCKET_DEPLOYMENT',
|
||||
'VERCEL_BITBUCKET_REPO_OWNER',
|
||||
'VERCEL_BITBUCKET_REPO_SLUG',
|
||||
'VERCEL_BITBUCKET_REPO_NAME',
|
||||
'VERCEL_BITBUCKET_COMMIT_REF',
|
||||
'VERCEL_BITBUCKET_COMMIT_SHA',
|
||||
'VERCEL_BITBUCKET_COMMIT_MESSAGE',
|
||||
'VERCEL_BITBUCKET_COMMIT_AUTHOR_NAME',
|
||||
'VERCEL_BITBUCKET_COMMIT_AUTHOR_URL',
|
||||
'VERCEL_BITBUCKET_COMMIT_AUTHOR_AVATAR',
|
||||
];
|
||||
@@ -2,7 +2,7 @@ import getEnvVariables from './env/get-env-records';
|
||||
import getDecryptedSecret from './env/get-decrypted-secret';
|
||||
import Client from './client';
|
||||
import { Output } from './output/create-output';
|
||||
import { ProjectEnvTarget, Project } from '../types';
|
||||
import { ProjectEnvTarget, Project, ProjectEnvType } from '../types';
|
||||
|
||||
import { Env } from '@vercel/build-utils';
|
||||
|
||||
@@ -12,9 +12,15 @@ export default async function getDecryptedEnvRecords(
|
||||
project: Project,
|
||||
target: ProjectEnvTarget
|
||||
): Promise<Env> {
|
||||
const envs = await getEnvVariables(output, client, project.id, 4, target);
|
||||
const { envs } = await getEnvVariables(output, client, project.id, target);
|
||||
const decryptedValues = await Promise.all(
|
||||
envs.map(async env => {
|
||||
if (env.type === ProjectEnvType.System) {
|
||||
return { value: '', found: true };
|
||||
} else if (env.type === ProjectEnvType.Plaintext) {
|
||||
return { value: env.value, found: true };
|
||||
}
|
||||
|
||||
try {
|
||||
const value = await getDecryptedSecret(output, client, env.value);
|
||||
return { value, found: true };
|
||||
|
||||
@@ -10,7 +10,7 @@ import chalk from 'chalk';
|
||||
*/
|
||||
|
||||
// adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/base.js#L126
|
||||
const getQuestion = function() {
|
||||
const getQuestion = function () {
|
||||
let message = `${chalk.gray('?')} ${this.opt.message} `;
|
||||
|
||||
if (this.opt.type === 'confirm') {
|
||||
@@ -35,7 +35,7 @@ inquirer.prompt.prompts.input.prototype.getQuestion = getQuestion;
|
||||
inquirer.prompt.prompts.confirm.prototype.getQuestion = getQuestion;
|
||||
|
||||
// adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/list.js#L80
|
||||
inquirer.prompt.prompts.list.prototype.render = function() {
|
||||
inquirer.prompt.prompts.list.prototype.render = function () {
|
||||
// Render question
|
||||
let message = this.getQuestion();
|
||||
|
||||
@@ -89,11 +89,22 @@ function listRender(choices, pointer) {
|
||||
}
|
||||
|
||||
// adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/checkbox.js#L84
|
||||
inquirer.prompt.prompts.checkbox.prototype.render = function(error) {
|
||||
inquirer.prompt.prompts.checkbox.prototype.render = function (error) {
|
||||
// Render question
|
||||
let message = this.getQuestion();
|
||||
let bottomContent = '';
|
||||
|
||||
if (!this.spaceKeyPressed) {
|
||||
message +=
|
||||
'(Press ' +
|
||||
chalk.cyan.bold('<space>') +
|
||||
' to select, ' +
|
||||
chalk.cyan.bold('<a>') +
|
||||
' to toggle all, ' +
|
||||
chalk.cyan.bold('<i>') +
|
||||
' to invert selection)';
|
||||
}
|
||||
|
||||
// Render choices or answer depending on the state
|
||||
if (this.status === 'answered') {
|
||||
message += this.selection.length > 0 ? this.selection.join(', ') : 'None';
|
||||
@@ -118,7 +129,7 @@ function renderChoices(choices, pointer) {
|
||||
let output = '';
|
||||
let separatorOffset = 0;
|
||||
|
||||
choices.forEach(function(choice, i) {
|
||||
choices.forEach(function (choice, i) {
|
||||
if (choice.type === 'separator') {
|
||||
separatorOffset++;
|
||||
output += '' + choice + '\n';
|
||||
@@ -151,7 +162,7 @@ function renderChoices(choices, pointer) {
|
||||
}
|
||||
|
||||
// adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/input.js#L44
|
||||
inquirer.prompt.prompts.input.prototype.render = function(error) {
|
||||
inquirer.prompt.prompts.input.prototype.render = function (error) {
|
||||
let bottomContent = '';
|
||||
let appendContent = '';
|
||||
let message = this.getQuestion();
|
||||
@@ -178,7 +189,7 @@ inquirer.prompt.prompts.input.prototype.render = function(error) {
|
||||
};
|
||||
|
||||
// adjusted from https://github.com/SBoudrias/Inquirer.js/blob/942908f17319343d1acc7b876f990797c5695918/packages/inquirer/lib/prompts/confirm.js#L64
|
||||
inquirer.prompt.prompts.confirm.prototype.render = function(answer) {
|
||||
inquirer.prompt.prompts.confirm.prototype.render = function (answer) {
|
||||
let message = this.getQuestion();
|
||||
|
||||
if (this.status === 'answered') {
|
||||
|
||||
3
packages/now-cli/src/util/output/ellipsis.ts
Normal file
3
packages/now-cli/src/util/output/ellipsis.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function ellipsis(str: string, length: number) {
|
||||
return str.length > length ? `${str.slice(0, length - 1)}…` : str;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import chalk from 'chalk';
|
||||
import { Output } from './output';
|
||||
|
||||
async function promptBool(output: Output, message: string): Promise<boolean> {
|
||||
return new Promise<boolean>(resolve => {
|
||||
output.print(`${chalk.gray('>')} ${message} ${chalk.gray('[y/N] ')}`);
|
||||
process.stdin
|
||||
.on('data', d => {
|
||||
process.stdin.pause();
|
||||
resolve(
|
||||
d
|
||||
.toString()
|
||||
.trim()
|
||||
.toLowerCase() === 'y'
|
||||
);
|
||||
})
|
||||
.resume();
|
||||
});
|
||||
}
|
||||
|
||||
export default promptBool;
|
||||
168
packages/now-cli/test/integration.js
vendored
168
packages/now-cli/test/integration.js
vendored
@@ -422,6 +422,19 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
|
||||
}
|
||||
|
||||
async function createSecret() {
|
||||
const name = `my-secret${Math.floor(Math.random() * 10000)}`;
|
||||
|
||||
const res = await apiFetch('/v2/now/secrets', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ name, value: 'my secret' }),
|
||||
});
|
||||
|
||||
t.is(res.status, 200);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
async function nowEnvLsIsEmpty() {
|
||||
const { exitCode, stderr, stdout } = await execa(
|
||||
binaryPath,
|
||||
@@ -436,26 +449,34 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
t.regex(stderr, /No Environment Variables found in Project/gm);
|
||||
}
|
||||
|
||||
async function nowEnvAdd() {
|
||||
async function nowEnvAddPlaintext() {
|
||||
const now = execa(binaryPath, ['env', 'add', ...defaultArgs], {
|
||||
reject: false,
|
||||
cwd: target,
|
||||
});
|
||||
|
||||
await waitForPrompt(now, chunk =>
|
||||
chunk.includes('Which type of Environment Variable do you want to add?')
|
||||
);
|
||||
now.stdin.write('\n'); // select plaintext
|
||||
|
||||
await waitForPrompt(now, chunk =>
|
||||
chunk.includes('What’s the name of the variable?')
|
||||
);
|
||||
now.stdin.write('MY_ENV_VAR\n');
|
||||
now.stdin.write('MY_PLAINTEXT_ENV_VAR\n');
|
||||
await waitForPrompt(
|
||||
now,
|
||||
chunk =>
|
||||
chunk.includes('What’s the value of') && chunk.includes('MY_ENV_VAR')
|
||||
chunk.includes('What’s the value of') &&
|
||||
chunk.includes('MY_PLAINTEXT_ENV_VAR')
|
||||
);
|
||||
now.stdin.write('MY_VALUE\n');
|
||||
now.stdin.write('my plaintext value\n');
|
||||
|
||||
await waitForPrompt(
|
||||
now,
|
||||
chunk =>
|
||||
chunk.includes('which Environments') && chunk.includes('MY_ENV_VAR')
|
||||
chunk.includes('which Environments') &&
|
||||
chunk.includes('MY_PLAINTEXT_ENV_VAR')
|
||||
);
|
||||
now.stdin.write('a\n'); // select all
|
||||
|
||||
@@ -464,10 +485,47 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
|
||||
}
|
||||
|
||||
async function nowEnvAddSecret(secretName) {
|
||||
const now = execa(binaryPath, ['env', 'add', ...defaultArgs], {
|
||||
reject: false,
|
||||
cwd: target,
|
||||
});
|
||||
|
||||
await waitForPrompt(now, chunk =>
|
||||
chunk.includes('Which type of Environment Variable do you want to add?')
|
||||
);
|
||||
now.stdin.write('j\n'); // select secret
|
||||
|
||||
await waitForPrompt(now, chunk =>
|
||||
chunk.includes('What’s the name of the variable?')
|
||||
);
|
||||
now.stdin.write('MY_SECRET_ENV_VAR\n');
|
||||
|
||||
await waitForPrompt(
|
||||
now,
|
||||
chunk =>
|
||||
chunk.includes('What’s the value of') &&
|
||||
chunk.includes('MY_SECRET_ENV_VAR')
|
||||
);
|
||||
now.stdin.write(`@${secretName}\n`);
|
||||
|
||||
await waitForPrompt(
|
||||
now,
|
||||
chunk =>
|
||||
chunk.includes('which Environments') &&
|
||||
chunk.includes('MY_SECRET_ENV_VAR')
|
||||
);
|
||||
now.stdin.write('j \n'); // select preview
|
||||
|
||||
const { exitCode, stderr, stdout } = await now;
|
||||
|
||||
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
|
||||
}
|
||||
|
||||
async function nowEnvAddFromStdin() {
|
||||
const now = execa(
|
||||
binaryPath,
|
||||
['env', 'add', 'MY_STDIN_VAR', 'development', ...defaultArgs],
|
||||
['env', 'add', 'plain', 'MY_STDIN_VAR', 'development', ...defaultArgs],
|
||||
{
|
||||
reject: false,
|
||||
cwd: target,
|
||||
@@ -481,13 +539,20 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
async function nowEnvAddSystemEnv() {
|
||||
const now = execa(
|
||||
binaryPath,
|
||||
['env', 'add', 'VERCEL_URL', ...defaultArgs],
|
||||
['env', 'add', 'system', 'VERCEL_URL', ...defaultArgs],
|
||||
{
|
||||
reject: false,
|
||||
cwd: target,
|
||||
}
|
||||
);
|
||||
|
||||
await waitForPrompt(
|
||||
now,
|
||||
chunk =>
|
||||
chunk.includes('What’s the value of') && chunk.includes('VERCEL_URL')
|
||||
);
|
||||
now.stdin.write(`\n`); // select VERCEL_URL
|
||||
|
||||
await waitForPrompt(
|
||||
now,
|
||||
chunk =>
|
||||
@@ -513,23 +578,28 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
|
||||
t.regex(stderr, /Environment Variables found in Project/gm);
|
||||
|
||||
console.log(stdout);
|
||||
|
||||
const lines = stdout.split('\n');
|
||||
|
||||
const myEnvVars = lines.filter(line => line.includes('MY_ENV_VAR'));
|
||||
t.is(myEnvVars.length, 3);
|
||||
t.regex(myEnvVars.join('\n'), /development/gm);
|
||||
t.regex(myEnvVars.join('\n'), /preview/gm);
|
||||
t.regex(myEnvVars.join('\n'), /production/gm);
|
||||
const plaintextEnvs = lines.filter(line =>
|
||||
line.includes('MY_PLAINTEXT_ENV_VAR')
|
||||
);
|
||||
t.is(plaintextEnvs.length, 1);
|
||||
t.regex(plaintextEnvs[0], /Production, Preview, Development/gm);
|
||||
|
||||
const myStdinVars = lines.filter(line => line.includes('MY_STDIN_VAR'));
|
||||
t.is(myStdinVars.length, 1);
|
||||
t.regex(myStdinVars.join('\n'), /development/gm);
|
||||
const secretEnvs = lines.filter(line => line.includes('MY_SECRET_ENV_VAR'));
|
||||
t.is(secretEnvs.length, 1);
|
||||
t.regex(secretEnvs[0], /Preview/gm);
|
||||
|
||||
const vercelVars = lines.filter(line => line.includes('VERCEL_URL'));
|
||||
t.is(vercelVars.length, 3);
|
||||
t.regex(vercelVars.join('\n'), /development/gm);
|
||||
t.regex(vercelVars.join('\n'), /preview/gm);
|
||||
t.regex(vercelVars.join('\n'), /production/gm);
|
||||
const stdinEnvs = lines.filter(line => line.includes('MY_STDIN_VAR'));
|
||||
t.is(stdinEnvs.length, 1);
|
||||
t.regex(stdinEnvs[0], /Development/gm);
|
||||
|
||||
const systemEnvs = lines.filter(line => line.includes('VERCEL_URL'));
|
||||
t.is(systemEnvs.length, 1);
|
||||
t.regex(systemEnvs[0], /VERCEL_URL/gm);
|
||||
t.regex(systemEnvs[0], /Production, Preview, Development/gm);
|
||||
}
|
||||
|
||||
async function nowEnvPull() {
|
||||
@@ -549,7 +619,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
t.true(contents.startsWith('# Created by Vercel CLI\n'));
|
||||
|
||||
const lines = new Set(contents.split('\n'));
|
||||
t.true(lines.has('MY_ENV_VAR="MY_VALUE"'));
|
||||
t.true(lines.has('MY_PLAINTEXT_ENV_VAR="my plaintext value"'));
|
||||
t.true(lines.has('MY_STDIN_VAR="{"expect":"quotes"}"'));
|
||||
t.true(lines.has('VERCEL_URL=""'));
|
||||
}
|
||||
@@ -603,7 +673,8 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
const apiRes = await fetch(apiUrl);
|
||||
t.is(apiRes.status, 200, formatOutput({ stderr, stdout }));
|
||||
const apiJson = await apiRes.json();
|
||||
t.is(apiJson['MY_ENV_VAR'], 'MY_VALUE');
|
||||
t.is(apiJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
|
||||
t.is(apiJson['MY_SECRET_ENV_VAR'], 'my secret');
|
||||
t.is(apiJson['VERCEL_URL'], host);
|
||||
|
||||
const homeUrl = `https://${host}`;
|
||||
@@ -611,7 +682,8 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
const homeRes = await fetch(homeUrl);
|
||||
t.is(homeRes.status, 200, formatOutput({ stderr, stdout }));
|
||||
const homeJson = await homeRes.json();
|
||||
t.is(homeJson['MY_ENV_VAR'], 'MY_VALUE');
|
||||
t.is(homeJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
|
||||
t.is(homeJson['MY_SECRET_ENV_VAR'], 'my secret');
|
||||
t.is(homeJson['VERCEL_URL'], host);
|
||||
}
|
||||
|
||||
@@ -639,14 +711,14 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
|
||||
const apiJson = await apiRes.json();
|
||||
|
||||
t.is(apiJson['MY_ENV_VAR'], 'MY_VALUE');
|
||||
t.is(apiJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
|
||||
t.is(apiJson['VERCEL_URL'], localhostNoProtocol);
|
||||
|
||||
const homeUrl = localhost[0];
|
||||
|
||||
const homeRes = await fetch(homeUrl);
|
||||
const homeJson = await homeRes.json();
|
||||
t.is(homeJson['MY_ENV_VAR'], 'MY_VALUE');
|
||||
t.is(homeJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
|
||||
t.is(homeJson['VERCEL_URL'], localhostNoProtocol);
|
||||
|
||||
vc.kill('SIGTERM', { forceKillAfterTimeout: 2000 });
|
||||
@@ -680,13 +752,15 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
const apiJson = await apiRes.json();
|
||||
|
||||
t.is(apiJson['VERCEL_URL'], localhostNoProtocol);
|
||||
t.is(apiJson['MY_ENV_VAR'], 'MY_VALUE');
|
||||
t.is(apiJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
|
||||
t.is(apiJson['MY_STDIN_VAR'], '{"expect":"quotes"}');
|
||||
|
||||
const homeUrl = localhost[0];
|
||||
const homeRes = await fetch(homeUrl);
|
||||
const homeJson = await homeRes.json();
|
||||
t.is(homeJson['MY_ENV_VAR'], 'MY_VALUE');
|
||||
t.is(homeJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
|
||||
t.is(homeJson['VERCEL_URL'], localhostNoProtocol);
|
||||
t.is(homeJson['MY_STDIN_VAR'], '{"expect":"quotes"}');
|
||||
|
||||
vc.kill('SIGTERM', { forceKillAfterTimeout: 2000 });
|
||||
|
||||
@@ -702,12 +776,27 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
await waitForPrompt(now, chunk =>
|
||||
chunk.includes('What’s the name of the variable?')
|
||||
);
|
||||
now.stdin.write('MY_ENV_VAR\n');
|
||||
now.stdin.write('MY_PLAINTEXT_ENV_VAR\n');
|
||||
|
||||
// expect error if no environment is selected
|
||||
await waitForPrompt(
|
||||
now,
|
||||
chunk =>
|
||||
chunk.includes('which Environments') &&
|
||||
chunk.includes('MY_PLAINTEXT_ENV_VAR')
|
||||
);
|
||||
now.stdin.write('\n'); // select none
|
||||
await waitForPrompt(now, chunk =>
|
||||
chunk.includes(
|
||||
'Please select an Environment to remove the Environment Variable from.'
|
||||
)
|
||||
);
|
||||
|
||||
await waitForPrompt(
|
||||
now,
|
||||
chunk =>
|
||||
chunk.includes('which Environments') && chunk.includes('MY_ENV_VAR')
|
||||
chunk.includes('which Environments') &&
|
||||
chunk.includes('MY_PLAINTEXT_ENV_VAR')
|
||||
);
|
||||
now.stdin.write('a\n'); // select all
|
||||
|
||||
@@ -719,7 +808,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
async function nowEnvRemoveWithArgs() {
|
||||
const { exitCode, stderr, stdout } = await execa(
|
||||
binaryPath,
|
||||
['env', 'rm', 'MY_STDIN_VAR', 'development', '-y', ...defaultArgs],
|
||||
['env', 'rm', 'MY_SECRET_ENV_VAR', 'preview', '-y', ...defaultArgs],
|
||||
{
|
||||
reject: false,
|
||||
cwd: target,
|
||||
@@ -727,6 +816,21 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
);
|
||||
|
||||
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
|
||||
|
||||
const {
|
||||
exitCode: exitCode2,
|
||||
stderr: stderr2,
|
||||
stdout: stdout2,
|
||||
} = await execa(
|
||||
binaryPath,
|
||||
['env', 'rm', 'MY_STDIN_VAR', 'development', '-y', ...defaultArgs],
|
||||
{
|
||||
reject: false,
|
||||
cwd: target,
|
||||
}
|
||||
);
|
||||
|
||||
t.is(exitCode2, 0, formatOutput({ stderr2, stdout2 }));
|
||||
}
|
||||
|
||||
async function nowEnvRemoveWithNameOnly() {
|
||||
@@ -751,8 +855,10 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
}
|
||||
|
||||
await nowDeploy();
|
||||
const secretName = await createSecret();
|
||||
await nowEnvLsIsEmpty();
|
||||
await nowEnvAdd();
|
||||
await nowEnvAddPlaintext();
|
||||
await nowEnvAddSecret(secretName);
|
||||
await nowEnvAddFromStdin();
|
||||
await nowEnvAddSystemEnv();
|
||||
await nowEnvLsIncludesVar();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/client",
|
||||
"version": "9.0.4-canary.0",
|
||||
"version": "9.0.4-canary.1",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"homepage": "https://vercel.com",
|
||||
@@ -37,7 +37,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.5.5-canary.0",
|
||||
"@vercel/build-utils": "2.5.5-canary.1",
|
||||
"@zeit/fetch": "5.2.0",
|
||||
"async-retry": "1.2.3",
|
||||
"async-sema": "3.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/next",
|
||||
"version": "2.6.34",
|
||||
"version": "2.6.38",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
|
||||
|
||||
@@ -421,7 +421,7 @@ export const build = async ({
|
||||
});
|
||||
}
|
||||
|
||||
const appMountPrefixNoTrailingSlash = path.posix
|
||||
let appMountPrefixNoTrailingSlash = path.posix
|
||||
.join('/', entryDirectory)
|
||||
.replace(/\/+$/, '');
|
||||
|
||||
@@ -470,6 +470,30 @@ export const build = async ({
|
||||
headers.push(...convertHeaders(routesManifest.headers));
|
||||
}
|
||||
|
||||
if (routesManifest.basePath && routesManifest.basePath !== '/') {
|
||||
const nextBasePath = routesManifest.basePath;
|
||||
|
||||
if (!nextBasePath.startsWith('/')) {
|
||||
throw new NowBuildError({
|
||||
code: 'NEXT_BASEPATH_STARTING_SLASH',
|
||||
message:
|
||||
'basePath must start with `/`. Please upgrade your `@vercel/next` builder and try again. Contact support if this continues to happen.',
|
||||
});
|
||||
}
|
||||
if (nextBasePath.endsWith('/')) {
|
||||
throw new NowBuildError({
|
||||
code: 'NEXT_BASEPATH_TRAILING_SLASH',
|
||||
message:
|
||||
'basePath must not end with `/`. Please upgrade your `@vercel/next` builder and try again. Contact support if this continues to happen.',
|
||||
});
|
||||
}
|
||||
|
||||
entryDirectory = path.join(entryDirectory, nextBasePath);
|
||||
appMountPrefixNoTrailingSlash = path.posix
|
||||
.join('/', entryDirectory)
|
||||
.replace(/\/+$/, '');
|
||||
}
|
||||
|
||||
if (routesManifest.dataRoutes) {
|
||||
// Load the /_next/data routes for both dynamic SSG and SSP pages.
|
||||
// These must be combined and sorted to prevent conflicts
|
||||
@@ -511,6 +535,7 @@ export const build = async ({
|
||||
const { i18n } = routesManifest;
|
||||
|
||||
if (i18n) {
|
||||
const origSrc = route.src;
|
||||
route.src = route.src.replace(
|
||||
// we need to double escape the build ID here
|
||||
// to replace it properly
|
||||
@@ -522,6 +547,21 @@ export const build = async ({
|
||||
.join('|')})/`
|
||||
);
|
||||
|
||||
// optional-catchall routes don't have slash between
|
||||
// build-id and the regex
|
||||
if (route.src === origSrc) {
|
||||
route.src = route.src.replace(
|
||||
// we need to double escape the build ID here
|
||||
// to replace it properly
|
||||
`/${escapedBuildId}`,
|
||||
`/${escapedBuildId}/(?${
|
||||
ssgDataRoute ? '<nextLocale>' : ':'
|
||||
}${i18n.locales
|
||||
.map(locale => escapeStringRegexp(locale))
|
||||
.join('|')})[/]?`
|
||||
);
|
||||
}
|
||||
|
||||
// make sure to route to the correct prerender output
|
||||
if (ssgDataRoute) {
|
||||
route.dest = route.dest.replace(
|
||||
@@ -538,26 +578,6 @@ export const build = async ({
|
||||
hasPages404 = true;
|
||||
}
|
||||
|
||||
if (routesManifest.basePath && routesManifest.basePath !== '/') {
|
||||
const nextBasePath = routesManifest.basePath;
|
||||
|
||||
if (!nextBasePath.startsWith('/')) {
|
||||
throw new NowBuildError({
|
||||
code: 'NEXT_BASEPATH_STARTING_SLASH',
|
||||
message:
|
||||
'basePath must start with `/`. Please upgrade your `@vercel/next` builder and try again. Contact support if this continues to happen.',
|
||||
});
|
||||
}
|
||||
if (nextBasePath.endsWith('/')) {
|
||||
throw new NowBuildError({
|
||||
code: 'NEXT_BASEPATH_TRAILING_SLASH',
|
||||
message:
|
||||
'basePath must not end with `/`. Please upgrade your `@vercel/next` builder and try again. Contact support if this continues to happen.',
|
||||
});
|
||||
}
|
||||
|
||||
entryDirectory = path.join(entryDirectory, nextBasePath);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -1395,17 +1415,23 @@ export const build = async ({
|
||||
const isFallback = prerenderManifest.fallbackRoutes[pathname!];
|
||||
const isBlocking =
|
||||
prerenderManifest.blockingFallbackRoutes[pathname!];
|
||||
const isAutoExport =
|
||||
staticPages[
|
||||
addLocaleOrDefault(pathname!, routesManifest).substr(1)
|
||||
];
|
||||
|
||||
const isLocalePrefixed = isFallback || isBlocking || isAutoExport;
|
||||
|
||||
route.src = route.src.replace(
|
||||
'^',
|
||||
`^${dynamicPrefix ? `${dynamicPrefix}[/]?` : '[/]?'}(?${
|
||||
isFallback || isBlocking ? '<nextLocale>' : ':'
|
||||
isLocalePrefixed ? '<nextLocale>' : ':'
|
||||
}${i18n.locales
|
||||
.map(locale => escapeStringRegexp(locale))
|
||||
.join('|')})?`
|
||||
);
|
||||
|
||||
if (isFallback || isBlocking) {
|
||||
if (isLocalePrefixed) {
|
||||
// ensure destination has locale prefix to match prerender output
|
||||
// path so that the prerender object is used
|
||||
route.dest = route.dest!.replace(
|
||||
@@ -1544,8 +1570,9 @@ export const build = async ({
|
||||
|
||||
if (!currentPage) {
|
||||
console.error(
|
||||
"Failed to find matching page for", {toRender, header: req.headers['x-nextjs-page'], url: req.url, pages: Object.keys(pages) }, "in lambda"
|
||||
"Failed to find matching page for", {toRender, header: req.headers['x-nextjs-page'], url: req.url }, "in lambda"
|
||||
)
|
||||
console.error('pages in lambda', Object.keys(pages))
|
||||
res.statusCode = 500
|
||||
return res.end('internal server error')
|
||||
}
|
||||
@@ -2063,7 +2090,7 @@ export const build = async ({
|
||||
},
|
||||
|
||||
// Handle redirecting to locale specific domains
|
||||
...(i18n.domains
|
||||
...(i18n.domains && i18n.localeDetection !== false
|
||||
? [
|
||||
{
|
||||
// TODO: enable redirecting between domains, will require
|
||||
@@ -2100,26 +2127,29 @@ export const build = async ({
|
||||
: []),
|
||||
|
||||
// Handle redirecting to locale paths
|
||||
{
|
||||
// TODO: enable redirecting between paths, will require
|
||||
// updating the src with the desired locales to redirect.
|
||||
// if default locale is included in this src it won't be visitable
|
||||
// by users who prefer another language since the cookie isn't set
|
||||
// on redirect currently like in `next start`
|
||||
src: '/',
|
||||
locale: {
|
||||
redirect: i18n.locales.reduce(
|
||||
(prev: Record<string, string>, locale) => {
|
||||
prev[locale] =
|
||||
locale === i18n.defaultLocale ? `/` : `/${locale}`;
|
||||
return prev;
|
||||
...(i18n.localeDetection !== false
|
||||
? [
|
||||
{
|
||||
// TODO: if default locale is included in this src it won't be
|
||||
// visitable by users who prefer another language since a
|
||||
// cookie isn't set signaling the default locale is preferred
|
||||
// on redirect currently, investigate adding this
|
||||
src: '/',
|
||||
locale: {
|
||||
redirect: i18n.locales.reduce(
|
||||
(prev: Record<string, string>, locale) => {
|
||||
prev[locale] =
|
||||
locale === i18n.defaultLocale ? `/` : `/${locale}`;
|
||||
return prev;
|
||||
},
|
||||
{}
|
||||
),
|
||||
cookie: 'NEXT_LOCALE',
|
||||
},
|
||||
continue: true,
|
||||
},
|
||||
{}
|
||||
),
|
||||
cookie: 'NEXT_LOCALE',
|
||||
},
|
||||
continue: true,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
|
||||
{
|
||||
src: `^${path.join('/', entryDirectory)}$`,
|
||||
@@ -2128,6 +2158,10 @@ export const build = async ({
|
||||
},
|
||||
|
||||
// Auto-prefix non-locale path with default locale
|
||||
// note for prerendered pages this will cause
|
||||
// x-now-route-matches to contain the path minus the locale
|
||||
// e.g. for /de/posts/[slug] x-now-route-matches would have
|
||||
// 1=posts%2Fpost-1
|
||||
{
|
||||
src: `^${path.join(
|
||||
'/',
|
||||
@@ -2170,10 +2204,22 @@ export const build = async ({
|
||||
{ handle: 'filesystem' },
|
||||
|
||||
// map pages to their lambda
|
||||
...pageLambdaRoutes,
|
||||
...pageLambdaRoutes.filter(route => {
|
||||
// filter out any SSG pages as they are already present in output
|
||||
if ('headers' in route) {
|
||||
let page = route.headers?.['x-nextjs-page']!;
|
||||
page = page === '/index' ? '/' : page;
|
||||
|
||||
// map /blog/[post] to correct lambda for iSSG
|
||||
...dynamicPageLambdaRoutes,
|
||||
if (
|
||||
prerenderManifest.staticRoutes[page] ||
|
||||
prerenderManifest.fallbackRoutes[page] ||
|
||||
prerenderManifest.blockingFallbackRoutes[page]
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
|
||||
// These need to come before handle: miss or else they are grouped
|
||||
// with that routing section
|
||||
|
||||
@@ -327,6 +327,7 @@ export type RoutesManifest = {
|
||||
routeKeys?: { [named: string]: string };
|
||||
}>;
|
||||
i18n?: {
|
||||
localeDetection?: boolean;
|
||||
defaultLocale: string;
|
||||
locales: string[];
|
||||
domains?: Array<{
|
||||
|
||||
22
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/next.config.js
vendored
Normal file
22
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/next.config.js
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
module.exports = {
|
||||
generateBuildId() {
|
||||
return 'testing-build-id';
|
||||
},
|
||||
i18n: {
|
||||
localeDetection: false,
|
||||
locales: ['nl-NL', 'nl-BE', 'nl', 'fr-BE', 'fr', 'en-US', 'en'],
|
||||
defaultLocale: 'en-US',
|
||||
// TODO: testing locale domains support, will require custom
|
||||
// testing set-up as test accounts are used currently
|
||||
domains: [
|
||||
{
|
||||
domain: 'example.be',
|
||||
defaultLocale: 'nl-BE',
|
||||
},
|
||||
{
|
||||
domain: 'example.fr',
|
||||
defaultLocale: 'fr',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
517
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/now.json
vendored
Normal file
517
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/now.json
vendored
Normal file
@@ -0,0 +1,517 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@vercel/next"
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
{
|
||||
"path": "/",
|
||||
"headers": {
|
||||
"accept-language": "en;q=0.9"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
},
|
||||
"status": 200,
|
||||
"mustContain": "\"en-US\""
|
||||
},
|
||||
{
|
||||
"path": "/",
|
||||
"headers": {
|
||||
"accept-language": "nl;q=0.9"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
},
|
||||
"status": 200,
|
||||
"mustContain": "\"en-US\""
|
||||
},
|
||||
{
|
||||
"path": "/",
|
||||
"headers": {
|
||||
"accept-language": "nl-NL;q=0.9"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
},
|
||||
"status": 200,
|
||||
"mustContain": "\"en-US\""
|
||||
},
|
||||
{
|
||||
"path": "/",
|
||||
"headers": {
|
||||
"accept-language": "fr;q=0.9"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
},
|
||||
"status": 200,
|
||||
"mustContain": "\"en-US\""
|
||||
},
|
||||
{
|
||||
"path": "/",
|
||||
"headers": {
|
||||
"accept-language": "en-US;q=0.9"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
},
|
||||
"status": 200,
|
||||
"mustContain": "index page"
|
||||
},
|
||||
{
|
||||
"path": "/en-US",
|
||||
"headers": {
|
||||
"accept-language": "nl;q=0.9"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
},
|
||||
"status": 200,
|
||||
"mustContain": "index page"
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/",
|
||||
"status": 200,
|
||||
"mustContain": "index page"
|
||||
},
|
||||
{
|
||||
"path": "/",
|
||||
"status": 200,
|
||||
"mustContain": ">en-US<"
|
||||
},
|
||||
{
|
||||
"path": "/en",
|
||||
"status": 200,
|
||||
"mustContain": "index page"
|
||||
},
|
||||
{
|
||||
"path": "/en",
|
||||
"status": 200,
|
||||
"mustContain": ">en<"
|
||||
},
|
||||
{
|
||||
"path": "/fr",
|
||||
"status": 200,
|
||||
"mustContain": "index page"
|
||||
},
|
||||
{
|
||||
"path": "/fr",
|
||||
"status": 200,
|
||||
"mustContain": ">fr<"
|
||||
},
|
||||
{
|
||||
"path": "/nl",
|
||||
"status": 200,
|
||||
"mustContain": "index page"
|
||||
},
|
||||
{
|
||||
"path": "/nl",
|
||||
"status": 200,
|
||||
"mustContain": ">nl<"
|
||||
},
|
||||
{
|
||||
"path": "/nl-NL",
|
||||
"status": 200,
|
||||
"mustContain": "index page"
|
||||
},
|
||||
{
|
||||
"path": "/nl-NL",
|
||||
"status": 200,
|
||||
"mustContain": ">nl-NL<"
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/non-existent",
|
||||
"status": 404
|
||||
},
|
||||
{
|
||||
"path": "/fr/non-existent",
|
||||
"status": 404,
|
||||
"mustContain": "lang=\"fr\""
|
||||
},
|
||||
{
|
||||
"path": "/en/non-existent",
|
||||
"status": 404,
|
||||
"mustContain": "lang=\"en\""
|
||||
},
|
||||
{
|
||||
"path": "/en-US/non-existent",
|
||||
"status": 404,
|
||||
"mustContain": "lang=\"en-US\""
|
||||
},
|
||||
{
|
||||
"path": "/nl/non-existent",
|
||||
"status": 404,
|
||||
"mustContain": "lang=\"nl\""
|
||||
},
|
||||
{
|
||||
"path": "/nl-NL/non-existent",
|
||||
"status": 404,
|
||||
"mustContain": "lang=\"nl-NL\""
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/hello.txt",
|
||||
"status": 200,
|
||||
"mustContain": "hello world!"
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "dynamic page"
|
||||
},
|
||||
{
|
||||
"path": "/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "\"en-US\""
|
||||
},
|
||||
{
|
||||
"path": "/en/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "dynamic page"
|
||||
},
|
||||
{
|
||||
"path": "/en/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "\"en\""
|
||||
},
|
||||
{
|
||||
"path": "/nl/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "dynamic page"
|
||||
},
|
||||
{
|
||||
"path": "/nl/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "\"nl\""
|
||||
},
|
||||
{
|
||||
"path": "/fr/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "dynamic page"
|
||||
},
|
||||
{
|
||||
"path": "/fr/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "\"fr\""
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/gsp",
|
||||
"status": 200,
|
||||
"mustContain": "gsp page"
|
||||
},
|
||||
{
|
||||
"path": "/gsp",
|
||||
"status": 200,
|
||||
"mustContain": ">en-US<"
|
||||
},
|
||||
{
|
||||
"path": "/en/gsp",
|
||||
"status": 200,
|
||||
"mustContain": "gsp page"
|
||||
},
|
||||
{
|
||||
"path": "/en/gsp",
|
||||
"status": 200,
|
||||
"mustContain": ">en<"
|
||||
},
|
||||
{
|
||||
"path": "/nl/gsp",
|
||||
"status": 200,
|
||||
"mustContain": "gsp page"
|
||||
},
|
||||
{
|
||||
"path": "/nl/gsp",
|
||||
"status": 200,
|
||||
"mustContain": ">nl<"
|
||||
},
|
||||
{
|
||||
"path": "/fr/gsp",
|
||||
"status": 200,
|
||||
"mustContain": "gsp page"
|
||||
},
|
||||
{
|
||||
"path": "/fr/gsp",
|
||||
"status": 200,
|
||||
"mustContain": ">fr<"
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/gssp",
|
||||
"status": 200,
|
||||
"mustContain": "gssp page"
|
||||
},
|
||||
{
|
||||
"path": "/gssp",
|
||||
"status": 200,
|
||||
"mustContain": ">en-US<"
|
||||
},
|
||||
{
|
||||
"path": "/en/gssp",
|
||||
"status": 200,
|
||||
"mustContain": "gssp page"
|
||||
},
|
||||
{
|
||||
"path": "/en/gssp",
|
||||
"status": 200,
|
||||
"mustContain": ">en<"
|
||||
},
|
||||
{
|
||||
"path": "/nl/gssp",
|
||||
"status": 200,
|
||||
"mustContain": "gssp page"
|
||||
},
|
||||
{
|
||||
"path": "/nl/gssp",
|
||||
"status": 200,
|
||||
"mustContain": ">nl<"
|
||||
},
|
||||
{
|
||||
"path": "/fr/gssp",
|
||||
"status": 200,
|
||||
"mustContain": "gssp page"
|
||||
},
|
||||
{
|
||||
"path": "/fr/gssp",
|
||||
"status": 200,
|
||||
"mustContain": ">fr<"
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/gssp/first",
|
||||
"status": 200,
|
||||
"mustContain": "gssp page"
|
||||
},
|
||||
{
|
||||
"path": "/gssp/first",
|
||||
"status": 200,
|
||||
"mustContain": ">en-US<"
|
||||
},
|
||||
{
|
||||
"path": "/gssp/first",
|
||||
"status": 200,
|
||||
"mustContain": "slug\":\"first\""
|
||||
},
|
||||
{
|
||||
"path": "/en/gssp/first",
|
||||
"status": 200,
|
||||
"mustContain": "gssp page"
|
||||
},
|
||||
{
|
||||
"path": "/en/gssp/first",
|
||||
"status": 200,
|
||||
"mustContain": ">en<"
|
||||
},
|
||||
{
|
||||
"path": "/en/gssp/first",
|
||||
"status": 200,
|
||||
"mustContain": "slug\":\"first\""
|
||||
},
|
||||
{
|
||||
"path": "/nl/gssp/first",
|
||||
"status": 200,
|
||||
"mustContain": "gssp page"
|
||||
},
|
||||
{
|
||||
"path": "/nl/gssp/first",
|
||||
"status": 200,
|
||||
"mustContain": ">nl<"
|
||||
},
|
||||
{
|
||||
"path": "/nl/gssp/first",
|
||||
"status": 200,
|
||||
"mustContain": "slug\":\"first\""
|
||||
},
|
||||
{
|
||||
"path": "/fr/gssp/first",
|
||||
"status": 200,
|
||||
"mustContain": "gssp page"
|
||||
},
|
||||
{
|
||||
"path": "/fr/gssp/first",
|
||||
"status": 200,
|
||||
"mustContain": ">fr<"
|
||||
},
|
||||
{
|
||||
"path": "/fr/gssp/first",
|
||||
"status": 200,
|
||||
"mustContain": "slug\":\"first\""
|
||||
},
|
||||
|
||||
// TODO: update when directory listing is disabled
|
||||
// and these are proper 404s
|
||||
{
|
||||
"path": "/en/not-found",
|
||||
"status": 200,
|
||||
"mustContain": "Index of"
|
||||
},
|
||||
{
|
||||
"path": "/nl/not-found",
|
||||
"status": 200,
|
||||
"mustContain": "Index of"
|
||||
},
|
||||
{
|
||||
"path": "/en-US/not-found",
|
||||
"status": 200,
|
||||
"mustContain": "lang=\"en-US\""
|
||||
},
|
||||
{
|
||||
"path": "/nl-NL/not-found",
|
||||
"status": 200,
|
||||
"mustContain": "lang=\"nl-NL\""
|
||||
},
|
||||
{
|
||||
"path": "/fr/not-found",
|
||||
"status": 200,
|
||||
"mustContain": "lang=\"fr\""
|
||||
},
|
||||
|
||||
// this will always be a 200 unless fallback: blocking is used
|
||||
// since the static fallback page is served before the 404
|
||||
// page is rendered
|
||||
{
|
||||
"path": "/en/not-found/fallback/first",
|
||||
"status": 200,
|
||||
"mustContain": "lang=\"en\""
|
||||
},
|
||||
{
|
||||
"delay": 2000
|
||||
},
|
||||
{
|
||||
"path": "/en/not-found/fallback/first",
|
||||
"status": 200,
|
||||
"mustNotContain": "gsp page"
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/en/not-found/fallback/first.json",
|
||||
"status": 404
|
||||
},
|
||||
{
|
||||
"path": "/en/not-found/fallback/first",
|
||||
"status": 200,
|
||||
"mustContain": "lang=\"en\""
|
||||
},
|
||||
{
|
||||
"path": "/en/not-found/fallback/first",
|
||||
"status": 200,
|
||||
"mustNotContain": "gsp page"
|
||||
},
|
||||
{
|
||||
"path": "/fr/not-found/fallback/first",
|
||||
"status": 200,
|
||||
"mustContain": "lang=\"fr\""
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/fr/not-found/fallback/first.json",
|
||||
"status": 200
|
||||
},
|
||||
{
|
||||
"path": "/fr/not-found/fallback/first",
|
||||
"status": 200,
|
||||
"mustContain": "lang=\"fr\""
|
||||
},
|
||||
{
|
||||
"delay": 2000
|
||||
},
|
||||
{
|
||||
"path": "/fr/not-found/fallback/first",
|
||||
"status": 200,
|
||||
"mustContain": "gsp page"
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/en-US/index.json",
|
||||
"status": 200,
|
||||
"mustContain": "\"locale\":\"en-US\""
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/en/index.json",
|
||||
"status": 200,
|
||||
"mustContain": "\"locale\":\"en\""
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/fr/index.json",
|
||||
"status": 200,
|
||||
"mustContain": "\"locale\":\"fr\""
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/nl/index.json",
|
||||
"status": 200,
|
||||
"mustContain": "\"locale\":\"nl\""
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/en-US/gsp.json",
|
||||
"status": 200,
|
||||
"mustContain": "\"locale\":\"en-US\""
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/en/gsp.json",
|
||||
"status": 200,
|
||||
"mustContain": "\"locale\":\"en\""
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/fr/gsp.json",
|
||||
"status": 200,
|
||||
"mustContain": "\"locale\":\"fr\""
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/nl/gsp.json",
|
||||
"status": 200,
|
||||
"mustContain": "\"locale\":\"nl\""
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/gsp/blocking/first",
|
||||
"status": 200,
|
||||
"mustContain": "catchall"
|
||||
},
|
||||
{
|
||||
"path": "/gsp/blocking/first",
|
||||
"status": 200,
|
||||
"mustContain": "lang=\"en-US\""
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/en-US/gsp/blocking/first.json",
|
||||
"status": 200,
|
||||
"mustContain": "\"catchall\":\"yes\""
|
||||
},
|
||||
{
|
||||
"path": "/nl-NL/gsp/blocking/first",
|
||||
"status": 200,
|
||||
"mustContain": "catchall"
|
||||
},
|
||||
{
|
||||
"path": "/nl-NL/gsp/blocking/first",
|
||||
"status": 200,
|
||||
"mustContain": "lang=\"nl-NL\""
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/nl-NL/gsp/blocking/first.json",
|
||||
"status": 200,
|
||||
"mustContain": "\"catchall\":\"yes\""
|
||||
},
|
||||
{
|
||||
"path": "/fr/gsp/blocking/first",
|
||||
"status": 200,
|
||||
"mustContain": "catchall"
|
||||
},
|
||||
{
|
||||
"path": "/fr/gsp/blocking/first",
|
||||
"status": 200,
|
||||
"mustContain": "lang=\"fr\""
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/fr/gsp/blocking/first.json",
|
||||
"status": 200,
|
||||
"mustContain": "\"catchall\":\"yes\""
|
||||
}
|
||||
]
|
||||
}
|
||||
7
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/package.json
vendored
Normal file
7
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/package.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"next": "canary",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
}
|
||||
}
|
||||
31
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/another.js
vendored
Normal file
31
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/another.js
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default function Page(props) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<>
|
||||
<p id="another">another page</p>
|
||||
<p id="props">{JSON.stringify(props)}</p>
|
||||
<p id="router-locale">{router.locale}</p>
|
||||
<p id="router-locales">{JSON.stringify(router.locales)}</p>
|
||||
<p id="router-query">{JSON.stringify(router.query)}</p>
|
||||
<p id="router-pathname">{router.pathname}</p>
|
||||
<p id="router-as-path">{router.asPath}</p>
|
||||
<Link href="/">
|
||||
<a id="to-index">to /</a>
|
||||
</Link>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps = ({ locale, locales }) => {
|
||||
return {
|
||||
props: {
|
||||
locale,
|
||||
locales,
|
||||
},
|
||||
};
|
||||
};
|
||||
21
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/auto-export/index.js
vendored
Normal file
21
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/auto-export/index.js
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default function Page(props) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<>
|
||||
<p id="auto-export">auto-export page</p>
|
||||
<p id="props">{JSON.stringify(props)}</p>
|
||||
<p id="router-locale">{router.locale}</p>
|
||||
<p id="router-locales">{JSON.stringify(router.locales)}</p>
|
||||
<p id="router-query">{JSON.stringify(router.query)}</p>
|
||||
<p id="router-pathname">{router.pathname}</p>
|
||||
<p id="router-as-path">{router.asPath}</p>
|
||||
<Link href="/">
|
||||
<a id="to-index">to /</a>
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
}
|
||||
12
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/dynamic/[slug].js
vendored
Normal file
12
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/dynamic/[slug].js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default function Dynamic(props) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>dynamic page</p>
|
||||
<p id="query">{JSON.stringify(router.query)}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
const Slug = props => {
|
||||
return (
|
||||
<div>
|
||||
<p id="props">{JSON.stringify(props)}</p>
|
||||
<Link href="/gsp/blocking/hallo-wereld" locale={'nl-NL'}>
|
||||
<a>/nl-NL/gsp/blocking/hallo-wereld</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gsp/blocking/42" locale={'nl-NL'}>
|
||||
<a>/nl-NL/gsp/blocking/42</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gsp/blocking/hallo-welt" locale={'fr'}>
|
||||
<a>/fr/gsp/blocking/hallo-welt</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gsp/blocking/42" locale={'fr'}>
|
||||
<a>/fr/gsp/blocking/42</a>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const getStaticProps = () => {
|
||||
return {
|
||||
props: {
|
||||
random: Math.random(),
|
||||
catchall: 'yes',
|
||||
},
|
||||
revalidate: 1,
|
||||
};
|
||||
};
|
||||
|
||||
export const getStaticPaths = () => {
|
||||
return {
|
||||
paths: [],
|
||||
fallback: 'blocking',
|
||||
};
|
||||
};
|
||||
|
||||
export default Slug;
|
||||
51
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/gsp/fallback/[slug].js
vendored
Normal file
51
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/gsp/fallback/[slug].js
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default function Page(props) {
|
||||
const router = useRouter();
|
||||
|
||||
if (router.isFallback) return 'Loading...';
|
||||
|
||||
return (
|
||||
<>
|
||||
<p id="gsp">gsp page</p>
|
||||
<p id="props">{JSON.stringify(props)}</p>
|
||||
<p id="router-locale">{router.locale}</p>
|
||||
<p id="router-locales">{JSON.stringify(router.locales)}</p>
|
||||
<p id="router-query">{JSON.stringify(router.query)}</p>
|
||||
<p id="router-pathname">{router.pathname}</p>
|
||||
<p id="router-as-path">{router.asPath}</p>
|
||||
<Link href="/">
|
||||
<a id="to-index">to /</a>
|
||||
</Link>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const getStaticProps = ({ params, locale, locales }) => {
|
||||
return {
|
||||
props: {
|
||||
random: Math.random(),
|
||||
params,
|
||||
locale,
|
||||
locales,
|
||||
},
|
||||
revalidate: 1,
|
||||
};
|
||||
};
|
||||
|
||||
export const getStaticPaths = ({ locales }) => {
|
||||
const paths = [];
|
||||
|
||||
for (const locale of locales) {
|
||||
paths.push({ params: { slug: 'first' }, locale });
|
||||
paths.push({ params: { slug: 'second' }, locale });
|
||||
}
|
||||
|
||||
return {
|
||||
// the default locale will be used since one isn't defined here
|
||||
paths,
|
||||
fallback: true,
|
||||
};
|
||||
};
|
||||
32
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/gsp/index.js
vendored
Normal file
32
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/gsp/index.js
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default function Page(props) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<>
|
||||
<p id="gsp">gsp page</p>
|
||||
<p id="props">{JSON.stringify(props)}</p>
|
||||
<p id="router-locale">{router.locale}</p>
|
||||
<p id="router-locales">{JSON.stringify(router.locales)}</p>
|
||||
<p id="router-query">{JSON.stringify(router.query)}</p>
|
||||
<p id="router-pathname">{router.pathname}</p>
|
||||
<p id="router-as-path">{router.asPath}</p>
|
||||
<Link href="/">
|
||||
<a id="to-index">to /</a>
|
||||
</Link>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: should non-dynamic GSP pages pre-render for each locale?
|
||||
export const getStaticProps = ({ locale, locales }) => {
|
||||
return {
|
||||
props: {
|
||||
locale,
|
||||
locales,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,49 @@
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default function Page(props) {
|
||||
const router = useRouter();
|
||||
|
||||
if (router.isFallback) return 'Loading...';
|
||||
|
||||
return (
|
||||
<>
|
||||
<p id="gsp">gsp page</p>
|
||||
<p id="props">{JSON.stringify(props)}</p>
|
||||
<p id="router-locale">{router.locale}</p>
|
||||
<p id="router-locales">{JSON.stringify(router.locales)}</p>
|
||||
<p id="router-query">{JSON.stringify(router.query)}</p>
|
||||
<p id="router-pathname">{router.pathname}</p>
|
||||
<p id="router-as-path">{router.asPath}</p>
|
||||
<Link href="/">
|
||||
<a id="to-index">to /</a>
|
||||
</Link>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const getStaticProps = ({ params, locale, locales }) => {
|
||||
return {
|
||||
props: {
|
||||
random: Math.random(),
|
||||
params,
|
||||
locale,
|
||||
locales,
|
||||
},
|
||||
revalidate: 1,
|
||||
};
|
||||
};
|
||||
|
||||
export const getStaticPaths = () => {
|
||||
return {
|
||||
paths: [
|
||||
{ params: { slug: 'first' } },
|
||||
'/gsp/no-fallback/second',
|
||||
{ params: { slug: 'first' }, locale: 'en-US' },
|
||||
'/nl-NL/gsp/no-fallback/second',
|
||||
'/fr/gsp/no-fallback/first',
|
||||
],
|
||||
fallback: false,
|
||||
};
|
||||
};
|
||||
32
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/gssp/[slug].js
vendored
Normal file
32
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/gssp/[slug].js
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default function Page(props) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<>
|
||||
<p id="gssp">gssp page</p>
|
||||
<p id="props">{JSON.stringify(props)}</p>
|
||||
<p id="router-locale">{router.locale}</p>
|
||||
<p id="router-locales">{JSON.stringify(router.locales)}</p>
|
||||
<p id="router-query">{JSON.stringify(router.query)}</p>
|
||||
<p id="router-pathname">{router.pathname}</p>
|
||||
<p id="router-as-path">{router.asPath}</p>
|
||||
<Link href="/">
|
||||
<a id="to-index">to /</a>
|
||||
</Link>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps = ({ params, locale, locales }) => {
|
||||
return {
|
||||
props: {
|
||||
params,
|
||||
locale,
|
||||
locales,
|
||||
},
|
||||
};
|
||||
};
|
||||
31
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/gssp/index.js
vendored
Normal file
31
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/gssp/index.js
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default function Page(props) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<>
|
||||
<p id="gssp">gssp page</p>
|
||||
<p id="props">{JSON.stringify(props)}</p>
|
||||
<p id="router-locale">{router.locale}</p>
|
||||
<p id="router-locales">{JSON.stringify(router.locales)}</p>
|
||||
<p id="router-query">{JSON.stringify(router.query)}</p>
|
||||
<p id="router-pathname">{router.pathname}</p>
|
||||
<p id="router-as-path">{router.asPath}</p>
|
||||
<Link href="/">
|
||||
<a id="to-index">to /</a>
|
||||
</Link>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps = ({ locale, locales }) => {
|
||||
return {
|
||||
props: {
|
||||
locale,
|
||||
locales,
|
||||
},
|
||||
};
|
||||
};
|
||||
57
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/index.js
vendored
Normal file
57
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/index.js
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default function Page(props) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<>
|
||||
<p id="index">index page</p>
|
||||
<p id="props">{JSON.stringify(props)}</p>
|
||||
<p id="router-locale">{router.locale}</p>
|
||||
<p id="router-locales">{JSON.stringify(router.locales)}</p>
|
||||
<p id="router-query">{JSON.stringify(router.query)}</p>
|
||||
<p id="router-pathname">{router.pathname}</p>
|
||||
<p id="router-as-path">{router.asPath}</p>
|
||||
<Link href="/another">
|
||||
<a id="to-another">to /another</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gsp">
|
||||
<a id="to-gsp">to /gsp</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gsp/fallback/first">
|
||||
<a id="to-fallback-first">to /gsp/fallback/first</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gsp/fallback/hello">
|
||||
<a id="to-fallback-hello">to /gsp/fallback/hello</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gsp/no-fallback/first">
|
||||
<a id="to-no-fallback-first">to /gsp/no-fallback/first</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gssp">
|
||||
<a id="to-gssp">to /gssp</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gssp/first">
|
||||
<a id="to-gssp-slug">to /gssp/first</a>
|
||||
</Link>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const getStaticProps = ({ locale, locales }) => {
|
||||
return {
|
||||
props: {
|
||||
random: Math.random(),
|
||||
locale,
|
||||
locales,
|
||||
},
|
||||
revalidate: 1,
|
||||
};
|
||||
};
|
||||
54
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/links.js
vendored
Normal file
54
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/links.js
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default function Page(props) {
|
||||
const router = useRouter();
|
||||
const { nextLocale } = router.query;
|
||||
|
||||
return (
|
||||
<>
|
||||
<p id="links">links page</p>
|
||||
<p id="props">{JSON.stringify(props)}</p>
|
||||
<p id="router-locale">{router.locale}</p>
|
||||
<p id="router-locales">{JSON.stringify(router.locales)}</p>
|
||||
<p id="router-query">{JSON.stringify(router.query)}</p>
|
||||
<p id="router-pathname">{router.pathname}</p>
|
||||
<p id="router-as-path">{router.asPath}</p>
|
||||
<Link href="/another" locale={nextLocale}>
|
||||
<a id="to-another">to /another</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gsp" locale={nextLocale}>
|
||||
<a id="to-gsp">to /gsp</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gsp/fallback/first" locale={nextLocale}>
|
||||
<a id="to-fallback-first">to /gsp/fallback/first</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gsp/fallback/hello" locale={nextLocale}>
|
||||
<a id="to-fallback-hello">to /gsp/fallback/hello</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gsp/no-fallback/first" locale={nextLocale}>
|
||||
<a id="to-no-fallback-first">to /gsp/no-fallback/first</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gssp" locale={nextLocale}>
|
||||
<a id="to-gssp">to /gssp</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gssp/first" locale={nextLocale}>
|
||||
<a id="to-gssp-slug">to /gssp/first</a>
|
||||
</Link>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// make SSR page so we have query values immediately
|
||||
export const getServerSideProps = () => {
|
||||
return {
|
||||
props: {},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default function Page(props) {
|
||||
const router = useRouter();
|
||||
|
||||
if (router.isFallback) return 'Loading...';
|
||||
|
||||
return (
|
||||
<>
|
||||
<p id="gsp">gsp page</p>
|
||||
<p id="props">{JSON.stringify(props)}</p>
|
||||
<p id="router-locale">{router.locale}</p>
|
||||
<p id="router-locales">{JSON.stringify(router.locales)}</p>
|
||||
<p id="router-query">{JSON.stringify(router.query)}</p>
|
||||
<p id="router-pathname">{router.pathname}</p>
|
||||
<p id="router-as-path">{router.asPath}</p>
|
||||
<Link href="/">
|
||||
<a id="to-index">to /</a>
|
||||
</Link>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const getStaticProps = ({ params, locale, locales }) => {
|
||||
if (locale === 'en' || locale === 'nl') {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
params,
|
||||
locale,
|
||||
locales,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const getStaticPaths = () => {
|
||||
return {
|
||||
// the default locale will be used since one isn't defined here
|
||||
paths: ['first', 'second'].map(slug => ({
|
||||
params: { slug },
|
||||
})),
|
||||
fallback: true,
|
||||
};
|
||||
};
|
||||
37
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/not-found/index.js
vendored
Normal file
37
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/pages/not-found/index.js
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default function Page(props) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<>
|
||||
<p id="gsp">gsp page</p>
|
||||
<p id="props">{JSON.stringify(props)}</p>
|
||||
<p id="router-locale">{router.locale}</p>
|
||||
<p id="router-locales">{JSON.stringify(router.locales)}</p>
|
||||
<p id="router-query">{JSON.stringify(router.query)}</p>
|
||||
<p id="router-pathname">{router.pathname}</p>
|
||||
<p id="router-as-path">{router.asPath}</p>
|
||||
<Link href="/">
|
||||
<a id="to-index">to /</a>
|
||||
</Link>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const getStaticProps = ({ locale, locales }) => {
|
||||
if (locale === 'en' || locale === 'nl') {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
locale,
|
||||
locales,
|
||||
},
|
||||
};
|
||||
};
|
||||
1
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/public/hello.txt
vendored
Normal file
1
packages/now-next/test/fixtures/00-i18n-support-no-locale-detection/public/hello.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
hello world!
|
||||
@@ -172,6 +172,47 @@
|
||||
"mustContain": "hello world!"
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "dynamic page"
|
||||
},
|
||||
{
|
||||
"path": "/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "\"en-US\""
|
||||
},
|
||||
{
|
||||
"path": "/en/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "dynamic page"
|
||||
},
|
||||
{
|
||||
"path": "/en/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "\"en\""
|
||||
},
|
||||
{
|
||||
"path": "/nl/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "dynamic page"
|
||||
},
|
||||
{
|
||||
"path": "/nl/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "\"nl\""
|
||||
},
|
||||
{
|
||||
"path": "/fr/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "dynamic page"
|
||||
},
|
||||
{
|
||||
"path": "/fr/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "\"fr\""
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/gsp",
|
||||
"status": 200,
|
||||
|
||||
12
packages/now-next/test/fixtures/00-i18n-support-no-shared-lambdas/pages/dynamic/[slug].js
vendored
Normal file
12
packages/now-next/test/fixtures/00-i18n-support-no-shared-lambdas/pages/dynamic/[slug].js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default function Dynamic(props) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>dynamic page</p>
|
||||
<p id="query">{JSON.stringify(router.query)}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
182
packages/now-next/test/fixtures/00-i18n-support-root-catchall/additional.js
vendored
Normal file
182
packages/now-next/test/fixtures/00-i18n-support-root-catchall/additional.js
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
/* eslint-env jest */
|
||||
const fetch = require('node-fetch');
|
||||
const cheerio = require('cheerio');
|
||||
|
||||
module.exports = function (ctx) {
|
||||
it('should revalidate content properly from /', async () => {
|
||||
// we have to hit the _next/data URL first
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/en-US.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
const res = await fetch(`${ctx.deploymentUrl}/`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
let $ = cheerio.load(await res.text());
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('en-US');
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res2 = await fetch(`${ctx.deploymentUrl}/`);
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
$ = cheerio.load(await res2.text());
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('en-US');
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /fr', async () => {
|
||||
// we have to hit the _next/data URL first
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/fr.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
const res = await fetch(`${ctx.deploymentUrl}/fr`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
let $ = cheerio.load(await res.text());
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('fr');
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res2 = await fetch(`${ctx.deploymentUrl}/fr`);
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
$ = cheerio.load(await res2.text());
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('fr');
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /nl-NL', async () => {
|
||||
// we have to hit the _next/data URL first
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/nl-NL/index.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
const res = await fetch(`${ctx.deploymentUrl}/nl-NL`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
let $ = cheerio.load(await res.text());
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('nl-NL');
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res2 = await fetch(`${ctx.deploymentUrl}/nl-NL`);
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
$ = cheerio.load(await res2.text());
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('nl-NL');
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /second', async () => {
|
||||
// we have to hit the _next/data URL first
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/en-US/second.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res = await fetch(`${ctx.deploymentUrl}/second`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
const html = await res.text();
|
||||
let $ = cheerio.load(html);
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('en-US');
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res2 = await fetch(`${ctx.deploymentUrl}/second`);
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
$ = cheerio.load(await res2.text());
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('en-US');
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /fr/second', async () => {
|
||||
// we have to hit the _next/data URL first
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/fr/second.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res = await fetch(`${ctx.deploymentUrl}/fr/second`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
const html = await res.text();
|
||||
let $ = cheerio.load(html);
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('fr');
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res2 = await fetch(`${ctx.deploymentUrl}/fr/second`);
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
$ = cheerio.load(await res2.text());
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('fr');
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /nl-NL/second', async () => {
|
||||
// we have to hit the _next/data URL first
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/nl-NL/second.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res = await fetch(`${ctx.deploymentUrl}/nl-NL/second`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
const html = await res.text();
|
||||
let $ = cheerio.load(html);
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('nl-NL');
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res2 = await fetch(`${ctx.deploymentUrl}/nl-NL/second`);
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
$ = cheerio.load(await res2.text());
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('nl-NL');
|
||||
});
|
||||
};
|
||||
21
packages/now-next/test/fixtures/00-i18n-support-root-catchall/next.config.js
vendored
Normal file
21
packages/now-next/test/fixtures/00-i18n-support-root-catchall/next.config.js
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
module.exports = {
|
||||
generateBuildId() {
|
||||
return 'testing-build-id';
|
||||
},
|
||||
i18n: {
|
||||
locales: ['nl-NL', 'nl-BE', 'nl', 'fr-BE', 'fr', 'en-US', 'en'],
|
||||
defaultLocale: 'en-US',
|
||||
// TODO: testing locale domains support, will require custom
|
||||
// testing set-up as test accounts are used currently
|
||||
domains: [
|
||||
{
|
||||
domain: 'example.be',
|
||||
defaultLocale: 'nl-BE',
|
||||
},
|
||||
{
|
||||
domain: 'example.fr',
|
||||
defaultLocale: 'fr',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
192
packages/now-next/test/fixtures/00-i18n-support-root-catchall/now.json
vendored
Normal file
192
packages/now-next/test/fixtures/00-i18n-support-root-catchall/now.json
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@vercel/next"
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
{
|
||||
"path": "/hello.txt",
|
||||
"status": 200,
|
||||
"mustContain": "hello world!"
|
||||
},
|
||||
{
|
||||
"path": "/",
|
||||
"headers": {
|
||||
"accept-language": "en;q=0.9"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
},
|
||||
"status": 307,
|
||||
"responseHeaders": {
|
||||
"location": "//en/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/",
|
||||
"headers": {
|
||||
"accept-language": "nl;q=0.9"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
},
|
||||
"status": 307,
|
||||
"responseHeaders": {
|
||||
"location": "//nl/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/",
|
||||
"headers": {
|
||||
"accept-language": "nl-NL;q=0.9"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
},
|
||||
"status": 307,
|
||||
"responseHeaders": {
|
||||
"location": "//nl-NL/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/",
|
||||
"headers": {
|
||||
"accept-language": "fr;q=0.9"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
},
|
||||
"status": 307,
|
||||
"responseHeaders": {
|
||||
"location": "//fr/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/",
|
||||
"headers": {
|
||||
"accept-language": "en-US;q=0.9"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
},
|
||||
"status": 200,
|
||||
"mustContain": "catchall page"
|
||||
},
|
||||
{
|
||||
"path": "/en-US",
|
||||
"headers": {
|
||||
"accept-language": "nl;q=0.9"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
},
|
||||
"status": 200,
|
||||
"mustContain": "catchall page"
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/",
|
||||
"status": 200,
|
||||
"mustContain": "catchall page"
|
||||
},
|
||||
{
|
||||
"path": "/",
|
||||
"status": 200,
|
||||
"mustContain": ">en-US<"
|
||||
},
|
||||
{
|
||||
"path": "/en",
|
||||
"status": 200,
|
||||
"mustContain": "catchall page"
|
||||
},
|
||||
{
|
||||
"path": "/en",
|
||||
"status": 200,
|
||||
"mustContain": ">en<"
|
||||
},
|
||||
{
|
||||
"path": "/fr",
|
||||
"status": 200,
|
||||
"mustContain": "catchall page"
|
||||
},
|
||||
{
|
||||
"path": "/fr",
|
||||
"status": 200,
|
||||
"mustContain": ">fr<"
|
||||
},
|
||||
{
|
||||
"path": "/nl",
|
||||
"status": 200,
|
||||
"mustContain": "catchall page"
|
||||
},
|
||||
{
|
||||
"path": "/nl",
|
||||
"status": 200,
|
||||
"mustContain": ">nl<"
|
||||
},
|
||||
{
|
||||
"path": "/nl-NL",
|
||||
"status": 200,
|
||||
"mustContain": "catchall page"
|
||||
},
|
||||
{
|
||||
"path": "/nl-NL",
|
||||
"status": 200,
|
||||
"mustContain": ">nl-NL<"
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/first",
|
||||
"status": 200,
|
||||
"mustContain": "catchall page"
|
||||
},
|
||||
{
|
||||
"path": "/first",
|
||||
"status": 200,
|
||||
"mustContain": ">en-US<"
|
||||
},
|
||||
{
|
||||
"path": "/en/first",
|
||||
"status": 200,
|
||||
"mustContain": "catchall page"
|
||||
},
|
||||
{
|
||||
"path": "/en/first",
|
||||
"status": 200,
|
||||
"mustContain": ">en<"
|
||||
},
|
||||
{
|
||||
"path": "/fr/first",
|
||||
"status": 200,
|
||||
"mustContain": "catchall page"
|
||||
},
|
||||
{
|
||||
"path": "/fr/first",
|
||||
"status": 200,
|
||||
"mustContain": ">fr<"
|
||||
},
|
||||
{
|
||||
"path": "/nl/first",
|
||||
"status": 200,
|
||||
"mustContain": "catchall page"
|
||||
},
|
||||
{
|
||||
"path": "/nl/first",
|
||||
"status": 200,
|
||||
"mustContain": ">nl<"
|
||||
},
|
||||
{
|
||||
"path": "/nl-NL/first",
|
||||
"status": 200,
|
||||
"mustContain": "catchall page"
|
||||
},
|
||||
{
|
||||
"path": "/nl-NL/first",
|
||||
"status": 200,
|
||||
"mustContain": ">nl-NL<"
|
||||
}
|
||||
]
|
||||
}
|
||||
7
packages/now-next/test/fixtures/00-i18n-support-root-catchall/package.json
vendored
Normal file
7
packages/now-next/test/fixtures/00-i18n-support-root-catchall/package.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"next": "canary",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
}
|
||||
}
|
||||
69
packages/now-next/test/fixtures/00-i18n-support-root-catchall/pages/[[...slug]].js
vendored
Normal file
69
packages/now-next/test/fixtures/00-i18n-support-root-catchall/pages/[[...slug]].js
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
const Slug = props => {
|
||||
const router = useRouter();
|
||||
|
||||
// invariant ensuring fallback is never accidentally flipped
|
||||
if (router.isFallback) {
|
||||
return 'Loading...';
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>catchall page</p>
|
||||
<p id="props">{JSON.stringify(props)}</p>
|
||||
<p id="router-locale">{router.locale}</p>
|
||||
<p id="router-locales">{JSON.stringify(router.locales)}</p>
|
||||
<p id="router-query">{JSON.stringify(router.query)}</p>
|
||||
<p id="router-pathname">{router.pathname}</p>
|
||||
<p id="router-as-path">{router.asPath}</p>
|
||||
<Link href="/gsp/blocking/hallo-wereld" locale={'nl-NL'}>
|
||||
<a>/nl-NL/gsp/blocking/hallo-wereld</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gsp/blocking/42" locale={'nl-NL'}>
|
||||
<a>/nl-NL/gsp/blocking/42</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gsp/blocking/hallo-welt" locale={'fr'}>
|
||||
<a>/fr/gsp/blocking/hallo-welt</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/gsp/blocking/42" locale={'fr'}>
|
||||
<a>/fr/gsp/blocking/42</a>
|
||||
</Link>
|
||||
<br />
|
||||
<Link href="/">
|
||||
<a>/</a>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const getStaticProps = ({ params }) => {
|
||||
return {
|
||||
props: {
|
||||
params,
|
||||
random: Math.random(),
|
||||
catchall: 'yes',
|
||||
},
|
||||
revalidate: 1,
|
||||
};
|
||||
};
|
||||
|
||||
export const getStaticPaths = ({ locales }) => {
|
||||
const paths = [];
|
||||
|
||||
for (const locale of locales) {
|
||||
paths.push({ params: { slug: ['first'] }, locale });
|
||||
paths.push({ params: { slug: ['first'] }, locale });
|
||||
}
|
||||
|
||||
return {
|
||||
paths,
|
||||
fallback: 'blocking',
|
||||
};
|
||||
};
|
||||
|
||||
export default Slug;
|
||||
1
packages/now-next/test/fixtures/00-i18n-support-root-catchall/public/hello.txt
vendored
Normal file
1
packages/now-next/test/fixtures/00-i18n-support-root-catchall/public/hello.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
hello world!
|
||||
@@ -4,6 +4,14 @@ const cheerio = require('cheerio');
|
||||
|
||||
module.exports = function (ctx) {
|
||||
it('should revalidate content properly from /', async () => {
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/en-US/index.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res = await fetch(`${ctx.deploymentUrl}/`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
@@ -11,6 +19,7 @@ module.exports = function (ctx) {
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('en-US');
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({});
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
@@ -22,9 +31,18 @@ module.exports = function (ctx) {
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('en-US');
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({});
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /fr', async () => {
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/fr/index.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res = await fetch(`${ctx.deploymentUrl}/fr`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
@@ -32,6 +50,7 @@ module.exports = function (ctx) {
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('fr');
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({});
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
@@ -43,9 +62,18 @@ module.exports = function (ctx) {
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('fr');
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({});
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /nl-NL', async () => {
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/nl-NL/index.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res = await fetch(`${ctx.deploymentUrl}/nl-NL`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
@@ -53,6 +81,7 @@ module.exports = function (ctx) {
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('nl-NL');
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({});
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
@@ -64,9 +93,122 @@ module.exports = function (ctx) {
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('nl-NL');
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({});
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /gsp/fallback/first', async () => {
|
||||
// check the _next/data URL first
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/en-US/gsp/fallback/first.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res = await fetch(`${ctx.deploymentUrl}/gsp/fallback/first`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
const html = await res.text();
|
||||
let $ = cheerio.load(html);
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('en-US');
|
||||
expect(props.params).toEqual({ slug: 'first' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res2 = await fetch(`${ctx.deploymentUrl}/gsp/fallback/first`);
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
$ = cheerio.load(await res2.text());
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('en-US');
|
||||
expect(props2.params).toEqual({ slug: 'first' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /fr/gsp/fallback/first', async () => {
|
||||
// check the _next/data URL first
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/fr/gsp/fallback/first.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res = await fetch(`${ctx.deploymentUrl}/fr/gsp/fallback/first`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
const html = await res.text();
|
||||
let $ = cheerio.load(html);
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('fr');
|
||||
expect(props.params).toEqual({ slug: 'first' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res2 = await fetch(`${ctx.deploymentUrl}/fr/gsp/fallback/first`);
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
$ = cheerio.load(await res2.text());
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('fr');
|
||||
expect(props2.params).toEqual({ slug: 'first' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /nl-NL/gsp/fallback/first', async () => {
|
||||
// check the _next/data URL first
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/nl-NL/gsp/fallback/first.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res = await fetch(`${ctx.deploymentUrl}/nl-NL/gsp/fallback/first`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
const html = await res.text();
|
||||
let $ = cheerio.load(html);
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('nl-NL');
|
||||
expect(props.params).toEqual({ slug: 'first' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res2 = await fetch(`${ctx.deploymentUrl}/nl-NL/gsp/fallback/first`);
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
$ = cheerio.load(await res2.text());
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('nl-NL');
|
||||
expect(props2.params).toEqual({ slug: 'first' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
|
||||
});
|
||||
//
|
||||
|
||||
it('should revalidate content properly from /gsp/fallback/new-page', async () => {
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/en-US/gsp/fallback/new-page.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
const initRes = await fetch(`${ctx.deploymentUrl}/gsp/fallback/new-page`);
|
||||
expect(initRes.status).toBe(200);
|
||||
|
||||
@@ -80,6 +222,8 @@ module.exports = function (ctx) {
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('en-US');
|
||||
expect(props.params).toEqual({ slug: 'new-page' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'new-page' });
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
@@ -91,6 +235,8 @@ module.exports = function (ctx) {
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('en-US');
|
||||
expect(props2.params).toEqual({ slug: 'new-page' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'new-page' });
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /fr/gsp/fallback/new-page', async () => {
|
||||
@@ -110,6 +256,8 @@ module.exports = function (ctx) {
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('fr');
|
||||
expect(props.params).toEqual({ slug: 'new-page' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'new-page' });
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
@@ -140,6 +288,8 @@ module.exports = function (ctx) {
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('nl-NL');
|
||||
expect(props.params).toEqual({ slug: 'new-page' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'new-page' });
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
@@ -153,9 +303,19 @@ module.exports = function (ctx) {
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('nl-NL');
|
||||
expect(props2.params).toEqual({ slug: 'new-page' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'new-page' });
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /gsp/no-fallback/first', async () => {
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/en-US/gsp/no-fallback/first.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res = await fetch(`${ctx.deploymentUrl}/gsp/no-fallback/first`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
@@ -163,6 +323,8 @@ module.exports = function (ctx) {
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('en-US');
|
||||
expect(props.params).toEqual({ slug: 'first' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
@@ -174,9 +336,19 @@ module.exports = function (ctx) {
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('en-US');
|
||||
expect(props2.params).toEqual({ slug: 'first' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /fr/gsp/no-fallback/first', async () => {
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/fr/gsp/no-fallback/first.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res = await fetch(`${ctx.deploymentUrl}/fr/gsp/no-fallback/first`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
@@ -184,6 +356,8 @@ module.exports = function (ctx) {
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('fr');
|
||||
expect(props.params).toEqual({ slug: 'first' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
@@ -195,9 +369,19 @@ module.exports = function (ctx) {
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('fr');
|
||||
expect(props2.params).toEqual({ slug: 'first' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /nl-NL/gsp/no-fallback/second', async () => {
|
||||
const dataRes = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/nl-NL/gsp/no-fallback/second.json`
|
||||
);
|
||||
expect(dataRes.status).toBe(200);
|
||||
await dataRes.json();
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res = await fetch(
|
||||
`${ctx.deploymentUrl}/nl-NL/gsp/no-fallback/second`
|
||||
);
|
||||
@@ -207,6 +391,8 @@ module.exports = function (ctx) {
|
||||
const props = JSON.parse($('#props').text());
|
||||
const initialRandom = props.random;
|
||||
expect($('#router-locale').text()).toBe('nl-NL');
|
||||
expect(props.params).toEqual({ slug: 'second' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'second' });
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
@@ -220,5 +406,7 @@ module.exports = function (ctx) {
|
||||
const props2 = JSON.parse($('#props').text());
|
||||
expect(initialRandom).not.toBe(props2.random);
|
||||
expect($('#router-locale').text()).toBe('nl-NL');
|
||||
expect(props2.params).toEqual({ slug: 'second' });
|
||||
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'second' });
|
||||
});
|
||||
};
|
||||
|
||||
@@ -169,6 +169,47 @@
|
||||
"mustContain": "hello world!"
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "dynamic page"
|
||||
},
|
||||
{
|
||||
"path": "/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "\"en-US\""
|
||||
},
|
||||
{
|
||||
"path": "/en/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "dynamic page"
|
||||
},
|
||||
{
|
||||
"path": "/en/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "\"en\""
|
||||
},
|
||||
{
|
||||
"path": "/nl/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "dynamic page"
|
||||
},
|
||||
{
|
||||
"path": "/nl/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "\"nl\""
|
||||
},
|
||||
{
|
||||
"path": "/fr/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "dynamic page"
|
||||
},
|
||||
{
|
||||
"path": "/fr/dynamic/hello",
|
||||
"status": 200,
|
||||
"mustContain": "\"fr\""
|
||||
},
|
||||
|
||||
{
|
||||
"path": "/gsp",
|
||||
"status": 200,
|
||||
@@ -348,6 +389,9 @@
|
||||
"status": 200,
|
||||
"mustContain": "lang=\"en\""
|
||||
},
|
||||
{
|
||||
"delay": 2000
|
||||
},
|
||||
{
|
||||
"path": "/en/not-found/fallback/first",
|
||||
"status": 200,
|
||||
@@ -381,6 +425,9 @@
|
||||
"status": 200,
|
||||
"mustContain": "lang=\"fr\""
|
||||
},
|
||||
{
|
||||
"delay": 2000
|
||||
},
|
||||
{
|
||||
"path": "/fr/not-found/fallback/first",
|
||||
"status": 200,
|
||||
|
||||
12
packages/now-next/test/fixtures/00-i18n-support/pages/dynamic/[slug].js
vendored
Normal file
12
packages/now-next/test/fixtures/00-i18n-support/pages/dynamic/[slug].js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default function Dynamic(props) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>dynamic page</p>
|
||||
<p id="query">{JSON.stringify(router.query)}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -35,12 +35,17 @@ export const getStaticProps = ({ params, locale, locales }) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const getStaticPaths = () => {
|
||||
export const getStaticPaths = ({ locales }) => {
|
||||
const paths = [];
|
||||
|
||||
for (const locale of locales) {
|
||||
paths.push({ params: { slug: 'first' }, locale });
|
||||
paths.push({ params: { slug: 'second' }, locale });
|
||||
}
|
||||
|
||||
return {
|
||||
// the default locale will be used since one isn't defined here
|
||||
paths: ['first', 'second'].map(slug => ({
|
||||
params: { slug },
|
||||
})),
|
||||
paths,
|
||||
fallback: true,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -55,6 +55,26 @@
|
||||
{
|
||||
"path": "/docs/blog/post-1/comments",
|
||||
"mustContain": "comments post: post-1"
|
||||
},
|
||||
{
|
||||
"path": "/docs/_next/data/testing-build-id/blog/post-1.json",
|
||||
"status": 200,
|
||||
"mustContain": "\"post\""
|
||||
},
|
||||
{
|
||||
"path": "/docs/_next/data/testing-build-id/blog/post-2/comments.json",
|
||||
"status": 200,
|
||||
"mustContain": "\"post\""
|
||||
},
|
||||
{
|
||||
"path": "/docs/_next/data/testing-build-id/blog-ssg/post-1.json",
|
||||
"status": 200,
|
||||
"mustContain": "\"post\""
|
||||
},
|
||||
{
|
||||
"path": "/docs/_next/data/testing-build-id/blog-ssg/post-2/comments.json",
|
||||
"status": 200,
|
||||
"mustContain": "\"post\""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
16
packages/now-next/test/fixtures/16-base-path/pages/blog-ssg/[post]/comments.js
vendored
Normal file
16
packages/now-next/test/fixtures/16-base-path/pages/blog-ssg/[post]/comments.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
export const getStaticProps = ({ params }) => ({
|
||||
props: {
|
||||
post: params.post,
|
||||
},
|
||||
});
|
||||
|
||||
export const getStaticPaths = () => {
|
||||
return {
|
||||
paths: [{ params: { post: 'post-1' } }, { params: { post: 'post-2' } }],
|
||||
fallback: true,
|
||||
};
|
||||
};
|
||||
|
||||
export default function Comment({ post }) {
|
||||
return `comments post: ${post}`;
|
||||
}
|
||||
16
packages/now-next/test/fixtures/16-base-path/pages/blog-ssg/[post]/index.js
vendored
Normal file
16
packages/now-next/test/fixtures/16-base-path/pages/blog-ssg/[post]/index.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
export const getStaticProps = ({ params }) => ({
|
||||
props: {
|
||||
post: params.post,
|
||||
},
|
||||
});
|
||||
|
||||
export const getStaticPaths = () => {
|
||||
return {
|
||||
paths: [{ params: { post: 'post-1' } }, { params: { post: 'post-2' } }],
|
||||
fallback: true,
|
||||
};
|
||||
};
|
||||
|
||||
export default function Post({ post }) {
|
||||
return `index post: ${post}`;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/static-build",
|
||||
"version": "0.17.9",
|
||||
"version": "0.17.11",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/build-step",
|
||||
|
||||
@@ -33,6 +33,7 @@ const {
|
||||
NowBuildError,
|
||||
} = buildUtils;
|
||||
import { Route, Source } from '@vercel/routing-utils';
|
||||
import * as GatsbyUtils from './utils/gatsby';
|
||||
|
||||
const sleep = (n: number) => new Promise(resolve => setTimeout(resolve, n));
|
||||
|
||||
@@ -327,6 +328,22 @@ export async function build({
|
||||
debug(
|
||||
`Detected ${framework.name} framework. Optimizing your deployment...`
|
||||
);
|
||||
|
||||
if (process.env.VERCEL_ANALYTICS_ID) {
|
||||
const frameworkDirectory = path.join(
|
||||
workPath,
|
||||
path.dirname(entrypoint)
|
||||
);
|
||||
switch (framework.slug) {
|
||||
case 'gatsby': {
|
||||
await GatsbyUtils.injectVercelAnalyticsPlugin(frameworkDirectory);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const nodeVersion = await getNodeVersion(
|
||||
|
||||
40
packages/now-static-build/src/utils/_shared.ts
Normal file
40
packages/now-static-build/src/utils/_shared.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { PackageJson } from '@vercel/build-utils';
|
||||
import { constants, PathLike, promises as fs } from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
export type DeepWriteable<T> = {
|
||||
-readonly [P in keyof T]: DeepWriteable<T[P]>;
|
||||
};
|
||||
|
||||
export async function fileExists(path: PathLike): Promise<boolean> {
|
||||
return fs.access(path, constants.F_OK).then(
|
||||
() => true,
|
||||
() => false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read package.json from files
|
||||
*/
|
||||
export async function readPackageJson(entryPath: string): Promise<PackageJson> {
|
||||
const packagePath = path.join(entryPath, 'package.json');
|
||||
|
||||
try {
|
||||
return JSON.parse(await fs.readFile(packagePath, 'utf8'));
|
||||
} catch (err) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write package.json
|
||||
*/
|
||||
export async function writePackageJson(
|
||||
workPath: string,
|
||||
packageJson: PackageJson
|
||||
) {
|
||||
await fs.writeFile(
|
||||
path.join(workPath, 'package.json'),
|
||||
JSON.stringify(packageJson, null, 2)
|
||||
);
|
||||
}
|
||||
86
packages/now-static-build/src/utils/gatsby.ts
Normal file
86
packages/now-static-build/src/utils/gatsby.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { PackageJson } from '@vercel/build-utils';
|
||||
import { promises as fs } from 'fs';
|
||||
import * as path from 'path';
|
||||
import {
|
||||
fileExists,
|
||||
readPackageJson,
|
||||
DeepWriteable,
|
||||
writePackageJson,
|
||||
} from './_shared';
|
||||
|
||||
const defaultConfig = {
|
||||
plugins: [
|
||||
{
|
||||
resolve: 'gatsby-plugin-vercel',
|
||||
options: {},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export async function injectVercelAnalyticsPlugin(dir: string) {
|
||||
// Gatsby requires a special variable name for environment variables to be
|
||||
// exposed to the client-side JavaScript bundles:
|
||||
process.env.GATSBY_VERCEL_ANALYTICS_ID = process.env.VERCEL_ANALYTICS_ID;
|
||||
|
||||
const gatsbyConfigName = 'gatsby-config.js';
|
||||
const gatsbyPluginPackageName = 'gatsby-plugin-vercel';
|
||||
|
||||
const gatsbyConfigPath = path.join(dir, gatsbyConfigName);
|
||||
|
||||
const pkgJson: DeepWriteable<PackageJson> = (await readPackageJson(
|
||||
dir
|
||||
)) as DeepWriteable<PackageJson>;
|
||||
if (!pkgJson.dependencies) {
|
||||
pkgJson.dependencies = {};
|
||||
}
|
||||
if (!pkgJson.dependencies[gatsbyPluginPackageName]) {
|
||||
pkgJson.dependencies[gatsbyPluginPackageName] = 'latest';
|
||||
|
||||
await writePackageJson(dir, pkgJson);
|
||||
}
|
||||
|
||||
if (await fileExists(gatsbyConfigPath)) {
|
||||
await fs.rename(
|
||||
gatsbyConfigPath,
|
||||
gatsbyConfigPath + '.__vercel_builder_backup__.js'
|
||||
);
|
||||
|
||||
await fs.writeFile(
|
||||
gatsbyConfigPath,
|
||||
`const userConfig = require("./gatsby-config.js.__vercel_builder_backup__.js");
|
||||
|
||||
// https://github.com/gatsbyjs/gatsby/blob/354003fb2908e02ff12109ca3a02978a5a6e608c/packages/gatsby/src/bootstrap/prefer-default.ts
|
||||
const preferDefault = m => (m && m.default) || m;
|
||||
|
||||
const vercelConfig = Object.assign(
|
||||
{},
|
||||
|
||||
// https://github.com/gatsbyjs/gatsby/blob/a6ecfb2b01d761e8a3612b8ea132c698659923d9/packages/gatsby/src/services/initialize.ts#L113-L117
|
||||
preferDefault(userConfig)
|
||||
);
|
||||
if (!vercelConfig.plugins) {
|
||||
vercelConfig.plugins = [];
|
||||
}
|
||||
|
||||
const hasPlugin = vercelConfig.plugins.find(
|
||||
(p) =>
|
||||
p && (p === "gatsby-plugin-vercel" || p.resolve === "gatsby-plugin-vercel")
|
||||
);
|
||||
if (!hasPlugin) {
|
||||
vercelConfig.plugins = vercelConfig.plugins.slice();
|
||||
vercelConfig.plugins.push({
|
||||
resolve: "gatsby-plugin-vercel",
|
||||
options: {},
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = vercelConfig;
|
||||
`
|
||||
);
|
||||
} else {
|
||||
await fs.writeFile(
|
||||
gatsbyConfigPath,
|
||||
`module.exports = ${JSON.stringify(defaultConfig)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
69
packages/now-static-build/test/build-fixtures/01-gatsby-default/.gitignore
vendored
Normal file
69
packages/now-static-build/test/build-fixtures/01-gatsby-default/.gitignore
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# dotenv environment variable files
|
||||
.env*
|
||||
|
||||
# gatsby files
|
||||
.cache/
|
||||
public
|
||||
|
||||
# Mac files
|
||||
.DS_Store
|
||||
|
||||
# Yarn
|
||||
yarn-error.log
|
||||
.pnp/
|
||||
.pnp.js
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "gatsby-starter-default",
|
||||
"private": true,
|
||||
"description": "A simple starter to get up and developing quickly with Gatsby",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"gatsby": "^2.24.91",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gatsby build",
|
||||
"develop": "gatsby develop",
|
||||
"start": "npm run develop",
|
||||
"serve": "gatsby serve",
|
||||
"clean": "gatsby clean"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
const NotFoundPage = () => <h1>404: Not Found</h1>;
|
||||
|
||||
export default NotFoundPage;
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
const IndexPage = () => <h1>Hello World people</h1>;
|
||||
|
||||
export default IndexPage;
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@vercel/static-build",
|
||||
"config": {
|
||||
"zeroConfig": true,
|
||||
"framework": "gatsby"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
69
packages/now-static-build/test/build-fixtures/02-gatsby-user-config/.gitignore
vendored
Normal file
69
packages/now-static-build/test/build-fixtures/02-gatsby-user-config/.gitignore
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# dotenv environment variable files
|
||||
.env*
|
||||
|
||||
# gatsby files
|
||||
.cache/
|
||||
public
|
||||
|
||||
# Mac files
|
||||
.DS_Store
|
||||
|
||||
# Yarn
|
||||
yarn-error.log
|
||||
.pnp/
|
||||
.pnp.js
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
siteMetadata: {
|
||||
title: `Gatsby Default Starter`,
|
||||
description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
|
||||
author: `@gatsbyjs`,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "gatsby-starter-default",
|
||||
"private": true,
|
||||
"description": "A simple starter to get up and developing quickly with Gatsby",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"gatsby": "^2.24.91",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gatsby build",
|
||||
"develop": "gatsby develop",
|
||||
"start": "npm run develop",
|
||||
"serve": "gatsby serve",
|
||||
"clean": "gatsby clean"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
const NotFoundPage = () => <h1>404: Not Found</h1>;
|
||||
|
||||
export default NotFoundPage;
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
const IndexPage = () => <h1>Hello World people</h1>;
|
||||
|
||||
export default IndexPage;
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@vercel/static-build",
|
||||
"config": {
|
||||
"zeroConfig": true,
|
||||
"framework": "gatsby"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
69
packages/now-static-build/test/build-fixtures/03-gatsby-with-plugins/.gitignore
vendored
Normal file
69
packages/now-static-build/test/build-fixtures/03-gatsby-with-plugins/.gitignore
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# dotenv environment variable files
|
||||
.env*
|
||||
|
||||
# gatsby files
|
||||
.cache/
|
||||
public
|
||||
|
||||
# Mac files
|
||||
.DS_Store
|
||||
|
||||
# Yarn
|
||||
yarn-error.log
|
||||
.pnp/
|
||||
.pnp.js
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
siteMetadata: {
|
||||
title: `Gatsby Default Starter`,
|
||||
description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
|
||||
author: `@gatsbyjs`,
|
||||
},
|
||||
plugins: [`gatsby-plugin-react-helmet`],
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "gatsby-starter-default",
|
||||
"private": true,
|
||||
"description": "A simple starter to get up and developing quickly with Gatsby",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"gatsby": "^2.24.91",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"gatsby-plugin-react-helmet": "3.3.14",
|
||||
"react-helmet": "^6.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gatsby build",
|
||||
"develop": "gatsby develop",
|
||||
"start": "npm run develop",
|
||||
"serve": "gatsby serve",
|
||||
"clean": "gatsby clean"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
const NotFoundPage = () => <h1>404: Not Found</h1>;
|
||||
|
||||
export default NotFoundPage;
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
const IndexPage = () => <h1>Hello World people</h1>;
|
||||
|
||||
export default IndexPage;
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@vercel/static-build",
|
||||
"config": {
|
||||
"zeroConfig": true,
|
||||
"framework": "gatsby"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
69
packages/now-static-build/test/build-fixtures/04-gatsby-no-dupe-simple/.gitignore
vendored
Normal file
69
packages/now-static-build/test/build-fixtures/04-gatsby-no-dupe-simple/.gitignore
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# dotenv environment variable files
|
||||
.env*
|
||||
|
||||
# gatsby files
|
||||
.cache/
|
||||
public
|
||||
|
||||
# Mac files
|
||||
.DS_Store
|
||||
|
||||
# Yarn
|
||||
yarn-error.log
|
||||
.pnp/
|
||||
.pnp.js
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
siteMetadata: {
|
||||
title: `Gatsby Default Starter`,
|
||||
description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
|
||||
author: `@gatsbyjs`,
|
||||
},
|
||||
plugins: [`gatsby-plugin-vercel`],
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "gatsby-starter-default",
|
||||
"private": true,
|
||||
"description": "A simple starter to get up and developing quickly with Gatsby",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"gatsby": "^2.24.91",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gatsby build",
|
||||
"develop": "gatsby develop",
|
||||
"start": "npm run develop",
|
||||
"serve": "gatsby serve",
|
||||
"clean": "gatsby clean"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
const NotFoundPage = () => <h1>404: Not Found</h1>;
|
||||
|
||||
export default NotFoundPage;
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
const IndexPage = () => <h1>Hello World people</h1>;
|
||||
|
||||
export default IndexPage;
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@vercel/static-build",
|
||||
"config": {
|
||||
"zeroConfig": true,
|
||||
"framework": "gatsby"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
69
packages/now-static-build/test/build-fixtures/05-gatsby-no-dupe-advanced/.gitignore
vendored
Normal file
69
packages/now-static-build/test/build-fixtures/05-gatsby-no-dupe-advanced/.gitignore
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# dotenv environment variable files
|
||||
.env*
|
||||
|
||||
# gatsby files
|
||||
.cache/
|
||||
public
|
||||
|
||||
# Mac files
|
||||
.DS_Store
|
||||
|
||||
# Yarn
|
||||
yarn-error.log
|
||||
.pnp/
|
||||
.pnp.js
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
siteMetadata: {
|
||||
title: `Gatsby Default Starter`,
|
||||
description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
|
||||
author: `@gatsbyjs`,
|
||||
},
|
||||
plugins: [{ resolve: `gatsby-plugin-vercel`, options: {} }],
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "gatsby-starter-default",
|
||||
"private": true,
|
||||
"description": "A simple starter to get up and developing quickly with Gatsby",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"gatsby": "^2.24.91",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gatsby build",
|
||||
"develop": "gatsby develop",
|
||||
"start": "npm run develop",
|
||||
"serve": "gatsby serve",
|
||||
"clean": "gatsby clean"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
const NotFoundPage = () => <h1>404: Not Found</h1>;
|
||||
|
||||
export default NotFoundPage;
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
const IndexPage = () => <h1>Hello World people</h1>;
|
||||
|
||||
export default IndexPage;
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@vercel/static-build",
|
||||
"config": {
|
||||
"zeroConfig": true,
|
||||
"framework": "gatsby"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
69
packages/now-static-build/test/build-fixtures/06-gatsby-export-default/.gitignore
vendored
Normal file
69
packages/now-static-build/test/build-fixtures/06-gatsby-export-default/.gitignore
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# dotenv environment variable files
|
||||
.env*
|
||||
|
||||
# gatsby files
|
||||
.cache/
|
||||
public
|
||||
|
||||
# Mac files
|
||||
.DS_Store
|
||||
|
||||
# Yarn
|
||||
yarn-error.log
|
||||
.pnp/
|
||||
.pnp.js
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user