@netlify/plugin-nextjs 4.17.1-runtime.0 → 4.17.1-runtime.3

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.
@@ -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;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.updateConfig = exports.writeEdgeFunctions = exports.loadMiddlewareManifest = void 0;
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
- if (!process.env.NEXT_USE_NETLIFY_EDGE) {
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.NEXT_USE_NETLIFY_EDGE) {
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 updateConfig = async (publish) => {
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.updateConfig = updateConfig;
146
+ exports.enableEdgeInNextConfig = enableEdgeInNextConfig;
131
147
  /* eslint-enable max-lines */
@@ -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.NEXT_USE_NETLIFY_EDGE) {
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.NEXT_USE_NETLIFY_EDGE) return null;`,
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.NEXT_USE_NETLIFY_EDGE) return [];`,
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.NEXT_USE_NETLIFY_EDGE) return undefined;`,
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 && !process.env.NEXT_USE_NETLIFY_EDGE) {`,
291
+ `getMiddlewareManifest() {\n if (!this.minimalMode && process.env.NEXT_DISABLE_NETLIFY_EDGE) {`,
292
292
  ],
293
293
  ];
294
294
  const patchNextFiles = async (root) => {
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");
@@ -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,22 +109,13 @@ const plugin = {
87
109
  nextConfig: { basePath, i18n, trailingSlash, appDir },
88
110
  buildId,
89
111
  });
90
- // We call this even if we don't have edge functions enabled because we still use it for images
91
- await (0, edge_1.writeEdgeFunctions)(netlifyConfig);
92
- if (process.env.NEXT_USE_NETLIFY_EDGE) {
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 }, }) {
@@ -125,5 +138,24 @@ const plugin = {
125
138
  (0, verification_1.warnForRootRedirects)({ appDir });
126
139
  },
127
140
  };
128
- module.exports = plugin;
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/plugin-nextjs",
3
- "version": "4.17.1-runtime.0",
3
+ "version": "4.17.1-runtime.3",
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/esbuild": "0.14.25",
12
13
  "@netlify/functions": "^1.2.0",
13
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,8 +24,8 @@
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": {
@@ -0,0 +1,87 @@
1
+ import { NextRequest } from 'https://esm.sh/v91/next@12.2.5/deno/dist/server/web/spec-extension/request.js'
2
+ import { NextResponse } from 'https://esm.sh/v91/next@12.2.5/deno/dist/server/web/spec-extension/response.js'
3
+ import { fromFileUrl } from 'https://deno.land/std@0.151.0/path/mod.ts'
4
+ import { buildResponse } from './utils.ts'
5
+
6
+ globalThis.NFRequestContextMap ||= new Map()
7
+ globalThis.__dirname = fromFileUrl(new URL('./', import.meta.url)).slice(0, -1)
8
+
9
+ // Check if a file exists, given a relative path
10
+ const exists = async (relativePath) => {
11
+ const path = fromFileUrl(new URL(relativePath, import.meta.url))
12
+ try {
13
+ await Deno.stat(path)
14
+ return true
15
+ } catch (error) {
16
+ if (error instanceof Deno.errors.NotFound) {
17
+ return false
18
+ }
19
+ throw error
20
+ }
21
+ }
22
+
23
+ const handler = async (req, context) => {
24
+ // Uncomment when CLI update lands
25
+ // if (!Deno.env.get('NETLIFY_DEV')) {
26
+ // // Only run in dev
27
+ // return
28
+ // }
29
+
30
+ let middleware
31
+ // Dynamic imports and FS operations aren't allowed when deployed,
32
+ // but that's fine because this is only ever used locally.
33
+ // We don't want to just try importing and use that to test,
34
+ // because that would also throw if there's an error in the middleware,
35
+ // which we would want to surface not ignore.
36
+ if (await exists('../../middleware.js')) {
37
+ // These will be user code
38
+ const nextMiddleware = await import('../../middleware.js')
39
+ middleware = nextMiddleware.middleware
40
+ } else {
41
+ // No middleware, so we silently return
42
+ return
43
+ }
44
+
45
+ // This is the format expected by Next.js
46
+ const geo = {
47
+ country: context.geo.country?.code,
48
+ region: context.geo.subdivision?.code,
49
+ city: context.geo.city,
50
+ }
51
+
52
+ // A default request id is fine locally
53
+ const requestId = req.headers.get('x-nf-request-id') || 'request-id'
54
+
55
+ globalThis.NFRequestContextMap.set(requestId, {
56
+ request: req,
57
+ context,
58
+ })
59
+
60
+ const request = {
61
+ headers: Object.fromEntries(req.headers.entries()),
62
+ geo,
63
+ method: req.method,
64
+ ip: context.ip,
65
+ body: req.body || undefined,
66
+ }
67
+
68
+ const nextRequest = new NextRequest(req, request)
69
+
70
+ try {
71
+ const response = await middleware(nextRequest)
72
+ return buildResponse({
73
+ result: { response: response || NextResponse.next(), waitUntil: Promise.resolve() },
74
+ request: req,
75
+ context,
76
+ })
77
+ } catch (error) {
78
+ console.error(error)
79
+ return new Response(error.message, { status: 500 })
80
+ } finally {
81
+ if (requestId) {
82
+ globalThis.NFRequestContextMap.delete(requestId)
83
+ }
84
+ }
85
+ }
86
+
87
+ 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', relativizeURL(rewrite, request.url))
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
  }