mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-25 19:00:01 +00:00
Compare commits
13 Commits
@vercel/ne
...
@vercel/ne
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6700630feb | ||
|
|
34cd8b4144 | ||
|
|
ad0ed6d852 | ||
|
|
0bad09b47a | ||
|
|
5120689bf2 | ||
|
|
5a39fd9242 | ||
|
|
352cd00ef0 | ||
|
|
abfe817f86 | ||
|
|
ebb5e2b208 | ||
|
|
e34858d082 | ||
|
|
f03c947f91 | ||
|
|
0d13fe7e34 | ||
|
|
4afec9d373 |
25
.github/workflows/cron-update-next.yml
vendored
Normal file
25
.github/workflows/cron-update-next.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Cron Update Next
|
||||
|
||||
on:
|
||||
# Run every 4 hours https://crontab.guru/every-4-hours
|
||||
schedule:
|
||||
- cron: '0 */4 * * *'
|
||||
|
||||
jobs:
|
||||
create-pull-request:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
# 0 means fetch all commits so we can commit and push in the script below
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Create Pull Request
|
||||
uses: actions/github-script@v6
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
# See https://github.com/actions/github-script#run-a-separate-file-with-an-async-function
|
||||
with:
|
||||
script: |
|
||||
const script = require('./utils/update-next.js')
|
||||
await script({ github, context })
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "5.3.1",
|
||||
"version": "5.3.2",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
|
||||
@@ -335,7 +335,6 @@ export interface ProjectSettings {
|
||||
directoryListing?: boolean;
|
||||
gitForkProtection?: boolean;
|
||||
commandForIgnoringBuildStep?: string | null;
|
||||
skipGitConnectDuringLink?: boolean;
|
||||
}
|
||||
|
||||
export interface BuilderV2 {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel",
|
||||
"version": "28.1.0",
|
||||
"version": "28.1.4",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Vercel",
|
||||
@@ -41,16 +41,16 @@
|
||||
"node": ">= 14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "5.3.1",
|
||||
"@vercel/go": "2.2.0",
|
||||
"@vercel/hydrogen": "0.0.14",
|
||||
"@vercel/next": "3.1.19",
|
||||
"@vercel/node": "2.5.8",
|
||||
"@vercel/python": "3.1.9",
|
||||
"@vercel/redwood": "1.0.18",
|
||||
"@vercel/remix": "1.0.19",
|
||||
"@vercel/ruby": "1.3.27",
|
||||
"@vercel/static-build": "1.0.18",
|
||||
"@vercel/build-utils": "5.3.2",
|
||||
"@vercel/go": "2.2.2",
|
||||
"@vercel/hydrogen": "0.0.15",
|
||||
"@vercel/next": "3.1.21",
|
||||
"@vercel/node": "2.5.10",
|
||||
"@vercel/python": "3.1.11",
|
||||
"@vercel/redwood": "1.0.19",
|
||||
"@vercel/remix": "1.0.20",
|
||||
"@vercel/ruby": "1.3.28",
|
||||
"@vercel/static-build": "1.0.19",
|
||||
"update-notifier": "5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -96,7 +96,7 @@
|
||||
"@types/which": "1.3.2",
|
||||
"@types/write-json-file": "2.2.1",
|
||||
"@types/yauzl-promise": "2.1.0",
|
||||
"@vercel/client": "12.2.0",
|
||||
"@vercel/client": "12.2.1",
|
||||
"@vercel/frameworks": "1.1.3",
|
||||
"@vercel/fs-detectors": "2.0.5",
|
||||
"@vercel/fun": "1.0.4",
|
||||
|
||||
@@ -58,9 +58,9 @@ export async function connectGitProvider(
|
||||
(err.action === 'Install GitHub App' || err.code === 'repo_not_found')
|
||||
) {
|
||||
client.output.error(
|
||||
`Failed to link ${chalk.cyan(
|
||||
`Failed to connect ${chalk.cyan(
|
||||
repo
|
||||
)}. Make sure there aren't any typos and that you have access to the repository if it's private.`
|
||||
)} to project. Make sure there aren't any typos and that you have access to the repository if it's private.`
|
||||
);
|
||||
} else if (apiError && err.action === 'Add a Login Connection') {
|
||||
client.output.error(
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
import { Dictionary } from '@vercel/client';
|
||||
import { parseRepoUrl } from '../git/connect-git-provider';
|
||||
import Client from '../client';
|
||||
import { Org, Project, ProjectSettings } from '../../types';
|
||||
import { handleOptions } from './handle-options';
|
||||
import {
|
||||
promptGitConnectMultipleUrls,
|
||||
promptGitConnectSingleUrl,
|
||||
} from './git-connect-prompts';
|
||||
|
||||
function getProjectSettings(project: Project): ProjectSettings {
|
||||
return {
|
||||
createdAt: project.createdAt,
|
||||
framework: project.framework,
|
||||
devCommand: project.devCommand,
|
||||
installCommand: project.installCommand,
|
||||
buildCommand: project.buildCommand,
|
||||
outputDirectory: project.outputDirectory,
|
||||
rootDirectory: project.rootDirectory,
|
||||
directoryListing: project.directoryListing,
|
||||
nodeVersion: project.nodeVersion,
|
||||
skipGitConnectDuringLink: project.skipGitConnectDuringLink,
|
||||
};
|
||||
}
|
||||
|
||||
export async function addGitConnection(
|
||||
client: Client,
|
||||
org: Org,
|
||||
project: Project,
|
||||
remoteUrls: Dictionary<string>,
|
||||
autoConfirm: Boolean,
|
||||
settings?: ProjectSettings
|
||||
): Promise<number | void> {
|
||||
if (!settings) {
|
||||
settings = getProjectSettings(project);
|
||||
}
|
||||
if (Object.keys(remoteUrls).length === 1) {
|
||||
return addSingleGitRemote(
|
||||
client,
|
||||
org,
|
||||
project,
|
||||
remoteUrls,
|
||||
settings || project,
|
||||
autoConfirm
|
||||
);
|
||||
} else if (Object.keys(remoteUrls).length > 1 && !project.link) {
|
||||
return addMultipleGitRemotes(
|
||||
client,
|
||||
org,
|
||||
project,
|
||||
remoteUrls,
|
||||
settings || project,
|
||||
autoConfirm
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function addSingleGitRemote(
|
||||
client: Client,
|
||||
org: Org,
|
||||
project: Project,
|
||||
remoteUrls: Dictionary<string>,
|
||||
settings: ProjectSettings,
|
||||
autoConfirm: Boolean
|
||||
) {
|
||||
const [remoteName, remoteUrl] = Object.entries(remoteUrls)[0];
|
||||
const repoInfo = parseRepoUrl(remoteUrl);
|
||||
if (!repoInfo) {
|
||||
client.output.debug(`Could not parse repo url ${repoInfo}.`);
|
||||
return 1;
|
||||
}
|
||||
const { org: parsedOrg, repo, provider } = repoInfo;
|
||||
const alreadyLinked =
|
||||
project.link &&
|
||||
project.link.org === parsedOrg &&
|
||||
project.link.repo === repo &&
|
||||
project.link.type === provider;
|
||||
if (alreadyLinked) {
|
||||
client.output.debug('Project already linked. Skipping...');
|
||||
return;
|
||||
}
|
||||
|
||||
const replace =
|
||||
project.link &&
|
||||
(project.link.org !== parsedOrg ||
|
||||
project.link.repo !== repo ||
|
||||
project.link.type !== provider);
|
||||
|
||||
let shouldConnectOption: string | undefined;
|
||||
if (autoConfirm) {
|
||||
shouldConnectOption = 'yes';
|
||||
} else {
|
||||
shouldConnectOption = await promptGitConnectSingleUrl(
|
||||
client,
|
||||
project,
|
||||
remoteName,
|
||||
remoteUrl,
|
||||
replace
|
||||
);
|
||||
}
|
||||
return handleOptions(
|
||||
shouldConnectOption,
|
||||
client,
|
||||
org,
|
||||
project,
|
||||
settings,
|
||||
repoInfo
|
||||
);
|
||||
}
|
||||
|
||||
async function addMultipleGitRemotes(
|
||||
client: Client,
|
||||
org: Org,
|
||||
project: Project,
|
||||
remoteUrls: Dictionary<string>,
|
||||
settings: ProjectSettings,
|
||||
autoConfirm: Boolean
|
||||
) {
|
||||
let remoteUrl: string | undefined;
|
||||
if (autoConfirm) {
|
||||
remoteUrl = remoteUrls['origin'] || Object.values(remoteUrls)[0];
|
||||
} else {
|
||||
client.output.log('Found multiple Git remote URLs in Git config.');
|
||||
remoteUrl = await promptGitConnectMultipleUrls(client, remoteUrls);
|
||||
}
|
||||
return handleOptions(remoteUrl, client, org, project, settings);
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
import { Dictionary } from '@vercel/client';
|
||||
import chalk from 'chalk';
|
||||
import { Project } from '../../types';
|
||||
import Client from '../client';
|
||||
import { formatProvider } from '../git/connect-git-provider';
|
||||
import list from '../input/list';
|
||||
export async function promptGitConnectSingleUrl(
|
||||
client: Client,
|
||||
project: Project,
|
||||
remoteName: string,
|
||||
remoteUrl: string,
|
||||
hasDiffConnectedProvider = false
|
||||
) {
|
||||
const { output } = client;
|
||||
if (hasDiffConnectedProvider) {
|
||||
const currentRepoPath = `${project.link!.org}/${project.link!.repo}`;
|
||||
const currentProvider = project.link!.type;
|
||||
output.print('\n');
|
||||
output.log(
|
||||
`Found Git remote URL ${chalk.cyan(
|
||||
remoteUrl
|
||||
)}, which is different from the connected ${formatProvider(
|
||||
currentProvider
|
||||
)} repository ${chalk.cyan(currentRepoPath)}.`
|
||||
);
|
||||
} else {
|
||||
output.print('\n');
|
||||
output.log(
|
||||
`Found local Git remote "${remoteName}": ${chalk.cyan(remoteUrl)}`
|
||||
);
|
||||
}
|
||||
return await list(client, {
|
||||
message: hasDiffConnectedProvider
|
||||
? 'Do you want to replace it?'
|
||||
: `Do you want to connect "${remoteName}" to your Vercel project?`,
|
||||
choices: [
|
||||
{
|
||||
name: 'Yes',
|
||||
value: 'yes',
|
||||
short: 'yes',
|
||||
},
|
||||
{
|
||||
name: 'No',
|
||||
value: 'no',
|
||||
short: 'no',
|
||||
},
|
||||
{
|
||||
name: 'Do not ask again for this project',
|
||||
value: 'opt-out',
|
||||
short: 'no (opt out)',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
export async function promptGitConnectMultipleUrls(
|
||||
client: Client,
|
||||
remoteUrls: Dictionary<string>
|
||||
) {
|
||||
const staticOptions = [
|
||||
{
|
||||
name: 'No',
|
||||
value: 'no',
|
||||
short: 'no',
|
||||
},
|
||||
{
|
||||
name: 'Do not ask again for this project',
|
||||
value: 'opt-out',
|
||||
short: 'no (opt out)',
|
||||
},
|
||||
];
|
||||
let choices = [];
|
||||
for (const url of Object.values(remoteUrls)) {
|
||||
choices.push({
|
||||
name: url,
|
||||
value: url,
|
||||
short: url,
|
||||
});
|
||||
}
|
||||
choices = choices.concat(staticOptions);
|
||||
|
||||
return await list(client, {
|
||||
message: 'Do you want to connect a Git repository to your Vercel project?',
|
||||
choices,
|
||||
});
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
import chalk from 'chalk';
|
||||
import { Org, Project, ProjectSettings } from '../../types';
|
||||
import Client from '../client';
|
||||
import {
|
||||
connectGitProvider,
|
||||
disconnectGitProvider,
|
||||
formatProvider,
|
||||
RepoInfo,
|
||||
parseRepoUrl,
|
||||
} from '../git/connect-git-provider';
|
||||
import { Output } from '../output';
|
||||
import { getCommandName } from '../pkg-name';
|
||||
import updateProject from '../projects/update-project';
|
||||
|
||||
export async function handleOptions(
|
||||
option: string,
|
||||
client: Client,
|
||||
org: Org,
|
||||
project: Project,
|
||||
settings: ProjectSettings,
|
||||
repoInfo?: RepoInfo
|
||||
) {
|
||||
const { output } = client;
|
||||
if (option === 'no') {
|
||||
skip(output);
|
||||
return;
|
||||
} else if (option === 'opt-out') {
|
||||
optOut(client, project, settings);
|
||||
return;
|
||||
} else if (option !== '') {
|
||||
// Option is "yes" or a URL
|
||||
|
||||
// Ensure parsed url exists
|
||||
if (!repoInfo) {
|
||||
const _repoInfo = parseRepoUrl(option);
|
||||
if (!_repoInfo) {
|
||||
output.debug(`Could not parse repo url ${option}.`);
|
||||
return 1;
|
||||
}
|
||||
repoInfo = _repoInfo;
|
||||
}
|
||||
return connect(client, org, project, repoInfo);
|
||||
}
|
||||
}
|
||||
|
||||
async function optOut(
|
||||
client: Client,
|
||||
project: Project,
|
||||
settings: ProjectSettings
|
||||
) {
|
||||
settings.skipGitConnectDuringLink = true;
|
||||
await updateProject(client, project.name, settings);
|
||||
client.output
|
||||
.log(`Opted out. You can re-enable this prompt by visiting the Settings > Git page on the
|
||||
dashboard for this Project.`);
|
||||
}
|
||||
|
||||
function skip(output: Output) {
|
||||
output.log('Skipping...');
|
||||
output.log(
|
||||
`You can connect a Git repository in the future by running ${getCommandName(
|
||||
'git connect'
|
||||
)}.`
|
||||
);
|
||||
}
|
||||
|
||||
async function connect(
|
||||
client: Client,
|
||||
org: Org,
|
||||
project: Project,
|
||||
repoInfo: RepoInfo
|
||||
): Promise<number | void> {
|
||||
const { output } = client;
|
||||
const { provider, org: parsedOrg, repo } = repoInfo;
|
||||
const repoPath = `${parsedOrg}/${repo}`;
|
||||
|
||||
output.log('Connecting...');
|
||||
|
||||
if (project.link) {
|
||||
await disconnectGitProvider(client, org, project.id);
|
||||
}
|
||||
const connect = await connectGitProvider(
|
||||
client,
|
||||
org,
|
||||
project.id,
|
||||
provider,
|
||||
repoPath
|
||||
);
|
||||
if (connect !== 1) {
|
||||
output.log(
|
||||
`Connected ${formatProvider(provider)} repository ${chalk.cyan(
|
||||
repoPath
|
||||
)}!`
|
||||
);
|
||||
} else {
|
||||
return connect;
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,6 @@ import { EmojiLabel } from '../emoji';
|
||||
import createDeploy from '../deploy/create-deploy';
|
||||
import Now, { CreateOptions } from '../index';
|
||||
import { isAPIError } from '../errors-ts';
|
||||
import { getRemoteUrls } from '../create-git-meta';
|
||||
import { addGitConnection } from './add-git-connection';
|
||||
|
||||
export interface SetupAndLinkOptions {
|
||||
forceDelete?: boolean;
|
||||
@@ -130,20 +128,6 @@ export default async function setupAndLink(
|
||||
} else {
|
||||
const project = projectOrNewProjectName;
|
||||
|
||||
const remoteUrls = await getRemoteUrls(join(path, '.git/config'), output);
|
||||
if (remoteUrls && !project.skipGitConnectDuringLink) {
|
||||
const connectGit = await addGitConnection(
|
||||
client,
|
||||
org,
|
||||
project,
|
||||
remoteUrls,
|
||||
autoConfirm
|
||||
);
|
||||
if (typeof connectGit === 'number') {
|
||||
return { status: 'error', exitCode: connectGit };
|
||||
}
|
||||
}
|
||||
|
||||
await linkFolderToProject(
|
||||
output,
|
||||
path,
|
||||
@@ -258,21 +242,6 @@ export default async function setupAndLink(
|
||||
|
||||
const project = await createProject(client, newProjectName);
|
||||
|
||||
const remoteUrls = await getRemoteUrls(join(path, '.git/config'), output);
|
||||
if (remoteUrls) {
|
||||
const connectGit = await addGitConnection(
|
||||
client,
|
||||
org,
|
||||
project,
|
||||
remoteUrls,
|
||||
autoConfirm,
|
||||
settings
|
||||
);
|
||||
if (typeof connectGit === 'number') {
|
||||
return { status: 'error', exitCode: connectGit };
|
||||
}
|
||||
}
|
||||
|
||||
await updateProject(client, project.id, settings);
|
||||
Object.assign(project, settings);
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import mod from '../increment.wasm?module';
|
||||
|
||||
export const config = { runtime: 'experimental-edge' };
|
||||
|
||||
const init$ = WebAssembly.instantiate(mod);
|
||||
|
||||
/** @param {Request} req */
|
||||
export default async req => {
|
||||
const givenNumber = Number(new URL(req.url).searchParams.get('number') || 0);
|
||||
const { exports } = await init$;
|
||||
const added = exports.add_one(givenNumber);
|
||||
return new Response(`${givenNumber} + 1 = ${added}`);
|
||||
};
|
||||
BIN
packages/cli/test/dev/fixtures/edge-function/increment.wasm
Executable file
BIN
packages/cli/test/dev/fixtures/edge-function/increment.wasm
Executable file
Binary file not shown.
@@ -53,6 +53,33 @@ test('[vercel dev] should support edge functions', async () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('[vercel dev] edge functions support WebAssembly files', async () => {
|
||||
const dir = fixture('edge-function');
|
||||
const { dev, port, readyResolver } = await testFixture(dir, {
|
||||
env: {
|
||||
ENV_VAR_IN_EDGE: '1',
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
await readyResolver;
|
||||
|
||||
for (const { number, result } of [
|
||||
{ number: 1, result: 2 },
|
||||
{ number: 2, result: 3 },
|
||||
{ number: 12, result: 13 },
|
||||
]) {
|
||||
let res = await fetch(
|
||||
`http://localhost:${port}/api/webassembly?number=${number}`
|
||||
);
|
||||
validateResponseHeaders(res);
|
||||
await expect(res.text()).resolves.toEqual(`${number} + 1 = ${result}`);
|
||||
}
|
||||
} finally {
|
||||
await dev.kill('SIGTERM');
|
||||
}
|
||||
});
|
||||
|
||||
test(
|
||||
'[vercel dev] edge functions respond properly the same as production',
|
||||
testFixtureStdio('edge-function', async (testPath: any) => {
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
!.vercel
|
||||
.vercel
|
||||
@@ -1,16 +0,0 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
||||
ignorecase = true
|
||||
precomposeunicode = true
|
||||
[remote "secondary"]
|
||||
url = https://github.com/user2/repo2.git
|
||||
fetch = +refs/heads/*:refs/remotes/secondary/*
|
||||
[remote "origin"]
|
||||
url = https://github.com/user/repo.git
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||
[remote "gitlab"]
|
||||
url = https://gitlab.com/user/repo.git
|
||||
fetch = +refs/heads/*:refs/remotes/gitlab/*
|
||||
@@ -1,2 +0,0 @@
|
||||
!.vercel
|
||||
.vercel
|
||||
16
packages/cli/test/fixtures/unit/link-connect-git/multiple-remotes/git/config
generated
vendored
16
packages/cli/test/fixtures/unit/link-connect-git/multiple-remotes/git/config
generated
vendored
@@ -1,16 +0,0 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
||||
ignorecase = true
|
||||
precomposeunicode = true
|
||||
[remote "origin"]
|
||||
url = https://github.com/user/repo.git
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||
[remote "secondary"]
|
||||
url = https://github.com/user2/repo2.git
|
||||
fetch = +refs/heads/*:refs/remotes/secondary/*
|
||||
[remote "gitlab"]
|
||||
url = https://gitlab.com/user/repo.git
|
||||
fetch = +refs/heads/*:refs/remotes/gitlab/*
|
||||
@@ -1,2 +0,0 @@
|
||||
!.vercel
|
||||
.vercel
|
||||
13
packages/cli/test/fixtures/unit/link-connect-git/single-remote-existing-link/git/config
generated
vendored
13
packages/cli/test/fixtures/unit/link-connect-git/single-remote-existing-link/git/config
generated
vendored
@@ -1,13 +0,0 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
||||
ignorecase = true
|
||||
precomposeunicode = true
|
||||
[remote "origin"]
|
||||
url = https://github.com/user2/repo2.git
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||
[branch "master"]
|
||||
remote = origin
|
||||
merge = refs/heads/master
|
||||
@@ -1,2 +0,0 @@
|
||||
!.vercel
|
||||
.vercel
|
||||
13
packages/cli/test/fixtures/unit/link-connect-git/single-remote/git/config
generated
vendored
13
packages/cli/test/fixtures/unit/link-connect-git/single-remote/git/config
generated
vendored
@@ -1,13 +0,0 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
||||
ignorecase = true
|
||||
precomposeunicode = true
|
||||
[remote "origin"]
|
||||
url = https://github.com/user/repo.git
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||
[branch "master"]
|
||||
remote = origin
|
||||
merge = refs/heads/master
|
||||
@@ -39,11 +39,6 @@ describe('git', () => {
|
||||
await expect(client.stderr).toOutput('Found project');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
'Do you want to connect "origin" to your Vercel project?'
|
||||
);
|
||||
client.stdin.write('n\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
`Connecting Git remote: https://github.com/user/repo.git`
|
||||
);
|
||||
@@ -295,7 +290,7 @@ describe('git', () => {
|
||||
`Connecting Git remote: https://github.com/laksfj/asdgklsadkl`
|
||||
);
|
||||
await expect(client.stderr).toOutput(
|
||||
`Failed to link laksfj/asdgklsadkl. Make sure there aren't any typos and that you have access to the repository if it's private.`
|
||||
`Failed to connect laksfj/asdgklsadkl to project. Make sure there aren't any typos and that you have access to the repository if it's private.`
|
||||
);
|
||||
|
||||
const exitCode = await gitPromise;
|
||||
|
||||
@@ -1,357 +0,0 @@
|
||||
import { join } from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import link from '../../../src/commands/link';
|
||||
import { useUser } from '../../mocks/user';
|
||||
import { useTeams } from '../../mocks/team';
|
||||
import {
|
||||
defaultProject,
|
||||
useUnknownProject,
|
||||
useProject,
|
||||
} from '../../mocks/project';
|
||||
import { client } from '../../mocks/client';
|
||||
import { useDeploymentMissingProjectSettings } from '../../mocks/deployment';
|
||||
import { Project } from '../../../src/types';
|
||||
|
||||
describe('link', () => {
|
||||
describe('git prompt', () => {
|
||||
const originalCwd = process.cwd();
|
||||
const fixture = (name: string) =>
|
||||
join(__dirname, '../../fixtures/unit/link-connect-git', name);
|
||||
|
||||
it('should prompt to connect a new project with a single remote', async () => {
|
||||
const cwd = fixture('single-remote');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
useUser();
|
||||
useUnknownProject();
|
||||
useDeploymentMissingProjectSettings();
|
||||
useTeams('team_dummy');
|
||||
const linkPromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput('Set up');
|
||||
client.stdin.write('y\n');
|
||||
await expect(client.stderr).toOutput('Which scope');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Link to existing project?');
|
||||
client.stdin.write('n\n');
|
||||
await expect(client.stderr).toOutput('What’s your project’s name?');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput(
|
||||
'In which directory is your code located?'
|
||||
);
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Want to modify these settings?');
|
||||
client.stdin.write('n\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
'Found local Git remote "origin": https://github.com/user/repo.git'
|
||||
);
|
||||
await expect(client.stderr).toOutput(
|
||||
'Do you want to connect "origin" to your Vercel project?'
|
||||
);
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput(
|
||||
'Connected GitHub repository user/repo!'
|
||||
);
|
||||
await expect(client.stderr).toOutput('Linked to');
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
|
||||
it('should prompt to connect an existing project with a single remote to git', async () => {
|
||||
const cwd = fixture('single-remote');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
useUser();
|
||||
useProject({
|
||||
...defaultProject,
|
||||
name: 'single-remote',
|
||||
id: 'single-remote',
|
||||
});
|
||||
useTeams('team_dummy');
|
||||
const linkPromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput('Set up');
|
||||
client.stdin.write('y\n');
|
||||
await expect(client.stderr).toOutput('Which scope');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Found project');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
'Found local Git remote "origin": https://github.com/user/repo.git'
|
||||
);
|
||||
await expect(client.stderr).toOutput(
|
||||
'Do you want to connect "origin" to your Vercel project?'
|
||||
);
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput(
|
||||
'Connected GitHub repository user/repo!'
|
||||
);
|
||||
await expect(client.stderr).toOutput('Linked to');
|
||||
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
it('should prompt to replace a connected repository if there is one remote', async () => {
|
||||
const cwd = fixture('single-remote-existing-link');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
useUser();
|
||||
const project = useProject({
|
||||
...defaultProject,
|
||||
name: 'single-remote-existing-link',
|
||||
id: 'single-remote-existing-link',
|
||||
});
|
||||
useTeams('team_dummy');
|
||||
project.project.link = {
|
||||
type: 'github',
|
||||
org: 'user',
|
||||
repo: 'repo',
|
||||
repoId: 1010,
|
||||
gitCredentialId: '',
|
||||
sourceless: true,
|
||||
createdAt: 1656109539791,
|
||||
updatedAt: 1656109539791,
|
||||
};
|
||||
|
||||
const linkPromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput('Set up');
|
||||
client.stdin.write('y\n');
|
||||
await expect(client.stderr).toOutput('Which scope');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Found project');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
`Found Git remote URL https://github.com/user2/repo2.git, which is different from the connected GitHub repository user/repo.`
|
||||
);
|
||||
await expect(client.stderr).toOutput('Do you want to replace it?');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput(
|
||||
'Connected GitHub repository user2/repo2!'
|
||||
);
|
||||
await expect(client.stderr).toOutput('Linked to');
|
||||
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
it('should prompt to connect an existing project with multiple remotes', async () => {
|
||||
const cwd = fixture('multiple-remotes');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
|
||||
useUser();
|
||||
useProject({
|
||||
...defaultProject,
|
||||
name: 'multiple-remotes',
|
||||
id: 'multiple-remotes',
|
||||
});
|
||||
useTeams('team_dummy');
|
||||
|
||||
const linkPromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput('Set up');
|
||||
client.stdin.write('y\n');
|
||||
await expect(client.stderr).toOutput('Which scope');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Found project');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
`> Do you want to connect a Git repository to your Vercel project?`
|
||||
);
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput(
|
||||
'Connected GitHub repository user/repo!'
|
||||
);
|
||||
await expect(client.stderr).toOutput('Linked to');
|
||||
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
it('should not prompt to replace a connected repository if there is more than one remote', async () => {
|
||||
const cwd = fixture('multiple-remotes');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
|
||||
useUser();
|
||||
const project = useProject({
|
||||
...defaultProject,
|
||||
name: 'multiple-remotes',
|
||||
id: 'multiple-remotes',
|
||||
});
|
||||
useTeams('team_dummy');
|
||||
project.project.link = {
|
||||
type: 'github',
|
||||
org: 'user',
|
||||
repo: 'repo',
|
||||
repoId: 1010,
|
||||
gitCredentialId: '',
|
||||
sourceless: true,
|
||||
createdAt: 1656109539791,
|
||||
updatedAt: 1656109539791,
|
||||
};
|
||||
|
||||
const linkPromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput('Set up');
|
||||
client.stdin.write('y\n');
|
||||
await expect(client.stderr).toOutput('Which scope');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Found project');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
expect(client.stderr).not.toOutput('Found multiple Git remote URLs');
|
||||
await expect(client.stderr).toOutput('Linked to');
|
||||
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
it('should set a project setting if user opts out', async () => {
|
||||
const cwd = fixture('single-remote');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
|
||||
useUser();
|
||||
useProject({
|
||||
...defaultProject,
|
||||
name: 'single-remote',
|
||||
id: 'single-remote',
|
||||
});
|
||||
useTeams('team_dummy');
|
||||
const linkPromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput('Set up');
|
||||
client.stdin.write('y\n');
|
||||
await expect(client.stderr).toOutput('Which scope');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Found project');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
await expect(client.stderr).toOutput(
|
||||
'Found local Git remote "origin": https://github.com/user/repo.git'
|
||||
);
|
||||
await expect(client.stderr).toOutput(
|
||||
'Do you want to connect "origin" to your Vercel project?'
|
||||
);
|
||||
client.stdin.write('\x1B[B'); // Down arrow
|
||||
client.stdin.write('\x1B[B');
|
||||
client.stdin.write('\r'); // Opt out
|
||||
|
||||
await expect(client.stderr).toOutput(`Opted out.`);
|
||||
await expect(client.stderr).toOutput('Linked to');
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
|
||||
const newProjectData: Project = await client.fetch(
|
||||
`/v8/projects/single-remote`
|
||||
);
|
||||
expect(newProjectData.skipGitConnectDuringLink).toBeTruthy();
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
it('should not prompt to connect git if the project has skipGitConnectDuringLink property', async () => {
|
||||
const cwd = fixture('single-remote');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
|
||||
useUser();
|
||||
const project = useProject({
|
||||
...defaultProject,
|
||||
name: 'single-remote',
|
||||
id: 'single-remote',
|
||||
});
|
||||
useTeams('team_dummy');
|
||||
project.project.skipGitConnectDuringLink = true;
|
||||
const linkPromise = link(client);
|
||||
|
||||
await expect(client.stderr).toOutput('Set up');
|
||||
client.stdin.write('y\n');
|
||||
await expect(client.stderr).toOutput('Which scope');
|
||||
client.stdin.write('\r');
|
||||
await expect(client.stderr).toOutput('Found project');
|
||||
client.stdin.write('y\n');
|
||||
|
||||
expect(client.stderr).not.toOutput('Found local Git remote "origin"');
|
||||
|
||||
await expect(client.stderr).toOutput('Linked to');
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
it('should respect --yes', async () => {
|
||||
const cwd = fixture('single-remote');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
|
||||
useUser();
|
||||
useProject({
|
||||
...defaultProject,
|
||||
name: 'single-remote',
|
||||
id: 'single-remote',
|
||||
});
|
||||
useTeams('team_dummy');
|
||||
client.setArgv('--yes');
|
||||
const linkPromise = link(client);
|
||||
expect(client.stderr).not.toOutput('Do you want to connect "origin"');
|
||||
await expect(client.stderr).toOutput('Linked to');
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
it('should respect --yes for multiple remotes when origin is not the first', async () => {
|
||||
const cwd = fixture('multiple-remotes-prefer-origin');
|
||||
try {
|
||||
process.chdir(cwd);
|
||||
await fs.rename(join(cwd, 'git'), join(cwd, '.git'));
|
||||
useUser();
|
||||
useProject({
|
||||
...defaultProject,
|
||||
name: 'multiple-remotes-prefer-origin',
|
||||
id: 'multiple-remotes-prefer-origin',
|
||||
});
|
||||
useTeams('team_dummy');
|
||||
client.setArgv('--yes');
|
||||
const linkPromise = link(client);
|
||||
expect(client.stderr).not.toOutput('Found multiple Git remote URLs');
|
||||
await expect(client.stderr).toOutput(
|
||||
'Connected GitHub repository user/repo'
|
||||
);
|
||||
await expect(linkPromise).resolves.toEqual(0);
|
||||
} finally {
|
||||
await fs.rename(join(cwd, '.git'), join(cwd, 'git'));
|
||||
process.chdir(originalCwd);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/client",
|
||||
"version": "12.2.0",
|
||||
"version": "12.2.1",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"homepage": "https://vercel.com",
|
||||
@@ -43,7 +43,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "5.3.1",
|
||||
"@vercel/build-utils": "5.3.2",
|
||||
"@vercel/routing-utils": "2.0.2",
|
||||
"@zeit/fetch": "5.2.0",
|
||||
"async-retry": "1.2.3",
|
||||
|
||||
20
packages/go/go.mod
Normal file
20
packages/go/go.mod
Normal file
@@ -0,0 +1,20 @@
|
||||
module main
|
||||
|
||||
go 1.18
|
||||
|
||||
// This file exists to allow debugging of Go files within this package,
|
||||
// such as `util/analyze.go`.
|
||||
|
||||
// You can do this by creating a VS Code Launcher Configuration
|
||||
// replacing `YOUR_VERCEL_DIR` with your vercel directory, like:
|
||||
// {
|
||||
// "name": "Debug Go",
|
||||
// "type": "go",
|
||||
// "request": "launch",
|
||||
// "mode": "auto",
|
||||
// "program": "${fileDirname}",
|
||||
// "args": [
|
||||
// "-modpath=YOUR_VERCEL_DIR/packages/go/test/fixtures/24-bad-handler/api/",
|
||||
// "YOUR_VERCEL_DIR/packages/go/test/fixtures/24-bad-handler/api/index.go"
|
||||
// ]
|
||||
// }
|
||||
@@ -351,10 +351,7 @@ export async function build({
|
||||
|
||||
if (isGoModExist && isGoModInRootDir) {
|
||||
debug('[mod-root] Write main file to ' + downloadPath);
|
||||
await writeFile(
|
||||
join(downloadPath, mainGoFileName),
|
||||
mainModGoContents
|
||||
);
|
||||
await writeFile(join(downloadPath, mainGoFileName), mainModGoContents);
|
||||
undoFileActions.push({
|
||||
to: undefined, // delete
|
||||
from: join(downloadPath, mainGoFileName),
|
||||
@@ -534,8 +531,14 @@ export async function build({
|
||||
async function renameHandlerFunction(fsPath: string, from: string, to: string) {
|
||||
let fileContents = await readFile(fsPath, 'utf8');
|
||||
|
||||
const fromRegex = new RegExp(`\\b${from}\\b`, 'g');
|
||||
fileContents = fileContents.replace(fromRegex, to);
|
||||
// This regex has to walk a fine line where it replaces the most-likely occurrences
|
||||
// of the handler's identifier without clobbering other syntax.
|
||||
// Left-hand Side: A single space was chosen because it can catch `func Handler`
|
||||
// as well as `var _ http.HandlerFunc = Index`.
|
||||
// Right-hand Side: a word boundary was chosen because this can be an end of line
|
||||
// or an open paren (as in `func Handler(`).
|
||||
const fromRegex = new RegExp(String.raw` ${from}\b`, 'g');
|
||||
fileContents = fileContents.replace(fromRegex, ` ${to}`);
|
||||
|
||||
await writeFile(fsPath, fileContents);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/go",
|
||||
"version": "2.2.0",
|
||||
"version": "2.2.2",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
||||
@@ -35,7 +35,7 @@
|
||||
"@types/jest": "28.1.6",
|
||||
"@types/node-fetch": "^2.3.0",
|
||||
"@types/tar": "^4.0.0",
|
||||
"@vercel/build-utils": "5.3.1",
|
||||
"@vercel/build-utils": "5.3.2",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"async-retry": "1.3.1",
|
||||
"execa": "^1.0.0",
|
||||
|
||||
1
packages/go/test/fixtures/24-bad-handler/.gitignore
vendored
Normal file
1
packages/go/test/fixtures/24-bad-handler/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.vercel
|
||||
34
packages/go/test/fixtures/24-bad-handler/api/bad-receiver.go
vendored
Normal file
34
packages/go/test/fixtures/24-bad-handler/api/bad-receiver.go
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type SampleDecoder struct {
|
||||
}
|
||||
|
||||
type Servers struct {
|
||||
path string
|
||||
}
|
||||
|
||||
// the handler location logic looks for the first function that matches the proper signature;
|
||||
// this test makes sure that the BadReceiverHandler is not found because it is a receiver function
|
||||
|
||||
// this handler will not be found because it is a receiver function
|
||||
func (d *SampleDecoder) BadReceiverHandler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "from BadHandler")
|
||||
}
|
||||
|
||||
// this handler can be delegated to without being renamed
|
||||
func (s Servers) Handler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, s.path)
|
||||
}
|
||||
|
||||
// this handler will be found because it has the correct function signature
|
||||
func GoodHandler_api_bad_receiver_go(w http.ResponseWriter, r *http.Request) {
|
||||
server := Servers{"some/path"}
|
||||
|
||||
// this occurence of "Handler" should not be renamed
|
||||
server.Handler(w, r)
|
||||
}
|
||||
3
packages/go/test/fixtures/24-bad-handler/api/go.mod
vendored
Normal file
3
packages/go/test/fixtures/24-bad-handler/api/go.mod
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module handler
|
||||
|
||||
go 1.13
|
||||
8
packages/go/test/fixtures/24-bad-handler/probes.json
vendored
Normal file
8
packages/go/test/fixtures/24-bad-handler/probes.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"probes": [
|
||||
{
|
||||
"path": "/api/bad-receiver",
|
||||
"mustContain": "some/path"
|
||||
}
|
||||
]
|
||||
}
|
||||
1
packages/go/test/fixtures/24-bad-handler/vercel.json
vendored
Normal file
1
packages/go/test/fixtures/24-bad-handler/vercel.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -197,7 +197,9 @@ func main() {
|
||||
// find a valid `http.HandlerFunc` handler function
|
||||
params := rf[fn.Type.Params.Pos()-offset : fn.Type.Params.End()-offset]
|
||||
validHandlerFunc := (strings.Contains(string(params), "http.ResponseWriter") &&
|
||||
strings.Contains(string(params), "*http.Request") && len(fn.Type.Params.List) == 2)
|
||||
strings.Contains(string(params), "*http.Request") &&
|
||||
len(fn.Type.Params.List) == 2 &&
|
||||
(fn.Recv == nil || len(fn.Recv.List) == 0))
|
||||
|
||||
if validHandlerFunc {
|
||||
// we found the first exported function with `http.HandlerFunc`
|
||||
@@ -223,7 +225,7 @@ func main() {
|
||||
if fn.Name.IsExported() == true {
|
||||
for _, param := range fn.Type.Params.List {
|
||||
paramStr := fmt.Sprintf("%s", param.Type)
|
||||
if strings.Contains(string(paramStr), "http ResponseWriter") && len(fn.Type.Params.List) == 2 {
|
||||
if strings.Contains(string(paramStr), "http ResponseWriter") && len(fn.Type.Params.List) == 2 && (fn.Recv == nil || len(fn.Recv.List) == 0) {
|
||||
analyzed := analyze{
|
||||
PackageName: parsed.Name.Name,
|
||||
FuncName: fn.Name.Name,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/hydrogen",
|
||||
"version": "0.0.14",
|
||||
"version": "0.0.15",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"homepage": "https://vercel.com/docs",
|
||||
@@ -21,7 +21,7 @@
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.5.1",
|
||||
"@types/node": "*",
|
||||
"@vercel/build-utils": "5.3.1",
|
||||
"@vercel/build-utils": "5.3.2",
|
||||
"typescript": "4.6.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/next",
|
||||
"version": "3.1.19",
|
||||
"version": "3.1.21",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
|
||||
@@ -44,7 +44,7 @@
|
||||
"@types/semver": "6.0.0",
|
||||
"@types/text-table": "0.2.1",
|
||||
"@types/webpack-sources": "3.2.0",
|
||||
"@vercel/build-utils": "5.3.1",
|
||||
"@vercel/build-utils": "5.3.2",
|
||||
"@vercel/nft": "0.21.0",
|
||||
"@vercel/routing-utils": "2.0.2",
|
||||
"async-sema": "3.0.1",
|
||||
|
||||
@@ -36,7 +36,14 @@ import { Sema } from 'async-sema';
|
||||
// escape-string-regexp version must match Next.js version
|
||||
import escapeStringRegexp from 'escape-string-regexp';
|
||||
import findUp from 'find-up';
|
||||
import { lstat, pathExists, readFile, remove, writeFile } from 'fs-extra';
|
||||
import {
|
||||
lstat,
|
||||
pathExists,
|
||||
readFile,
|
||||
readJSON,
|
||||
remove,
|
||||
writeFile,
|
||||
} from 'fs-extra';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import resolveFrom from 'resolve-from';
|
||||
@@ -477,6 +484,14 @@ export const build: BuildV2 = async ({
|
||||
: '/404'
|
||||
]?.initialRevalidate === 'number';
|
||||
|
||||
const hasIsr500Page =
|
||||
typeof prerenderManifest.staticRoutes[
|
||||
routesManifest?.i18n
|
||||
? // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
|
||||
path.join('/', routesManifest?.i18n!.defaultLocale!, '/500')
|
||||
: '/500'
|
||||
]?.initialRevalidate === 'number';
|
||||
|
||||
const wildcardConfig: BuildResult['wildcard'] =
|
||||
routesManifest?.i18n?.domains && routesManifest.i18n.domains.length > 0
|
||||
? routesManifest.i18n.domains.map(item => {
|
||||
@@ -996,7 +1011,7 @@ export const build: BuildV2 = async ({
|
||||
buildId,
|
||||
'pages'
|
||||
);
|
||||
const pages = await getServerlessPages({
|
||||
const { pages } = await getServerlessPages({
|
||||
pagesDir,
|
||||
entryPath,
|
||||
outputDirectory,
|
||||
@@ -1073,10 +1088,15 @@ export const build: BuildV2 = async ({
|
||||
'pages'
|
||||
);
|
||||
|
||||
const pages = await getServerlessPages({
|
||||
const appPathRoutesManifest = await readJSON(
|
||||
path.join(entryPath, outputDirectory, 'app-path-routes-manifest.json')
|
||||
).catch(() => null);
|
||||
|
||||
const { pages, appPaths: lambdaAppPaths } = await getServerlessPages({
|
||||
pagesDir,
|
||||
entryPath,
|
||||
outputDirectory,
|
||||
appPathRoutesManifest,
|
||||
});
|
||||
const isApiPage = (page: string) =>
|
||||
page
|
||||
@@ -1265,10 +1285,12 @@ export const build: BuildV2 = async ({
|
||||
config,
|
||||
nextVersion,
|
||||
trailingSlash,
|
||||
appPathRoutesManifest,
|
||||
dynamicPages,
|
||||
canUsePreviewMode,
|
||||
staticPages,
|
||||
lambdaPages: pages,
|
||||
lambdaAppPaths,
|
||||
omittedPrerenderRoutes,
|
||||
isCorrectLocaleAPIRoutes,
|
||||
pagesDir,
|
||||
@@ -1296,6 +1318,7 @@ export const build: BuildV2 = async ({
|
||||
requiredServerFilesManifest,
|
||||
privateOutputs,
|
||||
hasIsr404Page,
|
||||
hasIsr500Page,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2597,18 +2620,39 @@ async function getServerlessPages(params: {
|
||||
pagesDir: string;
|
||||
entryPath: string;
|
||||
outputDirectory: string;
|
||||
appPathRoutesManifest?: Record<string, string>;
|
||||
}) {
|
||||
const [pages, middlewareManifest] = await Promise.all([
|
||||
const [pages, appPaths, middlewareManifest] = await Promise.all([
|
||||
glob('**/!(_middleware).js', params.pagesDir),
|
||||
params.appPathRoutesManifest
|
||||
? glob('**/page.js', path.join(params.pagesDir, '../app'))
|
||||
: Promise.resolve({}),
|
||||
getMiddlewareManifest(params.entryPath, params.outputDirectory),
|
||||
]);
|
||||
|
||||
const normalizedAppPaths: typeof appPaths = {};
|
||||
|
||||
if (params.appPathRoutesManifest) {
|
||||
for (const [entry, normalizedEntry] of Object.entries(
|
||||
params.appPathRoutesManifest
|
||||
)) {
|
||||
const normalizedPath = `${path.join('.', normalizedEntry)}.js`;
|
||||
const globPath = `${path.join('.', entry)}.js`;
|
||||
|
||||
if (appPaths[globPath]) {
|
||||
normalizedAppPaths[normalizedPath] = appPaths[globPath];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Edge Functions do not consider as Serverless Functions
|
||||
for (const edgeFunctionFile of Object.keys(
|
||||
middlewareManifest?.functions ?? {}
|
||||
)) {
|
||||
delete pages[edgeFunctionFile.slice(1) + '.js'];
|
||||
const edgePath = edgeFunctionFile.slice(1) + '.js';
|
||||
delete normalizedAppPaths[edgePath];
|
||||
delete pages[edgePath];
|
||||
}
|
||||
|
||||
return pages;
|
||||
return { pages, appPaths: normalizedAppPaths };
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import {
|
||||
getNextServerPath,
|
||||
getMiddlewareBundle,
|
||||
getFilesMapFromReasons,
|
||||
UnwrapPromise,
|
||||
} from './utils';
|
||||
import {
|
||||
nodeFileTrace,
|
||||
@@ -80,21 +81,25 @@ export async function serverBuild({
|
||||
headers,
|
||||
dataRoutes,
|
||||
hasIsr404Page,
|
||||
hasIsr500Page,
|
||||
imagesManifest,
|
||||
wildcardConfig,
|
||||
routesManifest,
|
||||
staticPages,
|
||||
lambdaPages,
|
||||
nextVersion,
|
||||
lambdaAppPaths,
|
||||
canUsePreviewMode,
|
||||
trailingSlash,
|
||||
prerenderManifest,
|
||||
appPathRoutesManifest,
|
||||
omittedPrerenderRoutes,
|
||||
trailingSlashRedirects,
|
||||
isCorrectLocaleAPIRoutes,
|
||||
lambdaCompressedByteLimit,
|
||||
requiredServerFilesManifest,
|
||||
}: {
|
||||
appPathRoutesManifest?: Record<string, string>;
|
||||
dynamicPages: string[];
|
||||
trailingSlash: boolean;
|
||||
config: Config;
|
||||
@@ -103,6 +108,7 @@ export async function serverBuild({
|
||||
canUsePreviewMode: boolean;
|
||||
omittedPrerenderRoutes: Set<string>;
|
||||
staticPages: { [key: string]: FileFsRef };
|
||||
lambdaAppPaths: { [key: string]: FileFsRef };
|
||||
lambdaPages: { [key: string]: FileFsRef };
|
||||
privateOutputs: { files: Files; routes: Route[] };
|
||||
entryPath: string;
|
||||
@@ -122,6 +128,7 @@ export async function serverBuild({
|
||||
dataRoutes: Route[];
|
||||
nextVersion: string;
|
||||
hasIsr404Page: boolean;
|
||||
hasIsr500Page: boolean;
|
||||
trailingSlashRedirects: Route[];
|
||||
routesManifest: RoutesManifest;
|
||||
lambdaCompressedByteLimit: number;
|
||||
@@ -130,6 +137,8 @@ export async function serverBuild({
|
||||
prerenderManifest: NextPrerenderedRoutes;
|
||||
requiredServerFilesManifest: NextRequiredServerFilesManifest;
|
||||
}): Promise<BuildResult> {
|
||||
lambdaPages = Object.assign({}, lambdaPages, lambdaAppPaths);
|
||||
|
||||
const lambdas: { [key: string]: Lambda } = {};
|
||||
const prerenders: { [key: string]: Prerender } = {};
|
||||
const lambdaPageKeys = Object.keys(lambdaPages);
|
||||
@@ -139,6 +148,14 @@ export async function serverBuild({
|
||||
nextVersion,
|
||||
EMPTY_ALLOW_QUERY_FOR_PRERENDERED_VERSION
|
||||
);
|
||||
let appBuildTraces: UnwrapPromise<ReturnType<typeof glob>> = {};
|
||||
let appDir: string | null = null;
|
||||
|
||||
if (appPathRoutesManifest) {
|
||||
appDir = path.join(pagesDir, '../app');
|
||||
appBuildTraces = await glob('**/*.js.nft.json', appDir);
|
||||
}
|
||||
|
||||
const isCorrectNotFoundRoutes = semver.gte(
|
||||
nextVersion,
|
||||
CORRECT_NOT_FOUND_ROUTES_VERSION
|
||||
@@ -531,9 +548,26 @@ export async function serverBuild({
|
||||
const mergedPageKeys = [...nonApiPages, ...apiPages, ...internalPages];
|
||||
const traceCache = {};
|
||||
|
||||
const getOriginalPagePath = (page: string) => {
|
||||
let originalPagePath = page;
|
||||
|
||||
if (appDir && lambdaAppPaths[page]) {
|
||||
const { fsPath } = lambdaAppPaths[page];
|
||||
originalPagePath = path.relative(appDir, fsPath);
|
||||
}
|
||||
return originalPagePath;
|
||||
};
|
||||
|
||||
const getBuildTraceFile = (page: string) => {
|
||||
return (
|
||||
pageBuildTraces[page + '.nft.json'] ||
|
||||
appBuildTraces[page + '.nft.json']
|
||||
);
|
||||
};
|
||||
|
||||
const pathsToTrace: string[] = mergedPageKeys
|
||||
.map(page => {
|
||||
if (!pageBuildTraces[page + '.nft.json']) {
|
||||
if (!getBuildTraceFile(page)) {
|
||||
return lambdaPages[page].fsPath;
|
||||
}
|
||||
})
|
||||
@@ -557,7 +591,8 @@ export async function serverBuild({
|
||||
|
||||
for (const page of mergedPageKeys) {
|
||||
const tracedFiles: { [key: string]: FileFsRef } = {};
|
||||
const pageBuildTrace = pageBuildTraces[page + '.nft.json'];
|
||||
const originalPagePath = getOriginalPagePath(page);
|
||||
const pageBuildTrace = getBuildTraceFile(originalPagePath);
|
||||
let fileList: string[];
|
||||
let reasons: NodeFileTraceReasons;
|
||||
|
||||
@@ -565,8 +600,38 @@ export async function serverBuild({
|
||||
const { files } = JSON.parse(
|
||||
await fs.readFile(pageBuildTrace.fsPath, 'utf8')
|
||||
);
|
||||
|
||||
// TODO: this will be moved to a separate worker in the future
|
||||
// although currently this is needed in the lambda
|
||||
const isAppPath = appDir && lambdaAppPaths[page];
|
||||
const serverComponentFile = isAppPath
|
||||
? pageBuildTrace.fsPath.replace(
|
||||
/\.js\.nft\.json$/,
|
||||
'.__sc_client__.js'
|
||||
)
|
||||
: null;
|
||||
|
||||
if (serverComponentFile && (await fs.pathExists(serverComponentFile))) {
|
||||
files.push(
|
||||
path.relative(
|
||||
path.dirname(pageBuildTrace.fsPath),
|
||||
serverComponentFile
|
||||
)
|
||||
);
|
||||
|
||||
try {
|
||||
const scTrace = JSON.parse(
|
||||
await fs.readFile(`${serverComponentFile}.nft.json`, 'utf8')
|
||||
);
|
||||
scTrace.files.forEach((file: string) => files.push(file));
|
||||
} catch (err) {
|
||||
/* non-fatal for now */
|
||||
}
|
||||
}
|
||||
|
||||
fileList = [];
|
||||
const pageDir = path.dirname(path.join(pagesDir, page));
|
||||
const curPagesDir = isAppPath && appDir ? appDir : pagesDir;
|
||||
const pageDir = path.dirname(path.join(curPagesDir, originalPagePath));
|
||||
const normalizedBaseDir = `${baseDir}${
|
||||
baseDir.endsWith('/') ? '' : '/'
|
||||
}`;
|
||||
@@ -1375,7 +1440,10 @@ export async function serverBuild({
|
||||
route.src.replace(/(^\^|\$$)/g, '') + '.json$'
|
||||
);
|
||||
|
||||
const { pathname } = new URL(route.dest || '/', 'http://n');
|
||||
const { pathname, search } = new URL(
|
||||
route.dest || '/',
|
||||
'http://n'
|
||||
);
|
||||
let isPrerender = !!prerenders[path.join('./', pathname)];
|
||||
|
||||
if (routesManifest.i18n) {
|
||||
@@ -1392,7 +1460,9 @@ export async function serverBuild({
|
||||
}
|
||||
|
||||
if (isPrerender) {
|
||||
route.dest = `/_next/data/${buildId}${pathname}.json`;
|
||||
route.dest = `/_next/data/${buildId}${pathname}.json${
|
||||
search || ''
|
||||
}`;
|
||||
}
|
||||
return route;
|
||||
})
|
||||
@@ -1529,10 +1599,8 @@ export async function serverBuild({
|
||||
},
|
||||
]),
|
||||
|
||||
// static 500 page if present
|
||||
...(!hasStatic500
|
||||
? []
|
||||
: i18n
|
||||
// custom 500 page if present
|
||||
...(i18n && (hasStatic500 || hasIsr500Page || lambdaPages['500.js'])
|
||||
? [
|
||||
{
|
||||
src: `${path.join(
|
||||
@@ -1544,6 +1612,7 @@ export async function serverBuild({
|
||||
.join('|')})(/.*|$)`,
|
||||
dest: path.join('/', entryDirectory, '/$nextLocale/500'),
|
||||
status: 500,
|
||||
caseSensitive: true,
|
||||
},
|
||||
{
|
||||
src: path.join('/', entryDirectory, '.*'),
|
||||
@@ -1558,7 +1627,15 @@ export async function serverBuild({
|
||||
: [
|
||||
{
|
||||
src: path.join('/', entryDirectory, '.*'),
|
||||
dest: path.join('/', entryDirectory, '/500'),
|
||||
dest: path.join(
|
||||
'/',
|
||||
entryDirectory,
|
||||
hasStatic500 ||
|
||||
hasIsr500Page ||
|
||||
lambdas[path.join(entryDirectory, '500')]
|
||||
? '/500'
|
||||
: '/_error'
|
||||
),
|
||||
status: 500,
|
||||
},
|
||||
]),
|
||||
|
||||
@@ -2020,7 +2020,7 @@ export const onPrerenderRoute =
|
||||
}
|
||||
};
|
||||
|
||||
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
|
||||
export type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
|
||||
|
||||
export async function getStaticFiles(
|
||||
entryPath: string,
|
||||
|
||||
7
packages/next/test/fixtures/00-app-dir/app/(newroot)/dashboard/another/page.server.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/(newroot)/dashboard/another/page.server.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function AnotherPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from newroot/dashboard/another</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
18
packages/next/test/fixtures/00-app-dir/app/(newroot)/layout.server.js
vendored
Normal file
18
packages/next/test/fixtures/00-app-dir/app/(newroot)/layout.server.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
export async function getServerSideProps() {
|
||||
return {
|
||||
props: {
|
||||
world: 'world',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function Root({ children, world }) {
|
||||
return (
|
||||
<html className="this-is-another-document-html">
|
||||
<head>
|
||||
<title>{`hello ${world}`}</title>
|
||||
</head>
|
||||
<body className="this-is-another-document-body">{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/(rootonly)/dashboard/changelog/page.server.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/(rootonly)/dashboard/changelog/page.server.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function ChangelogPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard/changelog</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/(rootonly)/dashboard/hello/page.server.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/(rootonly)/dashboard/hello/page.server.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function HelloPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard/rootonly/hello</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
18
packages/next/test/fixtures/00-app-dir/app/client-component-route/page.client.js
vendored
Normal file
18
packages/next/test/fixtures/00-app-dir/app/client-component-route/page.client.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
import style from './style.module.css';
|
||||
import './style.css';
|
||||
|
||||
export default function ClientComponentRoute() {
|
||||
const [count, setCount] = useState(0);
|
||||
useEffect(() => {
|
||||
setCount(1);
|
||||
}, [count]);
|
||||
return (
|
||||
<>
|
||||
<p className={style.red}>
|
||||
hello from app/client-component-route. <b>count: {count}</b>
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
3
packages/next/test/fixtures/00-app-dir/app/client-component-route/style.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir/app/client-component-route/style.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
b {
|
||||
color: blue;
|
||||
}
|
||||
3
packages/next/test/fixtures/00-app-dir/app/client-component-route/style.module.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir/app/client-component-route/style.module.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.red {
|
||||
color: red;
|
||||
}
|
||||
18
packages/next/test/fixtures/00-app-dir/app/client-nested/layout.client.js
vendored
Normal file
18
packages/next/test/fixtures/00-app-dir/app/client-nested/layout.client.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
import styles from './style.module.css';
|
||||
import './style.css';
|
||||
|
||||
export default function ClientNestedLayout({ children }) {
|
||||
const [count, setCount] = useState(0);
|
||||
useEffect(() => {
|
||||
setCount(1);
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<h1 className={styles.red}>Client Nested. Count: {count}</h1>
|
||||
<button onClick={() => setCount(count + 1)}>{count}</button>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/client-nested/page.server.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/client-nested/page.server.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function ClientPage() {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/client-nested</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
3
packages/next/test/fixtures/00-app-dir/app/client-nested/style.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir/app/client-nested/style.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
button {
|
||||
color: red;
|
||||
}
|
||||
3
packages/next/test/fixtures/00-app-dir/app/client-nested/style.module.css
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir/app/client-nested/style.module.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.red {
|
||||
color: red;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export default function DeploymentsBreakdownPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard/(custom)/deployments/breakdown</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
8
packages/next/test/fixtures/00-app-dir/app/dashboard/(custom)/layout.server.js
vendored
Normal file
8
packages/next/test/fixtures/00-app-dir/app/dashboard/(custom)/layout.server.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
export default function CustomDashboardRootLayout({ children }) {
|
||||
return (
|
||||
<>
|
||||
<h2>Custom dashboard</h2>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
15
packages/next/test/fixtures/00-app-dir/app/dashboard/deployments/[id]/page.server.js
vendored
Normal file
15
packages/next/test/fixtures/00-app-dir/app/dashboard/deployments/[id]/page.server.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
export async function getServerSideProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
id: params.id,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function DeploymentsPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard/deployments/[id]. ID is: {props.id}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/dashboard/deployments/info/page.server.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/dashboard/deployments/info/page.server.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function DeploymentsInfoPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard/deployments/info</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
16
packages/next/test/fixtures/00-app-dir/app/dashboard/deployments/layout.server.js
vendored
Normal file
16
packages/next/test/fixtures/00-app-dir/app/dashboard/deployments/layout.server.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
export function getServerSideProps() {
|
||||
return {
|
||||
props: {
|
||||
message: 'hello',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function DeploymentsLayout({ message, children }) {
|
||||
return (
|
||||
<>
|
||||
<h2>Deployments {message}</h2>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/dashboard/index/lazy.client.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/dashboard/index/lazy.client.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function LazyComponent() {
|
||||
return (
|
||||
<>
|
||||
<p>hello from lazy</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
10
packages/next/test/fixtures/00-app-dir/app/dashboard/index/page.server.js
vendored
Normal file
10
packages/next/test/fixtures/00-app-dir/app/dashboard/index/page.server.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import { ClientComponent } from './test.client.js';
|
||||
|
||||
export default function DashboardIndexPage() {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard/index</p>
|
||||
<ClientComponent />
|
||||
</>
|
||||
);
|
||||
}
|
||||
13
packages/next/test/fixtures/00-app-dir/app/dashboard/index/test.client.js
vendored
Normal file
13
packages/next/test/fixtures/00-app-dir/app/dashboard/index/test.client.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import { useState, lazy } from 'react';
|
||||
|
||||
const Lazy = lazy(() => import('./lazy.client.js'));
|
||||
|
||||
export function ClientComponent() {
|
||||
let [state] = useState('client');
|
||||
return (
|
||||
<>
|
||||
<Lazy />
|
||||
<p className="hi">hello from modern the {state}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/dashboard/integrations/page.server.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/dashboard/integrations/page.server.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function IntegrationsPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard/integrations</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
8
packages/next/test/fixtures/00-app-dir/app/dashboard/layout.server.js
vendored
Normal file
8
packages/next/test/fixtures/00-app-dir/app/dashboard/layout.server.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
export default function DashboardLayout(props) {
|
||||
return (
|
||||
<>
|
||||
<h1>Dashboard</h1>
|
||||
{props.children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/dashboard/page.server.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/dashboard/page.server.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function DashboardPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/dashboard</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
19
packages/next/test/fixtures/00-app-dir/app/dynamic/[category]/[id]/layout.server.js
vendored
Normal file
19
packages/next/test/fixtures/00-app-dir/app/dynamic/[category]/[id]/layout.server.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
export async function getServerSideProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
params,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function IdLayout({ children, params }) {
|
||||
return (
|
||||
<>
|
||||
<h3>
|
||||
Id Layout. Params:{' '}
|
||||
<span id="id-layout-params">{JSON.stringify(params)}</span>
|
||||
</h3>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
19
packages/next/test/fixtures/00-app-dir/app/dynamic/[category]/[id]/page.server.js
vendored
Normal file
19
packages/next/test/fixtures/00-app-dir/app/dynamic/[category]/[id]/page.server.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
export async function getServerSideProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
params,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function IdPage({ children, params }) {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Id Page. Params:{' '}
|
||||
<span id="id-page-params">{JSON.stringify(params)}</span>
|
||||
</p>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
19
packages/next/test/fixtures/00-app-dir/app/dynamic/[category]/layout.server.js
vendored
Normal file
19
packages/next/test/fixtures/00-app-dir/app/dynamic/[category]/layout.server.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
export async function getServerSideProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
params,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function CategoryLayout({ children, params }) {
|
||||
return (
|
||||
<>
|
||||
<h2>
|
||||
Category Layout. Params:{' '}
|
||||
<span id="category-layout-params">{JSON.stringify(params)}</span>{' '}
|
||||
</h2>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
19
packages/next/test/fixtures/00-app-dir/app/dynamic/layout.server.js
vendored
Normal file
19
packages/next/test/fixtures/00-app-dir/app/dynamic/layout.server.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
export async function getServerSideProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
params,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function DynamicLayout({ children, params }) {
|
||||
return (
|
||||
<>
|
||||
<h1>
|
||||
Dynamic Layout. Params:{' '}
|
||||
<span id="dynamic-layout-params">{JSON.stringify(params)}</span>
|
||||
</h1>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
18
packages/next/test/fixtures/00-app-dir/app/layout.server.js
vendored
Normal file
18
packages/next/test/fixtures/00-app-dir/app/layout.server.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
export async function getServerSideProps() {
|
||||
return {
|
||||
props: {
|
||||
world: 'world',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function Root({ children, custom, world }) {
|
||||
return (
|
||||
<html className="this-is-the-document-html">
|
||||
<head>
|
||||
<title>{`hello ${world}`}</title>
|
||||
</head>
|
||||
<body className="this-is-the-document-body">{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
15
packages/next/test/fixtures/00-app-dir/app/partial-match-[id]/page.server.js
vendored
Normal file
15
packages/next/test/fixtures/00-app-dir/app/partial-match-[id]/page.server.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
export async function getServerSideProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
id: params.id,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function DeploymentsPage(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/partial-match-[id]. ID is: {props.id}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/shared-component-route/page.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/shared-component-route/page.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function SharedComponentRoute() {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/shared-component-route</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/should-not-serve-client/page.client.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/should-not-serve-client/page.client.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function ShouldNotServeClientDotJs(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/should-not-serve-client</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/app/should-not-serve-server/page.server.js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/app/should-not-serve-server/page.server.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function ShouldNotServeServerDotJs(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from app/should-not-serve-server</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
3
packages/next/test/fixtures/00-app-dir/app/slow-layout-and-page-with-loading/loading.js
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir/app/slow-layout-and-page-with-loading/loading.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function Loading() {
|
||||
return <p id="loading-layout">Loading layout...</p>;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
export async function getServerSideProps() {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
return {
|
||||
props: {
|
||||
message: 'hello from slow layout',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function SlowLayout(props) {
|
||||
return (
|
||||
<>
|
||||
<p id="slow-layout-message">{props.message}</p>
|
||||
{props.children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
3
packages/next/test/fixtures/00-app-dir/app/slow-layout-and-page-with-loading/slow/loading.js
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir/app/slow-layout-and-page-with-loading/slow/loading.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function Loading() {
|
||||
return <p id="loading-page">Loading page...</p>;
|
||||
}
|
||||
12
packages/next/test/fixtures/00-app-dir/app/slow-layout-and-page-with-loading/slow/page.server.js
vendored
Normal file
12
packages/next/test/fixtures/00-app-dir/app/slow-layout-and-page-with-loading/slow/page.server.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
export async function getServerSideProps() {
|
||||
await new Promise(resolve => setTimeout(resolve, 5000));
|
||||
return {
|
||||
props: {
|
||||
message: 'hello from slow page',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function SlowPage(props) {
|
||||
return <h1 id="slow-page-message">{props.message}</h1>;
|
||||
}
|
||||
3
packages/next/test/fixtures/00-app-dir/app/slow-layout-with-loading/loading.js
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir/app/slow-layout-with-loading/loading.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function Loading() {
|
||||
return <p id="loading">Loading...</p>;
|
||||
}
|
||||
17
packages/next/test/fixtures/00-app-dir/app/slow-layout-with-loading/slow/layout.server.js
vendored
Normal file
17
packages/next/test/fixtures/00-app-dir/app/slow-layout-with-loading/slow/layout.server.js
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
export async function getServerSideProps() {
|
||||
await new Promise(resolve => setTimeout(resolve, 5000));
|
||||
return {
|
||||
props: {
|
||||
message: 'hello from slow layout',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function SlowLayout(props) {
|
||||
return (
|
||||
<>
|
||||
<p id="slow-layout-message">{props.message}</p>
|
||||
{props.children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
3
packages/next/test/fixtures/00-app-dir/app/slow-layout-with-loading/slow/page.server.js
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir/app/slow-layout-with-loading/slow/page.server.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function Page() {
|
||||
return <h1 id="page-message">Hello World</h1>;
|
||||
}
|
||||
3
packages/next/test/fixtures/00-app-dir/app/slow-page-with-loading/loading.js
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir/app/slow-page-with-loading/loading.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function Loading() {
|
||||
return <p id="loading">Loading...</p>;
|
||||
}
|
||||
12
packages/next/test/fixtures/00-app-dir/app/slow-page-with-loading/page.server.js
vendored
Normal file
12
packages/next/test/fixtures/00-app-dir/app/slow-page-with-loading/page.server.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
export async function getServerSideProps() {
|
||||
await new Promise(resolve => setTimeout(resolve, 5000));
|
||||
return {
|
||||
props: {
|
||||
message: 'hello from slow page',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function SlowPage(props) {
|
||||
return <h1 id="slow-page-message">{props.message}</h1>;
|
||||
}
|
||||
3
packages/next/test/fixtures/00-app-dir/app/test-page/page.server.js
vendored
Normal file
3
packages/next/test/fixtures/00-app-dir/app/test-page/page.server.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function Page() {
|
||||
return <p id="page">Page</p>;
|
||||
}
|
||||
12
packages/next/test/fixtures/00-app-dir/index.test.js
vendored
Normal file
12
packages/next/test/fixtures/00-app-dir/index.test.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/* eslint-env jest */
|
||||
const path = require('path');
|
||||
const { deployAndTest } = require('../../utils');
|
||||
|
||||
const ctx = {};
|
||||
|
||||
describe(`${__dirname.split(path.sep).pop()}`, () => {
|
||||
it('should deploy and pass probe checks', async () => {
|
||||
const info = await deployAndTest(__dirname);
|
||||
Object.assign(ctx, info);
|
||||
});
|
||||
});
|
||||
8
packages/next/test/fixtures/00-app-dir/middleware.js
vendored
Normal file
8
packages/next/test/fixtures/00-app-dir/middleware.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export function middleware(request) {
|
||||
if (request.nextUrl.pathname === '/middleware-to-dashboard') {
|
||||
// TODO: this does not copy __flight__ and __flight_router_state_tree__
|
||||
return NextResponse.rewrite(new URL('/dashboard', request.url));
|
||||
}
|
||||
}
|
||||
17
packages/next/test/fixtures/00-app-dir/next.config.js
vendored
Normal file
17
packages/next/test/fixtures/00-app-dir/next.config.js
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
module.exports = {
|
||||
experimental: {
|
||||
appDir: true,
|
||||
runtime: 'nodejs',
|
||||
serverComponents: true,
|
||||
legacyBrowsers: false,
|
||||
browsersListForSwc: true,
|
||||
},
|
||||
rewrites: async () => {
|
||||
return [
|
||||
{
|
||||
source: '/rewritten-to-dashboard',
|
||||
destination: '/dashboard',
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
7
packages/next/test/fixtures/00-app-dir/package.json
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/package.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"next": "https://files-26yo0dy1b-ijjk-testing.vercel.app",
|
||||
"react": "experimental",
|
||||
"react-dom": "experimental"
|
||||
}
|
||||
}
|
||||
7
packages/next/test/fixtures/00-app-dir/pages/blog/[slug].js
vendored
Normal file
7
packages/next/test/fixtures/00-app-dir/pages/blog/[slug].js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function Page(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from pages/blog/[slug]</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
9
packages/next/test/fixtures/00-app-dir/pages/index.js
vendored
Normal file
9
packages/next/test/fixtures/00-app-dir/pages/index.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import Link from 'next/link';
|
||||
export default function Page(props) {
|
||||
return (
|
||||
<>
|
||||
<p>hello from pages/index</p>
|
||||
<Link href="/dashboard">Dashboard</Link>
|
||||
</>
|
||||
);
|
||||
}
|
||||
1
packages/next/test/fixtures/00-app-dir/public/hello.txt
vendored
Normal file
1
packages/next/test/fixtures/00-app-dir/public/hello.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
hello world
|
||||
45
packages/next/test/fixtures/00-app-dir/vercel.json
vendored
Normal file
45
packages/next/test/fixtures/00-app-dir/vercel.json
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"builds": [
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@vercel/next"
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
{
|
||||
"path": "/dashboard",
|
||||
"status": 200,
|
||||
"mustContain": "hello from app/dashboard"
|
||||
},
|
||||
{
|
||||
"path": "/dashboard/another",
|
||||
"status": 200,
|
||||
"mustContain": "hello from newroot/dashboard/another"
|
||||
},
|
||||
{
|
||||
"path": "/dashboard/deployments/123",
|
||||
"status": 200,
|
||||
"mustContain": "hello from app/dashboard/deployments/[id]. ID is: <!-- -->123"
|
||||
},
|
||||
{
|
||||
"path": "/",
|
||||
"status": 200,
|
||||
"mustContain": "hello from pages/index"
|
||||
},
|
||||
{
|
||||
"path": "/blog/123",
|
||||
"status": 200,
|
||||
"mustContain": "hello from pages/blog/[slug]"
|
||||
},
|
||||
{
|
||||
"path": "/dynamic/category-1/id-1",
|
||||
"status": 200,
|
||||
"mustContain": "{"category":"category-1","id":"id-1"}"
|
||||
},
|
||||
{
|
||||
"path": "/dashboard/changelog",
|
||||
"status": 200,
|
||||
"mustContain": "hello from app/dashboard/changelog"
|
||||
}
|
||||
]
|
||||
}
|
||||
8
packages/next/test/fixtures/00-lambda-pages-500/index.test.js
vendored
Normal file
8
packages/next/test/fixtures/00-lambda-pages-500/index.test.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
const path = require('path');
|
||||
const { deployAndTest } = require('../../utils');
|
||||
|
||||
describe(`${__dirname.split(path.sep).pop()}`, () => {
|
||||
it('should deploy and pass probe checks', async () => {
|
||||
await deployAndTest(__dirname);
|
||||
});
|
||||
});
|
||||
5
packages/next/test/fixtures/00-lambda-pages-500/next.config.js
vendored
Normal file
5
packages/next/test/fixtures/00-lambda-pages-500/next.config.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
generateBuildId() {
|
||||
return 'testing-build-id';
|
||||
},
|
||||
};
|
||||
10
packages/next/test/fixtures/00-lambda-pages-500/package.json
vendored
Normal file
10
packages/next/test/fixtures/00-lambda-pages-500/package.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"scripts": {
|
||||
"build": "next build"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "latest",
|
||||
"react": "latest",
|
||||
"react-dom": "latest"
|
||||
}
|
||||
}
|
||||
3
packages/next/test/fixtures/00-lambda-pages-500/pages/404.js
vendored
Normal file
3
packages/next/test/fixtures/00-lambda-pages-500/pages/404.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function Error404(props) {
|
||||
return <p>pages/404</p>;
|
||||
}
|
||||
3
packages/next/test/fixtures/00-lambda-pages-500/pages/500.js
vendored
Normal file
3
packages/next/test/fixtures/00-lambda-pages-500/pages/500.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function Error500(props) {
|
||||
return <p>pages/500</p>;
|
||||
}
|
||||
11
packages/next/test/fixtures/00-lambda-pages-500/pages/_app.js
vendored
Normal file
11
packages/next/test/fixtures/00-lambda-pages-500/pages/_app.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import App from 'next/app';
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
|
||||
MyApp.getInitialProps = async function (ctx) {
|
||||
return App.getInitialProps(ctx);
|
||||
};
|
||||
|
||||
export default MyApp;
|
||||
18
packages/next/test/fixtures/00-lambda-pages-500/pages/_error.js
vendored
Normal file
18
packages/next/test/fixtures/00-lambda-pages-500/pages/_error.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
function Error(props) {
|
||||
return (
|
||||
<>
|
||||
<p>pages/_error</p>
|
||||
<p>{JSON.stringify(props)}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Error.getInitialProps = async function getInitialProps({ statusCode, err }) {
|
||||
console.log('Error.getInitialProps', err);
|
||||
return {
|
||||
statusCode,
|
||||
message: err?.message,
|
||||
};
|
||||
};
|
||||
|
||||
export default Error;
|
||||
3
packages/next/test/fixtures/00-lambda-pages-500/pages/index.js
vendored
Normal file
3
packages/next/test/fixtures/00-lambda-pages-500/pages/index.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function Page(props) {
|
||||
return <p>index page</p>;
|
||||
}
|
||||
7
packages/next/test/fixtures/00-lambda-pages-500/pages/trigger-error.js
vendored
Normal file
7
packages/next/test/fixtures/00-lambda-pages-500/pages/trigger-error.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function Page(props) {
|
||||
return <p>pages/trigger-error</p>;
|
||||
}
|
||||
|
||||
export function getServerSideProps() {
|
||||
throw new Error('custom error');
|
||||
}
|
||||
19
packages/next/test/fixtures/00-lambda-pages-500/probes.json
vendored
Normal file
19
packages/next/test/fixtures/00-lambda-pages-500/probes.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"probes": [
|
||||
{
|
||||
"path": "/",
|
||||
"status": 200,
|
||||
"mustContain": "index page"
|
||||
},
|
||||
{
|
||||
"path": "/non-existent",
|
||||
"status": 404,
|
||||
"mustContain": "pages/404"
|
||||
},
|
||||
{
|
||||
"path": "/trigger-error",
|
||||
"status": 500,
|
||||
"mustContain": "pages/500"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,8 +1,69 @@
|
||||
const path = require('path');
|
||||
const { deployAndTest } = require('../../utils');
|
||||
const cheerio = require('cheerio');
|
||||
const { deployAndTest, check } = require('../../utils');
|
||||
const fetch = require('../../../../../test/lib/deployment/fetch-retry');
|
||||
|
||||
describe(`${__dirname.split(path.sep).pop()}`, () => {
|
||||
let ctx = {};
|
||||
|
||||
it('should deploy and pass probe checks', async () => {
|
||||
await deployAndTest(__dirname);
|
||||
const info = await deployAndTest(__dirname);
|
||||
Object.assign(ctx, info);
|
||||
});
|
||||
|
||||
it('should revalidate content correctly for middleware rewrite', async () => {
|
||||
const propsFromHtml = async () => {
|
||||
let res = await fetch(`${ctx.deploymentUrl}/rewrite-to-another-site`);
|
||||
let $ = cheerio.load(await res.text());
|
||||
let props = JSON.parse($('#props').text());
|
||||
return props;
|
||||
};
|
||||
let props = await propsFromHtml();
|
||||
expect(isNaN(props.now)).toBe(false);
|
||||
|
||||
const { pageProps: data } = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/rewrite-to-another-site.json`
|
||||
).then(res => res.json());
|
||||
|
||||
expect(isNaN(data.now)).toBe(false);
|
||||
|
||||
const revalidateRes = await fetch(
|
||||
`${ctx.deploymentUrl}/api/revalidate?urlPath=/_sites/test-revalidate`
|
||||
);
|
||||
expect(revalidateRes.status).toBe(200);
|
||||
expect(await revalidateRes.json()).toEqual({ revalidated: true });
|
||||
|
||||
await check(async () => {
|
||||
const newProps = await propsFromHtml();
|
||||
console.log({ props, newProps });
|
||||
|
||||
if (isNaN(newProps.now)) {
|
||||
throw new Error();
|
||||
}
|
||||
return newProps.now !== props.now
|
||||
? 'success'
|
||||
: JSON.stringify({
|
||||
newProps,
|
||||
props,
|
||||
});
|
||||
}, 'success');
|
||||
|
||||
await check(async () => {
|
||||
const { pageProps: newData } = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/rewrite-to-another-site.json`
|
||||
).then(res => res.json());
|
||||
|
||||
console.log({ newData, data });
|
||||
|
||||
if (isNaN(newData.now)) {
|
||||
throw new Error();
|
||||
}
|
||||
return newData.now !== data.now
|
||||
? 'success'
|
||||
: JSON.stringify({
|
||||
newData,
|
||||
data,
|
||||
});
|
||||
}, 'success');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -94,6 +94,13 @@ export function middleware(request) {
|
||||
return NextResponse.rewrite(customUrl);
|
||||
}
|
||||
|
||||
if (url.pathname === '/rewrite-to-another-site') {
|
||||
const customUrl = new URL(url);
|
||||
customUrl.pathname = '/_sites/test-revalidate';
|
||||
console.log('rewriting to', customUrl.pathname, customUrl.href);
|
||||
return NextResponse.rewrite(customUrl);
|
||||
}
|
||||
|
||||
if (url.pathname === '/redirect-me-to-about') {
|
||||
url.pathname = '/about';
|
||||
url.searchParams.set('middleware', 'foo');
|
||||
|
||||
@@ -2,7 +2,7 @@ export default function Page(props) {
|
||||
return (
|
||||
<>
|
||||
<p>/_sites/[site]</p>
|
||||
<p>{JSON.stringify(props)}</p>
|
||||
<p id="props">{JSON.stringify(props)}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
4
packages/next/test/fixtures/00-middleware/pages/api/revalidate.js
vendored
Normal file
4
packages/next/test/fixtures/00-middleware/pages/api/revalidate.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export default async function handler(req, res) {
|
||||
await res.revalidate(req.query.urlPath);
|
||||
res.json({ revalidated: true });
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user