Compare commits
99 Commits
@vercel/no
...
vercel@21.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b60467d2f | ||
|
|
4384a6104f | ||
|
|
f40f95ff37 | ||
|
|
90c05250b0 | ||
|
|
030880fe74 | ||
|
|
02bc88f33b | ||
|
|
38ff557cad | ||
|
|
47c34842d5 | ||
|
|
d21b215ad0 | ||
|
|
5827737fd5 | ||
|
|
a9e078d410 | ||
|
|
b4d9b17fb8 | ||
|
|
02c55bf634 | ||
|
|
08af15055f | ||
|
|
0597aaa5e4 | ||
|
|
176856a1ea | ||
|
|
375a55ebed | ||
|
|
7d33a05581 | ||
|
|
0377c8b737 | ||
|
|
662d546388 | ||
|
|
8c514b5608 | ||
|
|
a6ec53d9d3 | ||
|
|
3ad5903f70 | ||
|
|
3cf155e999 | ||
|
|
d9a298d97c | ||
|
|
487d3c8554 | ||
|
|
9d0bfd3656 | ||
|
|
ec75333569 | ||
|
|
51aab912a2 | ||
|
|
670b2653c0 | ||
|
|
f71686fdad | ||
|
|
ec9c8ce150 | ||
|
|
a2048fc6d3 | ||
|
|
09ff9cda9f | ||
|
|
3a4d6f7848 | ||
|
|
9a0d676c0d | ||
|
|
25cd7b9e6e | ||
|
|
f926d5516c | ||
|
|
4603383850 | ||
|
|
c0c57889c8 | ||
|
|
85908a0524 | ||
|
|
503b9a2429 | ||
|
|
eac8f32ae7 | ||
|
|
3f76fefde6 | ||
|
|
79ddc5746b | ||
|
|
9a14615b43 | ||
|
|
6d6ccbdc25 | ||
|
|
704424ec58 | ||
|
|
c471127c69 | ||
|
|
c02dc9ac49 | ||
|
|
dd10e8cc77 | ||
|
|
cf69c2398c | ||
|
|
e48707571f | ||
|
|
6051fe6f0c | ||
|
|
2b3ba8a14f | ||
|
|
25bea3f83e | ||
|
|
b3e1828ebe | ||
|
|
e0e2a8e87e | ||
|
|
37ec89796d | ||
|
|
d3e2a4c4db | ||
|
|
ece3645914 | ||
|
|
fee386493b | ||
|
|
d95ed184ab | ||
|
|
aef8e6388e | ||
|
|
ba43e88603 | ||
|
|
e61f9740c4 | ||
|
|
c4b010fe8b | ||
|
|
db18eb091f | ||
|
|
360e62d172 | ||
|
|
8c3cd0332d | ||
|
|
f5f276021e | ||
|
|
9fbec823f3 | ||
|
|
18c3dd3a63 | ||
|
|
5a4a20b33f | ||
|
|
4489ed0c85 | ||
|
|
359f23daf1 | ||
|
|
4ef92e85db | ||
|
|
659c4d6ccd | ||
|
|
e93d477df8 | ||
|
|
f64625655b | ||
|
|
25a8189997 | ||
|
|
25c3e627cf | ||
|
|
1d6d8b530f | ||
|
|
e821cc0ae7 | ||
|
|
8ecbdc5d03 | ||
|
|
895224985b | ||
|
|
0f42a63c03 | ||
|
|
81e4c9e6fe | ||
|
|
a0a29dc836 | ||
|
|
c1f9d51d7a | ||
|
|
422f0558c1 | ||
|
|
f064ae2908 | ||
|
|
58c3e636f0 | ||
|
|
d5081367f3 | ||
|
|
0ee88366ff | ||
|
|
9ae42c9e92 | ||
|
|
62b8df4a8d | ||
|
|
73ec7f3018 | ||
|
|
2d24a75ca6 |
9
.github/CONTRIBUTING.md
vendored
@@ -94,12 +94,3 @@ Sometimes you want to test changes to a Builder against an existing project, may
|
||||
4. Run `vercel *.tgz` to upload the tarball file and get a URL
|
||||
5. Edit any existing `vercel.json` project and replace `use` with the URL
|
||||
6. Run `vercel` or `vercel dev` to deploy with the experimental Builder
|
||||
|
||||
## Add a New Framework
|
||||
|
||||
You can add support for a new Framework by creating a Pull Request for this repository and following the steps below:
|
||||
|
||||
1. Add the Framework to the `@vercel/frameworks` package: The file is located in `./packages/frameworks/frameworks.json`. You can copy the structure of an existing one and adjust the required fields. Note that the `settings` property either contains a `value` or a `placeholder`. The `value` property is used when something is not configurable, the `placeholder` is used when something is configurable and can be changed with configuration. An example would be the Output Directory for Hugo, it's `public` by default but can be changed through its config file, so we use `placeholder` with an explanation of what can be used.
|
||||
2. Add an example to the `./examples` directory: The name of the directory should equal the slug of the framework used in `@vercel/frameworks`. The `.github/EXAMPLE_README_TEMPLATE.md` file can be used to create a `README.md` file for the example.
|
||||
3. Update the `@vercel/static-build` package: The file `./packages/now-static-build/src/frameworks.ts` has to be extended. You can add default routes that will always be applied to projects that use this Framework or specify some paths that will be cached to speed up the build process.
|
||||
4. After your Pull Request has been merged and released, other users can select the example on the Vercel dashboard and deploy it.
|
||||
|
||||
@@ -6,5 +6,5 @@ You're running Vercel CLI in a non-terminal context and there are no credentials
|
||||
|
||||
#### Possible Ways to Fix It
|
||||
|
||||
- Specify a value for the `--token` flag (this needs to be the token of the user account as which you'd like to act). You can either get the token from the `./vercel/auth.json` file located in your user directory or [from the dashboard](https://vercel.com/account/tokens).
|
||||
- Ensure that both `~/vercel/auth.json` and `~/vercel/config.json` exist
|
||||
- Specify a value for the `--token` flag (this needs to be the token of the user account as which you'd like to act). You can create a new token on your [Settings page](https://vercel.com/account/tokens).
|
||||
- Run `vercel login` to sign in and generate a new token
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { NowRequest, NowResponse } from '@now/node';
|
||||
import { NowRequest, NowResponse } from '@vercel/node';
|
||||
|
||||
export default (_req: NowRequest, res: NowResponse) => {
|
||||
const date = new Date().toString();
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"react-helmet": "^5.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@now/node": "^1.3.0"
|
||||
"@vercel/node": "1.8.5"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "gatsby develop",
|
||||
|
||||
@@ -1107,15 +1107,6 @@
|
||||
"@nodelib/fs.scandir" "2.1.3"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@now/node@^1.3.0":
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@now/node/-/node-1.7.1.tgz#764a0c6bcb24967f8014c4f73ad238c292996fe3"
|
||||
integrity sha512-+srVKopsVTPDR3u9eOjJryZroLTrPp8XEOuIDGBdfFcJuS7qpAomctSbfyA7WNyjC0ExtUxELqBg5sAedG5+2g==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
ts-node "8.9.1"
|
||||
typescript "3.9.3"
|
||||
|
||||
"@pieh/friendly-errors-webpack-plugin@1.7.0-chalk-2":
|
||||
version "1.7.0-chalk-2"
|
||||
resolved "https://registry.yarnpkg.com/@pieh/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.7.0-chalk-2.tgz#2e9da9d3ade9d18d013333eb408c457d04eabac0"
|
||||
@@ -1409,6 +1400,15 @@
|
||||
dependencies:
|
||||
wonka "^4.0.14"
|
||||
|
||||
"@vercel/node@1.8.5":
|
||||
version "1.8.5"
|
||||
resolved "https://registry.yarnpkg.com/@vercel/node/-/node-1.8.5.tgz#2c8b9532f1bb25734a9964c52973386ed78022d4"
|
||||
integrity sha512-1iw7FSR8Oau6vZB1MWfBnA5q2a/IqRHiSZSbt8lz0dyTF599q8pc5GcSv/TvmrYaEGzh3+N0S4cbmuMCqVlwJg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
ts-node "8.9.1"
|
||||
typescript "3.9.3"
|
||||
|
||||
"@webassemblyjs/ast@1.9.0":
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964"
|
||||
|
||||
@@ -14,6 +14,10 @@ Open [http://localhost:3000](http://localhost:3000) with your browser to see the
|
||||
|
||||
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
|
||||
|
||||
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
|
||||
|
||||
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "10.0.0",
|
||||
"next": "10.0.5",
|
||||
"react": "17.0.1",
|
||||
"react-dom": "17.0.1"
|
||||
}
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
max-width: 800px;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "2.6.0",
|
||||
"version": "2.7.0",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
|
||||
@@ -43,9 +43,8 @@ export function sortFiles(fileA: string, fileB: string) {
|
||||
export function detectApiExtensions(builders: Builder[]): Set<string> {
|
||||
return new Set<string>(
|
||||
builders
|
||||
.filter(
|
||||
b =>
|
||||
b.config && b.config.zeroConfig && b.src && b.src.startsWith('api/')
|
||||
.filter((b): b is Builder & { src: string } =>
|
||||
Boolean(b.config && b.config.zeroConfig && b.src?.startsWith('api/'))
|
||||
)
|
||||
.map(b => extname(b.src))
|
||||
.filter(Boolean)
|
||||
@@ -56,22 +55,28 @@ export function detectApiDirectory(builders: Builder[]): string | null {
|
||||
// TODO: We eventually want to save the api directory to
|
||||
// builder.config.apiDirectory so it is only detected once
|
||||
const found = builders.some(
|
||||
b => b.config && b.config.zeroConfig && b.src.startsWith('api/')
|
||||
b => b.config && b.config.zeroConfig && b.src?.startsWith('api/')
|
||||
);
|
||||
return found ? 'api' : null;
|
||||
}
|
||||
|
||||
// TODO: Replace this function with `config.outputDirectory`
|
||||
function getPublicBuilder(builders: Builder[]): Builder | null {
|
||||
const builder = builders.find(
|
||||
builder =>
|
||||
function getPublicBuilder(
|
||||
builders: Builder[]
|
||||
): (Builder & { src: string }) | null {
|
||||
for (const builder of builders) {
|
||||
if (
|
||||
typeof builder.src === 'string' &&
|
||||
isOfficialRuntime('static', builder.use) &&
|
||||
/^.*\/\*\*\/\*$/.test(builder.src) &&
|
||||
builder.config &&
|
||||
builder.config.zeroConfig === true
|
||||
);
|
||||
) {
|
||||
return builder as Builder & { src: string };
|
||||
}
|
||||
}
|
||||
|
||||
return builder || null;
|
||||
return null;
|
||||
}
|
||||
export function detectOutputDirectory(builders: Builder[]): string | null {
|
||||
// TODO: We eventually want to save the output directory to
|
||||
@@ -361,7 +366,7 @@ function maybeGetApiBuilder(
|
||||
return null;
|
||||
}
|
||||
|
||||
const match = apiMatches.find(({ src }) => {
|
||||
const match = apiMatches.find(({ src = '**' }) => {
|
||||
return src === fileName || minimatch(fileName, src);
|
||||
});
|
||||
|
||||
@@ -989,7 +994,6 @@ function getRouteResult(
|
||||
rewriteRoutes.push({
|
||||
src: '^/api(/.*)?$',
|
||||
status: 404,
|
||||
continue: true,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -292,6 +292,11 @@ export async function runNpmInstall(
|
||||
opts.prettyCommand = 'yarn install';
|
||||
command = 'yarn';
|
||||
commandArgs = ['install', ...args];
|
||||
|
||||
// Yarn v2 PnP mode may be activated, so force "node-modules" linker style
|
||||
if (!env.YARN_NODE_LINKER) {
|
||||
env.YARN_NODE_LINKER = 'node-modules';
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.NPM_ONLY_PRODUCTION) {
|
||||
@@ -388,10 +393,17 @@ export async function runPackageJsonScript(
|
||||
prettyCommand,
|
||||
});
|
||||
} else {
|
||||
// Yarn v2 PnP mode may be activated, so force "node-modules" linker style
|
||||
const env: typeof process.env = { ...spawnOpts?.env };
|
||||
if (!env.YARN_NODE_LINKER) {
|
||||
env.YARN_NODE_LINKER = 'node-modules';
|
||||
}
|
||||
|
||||
const prettyCommand = `yarn run ${scriptName}`;
|
||||
console.log(`Running "${prettyCommand}"`);
|
||||
await spawnAsync('yarn', ['run', scriptName], {
|
||||
...spawnOpts,
|
||||
env,
|
||||
cwd: destPath,
|
||||
prettyCommand,
|
||||
});
|
||||
|
||||
@@ -336,7 +336,7 @@ export interface NodeVersion {
|
||||
|
||||
export interface Builder {
|
||||
use: string;
|
||||
src: string;
|
||||
src?: string;
|
||||
config?: Config;
|
||||
}
|
||||
|
||||
|
||||
5
packages/now-build-utils/test/fixtures/19-yarn-v2/api/index.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
const { camelCase } = require('camel-case');
|
||||
|
||||
module.exports = (req, res) => {
|
||||
res.end(camelCase('camel-case module is working'));
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [{ "src": "package.json", "use": "@vercel/static-build" }],
|
||||
"probes": [{ "path": "/", "mustContain": "Svelte app" }]
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
"svelte": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"camel-case": "^4.1.2",
|
||||
"sirv-cli": "^0.4.4"
|
||||
}
|
||||
}
|
||||
|
||||
11
packages/now-build-utils/test/fixtures/19-yarn-v2/vercel.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{ "src": "package.json", "use": "@vercel/static-build" },
|
||||
{ "src": "api/index.js", "use": "@vercel/node" }
|
||||
],
|
||||
"probes": [
|
||||
{ "path": "/", "mustContain": "Svelte app" },
|
||||
{ "path": "/api", "mustContain": "camelCaseModuleIsWorking" }
|
||||
]
|
||||
}
|
||||
@@ -270,6 +270,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"camel-case@npm:^4.1.2":
|
||||
version: 4.1.2
|
||||
resolution: "camel-case@npm:4.1.2"
|
||||
dependencies:
|
||||
pascal-case: ^3.1.2
|
||||
tslib: ^2.0.3
|
||||
checksum: 3/0b8dcfb424c9497e45984b88ef005c66bdf8e877e36365aedfc3cf73182684fde5a14cf2c526579c0351a5f27dc39a00f1edecc25d43606075fea948c504e37f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"caseless@npm:~0.12.0":
|
||||
version: 0.12.0
|
||||
resolution: "caseless@npm:0.12.0"
|
||||
@@ -850,6 +860,15 @@ fsevents@~2.1.2:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lower-case@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "lower-case@npm:2.0.2"
|
||||
dependencies:
|
||||
tslib: ^2.0.3
|
||||
checksum: 3/aabaca9cef65f7564a1005b625664527e4d169e363101e65773f8f6ff2fdcf09884a3bc02990cd7a62cf05f3538114af25ee7bef553f1ca3208c8a77ac75cbfa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"magic-string@npm:^0.25.2":
|
||||
version: 0.25.7
|
||||
resolution: "magic-string@npm:0.25.7"
|
||||
@@ -944,6 +963,16 @@ fsevents@~2.1.2:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"no-case@npm:^3.0.4":
|
||||
version: 3.0.4
|
||||
resolution: "no-case@npm:3.0.4"
|
||||
dependencies:
|
||||
lower-case: ^2.0.2
|
||||
tslib: ^2.0.3
|
||||
checksum: 3/84db4909caec37504c6655f995a004067f8733be8cd8d849f1578661b60a1685e086325fa4e1a5e8ce94e7416c1d0f037e2a00f635a14457183de80ab4fc7612
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-gyp@npm:latest":
|
||||
version: 6.1.0
|
||||
resolution: "node-gyp@npm:6.1.0"
|
||||
@@ -1057,6 +1086,16 @@ fsevents@~2.1.2:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pascal-case@npm:^3.1.2":
|
||||
version: 3.1.2
|
||||
resolution: "pascal-case@npm:3.1.2"
|
||||
dependencies:
|
||||
no-case: ^3.0.4
|
||||
tslib: ^2.0.3
|
||||
checksum: 3/31708cecab221482edc81e2bd9b9d8282d72d4f1443b31f39725aa23768c5e42d93c4c014f1bc90f7f074e2a70d5091e4892ea370e550affc9ccf1d33c900bcd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-is-absolute@npm:^1.0.0":
|
||||
version: 1.0.1
|
||||
resolution: "path-is-absolute@npm:1.0.1"
|
||||
@@ -1447,6 +1486,7 @@ fsevents@~2.1.2:
|
||||
dependencies:
|
||||
"@rollup/plugin-commonjs": ^12.0.0
|
||||
"@rollup/plugin-node-resolve": ^8.0.0
|
||||
camel-case: ^4.1.2
|
||||
rollup: ^2.3.4
|
||||
rollup-plugin-livereload: ^1.0.0
|
||||
rollup-plugin-svelte: ^5.0.3
|
||||
@@ -1517,6 +1557,13 @@ fsevents@~2.1.2:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tslib@npm:^2.0.3":
|
||||
version: 2.0.3
|
||||
resolution: "tslib@npm:2.0.3"
|
||||
checksum: 3/447bfca5deaa157806c3f77eaba74d05dd0b38b014e47ce79d98b5c77ce7d91b00a687ba13ca1b5a74d35ca1098ac7a072c0a97fad06f0266612f2a03a6c8e8f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tunnel-agent@npm:^0.6.0":
|
||||
version: 0.6.0
|
||||
resolution: "tunnel-agent@npm:0.6.0"
|
||||
|
||||
@@ -182,7 +182,7 @@ describe('Test `detectBuilders`', () => {
|
||||
|
||||
const { builders } = await detectBuilders(files);
|
||||
expect(builders!.length).toBe(7);
|
||||
expect(builders!.some(b => b.src.endsWith('_test.go'))).toBe(false);
|
||||
expect(builders!.some(b => b.src!.endsWith('_test.go'))).toBe(false);
|
||||
});
|
||||
|
||||
it('just public', async () => {
|
||||
@@ -1341,7 +1341,7 @@ describe('Test `detectBuilders` with `featHandleMiss=true`', () => {
|
||||
featHandleMiss,
|
||||
});
|
||||
expect(builders!.length).toBe(7);
|
||||
expect(builders!.some(b => b.src.endsWith('_test.go'))).toBe(false);
|
||||
expect(builders!.some(b => b.src!.endsWith('_test.go'))).toBe(false);
|
||||
expect(errorRoutes!.length).toBe(1);
|
||||
expect((errorRoutes![0] as Source).status).toBe(404);
|
||||
});
|
||||
@@ -2393,7 +2393,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
expect(errorRoutes).toStrictEqual([
|
||||
@@ -2495,7 +2494,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2533,7 +2531,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2571,7 +2568,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2604,7 +2600,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2632,7 +2627,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2663,7 +2657,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2690,7 +2683,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`', async () => {
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2725,7 +2717,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
expect(errorRoutes).toStrictEqual([
|
||||
@@ -2820,7 +2811,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2853,7 +2843,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2887,7 +2876,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2913,7 +2901,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2937,7 +2924,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2962,7 +2948,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -2983,7 +2968,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`', async ()
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -3018,7 +3002,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -3076,7 +3059,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -3109,7 +3091,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -3143,7 +3124,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -3162,7 +3142,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -3186,7 +3165,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -3211,7 +3189,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
@@ -3232,7 +3209,6 @@ it('Test `detectRoutes` with `featHandleMiss=true`, `cleanUrls=true`, `trailingS
|
||||
{
|
||||
status: 404,
|
||||
src: '^/api(/.*)?$',
|
||||
continue: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel",
|
||||
"version": "20.1.3",
|
||||
"version": "21.1.0",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Vercel",
|
||||
@@ -61,11 +61,11 @@
|
||||
"node": ">= 10"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.6.0",
|
||||
"@vercel/go": "1.1.6",
|
||||
"@vercel/node": "1.8.5",
|
||||
"@vercel/python": "1.2.3",
|
||||
"@vercel/ruby": "1.2.4",
|
||||
"@vercel/build-utils": "2.7.0",
|
||||
"@vercel/go": "1.1.7",
|
||||
"@vercel/node": "1.9.0",
|
||||
"@vercel/python": "1.2.4",
|
||||
"@vercel/ruby": "1.2.5",
|
||||
"update-notifier": "4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -3,15 +3,15 @@ import { resolve, join } from 'path';
|
||||
import DevServer from '../../util/dev/server';
|
||||
import parseListen from '../../util/dev/parse-listen';
|
||||
import { Output } from '../../util/output';
|
||||
import { NowContext } from '../../types';
|
||||
import { NowContext, ProjectEnvVariable } from '../../types';
|
||||
import Client from '../../util/client';
|
||||
import { getLinkedProject } from '../../util/projects/link';
|
||||
import { getFrameworks } from '../../util/get-frameworks';
|
||||
import { isSettingValue } from '../../util/is-setting-value';
|
||||
import { ProjectSettings, ProjectEnvTarget } from '../../types';
|
||||
import { ProjectSettings } from '../../types';
|
||||
import getDecryptedEnvRecords from '../../util/get-decrypted-env-records';
|
||||
import { Env } from '@vercel/build-utils';
|
||||
import setupAndLink from '../../util/link/setup-and-link';
|
||||
import getSystemEnvValues from '../../util/env/get-system-env-values';
|
||||
|
||||
type Options = {
|
||||
'--debug'?: boolean;
|
||||
@@ -70,7 +70,8 @@ export default async function dev(
|
||||
let devCommand: string | undefined;
|
||||
let frameworkSlug: string | undefined;
|
||||
let projectSettings: ProjectSettings | undefined;
|
||||
let environmentVars: Env | undefined;
|
||||
let projectEnvs: ProjectEnvVariable[] = [];
|
||||
let systemEnvValues: string[] = [];
|
||||
if (link.status === 'linked') {
|
||||
const { project, org } = link;
|
||||
client.currentTeam = org.type === 'team' ? org.id : undefined;
|
||||
@@ -98,12 +99,12 @@ export default async function dev(
|
||||
cwd = join(cwd, project.rootDirectory);
|
||||
}
|
||||
|
||||
environmentVars = await getDecryptedEnvRecords(
|
||||
output,
|
||||
client,
|
||||
project,
|
||||
ProjectEnvTarget.Development
|
||||
);
|
||||
[{ envs: projectEnvs }, { systemEnvValues }] = await Promise.all([
|
||||
getDecryptedEnvRecords(output, client, project.id),
|
||||
project.autoExposeSystemEnvs
|
||||
? getSystemEnvValues(output, client, project.id)
|
||||
: { systemEnvValues: [] },
|
||||
]);
|
||||
}
|
||||
|
||||
const devServer = new DevServer(cwd, {
|
||||
@@ -112,7 +113,8 @@ export default async function dev(
|
||||
devCommand,
|
||||
frameworkSlug,
|
||||
projectSettings,
|
||||
environmentVars,
|
||||
projectEnvs,
|
||||
systemEnvValues,
|
||||
});
|
||||
|
||||
process.once('SIGINT', () => devServer.stop());
|
||||
|
||||
14
packages/now-cli/src/commands/env/add.ts
vendored
@@ -18,7 +18,7 @@ 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';
|
||||
import getSystemEnvValues from '../../util/env/get-system-env-values';
|
||||
|
||||
type Options = {
|
||||
'--debug': boolean;
|
||||
@@ -91,7 +91,10 @@ export default async function add(
|
||||
name: `Secret (can be created using ${getCommandName('secret add')})`,
|
||||
value: ProjectEnvType.Secret,
|
||||
},
|
||||
{ name: 'Provided by System', value: ProjectEnvType.System },
|
||||
{
|
||||
name: 'Reference to System Environment Variable',
|
||||
value: ProjectEnvType.System,
|
||||
},
|
||||
],
|
||||
})) as { inputEnvType: ProjectEnvType };
|
||||
|
||||
@@ -112,7 +115,10 @@ export default async function add(
|
||||
}
|
||||
}
|
||||
|
||||
const { envs } = await getEnvVariables(output, client, project.id);
|
||||
const [{ envs }, { systemEnvValues }] = await Promise.all([
|
||||
getEnvVariables(output, client, project.id),
|
||||
getSystemEnvValues(output, client, project.id),
|
||||
]);
|
||||
const existing = new Set(
|
||||
envs.filter(r => r.key === envName).map(r => r.target)
|
||||
);
|
||||
@@ -182,7 +188,7 @@ export default async function add(
|
||||
name: 'systemEnvValue',
|
||||
type: 'list',
|
||||
message: `What’s the value of ${envName}?`,
|
||||
choices: SYSTEM_ENV_VALUES.map(value => ({ name: value, value })),
|
||||
choices: systemEnvValues.map(value => ({ name: value, value })),
|
||||
});
|
||||
|
||||
envValue = systemEnvValue;
|
||||
|
||||
30
packages/now-cli/src/commands/env/pull.ts
vendored
@@ -1,5 +1,5 @@
|
||||
import chalk from 'chalk';
|
||||
import { ProjectEnvTarget, Project } from '../../types';
|
||||
import { Project } from '../../types';
|
||||
import { Output } from '../../util/output';
|
||||
import confirm from '../../util/input/confirm';
|
||||
import Client from '../../util/client';
|
||||
@@ -12,7 +12,8 @@ import { promises, openSync, closeSync, readSync } from 'fs';
|
||||
import { emoji, prependEmoji } from '../../util/emoji';
|
||||
import { getCommandName } from '../../util/pkg-name';
|
||||
const { writeFile } = promises;
|
||||
import { Env } from '@vercel/build-utils';
|
||||
import exposeSystemEnvs from '../../util/dev/expose-system-envs';
|
||||
import getSystemEnvValues from '../../util/env/get-system-env-values';
|
||||
|
||||
const CONTENTS_PREFIX = '# Created by Vercel CLI\n';
|
||||
|
||||
@@ -84,15 +85,22 @@ export default async function pull(
|
||||
);
|
||||
const pullStamp = stamp();
|
||||
|
||||
const records: Env = await withSpinner(
|
||||
'Downloading',
|
||||
async () =>
|
||||
await getDecryptedEnvRecords(
|
||||
output,
|
||||
client,
|
||||
project,
|
||||
ProjectEnvTarget.Development
|
||||
)
|
||||
const [
|
||||
{ envs: projectEnvs },
|
||||
{ systemEnvValues },
|
||||
] = await withSpinner('Downloading', () =>
|
||||
Promise.all([
|
||||
getDecryptedEnvRecords(output, client, project.id),
|
||||
project.autoExposeSystemEnvs
|
||||
? getSystemEnvValues(output, client, project.id)
|
||||
: { systemEnvValues: [] },
|
||||
])
|
||||
);
|
||||
|
||||
const records = exposeSystemEnvs(
|
||||
projectEnvs,
|
||||
systemEnvValues,
|
||||
project.autoExposeSystemEnvs
|
||||
);
|
||||
|
||||
const contents =
|
||||
|
||||
@@ -51,12 +51,6 @@ const help = () => {
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} ls my-app`)}
|
||||
|
||||
${chalk.gray(
|
||||
'–'
|
||||
)} List all deployments and all instances for the app ${chalk.dim('`my-app`')}
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} ls my-app --all`)}
|
||||
|
||||
${chalk.gray('–')} Filter deployments by metadata
|
||||
|
||||
${chalk.cyan(`$ ${getPkgName()} ls -m key1=value1 -m key2=value2`)}
|
||||
|
||||
@@ -324,7 +324,7 @@ function printLogRaw(log) {
|
||||
|
||||
if (log.object) {
|
||||
console.log(log.object);
|
||||
} else {
|
||||
} else if (typeof log.text === 'string') {
|
||||
console.log(
|
||||
log.text
|
||||
.replace(/\n$/, '')
|
||||
|
||||
@@ -230,6 +230,8 @@ export interface ProjectSettings {
|
||||
buildCommand?: string | null;
|
||||
outputDirectory?: string | null;
|
||||
rootDirectory?: string | null;
|
||||
autoExposeSystemEnvs?: boolean;
|
||||
directoryListing?: boolean;
|
||||
}
|
||||
|
||||
export interface Project extends ProjectSettings {
|
||||
@@ -243,6 +245,7 @@ export interface Project extends ProjectSettings {
|
||||
framework?: string | null;
|
||||
rootDirectory?: string | null;
|
||||
latestDeployments?: Partial<Deployment>[];
|
||||
autoExposeSystemEnvs?: boolean;
|
||||
}
|
||||
|
||||
export interface Org {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import chalk from 'chalk';
|
||||
import execa from 'execa';
|
||||
import semver from 'semver';
|
||||
import npa from 'npm-package-arg';
|
||||
@@ -8,9 +9,10 @@ import { mkdirp, readJSON, writeJSON } from 'fs-extra';
|
||||
import { NowBuildError, PackageJson } from '@vercel/build-utils';
|
||||
import cliPkg from '../pkg';
|
||||
|
||||
import { NoBuilderCacheError } from '../errors-ts';
|
||||
import cmd from '../output/cmd';
|
||||
import { Output } from '../output';
|
||||
import { getDistTag } from '../get-dist-tag';
|
||||
import { NoBuilderCacheError } from '../errors-ts';
|
||||
|
||||
import * as staticBuilder from './static-builder';
|
||||
import { BuilderWithPackage } from './types';
|
||||
@@ -261,7 +263,9 @@ async function npmInstall(
|
||||
throw new NowBuildError({
|
||||
message:
|
||||
(result as any).code === 'ENOENT'
|
||||
? '`npm` is not installed'
|
||||
? `Command not found: ${chalk.cyan(
|
||||
'npm'
|
||||
)}\nPlease ensure that ${cmd('npm')} is properly installed`
|
||||
: 'Failed to install `vercel dev` dependencies',
|
||||
code: 'NPM_INSTALL_ERROR',
|
||||
link: 'https://vercel.link/npm-install-failed-dev',
|
||||
|
||||
@@ -149,8 +149,8 @@ export async function executeBuild(
|
||||
filesRemoved,
|
||||
// This env distiniction is only necessary to maintain
|
||||
// backwards compatibility with the `@vercel/next` builder.
|
||||
env: envConfigs.runEnv,
|
||||
buildEnv: envConfigs.buildEnv,
|
||||
env: { ...envConfigs.runEnv },
|
||||
buildEnv: { ...envConfigs.buildEnv },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -402,7 +402,7 @@ export async function getBuildMatches(
|
||||
const builds = nowConfig.builds || [{ src: '**', use: '@vercel/static' }];
|
||||
|
||||
for (const buildConfig of builds) {
|
||||
let { src, use } = buildConfig;
|
||||
let { src = '**', use } = buildConfig;
|
||||
|
||||
if (!use) {
|
||||
continue;
|
||||
|
||||
41
packages/now-cli/src/util/dev/expose-system-envs.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { ProjectEnvType, ProjectEnvVariable } from '../../types';
|
||||
import { Env } from '@vercel/build-utils';
|
||||
|
||||
function getSystemEnvValue(
|
||||
systemEnvRef: string,
|
||||
{ vercelUrl }: { vercelUrl?: string }
|
||||
) {
|
||||
if (systemEnvRef === 'VERCEL_URL') {
|
||||
return vercelUrl || '';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
export default function exposeSystemEnvs(
|
||||
projectEnvs: ProjectEnvVariable[],
|
||||
systemEnvValues: string[],
|
||||
autoExposeSystemEnvs: boolean | undefined,
|
||||
vercelUrl?: string
|
||||
) {
|
||||
const envs: Env = {};
|
||||
|
||||
if (autoExposeSystemEnvs) {
|
||||
envs['VERCEL'] = '1';
|
||||
envs['VERCEL_ENV'] = 'development';
|
||||
|
||||
for (const key of systemEnvValues) {
|
||||
envs[key] = getSystemEnvValue(key, { vercelUrl });
|
||||
}
|
||||
}
|
||||
|
||||
for (let env of projectEnvs) {
|
||||
if (env.type === ProjectEnvType.System) {
|
||||
envs[env.key] = getSystemEnvValue(env.value, { vercelUrl });
|
||||
} else {
|
||||
envs[env.key] = env.value;
|
||||
}
|
||||
}
|
||||
|
||||
return envs;
|
||||
}
|
||||
@@ -43,6 +43,7 @@ import {
|
||||
} from '@vercel/build-utils';
|
||||
import _frameworks, { Framework } from '@vercel/frameworks';
|
||||
|
||||
import cmd from '../output/cmd';
|
||||
import link from '../output/link';
|
||||
import { Output } from '../output';
|
||||
import { relative } from '../path-helpers';
|
||||
@@ -85,7 +86,8 @@ import {
|
||||
HttpHeadersConfig,
|
||||
EnvConfigs,
|
||||
} from './types';
|
||||
import { ProjectSettings } from '../../types';
|
||||
import { ProjectEnvVariable, ProjectSettings } from '../../types';
|
||||
import exposeSystemEnvs from './expose-system-envs';
|
||||
|
||||
const frameworkList = _frameworks as Framework[];
|
||||
const frontendRuntimeSet = new Set(
|
||||
@@ -149,14 +151,16 @@ export default class DevServer {
|
||||
private updateBuildersTimeout: NodeJS.Timeout | undefined;
|
||||
private startPromise: Promise<void> | null;
|
||||
|
||||
private environmentVars: Env | undefined;
|
||||
private systemEnvValues: string[];
|
||||
private projectEnvs: ProjectEnvVariable[];
|
||||
|
||||
constructor(cwd: string, options: DevServerOptions) {
|
||||
this.cwd = cwd;
|
||||
this.debug = options.debug;
|
||||
this.output = options.output;
|
||||
this.envConfigs = { buildEnv: {}, runEnv: {}, allEnv: {} };
|
||||
this.environmentVars = options.environmentVars;
|
||||
this.systemEnvValues = options.systemEnvValues || [];
|
||||
this.projectEnvs = options.projectEnvs || [];
|
||||
this.files = {};
|
||||
this.address = '';
|
||||
this.devCommand = options.devCommand;
|
||||
@@ -491,7 +495,7 @@ export default class DevServer {
|
||||
const dotenv = await fs.readFile(filePath, 'utf8');
|
||||
this.output.debug(`Using local env: ${filePath}`);
|
||||
env = parseDotenv(dotenv);
|
||||
env = this.populateVercelEnvVars(env);
|
||||
env = this.injectSystemValuesInDotenv(env);
|
||||
} catch (err) {
|
||||
if (err.code !== 'ENOENT') {
|
||||
throw err;
|
||||
@@ -642,10 +646,30 @@ export default class DevServer {
|
||||
|
||||
let allEnv = { ...buildEnv, ...runEnv };
|
||||
|
||||
// If no .env/.build.env is present, fetch and use cloud environment variables
|
||||
// If no .env/.build.env is present, use cloud environment variables
|
||||
if (Object.keys(allEnv).length === 0) {
|
||||
const cloudEnv = this.populateVercelEnvVars(this.environmentVars);
|
||||
allEnv = runEnv = buildEnv = cloudEnv;
|
||||
const cloudEnv = exposeSystemEnvs(
|
||||
this.projectEnvs || [],
|
||||
this.systemEnvValues || [],
|
||||
this.projectSettings?.autoExposeSystemEnvs,
|
||||
new URL(this.address).host
|
||||
);
|
||||
|
||||
allEnv = { ...cloudEnv };
|
||||
runEnv = { ...cloudEnv };
|
||||
buildEnv = { ...cloudEnv };
|
||||
}
|
||||
|
||||
// legacy NOW_REGION env variable
|
||||
runEnv['NOW_REGION'] = 'dev1';
|
||||
buildEnv['NOW_REGION'] = 'dev1';
|
||||
allEnv['NOW_REGION'] = 'dev1';
|
||||
|
||||
// mirror how VERCEL_REGION is injected in prod/preview
|
||||
// only inject in `runEnvs`, because `allEnvs` is exposed to dev command
|
||||
// and should not contain VERCEL_REGION
|
||||
if (this.projectSettings?.autoExposeSystemEnvs) {
|
||||
runEnv['VERCEL_REGION'] = 'dev1';
|
||||
}
|
||||
|
||||
this.envConfigs = { buildEnv, runEnv, allEnv };
|
||||
@@ -753,23 +777,15 @@ export default class DevServer {
|
||||
return merged;
|
||||
}
|
||||
|
||||
populateVercelEnvVars(env: Env | undefined): Env {
|
||||
if (!env) {
|
||||
return {};
|
||||
}
|
||||
|
||||
injectSystemValuesInDotenv(env: Env): Env {
|
||||
for (const name of Object.keys(env)) {
|
||||
if (name === 'VERCEL_URL') {
|
||||
const host = new URL(this.address).host;
|
||||
env['VERCEL_URL'] = host;
|
||||
env['VERCEL_URL'] = new URL(this.address).host;
|
||||
} else if (name === 'VERCEL_REGION') {
|
||||
env['VERCEL_REGION'] = 'dev1';
|
||||
}
|
||||
}
|
||||
|
||||
// Always set NOW_REGION to match production
|
||||
env['NOW_REGION'] = 'dev1';
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
@@ -871,7 +887,7 @@ export default class DevServer {
|
||||
})
|
||||
.catch(err => {
|
||||
this.updateBuildersPromise = null;
|
||||
this.output.error(`Failed to update builders: ${err.message}`);
|
||||
this.output.prettyError(err);
|
||||
this.output.debug(err.stack);
|
||||
});
|
||||
}, ms('30s'));
|
||||
@@ -1658,15 +1674,24 @@ export default class DevServer {
|
||||
isDev: true,
|
||||
requestPath,
|
||||
devCacheDir,
|
||||
env: envConfigs.runEnv,
|
||||
buildEnv: envConfigs.buildEnv,
|
||||
env: { ...envConfigs.runEnv },
|
||||
buildEnv: { ...envConfigs.buildEnv },
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
// `startDevServer()` threw an error. Most likely this means the dev
|
||||
// server process exited before sending the port information message
|
||||
// (missing dependency at runtime, for example).
|
||||
debug(`Error starting "${builderPkg.name}" dev server: ${err}`);
|
||||
if (err.code === 'ENOENT') {
|
||||
err.message = `Command not found: ${chalk.cyan(
|
||||
err.path,
|
||||
...err.spawnargs
|
||||
)}\nPlease ensure that ${cmd(err.path)} is properly installed`;
|
||||
err.link = 'https://vercel.link/command-not-found';
|
||||
}
|
||||
|
||||
this.output.prettyError(err);
|
||||
|
||||
await this.sendError(
|
||||
req,
|
||||
res,
|
||||
@@ -1879,6 +1904,12 @@ export default class DevServer {
|
||||
requestPath: string,
|
||||
nowRequestId: string
|
||||
): boolean {
|
||||
// If the "directory listing" feature is disabled in the
|
||||
// Project's settings, then don't render the directory listing
|
||||
if (this.projectSettings?.directoryListing === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let prefix = requestPath;
|
||||
if (prefix.length > 0 && !prefix.endsWith('/')) {
|
||||
prefix += '/';
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
import { NowConfig } from '@vercel/client';
|
||||
import { HandleValue, Route } from '@vercel/routing-utils';
|
||||
import { Output } from '../output';
|
||||
import { ProjectSettings } from '../../types';
|
||||
import { ProjectEnvVariable, ProjectSettings } from '../../types';
|
||||
|
||||
export { NowConfig };
|
||||
|
||||
@@ -27,7 +27,8 @@ export interface DevServerOptions {
|
||||
devCommand?: string;
|
||||
frameworkSlug?: string;
|
||||
projectSettings?: ProjectSettings;
|
||||
environmentVars?: Env;
|
||||
systemEnvValues?: string[];
|
||||
projectEnvs?: ProjectEnvVariable[];
|
||||
}
|
||||
|
||||
export interface EnvConfigs {
|
||||
@@ -49,6 +50,7 @@ export interface EnvConfigs {
|
||||
|
||||
export interface BuildMatch extends BuildConfig {
|
||||
entrypoint: string;
|
||||
src: string;
|
||||
builderWithPkg: BuilderWithPackage;
|
||||
buildOutput: BuilderOutputs;
|
||||
buildResults: Map<string | null, BuildResult>;
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import { Output } from '../output';
|
||||
import Client from '../client';
|
||||
import { Secret } from '../../types';
|
||||
|
||||
export default async function getDecryptedSecret(
|
||||
output: Output,
|
||||
client: Client,
|
||||
secretId: string
|
||||
): Promise<string> {
|
||||
if (!secretId) {
|
||||
return '';
|
||||
}
|
||||
output.debug(`Fetching decrypted secret ${secretId}`);
|
||||
const url = `/v2/now/secrets/${secretId}?decrypt=true`;
|
||||
const secret = await client.fetch<Secret>(url);
|
||||
return secret.value;
|
||||
}
|
||||
12
packages/now-cli/src/util/env/get-system-env-values.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Output } from '../output';
|
||||
import Client from '../client';
|
||||
|
||||
export default async function getSystemEnvValues(
|
||||
output: Output,
|
||||
client: Client,
|
||||
projectId: string
|
||||
) {
|
||||
output.debug(`Fetching System Environment Values of project ${projectId}`);
|
||||
const url = `/v6/projects/${projectId}/system-env-values`;
|
||||
return client.fetch<{ systemEnvValues: string[] }>(url);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Output } from '../output';
|
||||
import Client from '../client';
|
||||
import { ProjectEnvTarget, Secret, ProjectEnvVariableV5 } from '../../types';
|
||||
import { ProjectEnvTarget, ProjectEnvVariableV5 } from '../../types';
|
||||
|
||||
export default async function removeEnvRecord(
|
||||
output: Output,
|
||||
@@ -18,32 +18,7 @@ export default async function removeEnvRecord(
|
||||
envName
|
||||
)}${qs}`;
|
||||
|
||||
const env = await client.fetch<ProjectEnvVariableV5>(urlProject, {
|
||||
await client.fetch<ProjectEnvVariableV5>(urlProject, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
|
||||
if (env && env.value) {
|
||||
const idOrName = env.value.startsWith('@') ? env.value.slice(1) : env.value;
|
||||
const urlSecret = `/v2/now/secrets/${idOrName}`;
|
||||
let secret: Secret | undefined;
|
||||
|
||||
try {
|
||||
secret = await client.fetch<Secret>(urlSecret);
|
||||
} catch (error) {
|
||||
if (error && error.status === 404) {
|
||||
// User likely deleted the secret before the env var, so we can still report success
|
||||
output.debug(
|
||||
`Skipped ${env.key} because secret ${idOrName} was already deleted`
|
||||
);
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Since integrations add global secrets, we must only delete if the secret was
|
||||
// specifically added to this project
|
||||
if (secret && secret.projectId === projectId) {
|
||||
await client.fetch<Secret>(urlSecret, { method: 'DELETE' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
32
packages/now-cli/src/util/env/system-env.ts
vendored
@@ -1,32 +0,0 @@
|
||||
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',
|
||||
];
|
||||
@@ -1,52 +1,65 @@
|
||||
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, ProjectEnvType } from '../types';
|
||||
|
||||
import { Env } from '@vercel/build-utils';
|
||||
import {
|
||||
ProjectEnvTarget,
|
||||
ProjectEnvType,
|
||||
ProjectEnvVariable,
|
||||
Secret,
|
||||
} from '../types';
|
||||
import getEnvRecords from './env/get-env-records';
|
||||
|
||||
export default async function getDecryptedEnvRecords(
|
||||
output: Output,
|
||||
client: Client,
|
||||
project: Project,
|
||||
target: ProjectEnvTarget
|
||||
): Promise<Env> {
|
||||
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 };
|
||||
projectId: string
|
||||
): Promise<{ envs: ProjectEnvVariable[] }> {
|
||||
const { envs } = await getEnvRecords(
|
||||
output,
|
||||
client,
|
||||
projectId,
|
||||
ProjectEnvTarget.Development
|
||||
);
|
||||
|
||||
const envsWithDecryptedSecrets = await Promise.all(
|
||||
envs.map(async ({ type, key, value }) => {
|
||||
// it's not possible to create secret env variables for development
|
||||
// anymore but we keep this because legacy env variables with "decryptable"
|
||||
// secret values still exit in our system
|
||||
if (type === ProjectEnvType.Secret) {
|
||||
try {
|
||||
const secretIdOrName = value;
|
||||
|
||||
if (!secretIdOrName) {
|
||||
return { type, key, value: '', found: true };
|
||||
}
|
||||
|
||||
output.debug(`Fetching decrypted secret ${secretIdOrName}`);
|
||||
const secret = await client.fetch<Secret>(
|
||||
`/v2/now/secrets/${secretIdOrName}?decrypt=true`
|
||||
);
|
||||
|
||||
return { type, key, value: secret.value, found: true };
|
||||
} catch (error) {
|
||||
if (error && error.status === 404) {
|
||||
return { type, key, value: '', found: false };
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const value = await getDecryptedSecret(output, client, env.value);
|
||||
return { value, found: true };
|
||||
} catch (error) {
|
||||
if (error && error.status === 404) {
|
||||
return { value: '', found: false };
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return { type, key, value, found: true };
|
||||
})
|
||||
);
|
||||
|
||||
const results: Env = {};
|
||||
for (let i = 0; i < decryptedValues.length; i++) {
|
||||
const { key } = envs[i];
|
||||
const { value, found } = decryptedValues[i];
|
||||
|
||||
if (!found) {
|
||||
for (let env of envsWithDecryptedSecrets) {
|
||||
if (!env.found) {
|
||||
output.print('');
|
||||
output.warn(
|
||||
`Unable to download variable ${key} because associated secret was deleted`
|
||||
`Unable to download variable ${env.key} because associated secret was deleted`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
results[key] = value ? value : '';
|
||||
}
|
||||
return results;
|
||||
|
||||
return { envs: envsWithDecryptedSecrets };
|
||||
}
|
||||
|
||||
4
packages/now-cli/test/dev/fixtures/30-next-image-optimization/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.next
|
||||
!public
|
||||
yarn.lock
|
||||
.vercel
|
||||
@@ -1,10 +1,12 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "canary",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import Image from 'next/image';
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<h1>Home Page</h1>
|
||||
<hr />
|
||||
<h2>Optimized</h2>
|
||||
<Image src="/test.png" width="400" height="400" />
|
||||
<hr />
|
||||
<h2>Original</h2>
|
||||
<img src="/test.png" width="400" height="400" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="400.000000pt" height="400.000000pt" viewBox="0 0 400.000000 400.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<g transform="translate(0.000000,400.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M0 2000 l0 -2000 2000 0 2000 0 0 2000 0 2000 -2000 0 -2000 0 0
|
||||
-2000z m2401 118 l396 -693 -398 -3 c-220 -1 -578 -1 -798 0 l-398 3 396 693
|
||||
c217 380 398 692 401 692 3 0 184 -312 401 -692z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 635 B |
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"version": 2,
|
||||
"build": {
|
||||
"env": {
|
||||
"FORCE_BUILDER_TAG": "canary"
|
||||
}
|
||||
}
|
||||
}
|
||||
4
packages/now-cli/test/dev/fixtures/missing-src-property/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
package.json
|
||||
yarn.lock
|
||||
.now
|
||||
.vercel
|
||||
@@ -0,0 +1 @@
|
||||
hello:index.txt
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"builds": [
|
||||
{
|
||||
"use": "@vercel/static"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -128,14 +128,13 @@ async function testPath(
|
||||
status,
|
||||
path,
|
||||
expectedText,
|
||||
headers = {},
|
||||
method = 'GET',
|
||||
body = undefined
|
||||
expectedHeaders = {},
|
||||
fetchOpts = {}
|
||||
) {
|
||||
const opts = { redirect: 'manual-dont-change', method, body };
|
||||
const opts = { ...fetchOpts, redirect: 'manual-dont-change' };
|
||||
const url = `${origin}${path}`;
|
||||
const res = await fetch(url, opts);
|
||||
const msg = `Testing response from ${method} ${url}`;
|
||||
const msg = `Testing response from ${fetchOpts.method || 'GET'} ${url}`;
|
||||
console.log(msg);
|
||||
t.is(res.status, status, msg);
|
||||
validateResponseHeaders(t, res);
|
||||
@@ -150,8 +149,8 @@ async function testPath(
|
||||
expectedText.lastIndex = 0; // reset since we test twice
|
||||
t.regex(actualText, expectedText);
|
||||
}
|
||||
if (headers) {
|
||||
Object.entries(headers).forEach(([key, expectedValue]) => {
|
||||
if (expectedHeaders) {
|
||||
Object.entries(expectedHeaders).forEach(([key, expectedValue]) => {
|
||||
let actualValue = res.headers.get(key);
|
||||
if (key.toLowerCase() === 'location' && actualValue === '//') {
|
||||
// HACK: `node-fetch` has strange behavior for location header so fix it
|
||||
@@ -233,7 +232,7 @@ async function testFixture(directory, opts = {}, args = []) {
|
||||
function testFixtureStdio(
|
||||
directory,
|
||||
fn,
|
||||
{ expectedCode = 0, skipDeploy, isExample } = {}
|
||||
{ expectedCode = 0, skipDeploy, isExample, projectSettings } = {}
|
||||
) {
|
||||
return async t => {
|
||||
const nodeMajor = Number(process.versions.node.split('.')[0]);
|
||||
@@ -250,24 +249,51 @@ function testFixtureStdio(
|
||||
|
||||
// Deploy fixture and link project
|
||||
if (!skipDeploy) {
|
||||
const project = join(cwd, '.vercel', 'project.json');
|
||||
if (await fs.exists(project)) {
|
||||
await fs.unlink(project);
|
||||
}
|
||||
const projectJsonPath = join(cwd, '.vercel', 'project.json');
|
||||
await fs.remove(projectJsonPath);
|
||||
const gitignore = join(cwd, '.gitignore');
|
||||
const gitignoreOrig = await fs.exists(gitignore);
|
||||
let { stdout, stderr, exitCode } = await execa(
|
||||
binaryPath,
|
||||
['-t', token, '--confirm', '--public', '--no-clipboard', '--debug'],
|
||||
{ cwd, reject: false }
|
||||
);
|
||||
console.log({ stdout, stderr, exitCode });
|
||||
if (!gitignoreOrig && (await fs.exists(gitignore))) {
|
||||
await fs.unlink(gitignore);
|
||||
}
|
||||
t.is(exitCode, expectedCode);
|
||||
if (expectedCode === 0) {
|
||||
deploymentUrl = new URL(stdout).host;
|
||||
const hasGitignore = await fs.exists(gitignore);
|
||||
|
||||
try {
|
||||
// Run `vc link`
|
||||
const { exitCode: linkExitCode } = await execa(
|
||||
binaryPath,
|
||||
['-t', token, 'link', '--confirm'],
|
||||
{ cwd, stdio: 'inherit', reject: false }
|
||||
);
|
||||
t.is(linkExitCode, 0);
|
||||
|
||||
// Patch the project with any non-default properties
|
||||
if (projectSettings) {
|
||||
const { projectId } = await fs.readJson(projectJsonPath);
|
||||
const res = await fetch(
|
||||
`https://api.vercel.com/v2/projects/${projectId}`,
|
||||
{
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify(projectSettings),
|
||||
}
|
||||
);
|
||||
t.is(res.status, 200);
|
||||
}
|
||||
|
||||
// Run `vc deploy`
|
||||
let { exitCode, stdout } = await execa(
|
||||
binaryPath,
|
||||
['-t', token, 'deploy', '--public', '--no-clipboard', '--debug'],
|
||||
{ cwd, stdio: ['ignore', 'pipe', 'inherit'], reject: false }
|
||||
);
|
||||
console.log({ exitCode, stdout });
|
||||
t.is(exitCode, expectedCode);
|
||||
if (expectedCode === 0) {
|
||||
deploymentUrl = new URL(stdout).host;
|
||||
}
|
||||
} finally {
|
||||
if (!hasGitignore) {
|
||||
await fs.remove(gitignore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,9 +413,12 @@ test(
|
||||
async testPath => {
|
||||
await testPath(200, '/', /<div id="redwood-app">/m);
|
||||
await testPath(200, '/about', /<div id="redwood-app">/m);
|
||||
const reqBody = '{"query":"{redwood{version}}"}';
|
||||
const fetchOpts = {
|
||||
method: 'POST',
|
||||
body: '{"query":"{redwood{version}}"}',
|
||||
};
|
||||
const resBody = '{"data":{"redwood":{"version":"0.15.0"}}}';
|
||||
await testPath(200, '/api/graphql', resBody, {}, 'POST', reqBody);
|
||||
await testPath(200, '/api/graphql', resBody, {}, fetchOpts);
|
||||
},
|
||||
{ isExample: true }
|
||||
)
|
||||
@@ -620,14 +649,6 @@ test(
|
||||
});
|
||||
})
|
||||
);
|
||||
/*
|
||||
test(
|
||||
'[vercel dev] displays directory listing after miss',
|
||||
testFixtureStdio('handle-miss-display-dir-list', async (testPath) => {
|
||||
await testPath(404, '/post', /one.html/m);
|
||||
})
|
||||
);
|
||||
*/
|
||||
|
||||
test(
|
||||
'[vercel dev] does not display directory listing after 404',
|
||||
@@ -945,12 +966,16 @@ test(
|
||||
'Access-Control-Allow-Methods':
|
||||
'GET, POST, OPTIONS, HEAD, PATCH, PUT, DELETE',
|
||||
};
|
||||
await testPath(200, '/', 'status api', headers, 'GET');
|
||||
await testPath(200, '/', 'status api', headers, 'POST');
|
||||
await testPath(200, '/api/status.js', 'status api', headers, 'GET');
|
||||
await testPath(200, '/api/status.js', 'status api', headers, 'POST');
|
||||
await testPath(204, '/', '', headers, 'OPTIONS');
|
||||
await testPath(204, '/api/status.js', '', headers, 'OPTIONS');
|
||||
await testPath(200, '/', 'status api', headers, { method: 'GET' });
|
||||
await testPath(200, '/', 'status api', headers, { method: 'POST' });
|
||||
await testPath(200, '/api/status.js', 'status api', headers, {
|
||||
method: 'GET',
|
||||
});
|
||||
await testPath(200, '/api/status.js', 'status api', headers, {
|
||||
method: 'POST',
|
||||
});
|
||||
await testPath(204, '/', '', headers, { method: 'OPTIONS' });
|
||||
await testPath(204, '/api/status.js', '', headers, { method: 'OPTIONS' });
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1050,12 +1075,16 @@ test(
|
||||
|
||||
test(
|
||||
'[vercel dev] 00-list-directory',
|
||||
testFixtureStdio('00-list-directory', async testPath => {
|
||||
await testPath(200, '/', /Files within/m);
|
||||
await testPath(200, '/', /test[0-3]\.txt/m);
|
||||
await testPath(200, '/', /\.well-known/m);
|
||||
await testPath(200, '/.well-known/keybase.txt', 'proof goes here');
|
||||
})
|
||||
testFixtureStdio(
|
||||
'00-list-directory',
|
||||
async testPath => {
|
||||
await testPath(200, '/', /Files within/m);
|
||||
await testPath(200, '/', /test[0-3]\.txt/m);
|
||||
await testPath(200, '/', /\.well-known/m);
|
||||
await testPath(200, '/.well-known/keybase.txt', 'proof goes here');
|
||||
},
|
||||
{ projectSettings: { directoryListing: true } }
|
||||
)
|
||||
);
|
||||
|
||||
test(
|
||||
@@ -1595,6 +1624,61 @@ test(
|
||||
})
|
||||
);
|
||||
|
||||
test(
|
||||
'[vercel dev] 30-next-image-optimization',
|
||||
testFixtureStdio('30-next-image-optimization', async testPath => {
|
||||
const toUrl = (url, w, q) => {
|
||||
const query = new URLSearchParams();
|
||||
query.append('url', url);
|
||||
query.append('w', w);
|
||||
query.append('q', q);
|
||||
return `/_next/image?${query}`;
|
||||
};
|
||||
|
||||
const expectHeader = accept => ({
|
||||
'content-type': accept,
|
||||
'cache-control': 'public, max-age=0, must-revalidate',
|
||||
});
|
||||
const fetchOpts = accept => ({ method: 'GET', headers: { accept } });
|
||||
await testPath(200, '/', /Home Page/m);
|
||||
await testPath(
|
||||
200,
|
||||
toUrl('/test.jpg', 64, 100),
|
||||
null,
|
||||
expectHeader('image/webp'),
|
||||
fetchOpts('image/webp')
|
||||
);
|
||||
await testPath(
|
||||
200,
|
||||
toUrl('/test.png', 64, 90),
|
||||
null,
|
||||
expectHeader('image/webp'),
|
||||
fetchOpts('image/webp')
|
||||
);
|
||||
await testPath(
|
||||
200,
|
||||
toUrl('/test.gif', 64, 80),
|
||||
null,
|
||||
expectHeader('image/webp'),
|
||||
fetchOpts('image/webp')
|
||||
);
|
||||
await testPath(
|
||||
200,
|
||||
toUrl('/test.svg', 64, 70),
|
||||
null,
|
||||
expectHeader('image/svg+xml'),
|
||||
fetchOpts('image/webp')
|
||||
);
|
||||
await testPath(
|
||||
200,
|
||||
toUrl('/animated.gif', 64, 60),
|
||||
null,
|
||||
expectHeader('image/gif'),
|
||||
fetchOpts('image/gif')
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
test(
|
||||
'[vercel dev] Use `@vercel/python` with Flask requirements.txt',
|
||||
testFixtureStdio('python-flask', async testPath => {
|
||||
@@ -1695,3 +1779,11 @@ test(
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
test(
|
||||
'[vercel dev] Do not fail if `src` is missing',
|
||||
testFixtureStdio('missing-src-property', async testPath => {
|
||||
await testPath(200, '/', /hello:index.txt/m);
|
||||
await testPath(404, '/i-do-not-exist');
|
||||
})
|
||||
);
|
||||
|
||||
210
packages/now-cli/test/integration.js
vendored
@@ -539,7 +539,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
async function nowEnvAddSystemEnv() {
|
||||
const now = execa(
|
||||
binaryPath,
|
||||
['env', 'add', 'system', 'VERCEL_URL', ...defaultArgs],
|
||||
['env', 'add', 'system', 'NEXT_PUBLIC_VERCEL_URL', ...defaultArgs],
|
||||
{
|
||||
reject: false,
|
||||
cwd: target,
|
||||
@@ -602,6 +602,41 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
t.regex(systemEnvs[0], /Production, Preview, Development/gm);
|
||||
}
|
||||
|
||||
// we create a "legacy" env variable that contains a decryptable secret
|
||||
// to check that vc env pull and vc dev work correctly with decryptable secrets
|
||||
async function createEnvWithDecryptableSecret() {
|
||||
console.log('creating an env variable with a decryptable secret');
|
||||
|
||||
const name = `my-secret${Math.floor(Math.random() * 10000)}`;
|
||||
|
||||
const res = await apiFetch('/v2/now/secrets', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
value: 'decryptable value',
|
||||
decryptable: true,
|
||||
}),
|
||||
});
|
||||
|
||||
t.is(res.status, 200);
|
||||
|
||||
const json = await res.json();
|
||||
|
||||
const link = require(path.join(target, '.vercel/project.json'));
|
||||
|
||||
const resEnv = await apiFetch(`/v4/projects/${link.projectId}/env`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
key: 'MY_DECRYPTABLE_SECRET_ENV',
|
||||
value: json.uid,
|
||||
target: ['development'],
|
||||
type: 'secret',
|
||||
}),
|
||||
});
|
||||
|
||||
t.is(resEnv.status, 200);
|
||||
}
|
||||
|
||||
async function nowEnvPull() {
|
||||
const { exitCode, stderr, stdout } = await execa(
|
||||
binaryPath,
|
||||
@@ -621,7 +656,8 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
const lines = new Set(contents.split('\n'));
|
||||
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=""'));
|
||||
t.true(lines.has('NEXT_PUBLIC_VERCEL_URL=""'));
|
||||
t.true(lines.has('MY_DECRYPTABLE_SECRET_ENV="decryptable value"'));
|
||||
}
|
||||
|
||||
async function nowEnvPullOverwrite() {
|
||||
@@ -675,7 +711,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
const apiJson = await apiRes.json();
|
||||
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);
|
||||
t.is(apiJson['NEXT_PUBLIC_VERCEL_URL'], host);
|
||||
|
||||
const homeUrl = `https://${host}`;
|
||||
console.log({ homeUrl });
|
||||
@@ -684,7 +720,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
const homeJson = await homeRes.json();
|
||||
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);
|
||||
t.is(homeJson['NEXT_PUBLIC_VERCEL_URL'], host);
|
||||
}
|
||||
|
||||
async function nowDevWithEnv() {
|
||||
@@ -702,8 +738,6 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
return false;
|
||||
});
|
||||
|
||||
const localhostNoProtocol = localhost[0].slice('http://'.length);
|
||||
|
||||
const apiUrl = `${localhost[0]}/api/get-env`;
|
||||
const apiRes = await fetch(apiUrl);
|
||||
|
||||
@@ -712,14 +746,16 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
const apiJson = await apiRes.json();
|
||||
|
||||
t.is(apiJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
|
||||
t.is(apiJson['VERCEL_URL'], localhostNoProtocol);
|
||||
t.is(apiJson['NEXT_PUBLIC_VERCEL_URL'], '');
|
||||
t.is(apiJson['MY_DECRYPTABLE_SECRET_ENV'], 'decryptable value');
|
||||
|
||||
const homeUrl = localhost[0];
|
||||
|
||||
const homeRes = await fetch(homeUrl);
|
||||
const homeJson = await homeRes.json();
|
||||
t.is(homeJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
|
||||
t.is(homeJson['VERCEL_URL'], localhostNoProtocol);
|
||||
t.is(homeJson['NEXT_PUBLIC_VERCEL_URL'], '');
|
||||
t.is(homeJson['MY_DECRYPTABLE_SECRET_ENV'], 'decryptable value');
|
||||
|
||||
vc.kill('SIGTERM', { forceKillAfterTimeout: 2000 });
|
||||
|
||||
@@ -751,16 +787,105 @@ 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['NEXT_PUBLIC_VERCEL_URL'], localhostNoProtocol);
|
||||
t.is(apiJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
|
||||
t.is(apiJson['MY_STDIN_VAR'], '{"expect":"quotes"}');
|
||||
t.is(apiJson['MY_DECRYPTABLE_SECRET_ENV'], 'decryptable value');
|
||||
|
||||
const homeUrl = localhost[0];
|
||||
const homeRes = await fetch(homeUrl);
|
||||
const homeJson = await homeRes.json();
|
||||
t.is(homeJson['MY_PLAINTEXT_ENV_VAR'], 'my plaintext value');
|
||||
t.is(homeJson['VERCEL_URL'], localhostNoProtocol);
|
||||
t.is(homeJson['NEXT_PUBLIC_VERCEL_URL'], localhostNoProtocol);
|
||||
t.is(homeJson['MY_STDIN_VAR'], '{"expect":"quotes"}');
|
||||
t.is(homeJson['MY_DECRYPTABLE_SECRET_ENV'], 'decryptable value');
|
||||
|
||||
// system env vars are automatically exposed
|
||||
t.is(apiJson['VERCEL'], '1');
|
||||
t.is(homeJson['VERCEL'], '1');
|
||||
|
||||
vc.kill('SIGTERM', { forceKillAfterTimeout: 2000 });
|
||||
|
||||
const { exitCode, stderr, stdout } = await vc;
|
||||
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
|
||||
}
|
||||
|
||||
async function enableAutoExposeSystemEnvs() {
|
||||
const link = require(path.join(target, '.vercel/project.json'));
|
||||
|
||||
const res = await apiFetch(`/v2/projects/${link.projectId}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify({ autoExposeSystemEnvs: true }),
|
||||
});
|
||||
|
||||
t.is(res.status, 200);
|
||||
if (res.status === 200) {
|
||||
console.log(
|
||||
`Set autoExposeSystemEnvs=true for project ${link.projectId}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function nowEnvPullFetchSystemVars() {
|
||||
const { exitCode, stderr, stdout } = await execa(
|
||||
binaryPath,
|
||||
['env', 'pull', '-y', ...defaultArgs],
|
||||
{
|
||||
reject: false,
|
||||
cwd: target,
|
||||
}
|
||||
);
|
||||
|
||||
t.is(exitCode, 0, formatOutput({ stderr, stdout }));
|
||||
|
||||
const contents = fs.readFileSync(path.join(target, '.env'), 'utf8');
|
||||
|
||||
const lines = new Set(contents.split('\n'));
|
||||
t.true(lines.has('VERCEL="1"'));
|
||||
t.true(lines.has('VERCEL_URL=""'));
|
||||
t.true(lines.has('NEXT_PUBLIC_VERCEL_URL=""'));
|
||||
t.true(lines.has('VERCEL_ENV="development"'));
|
||||
t.true(lines.has('VERCEL_GIT_PROVIDER=""'));
|
||||
t.true(lines.has('VERCEL_GIT_REPO_SLUG=""'));
|
||||
}
|
||||
|
||||
async function nowDevAndFetchSystemVars() {
|
||||
const vc = execa(binaryPath, ['dev', ...defaultArgs], {
|
||||
reject: false,
|
||||
cwd: target,
|
||||
});
|
||||
|
||||
let localhost = undefined;
|
||||
await waitForPrompt(vc, chunk => {
|
||||
if (chunk.includes('Ready! Available at')) {
|
||||
localhost = /(https?:[^\s]+)/g.exec(chunk);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
const apiUrl = `${localhost[0]}/api/get-env`;
|
||||
const apiRes = await fetch(apiUrl);
|
||||
|
||||
const localhostNoProtocol = localhost[0].slice('http://'.length);
|
||||
|
||||
const apiJson = await apiRes.json();
|
||||
t.is(apiJson['VERCEL'], '1');
|
||||
t.is(apiJson['VERCEL_URL'], localhostNoProtocol);
|
||||
t.is(apiJson['VERCEL_ENV'], 'development');
|
||||
t.is(apiJson['VERCEL_REGION'], 'dev1');
|
||||
t.is(apiJson['VERCEL_GIT_PROVIDER'], '');
|
||||
t.is(apiJson['VERCEL_GIT_REPO_SLUG'], '');
|
||||
|
||||
const homeUrl = localhost[0];
|
||||
const homeRes = await fetch(homeUrl);
|
||||
const homeJson = await homeRes.json();
|
||||
t.is(homeJson['VERCEL'], '1');
|
||||
t.is(homeJson['VERCEL_URL'], localhostNoProtocol);
|
||||
t.is(homeJson['VERCEL_ENV'], 'development');
|
||||
t.is(homeJson['VERCEL_REGION'], undefined);
|
||||
t.is(homeJson['VERCEL_GIT_PROVIDER'], '');
|
||||
t.is(homeJson['VERCEL_GIT_REPO_SLUG'], '');
|
||||
|
||||
vc.kill('SIGTERM', { forceKillAfterTimeout: 2000 });
|
||||
|
||||
@@ -831,12 +956,34 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
);
|
||||
|
||||
t.is(exitCode2, 0, formatOutput({ stderr2, stdout2 }));
|
||||
|
||||
const {
|
||||
exitCode: exitCode3,
|
||||
stderr: stderr3,
|
||||
stdout: stdout3,
|
||||
} = await execa(
|
||||
binaryPath,
|
||||
[
|
||||
'env',
|
||||
'rm',
|
||||
'MY_DECRYPTABLE_SECRET_ENV',
|
||||
'development',
|
||||
'-y',
|
||||
...defaultArgs,
|
||||
],
|
||||
{
|
||||
reject: false,
|
||||
cwd: target,
|
||||
}
|
||||
);
|
||||
|
||||
t.is(exitCode3, 0, formatOutput({ stderr3, stdout3 }));
|
||||
}
|
||||
|
||||
async function nowEnvRemoveWithNameOnly() {
|
||||
const vc = execa(
|
||||
binaryPath,
|
||||
['env', 'rm', 'VERCEL_URL', '-y', ...defaultArgs],
|
||||
['env', 'rm', 'NEXT_PUBLIC_VERCEL_URL', '-y', ...defaultArgs],
|
||||
{
|
||||
reject: false,
|
||||
cwd: target,
|
||||
@@ -846,7 +993,8 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
await waitForPrompt(
|
||||
vc,
|
||||
chunk =>
|
||||
chunk.includes('which Environments') && chunk.includes('VERCEL_URL')
|
||||
chunk.includes('which Environments') &&
|
||||
chunk.includes('NEXT_PUBLIC_VERCEL_URL')
|
||||
);
|
||||
vc.stdin.write('a\n'); // select all
|
||||
|
||||
@@ -862,6 +1010,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
await nowEnvAddFromStdin();
|
||||
await nowEnvAddSystemEnv();
|
||||
await nowEnvLsIncludesVar();
|
||||
await createEnvWithDecryptableSecret();
|
||||
await nowEnvPull();
|
||||
await nowEnvPullOverwrite();
|
||||
await nowEnvPullConfirm();
|
||||
@@ -869,6 +1018,10 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
|
||||
await nowDevWithEnv();
|
||||
fs.unlinkSync(path.join(target, '.env'));
|
||||
await nowDevAndFetchCloudVars();
|
||||
await enableAutoExposeSystemEnvs();
|
||||
await nowEnvPullFetchSystemVars();
|
||||
fs.unlinkSync(path.join(target, '.env'));
|
||||
await nowDevAndFetchSystemVars();
|
||||
await nowEnvRemove();
|
||||
await nowEnvRemoveWithArgs();
|
||||
await nowEnvRemoveWithNameOnly();
|
||||
@@ -1413,7 +1566,7 @@ test('ensure we render a warning for deployments with no files', async t => {
|
||||
t.is(res.status, 404);
|
||||
});
|
||||
|
||||
test('output logs of a 2.0 deployment', async t => {
|
||||
test('output logs with "short" output', async t => {
|
||||
const { stderr, stdout, exitCode } = await execa(
|
||||
binaryPath,
|
||||
['logs', context.deployment, ...defaultArgs],
|
||||
@@ -1430,13 +1583,21 @@ test('output logs of a 2.0 deployment', async t => {
|
||||
stderr.includes(`Fetched deployment "${context.deployment}"`),
|
||||
formatOutput({ stderr, stdout })
|
||||
);
|
||||
|
||||
// "short" format includes timestamps
|
||||
t.truthy(
|
||||
stdout.match(
|
||||
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/
|
||||
)
|
||||
);
|
||||
|
||||
t.is(exitCode, 0);
|
||||
});
|
||||
|
||||
test('output logs of a 2.0 deployment without annotate', async t => {
|
||||
test('output logs with "raw" output', async t => {
|
||||
const { stderr, stdout, exitCode } = await execa(
|
||||
binaryPath,
|
||||
['logs', context.deployment, ...defaultArgs],
|
||||
['logs', context.deployment, ...defaultArgs, '--output', 'raw'],
|
||||
{
|
||||
reject: false,
|
||||
}
|
||||
@@ -1446,12 +1607,19 @@ test('output logs of a 2.0 deployment without annotate', async t => {
|
||||
console.log(stdout);
|
||||
console.log(exitCode);
|
||||
|
||||
t.true(!stderr.includes('[now-builder-debug]'));
|
||||
t.true(!stderr.includes('START RequestId'));
|
||||
t.true(!stderr.includes('END RequestId'));
|
||||
t.true(!stderr.includes('REPORT RequestId'));
|
||||
t.true(!stderr.includes('Init Duration'));
|
||||
t.true(!stderr.includes('XRAY TraceId'));
|
||||
t.true(
|
||||
stderr.includes(`Fetched deployment "${context.deployment}"`),
|
||||
formatOutput({ stderr, stdout })
|
||||
);
|
||||
|
||||
// "raw" format does not include timestamps
|
||||
t.is(
|
||||
null,
|
||||
stdout.match(
|
||||
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/
|
||||
)
|
||||
);
|
||||
|
||||
t.is(exitCode, 0);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/client",
|
||||
"version": "9.0.4",
|
||||
"version": "9.0.5",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"homepage": "https://vercel.com",
|
||||
@@ -37,7 +37,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.6.0",
|
||||
"@vercel/build-utils": "2.7.0",
|
||||
"@zeit/fetch": "5.2.0",
|
||||
"async-retry": "1.2.3",
|
||||
"async-sema": "3.0.0",
|
||||
|
||||
@@ -285,8 +285,8 @@ Learn more: https://vercel.com/docs/runtimes#official-runtimes/go
|
||||
}
|
||||
|
||||
const mainModGoContents = modMainGoContents
|
||||
.replace('__NOW_HANDLER_PACKAGE_NAME', goPackageName)
|
||||
.replace('__NOW_HANDLER_FUNC_NAME', goFuncName);
|
||||
.replace('__VC_HANDLER_PACKAGE_NAME', goPackageName)
|
||||
.replace('__VC_HANDLER_FUNC_NAME', goFuncName);
|
||||
|
||||
if (isGoModExist && isGoModInRootDir) {
|
||||
debug('[mod-root] Write main file to ' + downloadPath);
|
||||
@@ -405,13 +405,13 @@ Learn more: https://vercel.com/docs/runtimes#official-runtimes/go
|
||||
'utf8'
|
||||
);
|
||||
const mainGoContents = origianlMainGoContents.replace(
|
||||
'__NOW_HANDLER_FUNC_NAME',
|
||||
'__VC_HANDLER_FUNC_NAME',
|
||||
handlerFunctionName
|
||||
);
|
||||
|
||||
// in order to allow the user to have `main.go`,
|
||||
// we need our `main.go` to be called something else
|
||||
const mainGoFileName = 'main__now__go__.go';
|
||||
const mainGoFileName = 'main__vc__go__.go';
|
||||
|
||||
// Go doesn't like to build files in different directories,
|
||||
// so now we place `main.go` together with the user code
|
||||
@@ -580,9 +580,9 @@ Learn more: https://vercel.com/docs/runtimes#official-runtimes/go`
|
||||
};
|
||||
} else if (Array.isArray(result)) {
|
||||
// Got "exit" event from child process
|
||||
throw new Error(
|
||||
`Failed to start dev server for "${entrypointWithExt}" (code=${result[0]}, signal=${result[1]})`
|
||||
);
|
||||
const [exitCode, signal] = result;
|
||||
const reason = signal ? `"${signal}" signal` : `exit code ${exitCode}`;
|
||||
throw new Error(`\`go run ${entrypointWithExt}\` failed with ${reason}`);
|
||||
} else {
|
||||
throw new Error(`Unexpected result type: ${typeof result}`);
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
vc.Start(http.HandlerFunc(__NOW_HANDLER_FUNC_NAME))
|
||||
vc.Start(http.HandlerFunc(__VC_HANDLER_FUNC_NAME))
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"__NOW_HANDLER_PACKAGE_NAME"
|
||||
"__VC_HANDLER_PACKAGE_NAME"
|
||||
"net/http"
|
||||
|
||||
vc "github.com/vercel/go-bridge/go/bridge"
|
||||
)
|
||||
|
||||
func main() {
|
||||
vc.Start(http.HandlerFunc(__NOW_HANDLER_FUNC_NAME))
|
||||
vc.Start(http.HandlerFunc(__VC_HANDLER_FUNC_NAME))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/go",
|
||||
"version": "1.1.6",
|
||||
"version": "1.1.7",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
||||
|
||||
2
packages/now-next/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
/dist
|
||||
/src/now__bridge.ts
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
bridge_defs="$(dirname $(pwd))/now-node-bridge/src/bridge.ts"
|
||||
|
||||
cp -v "$bridge_defs" src/now__bridge.ts
|
||||
|
||||
tsc
|
||||
|
||||
ncc build src/dev-server.ts -e @vercel/build-utils -e @now/build-utils -o dist/dev
|
||||
mv dist/dev/index.js dist/dev-server.js
|
||||
rm -rf dist/dev
|
||||
|
||||
ncc build src/index.ts -e @vercel/build-utils -e @now/build-utils -o dist/main
|
||||
mv dist/main/index.js dist/index.js
|
||||
rm -rf dist/main
|
||||
@@ -1,43 +0,0 @@
|
||||
{
|
||||
"name": "@vercel/next",
|
||||
"version": "2.7.0",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
|
||||
"scripts": {
|
||||
"build": "./build.sh",
|
||||
"test-integration-once": "jest --env node --verbose --runInBand --bail",
|
||||
"prepublishOnly": "./build.sh"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vercel/vercel.git",
|
||||
"directory": "packages/now-next"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/aws-lambda": "8.10.19",
|
||||
"@types/buffer-crc32": "0.2.0",
|
||||
"@types/find-up": "4.0.0",
|
||||
"@types/fs-extra": "8.0.0",
|
||||
"@types/next-server": "8.0.0",
|
||||
"@types/resolve-from": "5.0.1",
|
||||
"@types/semver": "6.0.0",
|
||||
"@types/yazl": "2.4.1",
|
||||
"@vercel/nft": "0.9.2",
|
||||
"async-sema": "3.0.1",
|
||||
"buffer-crc32": "0.2.13",
|
||||
"escape-string-regexp": "2.0.0",
|
||||
"execa": "2.0.4",
|
||||
"find-up": "4.1.0",
|
||||
"fs-extra": "7.0.0",
|
||||
"get-port": "5.0.0",
|
||||
"resolve-from": "5.0.0",
|
||||
"semver": "6.1.1",
|
||||
"set-cookie-parser": "2.4.6",
|
||||
"typescript": "3.9.3",
|
||||
"yazl": "https://github.com/ijjk/yazl#70949c55b482647669ce37023017b1514c42b33c"
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
let buildUtils: typeof import('@vercel/build-utils');
|
||||
|
||||
try {
|
||||
buildUtils = require('@vercel/build-utils');
|
||||
} catch (e) {
|
||||
// Fallback for older CLI versions
|
||||
buildUtils = require('@now/build-utils');
|
||||
}
|
||||
|
||||
export default buildUtils;
|
||||
@@ -1,90 +0,0 @@
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import semver from 'semver';
|
||||
|
||||
import { ExperimentalTraceVersion } from './utils';
|
||||
|
||||
function getCustomData(importName: string, target: string) {
|
||||
return `
|
||||
module.exports = function(...args) {
|
||||
let original = require('./${importName}');
|
||||
|
||||
const finalConfig = {};
|
||||
const target = { target: '${target}' };
|
||||
|
||||
if (typeof original === 'function' && original.constructor.name === 'AsyncFunction') {
|
||||
// AsyncFunctions will become promises
|
||||
original = original(...args);
|
||||
}
|
||||
|
||||
if (original instanceof Promise) {
|
||||
// Special case for promises, as it's currently not supported
|
||||
// and will just error later on
|
||||
return original
|
||||
.then((orignalConfig) => Object.assign(finalConfig, orignalConfig))
|
||||
.then((config) => Object.assign(config, target));
|
||||
} else if (typeof original === 'function') {
|
||||
Object.assign(finalConfig, original(...args));
|
||||
} else if (typeof original === 'object') {
|
||||
Object.assign(finalConfig, original);
|
||||
}
|
||||
|
||||
Object.assign(finalConfig, target);
|
||||
|
||||
return finalConfig;
|
||||
}
|
||||
`.trim();
|
||||
}
|
||||
|
||||
function getDefaultData(target: string) {
|
||||
return `module.exports = { target: '${target}' };`;
|
||||
}
|
||||
|
||||
export default async function createServerlessConfig(
|
||||
workPath: string,
|
||||
entryPath: string,
|
||||
nextVersion: string | undefined
|
||||
) {
|
||||
let target = 'serverless';
|
||||
if (nextVersion) {
|
||||
try {
|
||||
if (semver.gte(nextVersion, ExperimentalTraceVersion)) {
|
||||
target = 'experimental-serverless-trace';
|
||||
}
|
||||
} catch (
|
||||
_ignored
|
||||
// eslint-disable-next-line
|
||||
) {}
|
||||
}
|
||||
|
||||
const primaryConfigPath = path.join(entryPath, 'next.config.js');
|
||||
const secondaryConfigPath = path.join(workPath, 'next.config.js');
|
||||
const backupConfigName = `next.config.__vercel_builder_backup__.js`;
|
||||
|
||||
const hasPrimaryConfig = fs.existsSync(primaryConfigPath);
|
||||
const hasSecondaryConfig = fs.existsSync(secondaryConfigPath);
|
||||
|
||||
let configPath: string;
|
||||
let backupConfigPath: string;
|
||||
|
||||
if (hasPrimaryConfig) {
|
||||
// Prefer primary path
|
||||
configPath = primaryConfigPath;
|
||||
backupConfigPath = path.join(entryPath, backupConfigName);
|
||||
} else if (hasSecondaryConfig) {
|
||||
// Work with secondary path (some monorepo setups)
|
||||
configPath = secondaryConfigPath;
|
||||
backupConfigPath = path.join(workPath, backupConfigName);
|
||||
} else {
|
||||
// Default to primary path for creation
|
||||
configPath = primaryConfigPath;
|
||||
backupConfigPath = path.join(entryPath, backupConfigName);
|
||||
}
|
||||
|
||||
if (fs.existsSync(configPath)) {
|
||||
await fs.rename(configPath, backupConfigPath);
|
||||
await fs.writeFile(configPath, getCustomData(backupConfigName, target));
|
||||
} else {
|
||||
await fs.writeFile(configPath, getDefaultData(target));
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import resolveFrom from 'resolve-from';
|
||||
import { parse } from 'url';
|
||||
import getPort from 'get-port';
|
||||
import { createServer } from 'http';
|
||||
import { syncEnvVars } from './utils';
|
||||
|
||||
process.on('unhandledRejection', err => {
|
||||
console.error('Exiting builder due to build error:');
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
process.once('message', async ({ dir, runtimeEnv }) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const next = require(resolveFrom(dir, 'next'));
|
||||
const app = next({ dev: true, dir });
|
||||
const handler = app.getRequestHandler();
|
||||
|
||||
const [openPort] = await Promise.all([getPort(), app.prepare()]);
|
||||
const url = `http://localhost:${openPort}`;
|
||||
|
||||
syncEnvVars(process.env, process.env, runtimeEnv);
|
||||
|
||||
createServer((req, res) => {
|
||||
const parsedUrl = parse(req.url || '', true);
|
||||
handler(req, res, parsedUrl);
|
||||
}).listen(openPort, () => {
|
||||
if (process.send) {
|
||||
process.send(url);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,21 +0,0 @@
|
||||
import { Server } from 'http';
|
||||
import next from 'next-server';
|
||||
import url from 'url';
|
||||
import { Bridge } from './now__bridge';
|
||||
|
||||
if (!process.env.NODE_ENV) {
|
||||
const region = process.env.VERCEL_REGION || process.env.NOW_REGION;
|
||||
process.env.NODE_ENV = region === 'dev1' ? 'development' : 'production';
|
||||
}
|
||||
|
||||
const app = next({});
|
||||
|
||||
const server = new Server((req, res) => {
|
||||
const parsedUrl = url.parse(req.url || '', true);
|
||||
app.render(req, res, 'PATHNAME_PLACEHOLDER', parsedUrl.query, parsedUrl);
|
||||
});
|
||||
|
||||
const bridge = new Bridge(server);
|
||||
bridge.listen();
|
||||
|
||||
exports.launcher = bridge.launcher;
|
||||
@@ -1,336 +0,0 @@
|
||||
export default [
|
||||
'0.1.0',
|
||||
'0.1.1',
|
||||
'0.2.0',
|
||||
'0.2.1',
|
||||
'0.2.2',
|
||||
'0.2.3',
|
||||
'0.2.4',
|
||||
'0.2.5',
|
||||
'0.2.6',
|
||||
'0.2.7',
|
||||
'0.2.8',
|
||||
'0.2.9',
|
||||
'0.2.10',
|
||||
'0.2.11',
|
||||
'0.2.12',
|
||||
'0.2.13',
|
||||
'0.2.14',
|
||||
'0.3.0',
|
||||
'0.3.1',
|
||||
'0.3.2',
|
||||
'0.3.3',
|
||||
'0.4.0',
|
||||
'0.4.1',
|
||||
'0.9.9',
|
||||
'0.9.10',
|
||||
'0.9.11',
|
||||
'1.0.0',
|
||||
'1.0.1',
|
||||
'1.0.2',
|
||||
'1.1.0',
|
||||
'1.1.1',
|
||||
'1.1.2',
|
||||
'1.2.0',
|
||||
'1.2.1',
|
||||
'1.2.2',
|
||||
'1.2.3',
|
||||
'2.0.0-beta.0',
|
||||
'2.0.0-beta.1',
|
||||
'2.0.0-beta.2',
|
||||
'2.0.0-beta.3',
|
||||
'2.0.0-beta.4',
|
||||
'2.0.0-beta.5',
|
||||
'2.0.0-beta.6',
|
||||
'2.0.0-beta.7',
|
||||
'2.0.0-beta.8',
|
||||
'2.0.0-beta.9',
|
||||
'2.0.0-beta.10',
|
||||
'2.0.0-beta.11',
|
||||
'2.0.0-beta.12',
|
||||
'2.0.0-beta.13',
|
||||
'2.0.0-beta.14',
|
||||
'2.0.0-beta.15',
|
||||
'2.0.0-beta.16',
|
||||
'2.0.0-beta.17',
|
||||
'2.0.0-beta.18',
|
||||
'2.0.0-beta.19',
|
||||
'2.0.0-beta.20',
|
||||
'2.0.0-beta.21',
|
||||
'2.0.0-beta.22',
|
||||
'2.0.0-beta.23',
|
||||
'2.0.0-beta.24',
|
||||
'2.0.0-beta.25',
|
||||
'2.0.0-beta.26',
|
||||
'2.0.0-beta.27',
|
||||
'2.0.0-beta.28',
|
||||
'2.0.0-beta.29',
|
||||
'2.0.0-beta.30',
|
||||
'2.0.0-beta.31',
|
||||
'2.0.0-beta.32',
|
||||
'2.0.0-beta.33',
|
||||
'2.0.0-beta.34',
|
||||
'2.0.0-beta.35',
|
||||
'2.0.0-beta.36',
|
||||
'2.0.0-beta.37',
|
||||
'2.0.0-beta.38',
|
||||
'2.0.0-beta.39',
|
||||
'2.0.0-beta.40',
|
||||
'2.0.0-beta.41',
|
||||
'2.0.0-beta.42',
|
||||
'2.0.0',
|
||||
'2.0.1',
|
||||
'2.1.0',
|
||||
'2.1.1',
|
||||
'2.2.0',
|
||||
'2.3.0-alpha1',
|
||||
'2.3.0',
|
||||
'2.3.1',
|
||||
'2.4.0',
|
||||
'2.4.1',
|
||||
'2.4.2',
|
||||
'2.4.3',
|
||||
'2.4.4',
|
||||
'2.4.5',
|
||||
'2.4.6',
|
||||
'2.4.7',
|
||||
'2.4.8',
|
||||
'2.4.9',
|
||||
'3.0.0-beta1',
|
||||
'3.0.0-beta10',
|
||||
'3.0.0-beta11',
|
||||
'3.0.0-beta12',
|
||||
'3.0.0-beta13',
|
||||
'3.0.0-beta14',
|
||||
'3.0.0-beta15',
|
||||
'3.0.0-beta16',
|
||||
'3.0.0-beta2',
|
||||
'3.0.0-beta3',
|
||||
'3.0.0-beta4',
|
||||
'3.0.0-beta5',
|
||||
'3.0.0-beta6',
|
||||
'3.0.0-beta7',
|
||||
'3.0.0-beta8',
|
||||
'3.0.0-beta9',
|
||||
'3.0.1-beta.1',
|
||||
'3.0.1-beta.2',
|
||||
'3.0.1-beta.3',
|
||||
'3.0.1-beta.4',
|
||||
'3.0.1-beta.5',
|
||||
'3.0.1-beta.6',
|
||||
'3.0.1-beta.7',
|
||||
'3.0.1-beta.8',
|
||||
'3.0.1-beta.9',
|
||||
'3.0.1-beta.10',
|
||||
'3.0.1-beta.11',
|
||||
'3.0.1-beta.12',
|
||||
'3.0.1-beta.13',
|
||||
'3.0.1-beta.14',
|
||||
'3.0.1-beta.15',
|
||||
'3.0.1-beta.16',
|
||||
'3.0.1-beta.17',
|
||||
'3.0.1-beta.18',
|
||||
'3.0.1-beta.19',
|
||||
'3.0.1-beta.20',
|
||||
'3.0.1-beta.21',
|
||||
'3.0.1',
|
||||
'3.0.2',
|
||||
'3.0.3',
|
||||
'3.0.4',
|
||||
'3.0.5',
|
||||
'3.0.6',
|
||||
'3.1.0',
|
||||
'3.2.0',
|
||||
'3.2.1',
|
||||
'3.2.2',
|
||||
'3.2.3',
|
||||
'4.0.0-beta.1',
|
||||
'4.0.0-beta.2',
|
||||
'4.0.0-beta.3',
|
||||
'4.0.0-beta.4',
|
||||
'4.0.0-beta.5',
|
||||
'4.0.0-beta.6',
|
||||
'4.0.0',
|
||||
'4.0.1',
|
||||
'4.0.2',
|
||||
'4.0.3',
|
||||
'4.0.4',
|
||||
'4.0.5',
|
||||
'4.1.0',
|
||||
'4.1.1',
|
||||
'4.1.2',
|
||||
'4.1.3',
|
||||
'4.1.4-canary.1',
|
||||
'4.1.4-canary.2',
|
||||
'4.1.4',
|
||||
'4.2.0-canary.1',
|
||||
'4.2.0-zones.2',
|
||||
'4.2.0',
|
||||
'4.2.1',
|
||||
'4.2.2',
|
||||
'4.2.3',
|
||||
'4.3.0-canary.1',
|
||||
'4.3.0-universal-alpha.1',
|
||||
'4.3.0-universal-alpha.2',
|
||||
'4.3.0-universal-alpha.3',
|
||||
'4.3.0-universal-alpha.4',
|
||||
'4.3.0-zones.1',
|
||||
'4.4.0-canary.2',
|
||||
'4.4.0-canary.3',
|
||||
'5.0.0-universal-alpha.1',
|
||||
'5.0.0-universal-alpha.2',
|
||||
'5.0.0-universal-alpha.3',
|
||||
'5.0.0-universal-alpha.4',
|
||||
'5.0.0-universal-alpha.5',
|
||||
'5.0.0-universal-alpha.6',
|
||||
'5.0.0-universal-alpha.7',
|
||||
'5.0.0-universal-alpha.8',
|
||||
'5.0.0-universal-alpha.9',
|
||||
'5.0.0-universal-alpha.10',
|
||||
'5.0.0-universal-alpha.11',
|
||||
'5.0.0-universal-alpha.12',
|
||||
'5.0.0-universal-alpha.13',
|
||||
'5.0.0-universal-alpha.14',
|
||||
'5.0.0-universal-alpha.15',
|
||||
'5.0.0-universal-alpha.16',
|
||||
'5.0.0-universal-alpha.17',
|
||||
'5.0.0-universal-alpha.18',
|
||||
'5.0.0-universal-alpha.19',
|
||||
'5.0.0-universal-alpha.20',
|
||||
'5.0.0-universal-alpha.21',
|
||||
'5.0.0-universal-alpha.22',
|
||||
'5.0.0-universal-alpha.23',
|
||||
'5.0.0-zones.1',
|
||||
'5.0.0',
|
||||
'5.0.1-canary.1',
|
||||
'5.0.1-canary.2',
|
||||
'5.0.1-canary.3',
|
||||
'5.0.1-canary.4',
|
||||
'5.0.1-canary.5',
|
||||
'5.0.1-canary.6',
|
||||
'5.0.1-canary.7',
|
||||
'5.0.1-canary.8',
|
||||
'5.0.1-canary.9',
|
||||
'5.0.1-canary.10',
|
||||
'5.0.1-canary.11',
|
||||
'5.0.1-canary.12',
|
||||
'5.0.1-canary.13',
|
||||
'5.0.1-canary.14',
|
||||
'5.0.1-canary.15',
|
||||
'5.0.1-canary.16',
|
||||
'5.0.1-canary.17',
|
||||
'5.1.0',
|
||||
'6.0.0-canary.1',
|
||||
'6.0.0-canary.2',
|
||||
'6.0.0-canary.3',
|
||||
'6.0.0-canary.4',
|
||||
'6.0.0-canary.5',
|
||||
'6.0.0-canary.6',
|
||||
'6.0.0-canary.7',
|
||||
'6.0.0',
|
||||
'6.0.1-canary.0',
|
||||
'6.0.1-canary.1',
|
||||
'6.0.1-canary.2',
|
||||
'6.0.1',
|
||||
'6.0.2-canary.0',
|
||||
'6.0.2',
|
||||
'6.0.3-canary.0',
|
||||
'6.0.3-canary.1',
|
||||
'6.0.3',
|
||||
'6.0.4-canary.0',
|
||||
'6.0.4-canary.1',
|
||||
'6.0.4-canary.2',
|
||||
'6.0.4-canary.3',
|
||||
'6.0.4-canary.4',
|
||||
'6.0.4-canary.5',
|
||||
'6.0.4-canary.6',
|
||||
'6.0.4-canary.7',
|
||||
'6.0.4-canary.8',
|
||||
'6.0.4-canary.9',
|
||||
'6.1.0-canary.0',
|
||||
'6.1.0',
|
||||
'6.1.1-canary.0',
|
||||
'6.1.1-canary.1',
|
||||
'6.1.1-canary.2',
|
||||
'6.1.1-canary.3',
|
||||
'6.1.1-canary.4',
|
||||
'6.1.1-canary.5',
|
||||
'6.1.1',
|
||||
'6.1.2',
|
||||
'7.0.0-canary.0',
|
||||
'7.0.0-canary.1',
|
||||
'7.0.0-canary.2',
|
||||
'7.0.0-canary.3',
|
||||
'7.0.0-canary.4',
|
||||
'7.0.0-canary.5',
|
||||
'7.0.0-canary.6',
|
||||
'7.0.0-canary.7',
|
||||
'7.0.0-canary.8',
|
||||
'7.0.0-canary.9',
|
||||
'7.0.0-canary.10',
|
||||
'7.0.0-canary.11',
|
||||
'7.0.0-canary.12',
|
||||
'7.0.0-canary.13',
|
||||
'7.0.0-canary.14',
|
||||
'7.0.0-canary.15',
|
||||
'7.0.0-canary.16',
|
||||
'7.0.0-canary.18',
|
||||
'7.0.0-canary.19',
|
||||
'7.0.0-canary.20',
|
||||
'7.0.0',
|
||||
'7.0.1-canary.0',
|
||||
'7.0.1-canary.1',
|
||||
'7.0.1-canary.2',
|
||||
'7.0.1-canary.3',
|
||||
'7.0.1-canary.4',
|
||||
'7.0.1-canary.5',
|
||||
'7.0.1-canary.6',
|
||||
'7.0.1',
|
||||
'7.0.2-alpha.1',
|
||||
'7.0.2-alpha.3',
|
||||
'7.0.2-canary.5',
|
||||
'7.0.2-canary.6',
|
||||
'7.0.2-canary.7',
|
||||
'7.0.2-canary.8',
|
||||
'7.0.2-canary.9',
|
||||
'7.0.2-canary.10',
|
||||
'7.0.2-canary.11',
|
||||
'7.0.2-canary.12',
|
||||
'7.0.2-canary.13',
|
||||
'7.0.2-canary.14',
|
||||
'7.0.2-canary.15',
|
||||
'7.0.2-canary.16',
|
||||
'7.0.2-canary.17',
|
||||
'7.0.2-canary.18',
|
||||
'7.0.2-canary.19',
|
||||
'7.0.2-canary.20',
|
||||
'7.0.2-canary.21',
|
||||
'7.0.2-canary.22',
|
||||
'7.0.2-canary.23',
|
||||
'7.0.2-canary.24',
|
||||
'7.0.2-canary.25',
|
||||
'7.0.2-canary.26',
|
||||
'7.0.2-canary.27',
|
||||
'7.0.2-canary.28',
|
||||
'7.0.2-canary.29',
|
||||
'7.0.2-canary.31',
|
||||
'7.0.2-canary.33',
|
||||
'7.0.2-canary.34',
|
||||
'7.0.2-canary.35',
|
||||
'7.0.2-canary.36',
|
||||
'7.0.2-canary.37',
|
||||
'7.0.2-canary.38',
|
||||
'7.0.2-canary.39',
|
||||
'7.0.2-canary.40',
|
||||
'7.0.2-canary.41',
|
||||
'7.0.2-canary.42',
|
||||
'7.0.2-canary.43',
|
||||
'7.0.2-canary.44',
|
||||
'7.0.2-canary.45',
|
||||
'7.0.2-canary.46',
|
||||
'7.0.2-canary.47',
|
||||
'7.0.2-canary.48',
|
||||
'7.0.2-canary.49',
|
||||
'7.0.2-canary.50',
|
||||
'7.0.2',
|
||||
];
|
||||
@@ -1,25 +0,0 @@
|
||||
// The Next.js builder can emit the project in a subdirectory depending on how
|
||||
// many folder levels of `node_modules` are traced. To ensure `process.cwd()`
|
||||
// returns the proper path, we change the directory to the folder with the
|
||||
// launcher. This mimics `yarn workspace run` behavior.
|
||||
process.chdir(__dirname);
|
||||
|
||||
if (!process.env.NODE_ENV) {
|
||||
const region = process.env.VERCEL_REGION || process.env.NOW_REGION;
|
||||
process.env.NODE_ENV = region === 'dev1' ? 'development' : 'production';
|
||||
}
|
||||
|
||||
import { Server } from 'http';
|
||||
import { Bridge } from './now__bridge';
|
||||
// eslint-disable-next-line
|
||||
let page: any = {};
|
||||
// __LAUNCHER_PAGE_HANDLER__
|
||||
|
||||
// page.render is for React rendering
|
||||
// page.default is for /api rendering
|
||||
// page is for module.exports in /api
|
||||
const server = new Server(page.render || page.default || page);
|
||||
const bridge = new Bridge(server);
|
||||
bridge.listen();
|
||||
|
||||
exports.launcher = bridge.launcher;
|
||||
@@ -1,25 +0,0 @@
|
||||
// The Next.js builder can emit the project in a subdirectory depending on how
|
||||
// many folder levels of `node_modules` are traced. To ensure `process.cwd()`
|
||||
// returns the proper path, we change the directory to the folder with the
|
||||
// launcher. This mimics `yarn workspace run` behavior.
|
||||
process.chdir(__dirname);
|
||||
|
||||
if (!process.env.NODE_ENV) {
|
||||
const region = process.env.VERCEL_REGION || process.env.NOW_REGION;
|
||||
process.env.NODE_ENV = region === 'dev1' ? 'development' : 'production';
|
||||
}
|
||||
|
||||
import { Server } from 'http';
|
||||
import { Bridge } from './now__bridge';
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const page = require(__LAUNCHER_PAGE_PATH__);
|
||||
|
||||
// page.render is for React rendering
|
||||
// page.default is for /api rendering
|
||||
// page is for module.exports in /api
|
||||
const server = new Server(page.render || page.default || page);
|
||||
const bridge = new Bridge(server);
|
||||
bridge.listen();
|
||||
|
||||
exports.launcher = bridge.launcher;
|
||||
@@ -1,22 +0,0 @@
|
||||
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',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -1,517 +0,0 @@
|
||||
{
|
||||
"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\""
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"next": "canary",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
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,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
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;
|
||||
@@ -1,51 +0,0 @@
|
||||
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,
|
||||
};
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
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,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,49 +0,0 @@
|
||||
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,
|
||||
};
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
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,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
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,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,57 +0,0 @@
|
||||
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,
|
||||
};
|
||||
};
|
||||
@@ -1,54 +0,0 @@
|
||||
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: {},
|
||||
};
|
||||
};
|
||||
@@ -1,50 +0,0 @@
|
||||
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,
|
||||
};
|
||||
};
|
||||
@@ -1,37 +0,0 @@
|
||||
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 +0,0 @@
|
||||
hello world!
|
||||
@@ -1,21 +0,0 @@
|
||||
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',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -1,359 +0,0 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@vercel/next",
|
||||
"config": {
|
||||
"sharedLambdas": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
{
|
||||
"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": "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\""
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"next": "canary",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
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,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
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: {
|
||||
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,
|
||||
};
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
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,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,46 +0,0 @@
|
||||
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: {
|
||||
params,
|
||||
locale,
|
||||
locales,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const getStaticPaths = () => {
|
||||
return {
|
||||
paths: [
|
||||
{ params: { slug: 'first' } },
|
||||
'/gsp/no-fallback/second',
|
||||
{ params: { slug: 'first' }, locale: 'en-US' },
|
||||
'/nl-NL/gsp/no-fallback/second',
|
||||
],
|
||||
fallback: false,
|
||||
};
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
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,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
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,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,46 +0,0 @@
|
||||
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 />
|
||||
</>
|
||||
);
|
||||
}
|
||||