mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-06 04:22:01 +00:00
[next] Re-enable shared lambdas by default (#4757)
This re-enables the shared lambdas optimization by default and also adds additional tests to ensure that when a `now.json` or `vercel.json` contains either `routes` or `functions` configs the shared lambda optimization is disabled. Additional test deployments done: - minimal `now.json` with `builds` config [deploy](https://shared-lambdas-tests-d646fsqju.vercel.app) - `now.json` with `functions` config [deploy](https://shared-lambdas-tests-ahnuosp4s.vercel.app) - `now.json` with `routes` config [deploy](https://shared-lambdas-tests-gulam3jda.vercel.app) - minimal `vercel.json` with `builds` config [deploy](https://shared-lambdas-tests-7ic7wzirs.vercel.app) - `vercel.json` with `functions` config [deploy](https://shared-lambdas-tests-7ic7wzirs.vercel.app) - `vercel.json` with `routes` config [deploy](https://shared-lambdas-tests-rja2391tq.vercel.app)
This commit is contained in:
@@ -71,7 +71,7 @@ import {
|
||||
syncEnvVars,
|
||||
validateEntrypoint,
|
||||
} from './utils';
|
||||
// import findUp from 'find-up';
|
||||
import findUp from 'find-up';
|
||||
import { Sema } from 'async-sema';
|
||||
|
||||
interface BuildParamsMeta {
|
||||
@@ -231,47 +231,39 @@ export const build = async ({
|
||||
});
|
||||
}
|
||||
|
||||
// let nowJsonPath = Object.keys(files).find(file => {
|
||||
// return file.endsWith('now.json') || file.endsWith('vercel.json')
|
||||
// })
|
||||
const nowJsonPath = await findUp(['now.json', 'vercel.json'], {
|
||||
cwd: path.join(workPath, path.dirname(entrypoint)),
|
||||
});
|
||||
|
||||
// if (nowJsonPath) nowJsonPath = files[nowJsonPath].fsPath
|
||||
let hasLegacyRoutes = false;
|
||||
const hasFunctionsConfig = !!config.functions;
|
||||
|
||||
// if (!nowJsonPath) {
|
||||
// nowJsonPath = await findUp(['now.json', 'vercel.json'], {
|
||||
// cwd: path.join(workPath, path.dirname(entrypoint))
|
||||
// })
|
||||
// }
|
||||
if (nowJsonPath) {
|
||||
const nowJsonData = JSON.parse(await readFile(nowJsonPath, 'utf8'));
|
||||
|
||||
// let hasLegacyRoutes = false;
|
||||
// const hasFunctionsConfig = !!config.functions;
|
||||
if (Array.isArray(nowJsonData.routes) && nowJsonData.routes.length > 0) {
|
||||
hasLegacyRoutes = true;
|
||||
console.warn(
|
||||
`WARNING: your application is being opted out of @vercel/next's optimized lambdas mode due to legacy routes in ${path.basename(
|
||||
nowJsonPath
|
||||
)}. http://err.sh/vercel/vercel/next-legacy-routes-optimized-lambdas`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// if (nowJsonPath) {
|
||||
// const nowJsonData = JSON.parse(await readFile(nowJsonPath, 'utf8'));
|
||||
|
||||
// if (Array.isArray(nowJsonData.routes) && nowJsonData.routes.length > 0) {
|
||||
// hasLegacyRoutes = true;
|
||||
// console.warn(
|
||||
// `WARNING: your application is being opted out of @vercel/next's optimized lambdas mode due to legacy routes in ${path.basename(
|
||||
// nowJsonPath
|
||||
// )}. http://err.sh/vercel/vercel/next-legacy-routes-optimized-lambdas`
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (hasFunctionsConfig) {
|
||||
// console.warn(
|
||||
// `WARNING: Your application is being opted out of "@vercel/next" optimized lambdas mode due to \`functions\` config.\nMore info: http://err.sh/vercel/vercel/next-functions-config-optimized-lambdas`
|
||||
// );
|
||||
// }
|
||||
if (hasFunctionsConfig) {
|
||||
console.warn(
|
||||
`WARNING: Your application is being opted out of "@vercel/next" optimized lambdas mode due to \`functions\` config.\nMore info: http://err.sh/vercel/vercel/next-functions-config-optimized-lambdas`
|
||||
);
|
||||
}
|
||||
|
||||
// default to true but still allow opting out with the config
|
||||
const isSharedLambdas = !!config.sharedLambdas;
|
||||
// !hasLegacyRoutes &&
|
||||
// !hasFunctionsConfig &&
|
||||
// typeof config.sharedLambdas === 'undefined'
|
||||
// ? true
|
||||
// : !!config.sharedLambdas;
|
||||
const isSharedLambdas =
|
||||
!hasLegacyRoutes &&
|
||||
!hasFunctionsConfig &&
|
||||
typeof config.sharedLambdas === 'undefined'
|
||||
? true
|
||||
: !!config.sharedLambdas;
|
||||
|
||||
if (meta.isDev) {
|
||||
let childProcess: ChildProcess | undefined;
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
{
|
||||
"version": 2,
|
||||
"uploadNowJson": true,
|
||||
"builds": [
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@vercel/next",
|
||||
"config": {
|
||||
"sharedLambdas": true
|
||||
}
|
||||
"use": "@vercel/next"
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
@@ -29,6 +27,12 @@
|
||||
{
|
||||
"path": "/another/invite/hello",
|
||||
"mustContain": "hello from /[teamSlug]/[project]/[id]"
|
||||
},
|
||||
{
|
||||
"logMustNotContain": "WARNING: your application is being opted out of @vercel/next's optimized lambdas mode due to legacy routes"
|
||||
},
|
||||
{
|
||||
"logMustNotContain": "WARNING: Your application is being opted out of \"@vercel/next\" optimized lambdas mode due to `functions` config"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
"path": "/api/memory",
|
||||
"status": 200,
|
||||
"mustContain": "128"
|
||||
},
|
||||
{
|
||||
"logMustContain": "WARNING: Your application is being opted out of \"@vercel/next\" optimized lambdas mode due to `functions` config"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"uploadNowJson": true,
|
||||
"builds": [{ "src": "package.json", "use": "@vercel/next" }],
|
||||
"probes": [
|
||||
{
|
||||
@@ -61,6 +62,12 @@
|
||||
"x-hello": "world",
|
||||
"x-another": "value"
|
||||
}
|
||||
},
|
||||
{
|
||||
"logMustNotContain": "WARNING: your application is being opted out of @vercel/next's optimized lambdas mode due to legacy routes"
|
||||
},
|
||||
{
|
||||
"logMustNotContain": "WARNING: Your application is being opted out of \"@vercel/next\" optimized lambdas mode due to `functions` config"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
{
|
||||
"version": 2,
|
||||
"uploadNowJson": true,
|
||||
"builds": [{ "src": "packages/web/next.config.js", "use": "@vercel/next" }],
|
||||
"routes": [{ "src": "/(.*)", "dest": "/packages/web/$1", "continue": true }],
|
||||
"probes": [
|
||||
{
|
||||
"path": "/",
|
||||
"mustContain": "hello world <!-- -->6"
|
||||
},
|
||||
{
|
||||
"logMustContain": "WARNING: your application is being opted out of @vercel/next's optimized lambdas mode due to legacy routes"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
/* eslint-env jest */
|
||||
const fetch = require('node-fetch');
|
||||
const cheerio = require('cheerio');
|
||||
|
||||
module.exports = function(ctx) {
|
||||
it('should revalidate content properly from pathname', async () => {
|
||||
const res = await fetch(`${ctx.deploymentUrl}/another`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
let $ = cheerio.load(await res.text());
|
||||
const initialTime = $('#time').text();
|
||||
const initialRandom = $('#random').text();
|
||||
expect($('#hello').text()).toBe('hello: world');
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res2 = await fetch(`${ctx.deploymentUrl}/another`);
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
$ = cheerio.load(await res2.text());
|
||||
expect($('#hello').text()).toBe('hello: world');
|
||||
expect(initialTime).not.toBe($('#time').text());
|
||||
expect(initialRandom).not.toBe($('#random').text());
|
||||
});
|
||||
|
||||
it('should revalidate content properly from dynamic pathname', async () => {
|
||||
const res = await fetch(`${ctx.deploymentUrl}/blog/post-123`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
let $ = cheerio.load(await res.text());
|
||||
const initialTime = $('#time').text();
|
||||
const initialRandom = $('#random').text();
|
||||
expect($('#post').text()).toBe('Post: post-123');
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res2 = await fetch(`${ctx.deploymentUrl}/blog/post-123`);
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
$ = cheerio.load(await res2.text());
|
||||
expect($('#post').text()).toBe('Post: post-123');
|
||||
expect(initialTime).not.toBe($('#time').text());
|
||||
expect(initialRandom).not.toBe($('#random').text());
|
||||
});
|
||||
|
||||
it('should revalidate content properly from dynamic pathnames', async () => {
|
||||
const res = await fetch(`${ctx.deploymentUrl}/blog/post-123/comment-321`);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
let $ = cheerio.load(await res.text());
|
||||
const initialTime = $('#time').text();
|
||||
const initialRandom = $('#random').text();
|
||||
expect($('#post').text()).toBe('Post: post-123');
|
||||
expect($('#comment').text()).toBe('Comment: comment-321');
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res2 = await fetch(`${ctx.deploymentUrl}/blog/post-123/comment-321`);
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
$ = cheerio.load(await res2.text());
|
||||
expect($('#post').text()).toBe('Post: post-123');
|
||||
expect($('#comment').text()).toBe('Comment: comment-321');
|
||||
expect(initialTime).not.toBe($('#time').text());
|
||||
expect(initialRandom).not.toBe($('#random').text());
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /_next/data pathname', async () => {
|
||||
const res = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/another.json`
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
const { pageProps: data } = await res.json();
|
||||
const initialTime = data.time;
|
||||
const initialRandom = data.random;
|
||||
expect(data.world).toBe('world');
|
||||
expect(isNaN(initialTime)).toBe(false);
|
||||
expect(isNaN(initialRandom)).toBe(false);
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res2 = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/another.json`
|
||||
);
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
const { pageProps: data2 } = await res2.json();
|
||||
expect(data2.world).toBe('world');
|
||||
expect(isNaN(data2.time)).toBe(false);
|
||||
expect(isNaN(data2.random)).toBe(false);
|
||||
expect(initialTime).not.toBe(data2.time);
|
||||
expect(initialRandom).not.toBe(data2.random);
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /_next/data dynamic pathname', async () => {
|
||||
const res = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/blog/post-123.json`
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
const { pageProps: data } = await res.json();
|
||||
const initialTime = data.time;
|
||||
const initialRandom = data.random;
|
||||
expect(data.post).toBe('post-123');
|
||||
expect(isNaN(initialTime)).toBe(false);
|
||||
expect(isNaN(initialRandom)).toBe(false);
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res2 = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/blog/post-123.json`
|
||||
);
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
const { pageProps: data2 } = await res2.json();
|
||||
expect(data2.post).toBe('post-123');
|
||||
expect(isNaN(data2.time)).toBe(false);
|
||||
expect(isNaN(data2.random)).toBe(false);
|
||||
expect(initialTime).not.toBe(data2.time);
|
||||
expect(initialRandom).not.toBe(data2.random);
|
||||
});
|
||||
|
||||
it('should revalidate content properly from /_next/data dynamic pathnames', async () => {
|
||||
const res = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/blog/post-123/comment-321.json`
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
const { pageProps: data } = await res.json();
|
||||
const initialTime = data.time;
|
||||
const initialRandom = data.random;
|
||||
expect(data.post).toBe('post-123');
|
||||
expect(data.comment).toBe('comment-321');
|
||||
expect(isNaN(initialTime)).toBe(false);
|
||||
expect(isNaN(initialRandom)).toBe(false);
|
||||
|
||||
// wait for revalidation to occur
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const res2 = await fetch(
|
||||
`${ctx.deploymentUrl}/_next/data/testing-build-id/blog/post-123/comment-321.json`
|
||||
);
|
||||
expect(res2.status).toBe(200);
|
||||
|
||||
const { pageProps: data2 } = await res2.json();
|
||||
expect(data2.post).toBe('post-123');
|
||||
expect(data2.comment).toBe('comment-321');
|
||||
expect(isNaN(data2.time)).toBe(false);
|
||||
expect(isNaN(data2.random)).toBe(false);
|
||||
expect(initialTime).not.toBe(data2.time);
|
||||
expect(initialRandom).not.toBe(data2.random);
|
||||
});
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
generateBuildId() {
|
||||
return 'testing-build-id';
|
||||
},
|
||||
};
|
||||
@@ -1,146 +0,0 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@vercel/next",
|
||||
"config": {
|
||||
"sharedLambdas": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
{
|
||||
"path": "/lambda",
|
||||
"status": 200,
|
||||
"responseHeaders": {
|
||||
"x-vercel-cache": "MISS"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/forever",
|
||||
"status": 200,
|
||||
"responseHeaders": {
|
||||
"x-vercel-cache": "PRERENDER"
|
||||
}
|
||||
},
|
||||
{ "delay": 2000 },
|
||||
{
|
||||
"path": "/forever",
|
||||
"status": 200,
|
||||
"responseHeaders": {
|
||||
"x-vercel-cache": "HIT"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/blog/post-3",
|
||||
"status": 200,
|
||||
"mustContain": "loading..."
|
||||
},
|
||||
{ "delay": 2000 },
|
||||
{
|
||||
"path": "/blog/post-3",
|
||||
"status": 200,
|
||||
"responseHeaders": {
|
||||
"x-vercel-cache": "/HIT|STALE/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/blog/post-4.json",
|
||||
"status": 200,
|
||||
"responseHeaders": {
|
||||
"x-vercel-cache": "MISS"
|
||||
}
|
||||
},
|
||||
{ "delay": 2000 },
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/blog/post-4.json",
|
||||
"status": 200,
|
||||
"responseHeaders": {
|
||||
"x-vercel-cache": "/HIT|STALE/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/blog/post-3",
|
||||
"status": 200,
|
||||
"mustContain": "post-3"
|
||||
},
|
||||
{
|
||||
"path": "/blog/post-3/comment-3",
|
||||
"status": 200,
|
||||
"mustContain": "loading..."
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/lambda.json",
|
||||
"status": 404
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/forever.json",
|
||||
"status": 200,
|
||||
"responseHeaders": {
|
||||
"x-vercel-cache": "/PRERENDER|HIT/"
|
||||
}
|
||||
},
|
||||
{ "delay": 2000 },
|
||||
{
|
||||
"path": "/blog/post-3/comment-3",
|
||||
"status": 200,
|
||||
"mustContain": "comment-3"
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/forever.json",
|
||||
"status": 200,
|
||||
"responseHeaders": {
|
||||
"x-vercel-cache": "HIT"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/another2.json",
|
||||
"status": 200,
|
||||
"responseHeaders": {
|
||||
"x-vercel-cache": "PRERENDER"
|
||||
}
|
||||
},
|
||||
{ "delay": 2000 },
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/another2.json",
|
||||
"status": 200,
|
||||
"responseHeaders": {
|
||||
"x-vercel-cache": "HIT"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/nofallback/one",
|
||||
"status": 200,
|
||||
"mustContain": "one"
|
||||
},
|
||||
{
|
||||
"path": "/nofallback/two",
|
||||
"status": 200,
|
||||
"mustContain": "two"
|
||||
},
|
||||
{
|
||||
"path": "/nofallback/nope",
|
||||
"status": 404,
|
||||
"mustContain": "This page could not be found"
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/nofallback/one.json",
|
||||
"status": 200,
|
||||
"responseHeaders": {
|
||||
"x-vercel-cache": "/HIT|STALE|PRERENDER/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/nofallback/two.json",
|
||||
"status": 200,
|
||||
"responseHeaders": {
|
||||
"x-vercel-cache": "/HIT|STALE|PRERENDER/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/nofallback/nope.json",
|
||||
"status": 404
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"next": "canary",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export async function getStaticProps() {
|
||||
return {
|
||||
props: {
|
||||
world: 'world',
|
||||
random: Math.random(),
|
||||
time: new Date().getTime(),
|
||||
},
|
||||
unstable_revalidate: 1,
|
||||
};
|
||||
}
|
||||
|
||||
export default ({ world, time, random }) => {
|
||||
return (
|
||||
<>
|
||||
<p id="hello">hello: {world}</p>
|
||||
<span id="time">time: {time}</span>
|
||||
<span id="random">random: {random}</span>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export async function getStaticProps() {
|
||||
return {
|
||||
props: {
|
||||
world: 'world',
|
||||
time: new Date().getTime(),
|
||||
},
|
||||
unstable_revalidate: 5,
|
||||
};
|
||||
}
|
||||
|
||||
export default ({ world, time }) => {
|
||||
return (
|
||||
<>
|
||||
<p>hello: {world}</p>
|
||||
<span>time: {time}</span>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,40 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export async function getStaticPaths() {
|
||||
return {
|
||||
paths: [
|
||||
'/blog/post-1/comment-1',
|
||||
{ params: { post: 'post-2', comment: 'comment-2' } },
|
||||
'/blog/post-1337/comment-1337',
|
||||
'/blog/post-123/comment-321'
|
||||
],
|
||||
fallback: true,
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export async function getStaticProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
post: params.post,
|
||||
random: Math.random(),
|
||||
comment: params.comment,
|
||||
time: new Date().getTime(),
|
||||
},
|
||||
unstable_revalidate: 1,
|
||||
};
|
||||
}
|
||||
|
||||
export default ({ post, comment, time, random }) => {
|
||||
if (!post) return <p>loading...</p>;
|
||||
|
||||
return (
|
||||
<>
|
||||
<p id='post'>Post: {post}</p>
|
||||
<p id='comment'>Comment: {comment}</p>
|
||||
<span id='time'>time: {time}</span>
|
||||
<span id='random'>random: {random}</span>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export async function getStaticPaths() {
|
||||
return {
|
||||
paths: [
|
||||
'/blog/post-1',
|
||||
{ params: { post: 'post-2' } },
|
||||
'/blog/post-123',
|
||||
],
|
||||
fallback: true,
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export async function getStaticProps({ params }) {
|
||||
if (params.post === 'post-10') {
|
||||
await new Promise(resolve => {
|
||||
setTimeout(() => resolve(), 1000);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
post: params.post,
|
||||
random: Math.random(),
|
||||
time: (await import('perf_hooks')).performance.now(),
|
||||
},
|
||||
unstable_revalidate: 1,
|
||||
};
|
||||
}
|
||||
|
||||
export default ({ post, time, random }) => {
|
||||
if (!post) return <p>loading...</p>;
|
||||
|
||||
return (
|
||||
<>
|
||||
<p id='post'>Post: {post}</p>
|
||||
<span id='time'>time: {time}</span>
|
||||
<span id='random'>random: {random}</span>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export async function getStaticProps() {
|
||||
return {
|
||||
props: {
|
||||
world: 'world',
|
||||
time: new Date().getTime(),
|
||||
},
|
||||
unstable_revalidate: false,
|
||||
};
|
||||
}
|
||||
|
||||
export default ({ world, time }) => {
|
||||
return (
|
||||
<>
|
||||
<p>hello: {world}</p>
|
||||
<span>time: {time}</span>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export default () => 'Hi';
|
||||
@@ -1,5 +0,0 @@
|
||||
const Page = ({ data }) => <p>{data} world</p>;
|
||||
|
||||
Page.getInitialProps = () => ({ data: 'hello' });
|
||||
|
||||
export default Page;
|
||||
@@ -1,31 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export async function getStaticPaths() {
|
||||
return {
|
||||
paths: ['/nofallback/one', { params: { slug: 'two' } }],
|
||||
fallback: false,
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
export async function getStaticProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
slug: params.slug,
|
||||
time: (await import('perf_hooks')).performance.now(),
|
||||
},
|
||||
unstable_revalidate: 10,
|
||||
};
|
||||
}
|
||||
|
||||
export default ({ slug, time }) => {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
Slug ({slug.length}): {slug}
|
||||
</p>
|
||||
<span>time: {time}</span>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"uploadNowJson": true,
|
||||
"builds": [{ "src": "package.json", "use": "@vercel/next" }],
|
||||
"probes": [
|
||||
{
|
||||
@@ -133,6 +134,12 @@
|
||||
{
|
||||
"path": "/_next/data/testing-build-id/nofallback/nope.json",
|
||||
"status": 404
|
||||
},
|
||||
{
|
||||
"logMustNotContain": "WARNING: your application is being opted out of @vercel/next's optimized lambdas mode due to legacy routes"
|
||||
},
|
||||
{
|
||||
"logMustNotContain": "WARNING: Your application is being opted out of \"@vercel/next\" optimized lambdas mode due to `functions` config"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
!public
|
||||
@@ -1,217 +0,0 @@
|
||||
module.exports = {
|
||||
generateBuildId() {
|
||||
return 'testing-build-id';
|
||||
},
|
||||
async rewrites() {
|
||||
return [
|
||||
{
|
||||
source: '/to-another',
|
||||
destination: '/another/one',
|
||||
},
|
||||
{
|
||||
source: '/nav',
|
||||
destination: '/404',
|
||||
},
|
||||
{
|
||||
source: '/hello-world',
|
||||
destination: '/static/hello.txt',
|
||||
},
|
||||
{
|
||||
source: '/',
|
||||
destination: '/another',
|
||||
},
|
||||
{
|
||||
source: '/another',
|
||||
destination: '/multi-rewrites',
|
||||
},
|
||||
{
|
||||
source: '/first',
|
||||
destination: '/hello',
|
||||
},
|
||||
{
|
||||
source: '/second',
|
||||
destination: '/hello-again',
|
||||
},
|
||||
{
|
||||
source: '/to-hello',
|
||||
destination: '/hello',
|
||||
},
|
||||
{
|
||||
source: '/(.*)-:id(\\d+).html',
|
||||
destination: '/blog/:id',
|
||||
},
|
||||
{
|
||||
source: '/blog/post-1',
|
||||
destination: '/blog/post-2',
|
||||
},
|
||||
{
|
||||
source: '/test/:path',
|
||||
destination: '/:path',
|
||||
},
|
||||
{
|
||||
source: '/test-overwrite/:something/:another',
|
||||
destination: '/params/this-should-be-the-value',
|
||||
},
|
||||
{
|
||||
source: '/params/:something',
|
||||
destination: '/with-params',
|
||||
},
|
||||
{
|
||||
source: '/query-rewrite/:section/:name',
|
||||
destination: '/with-params?first=:section&second=:name',
|
||||
},
|
||||
{
|
||||
source: '/hidden/_next/:path*',
|
||||
destination: '/_next/:path*',
|
||||
},
|
||||
{
|
||||
source: '/api-hello',
|
||||
destination: '/api/hello',
|
||||
},
|
||||
{
|
||||
source: '/api-hello-regex/(.*)',
|
||||
destination: '/api/hello?name=:1',
|
||||
},
|
||||
{
|
||||
source: '/api-hello-param/:name',
|
||||
destination: '/api/hello?hello=:name',
|
||||
},
|
||||
{
|
||||
source: '/api-dynamic-param/:name',
|
||||
destination: '/api/dynamic/:name?hello=:name',
|
||||
},
|
||||
{
|
||||
source: '/:path/post-321',
|
||||
destination: '/with-params',
|
||||
},
|
||||
{
|
||||
source: '/a/catch-all/:path*',
|
||||
destination: '/a/catch-all',
|
||||
},
|
||||
];
|
||||
},
|
||||
async redirects() {
|
||||
return [
|
||||
{
|
||||
source: '/redirect/me/to-about/:lang',
|
||||
destination: '/:lang/about',
|
||||
permanent: false,
|
||||
},
|
||||
{
|
||||
source: '/docs/router-status/:code',
|
||||
destination: '/docs/v2/network/status-codes#:code',
|
||||
statusCode: 301,
|
||||
},
|
||||
{
|
||||
source: '/docs/github',
|
||||
destination: '/docs/v2/advanced/now-for-github',
|
||||
statusCode: 301,
|
||||
},
|
||||
{
|
||||
source: '/docs/v2/advanced/:all(.*)',
|
||||
destination: '/docs/v2/more/:all',
|
||||
statusCode: 301,
|
||||
},
|
||||
{
|
||||
source: '/hello/:id/another',
|
||||
destination: '/blog/:id',
|
||||
permanent: false,
|
||||
},
|
||||
{
|
||||
source: '/redirect1',
|
||||
destination: '/',
|
||||
permanent: false,
|
||||
},
|
||||
{
|
||||
source: '/redirect2',
|
||||
destination: '/',
|
||||
statusCode: 301,
|
||||
},
|
||||
{
|
||||
source: '/redirect3',
|
||||
destination: '/another',
|
||||
statusCode: 302,
|
||||
},
|
||||
{
|
||||
source: '/redirect4',
|
||||
destination: '/',
|
||||
permanent: true,
|
||||
},
|
||||
{
|
||||
source: '/redir-chain1',
|
||||
destination: '/redir-chain2',
|
||||
statusCode: 301,
|
||||
},
|
||||
{
|
||||
source: '/redir-chain2',
|
||||
destination: '/redir-chain3',
|
||||
statusCode: 302,
|
||||
},
|
||||
{
|
||||
source: '/redir-chain3',
|
||||
destination: '/',
|
||||
statusCode: 303,
|
||||
},
|
||||
{
|
||||
source: '/to-external',
|
||||
destination: 'https://google.com',
|
||||
permanent: false,
|
||||
},
|
||||
{
|
||||
source: '/query-redirect/:section/:name',
|
||||
destination: '/with-params?first=:section&second=:name',
|
||||
permanent: false,
|
||||
},
|
||||
{
|
||||
source: '/named-like-unnamed/:0',
|
||||
destination: '/:0',
|
||||
permanent: false,
|
||||
},
|
||||
{
|
||||
source: '/redirect-override',
|
||||
destination: '/thank-you-next',
|
||||
permanent: false,
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
async headers() {
|
||||
return [
|
||||
{
|
||||
source: '/add-header',
|
||||
headers: [
|
||||
{
|
||||
key: 'x-custom-header',
|
||||
value: 'hello world',
|
||||
},
|
||||
{
|
||||
key: 'x-another-header',
|
||||
value: 'hello again',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
source: '/my-headers/(.*)',
|
||||
headers: [
|
||||
{
|
||||
key: 'x-first-header',
|
||||
value: 'first',
|
||||
},
|
||||
{
|
||||
key: 'x-second-header',
|
||||
value: 'second',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
source: '/:path*',
|
||||
headers: [
|
||||
{
|
||||
key: 'x-something',
|
||||
value: 'applied-everywhere',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
@@ -1,246 +0,0 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@vercel/next",
|
||||
"config": {
|
||||
"sharedLambdas": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
// should handle one-to-one rewrite successfully
|
||||
{
|
||||
"path": "/first",
|
||||
"mustContain": "hello"
|
||||
},
|
||||
// should handle chained rewrites successfully
|
||||
{
|
||||
"path": "/",
|
||||
"mustContain": "multi-rewrites"
|
||||
},
|
||||
// should not match dynamic route immediately after applying header
|
||||
{
|
||||
"path": "/blog/post-321",
|
||||
"mustContain": "with-params"
|
||||
},
|
||||
{
|
||||
"path": "/blog/post-321",
|
||||
"mustNotContain": "post-321"
|
||||
},
|
||||
// should handle chained redirects successfully
|
||||
{
|
||||
"path": "/redir-chain1",
|
||||
"status": 301,
|
||||
"responseHeaders": {
|
||||
"location": "//redir-chain2/"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/redir-chain2",
|
||||
"status": 302,
|
||||
"responseHeaders": {
|
||||
"location": "//redir-chain3/"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/redir-chain3",
|
||||
"status": 303,
|
||||
"responseHeaders": {
|
||||
"location": "//$/"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
}
|
||||
},
|
||||
// should redirect successfully with permanent: false
|
||||
{
|
||||
"path": "/redirect1",
|
||||
"status": 307,
|
||||
"responseHeaders": {
|
||||
"location": "//$/"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
}
|
||||
},
|
||||
// should redirect with params successfully
|
||||
{
|
||||
"path": "/hello/123/another",
|
||||
"status": 307,
|
||||
"responseHeaders": {
|
||||
"location": "//blog/123/"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
}
|
||||
},
|
||||
// should redirect with hash successfully
|
||||
{
|
||||
"path": "/docs/router-status/500",
|
||||
"status": 301,
|
||||
"responseHeaders": {
|
||||
"location": "/#500$/"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
}
|
||||
},
|
||||
// should redirect successfully with provided statusCode
|
||||
{
|
||||
"path": "/redirect2",
|
||||
"status": 301,
|
||||
"responseHeaders": {
|
||||
"location": "//$/"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
}
|
||||
},
|
||||
// should server static files through a rewrite
|
||||
{
|
||||
"path": "/hello-world",
|
||||
"mustContain": "hello world!"
|
||||
},
|
||||
// should rewrite with params successfully
|
||||
{
|
||||
"path": "/test/hello",
|
||||
"mustContain": "Hello"
|
||||
},
|
||||
// should double redirect successfully
|
||||
{
|
||||
"path": "/docs/github",
|
||||
"mustContain": "hi there"
|
||||
},
|
||||
// should allow params in query for rewrite
|
||||
{
|
||||
"path": "/query-rewrite/hello/world?a=b",
|
||||
"mustContain": "\"a\":\"b\""
|
||||
},
|
||||
{
|
||||
"path": "/query-rewrite/hello/world?a=b",
|
||||
"mustContain": "\"section\":\"hello\""
|
||||
},
|
||||
{
|
||||
"path": "/query-rewrite/hello/world?a=b",
|
||||
"mustContain": "\"name\":\"world\""
|
||||
},
|
||||
{
|
||||
"path": "/query-rewrite/hello/world?a=b",
|
||||
"mustContain": "\"first\":\"hello\""
|
||||
},
|
||||
{
|
||||
"path": "/query-rewrite/hello/world?a=b",
|
||||
"mustContain": "\"second\":\"world\""
|
||||
},
|
||||
// should not allow rewrite to override page file
|
||||
{
|
||||
"path": "/nav",
|
||||
"mustContain": "to-hello"
|
||||
},
|
||||
// show allow redirect to override the page
|
||||
{
|
||||
"path": "/redirect-override",
|
||||
"status": 307,
|
||||
"responseHeaders": {
|
||||
"location": "//thank-you-next$/"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
}
|
||||
},
|
||||
// should match a page after a rewrite
|
||||
{
|
||||
"path": "/to-hello",
|
||||
"mustContain": "Hello"
|
||||
},
|
||||
// should match dynamic route after rewrite
|
||||
{
|
||||
"path": "/blog/post-1",
|
||||
"mustContain": "post-2"
|
||||
},
|
||||
// should match public file after rewrite
|
||||
{
|
||||
"path": "/blog/data.json",
|
||||
"mustContain": "\"hello\": \"world\""
|
||||
},
|
||||
// should match /_next file after rewrite
|
||||
{
|
||||
"path": "/hidden/_next/__NEXT_SCRIPT__(/hello)",
|
||||
"mustContain": "createElement"
|
||||
},
|
||||
// should allow redirecting to external resource
|
||||
{
|
||||
"path": "/to-external",
|
||||
"status": 307,
|
||||
"responseHeaders": {
|
||||
"location": "/google.com/"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
}
|
||||
},
|
||||
// should apply headers for exact match
|
||||
{
|
||||
"path": "/add-header",
|
||||
"responseHeaders": {
|
||||
"x-custom-header": "hello world",
|
||||
"x-another-header": "hello again"
|
||||
}
|
||||
},
|
||||
// should apply headers for multi match
|
||||
{
|
||||
"path": "/my-headers/first",
|
||||
"responseHeaders": {
|
||||
"x-first-header": "first",
|
||||
"x-second-header": "second"
|
||||
}
|
||||
},
|
||||
// should handle basic api rewrite successfully
|
||||
{
|
||||
"path": "/api-hello",
|
||||
"mustContain": "{\"query\":{}}"
|
||||
},
|
||||
// should handle api rewrite with param successfully
|
||||
{
|
||||
"path": "/api-hello-param/hello",
|
||||
"mustContain": "{\"query\":{\"hello\":\"hello\",\"name\":\"hello\"}}"
|
||||
},
|
||||
// should handle encoded value in the pathname correctly
|
||||
{
|
||||
"path": "/redirect/me/to-about/%5Cgoogle.com",
|
||||
"status": 307,
|
||||
"responseHeaders": {
|
||||
"location": "/%5Cgoogle.com/about/"
|
||||
},
|
||||
"fetchOptions": {
|
||||
"redirect": "manual"
|
||||
}
|
||||
},
|
||||
// should apply un-named multi-match correctly
|
||||
{
|
||||
"path": "/hello/post-123.html",
|
||||
"status": 200,
|
||||
"mustContain": "123"
|
||||
},
|
||||
// should rewrite to catch-all with dash in segment name
|
||||
{
|
||||
"path": "/catchall-dash/hello/world",
|
||||
"status": 200,
|
||||
"mustContain": "hello/world"
|
||||
},
|
||||
// should rewrite and normalize catch-all rewrite param
|
||||
{
|
||||
"path": "/a/catch-all/hello/world",
|
||||
"status": 200,
|
||||
"mustContain": "hello/world"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"next": "canary",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
export default () => <p>{useRouter().query.path?.join('/')}</p>;
|
||||
|
||||
export const getServerSideProps = () => {
|
||||
return {
|
||||
props: {},
|
||||
};
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export default () => 'hi'
|
||||
@@ -1 +0,0 @@
|
||||
export default async (req, res) => res.json({ query: req.query })
|
||||
@@ -1 +0,0 @@
|
||||
export default async (req, res) => res.json({ query: req.query });
|
||||
@@ -1,11 +0,0 @@
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
const Page = () => (
|
||||
<>
|
||||
<p>post: {useRouter().query.post}</p>
|
||||
</>
|
||||
)
|
||||
|
||||
Page.getInitialProps = () => ({ hello: 'world' })
|
||||
|
||||
export default Page
|
||||
@@ -1,17 +0,0 @@
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
const Page = () => {
|
||||
return (
|
||||
<p>path: {useRouter().query['hello-world']?.join('/')}</p>
|
||||
)
|
||||
}
|
||||
|
||||
export default Page
|
||||
|
||||
export const getServerSideProps = () => {
|
||||
return {
|
||||
props: {
|
||||
hello: 'world'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export default () => 'hi'
|
||||
@@ -1 +0,0 @@
|
||||
export default () => 'hi there';
|
||||
@@ -1,10 +0,0 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
export default () => (
|
||||
<>
|
||||
<h3 id="hello-again">Hello again</h3>
|
||||
<Link href="/nav">
|
||||
<a id="to-nav">to nav</a>
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
@@ -1,14 +0,0 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
const Page = () => (
|
||||
<>
|
||||
<h3 id="hello">Hello</h3>
|
||||
<Link href="/nav">
|
||||
<a id="to-nav">to nav</a>
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
|
||||
Page.getInitialProps = () => ({ hello: 'world' });
|
||||
|
||||
export default Page;
|
||||
@@ -1 +0,0 @@
|
||||
export default () => 'multi-rewrites';
|
||||
@@ -1,13 +0,0 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
export default () => (
|
||||
<>
|
||||
<h3 id="nav">Nav</h3>
|
||||
<Link href="/hello" as="/first">
|
||||
<a id="to-hello">to hello</a>
|
||||
</Link>
|
||||
<Link href="/hello-again" as="/second">
|
||||
<a id="to-hello-again">to hello-again</a>
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
@@ -1,10 +0,0 @@
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
const Page = () => {
|
||||
const { query } = useRouter();
|
||||
return <p>{JSON.stringify(query)}</p>;
|
||||
};
|
||||
|
||||
Page.getInitialProps = () => ({ a: 'b' });
|
||||
|
||||
export default Page;
|
||||
@@ -1 +0,0 @@
|
||||
export default () => 'got to the page';
|
||||
@@ -1,10 +0,0 @@
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
const Page = () => {
|
||||
const { query } = useRouter();
|
||||
return <p>{JSON.stringify(query)}</p>;
|
||||
};
|
||||
|
||||
Page.getInitialProps = () => ({ hello: 'GIPGIP' });
|
||||
|
||||
export default Page;
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"hello": "world"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
hello world!
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"uploadNowJson": true,
|
||||
"routes": [
|
||||
{ "src": "/(.*)", "dest": "/packages/webapp/$1", "continue": true }
|
||||
],
|
||||
@@ -31,6 +32,9 @@
|
||||
{
|
||||
"path": "/non-existent",
|
||||
"status": 404
|
||||
},
|
||||
{
|
||||
"logMustContain": "WARNING: your application is being opted out of @vercel/next's optimized lambdas mode due to legacy routes"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"uploadNowJson": true,
|
||||
"routes": [
|
||||
{ "src": "/(.*)", "dest": "/packages/webapp/$1", "continue": true }
|
||||
],
|
||||
@@ -25,6 +26,9 @@
|
||||
{
|
||||
"path": "/non-existent",
|
||||
"status": 404
|
||||
},
|
||||
{
|
||||
"logMustContain": "WARNING: your application is being opted out of @vercel/next's optimized lambdas mode due to legacy routes"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ it(
|
||||
buildResult: { output },
|
||||
} = await runBuildLambda(path.join(__dirname, 'standard'));
|
||||
expect(output['index']).toBeDefined();
|
||||
expect(output.goodbye).toBeDefined();
|
||||
expect(output.__NEXT_PAGE_LAMBDA_0).not.toBeDefined();
|
||||
expect(output.goodbye).not.toBeDefined();
|
||||
expect(output.__NEXT_PAGE_LAMBDA_0).toBeDefined();
|
||||
const filePaths = Object.keys(output);
|
||||
const serverlessError = filePaths.some(filePath =>
|
||||
filePath.match(/_error/)
|
||||
@@ -34,27 +34,29 @@ it(
|
||||
FOUR_MINUTES
|
||||
);
|
||||
|
||||
// it(
|
||||
// 'Should opt-out of shared lambdas when routes are detected',
|
||||
// async () => {
|
||||
// const {
|
||||
// buildResult: { output },
|
||||
// } = await runBuildLambda(path.join(__dirname, '../fixtures/26-mono-repo-404-lambda'));
|
||||
// expect(output['packages/webapp/404']).toBeDefined();
|
||||
// expect(output['packages/webapp/index']).toBeDefined();
|
||||
// expect(output['packages/webapp/__NEXT_PAGE_LAMBDA_0']).not.toBeDefined();
|
||||
// const filePaths = Object.keys(output);
|
||||
// const hasUnderScoreAppStaticFile = filePaths.some(filePath =>
|
||||
// filePath.match(/static.*\/pages\/_app\.js$/)
|
||||
// );
|
||||
// const hasUnderScoreErrorStaticFile = filePaths.some(filePath =>
|
||||
// filePath.match(/static.*\/pages\/_error\.js$/)
|
||||
// );
|
||||
// expect(hasUnderScoreAppStaticFile).toBeTruthy();
|
||||
// expect(hasUnderScoreErrorStaticFile).toBeTruthy();
|
||||
// },
|
||||
// FOUR_MINUTES
|
||||
// );
|
||||
it(
|
||||
'Should opt-out of shared lambdas when routes are detected',
|
||||
async () => {
|
||||
const {
|
||||
buildResult: { output },
|
||||
} = await runBuildLambda(
|
||||
path.join(__dirname, '../fixtures/26-mono-repo-404-lambda')
|
||||
);
|
||||
expect(output['packages/webapp/404']).toBeDefined();
|
||||
expect(output['packages/webapp/index']).toBeDefined();
|
||||
expect(output['packages/webapp/__NEXT_PAGE_LAMBDA_0']).not.toBeDefined();
|
||||
const filePaths = Object.keys(output);
|
||||
const hasUnderScoreAppStaticFile = filePaths.some(filePath =>
|
||||
filePath.match(/static.*\/pages\/_app\.js$/)
|
||||
);
|
||||
const hasUnderScoreErrorStaticFile = filePaths.some(filePath =>
|
||||
filePath.match(/static.*\/pages\/_error\.js$/)
|
||||
);
|
||||
expect(hasUnderScoreAppStaticFile).toBeTruthy();
|
||||
expect(hasUnderScoreErrorStaticFile).toBeTruthy();
|
||||
},
|
||||
FOUR_MINUTES
|
||||
);
|
||||
|
||||
it(
|
||||
'Should build the monorepo example',
|
||||
@@ -63,8 +65,8 @@ it(
|
||||
buildResult: { output },
|
||||
} = await runBuildLambda(path.join(__dirname, 'monorepo'));
|
||||
|
||||
expect(output['www/index']).toBeDefined();
|
||||
expect(output['www/__NEXT_PAGE_LAMBDA_0']).not.toBeDefined();
|
||||
expect(output['www/index']).not.toBeDefined();
|
||||
expect(output['www/__NEXT_PAGE_LAMBDA_0']).toBeDefined();
|
||||
expect(output['www/static/test.txt']).toBeDefined();
|
||||
expect(output['www/data.txt']).toBeDefined();
|
||||
const filePaths = Object.keys(output);
|
||||
@@ -164,9 +166,9 @@ it(
|
||||
buildResult: { output },
|
||||
} = await runBuildLambda(path.join(__dirname, 'serverless-config'));
|
||||
|
||||
expect(output.index).toBeDefined();
|
||||
expect(output.goodbye).toBeDefined();
|
||||
expect(output.__NEXT_PAGE_LAMBDA_0).not.toBeDefined();
|
||||
expect(output.index).not.toBeDefined();
|
||||
expect(output.goodbye).not.toBeDefined();
|
||||
expect(output.__NEXT_PAGE_LAMBDA_0).toBeDefined();
|
||||
const filePaths = Object.keys(output);
|
||||
const serverlessError = filePaths.some(filePath =>
|
||||
filePath.match(/_error/)
|
||||
@@ -201,9 +203,9 @@ it(
|
||||
path.join(__dirname, 'serverless-config-monorepo-missing')
|
||||
);
|
||||
|
||||
expect(output['nested/index']).toBeDefined();
|
||||
expect(output['nested/goodbye']).toBeDefined();
|
||||
expect(output['nested/__NEXT_PAGE_LAMBDA_0']).not.toBeDefined();
|
||||
expect(output['nested/index']).not.toBeDefined();
|
||||
expect(output['nested/goodbye']).not.toBeDefined();
|
||||
expect(output['nested/__NEXT_PAGE_LAMBDA_0']).toBeDefined();
|
||||
const filePaths = Object.keys(output);
|
||||
const serverlessError = filePaths.some(filePath =>
|
||||
filePath.match(/_error/)
|
||||
@@ -235,9 +237,9 @@ it(
|
||||
path.join(__dirname, 'serverless-config-monorepo-present')
|
||||
);
|
||||
|
||||
expect(output['nested/index']).toBeDefined();
|
||||
expect(output['nested/goodbye']).toBeDefined();
|
||||
expect(output['nested/__NEXT_PAGE_LAMBDA_0']).not.toBeDefined();
|
||||
expect(output['nested/index']).not.toBeDefined();
|
||||
expect(output['nested/goodbye']).not.toBeDefined();
|
||||
expect(output['nested/__NEXT_PAGE_LAMBDA_0']).toBeDefined();
|
||||
const filePaths = Object.keys(output);
|
||||
const serverlessError = filePaths.some(filePath =>
|
||||
filePath.match(/_error/)
|
||||
@@ -303,8 +305,8 @@ it(
|
||||
} = await runBuildLambda(path.join(__dirname, 'serverless-config-object'));
|
||||
|
||||
expect(output['index']).toBeDefined();
|
||||
expect(output.goodbye).toBeDefined();
|
||||
expect(output.__NEXT_PAGE_LAMBDA_0).not.toBeDefined();
|
||||
expect(output.goodbye).not.toBeDefined();
|
||||
expect(output.__NEXT_PAGE_LAMBDA_0).toBeDefined();
|
||||
const filePaths = Object.keys(output);
|
||||
const serverlessError = filePaths.some(filePath =>
|
||||
filePath.match(/_error/)
|
||||
@@ -338,8 +340,8 @@ it(
|
||||
} = await runBuildLambda(path.join(__dirname, 'serverless-no-config'));
|
||||
|
||||
expect(output['index']).toBeDefined();
|
||||
expect(output.goodbye).toBeDefined();
|
||||
expect(output.__NEXT_PAGE_LAMBDA_0).not.toBeDefined();
|
||||
expect(output.goodbye).not.toBeDefined();
|
||||
expect(output.__NEXT_PAGE_LAMBDA_0).toBeDefined();
|
||||
const filePaths = Object.keys(output);
|
||||
const serverlessError = filePaths.some(filePath =>
|
||||
filePath.match(/_error/)
|
||||
|
||||
9
packages/now-next/test/test.js
vendored
9
packages/now-next/test/test.js
vendored
@@ -24,9 +24,12 @@ beforeAll(async () => {
|
||||
}
|
||||
|
||||
process.env.NEXT_TELEMETRY_DISABLED = '1';
|
||||
const builderPath = path.resolve(__dirname, '..');
|
||||
builderUrl = await packAndDeploy(builderPath);
|
||||
console.log('builderUrl', builderUrl);
|
||||
|
||||
if (!builderUrl) {
|
||||
const builderPath = path.resolve(__dirname, '..');
|
||||
builderUrl = await packAndDeploy(builderPath);
|
||||
console.log('builderUrl', builderUrl);
|
||||
}
|
||||
});
|
||||
|
||||
const fixturesPath = path.resolve(__dirname, 'fixtures');
|
||||
|
||||
@@ -5,9 +5,11 @@ const _fetch = require('node-fetch');
|
||||
const fetch = require('./fetch-retry.js');
|
||||
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
async function nowDeploy(bodies, randomness) {
|
||||
async function nowDeploy(bodies, randomness, uploadNowJson) {
|
||||
const files = Object.keys(bodies)
|
||||
.filter(n => n !== 'vercel.json' && n !== 'now.json')
|
||||
.filter(n =>
|
||||
uploadNowJson ? true : n !== 'vercel.json' && n !== 'now.json'
|
||||
)
|
||||
.map(n => ({
|
||||
sha: digestOfFile(bodies[n]),
|
||||
size: bodies[n].length,
|
||||
|
||||
@@ -57,6 +57,8 @@ async function testDeployment(
|
||||
|
||||
// we use json5 to allow comments for probes
|
||||
const nowJson = json5.parse(bodies[configName]);
|
||||
const uploadNowJson = nowJson.uploadNowJson;
|
||||
delete nowJson.uploadNowJson;
|
||||
|
||||
if (process.env.VERCEL_BUILDER_DEBUG) {
|
||||
if (!nowJson.build) {
|
||||
@@ -94,8 +96,14 @@ async function testDeployment(
|
||||
|
||||
bodies[configName] = Buffer.from(JSON.stringify(nowJson));
|
||||
delete bodies['probe.js'];
|
||||
const { deploymentId, deploymentUrl } = await nowDeploy(bodies, randomness);
|
||||
|
||||
const { deploymentId, deploymentUrl } = await nowDeploy(
|
||||
bodies,
|
||||
randomness,
|
||||
uploadNowJson
|
||||
);
|
||||
let nextBuildManifest;
|
||||
let deploymentLogs;
|
||||
|
||||
for (const probe of nowJson.probes || []) {
|
||||
console.log('testing', JSON.stringify(probe));
|
||||
@@ -104,6 +112,60 @@ async function testDeployment(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (probe.logMustContain || probe.logMustNotContain) {
|
||||
const shouldContain = !!probe.logMustContain;
|
||||
const toCheck = probe.logMustContain || probe.logMustNotContain;
|
||||
|
||||
if (probe.logMustContain && probe.logMustNotContain) {
|
||||
throw new Error(
|
||||
`probe can not check logMustContain and logMustNotContain in the same check`
|
||||
);
|
||||
}
|
||||
|
||||
if (!deploymentLogs) {
|
||||
try {
|
||||
const logsRes = await fetch(
|
||||
`https://vercel.com/api/v1/now/deployments/${deploymentId}/events?limit=-1`
|
||||
);
|
||||
|
||||
if (!logsRes.ok) {
|
||||
throw new Error(
|
||||
`fetching logs failed with status ${logsRes.status}`
|
||||
);
|
||||
}
|
||||
deploymentLogs = await logsRes.json();
|
||||
} catch (err) {
|
||||
throw new Error(
|
||||
`Failed to get deployment logs for probe: ${err.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let found = false;
|
||||
|
||||
for (const log of deploymentLogs) {
|
||||
if (log.text && log.text.includes(toCheck)) {
|
||||
if (shouldContain) {
|
||||
found = true;
|
||||
break;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Expected deployment logs not to contain ${toCheck}, but found ${log.text}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && shouldContain) {
|
||||
throw new Error(
|
||||
`Expected deployment logs to contain ${toCheck}, it was not found`
|
||||
);
|
||||
} else {
|
||||
console.log('finished testing', JSON.stringify(probe));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const nextScriptIndex = probe.path.indexOf('__NEXT_SCRIPT__(');
|
||||
|
||||
if (nextScriptIndex > -1) {
|
||||
|
||||
@@ -2190,6 +2190,11 @@
|
||||
semver "^7.3.2"
|
||||
tsutils "^3.17.1"
|
||||
|
||||
"@vercel/static-build@0.17.4-canary.1":
|
||||
version "0.17.4-canary.1"
|
||||
resolved "https://registry.yarnpkg.com/@vercel/static-build/-/static-build-0.17.4-canary.1.tgz#42ba89d5dee7ced3a20ec0a3a2986d293405530a"
|
||||
integrity sha512-SWvu9zm6sQGuQeouHDnxOYxDlgvKSk7pb4m2QuVufFXrhOkx7OL6e91riHXCpmscv8Pb9mD7DFVl2o78FK7viA==
|
||||
|
||||
"@zeit/dns-cached-resolve@2.1.0":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@zeit/dns-cached-resolve/-/dns-cached-resolve-2.1.0.tgz#78583010df1683fdb7b05949b75593c9a8641bc1"
|
||||
|
||||
Reference in New Issue
Block a user