@netlify/plugin-nextjs 4.28.7 → 4.29.1
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 +1 -1
- package/lib/helpers/edge.js +17 -0
- package/lib/helpers/files.js +14 -15
- package/lib/helpers/redirects.js +16 -1
- package/lib/index.js +18 -20
- package/lib/templates/getHandler.js +7 -0
- package/package.json +1 -1
package/lib/helpers/config.js
CHANGED
|
@@ -79,7 +79,7 @@ const configureHandlerFunctions = async ({ netlifyConfig, publish, ignore = [],
|
|
|
79
79
|
(_a = netlifyConfig.functions)[functionName] || (_a[functionName] = { included_files: [], external_node_modules: [] });
|
|
80
80
|
netlifyConfig.functions[functionName].node_bundler = 'nft';
|
|
81
81
|
(_b = netlifyConfig.functions[functionName]).included_files || (_b.included_files = []);
|
|
82
|
-
netlifyConfig.functions[functionName].included_files.push('.env', '.env.local', '.env.production', '.env.production.local', './public/locales/**', './next-i18next.config.js', `${publish}/server/**`, `${publish}/serverless/**`, `${publish}/*.json`, `${publish}/BUILD_ID`, `${publish}/static/chunks/webpack-middleware*.js`, `!${publish}/server/**/*.js.nft.json`, '!**/node_modules/@next/swc*/**/*', ...cssFilesToInclude, ...ignore.map((path) => `!${(0, slash_1.default)(path)}`));
|
|
82
|
+
netlifyConfig.functions[functionName].included_files.push('.env', '.env.local', '.env.production', '.env.production.local', './public/locales/**', './next-i18next.config.js', `${publish}/server/**`, `${publish}/serverless/**`, `${publish}/*.json`, `${publish}/BUILD_ID`, `${publish}/static/chunks/webpack-middleware*.js`, `!${publish}/server/**/*.js.nft.json`, `!${publish}/server/**/*.map`, '!**/node_modules/@next/swc*/**/*', ...cssFilesToInclude, ...ignore.map((path) => `!${(0, slash_1.default)(path)}`));
|
|
83
83
|
const nextRoot = resolveModuleRoot('next');
|
|
84
84
|
if (nextRoot) {
|
|
85
85
|
netlifyConfig.functions[functionName].included_files.push(`!${nextRoot}/dist/server/lib/squoosh/**/*.wasm`, `!${nextRoot}/dist/next-server/server/lib/squoosh/**/*.wasm`, `!${nextRoot}/dist/compiled/webpack/bundle4.js`, `!${nextRoot}/dist/compiled/webpack/bundle5.js`);
|
package/lib/helpers/edge.js
CHANGED
|
@@ -39,6 +39,23 @@ globalThis.process = { env: {...Deno.env.toObject(), NEXT_RUNTIME: 'edge', 'NEXT
|
|
|
39
39
|
const self = {}
|
|
40
40
|
let _ENTRIES = {}
|
|
41
41
|
|
|
42
|
+
class Response extends globalThis.Response {
|
|
43
|
+
constructor(body, init) {
|
|
44
|
+
super(body, init);
|
|
45
|
+
// Next.js uses this extension to the Headers API implemented by Cloudflare workerd
|
|
46
|
+
this.headers.getAll = (name) => {
|
|
47
|
+
name = name.toLowerCase();
|
|
48
|
+
if (name !== "set-cookie") {
|
|
49
|
+
throw new Error("Headers.getAll is only supported for Set-Cookie");
|
|
50
|
+
}
|
|
51
|
+
return [...this.headers.entries()]
|
|
52
|
+
.filter(([key]) => key === name)
|
|
53
|
+
.map(([, value]) => value);
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
42
59
|
// Next uses blob: urls to refer to local assets, so we need to intercept these
|
|
43
60
|
const _fetch = globalThis.fetch
|
|
44
61
|
const fetch = async (url, init) => {
|
package/lib/helpers/files.js
CHANGED
|
@@ -53,12 +53,12 @@ const matchesRewrite = (file, rewrites) => {
|
|
|
53
53
|
return (0, exports.matchesRedirect)(file, rewrites.beforeFiles);
|
|
54
54
|
};
|
|
55
55
|
exports.matchesRewrite = matchesRewrite;
|
|
56
|
-
const getMiddleware = async (
|
|
56
|
+
const getMiddleware = async (publish) => {
|
|
57
57
|
var _a;
|
|
58
58
|
if (process.env.NEXT_DISABLE_NETLIFY_EDGE !== 'true' && process.env.NEXT_DISABLE_NETLIFY_EDGE !== '1') {
|
|
59
59
|
return [];
|
|
60
60
|
}
|
|
61
|
-
const manifestPath = (0, pathe_1.join)(
|
|
61
|
+
const manifestPath = (0, pathe_1.join)(publish, 'server', 'middleware-manifest.json');
|
|
62
62
|
if ((0, fs_extra_1.existsSync)(manifestPath)) {
|
|
63
63
|
const manifest = await (0, fs_extra_1.readJson)(manifestPath, { throws: false });
|
|
64
64
|
return (_a = manifest === null || manifest === void 0 ? void 0 : manifest.sortedMiddleware) !== null && _a !== void 0 ? _a : [];
|
|
@@ -67,18 +67,18 @@ const getMiddleware = async (distDir) => {
|
|
|
67
67
|
};
|
|
68
68
|
exports.getMiddleware = getMiddleware;
|
|
69
69
|
// eslint-disable-next-line max-lines-per-function
|
|
70
|
-
const moveStaticPages = async ({
|
|
70
|
+
const moveStaticPages = async ({ netlifyConfig, target, i18n, basePath, }) => {
|
|
71
71
|
console.log('Moving static page files to serve from CDN...');
|
|
72
|
-
const outputDir = (0, pathe_1.join)(
|
|
72
|
+
const outputDir = (0, pathe_1.join)(netlifyConfig.build.publish, target === 'server' ? 'server' : 'serverless');
|
|
73
73
|
const root = (0, pathe_1.join)(outputDir, 'pages');
|
|
74
|
-
const buildId = (0, fs_extra_1.readFileSync)((0, pathe_1.join)(
|
|
74
|
+
const buildId = (0, fs_extra_1.readFileSync)((0, pathe_1.join)(netlifyConfig.build.publish, 'BUILD_ID'), 'utf8').trim();
|
|
75
75
|
const dataDir = (0, pathe_1.join)('_next', 'data', buildId);
|
|
76
|
-
await (0, fs_extra_1.ensureDir)((0, pathe_1.join)(
|
|
76
|
+
await (0, fs_extra_1.ensureDir)((0, pathe_1.join)(netlifyConfig.build.publish, dataDir));
|
|
77
77
|
// Load the middleware manifest so we can check if a file matches it before moving
|
|
78
|
-
const middlewarePaths = await (0, exports.getMiddleware)(
|
|
78
|
+
const middlewarePaths = await (0, exports.getMiddleware)(netlifyConfig.build.publish);
|
|
79
79
|
const middleware = middlewarePaths.map((path) => path.slice(1));
|
|
80
|
-
const prerenderManifest = await (0, fs_extra_1.readJson)((0, pathe_1.join)(
|
|
81
|
-
const { redirects, rewrites } = await (0, fs_extra_1.readJson)((0, pathe_1.join)(
|
|
80
|
+
const prerenderManifest = await (0, fs_extra_1.readJson)((0, pathe_1.join)(netlifyConfig.build.publish, 'prerender-manifest.json'));
|
|
81
|
+
const { redirects, rewrites } = await (0, fs_extra_1.readJson)((0, pathe_1.join)(netlifyConfig.build.publish, 'routes-manifest.json'));
|
|
82
82
|
const isrFiles = new Set();
|
|
83
83
|
const shortRevalidateRoutes = [];
|
|
84
84
|
Object.entries(prerenderManifest.routes).forEach(([route, { initialRevalidateSeconds }]) => {
|
|
@@ -101,7 +101,7 @@ const moveStaticPages = async ({ distDir, i18n, basePath, publishDir, }) => {
|
|
|
101
101
|
const targetPath = basePath ? (0, pathe_1.join)(basePath, targetFile) : targetFile;
|
|
102
102
|
files.push(file);
|
|
103
103
|
filesManifest[file] = targetPath;
|
|
104
|
-
const dest = (0, pathe_1.join)(
|
|
104
|
+
const dest = (0, pathe_1.join)(netlifyConfig.build.publish, targetPath);
|
|
105
105
|
try {
|
|
106
106
|
await (0, fs_extra_1.move)(source, dest);
|
|
107
107
|
}
|
|
@@ -193,9 +193,9 @@ const moveStaticPages = async ({ distDir, i18n, basePath, publishDir, }) => {
|
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
// Write the manifest for use in the serverless functions
|
|
196
|
-
await (0, fs_extra_1.writeJson)((0, pathe_1.join)(
|
|
196
|
+
await (0, fs_extra_1.writeJson)((0, pathe_1.join)(netlifyConfig.build.publish, 'static-manifest.json'), Object.entries(filesManifest));
|
|
197
197
|
if (i18n === null || i18n === void 0 ? void 0 : i18n.defaultLocale) {
|
|
198
|
-
const rootPath = basePath ? (0, pathe_1.join)(
|
|
198
|
+
const rootPath = basePath ? (0, pathe_1.join)(netlifyConfig.build.publish, basePath) : netlifyConfig.build.publish;
|
|
199
199
|
// Copy the default locale into the root
|
|
200
200
|
const defaultLocaleDir = (0, pathe_1.join)(rootPath, i18n.defaultLocale);
|
|
201
201
|
if ((0, fs_extra_1.existsSync)(defaultLocaleDir)) {
|
|
@@ -358,8 +358,7 @@ const unpatchNextFiles = async (root) => {
|
|
|
358
358
|
}
|
|
359
359
|
};
|
|
360
360
|
exports.unpatchNextFiles = unpatchNextFiles;
|
|
361
|
-
const movePublicFiles = async ({ appDir, outdir,
|
|
362
|
-
await (0, fs_extra_1.ensureDir)(publishDir);
|
|
361
|
+
const movePublicFiles = async ({ appDir, outdir, publish, }) => {
|
|
363
362
|
// `outdir` is a config property added when using Next.js with Nx. It's typically
|
|
364
363
|
// a relative path outside of the appDir, e.g. '../../dist/apps/<app-name>', and
|
|
365
364
|
// the parent directory of the .next directory.
|
|
@@ -368,7 +367,7 @@ const movePublicFiles = async ({ appDir, outdir, publishDir, }) => {
|
|
|
368
367
|
// directory from the original app directory.
|
|
369
368
|
const publicDir = outdir ? (0, pathe_1.join)(appDir, outdir, 'public') : (0, pathe_1.join)(appDir, 'public');
|
|
370
369
|
if ((0, fs_extra_1.existsSync)(publicDir)) {
|
|
371
|
-
await (0, fs_extra_1.copy)(publicDir, `${
|
|
370
|
+
await (0, fs_extra_1.copy)(publicDir, `${publish}/`);
|
|
372
371
|
}
|
|
373
372
|
};
|
|
374
373
|
exports.movePublicFiles = movePublicFiles;
|
package/lib/helpers/redirects.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generateRedirects = void 0;
|
|
3
|
+
exports.generateRedirects = exports.generateStaticRedirects = void 0;
|
|
4
4
|
const chalk_1 = require("chalk");
|
|
5
5
|
const fs_extra_1 = require("fs-extra");
|
|
6
6
|
const outdent_1 = require("outdent");
|
|
@@ -9,6 +9,12 @@ const constants_1 = require("../constants");
|
|
|
9
9
|
const files_1 = require("./files");
|
|
10
10
|
const utils_1 = require("./utils");
|
|
11
11
|
const matchesMiddleware = (middleware, route) => middleware.some((middlewarePath) => route.startsWith(middlewarePath));
|
|
12
|
+
const generateHiddenPathRedirects = ({ basePath }) => constants_1.HIDDEN_PATHS.map((path) => ({
|
|
13
|
+
from: `${basePath}${path}`,
|
|
14
|
+
to: '/404.html',
|
|
15
|
+
status: 404,
|
|
16
|
+
force: true,
|
|
17
|
+
}));
|
|
12
18
|
const generateLocaleRedirects = ({ i18n, basePath, trailingSlash, }) => {
|
|
13
19
|
const redirects = [];
|
|
14
20
|
// If the cookie is set, we need to redirect at the origin
|
|
@@ -37,6 +43,14 @@ const generateLocaleRedirects = ({ i18n, basePath, trailingSlash, }) => {
|
|
|
37
43
|
});
|
|
38
44
|
return redirects;
|
|
39
45
|
};
|
|
46
|
+
const generateStaticRedirects = ({ netlifyConfig, nextConfig: { i18n, basePath }, }) => {
|
|
47
|
+
// Static files are in `static`
|
|
48
|
+
netlifyConfig.redirects.push({ from: `${basePath}/_next/static/*`, to: `/static/:splat`, status: 200 });
|
|
49
|
+
if (i18n) {
|
|
50
|
+
netlifyConfig.redirects.push({ from: `${basePath}/:locale/_next/static/*`, to: `/static/:splat`, status: 200 });
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
exports.generateStaticRedirects = generateStaticRedirects;
|
|
40
54
|
/**
|
|
41
55
|
* Routes that match middleware need to always use the SSR function
|
|
42
56
|
* This generates a rewrite for every middleware in every locale, both with and without a splat
|
|
@@ -141,6 +155,7 @@ const generateDynamicRewrites = ({ dynamicRoutes, prerenderedDynamicRoutes, midd
|
|
|
141
155
|
const generateRedirects = async ({ netlifyConfig, nextConfig: { i18n, basePath, trailingSlash, appDir }, buildId, apiRoutes, }) => {
|
|
142
156
|
const { dynamicRoutes: prerenderedDynamicRoutes, routes: prerenderedStaticRoutes } = await (0, fs_extra_1.readJSON)((0, pathe_1.join)(netlifyConfig.build.publish, 'prerender-manifest.json'));
|
|
143
157
|
const { dynamicRoutes, staticRoutes } = await (0, fs_extra_1.readJSON)((0, pathe_1.join)(netlifyConfig.build.publish, 'routes-manifest.json'));
|
|
158
|
+
netlifyConfig.redirects.push(...generateHiddenPathRedirects({ basePath }));
|
|
144
159
|
if (i18n && i18n.localeDetection !== false) {
|
|
145
160
|
netlifyConfig.redirects.push(...generateLocaleRedirects({ i18n, basePath, trailingSlash }));
|
|
146
161
|
}
|
package/lib/index.js
CHANGED
|
@@ -44,14 +44,10 @@ const plugin = {
|
|
|
44
44
|
}
|
|
45
45
|
const { publish } = netlifyConfig.build;
|
|
46
46
|
(0, verification_1.checkNextSiteHasBuilt)({ publish, failBuild });
|
|
47
|
-
const { appDir, basePath, i18n, images, target, ignore, trailingSlash, outdir, experimental
|
|
47
|
+
const { appDir, basePath, i18n, images, target, ignore, trailingSlash, outdir, experimental } = await (0, config_1.getNextConfig)({
|
|
48
48
|
publish,
|
|
49
49
|
failBuild,
|
|
50
50
|
});
|
|
51
|
-
const dotNextDir = (0, path_1.join)(appDir, distDir);
|
|
52
|
-
// This is the *generated* publish dir. The user specifies .next, be we actually use this subdirectory
|
|
53
|
-
const publishDir = (0, path_1.join)(dotNextDir, 'dist');
|
|
54
|
-
await (0, fs_extra_1.ensureDir)(publishDir);
|
|
55
51
|
await (0, edge_1.cleanupEdgeFunctions)(constants);
|
|
56
52
|
const middlewareManifest = await (0, edge_1.loadMiddlewareManifest)(netlifyConfig);
|
|
57
53
|
if ((middlewareManifest === null || middlewareManifest === void 0 ? void 0 : middlewareManifest.functions) &&
|
|
@@ -73,7 +69,7 @@ const plugin = {
|
|
|
73
69
|
`));
|
|
74
70
|
}
|
|
75
71
|
if ((0, utils_1.isNextAuthInstalled)()) {
|
|
76
|
-
const config = await (0, config_1.getRequiredServerFiles)(
|
|
72
|
+
const config = await (0, config_1.getRequiredServerFiles)(publish);
|
|
77
73
|
const userDefinedNextAuthUrl = config.config.env.NEXTAUTH_URL;
|
|
78
74
|
if (userDefinedNextAuthUrl) {
|
|
79
75
|
console.log(`NextAuth package detected, NEXTAUTH_URL environment variable set by user in next.config.js to ${userDefinedNextAuthUrl}`);
|
|
@@ -83,7 +79,7 @@ const plugin = {
|
|
|
83
79
|
const nextAuthUrl = `${process.env.NEXTAUTH_URL}${basePath}`;
|
|
84
80
|
console.log(`NextAuth package detected, NEXTAUTH_URL environment variable set by user in Netlify configuration to ${nextAuthUrl}`);
|
|
85
81
|
config.config.env.NEXTAUTH_URL = nextAuthUrl;
|
|
86
|
-
await (0, config_1.updateRequiredServerFiles)(
|
|
82
|
+
await (0, config_1.updateRequiredServerFiles)(publish, config);
|
|
87
83
|
}
|
|
88
84
|
else {
|
|
89
85
|
// Using the deploy prime url in production leads to issues because the unique deploy ID is part of the generated URL
|
|
@@ -91,20 +87,23 @@ const plugin = {
|
|
|
91
87
|
const nextAuthUrl = `${process.env.CONTEXT === 'production' ? process.env.URL : process.env.DEPLOY_PRIME_URL}${basePath}`;
|
|
92
88
|
console.log(`NextAuth package detected, setting NEXTAUTH_URL environment variable to ${nextAuthUrl}`);
|
|
93
89
|
config.config.env.NEXTAUTH_URL = nextAuthUrl;
|
|
94
|
-
await (0, config_1.updateRequiredServerFiles)(
|
|
90
|
+
await (0, config_1.updateRequiredServerFiles)(publish, config);
|
|
95
91
|
}
|
|
96
92
|
}
|
|
97
|
-
const buildId = (0, fs_extra_1.readFileSync)((0, path_1.join)(
|
|
98
|
-
await (0, config_1.configureHandlerFunctions)({ netlifyConfig, ignore, publish: (0, path_1.relative)(process.cwd(),
|
|
99
|
-
const apiRoutes = await (0, functions_1.getExtendedApiRouteConfigs)(
|
|
93
|
+
const buildId = (0, fs_extra_1.readFileSync)((0, path_1.join)(publish, 'BUILD_ID'), 'utf8').trim();
|
|
94
|
+
await (0, config_1.configureHandlerFunctions)({ netlifyConfig, ignore, publish: (0, path_1.relative)(process.cwd(), publish) });
|
|
95
|
+
const apiRoutes = await (0, functions_1.getExtendedApiRouteConfigs)(publish, appDir);
|
|
100
96
|
await (0, functions_1.generateFunctions)(constants, appDir, apiRoutes);
|
|
101
97
|
await (0, functions_1.generatePagesResolver)({ target, constants });
|
|
102
|
-
await (0, files_1.movePublicFiles)({ appDir, outdir,
|
|
98
|
+
await (0, files_1.movePublicFiles)({ appDir, outdir, publish });
|
|
103
99
|
await (0, files_1.patchNextFiles)(appDir);
|
|
104
100
|
if (!(0, destr_1.default)(process.env.SERVE_STATIC_FILES_FROM_ORIGIN)) {
|
|
105
|
-
await (0, files_1.moveStaticPages)({
|
|
101
|
+
await (0, files_1.moveStaticPages)({ target, netlifyConfig, i18n, basePath });
|
|
106
102
|
}
|
|
107
|
-
await (0,
|
|
103
|
+
await (0, redirects_1.generateStaticRedirects)({
|
|
104
|
+
netlifyConfig,
|
|
105
|
+
nextConfig: { basePath, i18n },
|
|
106
|
+
});
|
|
108
107
|
await (0, functions_1.setupImageFunction)({
|
|
109
108
|
constants,
|
|
110
109
|
imageconfig: images,
|
|
@@ -121,8 +120,8 @@ const plugin = {
|
|
|
121
120
|
});
|
|
122
121
|
await (0, edge_1.writeEdgeFunctions)(netlifyConfig);
|
|
123
122
|
},
|
|
124
|
-
async onPostBuild({ netlifyConfig, utils: { status, cache, functions, build: { failBuild }, }, constants: { FUNCTIONS_DIST
|
|
125
|
-
await (0, cache_1.saveCache)({ cache, publish
|
|
123
|
+
async onPostBuild({ netlifyConfig: { build: { publish }, redirects, headers, }, utils: { status, cache, functions, build: { failBuild }, }, constants: { FUNCTIONS_DIST }, }) {
|
|
124
|
+
await (0, cache_1.saveCache)({ cache, publish });
|
|
126
125
|
if ((0, utils_1.shouldSkip)()) {
|
|
127
126
|
status.show({
|
|
128
127
|
title: 'Next Runtime did not run',
|
|
@@ -134,13 +133,12 @@ const plugin = {
|
|
|
134
133
|
}
|
|
135
134
|
await (0, verification_1.checkForOldFunctions)({ functions });
|
|
136
135
|
await (0, verification_1.checkZipSize)((0, path_1.join)(FUNCTIONS_DIST, `${constants_1.ODB_FUNCTION_NAME}.zip`));
|
|
137
|
-
const nextConfig = await (0, config_1.getNextConfig)({ publish
|
|
136
|
+
const nextConfig = await (0, config_1.getNextConfig)({ publish, failBuild });
|
|
138
137
|
const { basePath, appDir } = nextConfig;
|
|
139
|
-
(0, config_1.generateCustomHeaders)(nextConfig,
|
|
140
|
-
(0, verification_1.warnForProblematicUserRewrites)({ basePath, redirects
|
|
138
|
+
(0, config_1.generateCustomHeaders)(nextConfig, headers);
|
|
139
|
+
(0, verification_1.warnForProblematicUserRewrites)({ basePath, redirects });
|
|
141
140
|
(0, verification_1.warnForRootRedirects)({ appDir });
|
|
142
141
|
await (0, functions_1.warnOnApiRoutes)({ FUNCTIONS_DIST });
|
|
143
|
-
netlifyConfig.build.publish = (0, path_1.join)(PUBLISH_DIR, 'dist');
|
|
144
142
|
},
|
|
145
143
|
};
|
|
146
144
|
// The types haven't been updated yet
|
|
@@ -92,6 +92,13 @@ const makeHandler = (conf, app, pageRoot, staticManifest = [], mode = 'ssr') =>
|
|
|
92
92
|
const { headers, ...result } = await getBridge(event).launcher(event, context);
|
|
93
93
|
// Convert all headers to multiValueHeaders
|
|
94
94
|
const multiValueHeaders = getMultiValueHeaders(headers);
|
|
95
|
+
if (event.headers['x-next-debug-logging']) {
|
|
96
|
+
const response = {
|
|
97
|
+
headers: multiValueHeaders,
|
|
98
|
+
statusCode: result.statusCode,
|
|
99
|
+
};
|
|
100
|
+
console.log('Origin response:', JSON.stringify(response, null, 2));
|
|
101
|
+
}
|
|
95
102
|
if ((_b = (_a = multiValueHeaders['set-cookie']) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.includes('__prerender_bypass')) {
|
|
96
103
|
delete multiValueHeaders.etag;
|
|
97
104
|
multiValueHeaders['cache-control'] = ['no-cache'];
|