@netlify/plugin-nextjs 4.16.0 → 4.17.1-runtime.2
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/cache.js +1 -1
- package/lib/helpers/dev.js +43 -0
- package/lib/helpers/edge.js +24 -8
- package/lib/helpers/files.js +5 -5
- package/lib/helpers/utils.js +1 -1
- package/lib/helpers/verification.js +3 -3
- package/lib/index.js +49 -17
- package/manifest.yml +1 -1
- package/package.json +8 -6
- package/src/templates/edge/next-dev.js +86 -0
- package/src/templates/edge/runtime.ts +4 -0
- package/src/templates/edge/utils.ts +22 -1
package/lib/helpers/cache.js
CHANGED
|
@@ -9,7 +9,7 @@ const findDistDir = (publish) => {
|
|
|
9
9
|
if (!(0, utils_1.shouldSkip)()) {
|
|
10
10
|
return publish;
|
|
11
11
|
}
|
|
12
|
-
// In this situation, the user has disabled the
|
|
12
|
+
// In this situation, the user has disabled the next-runtime, which means that they might be using next export,
|
|
13
13
|
// so we'll look in a few places to find the site root. This allows us to find the .next directory.
|
|
14
14
|
for (const root of [(0, path_1.resolve)(publish, '..'), (0, path_1.resolve)(publish, '..', '..')]) {
|
|
15
15
|
if ((0, fs_1.existsSync)((0, path_1.join)(root, 'next.config.js'))) {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.onPreDev = void 0;
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const execa_1 = __importDefault(require("execa"));
|
|
9
|
+
const fs_extra_1 = require("fs-extra");
|
|
10
|
+
const edge_1 = require("./edge");
|
|
11
|
+
const files_1 = require("./files");
|
|
12
|
+
// The types haven't been updated yet
|
|
13
|
+
const onPreDev = async ({ constants, netlifyConfig }) => {
|
|
14
|
+
var _a;
|
|
15
|
+
const base = (_a = netlifyConfig.build.base) !== null && _a !== void 0 ? _a : process.cwd();
|
|
16
|
+
// Need to patch the files, because build might not have been run
|
|
17
|
+
await (0, files_1.patchNextFiles)(base);
|
|
18
|
+
// Clean up old functions
|
|
19
|
+
await (0, fs_extra_1.unlink)((0, path_1.resolve)('.netlify', 'middleware.js')).catch(() => {
|
|
20
|
+
// Ignore if it doesn't exist
|
|
21
|
+
});
|
|
22
|
+
await (0, edge_1.writeDevEdgeFunction)(constants);
|
|
23
|
+
if (!(0, fs_extra_1.existsSync)((0, path_1.resolve)(base, 'middleware.ts')) && !(0, fs_extra_1.existsSync)((0, path_1.resolve)(base, 'middleware.js'))) {
|
|
24
|
+
console.log("No middleware found. Create a 'middleware.ts' or 'middleware.js' file in your project root to add custom middleware.");
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.log('Watching for changes in Next.js middleware...');
|
|
28
|
+
}
|
|
29
|
+
// Eventually we might want to do this via esbuild's API, but for now the CLI works fine
|
|
30
|
+
const childProcess = (0, execa_1.default)(`esbuild`, [
|
|
31
|
+
`--bundle`,
|
|
32
|
+
`--outdir=${(0, path_1.resolve)('.netlify')}`,
|
|
33
|
+
`--format=esm`,
|
|
34
|
+
'--watch',
|
|
35
|
+
// Watch for both, because it can have either ts or js
|
|
36
|
+
(0, path_1.resolve)(base, 'middleware.ts'),
|
|
37
|
+
(0, path_1.resolve)(base, 'middleware.js'),
|
|
38
|
+
]);
|
|
39
|
+
childProcess.stdout.pipe(process.stdout);
|
|
40
|
+
childProcess.stderr.pipe(process.stderr);
|
|
41
|
+
// Don't return the promise because we don't want to wait for the child process to finish
|
|
42
|
+
};
|
|
43
|
+
exports.onPreDev = onPreDev;
|
package/lib/helpers/edge.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.enableEdgeInNextConfig = exports.writeEdgeFunctions = exports.writeDevEdgeFunction = exports.loadMiddlewareManifest = void 0;
|
|
4
4
|
/* eslint-disable max-lines */
|
|
5
5
|
const fs_1 = require("fs");
|
|
6
6
|
const path_1 = require("path");
|
|
@@ -67,6 +67,25 @@ const writeEdgeFunction = async ({ edgeFunctionDefinition, edgeFunctionRoot, net
|
|
|
67
67
|
pattern: stripLookahead(edgeFunctionDefinition.regexp),
|
|
68
68
|
};
|
|
69
69
|
};
|
|
70
|
+
const writeDevEdgeFunction = async ({ INTERNAL_EDGE_FUNCTIONS_SRC = '.netlify/edge-functions', }) => {
|
|
71
|
+
const manifest = {
|
|
72
|
+
functions: [
|
|
73
|
+
{
|
|
74
|
+
function: 'next-dev',
|
|
75
|
+
path: '/*',
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
version: 1,
|
|
79
|
+
};
|
|
80
|
+
const edgeFunctionRoot = (0, path_1.resolve)(INTERNAL_EDGE_FUNCTIONS_SRC);
|
|
81
|
+
await (0, fs_extra_1.emptyDir)(edgeFunctionRoot);
|
|
82
|
+
await (0, fs_extra_1.writeJson)((0, path_1.join)(edgeFunctionRoot, 'manifest.json'), manifest);
|
|
83
|
+
const edgeFunctionDir = (0, path_1.join)(edgeFunctionRoot, 'next-dev');
|
|
84
|
+
await (0, fs_extra_1.ensureDir)(edgeFunctionDir);
|
|
85
|
+
await copyEdgeSourceFile({ edgeFunctionDir, file: 'next-dev.js', target: 'index.js' });
|
|
86
|
+
await copyEdgeSourceFile({ edgeFunctionDir, file: 'utils.ts' });
|
|
87
|
+
};
|
|
88
|
+
exports.writeDevEdgeFunction = writeDevEdgeFunction;
|
|
70
89
|
/**
|
|
71
90
|
* Writes Edge Functions for the Next middleware
|
|
72
91
|
*/
|
|
@@ -78,9 +97,7 @@ const writeEdgeFunctions = async (netlifyConfig) => {
|
|
|
78
97
|
const edgeFunctionRoot = (0, path_1.resolve)('.netlify', 'edge-functions');
|
|
79
98
|
await (0, fs_extra_1.emptyDir)(edgeFunctionRoot);
|
|
80
99
|
if (!process.env.NEXT_DISABLE_EDGE_IMAGES) {
|
|
81
|
-
|
|
82
|
-
console.log('Using Netlify Edge Functions for image format detection. Set env var "NEXT_DISABLE_EDGE_IMAGES=true" to disable.');
|
|
83
|
-
}
|
|
100
|
+
console.log('Using Netlify Edge Functions for image format detection. Set env var "NEXT_DISABLE_EDGE_IMAGES=true" to disable.');
|
|
84
101
|
const edgeFunctionDir = (0, path_1.join)(edgeFunctionRoot, 'ipx');
|
|
85
102
|
await (0, fs_extra_1.ensureDir)(edgeFunctionDir);
|
|
86
103
|
await copyEdgeSourceFile({ edgeFunctionDir, file: 'ipx.ts', target: 'index.ts' });
|
|
@@ -90,7 +107,7 @@ const writeEdgeFunctions = async (netlifyConfig) => {
|
|
|
90
107
|
path: '/_next/image*',
|
|
91
108
|
});
|
|
92
109
|
}
|
|
93
|
-
if (process.env.
|
|
110
|
+
if (!process.env.NEXT_DISABLE_NETLIFY_EDGE) {
|
|
94
111
|
const middlewareManifest = await (0, exports.loadMiddlewareManifest)(netlifyConfig);
|
|
95
112
|
if (!middlewareManifest) {
|
|
96
113
|
console.error("Couldn't find the middleware manifest");
|
|
@@ -121,11 +138,10 @@ const writeEdgeFunctions = async (netlifyConfig) => {
|
|
|
121
138
|
await (0, fs_extra_1.writeJson)((0, path_1.join)(edgeFunctionRoot, 'manifest.json'), manifest);
|
|
122
139
|
};
|
|
123
140
|
exports.writeEdgeFunctions = writeEdgeFunctions;
|
|
124
|
-
const
|
|
141
|
+
const enableEdgeInNextConfig = async (publish) => {
|
|
125
142
|
const configFile = (0, path_1.join)(publish, 'required-server-files.json');
|
|
126
143
|
const config = await (0, fs_extra_1.readJSON)(configFile);
|
|
127
|
-
config.config.env.NEXT_USE_NETLIFY_EDGE = 'true';
|
|
128
144
|
await (0, fs_extra_1.writeJSON)(configFile, config);
|
|
129
145
|
};
|
|
130
|
-
exports.
|
|
146
|
+
exports.enableEdgeInNextConfig = enableEdgeInNextConfig;
|
|
131
147
|
/* eslint-enable max-lines */
|
package/lib/helpers/files.js
CHANGED
|
@@ -54,7 +54,7 @@ const matchesRewrite = (file, rewrites) => {
|
|
|
54
54
|
exports.matchesRewrite = matchesRewrite;
|
|
55
55
|
const getMiddleware = async (publish) => {
|
|
56
56
|
var _a;
|
|
57
|
-
if (process.env.
|
|
57
|
+
if (!process.env.NEXT_DISABLE_NETLIFY_EDGE) {
|
|
58
58
|
return [];
|
|
59
59
|
}
|
|
60
60
|
const manifestPath = (0, pathe_1.join)(publish, 'server', 'middleware-manifest.json');
|
|
@@ -276,19 +276,19 @@ const baseServerReplacements = [
|
|
|
276
276
|
const nextServerReplacements = [
|
|
277
277
|
[
|
|
278
278
|
`getMiddlewareManifest() {\n if (this.minimalMode) return null;`,
|
|
279
|
-
`getMiddlewareManifest() {\n if (this.minimalMode || process.env.
|
|
279
|
+
`getMiddlewareManifest() {\n if (this.minimalMode || !process.env.NEXT_DISABLE_NETLIFY_EDGE) return null;`,
|
|
280
280
|
],
|
|
281
281
|
[
|
|
282
282
|
`generateCatchAllMiddlewareRoute(devReady) {\n if (this.minimalMode) return []`,
|
|
283
|
-
`generateCatchAllMiddlewareRoute(devReady) {\n if (this.minimalMode || process.env.
|
|
283
|
+
`generateCatchAllMiddlewareRoute(devReady) {\n if (this.minimalMode || !process.env.NEXT_DISABLE_NETLIFY_EDGE) return [];`,
|
|
284
284
|
],
|
|
285
285
|
[
|
|
286
286
|
`generateCatchAllMiddlewareRoute() {\n if (this.minimalMode) return undefined;`,
|
|
287
|
-
`generateCatchAllMiddlewareRoute() {\n if (this.minimalMode || process.env.
|
|
287
|
+
`generateCatchAllMiddlewareRoute() {\n if (this.minimalMode || !process.env.NEXT_DISABLE_NETLIFY_EDGE) return undefined;`,
|
|
288
288
|
],
|
|
289
289
|
[
|
|
290
290
|
`getMiddlewareManifest() {\n if (this.minimalMode) {`,
|
|
291
|
-
`getMiddlewareManifest() {\n if (!this.minimalMode &&
|
|
291
|
+
`getMiddlewareManifest() {\n if (!this.minimalMode && process.env.NEXT_DISABLE_NETLIFY_EDGE) {`,
|
|
292
292
|
],
|
|
293
293
|
];
|
|
294
294
|
const patchNextFiles = async (root) => {
|
package/lib/helpers/utils.js
CHANGED
|
@@ -136,7 +136,7 @@ const findModuleFromBase = ({ paths, candidates }) => {
|
|
|
136
136
|
exports.findModuleFromBase = findModuleFromBase;
|
|
137
137
|
const isNextAuthInstalled = () => {
|
|
138
138
|
try {
|
|
139
|
-
// eslint-disable-next-line import/no-unassigned-import, import/no-
|
|
139
|
+
// eslint-disable-next-line import/no-unassigned-import, import/no-extraneous-dependencies, n/no-extraneous-require
|
|
140
140
|
require('next-auth');
|
|
141
141
|
return true;
|
|
142
142
|
}
|
|
@@ -42,7 +42,7 @@ const verifyNetlifyBuildVersion = ({ IS_LOCAL, NETLIFY_BUILD_VERSION, failBuild,
|
|
|
42
42
|
// 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
|
|
43
43
|
if (IS_LOCAL && !(0, semver_1.satisfies)(NETLIFY_BUILD_VERSION, REQUIRED_BUILD_VERSION, { includePrerelease: true })) {
|
|
44
44
|
return failBuild((0, outdent_1.outdent) `
|
|
45
|
-
This version of the
|
|
45
|
+
This version of the Next Runtime requires netlify-cli@6.12.4 or higher. Please upgrade and try again.
|
|
46
46
|
You can do this by running: "npm install -g netlify-cli@latest" or "yarn global add netlify-cli@latest"
|
|
47
47
|
`);
|
|
48
48
|
}
|
|
@@ -136,7 +136,7 @@ exports.checkZipSize = checkZipSize;
|
|
|
136
136
|
const getProblematicUserRewrites = ({ redirects, basePath, }) => {
|
|
137
137
|
const userRewrites = [];
|
|
138
138
|
for (const redirect of redirects) {
|
|
139
|
-
// This is the first of the
|
|
139
|
+
// This is the first of the runtime-generated redirects so we can stop checking
|
|
140
140
|
if (redirect.from === `${basePath}/_next/static/*` && redirect.to === `/static/:splat` && redirect.status === 200) {
|
|
141
141
|
break;
|
|
142
142
|
}
|
|
@@ -159,7 +159,7 @@ const warnForProblematicUserRewrites = ({ redirects, basePath, }) => {
|
|
|
159
159
|
return;
|
|
160
160
|
}
|
|
161
161
|
console.log((0, chalk_1.yellowBright)((0, outdent_1.outdent) `
|
|
162
|
-
You have the following Netlify rewrite${userRewrites.length === 1 ? '' : 's'} that might cause conflicts with the Next.js
|
|
162
|
+
You have the following Netlify rewrite${userRewrites.length === 1 ? '' : 's'} that might cause conflicts with the Next.js Runtime:
|
|
163
163
|
|
|
164
164
|
${(0, chalk_1.reset)(userRewrites.map(({ from, to, status }) => `- ${from} ${to} ${status}`).join('\n'))}
|
|
165
165
|
|
package/lib/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const outdent_1 = require("outdent");
|
|
|
8
8
|
const constants_1 = require("./constants");
|
|
9
9
|
const cache_1 = require("./helpers/cache");
|
|
10
10
|
const config_1 = require("./helpers/config");
|
|
11
|
+
const dev_1 = require("./helpers/dev");
|
|
11
12
|
const edge_1 = require("./helpers/edge");
|
|
12
13
|
const files_1 = require("./helpers/files");
|
|
13
14
|
const functions_1 = require("./helpers/functions");
|
|
@@ -20,7 +21,7 @@ const plugin = {
|
|
|
20
21
|
const { publish } = netlifyConfig.build;
|
|
21
22
|
if ((0, utils_1.shouldSkip)()) {
|
|
22
23
|
await (0, cache_1.restoreCache)({ cache, publish });
|
|
23
|
-
console.log('Not running
|
|
24
|
+
console.log('Not running Next Runtime');
|
|
24
25
|
if ((0, fs_extra_1.existsSync)((0, path_1.join)(constants.INTERNAL_FUNCTIONS_SRC, constants_1.HANDLER_FUNCTION_NAME))) {
|
|
25
26
|
console.log(`Please ensure you remove any generated functions from ${constants.INTERNAL_FUNCTIONS_SRC}`);
|
|
26
27
|
}
|
|
@@ -34,7 +35,6 @@ const plugin = {
|
|
|
34
35
|
netlifyConfig.build.environment.NEXT_PRIVATE_TARGET = 'server';
|
|
35
36
|
},
|
|
36
37
|
async onBuild({ constants, netlifyConfig, utils: { build: { failBuild }, }, }) {
|
|
37
|
-
var _a;
|
|
38
38
|
if ((0, utils_1.shouldSkip)()) {
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
@@ -45,6 +45,28 @@ const plugin = {
|
|
|
45
45
|
publish,
|
|
46
46
|
failBuild,
|
|
47
47
|
});
|
|
48
|
+
const middlewareManifest = await (0, edge_1.loadMiddlewareManifest)(netlifyConfig);
|
|
49
|
+
let usingEdge = false;
|
|
50
|
+
if (Object.keys(middlewareManifest === null || middlewareManifest === void 0 ? void 0 : middlewareManifest.functions).length !== 0) {
|
|
51
|
+
usingEdge = true;
|
|
52
|
+
if (process.env.NEXT_DISABLE_NETLIFY_EDGE) {
|
|
53
|
+
failBuild((0, outdent_1.outdent) `
|
|
54
|
+
You are using Next.js experimental edge runtime, but have set NEXT_DISABLE_NETLIFY_EDGE to true. This is not supported.
|
|
55
|
+
To use edge runtime, remove the env var ${(0, chalk_1.bold) `NEXT_DISABLE_NETLIFY_EDGE`}.
|
|
56
|
+
`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (Object.keys(middlewareManifest === null || middlewareManifest === void 0 ? void 0 : middlewareManifest.middleware).length !== 0) {
|
|
60
|
+
usingEdge = true;
|
|
61
|
+
if (process.env.NEXT_DISABLE_NETLIFY_EDGE) {
|
|
62
|
+
console.log((0, chalk_1.redBright)((0, outdent_1.outdent) `
|
|
63
|
+
You are using Next.js Middleware without Netlify Edge Functions.
|
|
64
|
+
This is deprecated because it negatively affects performance and will disable ISR and static rendering.
|
|
65
|
+
It also disables advanced middleware features from @netlify/next
|
|
66
|
+
To get the best performance and use Netlify Edge Functions, remove the env var ${(0, chalk_1.bold) `NEXT_DISABLE_NETLIFY_EDGE`}.
|
|
67
|
+
`));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
48
70
|
if (experimental.images) {
|
|
49
71
|
experimentalRemotePatterns = experimental.images.remotePatterns || [];
|
|
50
72
|
}
|
|
@@ -87,29 +109,20 @@ const plugin = {
|
|
|
87
109
|
nextConfig: { basePath, i18n, trailingSlash, appDir },
|
|
88
110
|
buildId,
|
|
89
111
|
});
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
112
|
+
if (usingEdge) {
|
|
113
|
+
await (0, edge_1.writeEdgeFunctions)(netlifyConfig);
|
|
114
|
+
await (0, edge_1.enableEdgeInNextConfig)(publish);
|
|
93
115
|
console.log((0, outdent_1.outdent) `
|
|
94
|
-
✨ Deploying to ${(0, chalk_1.greenBright) `Netlify Edge Functions`} ✨
|
|
116
|
+
✨ Deploying middleware and functions to ${(0, chalk_1.greenBright) `Netlify Edge Functions`} ✨
|
|
95
117
|
This feature is in beta. Please share your feedback here: https://ntl.fyi/next-netlify-edge
|
|
96
118
|
`);
|
|
97
|
-
await (0, edge_1.updateConfig)(publish);
|
|
98
|
-
}
|
|
99
|
-
const middlewareManifest = await (0, edge_1.loadMiddlewareManifest)(netlifyConfig);
|
|
100
|
-
if (!process.env.NEXT_USE_NETLIFY_EDGE && ((_a = middlewareManifest === null || middlewareManifest === void 0 ? void 0 : middlewareManifest.sortedMiddleware) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
101
|
-
console.log((0, chalk_1.yellowBright)((0, outdent_1.outdent) `
|
|
102
|
-
You are using Next.js Middleware without Netlify Edge Functions.
|
|
103
|
-
This will soon be deprecated because it negatively affects performance and will disable ISR and static rendering.
|
|
104
|
-
To get the best performance and use Netlify Edge Functions, set the env var ${(0, chalk_1.bold) `NEXT_USE_NETLIFY_EDGE=true`}.
|
|
105
|
-
`));
|
|
106
119
|
}
|
|
107
120
|
},
|
|
108
121
|
async onPostBuild({ netlifyConfig: { build: { publish }, redirects, headers, }, utils: { status, cache, functions, build: { failBuild }, }, constants: { FUNCTIONS_DIST }, }) {
|
|
109
122
|
await (0, cache_1.saveCache)({ cache, publish });
|
|
110
123
|
if ((0, utils_1.shouldSkip)()) {
|
|
111
124
|
status.show({
|
|
112
|
-
title: '
|
|
125
|
+
title: 'Next Runtime did not run',
|
|
113
126
|
summary: `Next cache was stored, but all other functions were skipped because ${process.env.NETLIFY_NEXT_PLUGIN_SKIP
|
|
114
127
|
? `NETLIFY_NEXT_PLUGIN_SKIP is set`
|
|
115
128
|
: `NEXT_PLUGIN_FORCE_RUN is set to ${process.env.NEXT_PLUGIN_FORCE_RUN}`}`,
|
|
@@ -125,5 +138,24 @@ const plugin = {
|
|
|
125
138
|
(0, verification_1.warnForRootRedirects)({ appDir });
|
|
126
139
|
},
|
|
127
140
|
};
|
|
128
|
-
|
|
141
|
+
// The types haven't been updated yet
|
|
142
|
+
const nextRuntime = (_inputs, meta = {}) => {
|
|
143
|
+
var _a;
|
|
144
|
+
if (!((_a = meta === null || meta === void 0 ? void 0 : meta.events) === null || _a === void 0 ? void 0 : _a.has('onPreDev'))) {
|
|
145
|
+
return {
|
|
146
|
+
...plugin,
|
|
147
|
+
onEnd: ({ utils }) => {
|
|
148
|
+
utils.status.show({
|
|
149
|
+
title: 'Please upgrade to the latest version of the Netlify CLI',
|
|
150
|
+
summary: 'To support for the latest Next.js features, please upgrade to the latest version of the Netlify CLI',
|
|
151
|
+
});
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
...plugin,
|
|
157
|
+
onPreDev: dev_1.onPreDev,
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
module.exports = nextRuntime;
|
|
129
161
|
/* eslint-enable max-lines */
|
package/manifest.yml
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
name: netlify-
|
|
1
|
+
name: netlify-next-runtime-experimental
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/plugin-nextjs",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.17.1-runtime.2",
|
|
4
4
|
"description": "Run Next.js seamlessly on Netlify",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"files": [
|
|
@@ -9,10 +9,12 @@
|
|
|
9
9
|
"manifest.yml"
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@netlify/
|
|
13
|
-
"@netlify/
|
|
12
|
+
"@netlify/esbuild": "0.14.25",
|
|
13
|
+
"@netlify/functions": "^1.2.0",
|
|
14
|
+
"@netlify/ipx": "^1.2.2",
|
|
14
15
|
"@vercel/node-bridge": "^2.1.0",
|
|
15
16
|
"chalk": "^4.1.2",
|
|
17
|
+
"execa": "^5.1.1",
|
|
16
18
|
"fs-extra": "^10.0.0",
|
|
17
19
|
"globby": "^11.0.4",
|
|
18
20
|
"moize": "^6.1.0",
|
|
@@ -22,13 +24,13 @@
|
|
|
22
24
|
"p-limit": "^3.1.0",
|
|
23
25
|
"pathe": "^0.2.0",
|
|
24
26
|
"pretty-bytes": "^5.6.0",
|
|
25
|
-
"slash": "^3.0.0",
|
|
26
27
|
"semver": "^7.3.5",
|
|
28
|
+
"slash": "^3.0.0",
|
|
27
29
|
"tiny-glob": "^0.2.9"
|
|
28
30
|
},
|
|
29
31
|
"devDependencies": {
|
|
30
32
|
"@delucis/if-env": "^1.1.2",
|
|
31
|
-
"@netlify/build": "^27.
|
|
33
|
+
"@netlify/build": "^27.14.0",
|
|
32
34
|
"@types/fs-extra": "^9.0.13",
|
|
33
35
|
"@types/jest": "^27.4.1",
|
|
34
36
|
"@types/node": "^17.0.25",
|
|
@@ -61,4 +63,4 @@
|
|
|
61
63
|
"engines": {
|
|
62
64
|
"node": ">=12.0.0"
|
|
63
65
|
}
|
|
64
|
-
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'https://esm.sh/next/server'
|
|
2
|
+
import { fromFileUrl } from 'https://deno.land/std/path/mod.ts'
|
|
3
|
+
import { buildResponse } from './utils.ts'
|
|
4
|
+
|
|
5
|
+
globalThis.NFRequestContextMap ||= new Map()
|
|
6
|
+
globalThis.__dirname = fromFileUrl(new URL('./', import.meta.url)).slice(0, -1)
|
|
7
|
+
|
|
8
|
+
// Check if a file exists, given a relative path
|
|
9
|
+
const exists = async (relativePath) => {
|
|
10
|
+
const path = fromFileUrl(new URL(relativePath, import.meta.url))
|
|
11
|
+
try {
|
|
12
|
+
await Deno.stat(path)
|
|
13
|
+
return true
|
|
14
|
+
} catch (error) {
|
|
15
|
+
if (error instanceof Deno.errors.NotFound) {
|
|
16
|
+
return false
|
|
17
|
+
}
|
|
18
|
+
throw error
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const handler = async (req, context) => {
|
|
23
|
+
// Uncomment when CLI update lands
|
|
24
|
+
// if (!Deno.env.get('NETLIFY_DEV')) {
|
|
25
|
+
// // Only run in dev
|
|
26
|
+
// return
|
|
27
|
+
// }
|
|
28
|
+
|
|
29
|
+
let middleware
|
|
30
|
+
// Dynamic imports and FS operations aren't allowed when deployed,
|
|
31
|
+
// but that's fine because this is only ever used locally.
|
|
32
|
+
// We don't want to just try importing and use that to test,
|
|
33
|
+
// because that would also throw if there's an error in the middleware,
|
|
34
|
+
// which we would want to surface not ignore.
|
|
35
|
+
if (await exists('../../middleware.js')) {
|
|
36
|
+
// These will be user code
|
|
37
|
+
const nextMiddleware = await import('../../middleware.js')
|
|
38
|
+
middleware = nextMiddleware.middleware
|
|
39
|
+
} else {
|
|
40
|
+
// No middleware, so we silently return
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// This is the format expected by Next.js
|
|
45
|
+
const geo = {
|
|
46
|
+
country: context.geo.country?.code,
|
|
47
|
+
region: context.geo.subdivision?.code,
|
|
48
|
+
city: context.geo.city,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// A default request id is fine locally
|
|
52
|
+
const requestId = req.headers.get('x-nf-request-id') || 'request-id'
|
|
53
|
+
|
|
54
|
+
globalThis.NFRequestContextMap.set(requestId, {
|
|
55
|
+
request: req,
|
|
56
|
+
context,
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const request = {
|
|
60
|
+
headers: Object.fromEntries(req.headers.entries()),
|
|
61
|
+
geo,
|
|
62
|
+
method: req.method,
|
|
63
|
+
ip: context.ip,
|
|
64
|
+
body: req.body || undefined,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const nextRequest = new NextRequest(req, request)
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const response = await middleware(nextRequest)
|
|
71
|
+
return buildResponse({
|
|
72
|
+
result: { response: response || NextResponse.next(), waitUntil: Promise.resolve() },
|
|
73
|
+
request: req,
|
|
74
|
+
context,
|
|
75
|
+
})
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error(error)
|
|
78
|
+
return new Response(error.message, { status: 500 })
|
|
79
|
+
} finally {
|
|
80
|
+
if (requestId) {
|
|
81
|
+
globalThis.NFRequestContextMap.delete(requestId)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export default handler
|
|
@@ -45,6 +45,10 @@ declare global {
|
|
|
45
45
|
globalThis.NFRequestContextMap ||= new Map()
|
|
46
46
|
|
|
47
47
|
const handler = async (req: Request, context: Context) => {
|
|
48
|
+
if (Deno.env.get('NETLIFY_DEV')) {
|
|
49
|
+
// Don't run in dev
|
|
50
|
+
return
|
|
51
|
+
}
|
|
48
52
|
const url = new URL(req.url)
|
|
49
53
|
|
|
50
54
|
const geo = {
|
|
@@ -123,17 +123,38 @@ export const buildResponse = async ({
|
|
|
123
123
|
request.headers.set('x-nf-next-middleware', 'skip')
|
|
124
124
|
|
|
125
125
|
const rewrite = res.headers.get('x-middleware-rewrite')
|
|
126
|
+
|
|
127
|
+
// Data requests (i.e. requests for /_next/data ) need special handling
|
|
128
|
+
const isDataReq = request.headers.get('x-nextjs-data')
|
|
129
|
+
|
|
126
130
|
if (rewrite) {
|
|
127
131
|
const rewriteUrl = new URL(rewrite, request.url)
|
|
128
132
|
const baseUrl = new URL(request.url)
|
|
133
|
+
const relativeUrl = relativizeURL(rewrite, request.url)
|
|
134
|
+
|
|
135
|
+
// Data requests might be rewritten to an external URL
|
|
136
|
+
// This header tells the client router the redirect target, and if it's external then it will do a full navigation
|
|
137
|
+
if (isDataReq) {
|
|
138
|
+
res.headers.set('x-nextjs-rewrite', relativeUrl)
|
|
139
|
+
}
|
|
129
140
|
if (rewriteUrl.hostname !== baseUrl.hostname) {
|
|
130
141
|
// Netlify Edge Functions don't support proxying to external domains, but Next middleware does
|
|
131
142
|
const proxied = fetch(new Request(rewriteUrl.toString(), request))
|
|
132
143
|
return addMiddlewareHeaders(proxied, res)
|
|
133
144
|
}
|
|
134
|
-
res.headers.set('x-middleware-rewrite',
|
|
145
|
+
res.headers.set('x-middleware-rewrite', relativeUrl)
|
|
146
|
+
|
|
135
147
|
return addMiddlewareHeaders(context.rewrite(rewrite), res)
|
|
136
148
|
}
|
|
149
|
+
|
|
150
|
+
const redirect = res.headers.get('Location')
|
|
151
|
+
|
|
152
|
+
// Data requests shouldn;t automatically redirect in the browser (they might be HTML pages): they're handled by the router
|
|
153
|
+
if (redirect && isDataReq) {
|
|
154
|
+
res.headers.delete('location')
|
|
155
|
+
res.headers.set('x-nextjs-redirect', relativizeURL(redirect, request.url))
|
|
156
|
+
}
|
|
157
|
+
|
|
137
158
|
if (res.headers.get('x-middleware-next') === '1') {
|
|
138
159
|
return addMiddlewareHeaders(context.next(), res)
|
|
139
160
|
}
|