mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-06 12:57:46 +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,
|
syncEnvVars,
|
||||||
validateEntrypoint,
|
validateEntrypoint,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
// import findUp from 'find-up';
|
import findUp from 'find-up';
|
||||||
import { Sema } from 'async-sema';
|
import { Sema } from 'async-sema';
|
||||||
|
|
||||||
interface BuildParamsMeta {
|
interface BuildParamsMeta {
|
||||||
@@ -231,47 +231,39 @@ export const build = async ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// let nowJsonPath = Object.keys(files).find(file => {
|
const nowJsonPath = await findUp(['now.json', 'vercel.json'], {
|
||||||
// return file.endsWith('now.json') || file.endsWith('vercel.json')
|
cwd: path.join(workPath, path.dirname(entrypoint)),
|
||||||
// })
|
});
|
||||||
|
|
||||||
// if (nowJsonPath) nowJsonPath = files[nowJsonPath].fsPath
|
let hasLegacyRoutes = false;
|
||||||
|
const hasFunctionsConfig = !!config.functions;
|
||||||
|
|
||||||
// if (!nowJsonPath) {
|
if (nowJsonPath) {
|
||||||
// nowJsonPath = await findUp(['now.json', 'vercel.json'], {
|
const nowJsonData = JSON.parse(await readFile(nowJsonPath, 'utf8'));
|
||||||
// cwd: path.join(workPath, path.dirname(entrypoint))
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let hasLegacyRoutes = false;
|
if (Array.isArray(nowJsonData.routes) && nowJsonData.routes.length > 0) {
|
||||||
// const hasFunctionsConfig = !!config.functions;
|
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) {
|
if (hasFunctionsConfig) {
|
||||||
// const nowJsonData = JSON.parse(await readFile(nowJsonPath, 'utf8'));
|
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 (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`
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// default to true but still allow opting out with the config
|
// default to true but still allow opting out with the config
|
||||||
const isSharedLambdas = !!config.sharedLambdas;
|
const isSharedLambdas =
|
||||||
// !hasLegacyRoutes &&
|
!hasLegacyRoutes &&
|
||||||
// !hasFunctionsConfig &&
|
!hasFunctionsConfig &&
|
||||||
// typeof config.sharedLambdas === 'undefined'
|
typeof config.sharedLambdas === 'undefined'
|
||||||
// ? true
|
? true
|
||||||
// : !!config.sharedLambdas;
|
: !!config.sharedLambdas;
|
||||||
|
|
||||||
if (meta.isDev) {
|
if (meta.isDev) {
|
||||||
let childProcess: ChildProcess | undefined;
|
let childProcess: ChildProcess | undefined;
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
{
|
{
|
||||||
"version": 2,
|
"version": 2,
|
||||||
|
"uploadNowJson": true,
|
||||||
"builds": [
|
"builds": [
|
||||||
{
|
{
|
||||||
"src": "package.json",
|
"src": "package.json",
|
||||||
"use": "@vercel/next",
|
"use": "@vercel/next"
|
||||||
"config": {
|
|
||||||
"sharedLambdas": true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"probes": [
|
"probes": [
|
||||||
@@ -29,6 +27,12 @@
|
|||||||
{
|
{
|
||||||
"path": "/another/invite/hello",
|
"path": "/another/invite/hello",
|
||||||
"mustContain": "hello from /[teamSlug]/[project]/[id]"
|
"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",
|
"path": "/api/memory",
|
||||||
"status": 200,
|
"status": 200,
|
||||||
"mustContain": "128"
|
"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,
|
"version": 2,
|
||||||
|
"uploadNowJson": true,
|
||||||
"builds": [{ "src": "package.json", "use": "@vercel/next" }],
|
"builds": [{ "src": "package.json", "use": "@vercel/next" }],
|
||||||
"probes": [
|
"probes": [
|
||||||
{
|
{
|
||||||
@@ -61,6 +62,12 @@
|
|||||||
"x-hello": "world",
|
"x-hello": "world",
|
||||||
"x-another": "value"
|
"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,
|
"version": 2,
|
||||||
|
"uploadNowJson": true,
|
||||||
"builds": [{ "src": "packages/web/next.config.js", "use": "@vercel/next" }],
|
"builds": [{ "src": "packages/web/next.config.js", "use": "@vercel/next" }],
|
||||||
"routes": [{ "src": "/(.*)", "dest": "/packages/web/$1", "continue": true }],
|
"routes": [{ "src": "/(.*)", "dest": "/packages/web/$1", "continue": true }],
|
||||||
"probes": [
|
"probes": [
|
||||||
{
|
{
|
||||||
"path": "/",
|
"path": "/",
|
||||||
"mustContain": "hello world <!-- -->6"
|
"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,
|
"version": 2,
|
||||||
|
"uploadNowJson": true,
|
||||||
"builds": [{ "src": "package.json", "use": "@vercel/next" }],
|
"builds": [{ "src": "package.json", "use": "@vercel/next" }],
|
||||||
"probes": [
|
"probes": [
|
||||||
{
|
{
|
||||||
@@ -133,6 +134,12 @@
|
|||||||
{
|
{
|
||||||
"path": "/_next/data/testing-build-id/nofallback/nope.json",
|
"path": "/_next/data/testing-build-id/nofallback/nope.json",
|
||||||
"status": 404
|
"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,
|
"version": 2,
|
||||||
|
"uploadNowJson": true,
|
||||||
"routes": [
|
"routes": [
|
||||||
{ "src": "/(.*)", "dest": "/packages/webapp/$1", "continue": true }
|
{ "src": "/(.*)", "dest": "/packages/webapp/$1", "continue": true }
|
||||||
],
|
],
|
||||||
@@ -31,6 +32,9 @@
|
|||||||
{
|
{
|
||||||
"path": "/non-existent",
|
"path": "/non-existent",
|
||||||
"status": 404
|
"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,
|
"version": 2,
|
||||||
|
"uploadNowJson": true,
|
||||||
"routes": [
|
"routes": [
|
||||||
{ "src": "/(.*)", "dest": "/packages/webapp/$1", "continue": true }
|
{ "src": "/(.*)", "dest": "/packages/webapp/$1", "continue": true }
|
||||||
],
|
],
|
||||||
@@ -25,6 +26,9 @@
|
|||||||
{
|
{
|
||||||
"path": "/non-existent",
|
"path": "/non-existent",
|
||||||
"status": 404
|
"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 },
|
buildResult: { output },
|
||||||
} = await runBuildLambda(path.join(__dirname, 'standard'));
|
} = await runBuildLambda(path.join(__dirname, 'standard'));
|
||||||
expect(output['index']).toBeDefined();
|
expect(output['index']).toBeDefined();
|
||||||
expect(output.goodbye).toBeDefined();
|
expect(output.goodbye).not.toBeDefined();
|
||||||
expect(output.__NEXT_PAGE_LAMBDA_0).not.toBeDefined();
|
expect(output.__NEXT_PAGE_LAMBDA_0).toBeDefined();
|
||||||
const filePaths = Object.keys(output);
|
const filePaths = Object.keys(output);
|
||||||
const serverlessError = filePaths.some(filePath =>
|
const serverlessError = filePaths.some(filePath =>
|
||||||
filePath.match(/_error/)
|
filePath.match(/_error/)
|
||||||
@@ -34,27 +34,29 @@ it(
|
|||||||
FOUR_MINUTES
|
FOUR_MINUTES
|
||||||
);
|
);
|
||||||
|
|
||||||
// it(
|
it(
|
||||||
// 'Should opt-out of shared lambdas when routes are detected',
|
'Should opt-out of shared lambdas when routes are detected',
|
||||||
// async () => {
|
async () => {
|
||||||
// const {
|
const {
|
||||||
// buildResult: { output },
|
buildResult: { output },
|
||||||
// } = await runBuildLambda(path.join(__dirname, '../fixtures/26-mono-repo-404-lambda'));
|
} = await runBuildLambda(
|
||||||
// expect(output['packages/webapp/404']).toBeDefined();
|
path.join(__dirname, '../fixtures/26-mono-repo-404-lambda')
|
||||||
// expect(output['packages/webapp/index']).toBeDefined();
|
);
|
||||||
// expect(output['packages/webapp/__NEXT_PAGE_LAMBDA_0']).not.toBeDefined();
|
expect(output['packages/webapp/404']).toBeDefined();
|
||||||
// const filePaths = Object.keys(output);
|
expect(output['packages/webapp/index']).toBeDefined();
|
||||||
// const hasUnderScoreAppStaticFile = filePaths.some(filePath =>
|
expect(output['packages/webapp/__NEXT_PAGE_LAMBDA_0']).not.toBeDefined();
|
||||||
// filePath.match(/static.*\/pages\/_app\.js$/)
|
const filePaths = Object.keys(output);
|
||||||
// );
|
const hasUnderScoreAppStaticFile = filePaths.some(filePath =>
|
||||||
// const hasUnderScoreErrorStaticFile = filePaths.some(filePath =>
|
filePath.match(/static.*\/pages\/_app\.js$/)
|
||||||
// filePath.match(/static.*\/pages\/_error\.js$/)
|
);
|
||||||
// );
|
const hasUnderScoreErrorStaticFile = filePaths.some(filePath =>
|
||||||
// expect(hasUnderScoreAppStaticFile).toBeTruthy();
|
filePath.match(/static.*\/pages\/_error\.js$/)
|
||||||
// expect(hasUnderScoreErrorStaticFile).toBeTruthy();
|
);
|
||||||
// },
|
expect(hasUnderScoreAppStaticFile).toBeTruthy();
|
||||||
// FOUR_MINUTES
|
expect(hasUnderScoreErrorStaticFile).toBeTruthy();
|
||||||
// );
|
},
|
||||||
|
FOUR_MINUTES
|
||||||
|
);
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'Should build the monorepo example',
|
'Should build the monorepo example',
|
||||||
@@ -63,8 +65,8 @@ it(
|
|||||||
buildResult: { output },
|
buildResult: { output },
|
||||||
} = await runBuildLambda(path.join(__dirname, 'monorepo'));
|
} = await runBuildLambda(path.join(__dirname, 'monorepo'));
|
||||||
|
|
||||||
expect(output['www/index']).toBeDefined();
|
expect(output['www/index']).not.toBeDefined();
|
||||||
expect(output['www/__NEXT_PAGE_LAMBDA_0']).not.toBeDefined();
|
expect(output['www/__NEXT_PAGE_LAMBDA_0']).toBeDefined();
|
||||||
expect(output['www/static/test.txt']).toBeDefined();
|
expect(output['www/static/test.txt']).toBeDefined();
|
||||||
expect(output['www/data.txt']).toBeDefined();
|
expect(output['www/data.txt']).toBeDefined();
|
||||||
const filePaths = Object.keys(output);
|
const filePaths = Object.keys(output);
|
||||||
@@ -164,9 +166,9 @@ it(
|
|||||||
buildResult: { output },
|
buildResult: { output },
|
||||||
} = await runBuildLambda(path.join(__dirname, 'serverless-config'));
|
} = await runBuildLambda(path.join(__dirname, 'serverless-config'));
|
||||||
|
|
||||||
expect(output.index).toBeDefined();
|
expect(output.index).not.toBeDefined();
|
||||||
expect(output.goodbye).toBeDefined();
|
expect(output.goodbye).not.toBeDefined();
|
||||||
expect(output.__NEXT_PAGE_LAMBDA_0).not.toBeDefined();
|
expect(output.__NEXT_PAGE_LAMBDA_0).toBeDefined();
|
||||||
const filePaths = Object.keys(output);
|
const filePaths = Object.keys(output);
|
||||||
const serverlessError = filePaths.some(filePath =>
|
const serverlessError = filePaths.some(filePath =>
|
||||||
filePath.match(/_error/)
|
filePath.match(/_error/)
|
||||||
@@ -201,9 +203,9 @@ it(
|
|||||||
path.join(__dirname, 'serverless-config-monorepo-missing')
|
path.join(__dirname, 'serverless-config-monorepo-missing')
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(output['nested/index']).toBeDefined();
|
expect(output['nested/index']).not.toBeDefined();
|
||||||
expect(output['nested/goodbye']).toBeDefined();
|
expect(output['nested/goodbye']).not.toBeDefined();
|
||||||
expect(output['nested/__NEXT_PAGE_LAMBDA_0']).not.toBeDefined();
|
expect(output['nested/__NEXT_PAGE_LAMBDA_0']).toBeDefined();
|
||||||
const filePaths = Object.keys(output);
|
const filePaths = Object.keys(output);
|
||||||
const serverlessError = filePaths.some(filePath =>
|
const serverlessError = filePaths.some(filePath =>
|
||||||
filePath.match(/_error/)
|
filePath.match(/_error/)
|
||||||
@@ -235,9 +237,9 @@ it(
|
|||||||
path.join(__dirname, 'serverless-config-monorepo-present')
|
path.join(__dirname, 'serverless-config-monorepo-present')
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(output['nested/index']).toBeDefined();
|
expect(output['nested/index']).not.toBeDefined();
|
||||||
expect(output['nested/goodbye']).toBeDefined();
|
expect(output['nested/goodbye']).not.toBeDefined();
|
||||||
expect(output['nested/__NEXT_PAGE_LAMBDA_0']).not.toBeDefined();
|
expect(output['nested/__NEXT_PAGE_LAMBDA_0']).toBeDefined();
|
||||||
const filePaths = Object.keys(output);
|
const filePaths = Object.keys(output);
|
||||||
const serverlessError = filePaths.some(filePath =>
|
const serverlessError = filePaths.some(filePath =>
|
||||||
filePath.match(/_error/)
|
filePath.match(/_error/)
|
||||||
@@ -303,8 +305,8 @@ it(
|
|||||||
} = await runBuildLambda(path.join(__dirname, 'serverless-config-object'));
|
} = await runBuildLambda(path.join(__dirname, 'serverless-config-object'));
|
||||||
|
|
||||||
expect(output['index']).toBeDefined();
|
expect(output['index']).toBeDefined();
|
||||||
expect(output.goodbye).toBeDefined();
|
expect(output.goodbye).not.toBeDefined();
|
||||||
expect(output.__NEXT_PAGE_LAMBDA_0).not.toBeDefined();
|
expect(output.__NEXT_PAGE_LAMBDA_0).toBeDefined();
|
||||||
const filePaths = Object.keys(output);
|
const filePaths = Object.keys(output);
|
||||||
const serverlessError = filePaths.some(filePath =>
|
const serverlessError = filePaths.some(filePath =>
|
||||||
filePath.match(/_error/)
|
filePath.match(/_error/)
|
||||||
@@ -338,8 +340,8 @@ it(
|
|||||||
} = await runBuildLambda(path.join(__dirname, 'serverless-no-config'));
|
} = await runBuildLambda(path.join(__dirname, 'serverless-no-config'));
|
||||||
|
|
||||||
expect(output['index']).toBeDefined();
|
expect(output['index']).toBeDefined();
|
||||||
expect(output.goodbye).toBeDefined();
|
expect(output.goodbye).not.toBeDefined();
|
||||||
expect(output.__NEXT_PAGE_LAMBDA_0).not.toBeDefined();
|
expect(output.__NEXT_PAGE_LAMBDA_0).toBeDefined();
|
||||||
const filePaths = Object.keys(output);
|
const filePaths = Object.keys(output);
|
||||||
const serverlessError = filePaths.some(filePath =>
|
const serverlessError = filePaths.some(filePath =>
|
||||||
filePath.match(/_error/)
|
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';
|
process.env.NEXT_TELEMETRY_DISABLED = '1';
|
||||||
const builderPath = path.resolve(__dirname, '..');
|
|
||||||
builderUrl = await packAndDeploy(builderPath);
|
if (!builderUrl) {
|
||||||
console.log('builderUrl', builderUrl);
|
const builderPath = path.resolve(__dirname, '..');
|
||||||
|
builderUrl = await packAndDeploy(builderPath);
|
||||||
|
console.log('builderUrl', builderUrl);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const fixturesPath = path.resolve(__dirname, 'fixtures');
|
const fixturesPath = path.resolve(__dirname, 'fixtures');
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ const _fetch = require('node-fetch');
|
|||||||
const fetch = require('./fetch-retry.js');
|
const fetch = require('./fetch-retry.js');
|
||||||
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
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)
|
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 => ({
|
.map(n => ({
|
||||||
sha: digestOfFile(bodies[n]),
|
sha: digestOfFile(bodies[n]),
|
||||||
size: bodies[n].length,
|
size: bodies[n].length,
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ async function testDeployment(
|
|||||||
|
|
||||||
// we use json5 to allow comments for probes
|
// we use json5 to allow comments for probes
|
||||||
const nowJson = json5.parse(bodies[configName]);
|
const nowJson = json5.parse(bodies[configName]);
|
||||||
|
const uploadNowJson = nowJson.uploadNowJson;
|
||||||
|
delete nowJson.uploadNowJson;
|
||||||
|
|
||||||
if (process.env.VERCEL_BUILDER_DEBUG) {
|
if (process.env.VERCEL_BUILDER_DEBUG) {
|
||||||
if (!nowJson.build) {
|
if (!nowJson.build) {
|
||||||
@@ -94,8 +96,14 @@ async function testDeployment(
|
|||||||
|
|
||||||
bodies[configName] = Buffer.from(JSON.stringify(nowJson));
|
bodies[configName] = Buffer.from(JSON.stringify(nowJson));
|
||||||
delete bodies['probe.js'];
|
delete bodies['probe.js'];
|
||||||
const { deploymentId, deploymentUrl } = await nowDeploy(bodies, randomness);
|
|
||||||
|
const { deploymentId, deploymentUrl } = await nowDeploy(
|
||||||
|
bodies,
|
||||||
|
randomness,
|
||||||
|
uploadNowJson
|
||||||
|
);
|
||||||
let nextBuildManifest;
|
let nextBuildManifest;
|
||||||
|
let deploymentLogs;
|
||||||
|
|
||||||
for (const probe of nowJson.probes || []) {
|
for (const probe of nowJson.probes || []) {
|
||||||
console.log('testing', JSON.stringify(probe));
|
console.log('testing', JSON.stringify(probe));
|
||||||
@@ -104,6 +112,60 @@ async function testDeployment(
|
|||||||
continue;
|
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__(');
|
const nextScriptIndex = probe.path.indexOf('__NEXT_SCRIPT__(');
|
||||||
|
|
||||||
if (nextScriptIndex > -1) {
|
if (nextScriptIndex > -1) {
|
||||||
|
|||||||
@@ -2190,6 +2190,11 @@
|
|||||||
semver "^7.3.2"
|
semver "^7.3.2"
|
||||||
tsutils "^3.17.1"
|
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":
|
"@zeit/dns-cached-resolve@2.1.0":
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@zeit/dns-cached-resolve/-/dns-cached-resolve-2.1.0.tgz#78583010df1683fdb7b05949b75593c9a8641bc1"
|
resolved "https://registry.yarnpkg.com/@zeit/dns-cached-resolve/-/dns-cached-resolve-2.1.0.tgz#78583010df1683fdb7b05949b75593c9a8641bc1"
|
||||||
|
|||||||
Reference in New Issue
Block a user