Skip to content

Commit 39b2968

Browse files
committed
Merge branch 'main' into mk/ttl-support
2 parents 8302eca + 9e3dd0e commit 39b2968

File tree

10 files changed

+269
-42
lines changed

10 files changed

+269
-42
lines changed

demo/next.config.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module.exports = {
44
generateBuildId: () => 'build-id',
55
i18n: {
66
defaultLocale: 'en',
7-
locales: ['en', 'es', 'fr']
7+
locales: ['en', 'es', 'fr'],
88
},
99
async headers() {
1010
return [
@@ -14,7 +14,7 @@ module.exports = {
1414
{
1515
key: 'x-custom-header',
1616
value: 'my custom header value',
17-
}
17+
},
1818
],
1919
},
2020
]
@@ -29,8 +29,8 @@ module.exports = {
2929
{
3030
source: '/old/:path*',
3131
destination: '/:path*',
32-
}
33-
]
32+
},
33+
],
3434
}
3535
},
3636
// Redirects allow you to redirect an incoming request path to a different destination path.

demo/pages/old/image.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const Images = () => (
2+
<div>
3+
<p>If you can see this, rewrites aren&apos;t working</p>
4+
</div>
5+
)
6+
7+
export default Images

demo/pages/redirectme.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const Redirect = () => (
2+
<div>
3+
<p>If you can see this, redirects aren&apos;t working</p>
4+
</div>
5+
)
6+
7+
export default Redirect

package-lock.json

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

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
"@types/mocha": "^9.0.0",
8181
"babel-jest": "^27.2.5",
8282
"cpy": "^8.1.2",
83-
"cypress": "^8.5.0",
83+
"cypress": "^9.0.0",
8484
"eslint-config-next": "^11.0.0",
8585
"husky": "^4.3.0",
8686
"jest": "^27.0.0",

src/helpers/files.js

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,36 @@ const matchMiddleware = (middleware, filePath) =>
2828
filePath === middlewarePath || filePath === `${middlewarePath}.html` || filePath.startsWith(`${middlewarePath}/`),
2929
)
3030

31+
const matchesRedirect = (file, redirects) => {
32+
if (!Array.isArray(redirects)) {
33+
return false
34+
}
35+
return redirects.some((redirect) => {
36+
if (!redirect.regex || redirect.internal) {
37+
return false
38+
}
39+
// Strips the extension from the file path
40+
return new RegExp(redirect.regex).test(`/${file.slice(0, -5)}`)
41+
})
42+
}
43+
44+
const matchesRewrite = (file, rewrites) => {
45+
if (Array.isArray(rewrites)) {
46+
return matchesRedirect(file, rewrites)
47+
}
48+
if (!Array.isArray(rewrites?.beforeFiles)) {
49+
return false
50+
}
51+
return matchesRedirect(file, rewrites.beforeFiles)
52+
}
53+
54+
exports.matchesRedirect = matchesRedirect
55+
exports.matchesRewrite = matchesRewrite
3156
exports.matchMiddleware = matchMiddleware
3257
exports.stripLocale = stripLocale
3358
exports.isDynamicRoute = isDynamicRoute
3459

60+
// eslint-disable-next-line max-lines-per-function
3561
exports.moveStaticPages = async ({ netlifyConfig, target, i18n }) => {
3662
console.log('Moving static page files to serve from CDN...')
3763
const outputDir = join(netlifyConfig.build.publish, target === 'server' ? 'server' : 'serverless')
@@ -48,6 +74,7 @@ exports.moveStaticPages = async ({ netlifyConfig, target, i18n }) => {
4874
}
4975

5076
const prerenderManifest = await readJson(join(netlifyConfig.build.publish, 'prerender-manifest.json'))
77+
const { redirects, rewrites } = await readJson(join(netlifyConfig.build.publish, 'routes-manifest.json'))
5178

5279
const isrFiles = new Set()
5380

@@ -79,6 +106,8 @@ exports.moveStaticPages = async ({ netlifyConfig, target, i18n }) => {
79106

80107
const matchingMiddleware = new Set()
81108
const matchedPages = new Set()
109+
const matchedRedirects = new Set()
110+
const matchedRewrites = new Set()
82111

83112
// Limit concurrent file moves to number of cpus or 2 if there is only 1
84113
const limit = pLimit(Math.max(2, cpus().length))
@@ -91,6 +120,14 @@ exports.moveStaticPages = async ({ netlifyConfig, target, i18n }) => {
91120
if (isDynamicRoute(filePath)) {
92121
return
93122
}
123+
if (matchesRedirect(filePath, redirects)) {
124+
matchedRedirects.add(filePath)
125+
return
126+
}
127+
if (matchesRewrite(filePath, rewrites)) {
128+
matchedRewrites.add(filePath)
129+
return
130+
}
94131
// Middleware matches against the unlocalised path
95132
const unlocalizedPath = stripLocale(rawPath, i18n?.locales)
96133
const middlewarePath = matchMiddleware(middleware, unlocalizedPath)
@@ -110,7 +147,8 @@ exports.moveStaticPages = async ({ netlifyConfig, target, i18n }) => {
110147
yellowBright(outdent`
111148
Skipped moving ${matchedPages.size} ${
112149
matchedPages.size === 1 ? 'file because it matches' : 'files because they match'
113-
} middleware, so cannot be deployed to the CDN and will be served from the origin instead. This is fine, but we're letting you know because it may not be what you expect.
150+
} middleware, so cannot be deployed to the CDN and will be served from the origin instead.
151+
This is fine, but we're letting you know because it may not be what you expect.
114152
`),
115153
)
116154

@@ -119,6 +157,8 @@ exports.moveStaticPages = async ({ netlifyConfig, target, i18n }) => {
119157
The following middleware matched statically-rendered pages:
120158
121159
${yellowBright([...matchingMiddleware].map((mid) => `- /${mid}/_middleware`).join('\n'))}
160+
161+
────────────────────────────────────────────────────────────────
122162
`,
123163
)
124164
// There could potentially be thousands of matching pages, so we don't want to spam the console with this
@@ -128,6 +168,40 @@ exports.moveStaticPages = async ({ netlifyConfig, target, i18n }) => {
128168
The following files matched middleware and were not moved to the CDN:
129169
130170
${yellowBright([...matchedPages].map((mid) => `- ${mid}`).join('\n'))}
171+
172+
────────────────────────────────────────────────────────────────
173+
`,
174+
)
175+
}
176+
}
177+
178+
if (matchedRedirects.size !== 0 || matchedRewrites.size !== 0) {
179+
console.log(
180+
yellowBright(outdent`
181+
Skipped moving ${
182+
matchedRedirects.size + matchedRewrites.size
183+
} files because they match redirects or beforeFiles rewrites, so cannot be deployed to the CDN and will be served from the origin instead.
184+
`),
185+
)
186+
if (matchedRedirects.size < 50 && matchedRedirects.size !== 0) {
187+
console.log(
188+
outdent`
189+
The following files matched redirects and were not moved to the CDN:
190+
191+
${yellowBright([...matchedRedirects].map((mid) => `- ${mid}`).join('\n'))}
192+
193+
────────────────────────────────────────────────────────────────
194+
`,
195+
)
196+
}
197+
if (matchedRewrites.size < 50 && matchedRewrites.size !== 0) {
198+
console.log(
199+
outdent`
200+
The following files matched beforeFiles rewrites and were not moved to the CDN:
201+
202+
${yellowBright([...matchedRewrites].map((mid) => `- ${mid}`).join('\n'))}
203+
204+
────────────────────────────────────────────────────────────────
131205
`,
132206
)
133207
}

src/helpers/functions.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ exports.generateFunctions = async (
2222
await ensureDir(join(functionsDir, func))
2323
await writeFile(join(functionsDir, func, `${func}.js`), handlerSource)
2424
await copyFile(bridgeFile, join(functionsDir, func, 'bridge.js'))
25+
await copyFile(
26+
join(__dirname, '..', '..', 'lib', 'templates', 'handlerUtils.js'),
27+
join(functionsDir, func, 'handlerUtils.js'),
28+
)
2529
}
2630

2731
await writeHandler(HANDLER_FUNCTION_NAME, false)

src/templates/getHandler.js

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
/* eslint-disable max-lines-per-function, max-lines */
2-
const { promises, createWriteStream, existsSync } = require('fs')
1+
const { promises, existsSync } = require('fs')
32
const { Server } = require('http')
43
const { tmpdir } = require('os')
54
const path = require('path')
6-
const { promisify } = require('util')
75

8-
const streamPipeline = promisify(require('stream').pipeline)
96
const { Bridge } = require('@vercel/node/dist/bridge')
10-
const fetch = require('node-fetch')
7+
8+
const { downloadFile } = require('./handlerUtils')
119

1210
const makeHandler =
1311
() =>
@@ -59,14 +57,7 @@ const makeHandler =
5957

6058
// Append the path to our host and we can load it like a regular page
6159
const url = `${base}/${filePath}`
62-
console.log(`Downloading ${url} to ${cacheFile}`)
63-
const response = await fetch(url)
64-
if (!response.ok) {
65-
// Next catches this and returns it as a not found file
66-
throw new Error(`Failed to fetch ${url}`)
67-
}
68-
// Stream it to disk
69-
await streamPipeline(response.body, createWriteStream(cacheFile))
60+
await downloadFile(url, cacheFile)
7061
}
7162
// Return the cache file
7263
return readfileOrig(cacheFile, options)
@@ -195,12 +186,10 @@ const makeHandler =
195186
const getHandler = ({ isODB = false, publishDir = '../../../.next', appDir = '../../..' }) => `
196187
const { Server } = require("http");
197188
const { tmpdir } = require('os')
198-
const { promises, createWriteStream, existsSync } = require("fs");
199-
const { promisify } = require('util')
200-
const streamPipeline = promisify(require('stream').pipeline)
189+
const { promises, existsSync } = require("fs");
201190
// We copy the file here rather than requiring from the node module
202191
const { Bridge } = require("./bridge");
203-
const fetch = require('node-fetch')
192+
const { downloadFile } = require('./handlerUtils')
204193
205194
const { builder } = require("@netlify/functions");
206195
const { config } = require("${publishDir}/required-server-files.json")
@@ -218,4 +207,3 @@ exports.handler = ${
218207
`
219208

220209
module.exports = getHandler
221-
/* eslint-enable max-lines-per-function, max-lines */

src/templates/handlerUtils.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { createWriteStream } from 'fs'
2+
import http from 'http'
3+
import https from 'https'
4+
import { pipeline } from 'stream'
5+
import { promisify } from 'util'
6+
7+
const streamPipeline = promisify(pipeline)
8+
9+
export const downloadFile = async (url, destination) => {
10+
console.log(`Downloading ${url} to ${destination}`)
11+
12+
const httpx = url.startsWith('https') ? https : http
13+
14+
await new Promise((resolve, reject) => {
15+
const req = httpx.get(url, { timeout: 10000 }, (response) => {
16+
if (response.statusCode < 200 || response.statusCode > 299) {
17+
reject(new Error(`Failed to download ${url}: ${response.statusCode} ${response.statusMessage || ''}`))
18+
return
19+
}
20+
const fileStream = createWriteStream(destination)
21+
streamPipeline(response, fileStream)
22+
.then(resolve)
23+
.catch((error) => {
24+
console.log(`Error downloading ${url}`, error)
25+
reject(error)
26+
})
27+
})
28+
req.on('error', (error) => {
29+
console.log(`Error downloading ${url}`, error)
30+
reject(error)
31+
})
32+
})
33+
}

0 commit comments

Comments
 (0)