Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[now-next] Add /_next/data routes for getServerProps pages #3771

Merged
merged 10 commits into from Feb 26, 2020
28 changes: 24 additions & 4 deletions packages/now-next/src/index.ts
Expand Up @@ -334,11 +334,16 @@ export const build = async ({
env.NODE_OPTIONS = `--max_old_space_size=${memoryToConsume}`;
await runPackageJsonScript(entryPath, shouldRunScript, { ...spawnOpts, env });

const appMountPrefixNoTrailingSlash = path.posix
.join('/', entryDirectory)
.replace(/\/+$/, '');

const routesManifest = await getRoutesManifest(entryPath, realNextVersion);
const headers: Route[] = [];
const rewrites: Route[] = [];
const redirects: Route[] = [];
const nextBasePathRoute: Route[] = [];
const serverPropsRoutes: Route[] = [];
let nextBasePath: string | undefined;

if (routesManifest) {
Expand All @@ -352,6 +357,21 @@ export const build = async ({
headers.push(...convertHeaders(routesManifest.headers));
}

if (routesManifest.serverPropsRoutes) {
const sspRoutes = routesManifest.serverPropsRoutes;

// build the /_next/data routes for getServerProps
Object.keys(sspRoutes).forEach(page => {
serverPropsRoutes.push({
src: sspRoutes[page].dataRouteRegex.replace(
/^\^/,
`^${appMountPrefixNoTrailingSlash}`
),
dest: path.join('/', entryDirectory, page),
});
});
}

if (routesManifest.basePath && routesManifest.basePath !== '/') {
nextBasePath = routesManifest.basePath;

Expand Down Expand Up @@ -499,10 +519,6 @@ export const build = async ({
const dynamicPages: string[] = [];
const dynamicDataRoutes: Array<Source> = [];

const appMountPrefixNoTrailingSlash = path.posix
.join('/', entryDirectory)
.replace(/\/+$/, '');

if (isLegacy) {
const filesAfterBuild = await glob('**', entryPath);

Expand Down Expand Up @@ -1034,6 +1050,10 @@ export const build = async ({
continue: true,
},
{ src: path.join('/', entryDirectory, '_next(?!/data(?:/|$))(?:/.*)?') },

// /_next/data routes for getServerProps pages
...serverPropsRoutes,
ijjk marked this conversation as resolved.
Show resolved Hide resolved

// Next.js page lambdas, `static/` folder, reserved assets, and `public/`
// folder
{ handle: 'filesystem' },
Expand Down
6 changes: 6 additions & 0 deletions packages/now-next/src/utils.ts
Expand Up @@ -315,6 +315,12 @@ export type RoutesManifest = {
regex: string;
}[];
version: number;
serverPropsRoutes?: {
[page: string]: {
page: string;
dataRouteRegex: string;
};
};
};

export async function getRoutesManifest(
Expand Down
@@ -0,0 +1,5 @@
module.exports = {
generateBuildId() {
return 'testing-build-id';
},
};
164 changes: 164 additions & 0 deletions packages/now-next/test/fixtures/18-server-props/now.json
@@ -0,0 +1,164 @@
{
"version": 2,
"builds": [{ "src": "package.json", "use": "@now/next" }],
"probes": [
{
"path": "/lambda",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{
"path": "/forever",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{ "delay": 2000 },
{
"path": "/forever",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{
"path": "/another",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{ "delay": 2000 },
{
"path": "/another",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{
"path": "/blog/post-1",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{ "delay": 2000 },
{
"path": "/blog/post-1",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{
"path": "/blog/post-2",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{ "delay": 2000 },
{
"path": "/blog/post-2",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{
"path": "/blog/post-3",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{ "delay": 2000 },
{
"path": "/blog/post-3",
"status": 200,
"responseHeaders": {
"x-now-cache": "/MISS/"
}
},
{
"path": "/blog/post-1/comment-1",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{
"path": "/blog/post-2/comment-2",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{
"path": "/blog/post-3/comment-3",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{
"path": "/_next/data/testing-build-id/lambda.json",
"status": 404
},
{
"path": "/_next/data/testing-build-id/another.json",
"status": 200,
"responseHeaders": {
"x-now-cache": "/MISS/"
}
},
{
"path": "/_next/data/testing-build-id/another2.json",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{ "delay": 2000 },
{
"path": "/_next/data/testing-build-id/another2.json",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{
"path": "/_next/data/testing-build-id/blog/post-1.json",
"status": 200,
"responseHeaders": {
"x-now-cache": "/MISS/"
}
},
{
"path": "/_next/data/testing-build-id/blog/post-1.json",
"status": 200,
"mustContain": "post-1"
},
{
"path": "/_next/data/testing-build-id/blog/post-1337/comment-1337.json",
"status": 200,
"responseHeaders": {
"x-now-cache": "MISS"
}
},
{
"path": "/_next/data/testing-build-id/blog/post-1337/comment-1337.json",
"status": 200,
"mustContain": "comment-1337"
},
{
"path": "/_next/data/testing-build-id/blog/post-1337/comment-1337.json",
"status": 200,
"mustContain": "post-1337"
}
]
}
7 changes: 7 additions & 0 deletions packages/now-next/test/fixtures/18-server-props/package.json
@@ -0,0 +1,7 @@
{
"dependencies": {
"next": "9.2.2-canary.14",
"react": "^16.8.6",
"react-dom": "^16.8.6"
}
}
20 changes: 20 additions & 0 deletions packages/now-next/test/fixtures/18-server-props/pages/another.js
@@ -0,0 +1,20 @@
import React from 'react';

// eslint-disable-next-line camelcase
export async function unstable_getServerProps() {
return {
props: {
world: 'world',
time: new Date().getTime(),
},
};
}

export default ({ world, time }) => {
return (
<>
<p>hello: {world}</p>
<span>time: {time}</span>
</>
);
};
20 changes: 20 additions & 0 deletions packages/now-next/test/fixtures/18-server-props/pages/another2.js
@@ -0,0 +1,20 @@
import React from 'react';

// eslint-disable-next-line camelcase
export async function unstable_getServerProps() {
return {
props: {
world: 'world',
time: new Date().getTime(),
},
};
}

export default ({ world, time }) => {
return (
<>
<p>hello: {world}</p>
<span>time: {time}</span>
</>
);
};
@@ -0,0 +1,22 @@
import React from 'react';

// eslint-disable-next-line camelcase
export async function unstable_getServerProps ({ params }) {
return {
props: {
post: params.post,
comment: params.comment,
time: new Date().getTime(),
},
};
}

export default ({ post, comment, time }) => {
return (
<>
<p>Post: {post}</p>
<p>Comment: {comment}</p>
<span>time: {time}</span>
</>
);
};
@@ -0,0 +1,26 @@
import React from 'react'

// eslint-disable-next-line camelcase
export async function unstable_getServerProps ({ params }) {
if (params.post === 'post-10') {
await new Promise(resolve => {
setTimeout(() => resolve(), 1000)
})
}

return {
props: {
post: params.post,
time: (await import('perf_hooks')).performance.now()
},
}
}

export default ({ post, time }) => {
return (
<>
<p>Post: {post}</p>
<span>time: {time}</span>
</>
)
}
20 changes: 20 additions & 0 deletions packages/now-next/test/fixtures/18-server-props/pages/forever.js
@@ -0,0 +1,20 @@
import React from 'react';

// eslint-disable-next-line camelcase
export async function unstable_getServerProps() {
return {
props: {
world: 'world',
time: new Date().getTime(),
},
};
}

export default ({ world, time }) => {
return (
<>
<p>hello: {world}</p>
<span>time: {time}</span>
</>
);
};
@@ -0,0 +1 @@
export default () => 'Hi';
@@ -0,0 +1,5 @@
const Page = ({ data }) => <p>{data} world</p>;

Page.getInitialProps = () => ({ data: 'hello' });

export default Page;
2 changes: 1 addition & 1 deletion packages/now-next/test/unit/build.test.js
Expand Up @@ -115,7 +115,7 @@ describe('build meta dev', () => {
{ src: '/nested/page', dest: 'http://localhost:5000/nested/page' },
{ src: '/api/test', dest: 'http://localhost:5000/api/test' },
{
src: '^/(nested\\/([^\\/]+?)(?:\\/)?)$',
src: '^/(nested\\/([^/]+?)(?:\\/)?)$',
dest: 'http://localhost:5000/$1',
},
{ src: '/data.txt', dest: 'http://localhost:5000/data.txt' },
Expand Down