@netlify/plugin-nextjs 4.7.1 → 4.9.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 +66 -2
- package/lib/helpers/functions.js +2 -1
- package/lib/index.js +18 -4
- package/lib/templates/ipx.js +1 -0
- package/package.json +3 -3
- package/src/templates/edge/runtime.ts +1 -1
package/lib/helpers/config.js
CHANGED
|
@@ -3,11 +3,12 @@ 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.configureHandlerFunctions = exports.updateRequiredServerFiles = exports.getRequiredServerFiles = exports.getNextConfig = void 0;
|
|
6
|
+
exports.generateCustomHeaders = exports.configureHandlerFunctions = exports.updateRequiredServerFiles = exports.getRequiredServerFiles = exports.getNextConfig = void 0;
|
|
7
7
|
const fs_extra_1 = require("fs-extra");
|
|
8
8
|
const pathe_1 = require("pathe");
|
|
9
9
|
const slash_1 = __importDefault(require("slash"));
|
|
10
10
|
const constants_1 = require("../constants");
|
|
11
|
+
const ROUTES_MANIFEST_FILE = 'routes-manifest.json';
|
|
11
12
|
const defaultFailBuild = (message, { error }) => {
|
|
12
13
|
throw new Error(`${message}\n${error && error.stack}`);
|
|
13
14
|
};
|
|
@@ -19,7 +20,9 @@ const getNextConfig = async function getNextConfig({ publish, failBuild = defaul
|
|
|
19
20
|
// @ts-ignore
|
|
20
21
|
return failBuild('Error loading your Next config');
|
|
21
22
|
}
|
|
22
|
-
|
|
23
|
+
const routesManifest = await (0, fs_extra_1.readJSON)((0, pathe_1.join)(publish, ROUTES_MANIFEST_FILE));
|
|
24
|
+
// If you need access to other manifest files, you can add them here as well
|
|
25
|
+
return { ...config, appDir, ignore, routesManifest };
|
|
23
26
|
}
|
|
24
27
|
catch (error) {
|
|
25
28
|
return failBuild('Error loading your Next config', { error });
|
|
@@ -77,3 +80,64 @@ const configureHandlerFunctions = ({ netlifyConfig, publish, ignore = [] }) => {
|
|
|
77
80
|
});
|
|
78
81
|
};
|
|
79
82
|
exports.configureHandlerFunctions = configureHandlerFunctions;
|
|
83
|
+
const buildHeader = (buildHeaderParams) => {
|
|
84
|
+
const { path, headers } = buildHeaderParams;
|
|
85
|
+
return {
|
|
86
|
+
for: path,
|
|
87
|
+
values: headers.reduce((builtHeaders, { key, value }) => {
|
|
88
|
+
builtHeaders[key] = value;
|
|
89
|
+
return builtHeaders;
|
|
90
|
+
}, {}),
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
// Replace the pattern :path* at the end of a path with * since it's a named splat which the Netlify
|
|
94
|
+
// configuration does not support.
|
|
95
|
+
const sanitizePath = (path) => path.replace(/:[^*/]+\*$/, '*');
|
|
96
|
+
/**
|
|
97
|
+
* Persist NEXT.js custom headers to the Netlify configuration so the headers work with static files
|
|
98
|
+
* See {@link https://nextjs.org/docs/api-reference/next.config.js/headers} for more information on custom
|
|
99
|
+
* headers in Next.js
|
|
100
|
+
*
|
|
101
|
+
* @param nextConfig - The NextJS configuration
|
|
102
|
+
* @param netlifyHeaders - Existing headers that are already configured in the Netlify configuration
|
|
103
|
+
*/
|
|
104
|
+
const generateCustomHeaders = (nextConfig, netlifyHeaders = []) => {
|
|
105
|
+
var _a;
|
|
106
|
+
// The routesManifest is the contents of the routes-manifest.json file which will already contain the generated
|
|
107
|
+
// header paths which take locales and base path into account since this runs after the build. The routes-manifest.json
|
|
108
|
+
// file is located at demos/default/.next/routes-manifest.json once you've build the demo site.
|
|
109
|
+
const { routesManifest: { headers: customHeaders = [] }, i18n, } = nextConfig;
|
|
110
|
+
// Skip `has` based custom headers as they have more complex dynamic conditional header logic
|
|
111
|
+
// that currently isn't supported by the Netlify configuration.
|
|
112
|
+
// Also, this type of dynamic header logic is most likely not for SSG pages.
|
|
113
|
+
for (const { source, headers, locale: localeEnabled } of customHeaders.filter((customHeader) => !customHeader.has)) {
|
|
114
|
+
// Explicitly checking false to make the check simpler.
|
|
115
|
+
// Locale specific paths are excluded only if localeEnabled is false. There is no true value for localeEnabled. It's either
|
|
116
|
+
// false or undefined, where undefined means it's true.
|
|
117
|
+
//
|
|
118
|
+
// Again, the routesManifest has already been generated taking locales into account, but the check is required
|
|
119
|
+
// so the paths can be properly set in the Netlify configuration.
|
|
120
|
+
const useLocale = ((_a = i18n === null || i18n === void 0 ? void 0 : i18n.locales) === null || _a === void 0 ? void 0 : _a.length) > 0 && localeEnabled !== false;
|
|
121
|
+
if (useLocale) {
|
|
122
|
+
const { locales } = i18n;
|
|
123
|
+
const joinedLocales = locales.join('|');
|
|
124
|
+
/**
|
|
125
|
+
* converts e.g.
|
|
126
|
+
* /:nextInternalLocale(en|fr)/some-path
|
|
127
|
+
* to a path for each locale
|
|
128
|
+
* /en/some-path and /fr/some-path as well as /some-path (default locale)
|
|
129
|
+
*/
|
|
130
|
+
const defaultLocalePath = sanitizePath(source).replace(`/:nextInternalLocale(${joinedLocales})`, '');
|
|
131
|
+
netlifyHeaders.push(buildHeader({ path: defaultLocalePath, headers }));
|
|
132
|
+
for (const locale of locales) {
|
|
133
|
+
const path = sanitizePath(source).replace(`:nextInternalLocale(${joinedLocales})`, locale);
|
|
134
|
+
netlifyHeaders.push(buildHeader({ path, headers }));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
const path = sanitizePath(source);
|
|
139
|
+
netlifyHeaders.push(buildHeader({ path, headers }));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
exports.generateCustomHeaders = generateCustomHeaders;
|
package/lib/helpers/functions.js
CHANGED
|
@@ -40,7 +40,7 @@ const generatePagesResolver = async ({ constants: { INTERNAL_FUNCTIONS_SRC, FUNC
|
|
|
40
40
|
};
|
|
41
41
|
exports.generatePagesResolver = generatePagesResolver;
|
|
42
42
|
// Move our next/image function into the correct functions directory
|
|
43
|
-
const setupImageFunction = async ({ constants: { INTERNAL_FUNCTIONS_SRC, FUNCTIONS_SRC = constants_1.DEFAULT_FUNCTIONS_SRC }, imageconfig = {}, netlifyConfig, basePath, }) => {
|
|
43
|
+
const setupImageFunction = async ({ constants: { INTERNAL_FUNCTIONS_SRC, FUNCTIONS_SRC = constants_1.DEFAULT_FUNCTIONS_SRC }, imageconfig = {}, netlifyConfig, basePath, remotePatterns, }) => {
|
|
44
44
|
const functionsPath = INTERNAL_FUNCTIONS_SRC || FUNCTIONS_SRC;
|
|
45
45
|
const functionName = `${constants_1.IMAGE_FUNCTION_NAME}.js`;
|
|
46
46
|
const functionDirectory = (0, pathe_1.join)(functionsPath, constants_1.IMAGE_FUNCTION_NAME);
|
|
@@ -48,6 +48,7 @@ const setupImageFunction = async ({ constants: { INTERNAL_FUNCTIONS_SRC, FUNCTIO
|
|
|
48
48
|
await (0, fs_extra_1.writeJSON)((0, pathe_1.join)(functionDirectory, 'imageconfig.json'), {
|
|
49
49
|
...imageconfig,
|
|
50
50
|
basePath: [basePath, constants_1.IMAGE_FUNCTION_NAME].join('/'),
|
|
51
|
+
remotePatterns,
|
|
51
52
|
});
|
|
52
53
|
await (0, fs_extra_1.copyFile)((0, pathe_1.join)(__dirname, '..', '..', 'lib', 'templates', 'ipx.js'), (0, pathe_1.join)(functionDirectory, functionName));
|
|
53
54
|
const imagePath = imageconfig.path || '/_next/image';
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/* eslint-disable max-lines */
|
|
3
4
|
const path_1 = require("path");
|
|
4
5
|
const chalk_1 = require("chalk");
|
|
5
6
|
const fs_extra_1 = require("fs-extra");
|
|
@@ -38,10 +39,14 @@ const plugin = {
|
|
|
38
39
|
}
|
|
39
40
|
const { publish } = netlifyConfig.build;
|
|
40
41
|
(0, verification_1.checkNextSiteHasBuilt)({ publish, failBuild });
|
|
41
|
-
|
|
42
|
+
let experimentalRemotePatterns = [];
|
|
43
|
+
const { appDir, basePath, i18n, images, target, ignore, trailingSlash, outdir, experimental } = await (0, config_1.getNextConfig)({
|
|
42
44
|
publish,
|
|
43
45
|
failBuild,
|
|
44
46
|
});
|
|
47
|
+
if (experimental.images) {
|
|
48
|
+
experimentalRemotePatterns = experimental.images.remotePatterns || [];
|
|
49
|
+
}
|
|
45
50
|
if ((0, utils_1.isNextAuthInstalled)()) {
|
|
46
51
|
const config = await (0, config_1.getRequiredServerFiles)(publish);
|
|
47
52
|
const userDefinedNextAuthUrl = config.config.env.NEXTAUTH_URL;
|
|
@@ -68,7 +73,13 @@ const plugin = {
|
|
|
68
73
|
netlifyConfig,
|
|
69
74
|
nextConfig: { basePath, i18n },
|
|
70
75
|
});
|
|
71
|
-
await (0, functions_1.setupImageFunction)({
|
|
76
|
+
await (0, functions_1.setupImageFunction)({
|
|
77
|
+
constants,
|
|
78
|
+
imageconfig: images,
|
|
79
|
+
netlifyConfig,
|
|
80
|
+
basePath,
|
|
81
|
+
remotePatterns: experimentalRemotePatterns,
|
|
82
|
+
});
|
|
72
83
|
await (0, redirects_1.generateRedirects)({
|
|
73
84
|
netlifyConfig,
|
|
74
85
|
nextConfig: { basePath, i18n, trailingSlash, appDir },
|
|
@@ -83,7 +94,7 @@ const plugin = {
|
|
|
83
94
|
await (0, edge_1.updateConfig)(publish);
|
|
84
95
|
}
|
|
85
96
|
},
|
|
86
|
-
async onPostBuild({ netlifyConfig: { build: { publish }, redirects, }, utils: { status, cache, functions, build: { failBuild }, }, constants: { FUNCTIONS_DIST }, }) {
|
|
97
|
+
async onPostBuild({ netlifyConfig: { build: { publish }, redirects, headers, }, utils: { status, cache, functions, build: { failBuild }, }, constants: { FUNCTIONS_DIST }, }) {
|
|
87
98
|
await (0, cache_1.saveCache)({ cache, publish });
|
|
88
99
|
if ((0, utils_1.shouldSkip)()) {
|
|
89
100
|
status.show({
|
|
@@ -96,10 +107,13 @@ const plugin = {
|
|
|
96
107
|
}
|
|
97
108
|
await (0, verification_1.checkForOldFunctions)({ functions });
|
|
98
109
|
await (0, verification_1.checkZipSize)((0, path_1.join)(FUNCTIONS_DIST, `${constants_1.ODB_FUNCTION_NAME}.zip`));
|
|
99
|
-
const
|
|
110
|
+
const nextConfig = await (0, config_1.getNextConfig)({ publish, failBuild });
|
|
111
|
+
const { basePath, appDir } = nextConfig;
|
|
112
|
+
(0, config_1.generateCustomHeaders)(nextConfig, headers);
|
|
100
113
|
(0, verification_1.warnForProblematicUserRewrites)({ basePath, redirects });
|
|
101
114
|
(0, verification_1.warnForRootRedirects)({ appDir });
|
|
102
115
|
await (0, files_1.unpatchNextFiles)(basePath);
|
|
103
116
|
},
|
|
104
117
|
};
|
|
105
118
|
module.exports = plugin;
|
|
119
|
+
/* eslint-enable max-lines */
|
package/lib/templates/ipx.js
CHANGED
|
@@ -7,5 +7,6 @@ const imageconfig_json_1 = require("./imageconfig.json");
|
|
|
7
7
|
exports.handler = (0, ipx_1.createIPXHandler)({
|
|
8
8
|
basePath: imageconfig_json_1.basePath,
|
|
9
9
|
domains: imageconfig_json_1.domains,
|
|
10
|
+
remotePatterns: imageconfig_json_1.remotePatterns,
|
|
10
11
|
});
|
|
11
12
|
/* eslint-enable node/no-missing-import, import/no-unresolved, @typescript-eslint/ban-ts-comment */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/plugin-nextjs",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.9.1",
|
|
4
4
|
"description": "Run Next.js seamlessly on Netlify",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"files": [
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@netlify/functions": "^1.0.0",
|
|
13
|
-
"@netlify/ipx": "^1.0
|
|
13
|
+
"@netlify/ipx": "^1.1.0",
|
|
14
14
|
"@vercel/node-bridge": "^2.1.0",
|
|
15
15
|
"chalk": "^4.1.2",
|
|
16
16
|
"fs-extra": "^10.0.0",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@types/fs-extra": "^9.0.13",
|
|
33
33
|
"@types/jest": "^27.4.1",
|
|
34
34
|
"@types/node": "^17.0.25",
|
|
35
|
-
"next": "^12.1.
|
|
35
|
+
"next": "^12.1.7-canary.33",
|
|
36
36
|
"npm-run-all": "^4.1.5",
|
|
37
37
|
"typescript": "^4.6.3"
|
|
38
38
|
},
|