Compare commits

..

14 Commits

Author SHA1 Message Date
Nathan Rajlich
90c05250b0 Publish Canary
- vercel@21.0.2-canary.9
 - @vercel/go@1.1.7-canary.1
 - @vercel/node@1.8.6-canary.5
2021-01-12 17:47:24 -08:00
Nathan Rajlich
030880fe74 [node][go] Fix order of exit code in startDevServer() error reason (#5688) 2021-01-12 17:02:55 -08:00
Nathan Rajlich
02bc88f33b [cli] Use cmd() formatting for "npm not installed" message (#5687)
* [cli] Use `cmd()` formatting for "npm not installed" message

* Fix build
2021-01-12 17:02:36 -08:00
Nathan Rajlich
38ff557cad [cli] Skip "00-list-directory" and "temporary directory listing" tests temporarily (#5689)
* [cli] Skip "now-dev-directory-listing" test temporarily

* Disable correct tests

* Fix `vc env` test
2021-01-12 17:01:56 -08:00
Nathan Rajlich
47c34842d5 Publish Canary
- vercel@21.0.2-canary.8
 - @vercel/go@1.1.7-canary.0
 - @vercel/node@1.8.6-canary.4
 - @vercel/python@1.2.4-canary.0
 - @vercel/ruby@1.2.5-canary.0
2021-01-12 14:51:30 -08:00
Nathan Rajlich
d21b215ad0 [cli] Add error link when startDevServer() throws, and make npm not installed formatting consistent (#5684) 2021-01-12 14:47:11 -08:00
Nathan Rajlich
5827737fd5 [node][go] Better startDevServer() error message (#5674)
* [go] Better `startDevServer()` error message

* [node] Better `startDevServer()` error message

Co-authored-by: Steven <steven@ceriously.com>
2021-01-11 15:55:58 -08:00
Steven
a9e078d410 [all] Rename init files to vc_ prefix (#5675)
These files show up in error logs, so its confusing to see the [legacy now terminology](https://vercel.com/blog/zeit-is-now-vercel).
2021-01-11 20:38:03 +00:00
Lee Robinson
b4d9b17fb8 Update to latest Create Next App example. (#5655) 2021-01-10 19:52:18 -06:00
Steven
02c55bf634 [cli] Remove legacy example from vc ls --help (#5651)
`vc ls --help` was still listing an example using `--all` which was removed with Now 1.0 in PR #5011.

This PR removes that legacy example.
2021-01-07 20:28:48 +00:00
Nathan Rajlich
08af15055f Publish Canary
- vercel@21.0.2-canary.7
2021-01-06 18:33:16 -08:00
Nathan Rajlich
0597aaa5e4 [cli] Print better message upon ENOENT error when invoking startDevServer() (#5643)
When `spawn()` emits an "ENOENT" error, meaning that the command was not
found, the error would only be visible if `--debug` was enabled for vc
dev.

Now we will always render any error from `startDevServer()`, as well as
special-case the "ENOENT" error informing the user to double check their
installation of the command.
2021-01-06 13:48:55 -08:00
Nathan Rajlich
176856a1ea Stop publishing legacy @now scoped packages (#5641)
These `@now` scoped packages have been published and deprecated with the following warning since May 2020:

```
DEPRECATED ⚠️  - "@now/node" is deprecated and will stop receiving updates on December 31, 2020. Please use "@vercel/node" instead.
```

Since it is now 2021, the time has come to stop publishing.

### Related Issues

[[ch3378]]
2021-01-06 01:59:25 +00:00
Nathan Rajlich
375a55ebed [next][redwood][static-build] Remove frontend runtimes (#5640) 2021-01-05 14:11:55 -08:00
1912 changed files with 136 additions and 329055 deletions

View File

@@ -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:

View File

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

View File

@@ -76,7 +76,6 @@
align-items: center;
justify-content: center;
flex-wrap: wrap;
max-width: 800px;
margin-top: 3rem;
}

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "21.0.2-canary.6",
"version": "21.0.2-canary.9",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Vercel",
@@ -62,10 +62,10 @@
},
"dependencies": {
"@vercel/build-utils": "2.6.1-canary.2",
"@vercel/go": "1.1.6",
"@vercel/node": "1.8.6-canary.3",
"@vercel/python": "1.2.3",
"@vercel/ruby": "1.2.4",
"@vercel/go": "1.1.7-canary.1",
"@vercel/node": "1.8.6-canary.5",
"@vercel/python": "1.2.4-canary.0",
"@vercel/ruby": "1.2.5-canary.0",
"update-notifier": "4.1.0"
},
"devDependencies": {

View File

@@ -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`)}

View File

@@ -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',

View File

@@ -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';
@@ -886,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'));
@@ -1681,7 +1682,16 @@ export default class DevServer {
// `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,

View File

@@ -1054,6 +1054,10 @@ test(
})
);
// Directory listing is skipped for now until the project flag is respected
// in `vc dev`. Note that this test will need to be updated to patch the project
// to enable directory listing. See CH-18434.
/*
test(
'[vercel dev] 00-list-directory',
testFixtureStdio('00-list-directory', async testPath => {
@@ -1063,6 +1067,7 @@ test(
await testPath(200, '/.well-known/keybase.txt', 'proof goes here');
})
);
*/
test(
'[vercel dev] 01-node',
@@ -1382,6 +1387,10 @@ test('[vercel dev] 24-ember', async t => {
await tester(t);
});
// Directory listing is skipped for now until the project flag is respected
// in `vc dev`. Note that this test will need to be updated to patch the project
// to enable directory listing. See CH-18434.
/*
test(
'[vercel dev] temporary directory listing',
testFixtureStdio(
@@ -1414,6 +1423,7 @@ test(
{ skipDeploy: true }
)
);
*/
test('[vercel dev] add a `package.json` to trigger `@vercel/static-build`', async t => {
const directory = fixture('trigger-static-build');

View File

@@ -800,9 +800,9 @@ test('Deploy `api-env` fixture and test `vercel env` command', async t => {
t.is(homeJson['MY_STDIN_VAR'], '{"expect":"quotes"}');
t.is(homeJson['MY_DECRYPTABLE_SECRET_ENV'], 'decryptable value');
// system env vars are not automatically exposed
t.is(apiJson['VERCEL'], undefined);
t.is(homeJson['VERCEL'], undefined);
// system env vars are automatically exposed
t.is(apiJson['VERCEL'], '1');
t.is(homeJson['VERCEL'], '1');
vc.kill('SIGTERM', { forceKillAfterTimeout: 2000 });

View File

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

View File

@@ -6,5 +6,5 @@ import (
)
func main() {
vc.Start(http.HandlerFunc(__NOW_HANDLER_FUNC_NAME))
vc.Start(http.HandlerFunc(__VC_HANDLER_FUNC_NAME))
}

View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/go",
"version": "1.1.6",
"version": "1.1.7-canary.1",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",

View File

@@ -1,2 +0,0 @@
/dist
/src/now__bridge.ts

View File

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

View File

@@ -1,43 +0,0 @@
{
"name": "@vercel/next",
"version": "2.7.8",
"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.5",
"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"
}
}

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -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',
];

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -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',
},
],
},
};

View File

@@ -1,521 +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\""
},
{
"path": "/en/not-found",
"status": 404
},
{
"path": "/en/not-found",
"mustContain": "lang=\"en\""
},
{
"path": "/nl/not-found",
"status": 404
},
{
"path": "/nl/not-found",
"mustContain": "lang=\"nl\""
},
{
"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.json",
"status": 200,
"mustContain": "\"locale\":\"en-US\""
},
{
"path": "/_next/data/testing-build-id/en.json",
"status": 200,
"mustContain": "\"locale\":\"en\""
},
{
"path": "/_next/data/testing-build-id/fr.json",
"status": 200,
"mustContain": "\"locale\":\"fr\""
},
{
"path": "/_next/data/testing-build-id/nl.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\""
}
]
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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: {},
};
};

View File

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

View File

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

View File

@@ -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',
},
],
},
};

View File

@@ -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\""
}
]
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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: {},
};
};

View File

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

View File

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

View File

@@ -1,157 +0,0 @@
/* eslint-env jest */
const cheerio = require('cheerio');
const { check, waitFor } = require('../../utils');
const fetch = require('../../../../../test/lib/deployment/fetch-retry');
async function checkForChange(url, initialValue, hardError) {
return check(
async () => {
const res = await fetch(url);
if (res.status !== 200) {
throw new Error(`Invalid status code ${res.status}`);
}
const $ = cheerio.load(await res.text());
const props = JSON.parse($('#props').text());
if (isNaN(props.random)) {
throw new Error(`Invalid random value ${props.random}`);
}
const newValue = props.random;
return initialValue !== newValue ? 'success' : 'fail';
},
'success',
hardError
);
}
module.exports = function (ctx) {
it('should revalidate content properly from /', async () => {
const res = await fetch(`${ctx.deploymentUrl}/`);
expect(res.status).toBe(200);
let $ = cheerio.load(await res.text());
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('en-US');
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
expect($('#router-locale').text()).toBe('en-US');
await checkForChange(`${ctx.deploymentUrl}/`, initialRandom);
});
it('should revalidate content properly from /fr', async () => {
const res = await fetch(`${ctx.deploymentUrl}/fr`);
expect(res.status).toBe(200);
let $ = cheerio.load(await res.text());
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('fr');
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/fr`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
expect($('#router-locale').text()).toBe('fr');
await checkForChange(`${ctx.deploymentUrl}/fr`, initialRandom);
});
it('should revalidate content properly from /nl-NL', async () => {
const res = await fetch(`${ctx.deploymentUrl}/nl-NL`);
expect(res.status).toBe(200);
let $ = cheerio.load(await res.text());
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('nl-NL');
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/nl-NL`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
expect($('#router-locale').text()).toBe('nl-NL');
await checkForChange(`${ctx.deploymentUrl}/nl-NL`, initialRandom);
});
it('should revalidate content properly from /second', async () => {
const res = await fetch(`${ctx.deploymentUrl}/second`);
expect(res.status).toBe(200);
const html = await res.text();
let $ = cheerio.load(html);
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('en-US');
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/second`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
expect($('#router-locale').text()).toBe('en-US');
await checkForChange(`${ctx.deploymentUrl}/second`, initialRandom);
});
it('should revalidate content properly from /fr/second', async () => {
const res = await fetch(`${ctx.deploymentUrl}/fr/second`);
expect(res.status).toBe(200);
const html = await res.text();
let $ = cheerio.load(html);
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('fr');
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/fr/second`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
expect($('#router-locale').text()).toBe('fr');
await checkForChange(`${ctx.deploymentUrl}/fr/second`, initialRandom);
});
it('should revalidate content properly from /nl-NL/second', async () => {
const res = await fetch(`${ctx.deploymentUrl}/nl-NL/second`);
expect(res.status).toBe(200);
const html = await res.text();
let $ = cheerio.load(html);
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('nl-NL');
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/nl-NL/second`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
expect($('#router-locale').text()).toBe('nl-NL');
await checkForChange(`${ctx.deploymentUrl}/nl-NL/second`, initialRandom);
});
};

View File

@@ -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',
},
],
},
};

View File

@@ -1,192 +0,0 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/next"
}
],
"probes": [
{
"path": "/hello.txt",
"status": 200,
"mustContain": "hello world!"
},
{
"path": "/",
"headers": {
"accept-language": "en;q=0.9"
},
"fetchOptions": {
"redirect": "manual"
},
"status": 307,
"responseHeaders": {
"location": "//en/"
}
},
{
"path": "/",
"headers": {
"accept-language": "nl;q=0.9"
},
"fetchOptions": {
"redirect": "manual"
},
"status": 307,
"responseHeaders": {
"location": "//nl/"
}
},
{
"path": "/",
"headers": {
"accept-language": "nl-NL;q=0.9"
},
"fetchOptions": {
"redirect": "manual"
},
"status": 307,
"responseHeaders": {
"location": "//nl-NL/"
}
},
{
"path": "/",
"headers": {
"accept-language": "fr;q=0.9"
},
"fetchOptions": {
"redirect": "manual"
},
"status": 307,
"responseHeaders": {
"location": "//fr/"
}
},
{
"path": "/",
"headers": {
"accept-language": "en-US;q=0.9"
},
"fetchOptions": {
"redirect": "manual"
},
"status": 200,
"mustContain": "catchall page"
},
{
"path": "/en-US",
"headers": {
"accept-language": "nl;q=0.9"
},
"fetchOptions": {
"redirect": "manual"
},
"status": 200,
"mustContain": "catchall page"
},
{
"path": "/",
"status": 200,
"mustContain": "catchall page"
},
{
"path": "/",
"status": 200,
"mustContain": ">en-US<"
},
{
"path": "/en",
"status": 200,
"mustContain": "catchall page"
},
{
"path": "/en",
"status": 200,
"mustContain": ">en<"
},
{
"path": "/fr",
"status": 200,
"mustContain": "catchall page"
},
{
"path": "/fr",
"status": 200,
"mustContain": ">fr<"
},
{
"path": "/nl",
"status": 200,
"mustContain": "catchall page"
},
{
"path": "/nl",
"status": 200,
"mustContain": ">nl<"
},
{
"path": "/nl-NL",
"status": 200,
"mustContain": "catchall page"
},
{
"path": "/nl-NL",
"status": 200,
"mustContain": ">nl-NL<"
},
{
"path": "/first",
"status": 200,
"mustContain": "catchall page"
},
{
"path": "/first",
"status": 200,
"mustContain": ">en-US<"
},
{
"path": "/en/first",
"status": 200,
"mustContain": "catchall page"
},
{
"path": "/en/first",
"status": 200,
"mustContain": ">en<"
},
{
"path": "/fr/first",
"status": 200,
"mustContain": "catchall page"
},
{
"path": "/fr/first",
"status": 200,
"mustContain": ">fr<"
},
{
"path": "/nl/first",
"status": 200,
"mustContain": "catchall page"
},
{
"path": "/nl/first",
"status": 200,
"mustContain": ">nl<"
},
{
"path": "/nl-NL/first",
"status": 200,
"mustContain": "catchall page"
},
{
"path": "/nl-NL/first",
"status": 200,
"mustContain": ">nl-NL<"
}
]
}

View File

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

View File

@@ -1,69 +0,0 @@
import Link from 'next/link';
import { useRouter } from 'next/router';
const Slug = props => {
const router = useRouter();
// invariant ensuring fallback is never accidentally flipped
if (router.isFallback) {
return 'Loading...';
}
return (
<div>
<p>catchall page</p>
<p id="props">{JSON.stringify(props)}</p>
<p id="router-locale">{router.locale}</p>
<p id="router-locales">{JSON.stringify(router.locales)}</p>
<p id="router-query">{JSON.stringify(router.query)}</p>
<p id="router-pathname">{router.pathname}</p>
<p id="router-as-path">{router.asPath}</p>
<Link href="/gsp/blocking/hallo-wereld" locale={'nl-NL'}>
<a>/nl-NL/gsp/blocking/hallo-wereld</a>
</Link>
<br />
<Link href="/gsp/blocking/42" locale={'nl-NL'}>
<a>/nl-NL/gsp/blocking/42</a>
</Link>
<br />
<Link href="/gsp/blocking/hallo-welt" locale={'fr'}>
<a>/fr/gsp/blocking/hallo-welt</a>
</Link>
<br />
<Link href="/gsp/blocking/42" locale={'fr'}>
<a>/fr/gsp/blocking/42</a>
</Link>
<br />
<Link href="/">
<a>/</a>
</Link>
</div>
);
};
export const getStaticProps = ({ params }) => {
return {
props: {
params,
random: Math.random(),
catchall: 'yes',
},
revalidate: 1,
};
};
export const getStaticPaths = ({ locales }) => {
const paths = [];
for (const locale of locales) {
paths.push({ params: { slug: ['first'] }, locale });
paths.push({ params: { slug: ['first'] }, locale });
}
return {
paths,
fallback: 'blocking',
};
};
export default Slug;

View File

@@ -1,471 +0,0 @@
/* eslint-env jest */
const cheerio = require('cheerio');
const { check, waitFor } = require('../../utils');
const fetch = require('../../../../../test/lib/deployment/fetch-retry');
async function checkForChange(url, initialValue, hardError) {
return check(
async () => {
const res = await fetch(url);
if (res.status !== 200) {
throw new Error(`Invalid status code ${res.status}`);
}
const $ = cheerio.load(await res.text());
const props = JSON.parse($('#props').text());
if (isNaN(props.random)) {
throw new Error(`Invalid random value ${props.random}`);
}
const newValue = props.random;
return initialValue !== newValue ? 'success' : 'fail';
},
'success',
hardError
);
}
module.exports = function (ctx) {
it('should revalidate content properly from /', async () => {
const dataRes = await fetch(
`${ctx.deploymentUrl}/_next/data/testing-build-id/en-US.json`
);
expect(dataRes.status).toBe(200);
await dataRes.json();
await waitFor(2000);
const res = await fetch(`${ctx.deploymentUrl}/`);
expect(res.status).toBe(200);
let $ = cheerio.load(await res.text());
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('en-US');
expect(JSON.parse($('#router-query').text())).toEqual({});
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
expect($('#router-locale').text()).toBe('en-US');
expect(JSON.parse($('#router-query').text())).toEqual({});
await checkForChange(`${ctx.deploymentUrl}/`, initialRandom);
});
it('should revalidate content properly from /fr', async () => {
const dataRes = await fetch(
`${ctx.deploymentUrl}/_next/data/testing-build-id/fr.json`
);
expect(dataRes.status).toBe(200);
await dataRes.json();
await waitFor(2000);
const res = await fetch(`${ctx.deploymentUrl}/fr`);
expect(res.status).toBe(200);
let $ = cheerio.load(await res.text());
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('fr');
expect(JSON.parse($('#router-query').text())).toEqual({});
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/fr`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
expect($('#router-locale').text()).toBe('fr');
expect(JSON.parse($('#router-query').text())).toEqual({});
await checkForChange(`${ctx.deploymentUrl}/fr`, initialRandom);
});
it('should revalidate content properly from /nl-NL', async () => {
const dataRes = await fetch(
`${ctx.deploymentUrl}/_next/data/testing-build-id/nl-NL.json`
);
expect(dataRes.status).toBe(200);
await dataRes.json();
await waitFor(2000);
const res = await fetch(`${ctx.deploymentUrl}/nl-NL`);
expect(res.status).toBe(200);
let $ = cheerio.load(await res.text());
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('nl-NL');
expect(JSON.parse($('#router-query').text())).toEqual({});
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/nl-NL`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
expect($('#router-locale').text()).toBe('nl-NL');
expect(JSON.parse($('#router-query').text())).toEqual({});
await checkForChange(`${ctx.deploymentUrl}/nl-NL`, initialRandom);
});
it('should revalidate content properly from /gsp/fallback/first', async () => {
// check the _next/data URL first
const dataRes = await fetch(
`${ctx.deploymentUrl}/_next/data/testing-build-id/en-US/gsp/fallback/first.json`
);
expect(dataRes.status).toBe(200);
await dataRes.json();
await waitFor(2000);
const res = await fetch(`${ctx.deploymentUrl}/gsp/fallback/first`);
expect(res.status).toBe(200);
const html = await res.text();
let $ = cheerio.load(html);
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('en-US');
expect(props.params).toEqual({ slug: 'first' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/gsp/fallback/first`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
const props2 = JSON.parse($('#props').text());
expect($('#router-locale').text()).toBe('en-US');
expect(props2.params).toEqual({ slug: 'first' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
await checkForChange(
`${ctx.deploymentUrl}/gsp/fallback/first`,
initialRandom
);
});
it('should revalidate content properly from /fr/gsp/fallback/first', async () => {
// check the _next/data URL first
const dataRes = await fetch(
`${ctx.deploymentUrl}/_next/data/testing-build-id/fr/gsp/fallback/first.json`
);
expect(dataRes.status).toBe(200);
await dataRes.json();
await waitFor(2000);
const res = await fetch(`${ctx.deploymentUrl}/fr/gsp/fallback/first`);
expect(res.status).toBe(200);
const html = await res.text();
let $ = cheerio.load(html);
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('fr');
expect(props.params).toEqual({ slug: 'first' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/fr/gsp/fallback/first`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
const props2 = JSON.parse($('#props').text());
expect($('#router-locale').text()).toBe('fr');
expect(props2.params).toEqual({ slug: 'first' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
await checkForChange(
`${ctx.deploymentUrl}/fr/gsp/fallback/first`,
initialRandom
);
});
it('should revalidate content properly from /nl-NL/gsp/fallback/first', async () => {
// check the _next/data URL first
const dataRes = await fetch(
`${ctx.deploymentUrl}/_next/data/testing-build-id/nl-NL/gsp/fallback/first.json`
);
expect(dataRes.status).toBe(200);
await dataRes.json();
await waitFor(2000);
const res = await fetch(`${ctx.deploymentUrl}/nl-NL/gsp/fallback/first`);
expect(res.status).toBe(200);
const html = await res.text();
let $ = cheerio.load(html);
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('nl-NL');
expect(props.params).toEqual({ slug: 'first' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/nl-NL/gsp/fallback/first`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
const props2 = JSON.parse($('#props').text());
expect($('#router-locale').text()).toBe('nl-NL');
expect(props2.params).toEqual({ slug: 'first' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
await checkForChange(
`${ctx.deploymentUrl}/nl-NL/gsp/fallback/first`,
initialRandom
);
});
//
it('should revalidate content properly from /gsp/fallback/new-page', async () => {
const dataRes = await fetch(
`${ctx.deploymentUrl}/_next/data/testing-build-id/en-US/gsp/fallback/new-page.json`
);
expect(dataRes.status).toBe(200);
await dataRes.json();
const initRes = await fetch(`${ctx.deploymentUrl}/gsp/fallback/new-page`);
expect(initRes.status).toBe(200);
await waitFor(2000);
const res = await fetch(`${ctx.deploymentUrl}/gsp/fallback/new-page`);
expect(res.status).toBe(200);
const html = await res.text();
let $ = cheerio.load(html);
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('en-US');
expect(props.params).toEqual({ slug: 'new-page' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'new-page' });
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/gsp/fallback/new-page`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
const props2 = JSON.parse($('#props').text());
expect($('#router-locale').text()).toBe('en-US');
expect(props2.params).toEqual({ slug: 'new-page' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'new-page' });
await checkForChange(
`${ctx.deploymentUrl}/gsp/fallback/new-page`,
initialRandom
);
});
it('should revalidate content properly from /fr/gsp/fallback/new-page', async () => {
// we have to hit the _next/data URL first
const dataRes = await fetch(
`${ctx.deploymentUrl}/_next/data/testing-build-id/fr/gsp/fallback/new-page.json`
);
expect(dataRes.status).toBe(200);
await waitFor(2000);
const res = await fetch(`${ctx.deploymentUrl}/fr/gsp/fallback/new-page`);
expect(res.status).toBe(200);
const html = await res.text();
let $ = cheerio.load(html);
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('fr');
expect(props.params).toEqual({ slug: 'new-page' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'new-page' });
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/fr/gsp/fallback/new-page`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
expect($('#router-locale').text()).toBe('fr');
await checkForChange(
`${ctx.deploymentUrl}/fr/gsp/fallback/new-page`,
initialRandom
);
});
it('should revalidate content properly from /nl-NL/gsp/fallback/new-page', async () => {
// we have to hit the _next/data URL first
const dataRes = await fetch(
`${ctx.deploymentUrl}/_next/data/testing-build-id/nl-NL/gsp/fallback/new-page.json`
);
expect(dataRes.status).toBe(200);
await waitFor(2000);
const res = await fetch(`${ctx.deploymentUrl}/nl-NL/gsp/fallback/new-page`);
expect(res.status).toBe(200);
const html = await res.text();
let $ = cheerio.load(html);
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('nl-NL');
expect(props.params).toEqual({ slug: 'new-page' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'new-page' });
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(
`${ctx.deploymentUrl}/nl-NL/gsp/fallback/new-page`
);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
const props2 = JSON.parse($('#props').text());
expect($('#router-locale').text()).toBe('nl-NL');
expect(props2.params).toEqual({ slug: 'new-page' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'new-page' });
await checkForChange(
`${ctx.deploymentUrl}/nl-NL/gsp/fallback/new-page`,
initialRandom
);
});
it('should revalidate content properly from /gsp/no-fallback/first', async () => {
const dataRes = await fetch(
`${ctx.deploymentUrl}/_next/data/testing-build-id/en-US/gsp/no-fallback/first.json`
);
expect(dataRes.status).toBe(200);
await dataRes.json();
await waitFor(2000);
const res = await fetch(`${ctx.deploymentUrl}/gsp/no-fallback/first`);
expect(res.status).toBe(200);
let $ = cheerio.load(await res.text());
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('en-US');
expect(props.params).toEqual({ slug: 'first' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/gsp/no-fallback/first`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
const props2 = JSON.parse($('#props').text());
expect($('#router-locale').text()).toBe('en-US');
expect(props2.params).toEqual({ slug: 'first' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
await checkForChange(
`${ctx.deploymentUrl}/gsp/no-fallback/first`,
initialRandom
);
});
it('should revalidate content properly from /fr/gsp/no-fallback/first', async () => {
const dataRes = await fetch(
`${ctx.deploymentUrl}/_next/data/testing-build-id/fr/gsp/no-fallback/first.json`
);
expect(dataRes.status).toBe(200);
await dataRes.json();
await waitFor(2000);
const res = await fetch(`${ctx.deploymentUrl}/fr/gsp/no-fallback/first`);
expect(res.status).toBe(200);
let $ = cheerio.load(await res.text());
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('fr');
expect(props.params).toEqual({ slug: 'first' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(`${ctx.deploymentUrl}/fr/gsp/no-fallback/first`);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
const props2 = JSON.parse($('#props').text());
expect($('#router-locale').text()).toBe('fr');
expect(props2.params).toEqual({ slug: 'first' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'first' });
await checkForChange(
`${ctx.deploymentUrl}/fr/gsp/no-fallback/first`,
initialRandom
);
});
it('should revalidate content properly from /nl-NL/gsp/no-fallback/second', async () => {
const dataRes = await fetch(
`${ctx.deploymentUrl}/_next/data/testing-build-id/nl-NL/gsp/no-fallback/second.json`
);
expect(dataRes.status).toBe(200);
await dataRes.json();
await waitFor(2000);
const res = await fetch(
`${ctx.deploymentUrl}/nl-NL/gsp/no-fallback/second`
);
expect(res.status).toBe(200);
let $ = cheerio.load(await res.text());
const props = JSON.parse($('#props').text());
const initialRandom = props.random;
expect($('#router-locale').text()).toBe('nl-NL');
expect(props.params).toEqual({ slug: 'second' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'second' });
// wait for revalidation to occur
await waitFor(2000);
const res2 = await fetch(
`${ctx.deploymentUrl}/nl-NL/gsp/no-fallback/second`
);
expect(res2.status).toBe(200);
$ = cheerio.load(await res2.text());
const props2 = JSON.parse($('#props').text());
expect($('#router-locale').text()).toBe('nl-NL');
expect(props2.params).toEqual({ slug: 'second' });
expect(JSON.parse($('#router-query').text())).toEqual({ slug: 'second' });
await checkForChange(
`${ctx.deploymentUrl}/nl-NL/gsp/no-fallback/second`,
initialRandom
);
});
};

View File

@@ -1,98 +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',
},
],
},
async redirects() {
return [
{
source: '/en-US/redirect-1',
destination: '/somewhere-else',
permanent: false,
locale: false,
},
{
source: '/nl/redirect-2',
destination: '/somewhere-else',
permanent: false,
locale: false,
},
{
source: '/redirect-3',
destination: '/somewhere-else',
permanent: false,
},
];
},
async rewrites() {
return [
{
source: '/en-US/rewrite-1',
destination: '/another',
locale: false,
},
{
source: '/nl/rewrite-2',
destination: '/nl/another',
locale: false,
},
{
source: '/fr/rewrite-3',
destination: '/nl/another',
locale: false,
},
{
source: '/rewrite-4',
destination: '/another',
},
];
},
async headers() {
return [
{
source: '/en-US/add-header-1',
locale: false,
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
{
source: '/nl/add-header-2',
locale: false,
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
{
source: '/add-header-3',
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
];
},
};

View File

@@ -1,803 +0,0 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/next"
}
],
"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\""
},
{
"path": "/en/not-found",
"status": 404
},
{
"path": "/en/not-found",
"mustContain": "lang=\"en\""
},
{
"path": "/nl/not-found",
"status": 404
},
{
"path": "/nl/not-found",
"mustContain": "lang=\"nl\""
},
{
"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.json",
"status": 200,
"mustContain": "\"locale\":\"en-US\""
},
{
"path": "/_next/data/testing-build-id/en.json",
"status": 200,
"mustContain": "\"locale\":\"en\""
},
{
"path": "/_next/data/testing-build-id/fr.json",
"status": 200,
"mustContain": "\"locale\":\"fr\""
},
{
"path": "/_next/data/testing-build-id/nl.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\""
},
{
"path": "/en-US/redirect-1",
"fetchOptions": {
"redirect": "manual"
},
"status": 307,
"responseHeaders": {
"location": "//somewhere-else/"
}
},
{
"path": "/en/redirect-1",
"fetchOptions": {
"redirect": "manual"
},
"status": 404
},
{
"path": "/nl/redirect-2",
"fetchOptions": {
"redirect": "manual"
},
"status": 307,
"responseHeaders": {
"location": "//somewhere-else/"
}
},
{
"path": "/en-US/redirect-2",
"fetchOptions": {
"redirect": "manual"
},
"status": 404
},
{
"path": "/redirect-3",
"fetchOptions": {
"redirect": "manual"
},
"status": 307,
"responseHeaders": {
"location": "//somewhere-else/"
}
},
{
"path": "/en-US/redirect-3",
"fetchOptions": {
"redirect": "manual"
},
"status": 307,
"responseHeaders": {
"location": "//somewhere-else/"
}
},
{
"path": "/fr/redirect-3",
"fetchOptions": {
"redirect": "manual"
},
"status": 307,
"responseHeaders": {
"location": "//somewhere-else/"
}
},
{
"path": "/nl-NL/redirect-3",
"fetchOptions": {
"redirect": "manual"
},
"status": 307,
"responseHeaders": {
"location": "//somewhere-else/"
}
},
{
"path": "/en-US/rewrite-1",
"fetchOptions": {
"redirect": "manual"
},
"status": 200,
"mustContain": "another page"
},
{
"path": "/en-US/rewrite-1",
"fetchOptions": {
"redirect": "manual"
},
"status": 200,
"mustContain": "lang=\"en-US\""
},
{
"path": "/nl/rewrite-1",
"fetchOptions": {
"redirect": "manual"
},
"status": 404
},
{
"path": "/nl/rewrite-2",
"fetchOptions": {
"redirect": "manual"
},
"status": 200,
"mustContain": "another page"
},
{
"path": "/nl/rewrite-2",
"fetchOptions": {
"redirect": "manual"
},
"status": 200,
"mustContain": "lang=\"nl\""
},
{
"path": "/rewrite-2",
"fetchOptions": {
"redirect": "manual"
},
"status": 404
},
{
"path": "/fr/rewrite-3",
"fetchOptions": {
"redirect": "manual"
},
"status": 200,
"mustContain": "another page"
},
{
"path": "/fr/rewrite-3",
"fetchOptions": {
"redirect": "manual"
},
"status": 200,
"mustContain": "lang=\"nl\""
},
{
"path": "/rewrite-3",
"fetchOptions": {
"redirect": "manual"
},
"status": 404
},
{
"path": "/rewrite-4",
"fetchOptions": {
"redirect": "manual"
},
"status": 200,
"mustContain": "another page"
},
{
"path": "/rewrite-4",
"fetchOptions": {
"redirect": "manual"
},
"status": 200,
"mustContain": "lang=\"en-US\""
},
{
"path": "/en/rewrite-4",
"fetchOptions": {
"redirect": "manual"
},
"status": 200,
"mustContain": "another page"
},
{
"path": "/en/rewrite-4",
"fetchOptions": {
"redirect": "manual"
},
"status": 200,
"mustContain": "lang=\"en\""
},
{
"path": "/fr/rewrite-4",
"fetchOptions": {
"redirect": "manual"
},
"status": 200,
"mustContain": "another page"
},
{
"path": "/fr/rewrite-4",
"fetchOptions": {
"redirect": "manual"
},
"status": 200,
"mustContain": "lang=\"fr\""
},
{
"path": "/en-US/add-header-1",
"fetchOptions": {
"redirect": "manual"
},
"status": 404,
"responseHeaders": {
"x-hello": "world"
}
},
{
"path": "/en/add-header-1",
"fetchOptions": {
"redirect": "manual"
},
"status": 404,
"responseHeaders": {
"x-hello": null
}
},
{
"path": "/nl/add-header-2",
"fetchOptions": {
"redirect": "manual"
},
"status": 404,
"responseHeaders": {
"x-hello": "world"
}
},
{
"path": "/en-US/add-header-2",
"fetchOptions": {
"redirect": "manual"
},
"status": 404,
"responseHeaders": {
"x-hello": null
}
},
{
"path": "/add-header-3",
"fetchOptions": {
"redirect": "manual"
},
"status": 404,
"responseHeaders": {
"x-hello": "world"
}
},
{
"path": "/en-US/add-header-3",
"fetchOptions": {
"redirect": "manual"
},
"status": 404,
"responseHeaders": {
"x-hello": "world"
}
},
{
"path": "/fr/add-header-3",
"fetchOptions": {
"redirect": "manual"
},
"status": 404,
"responseHeaders": {
"x-hello": "world"
}
},
{
"path": "/nl-NL/add-header-3",
"fetchOptions": {
"redirect": "manual"
},
"status": 404,
"responseHeaders": {
"x-hello": "world"
}
}
]
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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: {},
};
};

View File

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

View File

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

View File

@@ -1 +0,0 @@
hello world!

View File

@@ -1,109 +0,0 @@
/* eslint-env jest */
const fetch = require('../../../../../test/lib/deployment/fetch-retry');
const cheerio = require('cheerio');
const { waitFor, check } = require('../../utils');
module.exports = function (ctx) {
const getProps = async path => {
const html = await fetch(`${ctx.deploymentUrl}/${path}`).then(res =>
res.text()
);
const $ = cheerio.load(html);
return JSON.parse($('#props').text());
};
const getInitialData = async path => {
return fetch(
`${ctx.deploymentUrl}/_next/data/testing-build-id${path}.json`
).then(res => res.json());
};
async function checkForChange(url, initialValue, hardError) {
return check(
async () => {
const props = await getProps(url);
if (isNaN(props.random)) {
throw new Error(`Invalid random value ${props.random}`);
}
const newValue = props.random;
return initialValue !== newValue ? 'success' : 'fail';
},
'success',
hardError
);
}
it('should render / correctly', async () => {
const props = await getInitialData('');
expect(props.pageProps.params).toEqual({});
await waitFor(2000);
await getProps('/');
const newProps = await getProps('/');
expect(newProps.params).toEqual({});
await checkForChange('/', props.pageProps.random);
});
it('should render /a correctly', async () => {
const props = await getInitialData('/a');
expect(props.pageProps.params).toEqual({ slug: ['a'] });
await waitFor(2000);
await getProps('/a');
const newProps = await getProps('/a');
expect(newProps.params).toEqual({ slug: ['a'] });
await checkForChange('/a', props.pageProps.random);
});
it('should render /hello/world correctly', async () => {
const props = await getInitialData('/hello/world');
expect(props.pageProps.params).toEqual({ slug: ['hello', 'world'] });
await waitFor(2000);
await getProps('/hello/world');
const newProps = await getProps('/hello/world');
expect(newProps.params).toEqual({ slug: ['hello', 'world'] });
await checkForChange('/hello/world', props.pageProps.random);
});
it('should render /posts correctly', async () => {
const props = await getInitialData('/posts');
expect(props.pageProps.params).toEqual({});
await waitFor(2000);
await getProps('/posts');
const newProps = await getProps('/posts');
expect(newProps.params).toEqual({});
await checkForChange('/posts', props.pageProps.random);
});
it('should render /posts/a correctly', async () => {
const props = await getInitialData('/posts/a');
expect(props.pageProps.params).toEqual({ slug: ['a'] });
await waitFor(2000);
await getProps('/posts/a');
const newProps = await getProps('/posts/a');
expect(newProps.params).toEqual({ slug: ['a'] });
await checkForChange('/posts/a', props.pageProps.random);
});
it('should render /posts/hello/world correctly', async () => {
const props = await getInitialData('/posts/hello/world');
expect(props.pageProps.params).toEqual({ slug: ['hello', 'world'] });
await waitFor(2000);
await getProps('/posts/hello/world');
const newProps = await getProps('/posts/hello/world');
expect(newProps.params).toEqual({ slug: ['hello', 'world'] });
await checkForChange('/posts/hello/world', props.pageProps.random);
});
};

View File

@@ -1,5 +0,0 @@
module.exports = {
generateBuildId() {
return 'testing-build-id';
},
};

View File

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

View File

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

View File

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

View File

@@ -1,9 +0,0 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/next"
}
]
}

View File

@@ -1,39 +0,0 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/next",
"config": {
"outputDirectory": "web/.next"
}
}
],
"probes": [
{
"path": "/",
"status": 200,
"mustContain": "Index page"
},
{
"path": "/dynamic/first",
"status": 200,
"mustContain": "Dynamic Page"
},
{
"path": "/dynamic-ssr/second",
"status": 200,
"mustContain": "Dynamic SSR Page"
},
{
"path": "/hello.txt",
"status": 200,
"mustContain": "hello world!"
},
{
"path": "/public/data.txt",
"status": 200,
"mustContain": "data!!"
}
]
}

View File

@@ -1,10 +0,0 @@
{
"scripts": {
"build": "next build web"
},
"dependencies": {
"next": "canary",
"react": "^16.8.6",
"react-dom": "^16.8.6"
}
}

View File

@@ -1,12 +0,0 @@
export function getServerSideProps() {
return {
props: {
hello: 'world',
random: Math.random(),
},
};
}
export default function Dynamic() {
return <p>Dynamic SSR Page</p>;
}

View File

@@ -1,3 +0,0 @@
export default function Dynamic() {
return <p>Dynamic Page</p>;
}

View File

@@ -1,3 +0,0 @@
export default function Index() {
return <p>Index page</p>;
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +0,0 @@
module.exports = {
generateBuildId() {
return 'testing-build-id';
},
};

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