@netlify/plugin-nextjs 4.29.3-appdir.0 → 4.29.4
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/config.js +0 -1
- package/lib/helpers/edge.js +8 -5
- package/lib/helpers/files.js +18 -15
- package/lib/helpers/functions.js +4 -2
- package/lib/helpers/redirects.js +7 -3
- package/lib/helpers/utils.js +17 -5
- package/lib/helpers/verification.js +0 -2
- package/lib/index.js +0 -2
- package/lib/templates/getHandler.js +10 -3
- package/lib/templates/handlerUtils.js +22 -4
- package/package.json +4 -4
- package/src/templates/edge/next-dev.js +11 -0
package/lib/helpers/config.js
CHANGED
package/lib/helpers/edge.js
CHANGED
|
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.writeEdgeFunctions = exports.writeDevEdgeFunction = exports.cleanupEdgeFunctions = exports.loadAppPathRoutesManifest = exports.loadMiddlewareManifest = void 0;
|
|
7
|
-
/* eslint-disable max-lines */
|
|
8
7
|
const fs_1 = require("fs");
|
|
9
8
|
const path_1 = require("path");
|
|
10
9
|
const chalk_1 = require("chalk");
|
|
@@ -37,8 +36,6 @@ import {
|
|
|
37
36
|
delete globalThis.window
|
|
38
37
|
globalThis.process = { env: {...Deno.env.toObject(), NEXT_RUNTIME: 'edge', 'NEXT_PRIVATE_MINIMAL_MODE': '1' } }
|
|
39
38
|
globalThis.EdgeRuntime = "netlify-edge"
|
|
40
|
-
// Next uses "self" as a function-scoped global-like object
|
|
41
|
-
const self = {}
|
|
42
39
|
let _ENTRIES = {}
|
|
43
40
|
|
|
44
41
|
// Next.js uses this extension to the Headers API implemented by Cloudflare workerd
|
|
@@ -70,6 +67,10 @@ const fetch = async (url, init) => {
|
|
|
70
67
|
}
|
|
71
68
|
}
|
|
72
69
|
|
|
70
|
+
// Next edge runtime uses "self" as a function-scoped global-like object, but some of the older polyfills expect it to equal globalThis
|
|
71
|
+
// See https://nextjs.org/docs/basic-features/supported-browsers-features#polyfills
|
|
72
|
+
const self = { ...globalThis, fetch }
|
|
73
|
+
|
|
73
74
|
`;
|
|
74
75
|
// Slightly different spacing in different versions!
|
|
75
76
|
const IMPORT_UNSUPPORTED = [
|
|
@@ -178,6 +179,7 @@ exports.writeDevEdgeFunction = writeDevEdgeFunction;
|
|
|
178
179
|
* Writes Edge Functions for the Next middleware
|
|
179
180
|
*/
|
|
180
181
|
const writeEdgeFunctions = async ({ netlifyConfig, routesManifest, }) => {
|
|
182
|
+
var _a;
|
|
181
183
|
const manifest = {
|
|
182
184
|
functions: [],
|
|
183
185
|
version: 1,
|
|
@@ -187,6 +189,7 @@ const writeEdgeFunctions = async ({ netlifyConfig, routesManifest, }) => {
|
|
|
187
189
|
const { publish } = netlifyConfig.build;
|
|
188
190
|
const nextConfigFile = await (0, config_1.getRequiredServerFiles)(publish);
|
|
189
191
|
const nextConfig = nextConfigFile.config;
|
|
192
|
+
const usesAppDir = (_a = nextConfig.experimental) === null || _a === void 0 ? void 0 : _a.appDir;
|
|
190
193
|
await (0, fs_extra_1.copy)(getEdgeTemplatePath('../edge-shared'), (0, path_1.join)(edgeFunctionRoot, 'edge-shared'));
|
|
191
194
|
await (0, fs_extra_1.writeJSON)((0, path_1.join)(edgeFunctionRoot, 'edge-shared', 'nextConfig.json'), nextConfig);
|
|
192
195
|
if (!(0, destr_1.default)(process.env.NEXT_DISABLE_EDGE_IMAGES) &&
|
|
@@ -239,7 +242,8 @@ const writeEdgeFunctions = async ({ netlifyConfig, routesManifest, }) => {
|
|
|
239
242
|
pageRegexMap,
|
|
240
243
|
appPathRoutesManifest,
|
|
241
244
|
nextConfig,
|
|
242
|
-
cache:
|
|
245
|
+
// cache: "manual" is currently experimental, so we restrict it to sites that use experimental appDir
|
|
246
|
+
cache: usesAppDir ? 'manual' : undefined,
|
|
243
247
|
});
|
|
244
248
|
manifest.functions.push(...functionDefinitions);
|
|
245
249
|
}
|
|
@@ -254,4 +258,3 @@ const writeEdgeFunctions = async ({ netlifyConfig, routesManifest, }) => {
|
|
|
254
258
|
await (0, fs_extra_1.writeJson)((0, path_1.join)(edgeFunctionRoot, 'manifest.json'), manifest);
|
|
255
259
|
};
|
|
256
260
|
exports.writeEdgeFunctions = writeEdgeFunctions;
|
|
257
|
-
/* eslint-enable max-lines */
|
package/lib/helpers/files.js
CHANGED
|
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.movePublicFiles = exports.unpatchNextFiles = exports.unpatchFile = exports.patchNextFiles = exports.getDependenciesOfFile = exports.getSourceFileForPage = exports.moveStaticPages = exports.getMiddleware = exports.matchesRewrite = exports.matchesRedirect = exports.matchMiddleware = exports.stripLocale = exports.isDynamicRoute = void 0;
|
|
7
|
-
/* eslint-disable max-lines */
|
|
8
7
|
const os_1 = require("os");
|
|
9
8
|
const chalk_1 = require("chalk");
|
|
10
9
|
const fs_extra_1 = require("fs-extra");
|
|
@@ -123,29 +122,32 @@ const moveStaticPages = async ({ netlifyConfig, target, i18n, basePath, }) => {
|
|
|
123
122
|
// Limit concurrent file moves to number of cpus or 2 if there is only 1
|
|
124
123
|
const limit = (0, p_limit_1.default)(Math.max(2, (0, os_1.cpus)().length));
|
|
125
124
|
const promises = pages.map((rawPath) => {
|
|
125
|
+
// Convert to POSIX path
|
|
126
126
|
const filePath = (0, slash_1.default)(rawPath);
|
|
127
|
+
// Remove the initial 'app' or 'pages' directory from the output path
|
|
128
|
+
const pagePath = filePath.split('/').slice(1).join('/');
|
|
127
129
|
// Don't move ISR files, as they're used for the first request
|
|
128
|
-
if (isrFiles.has(
|
|
130
|
+
if (isrFiles.has(pagePath)) {
|
|
129
131
|
return;
|
|
130
132
|
}
|
|
131
|
-
if ((0, exports.isDynamicRoute)(
|
|
133
|
+
if ((0, exports.isDynamicRoute)(pagePath)) {
|
|
132
134
|
return;
|
|
133
135
|
}
|
|
134
|
-
if ((0, exports.matchesRedirect)(
|
|
135
|
-
matchedRedirects.add(
|
|
136
|
+
if ((0, exports.matchesRedirect)(pagePath, redirects)) {
|
|
137
|
+
matchedRedirects.add(pagePath);
|
|
136
138
|
return;
|
|
137
139
|
}
|
|
138
|
-
if ((0, exports.matchesRewrite)(
|
|
139
|
-
matchedRewrites.add(
|
|
140
|
+
if ((0, exports.matchesRewrite)(pagePath, rewrites)) {
|
|
141
|
+
matchedRewrites.add(pagePath);
|
|
140
142
|
return;
|
|
141
143
|
}
|
|
142
144
|
// Middleware matches against the unlocalised path
|
|
143
|
-
const unlocalizedPath = (0, exports.stripLocale)(
|
|
145
|
+
const unlocalizedPath = (0, exports.stripLocale)(pagePath, i18n === null || i18n === void 0 ? void 0 : i18n.locales);
|
|
144
146
|
const middlewarePath = (0, exports.matchMiddleware)(middleware, unlocalizedPath);
|
|
145
147
|
// If a file matches middleware it can't be offloaded to the CDN, and needs to stay at the origin to be served by next/server
|
|
146
148
|
if (middlewarePath) {
|
|
147
149
|
matchingMiddleware.add(middlewarePath);
|
|
148
|
-
matchedPages.add(
|
|
150
|
+
matchedPages.add(filePath);
|
|
149
151
|
return;
|
|
150
152
|
}
|
|
151
153
|
return limit(moveFile, filePath);
|
|
@@ -276,11 +278,13 @@ const getServerFile = (root, includeBase = true) => {
|
|
|
276
278
|
/**
|
|
277
279
|
* Find the source file for a given page route
|
|
278
280
|
*/
|
|
279
|
-
const getSourceFileForPage = (page,
|
|
280
|
-
for (const
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
281
|
+
const getSourceFileForPage = (page, roots) => {
|
|
282
|
+
for (const root of roots) {
|
|
283
|
+
for (const extension of SOURCE_FILE_EXTENSIONS) {
|
|
284
|
+
const file = (0, pathe_1.join)(root, `${page}.${extension}`);
|
|
285
|
+
if ((0, fs_extra_1.existsSync)(file)) {
|
|
286
|
+
return file;
|
|
287
|
+
}
|
|
284
288
|
}
|
|
285
289
|
}
|
|
286
290
|
console.log('Could not find source file for page', page);
|
|
@@ -373,4 +377,3 @@ const movePublicFiles = async ({ appDir, outdir, publish, }) => {
|
|
|
373
377
|
}
|
|
374
378
|
};
|
|
375
379
|
exports.movePublicFiles = movePublicFiles;
|
|
376
|
-
/* eslint-enable max-lines */
|
package/lib/helpers/functions.js
CHANGED
|
@@ -126,9 +126,12 @@ exports.setupImageFunction = setupImageFunction;
|
|
|
126
126
|
const getApiRouteConfigs = async (publish, baseDir) => {
|
|
127
127
|
const pages = await (0, fs_extra_1.readJSON)((0, pathe_1.join)(publish, 'server', 'pages-manifest.json'));
|
|
128
128
|
const apiRoutes = Object.keys(pages).filter((page) => page.startsWith('/api/'));
|
|
129
|
+
// two possible places
|
|
130
|
+
// Ref: https://nextjs.org/docs/advanced-features/src-directory
|
|
129
131
|
const pagesDir = (0, pathe_1.join)(baseDir, 'pages');
|
|
132
|
+
const srcPagesDir = (0, pathe_1.join)(baseDir, 'src', 'pages');
|
|
130
133
|
return await Promise.all(apiRoutes.map(async (apiRoute) => {
|
|
131
|
-
const filePath = (0, files_1.getSourceFileForPage)(apiRoute, pagesDir);
|
|
134
|
+
const filePath = (0, files_1.getSourceFileForPage)(apiRoute, [pagesDir, srcPagesDir]);
|
|
132
135
|
return { route: apiRoute, config: await (0, analysis_1.extractConfigFromFile)(filePath), compiled: pages[apiRoute] };
|
|
133
136
|
}));
|
|
134
137
|
};
|
|
@@ -167,4 +170,3 @@ const warnOnApiRoutes = async ({ FUNCTIONS_DIST, }) => {
|
|
|
167
170
|
}
|
|
168
171
|
};
|
|
169
172
|
exports.warnOnApiRoutes = warnOnApiRoutes;
|
|
170
|
-
/* eslint-enable max-lines */
|
package/lib/helpers/redirects.js
CHANGED
|
@@ -127,7 +127,7 @@ const generateStaticIsrRewrites = ({ staticRouteEntries, basePath, i18n, buildId
|
|
|
127
127
|
/**
|
|
128
128
|
* Generate rewrites for all dynamic routes
|
|
129
129
|
*/
|
|
130
|
-
const generateDynamicRewrites = ({ dynamicRoutes, prerenderedDynamicRoutes, middleware, basePath, buildId, i18n, }) => {
|
|
130
|
+
const generateDynamicRewrites = ({ dynamicRoutes, prerenderedDynamicRoutes, middleware, basePath, buildId, i18n, is404Isr, }) => {
|
|
131
131
|
const dynamicRewrites = [];
|
|
132
132
|
const dynamicRoutesThatMatchMiddleware = [];
|
|
133
133
|
dynamicRoutes.forEach((route) => {
|
|
@@ -138,8 +138,11 @@ const generateDynamicRewrites = ({ dynamicRoutes, prerenderedDynamicRoutes, midd
|
|
|
138
138
|
if (matchesMiddleware(middleware, route.page)) {
|
|
139
139
|
dynamicRoutesThatMatchMiddleware.push(route.page);
|
|
140
140
|
}
|
|
141
|
+
else if (prerenderedDynamicRoutes[route.page].fallback === false && !is404Isr) {
|
|
142
|
+
dynamicRewrites.push(...(0, utils_1.redirectsForNext404Route)({ route: route.page, buildId, basePath, i18n }));
|
|
143
|
+
}
|
|
141
144
|
else {
|
|
142
|
-
dynamicRewrites.push(...(0, utils_1.redirectsForNextRoute)({
|
|
145
|
+
dynamicRewrites.push(...(0, utils_1.redirectsForNextRoute)({ route: route.page, buildId, basePath, to: constants_1.ODB_FUNCTION_PATH, i18n }));
|
|
143
146
|
}
|
|
144
147
|
}
|
|
145
148
|
else {
|
|
@@ -168,6 +171,7 @@ const generateRedirects = async ({ netlifyConfig, nextConfig: { i18n, basePath,
|
|
|
168
171
|
const middleware = await (0, files_1.getMiddleware)(netlifyConfig.build.publish);
|
|
169
172
|
netlifyConfig.redirects.push(...generateMiddlewareRewrites({ basePath, i18n, middleware, buildId }));
|
|
170
173
|
const staticRouteEntries = Object.entries(prerenderedStaticRoutes);
|
|
174
|
+
const is404Isr = staticRouteEntries.some(([route, { initialRevalidateSeconds }]) => (0, utils_1.is404Route)(route, i18n) && initialRevalidateSeconds !== false);
|
|
171
175
|
const routesThatMatchMiddleware = [];
|
|
172
176
|
const { staticRoutePaths, staticIsrRewrites, staticIsrRoutesThatMatchMiddleware } = generateStaticIsrRewrites({
|
|
173
177
|
staticRouteEntries,
|
|
@@ -194,6 +198,7 @@ const generateRedirects = async ({ netlifyConfig, nextConfig: { i18n, basePath,
|
|
|
194
198
|
basePath,
|
|
195
199
|
buildId,
|
|
196
200
|
i18n,
|
|
201
|
+
is404Isr,
|
|
197
202
|
});
|
|
198
203
|
netlifyConfig.redirects.push(...dynamicRewrites);
|
|
199
204
|
routesThatMatchMiddleware.push(...dynamicRoutesThatMatchMiddleware);
|
|
@@ -214,4 +219,3 @@ const generateRedirects = async ({ netlifyConfig, nextConfig: { i18n, basePath,
|
|
|
214
219
|
}
|
|
215
220
|
};
|
|
216
221
|
exports.generateRedirects = generateRedirects;
|
|
217
|
-
/* eslint-enable max-lines */
|
package/lib/helpers/utils.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.getRemotePatterns = exports.isBundleSizeCheckDisabled = exports.getCustomImageResponseHeaders = exports.isNextAuthInstalled = exports.findModuleFromBase = exports.shouldSkip = exports.getPreviewRewrites = exports.getApiRewrites = exports.redirectsForNextRouteWithData = exports.redirectsForNextRoute = exports.is404Route = exports.isApiRoute = exports.routeToDataRoute = exports.netlifyRoutesForNextRouteWithData = exports.toNetlifyRoute = exports.getFunctionNameForPage = void 0;
|
|
6
|
+
exports.getRemotePatterns = exports.isBundleSizeCheckDisabled = exports.getCustomImageResponseHeaders = exports.isNextAuthInstalled = exports.findModuleFromBase = exports.shouldSkip = exports.getPreviewRewrites = exports.getApiRewrites = exports.redirectsForNextRouteWithData = exports.redirectsForNext404Route = exports.redirectsForNextRoute = exports.is404Route = exports.isApiRoute = exports.routeToDataRoute = exports.netlifyRoutesForNextRouteWithData = exports.toNetlifyRoute = exports.getFunctionNameForPage = void 0;
|
|
7
7
|
const globby_1 = __importDefault(require("globby"));
|
|
8
8
|
const pathe_1 = require("pathe");
|
|
9
9
|
const constants_1 = require("../constants");
|
|
@@ -57,7 +57,10 @@ exports.routeToDataRoute = routeToDataRoute;
|
|
|
57
57
|
const netlifyRoutesForNextRoute = (route, buildId, i18n) => {
|
|
58
58
|
var _a;
|
|
59
59
|
if (!((_a = i18n === null || i18n === void 0 ? void 0 : i18n.locales) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
60
|
-
return (0, exports.netlifyRoutesForNextRouteWithData)({ route, dataRoute: (0, exports.routeToDataRoute)(route, buildId) })
|
|
60
|
+
return (0, exports.netlifyRoutesForNextRouteWithData)({ route, dataRoute: (0, exports.routeToDataRoute)(route, buildId) }).map((redirect) => ({
|
|
61
|
+
redirect,
|
|
62
|
+
locale: false,
|
|
63
|
+
}));
|
|
61
64
|
}
|
|
62
65
|
const { locales, defaultLocale } = i18n;
|
|
63
66
|
const routes = [];
|
|
@@ -69,7 +72,10 @@ const netlifyRoutesForNextRoute = (route, buildId, i18n) => {
|
|
|
69
72
|
...(0, exports.netlifyRoutesForNextRouteWithData)({
|
|
70
73
|
route: locale === defaultLocale ? route : `/${locale}${route}`,
|
|
71
74
|
dataRoute,
|
|
72
|
-
}))
|
|
75
|
+
}).map((redirect) => ({
|
|
76
|
+
redirect,
|
|
77
|
+
locale,
|
|
78
|
+
})));
|
|
73
79
|
});
|
|
74
80
|
return routes;
|
|
75
81
|
};
|
|
@@ -77,13 +83,20 @@ const isApiRoute = (route) => route.startsWith('/api/') || route === '/api';
|
|
|
77
83
|
exports.isApiRoute = isApiRoute;
|
|
78
84
|
const is404Route = (route, i18n) => i18n ? i18n.locales.some((locale) => route === `/${locale}/404`) : route === '/404';
|
|
79
85
|
exports.is404Route = is404Route;
|
|
80
|
-
const redirectsForNextRoute = ({ route, buildId, basePath, to, i18n, status = 200, force = false, }) => netlifyRoutesForNextRoute(route, buildId, i18n).map((redirect) => ({
|
|
86
|
+
const redirectsForNextRoute = ({ route, buildId, basePath, to, i18n, status = 200, force = false, }) => netlifyRoutesForNextRoute(route, buildId, i18n).map(({ redirect }) => ({
|
|
81
87
|
from: `${basePath}${redirect}`,
|
|
82
88
|
to,
|
|
83
89
|
status,
|
|
84
90
|
force,
|
|
85
91
|
}));
|
|
86
92
|
exports.redirectsForNextRoute = redirectsForNextRoute;
|
|
93
|
+
const redirectsForNext404Route = ({ route, buildId, basePath, i18n, force = false, }) => netlifyRoutesForNextRoute(route, buildId, i18n).map(({ redirect, locale }) => ({
|
|
94
|
+
from: `${basePath}${redirect}`,
|
|
95
|
+
to: locale ? `${basePath}/server/pages/${locale}/404.html` : `${basePath}/server/pages/404.html`,
|
|
96
|
+
status: 404,
|
|
97
|
+
force,
|
|
98
|
+
}));
|
|
99
|
+
exports.redirectsForNext404Route = redirectsForNext404Route;
|
|
87
100
|
const redirectsForNextRouteWithData = ({ route, dataRoute, basePath, to, status = 200, force = false, }) => (0, exports.netlifyRoutesForNextRouteWithData)({ route, dataRoute }).map((redirect) => ({
|
|
88
101
|
from: `${basePath}${redirect}`,
|
|
89
102
|
to,
|
|
@@ -193,4 +206,3 @@ const getRemotePatterns = (experimental, images) => {
|
|
|
193
206
|
return [];
|
|
194
207
|
};
|
|
195
208
|
exports.getRemotePatterns = getRemotePatterns;
|
|
196
|
-
/* eslint-enable max-lines */
|
|
@@ -27,7 +27,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.warnForRootRedirects = exports.warnForProblematicUserRewrites = exports.getProblematicUserRewrites = exports.checkZipSize = exports.checkForRootPublish = exports.checkNextSiteHasBuilt = exports.checkForOldFunctions = exports.verifyNetlifyBuildVersion = void 0;
|
|
30
|
-
/* eslint-disable max-lines */
|
|
31
30
|
const fs_1 = require("fs");
|
|
32
31
|
const path_1 = __importStar(require("path"));
|
|
33
32
|
const chalk_1 = require("chalk");
|
|
@@ -180,4 +179,3 @@ const warnForRootRedirects = ({ appDir }) => {
|
|
|
180
179
|
}
|
|
181
180
|
};
|
|
182
181
|
exports.warnForRootRedirects = warnForRootRedirects;
|
|
183
|
-
/* eslint-enable max-lines */
|
package/lib/index.js
CHANGED
|
@@ -3,7 +3,6 @@ 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
|
-
/* eslint-disable max-lines */
|
|
7
6
|
const path_1 = require("path");
|
|
8
7
|
const chalk_1 = require("chalk");
|
|
9
8
|
const destr_1 = __importDefault(require("destr"));
|
|
@@ -164,4 +163,3 @@ const nextRuntime = (_inputs, meta = {}) => {
|
|
|
164
163
|
};
|
|
165
164
|
};
|
|
166
165
|
module.exports = nextRuntime;
|
|
167
|
-
/* eslint-enable max-lines */
|
|
@@ -10,7 +10,7 @@ const path = require('path');
|
|
|
10
10
|
// eslint-disable-next-line n/prefer-global/url, n/prefer-global/url-search-params
|
|
11
11
|
const { URLSearchParams, URL } = require('url');
|
|
12
12
|
const { Bridge } = require('@vercel/node-bridge/bridge');
|
|
13
|
-
const { augmentFsModule, getMaxAge, getMultiValueHeaders, getNextServer } = require('./handlerUtils');
|
|
13
|
+
const { augmentFsModule, getMaxAge, getMultiValueHeaders, getPrefetchResponse, getNextServer, } = require('./handlerUtils');
|
|
14
14
|
// We return a function and then call `toString()` on it to serialise it as the launcher function
|
|
15
15
|
// eslint-disable-next-line max-params
|
|
16
16
|
const makeHandler = (conf, app, pageRoot, staticManifest = [], mode = 'ssr') => {
|
|
@@ -37,7 +37,9 @@ const makeHandler = (conf, app, pageRoot, staticManifest = [], mode = 'ssr') =>
|
|
|
37
37
|
for (const [key, value] of Object.entries(conf.env)) {
|
|
38
38
|
process.env[key] = String(value);
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
// Set during the request as it needs to get it from the request URL. Defaults to the URL env var
|
|
41
|
+
let base = process.env.URL;
|
|
42
|
+
augmentFsModule({ promises, staticManifest, pageRoot, getBase: () => base });
|
|
41
43
|
// We memoize this because it can be shared between requests, but don't instantiate it until
|
|
42
44
|
// the first request because we need the host and port.
|
|
43
45
|
let bridge;
|
|
@@ -47,6 +49,7 @@ const makeHandler = (conf, app, pageRoot, staticManifest = [], mode = 'ssr') =>
|
|
|
47
49
|
}
|
|
48
50
|
const url = new URL(event.rawUrl);
|
|
49
51
|
const port = Number.parseInt(url.port) || 80;
|
|
52
|
+
base = url.origin;
|
|
50
53
|
const NextServer = getNextServer();
|
|
51
54
|
const nextServer = new NextServer({
|
|
52
55
|
conf,
|
|
@@ -72,6 +75,10 @@ const makeHandler = (conf, app, pageRoot, staticManifest = [], mode = 'ssr') =>
|
|
|
72
75
|
return async function handler(event, context) {
|
|
73
76
|
var _a, _b, _c;
|
|
74
77
|
let requestMode = mode;
|
|
78
|
+
const prefetchResponse = getPrefetchResponse(event, mode);
|
|
79
|
+
if (prefetchResponse) {
|
|
80
|
+
return prefetchResponse;
|
|
81
|
+
}
|
|
75
82
|
// Ensure that paths are encoded - but don't double-encode them
|
|
76
83
|
event.path = new URL(event.rawUrl).pathname;
|
|
77
84
|
// Next expects to be able to parse the query from the URL
|
|
@@ -135,7 +142,7 @@ const getHandler = ({ isODB = false, publishDir = '../../../.next', appDir = '..
|
|
|
135
142
|
const { promises } = require("fs");
|
|
136
143
|
// We copy the file here rather than requiring from the node module
|
|
137
144
|
const { Bridge } = require("./bridge");
|
|
138
|
-
const { augmentFsModule, getMaxAge, getMultiValueHeaders, getNextServer } = require('./handlerUtils')
|
|
145
|
+
const { augmentFsModule, getMaxAge, getMultiValueHeaders, getPrefetchResponse, getNextServer } = require('./handlerUtils')
|
|
139
146
|
|
|
140
147
|
${isODB ? `const { builder } = require("@netlify/functions")` : ''}
|
|
141
148
|
const { config } = require("${publishDir}/required-server-files.json")
|
|
@@ -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.getNextServer = exports.augmentFsModule = exports.getMultiValueHeaders = exports.getMaxAge = exports.downloadFile = void 0;
|
|
6
|
+
exports.getPrefetchResponse = exports.getNextServer = exports.augmentFsModule = exports.getMultiValueHeaders = exports.getMaxAge = exports.downloadFile = void 0;
|
|
7
7
|
const fs_1 = require("fs");
|
|
8
8
|
const os_1 = require("os");
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
@@ -75,7 +75,7 @@ exports.getMultiValueHeaders = getMultiValueHeaders;
|
|
|
75
75
|
/**
|
|
76
76
|
* Monkey-patch the fs module to download missing files from the CDN
|
|
77
77
|
*/
|
|
78
|
-
const augmentFsModule = ({ promises, staticManifest, pageRoot, }) => {
|
|
78
|
+
const augmentFsModule = ({ promises, staticManifest, pageRoot, getBase, }) => {
|
|
79
79
|
// Only do this if we have some static files moved to the CDN
|
|
80
80
|
if (staticManifest.length === 0) {
|
|
81
81
|
return;
|
|
@@ -93,8 +93,7 @@ const augmentFsModule = ({ promises, staticManifest, pageRoot, }) => {
|
|
|
93
93
|
const statsOrig = promises.stat;
|
|
94
94
|
// ...then money-patch it to see if it's requesting a CDN file
|
|
95
95
|
promises.readFile = (async (file, options) => {
|
|
96
|
-
|
|
97
|
-
const baseUrl = process.env.CONTEXT === 'production' ? process.env.URL : process.env.DEPLOY_PRIME_URL;
|
|
96
|
+
const baseUrl = getBase();
|
|
98
97
|
// We only care about page files
|
|
99
98
|
if (file.startsWith(pageRoot)) {
|
|
100
99
|
// We only want the part after `.next/server/`
|
|
@@ -173,3 +172,22 @@ const getNextServer = () => {
|
|
|
173
172
|
return NextServer;
|
|
174
173
|
};
|
|
175
174
|
exports.getNextServer = getNextServer;
|
|
175
|
+
/**
|
|
176
|
+
* Prefetch requests are used to check for middleware redirects, and shouldn't trigger SSR.
|
|
177
|
+
*/
|
|
178
|
+
const getPrefetchResponse = (event, mode) => {
|
|
179
|
+
if (event.headers['x-middleware-prefetch'] && mode === 'ssr') {
|
|
180
|
+
return {
|
|
181
|
+
statusCode: 200,
|
|
182
|
+
body: '{}',
|
|
183
|
+
headers: {
|
|
184
|
+
'Content-Type': 'application/json',
|
|
185
|
+
'x-middleware-skip': '1',
|
|
186
|
+
// https://github.com/vercel/next.js/pull/42936/files#r1027563953
|
|
187
|
+
vary: 'x-middleware-prefetch',
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
return false;
|
|
192
|
+
};
|
|
193
|
+
exports.getPrefetchResponse = getPrefetchResponse;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/plugin-nextjs",
|
|
3
|
-
"version": "4.29.
|
|
3
|
+
"version": "4.29.4",
|
|
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.3.0",
|
|
16
|
-
"@netlify/ipx": "^1.3.
|
|
16
|
+
"@netlify/ipx": "^1.3.2",
|
|
17
17
|
"@vercel/node-bridge": "^2.1.0",
|
|
18
18
|
"chalk": "^4.1.2",
|
|
19
19
|
"destr": "^1.1.1",
|
|
@@ -36,12 +36,12 @@
|
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@delucis/if-env": "^1.1.2",
|
|
39
|
-
"@netlify/build": "^
|
|
39
|
+
"@netlify/build": "^29.1.3",
|
|
40
40
|
"@types/fs-extra": "^9.0.13",
|
|
41
41
|
"@types/jest": "^27.4.1",
|
|
42
42
|
"@types/merge-stream": "^1.1.2",
|
|
43
43
|
"@types/node": "^17.0.25",
|
|
44
|
-
"next": "^13.0.
|
|
44
|
+
"next": "^13.0.6",
|
|
45
45
|
"npm-run-all": "^4.1.5",
|
|
46
46
|
"typescript": "^4.6.3"
|
|
47
47
|
},
|
|
@@ -6,6 +6,17 @@ import { buildResponse } from '../edge-shared/utils.ts'
|
|
|
6
6
|
globalThis.NFRequestContextMap ||= new Map()
|
|
7
7
|
globalThis.__dirname = fromFileUrl(new URL('./', import.meta.url)).slice(0, -1)
|
|
8
8
|
|
|
9
|
+
// Next.js uses this extension to the Headers API implemented by Cloudflare workerd
|
|
10
|
+
if (!('getAll' in Headers.prototype)) {
|
|
11
|
+
Headers.prototype.getAll = function getAll(name) {
|
|
12
|
+
name = name.toLowerCase()
|
|
13
|
+
if (name !== 'set-cookie') {
|
|
14
|
+
throw new Error('Headers.getAll is only supported for Set-Cookie')
|
|
15
|
+
}
|
|
16
|
+
return [...this.entries()].filter(([key]) => key === name).map(([, value]) => value)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
9
20
|
// Check if a file exists, given a relative path
|
|
10
21
|
const exists = async (relativePath) => {
|
|
11
22
|
const path = fromFileUrl(new URL(relativePath, import.meta.url))
|