Skip to content

Commit 2e65907

Browse files
authored
Merge branch 'main' into mk/locale-detection
2 parents 14fbaec + adea889 commit 2e65907

File tree

8 files changed

+333
-88
lines changed

8 files changed

+333
-88
lines changed

demos/default/next.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ module.exports = {
3131
destination: '/:path*',
3232
},
3333
],
34+
afterFiles: [{
35+
source: '/rewriteToStatic',
36+
destination: '/getStaticProps/1',
37+
}]
3438
}
3539
},
3640
// Redirects allow you to redirect an incoming request path to a different destination path.

demos/default/pages/index.js

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const Index = ({ shows }) => {
5151
))}
5252
</ul>
5353

54-
<h2>Catch-All Routess</h2>
54+
<h2>Catch-All Routes</h2>
5555

5656
<ul data-testid="list-catch-all">
5757
<li>
@@ -105,6 +105,79 @@ const Index = ({ shows }) => {
105105
</Link>
106106
</li>
107107
</ul>
108+
<h2>Page types</h2>
109+
<ul>
110+
<li>
111+
<Link href="/getServerSideProps/1">
112+
<a>/getServerSideProps/1</a>
113+
</Link>
114+
</li>
115+
<li>
116+
<Link href="/getServerSideProps/static">
117+
<a>/getServerSideProps/static</a>
118+
</Link>
119+
</li>
120+
<li>
121+
<Link href="/getServerSideProps/all/1">
122+
<a>/getServerSideProps/all/1</a>
123+
</Link>
124+
</li>
125+
<li>
126+
<Link href="/getStaticProps/1">
127+
<a>/getStaticProps/1</a>
128+
</Link>
129+
</li>
130+
<li>
131+
<Link href="/getStaticProps/static">
132+
<a>/getStaticProps/static</a>
133+
</Link>
134+
</li>
135+
<li>
136+
<Link href="/getStaticProps/with-revalidate">
137+
<a>/getStaticProps/with-revalidate</a>
138+
</Link>
139+
</li>
140+
<li>
141+
<Link href="/getStaticProps/withFallback/3">
142+
<a>/getStaticProps/withFallback/3 (pre-rendered)</a>
143+
</Link>
144+
</li>
145+
<li>
146+
<Link href="/getStaticProps/withFallback/300">
147+
<a>/getStaticProps/withFallback/300 (SSR)</a>
148+
</Link>
149+
</li>
150+
<li>
151+
<Link href="/getStaticProps/withFallbackBlocking/300">
152+
<a>/getStaticProps/withFallbackBlocking/300 (SSR)</a>
153+
</Link>
154+
</li>
155+
<li>
156+
<Link href="/getStaticProps/withRevalidate/2">
157+
<a>/getStaticProps/withRevalidate/2</a>
158+
</Link>
159+
</li>
160+
<li>
161+
<Link href="/getStaticProps/withRevalidate/withFallback/200">
162+
<a>/getStaticProps/withRevalidate/withFallback/200</a>
163+
</Link>
164+
</li>
165+
<li>
166+
<Link href="/old/image">
167+
<a>Rewrite (should display image)</a>
168+
</Link>
169+
</li>
170+
<li>
171+
<Link href="/rewriteToStatic">
172+
<a>Rewrite to static (should show getStaticProps/1)</a>
173+
</Link>
174+
</li>
175+
<li>
176+
<Link href="/middle">
177+
<a>Middleware</a>
178+
</Link>
179+
</li>
180+
</ul>
108181
</div>
109182
)
110183
}

package-lock.json

Lines changed: 30 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@
7575
"@babel/core": "^7.15.8",
7676
"@babel/preset-env": "^7.15.8",
7777
"@babel/preset-typescript": "^7.16.0",
78-
"@netlify/build": "^20.0.1",
79-
"@netlify/eslint-config-node": "^3.3.10",
78+
"@netlify/build": "^20.0.3",
79+
"@netlify/eslint-config-node": "^3.3.11",
8080
"@testing-library/cypress": "^8.0.1",
8181
"@types/fs-extra": "^9.0.13",
8282
"@types/jest": "^27.0.2",

src/helpers/files.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,17 @@
22
const { cpus } = require('os')
33

44
const { yellowBright } = require('chalk')
5-
const { existsSync, readJson, move, cpSync, copy, writeJson, readFile, writeFile } = require('fs-extra')
5+
const {
6+
existsSync,
7+
readJson,
8+
move,
9+
copy,
10+
writeJson,
11+
readFile,
12+
writeFile,
13+
ensureDir,
14+
readFileSync,
15+
} = require('fs-extra')
616
const globby = require('globby')
717
const { outdent } = require('outdent')
818
const pLimit = require('p-limit')
@@ -62,7 +72,9 @@ exports.moveStaticPages = async ({ netlifyConfig, target, i18n }) => {
6272
console.log('Moving static page files to serve from CDN...')
6373
const outputDir = join(netlifyConfig.build.publish, target === 'server' ? 'server' : 'serverless')
6474
const root = join(outputDir, 'pages')
65-
75+
const buildId = readFileSync(join(netlifyConfig.build.publish, 'BUILD_ID'), 'utf8').trim()
76+
const dataDir = join('_next', 'data', buildId)
77+
await ensureDir(dataDir)
6678
// Load the middleware manifest so we can check if a file matches it before moving
6779
let middleware
6880
const manifestPath = join(outputDir, 'middleware-manifest.json')
@@ -88,10 +100,17 @@ exports.moveStaticPages = async ({ netlifyConfig, target, i18n }) => {
88100
})
89101

90102
const files = []
103+
const filesManifest = {}
91104
const moveFile = async (file) => {
105+
const isData = file.endsWith('.json')
92106
const source = join(root, file)
107+
const target = isData ? join(dataDir, file) : file
108+
93109
files.push(file)
94-
const dest = join(netlifyConfig.build.publish, file)
110+
filesManifest[file] = target
111+
112+
const dest = join(netlifyConfig.build.publish, target)
113+
95114
try {
96115
await move(source, dest)
97116
} catch (error) {
@@ -208,7 +227,7 @@ exports.moveStaticPages = async ({ netlifyConfig, target, i18n }) => {
208227
}
209228

210229
// Write the manifest for use in the serverless functions
211-
await writeJson(join(netlifyConfig.build.publish, 'static-manifest.json'), files)
230+
await writeJson(join(netlifyConfig.build.publish, 'static-manifest.json'), Object.entries(filesManifest))
212231

213232
if (i18n?.defaultLocale) {
214233
// Copy the default locale into the root

src/templates/getHandler.js

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable max-lines-per-function */
12
const { promises, existsSync } = require('fs')
23
const { Server } = require('http')
34
const { tmpdir } = require('os')
@@ -34,12 +35,14 @@ const makeHandler =
3435
// In most cases these are served from the CDN, but for rewrites Next may try to read them
3536
// from disk. We need to intercept these and load them from the CDN instead
3637
// Sadly the only way to do this is to monkey-patch fs.promises. Yeah, I know.
37-
const staticFiles = new Set(staticManifest)
38-
38+
const staticFiles = new Map(staticManifest)
39+
const downloadPromises = new Map()
40+
const statsCache = new Map()
3941
// Yes, you can cache stuff locally in a Lambda
4042
const cacheDir = path.join(tmpdir(), 'next-static-cache')
4143
// Grab the real fs.promises.readFile...
4244
const readfileOrig = promises.readFile
45+
const statsOrig = promises.stat
4346
// ...then money-patch it to see if it's requesting a CDN file
4447
promises.readFile = async (file, options) => {
4548
// We only care about page files
@@ -51,13 +54,24 @@ const makeHandler =
5154
if (staticFiles.has(filePath) && !existsSync(file)) {
5255
// This name is safe to use, because it's one that was already created by Next
5356
const cacheFile = path.join(cacheDir, filePath)
54-
// Have we already cached it? We ignore the cache if running locally to avoid staleness
57+
const url = `${base}/${staticFiles.get(filePath)}`
58+
59+
// If it's already downloading we can wait for it to finish
60+
if (downloadPromises.has(url)) {
61+
await downloadPromises.get(url)
62+
}
63+
// Have we already cached it? We download every time if running locally to avoid staleness
5564
if ((!existsSync(cacheFile) || process.env.NETLIFY_DEV) && base) {
5665
await promises.mkdir(path.dirname(cacheFile), { recursive: true })
5766

58-
// Append the path to our host and we can load it like a regular page
59-
const url = `${base}/${filePath}`
60-
await downloadFile(url, cacheFile)
67+
try {
68+
// Append the path to our host and we can load it like a regular page
69+
const downloadPromise = downloadFile(url, cacheFile)
70+
downloadPromises.set(url, downloadPromise)
71+
await downloadPromise
72+
} finally {
73+
downloadPromises.delete(url)
74+
}
6175
}
6276
// Return the cache file
6377
return readfileOrig(cacheFile, options)
@@ -66,6 +80,18 @@ const makeHandler =
6680

6781
return readfileOrig(file, options)
6882
}
83+
84+
promises.stat = async (file, options) => {
85+
// We only care about page files
86+
if (file.startsWith(pageRoot)) {
87+
// We only want the part after `pages/`
88+
const cacheFile = path.join(cacheDir, file.slice(pageRoot.length + 1))
89+
if (existsSync(cacheFile)) {
90+
return statsOrig(cacheFile, options)
91+
}
92+
}
93+
return statsOrig(file, options)
94+
}
6995
}
7096
let NextServer
7197
try {
@@ -183,3 +209,4 @@ exports.handler = ${
183209
`
184210

185211
module.exports = getHandler
212+
/* eslint-enable max-lines-per-function */

0 commit comments

Comments
 (0)