@netlify/plugin-nextjs 4.2.2 → 4.2.6
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/files.js +57 -42
- package/lib/helpers/redirects.js +128 -35
- package/lib/helpers/utils.js +19 -11
- package/lib/index.js +1 -1
- package/package.json +8 -4
package/lib/helpers/files.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.movePublicFiles = exports.unpatchNextFiles = exports.patchNextFiles = exports.moveStaticPages = exports.matchesRewrite = exports.matchesRedirect = exports.matchMiddleware = exports.stripLocale = exports.isDynamicRoute = void 0;
|
|
6
|
+
exports.movePublicFiles = exports.unpatchNextFiles = exports.patchNextFiles = exports.moveStaticPages = exports.getMiddleware = exports.matchesRewrite = exports.matchesRedirect = exports.matchMiddleware = exports.stripLocale = exports.isDynamicRoute = void 0;
|
|
7
7
|
/* eslint-disable max-lines */
|
|
8
8
|
const os_1 = require("os");
|
|
9
9
|
const chalk_1 = require("chalk");
|
|
@@ -14,6 +14,7 @@ const p_limit_1 = __importDefault(require("p-limit"));
|
|
|
14
14
|
const pathe_1 = require("pathe");
|
|
15
15
|
const slash_1 = __importDefault(require("slash"));
|
|
16
16
|
const constants_1 = require("../constants");
|
|
17
|
+
const utils_1 = require("./utils");
|
|
17
18
|
const TEST_ROUTE = /(|\/)\[[^/]+?](\/|\.html|$)/;
|
|
18
19
|
const isDynamicRoute = (route) => TEST_ROUTE.test(route);
|
|
19
20
|
exports.isDynamicRoute = isDynamicRoute;
|
|
@@ -51,8 +52,18 @@ const matchesRewrite = (file, rewrites) => {
|
|
|
51
52
|
return (0, exports.matchesRedirect)(file, rewrites.beforeFiles);
|
|
52
53
|
};
|
|
53
54
|
exports.matchesRewrite = matchesRewrite;
|
|
55
|
+
const getMiddleware = async (publish) => {
|
|
56
|
+
var _a;
|
|
57
|
+
const manifestPath = (0, pathe_1.join)(publish, 'server', 'middleware-manifest.json');
|
|
58
|
+
if ((0, fs_extra_1.existsSync)(manifestPath)) {
|
|
59
|
+
const manifest = await (0, fs_extra_1.readJson)(manifestPath, { throws: false });
|
|
60
|
+
return (_a = manifest === null || manifest === void 0 ? void 0 : manifest.sortedMiddleware) !== null && _a !== void 0 ? _a : [];
|
|
61
|
+
}
|
|
62
|
+
return [];
|
|
63
|
+
};
|
|
64
|
+
exports.getMiddleware = getMiddleware;
|
|
54
65
|
// eslint-disable-next-line max-lines-per-function
|
|
55
|
-
const moveStaticPages = async ({ netlifyConfig, target, i18n, }) => {
|
|
66
|
+
const moveStaticPages = async ({ netlifyConfig, target, i18n, basePath, }) => {
|
|
56
67
|
console.log('Moving static page files to serve from CDN...');
|
|
57
68
|
const outputDir = (0, pathe_1.join)(netlifyConfig.build.publish, target === 'server' ? 'server' : 'serverless');
|
|
58
69
|
const root = (0, pathe_1.join)(outputDir, 'pages');
|
|
@@ -60,14 +71,8 @@ const moveStaticPages = async ({ netlifyConfig, target, i18n, }) => {
|
|
|
60
71
|
const dataDir = (0, pathe_1.join)('_next', 'data', buildId);
|
|
61
72
|
await (0, fs_extra_1.ensureDir)(dataDir);
|
|
62
73
|
// Load the middleware manifest so we can check if a file matches it before moving
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
if ((0, fs_extra_1.existsSync)(manifestPath)) {
|
|
66
|
-
const manifest = await (0, fs_extra_1.readJson)(manifestPath);
|
|
67
|
-
if (manifest === null || manifest === void 0 ? void 0 : manifest.middleware) {
|
|
68
|
-
middleware = Object.keys(manifest.middleware).map((path) => path.slice(1));
|
|
69
|
-
}
|
|
70
|
-
}
|
|
74
|
+
const middlewarePaths = await (0, exports.getMiddleware)(netlifyConfig.build.publish);
|
|
75
|
+
const middleware = middlewarePaths.map((path) => path.slice(1));
|
|
71
76
|
const prerenderManifest = await (0, fs_extra_1.readJson)((0, pathe_1.join)(netlifyConfig.build.publish, 'prerender-manifest.json'));
|
|
72
77
|
const { redirects, rewrites } = await (0, fs_extra_1.readJson)((0, pathe_1.join)(netlifyConfig.build.publish, 'routes-manifest.json'));
|
|
73
78
|
const isrFiles = new Set();
|
|
@@ -89,9 +94,10 @@ const moveStaticPages = async ({ netlifyConfig, target, i18n, }) => {
|
|
|
89
94
|
const isData = file.endsWith('.json');
|
|
90
95
|
const source = (0, pathe_1.join)(root, file);
|
|
91
96
|
const targetFile = isData ? (0, pathe_1.join)(dataDir, file) : file;
|
|
97
|
+
const targetPath = basePath ? (0, pathe_1.join)(basePath, targetFile) : targetFile;
|
|
92
98
|
files.push(file);
|
|
93
|
-
filesManifest[file] =
|
|
94
|
-
const dest = (0, pathe_1.join)(netlifyConfig.build.publish,
|
|
99
|
+
filesManifest[file] = targetPath;
|
|
100
|
+
const dest = (0, pathe_1.join)(netlifyConfig.build.publish, targetPath);
|
|
95
101
|
try {
|
|
96
102
|
await (0, fs_extra_1.move)(source, dest);
|
|
97
103
|
}
|
|
@@ -185,19 +191,23 @@ const moveStaticPages = async ({ netlifyConfig, target, i18n, }) => {
|
|
|
185
191
|
// Write the manifest for use in the serverless functions
|
|
186
192
|
await (0, fs_extra_1.writeJson)((0, pathe_1.join)(netlifyConfig.build.publish, 'static-manifest.json'), Object.entries(filesManifest));
|
|
187
193
|
if (i18n === null || i18n === void 0 ? void 0 : i18n.defaultLocale) {
|
|
194
|
+
const rootPath = basePath ? (0, pathe_1.join)(netlifyConfig.build.publish, basePath) : netlifyConfig.build.publish;
|
|
188
195
|
// Copy the default locale into the root
|
|
189
|
-
const defaultLocaleDir = (0, pathe_1.join)(
|
|
196
|
+
const defaultLocaleDir = (0, pathe_1.join)(rootPath, i18n.defaultLocale);
|
|
190
197
|
if ((0, fs_extra_1.existsSync)(defaultLocaleDir)) {
|
|
191
|
-
await (0, fs_extra_1.copy)(defaultLocaleDir, `${
|
|
198
|
+
await (0, fs_extra_1.copy)(defaultLocaleDir, `${rootPath}/`);
|
|
192
199
|
}
|
|
193
|
-
const defaultLocaleIndex = (0, pathe_1.join)(
|
|
194
|
-
const indexHtml = (0, pathe_1.join)(
|
|
200
|
+
const defaultLocaleIndex = (0, pathe_1.join)(rootPath, `${i18n.defaultLocale}.html`);
|
|
201
|
+
const indexHtml = (0, pathe_1.join)(rootPath, 'index.html');
|
|
195
202
|
if ((0, fs_extra_1.existsSync)(defaultLocaleIndex) && !(0, fs_extra_1.existsSync)(indexHtml)) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
|
|
203
|
+
await (0, fs_extra_1.copy)(defaultLocaleIndex, indexHtml, { overwrite: false }).catch(() => {
|
|
204
|
+
/* ignore */
|
|
205
|
+
});
|
|
206
|
+
await (0, fs_extra_1.copy)((0, pathe_1.join)(rootPath, `${i18n.defaultLocale}.json`), (0, pathe_1.join)(rootPath, 'index.json'), {
|
|
207
|
+
overwrite: false,
|
|
208
|
+
}).catch(() => {
|
|
209
|
+
/* ignore */
|
|
210
|
+
});
|
|
201
211
|
}
|
|
202
212
|
}
|
|
203
213
|
if (shortRevalidateRoutes.length !== 0) {
|
|
@@ -216,47 +226,52 @@ const moveStaticPages = async ({ netlifyConfig, target, i18n, }) => {
|
|
|
216
226
|
}
|
|
217
227
|
};
|
|
218
228
|
exports.moveStaticPages = moveStaticPages;
|
|
229
|
+
/**
|
|
230
|
+
* Attempt to patch a source file, preserving a backup
|
|
231
|
+
*/
|
|
219
232
|
const patchFile = async ({ file, from, to }) => {
|
|
220
233
|
if (!(0, fs_extra_1.existsSync)(file)) {
|
|
221
|
-
|
|
234
|
+
console.warn('File was not found');
|
|
235
|
+
return false;
|
|
222
236
|
}
|
|
223
237
|
const content = await (0, fs_extra_1.readFile)(file, 'utf8');
|
|
224
238
|
if (content.includes(to)) {
|
|
225
|
-
|
|
239
|
+
console.log('File already patched');
|
|
240
|
+
return false;
|
|
226
241
|
}
|
|
227
242
|
const newContent = content.replace(from, to);
|
|
243
|
+
if (newContent === content) {
|
|
244
|
+
console.warn('File was not changed');
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
228
247
|
await (0, fs_extra_1.writeFile)(`${file}.orig`, content);
|
|
229
248
|
await (0, fs_extra_1.writeFile)(file, newContent);
|
|
249
|
+
console.log('Done');
|
|
250
|
+
return true;
|
|
230
251
|
};
|
|
252
|
+
/**
|
|
253
|
+
* The file we need has moved around a bit over the past few versions,
|
|
254
|
+
* so we iterate through the options until we find it
|
|
255
|
+
*/
|
|
231
256
|
const getServerFile = (root) => {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
if (!serverFile) {
|
|
240
|
-
try {
|
|
241
|
-
// eslint-disable-next-line node/no-missing-require
|
|
242
|
-
serverFile = require.resolve('next/dist/next-server/server/next-server', { paths: [root] });
|
|
243
|
-
}
|
|
244
|
-
catch {
|
|
245
|
-
// Ignore
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
return serverFile;
|
|
257
|
+
const candidates = [
|
|
258
|
+
'next/dist/server/base-server',
|
|
259
|
+
'next/dist/server/next-server',
|
|
260
|
+
'next/dist/next-server/server/next-server',
|
|
261
|
+
];
|
|
262
|
+
return (0, utils_1.findModuleFromBase)({ candidates, paths: [root] });
|
|
249
263
|
};
|
|
250
|
-
const patchNextFiles =
|
|
264
|
+
const patchNextFiles = (root) => {
|
|
251
265
|
const serverFile = getServerFile(root);
|
|
252
266
|
console.log(`Patching ${serverFile}`);
|
|
253
267
|
if (serverFile) {
|
|
254
|
-
|
|
268
|
+
return patchFile({
|
|
255
269
|
file: serverFile,
|
|
256
270
|
from: `let ssgCacheKey = `,
|
|
257
271
|
to: `let ssgCacheKey = process.env._BYPASS_SSG || `,
|
|
258
272
|
});
|
|
259
273
|
}
|
|
274
|
+
return false;
|
|
260
275
|
};
|
|
261
276
|
exports.patchNextFiles = patchNextFiles;
|
|
262
277
|
const unpatchNextFiles = async (root) => {
|
package/lib/helpers/redirects.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.generateRedirects = exports.generateStaticRedirects = void 0;
|
|
4
|
+
const chalk_1 = require("chalk");
|
|
4
5
|
const fs_extra_1 = require("fs-extra");
|
|
6
|
+
const outdent_1 = require("outdent");
|
|
5
7
|
const pathe_1 = require("pathe");
|
|
6
8
|
const constants_1 = require("../constants");
|
|
9
|
+
const files_1 = require("./files");
|
|
7
10
|
const utils_1 = require("./utils");
|
|
11
|
+
const matchesMiddleware = (middleware, route) => middleware.some((middlewarePath) => route.startsWith(middlewarePath));
|
|
8
12
|
const generateLocaleRedirects = ({ i18n, basePath, trailingSlash, }) => {
|
|
9
13
|
const redirects = [];
|
|
10
14
|
// If the cookie is set, we need to redirect at the origin
|
|
@@ -41,27 +45,38 @@ const generateStaticRedirects = ({ netlifyConfig, nextConfig: { i18n, basePath }
|
|
|
41
45
|
}
|
|
42
46
|
};
|
|
43
47
|
exports.generateStaticRedirects = generateStaticRedirects;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Routes that match middleware need to always use the SSR function
|
|
50
|
+
* This generates a rewrite for every middleware in every locale, both with and without a splat
|
|
51
|
+
*/
|
|
52
|
+
const generateMiddlewareRewrites = ({ basePath, middleware, i18n, buildId }) => {
|
|
53
|
+
const handlerRewrite = (from) => ({
|
|
54
|
+
from: `${basePath}${from}`,
|
|
55
|
+
to: constants_1.HANDLER_FUNCTION_PATH,
|
|
56
|
+
status: 200,
|
|
57
|
+
});
|
|
58
|
+
return (middleware
|
|
59
|
+
.map((route) => {
|
|
60
|
+
var _a;
|
|
61
|
+
const unlocalized = [handlerRewrite(`${route}`), handlerRewrite(`${route}/*`)];
|
|
62
|
+
if (((_a = i18n === null || i18n === void 0 ? void 0 : i18n.locales) === null || _a === void 0 ? void 0 : _a.length) > 0) {
|
|
63
|
+
const localized = i18n.locales.map((locale) => [
|
|
64
|
+
handlerRewrite(`/${locale}${route}`),
|
|
65
|
+
handlerRewrite(`/${locale}${route}/*`),
|
|
66
|
+
handlerRewrite(`/_next/data/${buildId}/${locale}${route}/*`),
|
|
67
|
+
]);
|
|
68
|
+
// With i18n, all data routes are prefixed with the locale, but the HTML also has the unprefixed default
|
|
69
|
+
return [...unlocalized, ...localized];
|
|
70
|
+
}
|
|
71
|
+
return [...unlocalized, handlerRewrite(`/_next/data/${buildId}${route}/*`)];
|
|
72
|
+
})
|
|
73
|
+
// Flatten the array of arrays. Can't use flatMap as it might be 2 levels deep
|
|
74
|
+
.flat(2));
|
|
75
|
+
};
|
|
76
|
+
const generateStaticIsrRewrites = ({ staticRouteEntries, basePath, i18n, buildId, middleware, }) => {
|
|
77
|
+
const staticIsrRoutesThatMatchMiddleware = [];
|
|
63
78
|
const staticRoutePaths = new Set();
|
|
64
|
-
|
|
79
|
+
const staticIsrRewrites = [];
|
|
65
80
|
staticRouteEntries.forEach(([route, { initialRevalidateSeconds }]) => {
|
|
66
81
|
if ((0, utils_1.isApiRoute)(route)) {
|
|
67
82
|
return;
|
|
@@ -75,7 +90,10 @@ const generateRedirects = async ({ netlifyConfig, nextConfig: { i18n, basePath,
|
|
|
75
90
|
if ((i18n === null || i18n === void 0 ? void 0 : i18n.defaultLocale) && route.startsWith(`/${i18n.defaultLocale}/`)) {
|
|
76
91
|
route = route.slice(i18n.defaultLocale.length + 1);
|
|
77
92
|
staticRoutePaths.add(route);
|
|
78
|
-
|
|
93
|
+
if (matchesMiddleware(middleware, route)) {
|
|
94
|
+
staticIsrRoutesThatMatchMiddleware.push(route);
|
|
95
|
+
}
|
|
96
|
+
staticIsrRewrites.push(...(0, utils_1.redirectsForNextRouteWithData)({
|
|
79
97
|
route,
|
|
80
98
|
dataRoute: (0, utils_1.routeToDataRoute)(route, buildId, i18n.defaultLocale),
|
|
81
99
|
basePath,
|
|
@@ -83,41 +101,116 @@ const generateRedirects = async ({ netlifyConfig, nextConfig: { i18n, basePath,
|
|
|
83
101
|
force: true,
|
|
84
102
|
}));
|
|
85
103
|
}
|
|
104
|
+
else if (matchesMiddleware(middleware, route)) {
|
|
105
|
+
// Routes that match middleware can't use the ODB
|
|
106
|
+
staticIsrRoutesThatMatchMiddleware.push(route);
|
|
107
|
+
}
|
|
86
108
|
else {
|
|
87
109
|
// ISR routes use the ODB handler
|
|
88
|
-
|
|
110
|
+
staticIsrRewrites.push(
|
|
89
111
|
// No i18n, because the route is already localized
|
|
90
112
|
...(0, utils_1.redirectsForNextRoute)({ route, basePath, to: constants_1.ODB_FUNCTION_PATH, force: true, buildId, i18n: null }));
|
|
91
113
|
}
|
|
92
114
|
});
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
115
|
+
return {
|
|
116
|
+
staticRoutePaths,
|
|
117
|
+
staticIsrRoutesThatMatchMiddleware,
|
|
118
|
+
staticIsrRewrites,
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Generate rewrites for all dynamic routes
|
|
123
|
+
*/
|
|
124
|
+
const generateDynamicRewrites = ({ dynamicRoutes, prerenderedDynamicRoutes, middleware, basePath, buildId, i18n, }) => {
|
|
125
|
+
const dynamicRewrites = [];
|
|
126
|
+
const dynamicRoutesThatMatchMiddleware = [];
|
|
102
127
|
dynamicRoutes.forEach((route) => {
|
|
103
128
|
if ((0, utils_1.isApiRoute)(route.page)) {
|
|
104
129
|
return;
|
|
105
130
|
}
|
|
106
131
|
if (route.page in prerenderedDynamicRoutes) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
132
|
+
if (matchesMiddleware(middleware, route.page)) {
|
|
133
|
+
dynamicRoutesThatMatchMiddleware.push(route.page);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
dynamicRewrites.push(...(0, utils_1.redirectsForNextRoute)({ buildId, route: route.page, basePath, to: constants_1.ODB_FUNCTION_PATH, status: 200, i18n }));
|
|
137
|
+
}
|
|
110
138
|
}
|
|
111
139
|
else {
|
|
112
140
|
// If the route isn't prerendered, it's SSR
|
|
113
|
-
|
|
141
|
+
dynamicRewrites.push(...(0, utils_1.redirectsForNextRoute)({ route: route.page, buildId, basePath, to: constants_1.HANDLER_FUNCTION_PATH, i18n }));
|
|
114
142
|
}
|
|
115
143
|
});
|
|
144
|
+
return {
|
|
145
|
+
dynamicRoutesThatMatchMiddleware,
|
|
146
|
+
dynamicRewrites,
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
const generateRedirects = async ({ netlifyConfig, nextConfig: { i18n, basePath, trailingSlash, appDir }, buildId, }) => {
|
|
150
|
+
const { dynamicRoutes: prerenderedDynamicRoutes, routes: prerenderedStaticRoutes } = await (0, fs_extra_1.readJSON)((0, pathe_1.join)(netlifyConfig.build.publish, 'prerender-manifest.json'));
|
|
151
|
+
const { dynamicRoutes, staticRoutes } = await (0, fs_extra_1.readJSON)((0, pathe_1.join)(netlifyConfig.build.publish, 'routes-manifest.json'));
|
|
152
|
+
netlifyConfig.redirects.push(...constants_1.HIDDEN_PATHS.map((path) => ({
|
|
153
|
+
from: `${basePath}${path}`,
|
|
154
|
+
to: '/404.html',
|
|
155
|
+
status: 404,
|
|
156
|
+
force: true,
|
|
157
|
+
})));
|
|
158
|
+
if (i18n && i18n.localeDetection !== false) {
|
|
159
|
+
netlifyConfig.redirects.push(...generateLocaleRedirects({ i18n, basePath, trailingSlash }));
|
|
160
|
+
}
|
|
161
|
+
// This is only used in prod, so dev uses `next dev` directly
|
|
162
|
+
netlifyConfig.redirects.push(
|
|
163
|
+
// API routes always need to be served from the regular function
|
|
164
|
+
...(0, utils_1.getApiRewrites)(basePath),
|
|
165
|
+
// Preview mode gets forced to the function, to bypass pre-rendered pages, but static files need to be skipped
|
|
166
|
+
...(await (0, utils_1.getPreviewRewrites)({ basePath, appDir })));
|
|
167
|
+
const middleware = await (0, files_1.getMiddleware)(netlifyConfig.build.publish);
|
|
168
|
+
netlifyConfig.redirects.push(...generateMiddlewareRewrites({ basePath, i18n, middleware, buildId }));
|
|
169
|
+
const staticRouteEntries = Object.entries(prerenderedStaticRoutes);
|
|
170
|
+
const routesThatMatchMiddleware = [];
|
|
171
|
+
const { staticRoutePaths, staticIsrRewrites, staticIsrRoutesThatMatchMiddleware } = generateStaticIsrRewrites({
|
|
172
|
+
staticRouteEntries,
|
|
173
|
+
basePath,
|
|
174
|
+
i18n,
|
|
175
|
+
buildId,
|
|
176
|
+
middleware,
|
|
177
|
+
});
|
|
178
|
+
routesThatMatchMiddleware.push(...staticIsrRoutesThatMatchMiddleware);
|
|
179
|
+
netlifyConfig.redirects.push(...staticIsrRewrites);
|
|
180
|
+
// Add rewrites for all static SSR routes. This is Next 12+
|
|
181
|
+
staticRoutes === null || staticRoutes === void 0 ? void 0 : staticRoutes.forEach((route) => {
|
|
182
|
+
if (staticRoutePaths.has(route.page) || (0, utils_1.isApiRoute)(route.page)) {
|
|
183
|
+
// Prerendered static routes are either handled by the CDN or are ISR
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
netlifyConfig.redirects.push(...(0, utils_1.redirectsForNextRoute)({ route: route.page, buildId, basePath, to: constants_1.HANDLER_FUNCTION_PATH, i18n }));
|
|
187
|
+
});
|
|
188
|
+
// Add rewrites for all dynamic routes (both SSR and ISR)
|
|
189
|
+
const { dynamicRewrites, dynamicRoutesThatMatchMiddleware } = generateDynamicRewrites({
|
|
190
|
+
dynamicRoutes,
|
|
191
|
+
prerenderedDynamicRoutes,
|
|
192
|
+
middleware,
|
|
193
|
+
basePath,
|
|
194
|
+
buildId,
|
|
195
|
+
i18n,
|
|
196
|
+
});
|
|
197
|
+
netlifyConfig.redirects.push(...dynamicRewrites);
|
|
198
|
+
routesThatMatchMiddleware.push(...dynamicRoutesThatMatchMiddleware);
|
|
116
199
|
// Final fallback
|
|
117
200
|
netlifyConfig.redirects.push({
|
|
118
201
|
from: `${basePath}/*`,
|
|
119
202
|
to: constants_1.HANDLER_FUNCTION_PATH,
|
|
120
203
|
status: 200,
|
|
121
204
|
});
|
|
205
|
+
const middlewareMatches = new Set(routesThatMatchMiddleware).size;
|
|
206
|
+
if (middlewareMatches > 0) {
|
|
207
|
+
console.log((0, chalk_1.yellowBright)((0, outdent_1.outdent) `
|
|
208
|
+
There ${middlewareMatches === 1
|
|
209
|
+
? `is one statically-generated or ISR route that matches`
|
|
210
|
+
: `are ${middlewareMatches} statically-generated or ISR routes that match`} a middleware function. Matched routes will always be served from the SSR function and will not use ISR or be served from the CDN.
|
|
211
|
+
If this was not intended, ensure that your middleware only matches routes that you intend to use SSR.
|
|
212
|
+
`));
|
|
213
|
+
}
|
|
122
214
|
};
|
|
123
215
|
exports.generateRedirects = generateRedirects;
|
|
216
|
+
/* 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.shouldSkip = exports.getPreviewRewrites = exports.getApiRewrites = exports.redirectsForNextRouteWithData = exports.redirectsForNextRoute = exports.
|
|
6
|
+
exports.findModuleFromBase = exports.shouldSkip = exports.getPreviewRewrites = exports.getApiRewrites = exports.redirectsForNextRouteWithData = exports.redirectsForNextRoute = exports.isApiRoute = exports.routeToDataRoute = exports.netlifyRoutesForNextRouteWithData = exports.toNetlifyRoute = void 0;
|
|
7
7
|
const globby_1 = __importDefault(require("globby"));
|
|
8
8
|
const pathe_1 = require("pathe");
|
|
9
9
|
const constants_1 = require("../constants");
|
|
@@ -63,16 +63,6 @@ const netlifyRoutesForNextRoute = (route, buildId, i18n) => {
|
|
|
63
63
|
};
|
|
64
64
|
const isApiRoute = (route) => route.startsWith('/api/') || route === '/api';
|
|
65
65
|
exports.isApiRoute = isApiRoute;
|
|
66
|
-
const targetForFallback = (fallback) => {
|
|
67
|
-
if (fallback === null || fallback === false) {
|
|
68
|
-
// fallback = null mean "blocking", which uses ODB. For fallback=false then anything prerendered should 404.
|
|
69
|
-
// However i18n pages may not have been prerendered, so we still need to hit the origin
|
|
70
|
-
return { to: constants_1.ODB_FUNCTION_PATH, status: 200 };
|
|
71
|
-
}
|
|
72
|
-
// fallback = true is also ODB
|
|
73
|
-
return { to: constants_1.ODB_FUNCTION_PATH, status: 200 };
|
|
74
|
-
};
|
|
75
|
-
exports.targetForFallback = targetForFallback;
|
|
76
66
|
const redirectsForNextRoute = ({ route, buildId, basePath, to, i18n, status = 200, force = false, }) => netlifyRoutesForNextRoute(route, buildId, i18n).map((redirect) => ({
|
|
77
67
|
from: `${basePath}${redirect}`,
|
|
78
68
|
to,
|
|
@@ -126,3 +116,21 @@ const shouldSkip = () => process.env.NEXT_PLUGIN_FORCE_RUN === 'false' ||
|
|
|
126
116
|
process.env.NETLIFY_NEXT_PLUGIN_SKIP === 'true' ||
|
|
127
117
|
process.env.NETLIFY_NEXT_PLUGIN_SKIP === '1';
|
|
128
118
|
exports.shouldSkip = shouldSkip;
|
|
119
|
+
/**
|
|
120
|
+
* Given an array of base paths and candidate modules, return the first one that exists
|
|
121
|
+
*/
|
|
122
|
+
const findModuleFromBase = ({ paths, candidates }) => {
|
|
123
|
+
for (const candidate of candidates) {
|
|
124
|
+
try {
|
|
125
|
+
const modulePath = require.resolve(candidate, { paths });
|
|
126
|
+
if (modulePath) {
|
|
127
|
+
return modulePath;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Ignore the error
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
};
|
|
136
|
+
exports.findModuleFromBase = findModuleFromBase;
|
package/lib/index.js
CHANGED
|
@@ -49,7 +49,7 @@ const plugin = {
|
|
|
49
49
|
console.log("The flag 'EXPERIMENTAL_MOVE_STATIC_PAGES' is no longer required, as it is now the default. To disable this behavior, set the env var 'SERVE_STATIC_FILES_FROM_ORIGIN' to 'true'");
|
|
50
50
|
}
|
|
51
51
|
if (!process.env.SERVE_STATIC_FILES_FROM_ORIGIN) {
|
|
52
|
-
await (0, files_1.moveStaticPages)({ target, netlifyConfig, i18n });
|
|
52
|
+
await (0, files_1.moveStaticPages)({ target, netlifyConfig, i18n, basePath });
|
|
53
53
|
}
|
|
54
54
|
await (0, redirects_1.generateStaticRedirects)({
|
|
55
55
|
netlifyConfig,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/plugin-nextjs",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.6",
|
|
4
4
|
"description": "Run Next.js seamlessly on Netlify",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"files": [
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"fs-extra": "^10.0.0",
|
|
61
61
|
"globby": "^11.0.4",
|
|
62
62
|
"moize": "^6.1.0",
|
|
63
|
+
"next": "^12.0.10",
|
|
63
64
|
"node-fetch": "^2.6.6",
|
|
64
65
|
"node-stream-zip": "^1.15.0",
|
|
65
66
|
"outdent": "^0.8.0",
|
|
@@ -74,13 +75,16 @@
|
|
|
74
75
|
"@babel/core": "^7.15.8",
|
|
75
76
|
"@babel/preset-env": "^7.15.8",
|
|
76
77
|
"@babel/preset-typescript": "^7.16.0",
|
|
77
|
-
"@netlify/build": "^26.
|
|
78
|
-
"@netlify/eslint-config-node": "^
|
|
78
|
+
"@netlify/build": "^26.3.1",
|
|
79
|
+
"@netlify/eslint-config-node": "^5.1.4",
|
|
80
|
+
"@reach/dialog": "^0.16.2",
|
|
81
|
+
"@reach/visually-hidden": "^0.16.0",
|
|
79
82
|
"@testing-library/cypress": "^8.0.1",
|
|
80
83
|
"@types/fs-extra": "^9.0.13",
|
|
81
84
|
"@types/jest": "^27.0.2",
|
|
82
85
|
"@types/mocha": "^9.0.0",
|
|
83
86
|
"@types/node": "^17.0.10",
|
|
87
|
+
"@types/react": "^17.0.38",
|
|
84
88
|
"babel-jest": "^27.2.5",
|
|
85
89
|
"cpy": "^8.1.2",
|
|
86
90
|
"cypress": "^9.0.0",
|
|
@@ -88,12 +92,12 @@
|
|
|
88
92
|
"husky": "^7.0.4",
|
|
89
93
|
"jest": "^27.0.0",
|
|
90
94
|
"netlify-plugin-cypress": "^2.2.0",
|
|
91
|
-
"next": "^12.0.8",
|
|
92
95
|
"npm-run-all": "^4.1.5",
|
|
93
96
|
"prettier": "^2.1.2",
|
|
94
97
|
"react": "^17.0.1",
|
|
95
98
|
"react-dom": "^17.0.1",
|
|
96
99
|
"rimraf": "^3.0.2",
|
|
100
|
+
"sass": "^1.49.0",
|
|
97
101
|
"tmp-promise": "^3.0.2",
|
|
98
102
|
"typescript": "^4.3.4"
|
|
99
103
|
},
|