Skip to content

Commit 267ff0b

Browse files
authored
fix: resolve all pages using nft (#1780)
* fix: resolve all pages using nft * chore: remove logging * chore: simplify function signature * chore: fix test on old Node * chore: fix test on old Node * fix: `:old-man-yells-at-windows-paths:`
1 parent c6aeb68 commit 267ff0b

File tree

7 files changed

+298
-84
lines changed

7 files changed

+298
-84
lines changed

demos/default/hello.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
world
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Link from 'next/link'
2+
import path from 'path'
3+
import fs from 'fs'
4+
5+
export async function getServerSideProps() {
6+
const text = fs.readFileSync(path.join(process.cwd(), 'hello.txt'), 'utf8').trim()
7+
8+
return {
9+
props: {
10+
world: text,
11+
time: new Date().getTime(),
12+
},
13+
}
14+
}
15+
16+
const File = ({ world, time }) => (
17+
<>
18+
<p>hello {world}</p>
19+
<span id="anotherTime">time: {time}</span>
20+
<Link href="/" id="home">
21+
to home
22+
</Link>
23+
<br />
24+
<Link href="/something" id="something">
25+
to something
26+
</Link>
27+
</>
28+
)
29+
export default File

packages/runtime/src/helpers/functions.ts

+7-12
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { join, relative, resolve } from 'pathe'
1111
import { HANDLER_FUNCTION_NAME, ODB_FUNCTION_NAME, IMAGE_FUNCTION_NAME, DEFAULT_FUNCTIONS_SRC } from '../constants'
1212
import { getApiHandler } from '../templates/getApiHandler'
1313
import { getHandler } from '../templates/getHandler'
14-
import { getPageResolver, getSinglePageResolver } from '../templates/getPageResolver'
14+
import { getResolverForPages, getResolverForSourceFiles } from '../templates/getPageResolver'
1515

1616
import { ApiConfig, ApiRouteType, extractConfigFromFile } from './analysis'
1717
import { getSourceFileForPage } from './files'
@@ -52,7 +52,7 @@ export const generateFunctions = async (
5252

5353
const resolveSourceFile = (file: string) => join(publish, 'server', file)
5454

55-
const resolverSource = await getSinglePageResolver({
55+
const resolverSource = await getResolverForSourceFiles({
5656
functionsDir,
5757
// These extra pages are always included by Next.js
5858
sourceFiles: [compiled, 'pages/_app.js', 'pages/_document.js', 'pages/_error.js'].map(resolveSourceFile),
@@ -80,18 +80,13 @@ export const generateFunctions = async (
8080
* This is just so that the nft bundler knows about them. We'll eventually do this better.
8181
*/
8282
export const generatePagesResolver = async ({
83-
constants: { INTERNAL_FUNCTIONS_SRC, FUNCTIONS_SRC = DEFAULT_FUNCTIONS_SRC, PUBLISH_DIR },
84-
target,
85-
}: {
86-
constants: NetlifyPluginConstants
87-
target: string
88-
}): Promise<void> => {
83+
INTERNAL_FUNCTIONS_SRC,
84+
FUNCTIONS_SRC = DEFAULT_FUNCTIONS_SRC,
85+
PUBLISH_DIR,
86+
}: NetlifyPluginConstants): Promise<void> => {
8987
const functionsPath = INTERNAL_FUNCTIONS_SRC || FUNCTIONS_SRC
9088

91-
const jsSource = await getPageResolver({
92-
publish: PUBLISH_DIR,
93-
target,
94-
})
89+
const jsSource = await getResolverForPages(PUBLISH_DIR)
9590

9691
await writeFile(join(functionsPath, ODB_FUNCTION_NAME, 'pages.js'), jsSource)
9792
await writeFile(join(functionsPath, HANDLER_FUNCTION_NAME, 'pages.js'), jsSource)

packages/runtime/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ const plugin: NetlifyPlugin = {
155155
const apiRoutes = await getExtendedApiRouteConfigs(publish, appDir)
156156

157157
await generateFunctions(constants, appDir, apiRoutes)
158-
await generatePagesResolver({ target, constants })
158+
await generatePagesResolver(constants)
159159

160160
await movePublicFiles({ appDir, outdir, publish })
161161

Original file line numberDiff line numberDiff line change
@@ -1,30 +1,40 @@
1-
import { posix } from 'path'
2-
1+
import glob from 'globby'
32
import { outdent } from 'outdent'
4-
import { relative, resolve } from 'pathe'
5-
import slash from 'slash'
6-
import glob from 'tiny-glob'
3+
import { join, relative, resolve } from 'pathe'
74

85
import { HANDLER_FUNCTION_NAME } from '../constants'
96
import { getDependenciesOfFile } from '../helpers/files'
107

118
// Generate a file full of require.resolve() calls for all the pages in the
129
// build. This is used by the nft bundler to find all the pages.
1310

14-
export const getPageResolver = async ({ publish, target }: { publish: string; target: string }) => {
15-
const functionDir = posix.resolve(posix.join('.netlify', 'functions', HANDLER_FUNCTION_NAME))
16-
const root = posix.resolve(slash(publish), target === 'server' ? 'server' : 'serverless', 'pages')
11+
export const getUniqueDependencies = async (sourceFiles: Array<string>) => {
12+
const dependencies = await Promise.all(sourceFiles.map((sourceFile) => getDependenciesOfFile(sourceFile)))
13+
return [...new Set([...sourceFiles, ...dependencies.flat()])].sort()
14+
}
1715

18-
const pages = await glob('**/*.js', {
16+
export const getAllPageDependencies = async (publish: string) => {
17+
const root = resolve(publish, 'server')
18+
19+
const pageFiles = await glob('{pages,app}/**/*.js', {
1920
cwd: root,
2021
dot: true,
2122
})
22-
const pageFiles = pages
23-
.map((page) => `require.resolve('${posix.relative(functionDir, posix.join(root, slash(page)))}')`)
24-
.sort()
23+
// We don't use `absolute: true` because that returns Windows paths on Windows.
24+
// Instead we use pathe to normalize the paths.
25+
return getUniqueDependencies(pageFiles.map((pageFile) => join(root, pageFile)))
26+
}
2527

26-
return outdent`
27-
// This file is purely to allow nft to know about these pages. It should be temporary.
28+
export const getResolverForDependencies = ({
29+
dependencies,
30+
functionDir,
31+
}: {
32+
dependencies: string[]
33+
functionDir: string
34+
}) => {
35+
const pageFiles = dependencies.map((file) => `require.resolve('${relative(functionDir, file)}')`)
36+
return outdent/* javascript */ `
37+
// This file is purely to allow nft to know about these pages.
2838
exports.resolvePages = () => {
2939
try {
3040
${pageFiles.join('\n ')}
@@ -33,31 +43,21 @@ export const getPageResolver = async ({ publish, target }: { publish: string; ta
3343
`
3444
}
3545

36-
/**
37-
* API routes only need the dependencies for a single entrypoint, so we use the
38-
* NFT trace file to get the dependencies.
39-
*/
40-
export const getSinglePageResolver = async ({
46+
export const getResolverForPages = async (publish: string) => {
47+
const functionDir = resolve('.netlify', 'functions', HANDLER_FUNCTION_NAME)
48+
const dependencies = await getAllPageDependencies(publish)
49+
return getResolverForDependencies({ dependencies, functionDir })
50+
}
51+
52+
export const getResolverForSourceFiles = async ({
4153
functionsDir,
4254
sourceFiles,
4355
}: {
4456
functionsDir: string
4557
sourceFiles: Array<string>
4658
}) => {
47-
const dependencies = await Promise.all(sourceFiles.map((sourceFile) => getDependenciesOfFile(sourceFile)))
4859
// We don't need the actual name, just the relative path.
4960
const functionDir = resolve(functionsDir, 'functionName')
50-
51-
const deduped = [...new Set(dependencies.flat())]
52-
53-
const pageFiles = [...sourceFiles, ...deduped]
54-
.map((file) => `require.resolve('${relative(functionDir, file)}')`)
55-
.sort()
56-
57-
return outdent/* javascript */ `
58-
// This file is purely to allow nft to know about these pages.
59-
try {
60-
${pageFiles.join('\n ')}
61-
} catch {}
62-
`
61+
const dependencies = await getUniqueDependencies(sourceFiles)
62+
return getResolverForDependencies({ dependencies, functionDir })
6363
}

0 commit comments

Comments
 (0)