Compare commits

...

19 Commits

Author SHA1 Message Date
Sean Massa
ebb5e2b208 Publish Stable
- vercel@28.1.1
 - @vercel/next@3.1.20
 - @vercel/python@3.1.10
2022-08-22 15:33:41 -05:00
JJ Kasper
e34858d082 [next] Add handling for app-paths-manifest (#8098)
This adds handling for the `app` outputs and adds initial tests to ensure it is working as expected. 

### Related Issues

x-ref: https://github.com/vercel/next.js/pull/38420

### 📋 Checklist

<!--
  Please keep your PR as a Draft until the checklist is complete
-->

#### Tests

- [ ] The code changed/added as part of this PR has been covered with tests
- [ ] All tests pass locally with `yarn test-unit`

#### Code Review

- [ ] This PR has a concise title and thorough description useful to a reviewer
- [ ] Issue from task tracker has a link to this PR
2022-08-22 14:58:21 -05:00
Ikko Ashimine
f03c947f91 [python] fix typo in install.ts comment (#8442)
overriden -> overridden
2022-08-22 11:58:27 -04:00
JJ Kasper
0d13fe7e34 [next] Ensure non-static pages/500 is handled (#8438)
Related Issues
Previously we were only checking for a non-static version of pages/404 although this can also be the case for pages/500 so this ensures we match that handling and add a test case to prevent regression.
Fixes: slack thread
📋 Checklist

Tests

 The code changed/added as part of this PR has been covered with tests
 All tests pass locally with yarn test-unit

Code Review

 This PR has a concise title and thorough description useful to a reviewer
 Issue from task tracker has a link to this PR
2022-08-22 10:13:16 -05:00
JJ Kasper
4afec9d373 [next] Update middleware data routes to fix caching (#8431)
Related Issues
This fixes caches for data routes with middleware due to search params not matching between the non-data variant and the data variant. Additional tests have been added to ensure this is working as expected.
Fixes: vercel/next.js#39595
📋 Checklist

Tests

 The code changed/added as part of this PR has been covered with tests
 All tests pass locally with yarn test-unit

Code Review

 This PR has a concise title and thorough description useful to a reviewer
 Issue from task tracker has a link to this PR
2022-08-22 09:52:24 -05:00
Sean Massa
09c85f63d2 Publish Stable
- vercel@28.1.0
 - @vercel/go@2.2.0
 - @vercel/next@3.1.19
2022-08-16 15:05:36 -05:00
Matthew Stanciu
9963965e9a [cli] Fix vc link not respecting --yes (#8412)
As of 28.0.0, `vc link` stopped respecting `--yes` and would wait for prompt if it found a Git repository to connect. This PR passes `autoConfirm` through to the Git prompt, so that `vc link` continues to respect `--yes`.

Here's what `vc link` looks like after this PR if a user has a local Git repository:

<img width="513" alt="Screen Shot 2022-08-16 at 10 05 56 AM" src="https://user-images.githubusercontent.com/14811170/184899917-c3dc0603-370d-4c86-afb8-19758fbc051a.png">

Not sure if we want to remove the log messages to be consistent with the rest of `vc link`?

### 📋 Checklist

<!--
  Please keep your PR as a Draft until the checklist is complete
-->

#### Tests

- [x] The code changed/added as part of this PR has been covered with tests
- [x] All tests pass locally with `yarn test-unit`

#### Code Review

- [ ] This PR has a concise title and thorough description useful to a reviewer
- [ ] Issue from task tracker has a link to this PR
2022-08-16 19:16:54 +00:00
Matthew Stanciu
f3ed279007 [cli] Change mentions of "Aborted" to "Canceled" (#8411)
@leerob flagged that the language "Aborted" throughout the CLI should be changed to be more inclusive. This PR updates this throughout.

I didn't go as far as to update type names because I wanted to avoid potentially unintended consequences, but happy to also do that if we want.

### 📋 Checklist

<!--
  Please keep your PR as a Draft until the checklist is complete
-->

#### Tests

- [ ] The code changed/added as part of this PR has been covered with tests
- [ ] All tests pass locally with `yarn test-unit`

#### Code Review

- [ ] This PR has a concise title and thorough description useful to a reviewer
- [ ] Issue from task tracker has a link to this PR
2022-08-16 18:47:52 +00:00
Sean Massa
4fe489edad Revert "Revert "[go] add lambda wrapper support to the go runtime"" (#8407)
Co-authored-by: Craig Andrews <craig.andrews@vercel.com>
Co-authored-by: Craig Andrews <44933829+craigandrews@users.noreply.github.com>
2022-08-16 11:54:44 -05:00
Matthew Stanciu
e2911aac0b [cli] Small vc ls wording changes (#8405)
I ran `vc ls` for a project and I spotted a few small details that I felt compelled to make better.

### 📋 Checklist

<!--
  Please keep your PR as a Draft until the checklist is complete
-->

#### Tests

- [ ] The code changed/added as part of this PR has been covered with tests
- [ ] All tests pass locally with `yarn test-unit`

#### Code Review

- [ ] This PR has a concise title and thorough description useful to a reviewer
- [ ] Issue from task tracker has a link to this PR
2022-08-16 14:47:41 +00:00
JJ Kasper
f3cbc5d746 [next] Fix un-necessary edge routes being added (#8408)
Currently we are adding routes for edge function un-necessarily as static edge functions don't need routes added and dynamic edge functions already have their routes included in dynamicRoutes in the routes-manifest.
Related Issues
Fixes: slack thread
📋 Checklist

Tests

 The code changed/added as part of this PR has been covered with tests
 All tests pass locally with yarn test-unit

Code Review

 This PR has a concise title and thorough description useful to a reviewer
 Issue from task tracker has a link to this PR
2022-08-16 15:14:49 +01:00
Sean Massa
40df88b483 Revert "add test for main.go scenario"
This reverts commit 75c4f45b73.
2022-08-16 03:03:11 -05:00
Sean Massa
75c4f45b73 add test for main.go scenario 2022-08-16 03:01:12 -05:00
Sean Massa
05a236f944 Publish Stable
- vercel@28.0.2
 - @vercel/ruby@1.3.27
2022-08-16 02:49:19 -05:00
Sean Massa
4b7383f521 [cli] serialize getDeployment calls in vercel bisect (#8403) 2022-08-16 02:45:48 -05:00
Sean Massa
c263c31e48 [cli][tests] remove dupe inspectorUrl (#8400) 2022-08-15 22:14:29 -05:00
Sean Massa
c80530f9b1 [cli] fix: undefined variable (#8401)
The variable `chunks` doesn't exist in this context. Updated the error message to reference the `lines` count instead.
2022-08-15 22:43:04 +00:00
Sean Massa
16fd4396ef [tests] skip ruby test for now (#8404) 2022-08-15 17:30:02 -05:00
Nathan Rajlich
4e7138f400 [docs] Remove "watch" from DEVELOPING_A_RUNTIME.md (#8391)
Remove "watch" from `DEVELOPING_A_RUNTIME.md`

`vercel dev` no longer utilizes the `watch` field, so let's not document it here.
2022-08-13 15:57:25 -07:00
123 changed files with 1202 additions and 135 deletions

View File

@@ -63,9 +63,6 @@ export async function build(options: BuildOptions) {
const lambda = createLambda(/* … */);
return {
output: lambda,
watch: [
// Dependent files to trigger a rebuild in `vercel dev` go here…
],
routes: [
// If your Runtime needs to define additional routing, define it here…
],

View File

@@ -99,6 +99,7 @@
"selector": "MemberExpression > Identifier[name='substr']"
}
],
"no-dupe-keys": 2,
"require-atomic-updates": 0,
"@typescript-eslint/ban-ts-comment": 0,
"@typescript-eslint/camelcase": 0,

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "28.0.1",
"version": "28.1.1",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Vercel",
@@ -42,14 +42,14 @@
},
"dependencies": {
"@vercel/build-utils": "5.3.1",
"@vercel/go": "2.1.1",
"@vercel/go": "2.2.0",
"@vercel/hydrogen": "0.0.14",
"@vercel/next": "3.1.18",
"@vercel/next": "3.1.20",
"@vercel/node": "2.5.8",
"@vercel/python": "3.1.9",
"@vercel/python": "3.1.10",
"@vercel/redwood": "1.0.18",
"@vercel/remix": "1.0.19",
"@vercel/ruby": "1.3.26",
"@vercel/ruby": "1.3.27",
"@vercel/static-build": "1.0.18",
"update-notifier": "5.1.0"
},

View File

@@ -59,7 +59,7 @@ export default async function rm(
const removeStamp = stamp();
if (!opts['--yes'] && !(await confirmAliasRemove(client, alias))) {
output.log('Aborted');
output.log('Canceled');
return 0;
}

View File

@@ -220,7 +220,7 @@ function handleSetupDomainError<T>(
}
if (error instanceof ERRORS.UserAborted) {
output.error(`User aborted`);
output.error(`User canceled.`);
return 1;
}

View File

@@ -116,8 +116,6 @@ export default async function main(client: Client): Promise<number> {
}
}
const badDeploymentPromise = getDeployment(client, bad).catch(err => err);
good = normalizeURL(good);
parsed = parse(good);
if (!parsed.hostname) {
@@ -138,8 +136,6 @@ export default async function main(client: Client): Promise<number> {
);
}
const goodDeploymentPromise = getDeployment(client, good).catch(err => err);
if (!subpath) {
subpath = await prompt(
client,
@@ -148,10 +144,9 @@ export default async function main(client: Client): Promise<number> {
}
output.spinner('Retrieving deployments…');
const [badDeployment, goodDeployment] = await Promise.all([
badDeploymentPromise,
goodDeploymentPromise,
]);
// `getDeployment` cannot be parallelized because it might prompt for login
const badDeployment = await getDeployment(client, bad).catch(err => err);
if (badDeployment) {
if (badDeployment instanceof Error) {
@@ -165,7 +160,8 @@ export default async function main(client: Client): Promise<number> {
return 1;
}
const { projectId } = badDeployment;
// `getDeployment` cannot be parallelized because it might prompt for login
const goodDeployment = await getDeployment(client, good).catch(err => err);
if (goodDeployment) {
if (goodDeployment instanceof Error) {
@@ -181,6 +177,8 @@ export default async function main(client: Client): Promise<number> {
return 1;
}
const { projectId } = badDeployment;
if (projectId !== goodDeployment.projectId) {
output.error(`Good and Bad deployments must be from the same Project`);
return 1;

View File

@@ -171,7 +171,7 @@ export default async function main(client: Client): Promise<number> {
);
}
if (!confirmed) {
client.output.print(`Aborted. No Project Settings retrieved.\n`);
client.output.print(`Canceled. No Project Settings retrieved.\n`);
return 0;
}
const { argv: originalArgv } = client;

View File

@@ -296,7 +296,7 @@ export default async (client: Client): Promise<number> => {
));
if (!shouldStartSetup) {
output.print(`Aborted. Project not set up.\n`);
output.print(`Canceled. Project not set up.\n`);
return 0;
}

View File

@@ -37,7 +37,7 @@ export default async function add(
const { domain, data: argData } = parsedParams;
const data = await getDNSData(client, argData);
if (!data) {
output.log(`Aborted`);
output.log(`Canceled`);
return 1;
}

View File

@@ -46,7 +46,7 @@ export default async function rm(
);
if (!yes) {
output.error(`User aborted.`);
output.error(`User canceled.`);
return 0;
}

View File

@@ -68,7 +68,7 @@ export default async function move(
client
))
) {
output.log('Aborted');
output.log('Canceled');
return 0;
}
}
@@ -87,7 +87,7 @@ export default async function move(
client
))
) {
output.log('Aborted');
output.log('Canceled');
return 0;
}
}

View File

@@ -86,7 +86,7 @@ export default async function rm(
client
))
) {
output.log('Aborted');
output.log('Canceled');
return 0;
}
@@ -224,7 +224,7 @@ async function removeDomain(
!skipConfirmation &&
!(await promptBool(`Remove conflicts associated with domain?`, client))
) {
output.log('Aborted');
output.log('Canceled');
return 0;
}

View File

@@ -84,7 +84,7 @@ export default async function pull(
false
))
) {
output.log('Aborted');
output.log('Canceled');
return 0;
}

View File

@@ -111,7 +111,7 @@ export default async function rm(
false
))
) {
output.log('Aborted');
output.log('Canceled');
return 0;
}

View File

@@ -149,7 +149,7 @@ export default async function connect(
}
if (remoteUrl === '') {
output.log('Aborted.');
output.log('Canceled');
return 0;
}
@@ -317,7 +317,7 @@ async function promptConnectArg({
false
);
if (!shouldConnect) {
client.output.log('Aborted. Repo not connected.');
client.output.log('Canceled. Repo not connected.');
}
}
return shouldConnect;
@@ -404,7 +404,7 @@ async function confirmRepoConnect(
true
);
if (!shouldReplaceProject) {
client.output.log('Aborted. Repo not connected.');
client.output.log('Canceled. Repo not connected.');
}
}
return shouldReplaceProject;

View File

@@ -43,7 +43,7 @@ export default async function disconnect(
await disconnectGitProvider(client, org, project.id);
output.log(`Disconnected ${chalk.cyan(`${linkOrg}/${repo}`)}.`);
} else {
output.log('Aborted.');
output.log('Canceled');
}
} else {
output.error(

View File

@@ -53,7 +53,7 @@ export default async function init(
);
if (!chosen) {
output.log('Aborted');
output.log('Canceled');
return 0;
}

View File

@@ -293,9 +293,7 @@ export default async function main(client: Client) {
// information to help the user find other deployments or instances
log(
`To list more deployments for a project, run ${getCommandName(
'ls [project]'
)}.`
`To list deployments for a project, run ${getCommandName('ls [project]')}.`
);
print('\n');
@@ -338,7 +336,7 @@ export default async function main(client: Client) {
if (pagination && pagination.count === 20) {
const flags = getCommandFlags(argv, ['_', '--next']);
log(
`To display the next page run ${getCommandName(
`To display the next page, run ${getCommandName(
`ls${app ? ' ' + app : ''}${flags} --next ${pagination.next}`
)}`
);

View File

@@ -226,7 +226,7 @@ export default async function main(client: Client) {
).toLowerCase();
if (confirmation !== 'y' && confirmation !== 'yes') {
output.log('Aborted');
output.log('Canceled');
return 1;
}
}

View File

@@ -229,7 +229,7 @@ async function run({ output, contextName, currentTeam, client }) {
argv.yes ||
(await readConfirmation(client, output, theSecret, contextName));
if (!yes) {
output.print(`Aborted. Secret not deleted.\n`);
output.print(`Canceled. Secret not deleted.\n`);
return 0;
}
} else {

View File

@@ -59,7 +59,7 @@ export default async function add(client: Client): Promise<number> {
});
} catch (err: unknown) {
if (isError(err) && err.message === 'USER_ABORT') {
output.log('Aborted');
output.log('Canceled');
return 0;
}

View File

@@ -426,7 +426,7 @@ export class UserAborted extends NowError<'USER_ABORTED', {}> {
super({
code: 'USER_ABORTED',
meta: {},
message: `The user aborted the operation.`,
message: `The user canceled the operation.`,
});
}
}

View File

@@ -39,7 +39,7 @@ export default function handleError(error: unknown, { debug = false } = {}) {
} else if (status === 500) {
console.error(errorOutput('Unexpected server error. Please retry.'));
} else if (code === 'USER_ABORT') {
info('Aborted');
info('Canceled');
} else {
console.error(
errorOutput(`Unexpected error. Please try again later. (${message})`)

View File

@@ -21,7 +21,7 @@ interface ListOptions {
choices: ListChoice[];
pageSize?: number;
separator?: boolean;
abort?: 'start' | 'end';
cancel?: 'start' | 'end';
eraseFinalAnswer?: boolean;
}
@@ -50,7 +50,7 @@ export default async function list(
],
pageSize = 15, // Show 15 lines without scrolling (~4 credit cards)
separator = false, // Puts a blank separator between each choice
abort = 'end', // Whether the `abort` option will be at the `start` or the `end`,
cancel = 'end', // Whether the `cancel` option will be at the `start` or the `end`,
eraseFinalAnswer = false, // If true, the line with the final answer that inquirer prints will be erased before returning
}: ListOptions
): Promise<string> {
@@ -97,17 +97,17 @@ export default async function list(
}
}
const abortSeparator = new inquirer.Separator('─'.repeat(biggestLength));
const _abort = {
name: 'Abort',
const cancelSeparator = new inquirer.Separator('─'.repeat(biggestLength));
const _cancel = {
name: 'Cancel',
value: '',
short: '',
};
if (abort === 'start') {
choices.unshift(_abort, abortSeparator);
if (cancel === 'start') {
choices.unshift(_cancel, cancelSeparator);
} else {
choices.push(abortSeparator, _abort);
choices.push(cancelSeparator, _cancel);
}
const answer = await client.prompt({

View File

@@ -28,6 +28,7 @@ export async function addGitConnection(
org: Org,
project: Project,
remoteUrls: Dictionary<string>,
autoConfirm: Boolean,
settings?: ProjectSettings
): Promise<number | void> {
if (!settings) {
@@ -39,7 +40,8 @@ export async function addGitConnection(
org,
project,
remoteUrls,
settings || project
settings || project,
autoConfirm
);
} else if (Object.keys(remoteUrls).length > 1 && !project.link) {
return addMultipleGitRemotes(
@@ -47,7 +49,8 @@ export async function addGitConnection(
org,
project,
remoteUrls,
settings || project
settings || project,
autoConfirm
);
}
}
@@ -57,7 +60,8 @@ async function addSingleGitRemote(
org: Org,
project: Project,
remoteUrls: Dictionary<string>,
settings: ProjectSettings
settings: ProjectSettings,
autoConfirm: Boolean
) {
const [remoteName, remoteUrl] = Object.entries(remoteUrls)[0];
const repoInfo = parseRepoUrl(remoteUrl);
@@ -81,14 +85,27 @@ async function addSingleGitRemote(
(project.link.org !== parsedOrg ||
project.link.repo !== repo ||
project.link.type !== provider);
const shouldConnect = await promptGitConnectSingleUrl(
let shouldConnectOption: string | undefined;
if (autoConfirm) {
shouldConnectOption = 'yes';
} else {
shouldConnectOption = await promptGitConnectSingleUrl(
client,
project,
remoteName,
remoteUrl,
replace
);
}
return handleOptions(
shouldConnectOption,
client,
org,
project,
remoteName,
remoteUrl,
replace
settings,
repoInfo
);
return handleOptions(shouldConnect, client, org, project, settings, repoInfo);
}
async function addMultipleGitRemotes(
@@ -96,12 +113,15 @@ async function addMultipleGitRemotes(
org: Org,
project: Project,
remoteUrls: Dictionary<string>,
settings: ProjectSettings
settings: ProjectSettings,
autoConfirm: Boolean
) {
client.output.log('Found multiple Git remote URLs in Git config.');
const remoteUrlOrOptions = await promptGitConnectMultipleUrls(
client,
remoteUrls
);
return handleOptions(remoteUrlOrOptions, client, org, project, settings);
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);
}

View File

@@ -89,7 +89,7 @@ export default async function setupAndLink(
));
if (!shouldStartSetup) {
output.print(`Aborted. Project not set up.\n`);
output.print(`Canceled. Project not set up.\n`);
return { status: 'not_linked', org: null, project: null };
}
@@ -136,7 +136,8 @@ export default async function setupAndLink(
client,
org,
project,
remoteUrls
remoteUrls,
autoConfirm
);
if (typeof connectGit === 'number') {
return { status: 'error', exitCode: connectGit };
@@ -264,6 +265,7 @@ export default async function setupAndLink(
org,
project,
remoteUrls,
autoConfirm,
settings
);
if (typeof connectGit === 'number') {

View File

@@ -94,7 +94,7 @@ export default async function validatePaths(
);
if (!shouldDeployHomeDirectory) {
output.print(`Aborted\n`);
output.print(`Canceled\n`);
return { valid: false, exitCode: 0 };
}
}

View File

@@ -0,0 +1,2 @@
!.vercel
.vercel

View File

@@ -0,0 +1,16 @@
[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/*

View File

@@ -9,7 +9,7 @@ export function readOutputStream(
let lines = 0;
const timeout = setTimeout(() => {
reject(
new Error(`Was waiting for ${length} lines, but only received ${chunks.length}`)
new Error(`Was waiting for ${length} lines, but only received ${lines}`)
);
}, 3000);

View File

@@ -1862,7 +1862,7 @@ test('ensure we render a prompt when deploying home directory', async t => {
'You are deploying your home directory. Do you want to continue? [y/N]'
)
);
t.true(stderr.includes('Aborted'));
t.true(stderr.includes('Canceled'));
});
test('ensure the `scope` property works with email', async t => {

View File

@@ -24,7 +24,6 @@ export function useDeployment({
const deployment: Deployment = {
id,
url: url.hostname,
inspectorUrl: `https://vercel.com/team/project/${id.replace('dpl_', '')}`,
name,
meta: {},
regions: [],

View File

@@ -306,5 +306,52 @@ describe('link', () => {
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);
}
});
});
});

View File

@@ -285,6 +285,10 @@ export async function build({
const outDir = await getWriteableDirectory();
// in order to allow the user to have `main.go`,
// we need our `main.go` to be called something else
const mainGoFileName = 'main__vc__go__.go';
if (packageName !== 'main') {
const go = await createGo(
workPath,
@@ -321,9 +325,8 @@ export async function build({
}
}
const mainModGoFileName = 'main__mod__.go';
const modMainGoContents = await readFile(
join(__dirname, mainModGoFileName),
join(__dirname, 'main.go'),
'utf8'
);
@@ -349,29 +352,29 @@ export async function build({
if (isGoModExist && isGoModInRootDir) {
debug('[mod-root] Write main file to ' + downloadPath);
await writeFile(
join(downloadPath, mainModGoFileName),
join(downloadPath, mainGoFileName),
mainModGoContents
);
undoFileActions.push({
to: undefined, // delete
from: join(downloadPath, mainModGoFileName),
from: join(downloadPath, mainGoFileName),
});
} else if (isGoModExist && !isGoModInRootDir) {
debug('[mod-other] Write main file to ' + goModPath);
await writeFile(join(goModPath, mainModGoFileName), mainModGoContents);
await writeFile(join(goModPath, mainGoFileName), mainModGoContents);
undoFileActions.push({
to: undefined, // delete
from: join(goModPath, mainModGoFileName),
from: join(goModPath, mainGoFileName),
});
} else {
debug('[entrypoint] Write main file to ' + entrypointDirname);
await writeFile(
join(entrypointDirname, mainModGoFileName),
join(entrypointDirname, mainGoFileName),
mainModGoContents
);
undoFileActions.push({
to: undefined, // delete
from: join(entrypointDirname, mainModGoFileName),
from: join(entrypointDirname, mainGoFileName),
});
}
@@ -428,7 +431,7 @@ export async function build({
const destPath = join(outDir, handlerFileName);
try {
const src = [join(baseGoModPath, mainModGoFileName)];
const src = [join(baseGoModPath, mainGoFileName)];
await go.build(src, destPath);
} catch (err) {
@@ -449,18 +452,13 @@ export async function build({
},
false
);
const origianlMainGoContents = await readFile(
const originalMainGoContents = await readFile(
join(__dirname, 'main.go'),
'utf8'
);
const mainGoContents = origianlMainGoContents.replace(
'__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__vc__go__.go';
const mainGoContents = originalMainGoContents
.replace('"__VC_HANDLER_PACKAGE_NAME"', '')
.replace('__VC_HANDLER_FUNC_NAME', handlerFunctionName);
// Go doesn't like to build files in different directories,
// so now we place `main.go` together with the user code
@@ -498,6 +496,7 @@ export async function build({
files: { ...(await glob('**', outDir)), ...includedFiles },
handler: handlerFileName,
runtime: 'go1.x',
supportsWrapper: true,
environment: {},
});

View File

@@ -1,10 +1,31 @@
package main
import (
vc "github.com/vercel/go-bridge/go/bridge"
"net/http"
"os"
"syscall"
"__VC_HANDLER_PACKAGE_NAME"
vc "github.com/vercel/go-bridge/go/bridge"
)
func checkForLambdaWrapper() {
wrapper := os.Getenv("AWS_LAMBDA_EXEC_WRAPPER")
if wrapper == "" {
return
}
// Removing the env var doesn't work
// Set it to empty string to override the previous value
os.Setenv("AWS_LAMBDA_EXEC_WRAPPER", "")
argv := append([]string{wrapper}, os.Args...)
err := syscall.Exec(wrapper, argv, os.Environ())
if err != nil {
panic(err)
}
}
func main() {
checkForLambdaWrapper()
vc.Start(http.HandlerFunc(__VC_HANDLER_FUNC_NAME))
}

View File

@@ -1,12 +0,0 @@
package main
import (
"__VC_HANDLER_PACKAGE_NAME"
"net/http"
vc "github.com/vercel/go-bridge/go/bridge"
)
func main() {
vc.Start(http.HandlerFunc(__VC_HANDLER_FUNC_NAME))
}

View File

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

View File

@@ -0,0 +1 @@
module env

View File

@@ -0,0 +1,19 @@
package env
import (
"fmt"
"net/http"
"os"
)
// Handler function
func Handler(w http.ResponseWriter, r *http.Request) {
rdm := os.Getenv("RANDOMNESS_ENV")
if rdm == "" {
fmt.Println("No env received")
}
fmt.Fprintln(w, rdm)
fmt.Fprintln(w, os.Getenv("LOREM"))
fmt.Fprintln(w, os.Getenv("IPSUM"))
}

View File

@@ -0,0 +1,28 @@
{
"version": 2,
"builds": [
{
"src": "env/index.go",
"use": "@vercel/go"
}
],
"env": {
"RANDOMNESS_ENV": "RANDOMNESS_PLACEHOLDER",
"LOREM": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean turpis nisl, porta vel dictum id, placerat eu massa. Curabitur id diam at urna elementum condimentum a eget augue. Sed vehicula, mauris quis tincidunt iaculis, lacus quam dictum nulla, eu pellentesque justo lectus a erat. Integer volutpat magna tortor, non mollis tortor rhoncus quis. Donec id urna ligula. Praesent et ligula id ligula blandit rhoncus. Proin consequat, justo id maximus lacinia, tortor dui facilisis nunc, at aliquet odio orci nec tellus. Vestibulum sagittis nec sem id mollis. Donec eleifend risus eget lectus mattis convallis. Nam ac urna commodo, venenatis massa ut, varius magna. Aliquam erat volutpat. Ut ac lacinia erat. Mauris finibus vehicula elementum. Proin mauris neque, fringilla a erat fermentum, convallis elementum urna. Pellentesque bibendum nisl eget nisi sodales, a faucibus felis scelerisque. Fusce blandit imperdiet nunc, ac hendrerit ante placerat sed. Cras metus dolor, cursus non orci sed, iaculis tempor nunc. Quisque vitae enim pharetra, viverra massa non, mollis magna. Vivamus sit amet ultricies ligula, in vulputate sapien. Praesent ullamcorper justo in elit vulputate, et varius augue egestas. Donec quis rutrum mauris. Suspendisse placerat volutpat gravida. Nunc laoreet velit a accumsan faucibus. Nunc eu lorem sem. Sed id nunc a metus gravida accumsan. Morbi aliquet purus id ipsum dictum, nec finibus quam ullamcorper. Quisque sapien nulla, laoreet a accumsan non, luctus quis ante. Sed sit amet pellentesque magna. Aenean pulvinar porta est sed posuere. Aenean id nisl dictum, varius diam vel, facilisis ex. Praesent quis justo id mi eleifend eleifend. Aliquam imperdiet purus non ligula lobortis laoreet. Sed mollis aliquet dui et luctus. Donec ut lacus vel tellus porta feugiat. Nam lacinia euismod libero. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi facilisis quam nec nisl pretium, id blandit sapien pretium. Donec id sapien varius, ornare mi sed, pretium magna. Phasellus tortor ligula, porttitor sit amet magna in, semper condimentum elit.",
"IPSUM": "Phasellus ac orci eleifend, dignissim turpis et, aliquet libero. Praesent aliquet justo augue, vel vulputate ex dictum ut. Donec eu interdum ex, sit amet hendrerit felis. Maecenas eget iaculis orci, eget porta eros. Pellentesque vitae neque in velit dapibus luctus. Pellentesque ornare et tellus eu congue. Aliquam eu sem vel neque varius faucibus. Ut eget tortor ornare, fermentum enim nec, pellentesque massa. Phasellus rhoncus aliquet nunc nec semper. Nullam sed iaculis tellus. Mauris a sollicitudin velit, id egestas odio. Suspendisse commodo commodo turpis, et sollicitudin sem commodo a. Vivamus condimentum, arcu ac tempus blandit, lectus ligula pulvinar est, in congue mi nunc et lacus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi sodales ipsum quis scelerisque vehicula. Quisque gravida nibh vitae mattis sollicitudin. Donec fringilla dapibus urna non gravida. Phasellus et eros id magna tristique consequat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In lacus neque, auctor sed arcu at, varius volutpat est. Maecenas eget ante sed ipsum sagittis laoreet ut nec nisi. Quisque scelerisque, risus ut efficitur sollicitudin, neque est faucibus lacus, vitae eleifend nulla sem a magna. Integer viverra, diam eget venenatis pretium, augue ex pulvinar justo, ac ultrices neque nisl laoreet risus. Pellentesque commodo ultrices laoreet. Nulla nec ipsum non augue hendrerit vulputate sed eget diam. Maecenas semper rutrum ligula. Sed egestas, orci sed volutpat varius, eros mi lacinia magna, tincidunt aliquet nibh lacus eget dui. Integer vestibulum velit in interdum ultrices. Mauris porta vitae quam non placerat. In nisi risus, hendrerit rhoncus hendrerit at, lacinia vel mauris. Curabitur tempus mattis eros nec consequat. Sed posuere elit lobortis libero porta, sed pharetra tortor ornare. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse pulvinar ante vitae metus ullamcorper euismod. Nulla facilisi. Donec quam nulla, eleifend vel consequat sed, maximus et nisi. Donec molestie euismod semper. Fusce eget arcu feugiat, efficitur lectus sed, feugiat justo. Mauris ultricies pretium ante non faucibus. Aenean egestas ante nunc, id pellentesque metus blandit eu. Nullam faucibus fringilla lectus, quis dapibus turpis elementum eu. Nunc eget dolor in velit molestie interdum id eu justo. Aliquam ornare arcu quis tincidunt posuere. Mauris sed porttitor ligula. Vestibulum tincidunt non lacus id lacinia. Donec ex augue, convallis vel justo vel, faucibus ultricies tortor."
},
"probes": [
{
"path": "/env",
"mustContain": "RANDOMNESS_PLACEHOLDER"
},
{
"path": "/env",
"mustContain": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean turpis nisl, porta vel dictum id, placerat eu massa. Curabitur id diam at urna elementum condimentum a eget augue. Sed vehicula, mauris quis tincidunt iaculis, lacus quam dictum nulla, eu pellentesque justo lectus a erat. Integer volutpat magna tortor, non mollis tortor rhoncus quis. Donec id urna ligula. Praesent et ligula id ligula blandit rhoncus. Proin consequat, justo id maximus lacinia, tortor dui facilisis nunc, at aliquet odio orci nec tellus. Vestibulum sagittis nec sem id mollis. Donec eleifend risus eget lectus mattis convallis. Nam ac urna commodo, venenatis massa ut, varius magna. Aliquam erat volutpat. Ut ac lacinia erat. Mauris finibus vehicula elementum. Proin mauris neque, fringilla a erat fermentum, convallis elementum urna. Pellentesque bibendum nisl eget nisi sodales, a faucibus felis scelerisque. Fusce blandit imperdiet nunc, ac hendrerit ante placerat sed. Cras metus dolor, cursus non orci sed, iaculis tempor nunc. Quisque vitae enim pharetra, viverra massa non, mollis magna. Vivamus sit amet ultricies ligula, in vulputate sapien. Praesent ullamcorper justo in elit vulputate, et varius augue egestas. Donec quis rutrum mauris. Suspendisse placerat volutpat gravida. Nunc laoreet velit a accumsan faucibus. Nunc eu lorem sem. Sed id nunc a metus gravida accumsan. Morbi aliquet purus id ipsum dictum, nec finibus quam ullamcorper. Quisque sapien nulla, laoreet a accumsan non, luctus quis ante. Sed sit amet pellentesque magna. Aenean pulvinar porta est sed posuere. Aenean id nisl dictum, varius diam vel, facilisis ex. Praesent quis justo id mi eleifend eleifend. Aliquam imperdiet purus non ligula lobortis laoreet. Sed mollis aliquet dui et luctus. Donec ut lacus vel tellus porta feugiat. Nam lacinia euismod libero. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi facilisis quam nec nisl pretium, id blandit sapien pretium. Donec id sapien varius, ornare mi sed, pretium magna. Phasellus tortor ligula, porttitor sit amet magna in, semper condimentum elit."
},
{
"path": "/env",
"mustContain": "Phasellus ac orci eleifend, dignissim turpis et, aliquet libero. Praesent aliquet justo augue, vel vulputate ex dictum ut. Donec eu interdum ex, sit amet hendrerit felis. Maecenas eget iaculis orci, eget porta eros. Pellentesque vitae neque in velit dapibus luctus. Pellentesque ornare et tellus eu congue. Aliquam eu sem vel neque varius faucibus. Ut eget tortor ornare, fermentum enim nec, pellentesque massa. Phasellus rhoncus aliquet nunc nec semper. Nullam sed iaculis tellus. Mauris a sollicitudin velit, id egestas odio. Suspendisse commodo commodo turpis, et sollicitudin sem commodo a. Vivamus condimentum, arcu ac tempus blandit, lectus ligula pulvinar est, in congue mi nunc et lacus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi sodales ipsum quis scelerisque vehicula. Quisque gravida nibh vitae mattis sollicitudin. Donec fringilla dapibus urna non gravida. Phasellus et eros id magna tristique consequat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In lacus neque, auctor sed arcu at, varius volutpat est. Maecenas eget ante sed ipsum sagittis laoreet ut nec nisi. Quisque scelerisque, risus ut efficitur sollicitudin, neque est faucibus lacus, vitae eleifend nulla sem a magna. Integer viverra, diam eget venenatis pretium, augue ex pulvinar justo, ac ultrices neque nisl laoreet risus. Pellentesque commodo ultrices laoreet. Nulla nec ipsum non augue hendrerit vulputate sed eget diam. Maecenas semper rutrum ligula. Sed egestas, orci sed volutpat varius, eros mi lacinia magna, tincidunt aliquet nibh lacus eget dui. Integer vestibulum velit in interdum ultrices. Mauris porta vitae quam non placerat. In nisi risus, hendrerit rhoncus hendrerit at, lacinia vel mauris. Curabitur tempus mattis eros nec consequat. Sed posuere elit lobortis libero porta, sed pharetra tortor ornare. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse pulvinar ante vitae metus ullamcorper euismod. Nulla facilisi. Donec quam nulla, eleifend vel consequat sed, maximus et nisi. Donec molestie euismod semper. Fusce eget arcu feugiat, efficitur lectus sed, feugiat justo. Mauris ultricies pretium ante non faucibus. Aenean egestas ante nunc, id pellentesque metus blandit eu. Nullam faucibus fringilla lectus, quis dapibus turpis elementum eu. Nunc eget dolor in velit molestie interdum id eu justo. Aliquam ornare arcu quis tincidunt posuere. Mauris sed porttitor ligula. Vestibulum tincidunt non lacus id lacinia. Donec ex augue, convallis vel justo vel, faucibus ultricies tortor."
}
]
}

View File

@@ -0,0 +1,5 @@
module github.com/vercel/does-not-exist
go 1.13
require github.com/dhruvbird/go-cowsay v0.0.0-20131019225157-6fd7bd0281c0 // indirect

View File

@@ -0,0 +1,11 @@
package handler
import (
"fmt"
"net/http"
"runtime"
)
func Handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "version:%s:RANDOMNESS_PLACEHOLDER", runtime.Version())
}

View File

@@ -0,0 +1,14 @@
package main
import (
"net/http"
)
func main() {
server := http.Server{
Addr: "localhost:3000",
Handler: http.HandlerFunc(api.IndexHandler),
}
server.ListenAndServe()
}

View File

@@ -0,0 +1,9 @@
{
"version": 2,
"probes": [
{
"path": "/api",
"mustContain": "version:go1.13.15:RANDOMNESS_PLACEHOLDER"
}
]
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/next",
"version": "3.1.18",
"version": "3.1.20",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",

View File

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

View File

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

View File

@@ -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,
@@ -2326,8 +2326,16 @@ export async function getMiddlewareBundle({
for (const worker of workerConfigs.values()) {
const edgeFile = worker.edgeFunction.name;
const shortPath = edgeFile.replace(/^pages\//, '');
worker.edgeFunction.name = shortPath;
source.edgeFunctions[shortPath] = worker.edgeFunction;
// we don't add the route for edge functions as these
// are already added in the routes-manifest under dynamicRoutes
if (worker.type === 'function') {
continue;
}
const route: Route = {
continue: true,
src: worker.routeSrc,
@@ -2340,13 +2348,9 @@ export async function getMiddlewareBundle({
],
};
if (worker.type === 'function') {
route.dest = shortPath;
} else {
route.middlewarePath = shortPath;
if (isCorrectMiddlewareOrder) {
route.override = true;
}
route.middlewarePath = shortPath;
if (isCorrectMiddlewareOrder) {
route.override = true;
}
if (routesManifest.version > 3 && isDynamicRoute(worker.page)) {

View File

@@ -0,0 +1,7 @@
export default function AnotherPage(props) {
return (
<>
<p>hello from newroot/dashboard/another</p>
</>
);
}

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

View File

@@ -0,0 +1,7 @@
export default function ChangelogPage(props) {
return (
<>
<p>hello from app/dashboard/changelog</p>
</>
);
}

View File

@@ -0,0 +1,7 @@
export default function HelloPage(props) {
return (
<>
<p>hello from app/dashboard/rootonly/hello</p>
</>
);
}

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

View File

@@ -0,0 +1,3 @@
b {
color: blue;
}

View File

@@ -0,0 +1,3 @@
.red {
color: red;
}

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

View File

@@ -0,0 +1,7 @@
export default function ClientPage() {
return (
<>
<p>hello from app/client-nested</p>
</>
);
}

View File

@@ -0,0 +1,3 @@
button {
color: red;
}

View File

@@ -0,0 +1,3 @@
.red {
color: red;
}

View File

@@ -0,0 +1,7 @@
export default function DeploymentsBreakdownPage(props) {
return (
<>
<p>hello from app/dashboard/(custom)/deployments/breakdown</p>
</>
);
}

View File

@@ -0,0 +1,8 @@
export default function CustomDashboardRootLayout({ children }) {
return (
<>
<h2>Custom dashboard</h2>
{children}
</>
);
}

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

View File

@@ -0,0 +1,7 @@
export default function DeploymentsInfoPage(props) {
return (
<>
<p>hello from app/dashboard/deployments/info</p>
</>
);
}

View File

@@ -0,0 +1,16 @@
export function getServerSideProps() {
return {
props: {
message: 'hello',
},
};
}
export default function DeploymentsLayout({ message, children }) {
return (
<>
<h2>Deployments {message}</h2>
{children}
</>
);
}

View File

@@ -0,0 +1,7 @@
export default function LazyComponent() {
return (
<>
<p>hello from lazy</p>
</>
);
}

View File

@@ -0,0 +1,10 @@
import { ClientComponent } from './test.client.js';
export default function DashboardIndexPage() {
return (
<>
<p>hello from app/dashboard/index</p>
<ClientComponent />
</>
);
}

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

View File

@@ -0,0 +1,7 @@
export default function IntegrationsPage(props) {
return (
<>
<p>hello from app/dashboard/integrations</p>
</>
);
}

View File

@@ -0,0 +1,8 @@
export default function DashboardLayout(props) {
return (
<>
<h1>Dashboard</h1>
{props.children}
</>
);
}

View File

@@ -0,0 +1,7 @@
export default function DashboardPage(props) {
return (
<>
<p>hello from app/dashboard</p>
</>
);
}

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

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

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

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

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

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

View File

@@ -0,0 +1,7 @@
export default function SharedComponentRoute() {
return (
<>
<p>hello from app/shared-component-route</p>
</>
);
}

View File

@@ -0,0 +1,7 @@
export default function ShouldNotServeClientDotJs(props) {
return (
<>
<p>hello from app/should-not-serve-client</p>
</>
);
}

View File

@@ -0,0 +1,7 @@
export default function ShouldNotServeServerDotJs(props) {
return (
<>
<p>hello from app/should-not-serve-server</p>
</>
);
}

View File

@@ -0,0 +1,3 @@
export default function Loading() {
return <p id="loading-layout">Loading layout...</p>;
}

View File

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

View File

@@ -0,0 +1,3 @@
export default function Loading() {
return <p id="loading-page">Loading page...</p>;
}

View 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>;
}

View File

@@ -0,0 +1,3 @@
export default function Loading() {
return <p id="loading">Loading...</p>;
}

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

View File

@@ -0,0 +1,3 @@
export default function Page() {
return <h1 id="page-message">Hello World</h1>;
}

View File

@@ -0,0 +1,3 @@
export default function Loading() {
return <p id="loading">Loading...</p>;
}

View 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>;
}

View File

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

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

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

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

View File

@@ -0,0 +1,7 @@
{
"dependencies": {
"next": "https://files-26yo0dy1b-ijjk-testing.vercel.app",
"react": "experimental",
"react-dom": "experimental"
}
}

View File

@@ -0,0 +1,7 @@
export default function Page(props) {
return (
<>
<p>hello from pages/blog/[slug]</p>
</>
);
}

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

View File

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

View 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": "{&quot;category&quot;:&quot;category-1&quot;,&quot;id&quot;:&quot;id-1&quot;}"
},
{
"path": "/dashboard/changelog",
"status": 200,
"mustContain": "hello from app/dashboard/changelog"
}
]
}

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

View File

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

View File

@@ -0,0 +1,11 @@
{
"scripts": {
"dev": "next dev",
"build": "next build"
},
"dependencies": {
"next": "canary",
"react": "latest",
"react-dom": "latest"
}
}

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