@netlify/plugin-nextjs 4.33.1-lazy-server-import.0 → 4.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/helpers/analysis.js +5 -3
- package/lib/helpers/edge.js +12 -7
- package/lib/helpers/functions.js +1 -1
- package/lib/templates/getHandler.js +2 -2
- package/lib/templates/handlerUtils.js +1 -1
- package/package.json +3 -3
- package/src/templates/edge/imageconfig.json +3 -0
- package/src/templates/edge/ipx.ts +3 -71
- package/src/templates/edge-shared/rsc-data.ts +1 -1
package/lib/helpers/analysis.js
CHANGED
|
@@ -23,16 +23,18 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.extractConfigFromFile = exports.validateConfigValue = void 0;
|
|
26
|
+
exports.extractConfigFromFile = exports.validateConfigValue = exports.isEdgeConfig = void 0;
|
|
27
27
|
const fs_1 = __importStar(require("fs"));
|
|
28
28
|
const pathe_1 = require("pathe");
|
|
29
|
+
const isEdgeConfig = (config) => ['experimental-edge', 'edge'].includes(config);
|
|
30
|
+
exports.isEdgeConfig = isEdgeConfig;
|
|
29
31
|
const validateConfigValue = (config, apiFilePath) => {
|
|
30
32
|
if (config.type === "experimental-scheduled" /* ApiRouteType.SCHEDULED */) {
|
|
31
33
|
if (!config.schedule) {
|
|
32
34
|
console.error(`Invalid config value in ${(0, pathe_1.relative)(process.cwd(), apiFilePath)}: schedule is required when type is "${"experimental-scheduled" /* ApiRouteType.SCHEDULED */}"`);
|
|
33
35
|
return false;
|
|
34
36
|
}
|
|
35
|
-
if (config.runtime
|
|
37
|
+
if ((0, exports.isEdgeConfig)(config.runtime)) {
|
|
36
38
|
console.error(`Invalid config value in ${(0, pathe_1.relative)(process.cwd(), apiFilePath)}: edge runtime is not supported for scheduled functions`);
|
|
37
39
|
return false;
|
|
38
40
|
}
|
|
@@ -43,7 +45,7 @@ const validateConfigValue = (config, apiFilePath) => {
|
|
|
43
45
|
console.error(`Invalid config value in ${(0, pathe_1.relative)(process.cwd(), apiFilePath)}: schedule is not allowed unless type is "${"experimental-scheduled" /* ApiRouteType.SCHEDULED */}"`);
|
|
44
46
|
return false;
|
|
45
47
|
}
|
|
46
|
-
if (config.type && config.runtime
|
|
48
|
+
if (config.type && (0, exports.isEdgeConfig)(config.runtime)) {
|
|
47
49
|
console.error(`Invalid config value in ${(0, pathe_1.relative)(process.cwd(), apiFilePath)}: edge runtime is not supported for background functions`);
|
|
48
50
|
return false;
|
|
49
51
|
}
|
package/lib/helpers/edge.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.writeEdgeFunctions = exports.getEdgeFunctionPatternForPage = exports.
|
|
6
|
+
exports.writeEdgeFunctions = exports.getEdgeFunctionPatternForPage = exports.generateRscDataEdgeManifest = exports.writeDevEdgeFunction = exports.cleanupEdgeFunctions = exports.loadPrerenderManifest = exports.loadAppPathRoutesManifest = exports.loadMiddlewareManifest = exports.isAppDirRoute = void 0;
|
|
7
7
|
const fs_1 = require("fs");
|
|
8
8
|
const path_1 = require("path");
|
|
9
9
|
const chalk_1 = require("chalk");
|
|
@@ -130,19 +130,19 @@ exports.writeDevEdgeFunction = writeDevEdgeFunction;
|
|
|
130
130
|
/**
|
|
131
131
|
* Writes an edge function that routes RSC data requests to the `.rsc` route
|
|
132
132
|
*/
|
|
133
|
-
const
|
|
133
|
+
const generateRscDataEdgeManifest = async ({ prerenderManifest, appPathRoutesManifest, }) => {
|
|
134
134
|
if (!prerenderManifest || !appPathRoutesManifest) {
|
|
135
135
|
return [];
|
|
136
136
|
}
|
|
137
137
|
const staticAppdirRoutes = [];
|
|
138
138
|
for (const [path, route] of Object.entries(prerenderManifest.routes)) {
|
|
139
|
-
if ((0, exports.isAppDirRoute)(route.srcRoute, appPathRoutesManifest)) {
|
|
139
|
+
if ((0, exports.isAppDirRoute)(route.srcRoute, appPathRoutesManifest) && route.dataRoute) {
|
|
140
140
|
staticAppdirRoutes.push(path, route.dataRoute);
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
const dynamicAppDirRoutes = [];
|
|
144
144
|
for (const [path, route] of Object.entries(prerenderManifest.dynamicRoutes)) {
|
|
145
|
-
if ((0, exports.isAppDirRoute)(path, appPathRoutesManifest)) {
|
|
145
|
+
if ((0, exports.isAppDirRoute)(path, appPathRoutesManifest) && route.dataRouteRegex) {
|
|
146
146
|
dynamicAppDirRoutes.push(route.routeRegex, route.dataRouteRegex);
|
|
147
147
|
}
|
|
148
148
|
}
|
|
@@ -165,7 +165,7 @@ const writeRscDataEdgeFunction = async ({ prerenderManifest, appPathRoutesManife
|
|
|
165
165
|
})),
|
|
166
166
|
];
|
|
167
167
|
};
|
|
168
|
-
exports.
|
|
168
|
+
exports.generateRscDataEdgeManifest = generateRscDataEdgeManifest;
|
|
169
169
|
const getEdgeFunctionPatternForPage = ({ edgeFunctionDefinition, pageRegexMap, appPathRoutesManifest, }) => {
|
|
170
170
|
// We don't just use the matcher from the edge function definition, because it doesn't handle trailing slashes
|
|
171
171
|
var _a, _b;
|
|
@@ -189,6 +189,7 @@ const writeEdgeFunctions = async ({ netlifyConfig, routesManifest, }) => {
|
|
|
189
189
|
var _a;
|
|
190
190
|
const manifest = {
|
|
191
191
|
functions: [],
|
|
192
|
+
layers: [],
|
|
192
193
|
version: 1,
|
|
193
194
|
};
|
|
194
195
|
const edgeFunctionRoot = (0, path_1.resolve)('.netlify', 'edge-functions');
|
|
@@ -205,7 +206,7 @@ const writeEdgeFunctions = async ({ netlifyConfig, routesManifest, }) => {
|
|
|
205
206
|
console.log('Environment variable NEXT_DISABLE_NETLIFY_EDGE has been set, skipping Netlify Edge Function creation.');
|
|
206
207
|
return;
|
|
207
208
|
}
|
|
208
|
-
const rscFunctions = await (0, exports.
|
|
209
|
+
const rscFunctions = await (0, exports.generateRscDataEdgeManifest)({
|
|
209
210
|
prerenderManifest: await (0, exports.loadPrerenderManifest)(netlifyConfig),
|
|
210
211
|
appPathRoutesManifest: await (0, exports.loadAppPathRoutesManifest)(netlifyConfig),
|
|
211
212
|
});
|
|
@@ -291,7 +292,11 @@ const writeEdgeFunctions = async ({ netlifyConfig, routesManifest, }) => {
|
|
|
291
292
|
manifest.functions.push({
|
|
292
293
|
function: 'ipx',
|
|
293
294
|
name: 'next/image handler',
|
|
294
|
-
path: '/_next/image
|
|
295
|
+
path: nextConfig.images.path || '/_next/image',
|
|
296
|
+
});
|
|
297
|
+
manifest.layers.push({
|
|
298
|
+
name: 'https://ipx-edge-function-layer.netlify.app/mod.ts',
|
|
299
|
+
flag: 'ipx-edge-function-layer-url',
|
|
295
300
|
});
|
|
296
301
|
}
|
|
297
302
|
else {
|
package/lib/helpers/functions.js
CHANGED
|
@@ -25,7 +25,7 @@ const generateFunctions = async ({ FUNCTIONS_SRC = constants_1.DEFAULT_FUNCTIONS
|
|
|
25
25
|
const publishDir = (0, pathe_1.relative)(functionDir, publish);
|
|
26
26
|
for (const { route, config, compiled } of apiRoutes) {
|
|
27
27
|
// Don't write a lambda if the runtime is edge
|
|
28
|
-
if (config.runtime
|
|
28
|
+
if ((0, analysis_1.isEdgeConfig)(config.runtime)) {
|
|
29
29
|
continue;
|
|
30
30
|
}
|
|
31
31
|
const apiHandlerSource = await (0, getApiHandler_1.getApiHandler)({
|
|
@@ -11,14 +11,13 @@ const path = require('path');
|
|
|
11
11
|
const { URLSearchParams, URL } = require('url');
|
|
12
12
|
const { Bridge } = require('@vercel/node-bridge/bridge');
|
|
13
13
|
const { augmentFsModule, getMaxAge, getMultiValueHeaders, getPrefetchResponse, normalizePath, } = require('./handlerUtils');
|
|
14
|
+
const { NetlifyNextServer } = require('./server');
|
|
14
15
|
// We return a function and then call `toString()` on it to serialise it as the launcher function
|
|
15
16
|
// eslint-disable-next-line max-params, max-lines-per-function
|
|
16
17
|
const makeHandler = (conf, app, pageRoot, staticManifest = [], mode = 'ssr') => {
|
|
17
18
|
var _a;
|
|
18
19
|
// Change working directory into the site root, unless using Nx, which moves the
|
|
19
20
|
// dist directory and handles this itself
|
|
20
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
21
|
-
const { NetlifyNextServer } = require('./server');
|
|
22
21
|
const dir = path.resolve(__dirname, app);
|
|
23
22
|
if (pageRoot.startsWith(dir)) {
|
|
24
23
|
process.chdir(dir);
|
|
@@ -146,6 +145,7 @@ const getHandler = ({ isODB = false, publishDir = '../../../.next', appDir = '..
|
|
|
146
145
|
// We copy the file here rather than requiring from the node module
|
|
147
146
|
const { Bridge } = require("./bridge");
|
|
148
147
|
const { augmentFsModule, getMaxAge, getMultiValueHeaders, getPrefetchResponse, getNextServer, normalizePath } = require('./handlerUtils')
|
|
148
|
+
const { NetlifyNextServer } = require('./server')
|
|
149
149
|
|
|
150
150
|
${isODB ? `const { builder } = require("@netlify/functions")` : ''}
|
|
151
151
|
const { config } = require("${publishDir}/required-server-files.json")
|
|
@@ -91,7 +91,7 @@ const augmentFsModule = ({ promises, staticManifest, pageRoot, getBase, }) => {
|
|
|
91
91
|
// Grab the real fs.promises.readFile...
|
|
92
92
|
const readfileOrig = promises.readFile;
|
|
93
93
|
const statsOrig = promises.stat;
|
|
94
|
-
// ...then
|
|
94
|
+
// ...then monkey-patch it to see if it's requesting a CDN file
|
|
95
95
|
promises.readFile = (async (file, options) => {
|
|
96
96
|
const baseUrl = getBase();
|
|
97
97
|
// We only care about page files
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/plugin-nextjs",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.35.0",
|
|
4
4
|
"description": "Run Next.js seamlessly on Netlify",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@netlify/esbuild": "0.14.39",
|
|
15
15
|
"@netlify/functions": "^1.4.0",
|
|
16
|
-
"@netlify/ipx": "^1.
|
|
16
|
+
"@netlify/ipx": "^1.4.0",
|
|
17
17
|
"@vercel/node-bridge": "^2.1.0",
|
|
18
18
|
"chalk": "^4.1.2",
|
|
19
19
|
"chokidar": "^3.5.3",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@delucis/if-env": "^1.1.2",
|
|
40
|
-
"@netlify/build": "^29.9.
|
|
40
|
+
"@netlify/build": "^29.9.2",
|
|
41
41
|
"@types/fs-extra": "^9.0.13",
|
|
42
42
|
"@types/jest": "^27.4.1",
|
|
43
43
|
"@types/merge-stream": "^1.1.2",
|
|
@@ -1,73 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Context } from 'https://edge.netlify.com'
|
|
3
|
-
// Available at build time
|
|
4
|
-
import imageconfig from './imageconfig.json' assert { type: 'json' }
|
|
5
|
-
|
|
6
|
-
const defaultFormat = 'webp'
|
|
7
|
-
|
|
8
|
-
interface ImageConfig extends Record<string, unknown> {
|
|
9
|
-
formats?: string[]
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// Checks if a URL param is numeric
|
|
13
|
-
const isNumeric = (value: string | null) => Number(value).toString() === value
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Implement content negotiation for images
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
// deno-lint-ignore require-await
|
|
20
|
-
const handler = async (req: Request, context: Context) => {
|
|
21
|
-
const { searchParams } = new URL(req.url)
|
|
22
|
-
const accept = new Accepts(req.headers)
|
|
23
|
-
const { formats = [defaultFormat] } = imageconfig as ImageConfig
|
|
24
|
-
if (formats.length === 0) {
|
|
25
|
-
formats.push(defaultFormat)
|
|
26
|
-
}
|
|
27
|
-
let type = accept.types(formats) || defaultFormat
|
|
28
|
-
if (Array.isArray(type)) {
|
|
29
|
-
type = type[0]
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const source = searchParams.get('url')
|
|
33
|
-
const width = searchParams.get('w')
|
|
34
|
-
const quality = searchParams.get('q') ?? '75'
|
|
1
|
+
import { getHandler } from 'https://ipx-edge-function-layer.netlify.app/mod.ts'
|
|
35
2
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (!source) {
|
|
39
|
-
errors.push('Missing "url" parameter')
|
|
40
|
-
} else if (!source.startsWith('http') && !source.startsWith('/')) {
|
|
41
|
-
errors.push('The "url" parameter must be a valid URL or path')
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (!width) {
|
|
45
|
-
errors.push('Missing "w" parameter')
|
|
46
|
-
} else if (!isNumeric(width)) {
|
|
47
|
-
errors.push('Invalid "w" parameter')
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (!isNumeric(quality)) {
|
|
51
|
-
errors.push('Invalid "q" parameter')
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (!source || errors.length > 0) {
|
|
55
|
-
return new Response(`Invalid request: \n${errors.join('\n')}`, {
|
|
56
|
-
status: 400,
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const modifiers = [`w_${width}`, `q_${quality}`]
|
|
61
|
-
|
|
62
|
-
if (type) {
|
|
63
|
-
if (type.includes('/')) {
|
|
64
|
-
// If this is a mimetype, strip "image/"
|
|
65
|
-
type = type.split('/')[1]
|
|
66
|
-
}
|
|
67
|
-
modifiers.push(`f_${type}`)
|
|
68
|
-
}
|
|
69
|
-
const target = `/_ipx/${modifiers.join(',')}/${encodeURIComponent(source)}`
|
|
70
|
-
return context.rewrite(target)
|
|
71
|
-
}
|
|
3
|
+
import imageconfig from './imageconfig.json' assert { type: 'json' }
|
|
72
4
|
|
|
73
|
-
export default
|
|
5
|
+
export default getHandler({ formats: imageconfig?.formats })
|
|
@@ -44,7 +44,7 @@ export const getRscDataRouter = ({ routes: staticRoutes, dynamicRoutes }: Preren
|
|
|
44
44
|
)
|
|
45
45
|
|
|
46
46
|
const dynamicRouteMatcher = Object.values(dynamicRoutes)
|
|
47
|
-
.filter(({ dataRoute }) => dataRoute
|
|
47
|
+
.filter(({ dataRoute }) => dataRoute?.endsWith('.rsc'))
|
|
48
48
|
.map(({ routeRegex }) => new RegExp(routeRegex))
|
|
49
49
|
|
|
50
50
|
const matchesDynamicRscDataRoute = (pathname: string) => {
|