@netlify/plugin-nextjs 4.2.0 → 4.2.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/README.md +14 -1
- package/lib/helpers/cache.js +3 -3
- package/lib/helpers/config.js +3 -3
- package/lib/helpers/files.js +90 -80
- package/lib/helpers/functions.js +18 -15
- package/lib/helpers/redirects.js +132 -39
- package/lib/helpers/utils.js +26 -18
- package/lib/helpers/verification.js +27 -21
- package/lib/index.js +27 -26
- package/lib/templates/getHandler.js +59 -46
- package/lib/templates/getPageResolver.js +4 -4
- package/lib/templates/handlerUtils.js +21 -8
- package/lib/templates/ipx.js +1 -1
- package/package.json +10 -15
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,29 +45,40 @@ 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
|
-
if (utils_1.isApiRoute(route)) {
|
|
81
|
+
if ((0, utils_1.isApiRoute)(route)) {
|
|
67
82
|
return;
|
|
68
83
|
}
|
|
69
84
|
staticRoutePaths.add(route);
|
|
@@ -75,49 +90,127 @@ 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
|
-
dataRoute: utils_1.routeToDataRoute(route, buildId, i18n.defaultLocale),
|
|
98
|
+
dataRoute: (0, utils_1.routeToDataRoute)(route, buildId, i18n.defaultLocale),
|
|
81
99
|
basePath,
|
|
82
100
|
to: constants_1.ODB_FUNCTION_PATH,
|
|
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
|
-
...utils_1.redirectsForNextRoute({ route, basePath, to: constants_1.ODB_FUNCTION_PATH, force: true, buildId, i18n: null }));
|
|
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
|
-
if (utils_1.isApiRoute(route.page)) {
|
|
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");
|
|
@@ -36,8 +36,8 @@ const toNetlifyRoute = (nextRoute) => {
|
|
|
36
36
|
};
|
|
37
37
|
exports.toNetlifyRoute = toNetlifyRoute;
|
|
38
38
|
const netlifyRoutesForNextRouteWithData = ({ route, dataRoute }) => [
|
|
39
|
-
...exports.toNetlifyRoute(dataRoute),
|
|
40
|
-
...exports.toNetlifyRoute(route),
|
|
39
|
+
...(0, exports.toNetlifyRoute)(dataRoute),
|
|
40
|
+
...(0, exports.toNetlifyRoute)(route),
|
|
41
41
|
];
|
|
42
42
|
exports.netlifyRoutesForNextRouteWithData = netlifyRoutesForNextRouteWithData;
|
|
43
43
|
const routeToDataRoute = (route, buildId, locale) => `/_next/data/${buildId}${locale ? `/${locale}` : ''}${route === '/' ? '/index' : route}.json`;
|
|
@@ -45,16 +45,16 @@ exports.routeToDataRoute = routeToDataRoute;
|
|
|
45
45
|
const netlifyRoutesForNextRoute = (route, buildId, i18n) => {
|
|
46
46
|
var _a;
|
|
47
47
|
if (!((_a = i18n === null || i18n === void 0 ? void 0 : i18n.locales) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
48
|
-
return exports.netlifyRoutesForNextRouteWithData({ route, dataRoute: exports.routeToDataRoute(route, buildId) });
|
|
48
|
+
return (0, exports.netlifyRoutesForNextRouteWithData)({ route, dataRoute: (0, exports.routeToDataRoute)(route, buildId) });
|
|
49
49
|
}
|
|
50
50
|
const { locales, defaultLocale } = i18n;
|
|
51
51
|
const routes = [];
|
|
52
52
|
locales.forEach((locale) => {
|
|
53
53
|
// Data route is always localized
|
|
54
|
-
const dataRoute = exports.routeToDataRoute(route, buildId, locale);
|
|
54
|
+
const dataRoute = (0, exports.routeToDataRoute)(route, buildId, locale);
|
|
55
55
|
routes.push(
|
|
56
56
|
// Default locale is served from root, not localized
|
|
57
|
-
...exports.netlifyRoutesForNextRouteWithData({
|
|
57
|
+
...(0, exports.netlifyRoutesForNextRouteWithData)({
|
|
58
58
|
route: locale === defaultLocale ? route : `/${locale}${route}`,
|
|
59
59
|
dataRoute,
|
|
60
60
|
}));
|
|
@@ -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,
|
|
@@ -80,7 +70,7 @@ const redirectsForNextRoute = ({ route, buildId, basePath, to, i18n, status = 20
|
|
|
80
70
|
force,
|
|
81
71
|
}));
|
|
82
72
|
exports.redirectsForNextRoute = redirectsForNextRoute;
|
|
83
|
-
const redirectsForNextRouteWithData = ({ route, dataRoute, basePath, to, status = 200, force = false, }) => exports.netlifyRoutesForNextRouteWithData({ route, dataRoute }).map((redirect) => ({
|
|
73
|
+
const redirectsForNextRouteWithData = ({ route, dataRoute, basePath, to, status = 200, force = false, }) => (0, exports.netlifyRoutesForNextRouteWithData)({ route, dataRoute }).map((redirect) => ({
|
|
84
74
|
from: `${basePath}${redirect}`,
|
|
85
75
|
to,
|
|
86
76
|
status,
|
|
@@ -101,7 +91,7 @@ const getApiRewrites = (basePath) => [
|
|
|
101
91
|
];
|
|
102
92
|
exports.getApiRewrites = getApiRewrites;
|
|
103
93
|
const getPreviewRewrites = async ({ basePath, appDir }) => {
|
|
104
|
-
const publicFiles = await globby_1.default('**/*', { cwd: pathe_1.join(appDir, 'public') });
|
|
94
|
+
const publicFiles = await (0, globby_1.default)('**/*', { cwd: (0, pathe_1.join)(appDir, 'public') });
|
|
105
95
|
// Preview mode gets forced to the function, to bypass pre-rendered pages, but static files need to be skipped
|
|
106
96
|
return [
|
|
107
97
|
...publicFiles.map((file) => ({
|
|
@@ -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 (error) {
|
|
131
|
+
console.error(error);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
};
|
|
136
|
+
exports.findModuleFromBase = findModuleFromBase;
|
|
@@ -22,7 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
22
22
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.warnForProblematicUserRewrites = exports.getProblematicUserRewrites = exports.checkZipSize = exports.checkForRootPublish = exports.checkNextSiteHasBuilt = exports.checkForOldFunctions = exports.verifyNetlifyBuildVersion = void 0;
|
|
25
|
+
exports.warnForRootRedirects = exports.warnForProblematicUserRewrites = exports.getProblematicUserRewrites = exports.checkZipSize = exports.checkForRootPublish = exports.checkNextSiteHasBuilt = exports.checkForOldFunctions = exports.verifyNetlifyBuildVersion = void 0;
|
|
26
26
|
/* eslint-disable max-lines */
|
|
27
27
|
const fs_1 = require("fs");
|
|
28
28
|
const path_1 = __importStar(require("path"));
|
|
@@ -36,8 +36,8 @@ const constants_1 = require("../constants");
|
|
|
36
36
|
const REQUIRED_BUILD_VERSION = '>=18.16.0';
|
|
37
37
|
const verifyNetlifyBuildVersion = ({ IS_LOCAL, NETLIFY_BUILD_VERSION, failBuild, }) => {
|
|
38
38
|
// We check for build version because that's what's available to us, but prompt about the cli because that's what they can upgrade
|
|
39
|
-
if (IS_LOCAL && !semver_1.satisfies(NETLIFY_BUILD_VERSION, REQUIRED_BUILD_VERSION, { includePrerelease: true })) {
|
|
40
|
-
return failBuild(outdent_1.outdent `
|
|
39
|
+
if (IS_LOCAL && !(0, semver_1.satisfies)(NETLIFY_BUILD_VERSION, REQUIRED_BUILD_VERSION, { includePrerelease: true })) {
|
|
40
|
+
return failBuild((0, outdent_1.outdent) `
|
|
41
41
|
This version of the Essential Next.js plugin requires netlify-cli@6.12.4 or higher. Please upgrade and try again.
|
|
42
42
|
You can do this by running: "npm install -g netlify-cli@latest" or "yarn global add netlify-cli@latest"
|
|
43
43
|
`);
|
|
@@ -48,31 +48,31 @@ const checkForOldFunctions = async ({ functions }) => {
|
|
|
48
48
|
const allOldFunctions = await functions.list();
|
|
49
49
|
const oldFunctions = allOldFunctions.filter(({ name }) => name.startsWith('next_'));
|
|
50
50
|
if (oldFunctions.length !== 0) {
|
|
51
|
-
console.log(chalk_1.yellowBright(outdent_1.outdent `
|
|
51
|
+
console.log((0, chalk_1.yellowBright)((0, outdent_1.outdent) `
|
|
52
52
|
We have found the following functions in your site that seem to be left over from the old Next.js plugin (v3). We have guessed this because the name starts with "next_".
|
|
53
53
|
|
|
54
|
-
${chalk_1.reset(oldFunctions.map(({ name }) => `- ${name}`).join('\n'))}
|
|
54
|
+
${(0, chalk_1.reset)(oldFunctions.map(({ name }) => `- ${name}`).join('\n'))}
|
|
55
55
|
|
|
56
56
|
If they were created by the old plugin, these functions are likely to cause errors so should be removed. You can do this by deleting the following directories:
|
|
57
57
|
|
|
58
|
-
${chalk_1.reset(oldFunctions.map(({ mainFile }) => `- ${path_1.default.relative(process.cwd(), path_1.default.dirname(mainFile))}`).join('\n'))}
|
|
58
|
+
${(0, chalk_1.reset)(oldFunctions.map(({ mainFile }) => `- ${path_1.default.relative(process.cwd(), path_1.default.dirname(mainFile))}`).join('\n'))}
|
|
59
59
|
`));
|
|
60
60
|
}
|
|
61
61
|
};
|
|
62
62
|
exports.checkForOldFunctions = checkForOldFunctions;
|
|
63
63
|
const checkNextSiteHasBuilt = ({ publish, failBuild, }) => {
|
|
64
|
-
if (!fs_1.existsSync(path_1.default.join(publish, 'BUILD_ID'))) {
|
|
64
|
+
if (!(0, fs_1.existsSync)(path_1.default.join(publish, 'BUILD_ID'))) {
|
|
65
65
|
const outWarning = path_1.default.basename(publish) === 'out'
|
|
66
66
|
? `Your publish directory is set to "out", but in most cases it should be ".next".`
|
|
67
67
|
: `In most cases it should be set to ".next", unless you have chosen a custom "distDir" in your Next config.`;
|
|
68
|
-
return failBuild(outdent_1.outdent `
|
|
68
|
+
return failBuild((0, outdent_1.outdent) `
|
|
69
69
|
The directory "${path_1.default.relative(process.cwd(), publish)}" does not contain a Next.js production build. Perhaps the build command was not run, or you specified the wrong publish directory.
|
|
70
70
|
${outWarning}
|
|
71
71
|
If you are using "next export" then you should set the environment variable NETLIFY_NEXT_PLUGIN_SKIP to "true".
|
|
72
72
|
`);
|
|
73
73
|
}
|
|
74
|
-
if (fs_1.existsSync(path_1.default.join(publish, 'export-detail.json'))) {
|
|
75
|
-
failBuild(outdent_1.outdent `
|
|
74
|
+
if ((0, fs_1.existsSync)(path_1.default.join(publish, 'export-detail.json'))) {
|
|
75
|
+
failBuild((0, outdent_1.outdent) `
|
|
76
76
|
Detected that "next export" was run, but site is incorrectly publishing the ".next" directory.
|
|
77
77
|
The publish directory should be set to "out", and you should set the environment variable NETLIFY_NEXT_PLUGIN_SKIP to "true".
|
|
78
78
|
`);
|
|
@@ -81,7 +81,7 @@ const checkNextSiteHasBuilt = ({ publish, failBuild, }) => {
|
|
|
81
81
|
exports.checkNextSiteHasBuilt = checkNextSiteHasBuilt;
|
|
82
82
|
const checkForRootPublish = ({ publish, failBuild, }) => {
|
|
83
83
|
if (path_1.default.resolve(publish) === path_1.default.resolve('.')) {
|
|
84
|
-
failBuild(outdent_1.outdent `
|
|
84
|
+
failBuild((0, outdent_1.outdent) `
|
|
85
85
|
Your publish directory is pointing to the base directory of your site. This is not supported for Next.js sites, and is probably a mistake.
|
|
86
86
|
In most cases it should be set to ".next", unless you have chosen a custom "distDir" in your Next config, or the Next site is in a subdirectory.
|
|
87
87
|
`);
|
|
@@ -89,7 +89,7 @@ const checkForRootPublish = ({ publish, failBuild, }) => {
|
|
|
89
89
|
};
|
|
90
90
|
exports.checkForRootPublish = checkForRootPublish;
|
|
91
91
|
const checkZipSize = async (file, maxSize = constants_1.LAMBDA_MAX_SIZE) => {
|
|
92
|
-
if (!fs_1.existsSync(file)) {
|
|
92
|
+
if (!(0, fs_1.existsSync)(file)) {
|
|
93
93
|
console.warn(`Could not check zip size because ${file} does not exist`);
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
@@ -98,8 +98,8 @@ const checkZipSize = async (file, maxSize = constants_1.LAMBDA_MAX_SIZE) => {
|
|
|
98
98
|
return;
|
|
99
99
|
}
|
|
100
100
|
// We don't fail the build, because the actual hard max size is larger so it might still succeed
|
|
101
|
-
console.log(chalk_1.redBright(outdent_1.outdent `
|
|
102
|
-
The function zip ${chalk_1.yellowBright(path_1.relative(process.cwd(), file))} size is ${pretty_bytes_1.default(fileSize)}, which is larger than the maximum supported size of ${pretty_bytes_1.default(maxSize)}.
|
|
101
|
+
console.log((0, chalk_1.redBright)((0, outdent_1.outdent) `
|
|
102
|
+
The function zip ${(0, chalk_1.yellowBright)((0, path_1.relative)(process.cwd(), file))} size is ${(0, pretty_bytes_1.default)(fileSize)}, which is larger than the maximum supported size of ${(0, pretty_bytes_1.default)(maxSize)}.
|
|
103
103
|
There are a few reasons this could happen. You may have accidentally bundled a large dependency, or you might have a
|
|
104
104
|
large number of pre-rendered pages included.
|
|
105
105
|
`));
|
|
@@ -110,13 +110,13 @@ const checkZipSize = async (file, maxSize = constants_1.LAMBDA_MAX_SIZE) => {
|
|
|
110
110
|
for (let i = 0; i < 10 && i < sortedFiles.length; i++) {
|
|
111
111
|
largest[`${i + 1}`] = {
|
|
112
112
|
File: sortedFiles[i].name,
|
|
113
|
-
'Compressed Size': pretty_bytes_1.default(sortedFiles[i].compressedSize),
|
|
114
|
-
'Uncompressed Size': pretty_bytes_1.default(sortedFiles[i].size),
|
|
113
|
+
'Compressed Size': (0, pretty_bytes_1.default)(sortedFiles[i].compressedSize),
|
|
114
|
+
'Uncompressed Size': (0, pretty_bytes_1.default)(sortedFiles[i].size),
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
|
-
console.log(chalk_1.yellowBright `\n\nThese are the largest files in the zip:`);
|
|
117
|
+
console.log((0, chalk_1.yellowBright) `\n\nThese are the largest files in the zip:`);
|
|
118
118
|
console.table(largest);
|
|
119
|
-
console.log(chalk_1.greenBright `\n\nFor more information on fixing this, see ${chalk_1.blueBright `https://ntl.fyi/large-next-functions`}`);
|
|
119
|
+
console.log((0, chalk_1.greenBright) `\n\nFor more information on fixing this, see ${(0, chalk_1.blueBright) `https://ntl.fyi/large-next-functions`}`);
|
|
120
120
|
};
|
|
121
121
|
exports.checkZipSize = checkZipSize;
|
|
122
122
|
const getProblematicUserRewrites = ({ redirects, basePath, }) => {
|
|
@@ -140,17 +140,23 @@ const getProblematicUserRewrites = ({ redirects, basePath, }) => {
|
|
|
140
140
|
};
|
|
141
141
|
exports.getProblematicUserRewrites = getProblematicUserRewrites;
|
|
142
142
|
const warnForProblematicUserRewrites = ({ redirects, basePath, }) => {
|
|
143
|
-
const userRewrites = exports.getProblematicUserRewrites({ redirects, basePath });
|
|
143
|
+
const userRewrites = (0, exports.getProblematicUserRewrites)({ redirects, basePath });
|
|
144
144
|
if (userRewrites.length === 0) {
|
|
145
145
|
return;
|
|
146
146
|
}
|
|
147
|
-
console.log(chalk_1.yellowBright(outdent_1.outdent `
|
|
147
|
+
console.log((0, chalk_1.yellowBright)((0, outdent_1.outdent) `
|
|
148
148
|
You have the following Netlify rewrite${userRewrites.length === 1 ? '' : 's'} that might cause conflicts with the Next.js plugin:
|
|
149
149
|
|
|
150
|
-
${chalk_1.reset(userRewrites.map(({ from, to, status }) => `- ${from} ${to} ${status}`).join('\n'))}
|
|
150
|
+
${(0, chalk_1.reset)(userRewrites.map(({ from, to, status }) => `- ${from} ${to} ${status}`).join('\n'))}
|
|
151
151
|
|
|
152
152
|
For more information, see https://ntl.fyi/next-rewrites
|
|
153
153
|
`));
|
|
154
154
|
};
|
|
155
155
|
exports.warnForProblematicUserRewrites = warnForProblematicUserRewrites;
|
|
156
|
+
const warnForRootRedirects = ({ appDir }) => {
|
|
157
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(appDir, '_redirects'))) {
|
|
158
|
+
console.log((0, chalk_1.yellowBright)(`You have a "_redirects" file in your root directory, which is not deployed and will be ignored. If you want it to be used, please move it into "public".`));
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
exports.warnForRootRedirects = warnForRootRedirects;
|
|
156
162
|
/* eslint-enable max-lines */
|
package/lib/index.js
CHANGED
|
@@ -14,57 +14,57 @@ const plugin = {
|
|
|
14
14
|
async onPreBuild({ constants, netlifyConfig, utils: { build: { failBuild }, cache, }, }) {
|
|
15
15
|
var _a;
|
|
16
16
|
const { publish } = netlifyConfig.build;
|
|
17
|
-
if (utils_1.shouldSkip()) {
|
|
18
|
-
await cache_1.restoreCache({ cache, publish });
|
|
17
|
+
if ((0, utils_1.shouldSkip)()) {
|
|
18
|
+
await (0, cache_1.restoreCache)({ cache, publish });
|
|
19
19
|
console.log('Not running Essential Next.js plugin');
|
|
20
|
-
if (fs_extra_1.existsSync(path_1.join(constants.INTERNAL_FUNCTIONS_SRC, constants_1.HANDLER_FUNCTION_NAME))) {
|
|
20
|
+
if ((0, fs_extra_1.existsSync)((0, path_1.join)(constants.INTERNAL_FUNCTIONS_SRC, constants_1.HANDLER_FUNCTION_NAME))) {
|
|
21
21
|
console.log(`Please ensure you remove any generated functions from ${constants.INTERNAL_FUNCTIONS_SRC}`);
|
|
22
22
|
}
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
|
-
verification_1.checkForRootPublish({ publish, failBuild });
|
|
26
|
-
verification_1.verifyNetlifyBuildVersion({ failBuild, ...constants });
|
|
27
|
-
await cache_1.restoreCache({ cache, publish });
|
|
25
|
+
(0, verification_1.checkForRootPublish)({ publish, failBuild });
|
|
26
|
+
(0, verification_1.verifyNetlifyBuildVersion)({ failBuild, ...constants });
|
|
27
|
+
await (0, cache_1.restoreCache)({ cache, publish });
|
|
28
28
|
(_a = netlifyConfig.build).environment || (_a.environment = {});
|
|
29
29
|
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
30
30
|
netlifyConfig.build.environment.NEXT_PRIVATE_TARGET = 'server';
|
|
31
31
|
},
|
|
32
32
|
async onBuild({ constants, netlifyConfig, utils: { build: { failBuild }, }, }) {
|
|
33
|
-
if (utils_1.shouldSkip()) {
|
|
33
|
+
if ((0, utils_1.shouldSkip)()) {
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
36
|
const { publish } = netlifyConfig.build;
|
|
37
|
-
verification_1.checkNextSiteHasBuilt({ publish, failBuild });
|
|
38
|
-
const { appDir, basePath, i18n, images, target, ignore, trailingSlash, outdir } = await config_1.getNextConfig({
|
|
37
|
+
(0, verification_1.checkNextSiteHasBuilt)({ publish, failBuild });
|
|
38
|
+
const { appDir, basePath, i18n, images, target, ignore, trailingSlash, outdir } = await (0, config_1.getNextConfig)({
|
|
39
39
|
publish,
|
|
40
40
|
failBuild,
|
|
41
41
|
});
|
|
42
|
-
const buildId = fs_extra_1.readFileSync(path_1.join(publish, 'BUILD_ID'), 'utf8').trim();
|
|
43
|
-
config_1.configureHandlerFunctions({ netlifyConfig, ignore, publish: path_1.relative(process.cwd(), publish) });
|
|
44
|
-
await functions_1.generateFunctions(constants, appDir);
|
|
45
|
-
await functions_1.generatePagesResolver({ target, constants });
|
|
46
|
-
await files_1.movePublicFiles({ appDir, outdir, publish });
|
|
47
|
-
await files_1.patchNextFiles(basePath);
|
|
42
|
+
const buildId = (0, fs_extra_1.readFileSync)((0, path_1.join)(publish, 'BUILD_ID'), 'utf8').trim();
|
|
43
|
+
(0, config_1.configureHandlerFunctions)({ netlifyConfig, ignore, publish: (0, path_1.relative)(process.cwd(), publish) });
|
|
44
|
+
await (0, functions_1.generateFunctions)(constants, appDir);
|
|
45
|
+
await (0, functions_1.generatePagesResolver)({ target, constants });
|
|
46
|
+
await (0, files_1.movePublicFiles)({ appDir, outdir, publish });
|
|
47
|
+
await (0, files_1.patchNextFiles)(basePath);
|
|
48
48
|
if (process.env.EXPERIMENTAL_MOVE_STATIC_PAGES) {
|
|
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 files_1.moveStaticPages({ target, netlifyConfig, i18n });
|
|
52
|
+
await (0, files_1.moveStaticPages)({ target, netlifyConfig, i18n });
|
|
53
53
|
}
|
|
54
|
-
await redirects_1.generateStaticRedirects({
|
|
54
|
+
await (0, redirects_1.generateStaticRedirects)({
|
|
55
55
|
netlifyConfig,
|
|
56
56
|
nextConfig: { basePath, i18n },
|
|
57
57
|
});
|
|
58
|
-
await functions_1.setupImageFunction({ constants, imageconfig: images, netlifyConfig, basePath });
|
|
59
|
-
await redirects_1.generateRedirects({
|
|
58
|
+
await (0, functions_1.setupImageFunction)({ constants, imageconfig: images, netlifyConfig, basePath });
|
|
59
|
+
await (0, redirects_1.generateRedirects)({
|
|
60
60
|
netlifyConfig,
|
|
61
61
|
nextConfig: { basePath, i18n, trailingSlash, appDir },
|
|
62
62
|
buildId,
|
|
63
63
|
});
|
|
64
64
|
},
|
|
65
65
|
async onPostBuild({ netlifyConfig: { build: { publish }, redirects, }, utils: { status, cache, functions, build: { failBuild }, }, constants: { FUNCTIONS_DIST }, }) {
|
|
66
|
-
await cache_1.saveCache({ cache, publish });
|
|
67
|
-
if (utils_1.shouldSkip()) {
|
|
66
|
+
await (0, cache_1.saveCache)({ cache, publish });
|
|
67
|
+
if ((0, utils_1.shouldSkip)()) {
|
|
68
68
|
status.show({
|
|
69
69
|
title: 'Essential Next.js plugin did not run',
|
|
70
70
|
summary: `Next cache was stored, but all other functions were skipped because ${process.env.NETLIFY_NEXT_PLUGIN_SKIP
|
|
@@ -73,11 +73,12 @@ const plugin = {
|
|
|
73
73
|
});
|
|
74
74
|
return;
|
|
75
75
|
}
|
|
76
|
-
await verification_1.checkForOldFunctions({ functions });
|
|
77
|
-
await verification_1.checkZipSize(path_1.join(FUNCTIONS_DIST, `${constants_1.ODB_FUNCTION_NAME}.zip`));
|
|
78
|
-
const { basePath } = await config_1.getNextConfig({ publish, failBuild });
|
|
79
|
-
verification_1.warnForProblematicUserRewrites({ basePath, redirects });
|
|
80
|
-
|
|
76
|
+
await (0, verification_1.checkForOldFunctions)({ functions });
|
|
77
|
+
await (0, verification_1.checkZipSize)((0, path_1.join)(FUNCTIONS_DIST, `${constants_1.ODB_FUNCTION_NAME}.zip`));
|
|
78
|
+
const { basePath, appDir } = await (0, config_1.getNextConfig)({ publish, failBuild });
|
|
79
|
+
(0, verification_1.warnForProblematicUserRewrites)({ basePath, redirects });
|
|
80
|
+
(0, verification_1.warnForRootRedirects)({ appDir });
|
|
81
|
+
await (0, files_1.unpatchNextFiles)(basePath);
|
|
81
82
|
},
|
|
82
83
|
};
|
|
83
84
|
module.exports = plugin;
|