@netlify/plugin-nextjs 4.1.1 → 4.2.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/README.md CHANGED
@@ -31,6 +31,12 @@ npm install -D @netlify/plugin-nextjs
31
31
  package = "@netlify/plugin-nextjs"
32
32
  ```
33
33
 
34
+ ## Deploying
35
+
36
+ If you build on Netlify, this plugin will work with no additional configuration. However if you are building and
37
+ deploying locally using the Netlify CLI, you must deploy using `netlify deploy --build`. Running the
38
+ build and deploy commands separately will not work, because the plugin will not generate the required configuration.
39
+
34
40
  ## Migrating from an older version of the plugin
35
41
 
36
42
  You can manually upgrade from the previous version of the plugin by running the following command:
@@ -58,7 +64,8 @@ it.
58
64
 
59
65
  If you currently use redirects or rewrites on your site, see
60
66
  [the Rewrites and Redirects guide](https://github.com/netlify/netlify-plugin-nextjs/blob/main/docs/redirects-rewrites.md)
61
- for information on changes to how they are handled in this version.
67
+ for information on changes to how they are handled in this version. In particular, note that `_redirects` and `_headers`
68
+ files must be placed in `public`, not in the root of the site.
62
69
 
63
70
  If you want to use Next 12's beta Middleware feature, this will mostly work as expected but please
64
71
  [read the docs on some caveats and workarounds](https://github.com/netlify/netlify-plugin-nextjs/blob/main/docs/middleware.md)
@@ -85,6 +92,20 @@ you can remove it. Alternatively you can
85
92
  support. See [`demos/next-export`](https://github.com/netlify/netlify-plugin-nextjs/tree/main/demos/next-export) for an
86
93
  example.
87
94
 
95
+ ## Asset optimization
96
+
97
+ Netlify [asset optimization](https://docs.netlify.com/site-deploys/post-processing/) should not be used with Next.js
98
+ sites. Assets are already optimized by Next.js at build time, and doing further optimization can break your site. Ensure
99
+ that it is not enabled at **Site settings > Build & deploy > Post processing > Asset optimization**.
100
+
101
+ ## Generated functions
102
+
103
+ This plugin works by generating three Netlify functions that handle requests that haven't been pre-rendered. These are
104
+ `___netlify-handler` (for SSR and API routes), `___netlify-odb-handler` (for ISR and fallback routes), and `_ipx` (for
105
+ images). You can see the requests for these in [the function logs](https://docs.netlify.com/functions/logs/). For ISR
106
+ and fallback routes you will not see any requests that are served from the edge cache, just actual rendering requests.
107
+ These are all internal functions, so you won't find them in your site's own functions directory.
108
+
88
109
  ## Feedback
89
110
 
90
111
  If you think you have found a bug in the plugin,
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.saveCache = exports.restoreCache = void 0;
4
4
  const path_1 = require("path");
5
5
  const restoreCache = async ({ cache, publish }) => {
6
- const cacheDir = path_1.join(publish, 'cache');
6
+ const cacheDir = (0, path_1.join)(publish, 'cache');
7
7
  if (await cache.restore(cacheDir)) {
8
8
  console.log('Next.js cache restored.');
9
9
  }
@@ -13,8 +13,8 @@ const restoreCache = async ({ cache, publish }) => {
13
13
  };
14
14
  exports.restoreCache = restoreCache;
15
15
  const saveCache = async ({ cache, publish }) => {
16
- const cacheDir = path_1.join(publish, 'cache');
17
- const buildManifest = path_1.join(publish, 'build-manifest.json');
16
+ const cacheDir = (0, path_1.join)(publish, 'cache');
17
+ const buildManifest = (0, path_1.join)(publish, 'build-manifest.json');
18
18
  if (await cache.save(cacheDir, { digests: [buildManifest] })) {
19
19
  console.log('Next.js cache saved.');
20
20
  }
@@ -13,7 +13,7 @@ const defaultFailBuild = (message, { error }) => {
13
13
  };
14
14
  const getNextConfig = async function getNextConfig({ publish, failBuild = defaultFailBuild, }) {
15
15
  try {
16
- const { config, appDir, ignore } = await fs_extra_1.readJSON(pathe_1.join(publish, 'required-server-files.json'));
16
+ const { config, appDir, ignore } = await (0, fs_extra_1.readJSON)((0, pathe_1.join)(publish, 'required-server-files.json'));
17
17
  if (!config) {
18
18
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
19
19
  // @ts-ignore
@@ -28,9 +28,9 @@ const getNextConfig = async function getNextConfig({ publish, failBuild = defaul
28
28
  exports.getNextConfig = getNextConfig;
29
29
  const resolveModuleRoot = (moduleName) => {
30
30
  try {
31
- return pathe_1.dirname(pathe_1.relative(process.cwd(), require.resolve(`${moduleName}/package.json`, { paths: [process.cwd()] })));
31
+ return (0, pathe_1.dirname)((0, pathe_1.relative)(process.cwd(), require.resolve(`${moduleName}/package.json`, { paths: [process.cwd()] })));
32
32
  }
33
- catch (error) {
33
+ catch {
34
34
  return null;
35
35
  }
36
36
  };
@@ -45,7 +45,7 @@ const configureHandlerFunctions = ({ netlifyConfig, publish, ignore = [] }) => {
45
45
  (_a = netlifyConfig.functions)[functionName] || (_a[functionName] = { included_files: [], external_node_modules: [] });
46
46
  netlifyConfig.functions[functionName].node_bundler = 'nft';
47
47
  (_b = netlifyConfig.functions[functionName]).included_files || (_b.included_files = []);
48
- netlifyConfig.functions[functionName].included_files.push('.env', '.env.local', '.env.production', '.env.production.local', `${publish}/server/**`, `${publish}/serverless/**`, `${publish}/*.json`, `${publish}/BUILD_ID`, `${publish}/static/chunks/webpack-middleware*.js`, `!${publish}/server/**/*.js.nft.json`, ...ignore.map((path) => `!${slash_1.default(path)}`));
48
+ netlifyConfig.functions[functionName].included_files.push('.env', '.env.local', '.env.production', '.env.production.local', `${publish}/server/**`, `${publish}/serverless/**`, `${publish}/*.json`, `${publish}/BUILD_ID`, `${publish}/static/chunks/webpack-middleware*.js`, `!${publish}/server/**/*.js.nft.json`, ...ignore.map((path) => `!${(0, slash_1.default)(path)}`));
49
49
  const nextRoot = resolveModuleRoot('next');
50
50
  if (nextRoot) {
51
51
  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`, `!${nextRoot}/dist/compiled/terser/bundle.min.js`);
@@ -43,33 +43,33 @@ const matchesRedirect = (file, redirects) => {
43
43
  exports.matchesRedirect = matchesRedirect;
44
44
  const matchesRewrite = (file, rewrites) => {
45
45
  if (Array.isArray(rewrites)) {
46
- return exports.matchesRedirect(file, rewrites);
46
+ return (0, exports.matchesRedirect)(file, rewrites);
47
47
  }
48
48
  if (!Array.isArray(rewrites === null || rewrites === void 0 ? void 0 : rewrites.beforeFiles)) {
49
49
  return false;
50
50
  }
51
- return exports.matchesRedirect(file, rewrites.beforeFiles);
51
+ return (0, exports.matchesRedirect)(file, rewrites.beforeFiles);
52
52
  };
53
53
  exports.matchesRewrite = matchesRewrite;
54
54
  // eslint-disable-next-line max-lines-per-function
55
55
  const moveStaticPages = async ({ netlifyConfig, target, i18n, }) => {
56
56
  console.log('Moving static page files to serve from CDN...');
57
- const outputDir = pathe_1.join(netlifyConfig.build.publish, target === 'server' ? 'server' : 'serverless');
58
- const root = pathe_1.join(outputDir, 'pages');
59
- const buildId = fs_extra_1.readFileSync(pathe_1.join(netlifyConfig.build.publish, 'BUILD_ID'), 'utf8').trim();
60
- const dataDir = pathe_1.join('_next', 'data', buildId);
61
- await fs_extra_1.ensureDir(dataDir);
57
+ const outputDir = (0, pathe_1.join)(netlifyConfig.build.publish, target === 'server' ? 'server' : 'serverless');
58
+ const root = (0, pathe_1.join)(outputDir, 'pages');
59
+ const buildId = (0, fs_extra_1.readFileSync)((0, pathe_1.join)(netlifyConfig.build.publish, 'BUILD_ID'), 'utf8').trim();
60
+ const dataDir = (0, pathe_1.join)('_next', 'data', buildId);
61
+ await (0, fs_extra_1.ensureDir)(dataDir);
62
62
  // Load the middleware manifest so we can check if a file matches it before moving
63
63
  let middleware;
64
- const manifestPath = pathe_1.join(outputDir, 'middleware-manifest.json');
65
- if (fs_extra_1.existsSync(manifestPath)) {
66
- const manifest = await fs_extra_1.readJson(manifestPath);
64
+ const manifestPath = (0, pathe_1.join)(outputDir, 'middleware-manifest.json');
65
+ if ((0, fs_extra_1.existsSync)(manifestPath)) {
66
+ const manifest = await (0, fs_extra_1.readJson)(manifestPath);
67
67
  if (manifest === null || manifest === void 0 ? void 0 : manifest.middleware) {
68
68
  middleware = Object.keys(manifest.middleware).map((path) => path.slice(1));
69
69
  }
70
70
  }
71
- const prerenderManifest = await fs_extra_1.readJson(pathe_1.join(netlifyConfig.build.publish, 'prerender-manifest.json'));
72
- const { redirects, rewrites } = await fs_extra_1.readJson(pathe_1.join(netlifyConfig.build.publish, 'routes-manifest.json'));
71
+ const prerenderManifest = await (0, fs_extra_1.readJson)((0, pathe_1.join)(netlifyConfig.build.publish, 'prerender-manifest.json'));
72
+ const { redirects, rewrites } = await (0, fs_extra_1.readJson)((0, pathe_1.join)(netlifyConfig.build.publish, 'routes-manifest.json'));
73
73
  const isrFiles = new Set();
74
74
  const shortRevalidateRoutes = [];
75
75
  Object.entries(prerenderManifest.routes).forEach(([route, { initialRevalidateSeconds }]) => {
@@ -87,20 +87,20 @@ const moveStaticPages = async ({ netlifyConfig, target, i18n, }) => {
87
87
  const filesManifest = {};
88
88
  const moveFile = async (file) => {
89
89
  const isData = file.endsWith('.json');
90
- const source = pathe_1.join(root, file);
91
- const targetFile = isData ? pathe_1.join(dataDir, file) : file;
90
+ const source = (0, pathe_1.join)(root, file);
91
+ const targetFile = isData ? (0, pathe_1.join)(dataDir, file) : file;
92
92
  files.push(file);
93
93
  filesManifest[file] = targetFile;
94
- const dest = pathe_1.join(netlifyConfig.build.publish, targetFile);
94
+ const dest = (0, pathe_1.join)(netlifyConfig.build.publish, targetFile);
95
95
  try {
96
- await fs_extra_1.move(source, dest);
96
+ await (0, fs_extra_1.move)(source, dest);
97
97
  }
98
98
  catch (error) {
99
99
  console.warn('Error moving file', source, error);
100
100
  }
101
101
  };
102
102
  // Move all static files, except error documents and nft manifests
103
- const pages = await globby_1.default(['**/*.{html,json}', '!**/(500|404|*.js.nft).{html,json}'], {
103
+ const pages = await (0, globby_1.default)(['**/*.{html,json}', '!**/(500|404|*.js.nft).{html,json}'], {
104
104
  cwd: root,
105
105
  dot: true,
106
106
  });
@@ -109,27 +109,27 @@ const moveStaticPages = async ({ netlifyConfig, target, i18n, }) => {
109
109
  const matchedRedirects = new Set();
110
110
  const matchedRewrites = new Set();
111
111
  // Limit concurrent file moves to number of cpus or 2 if there is only 1
112
- const limit = p_limit_1.default(Math.max(2, os_1.cpus().length));
112
+ const limit = (0, p_limit_1.default)(Math.max(2, (0, os_1.cpus)().length));
113
113
  const promises = pages.map((rawPath) => {
114
- const filePath = slash_1.default(rawPath);
114
+ const filePath = (0, slash_1.default)(rawPath);
115
115
  // Don't move ISR files, as they're used for the first request
116
116
  if (isrFiles.has(filePath)) {
117
117
  return;
118
118
  }
119
- if (exports.isDynamicRoute(filePath)) {
119
+ if ((0, exports.isDynamicRoute)(filePath)) {
120
120
  return;
121
121
  }
122
- if (exports.matchesRedirect(filePath, redirects)) {
122
+ if ((0, exports.matchesRedirect)(filePath, redirects)) {
123
123
  matchedRedirects.add(filePath);
124
124
  return;
125
125
  }
126
- if (exports.matchesRewrite(filePath, rewrites)) {
126
+ if ((0, exports.matchesRewrite)(filePath, rewrites)) {
127
127
  matchedRewrites.add(filePath);
128
128
  return;
129
129
  }
130
130
  // Middleware matches against the unlocalised path
131
- const unlocalizedPath = exports.stripLocale(rawPath, i18n === null || i18n === void 0 ? void 0 : i18n.locales);
132
- const middlewarePath = exports.matchMiddleware(middleware, unlocalizedPath);
131
+ const unlocalizedPath = (0, exports.stripLocale)(rawPath, i18n === null || i18n === void 0 ? void 0 : i18n.locales);
132
+ const middlewarePath = (0, exports.matchMiddleware)(middleware, unlocalizedPath);
133
133
  // If a file matches middleware it can't be offloaded to the CDN, and needs to stay at the origin to be served by next/server
134
134
  if (middlewarePath) {
135
135
  matchingMiddleware.add(middlewarePath);
@@ -141,67 +141,67 @@ const moveStaticPages = async ({ netlifyConfig, target, i18n, }) => {
141
141
  await Promise.all(promises);
142
142
  console.log(`Moved ${files.length} files`);
143
143
  if (matchedPages.size !== 0) {
144
- console.log(chalk_1.yellowBright(outdent_1.outdent `
144
+ console.log((0, chalk_1.yellowBright)((0, outdent_1.outdent) `
145
145
  Skipped moving ${matchedPages.size} ${matchedPages.size === 1 ? 'file because it matches' : 'files because they match'} middleware, so cannot be deployed to the CDN and will be served from the origin instead.
146
146
  This is fine, but we're letting you know because it may not be what you expect.
147
147
  `));
148
- console.log(outdent_1.outdent `
148
+ console.log((0, outdent_1.outdent) `
149
149
  The following middleware matched statically-rendered pages:
150
150
 
151
- ${chalk_1.yellowBright([...matchingMiddleware].map((mid) => `- /${mid}/_middleware`).join('\n'))}
151
+ ${(0, chalk_1.yellowBright)([...matchingMiddleware].map((mid) => `- /${mid}/_middleware`).join('\n'))}
152
152
  ${constants_1.DIVIDER}
153
153
  `);
154
154
  // There could potentially be thousands of matching pages, so we don't want to spam the console with this
155
155
  if (matchedPages.size < 50) {
156
- console.log(outdent_1.outdent `
156
+ console.log((0, outdent_1.outdent) `
157
157
  The following files matched middleware and were not moved to the CDN:
158
158
 
159
- ${chalk_1.yellowBright([...matchedPages].map((mid) => `- ${mid}`).join('\n'))}
159
+ ${(0, chalk_1.yellowBright)([...matchedPages].map((mid) => `- ${mid}`).join('\n'))}
160
160
  ${constants_1.DIVIDER}
161
161
  `);
162
162
  }
163
163
  }
164
164
  if (matchedRedirects.size !== 0 || matchedRewrites.size !== 0) {
165
- console.log(chalk_1.yellowBright(outdent_1.outdent `
165
+ console.log((0, chalk_1.yellowBright)((0, outdent_1.outdent) `
166
166
  Skipped moving ${matchedRedirects.size + matchedRewrites.size} files because they match redirects or beforeFiles rewrites, so cannot be deployed to the CDN and will be served from the origin instead.
167
167
  `));
168
168
  if (matchedRedirects.size < 50 && matchedRedirects.size !== 0) {
169
- console.log(outdent_1.outdent `
169
+ console.log((0, outdent_1.outdent) `
170
170
  The following files matched redirects and were not moved to the CDN:
171
171
 
172
- ${chalk_1.yellowBright([...matchedRedirects].map((mid) => `- ${mid}`).join('\n'))}
172
+ ${(0, chalk_1.yellowBright)([...matchedRedirects].map((mid) => `- ${mid}`).join('\n'))}
173
173
  ${constants_1.DIVIDER}
174
174
  `);
175
175
  }
176
176
  if (matchedRewrites.size < 50 && matchedRewrites.size !== 0) {
177
- console.log(outdent_1.outdent `
177
+ console.log((0, outdent_1.outdent) `
178
178
  The following files matched beforeFiles rewrites and were not moved to the CDN:
179
179
 
180
- ${chalk_1.yellowBright([...matchedRewrites].map((mid) => `- ${mid}`).join('\n'))}
180
+ ${(0, chalk_1.yellowBright)([...matchedRewrites].map((mid) => `- ${mid}`).join('\n'))}
181
181
  ${constants_1.DIVIDER}
182
182
  `);
183
183
  }
184
184
  }
185
185
  // Write the manifest for use in the serverless functions
186
- await fs_extra_1.writeJson(pathe_1.join(netlifyConfig.build.publish, 'static-manifest.json'), Object.entries(filesManifest));
186
+ await (0, fs_extra_1.writeJson)((0, pathe_1.join)(netlifyConfig.build.publish, 'static-manifest.json'), Object.entries(filesManifest));
187
187
  if (i18n === null || i18n === void 0 ? void 0 : i18n.defaultLocale) {
188
188
  // Copy the default locale into the root
189
- const defaultLocaleDir = pathe_1.join(netlifyConfig.build.publish, i18n.defaultLocale);
190
- if (fs_extra_1.existsSync(defaultLocaleDir)) {
191
- await fs_extra_1.copy(defaultLocaleDir, `${netlifyConfig.build.publish}/`);
189
+ const defaultLocaleDir = (0, pathe_1.join)(netlifyConfig.build.publish, i18n.defaultLocale);
190
+ if ((0, fs_extra_1.existsSync)(defaultLocaleDir)) {
191
+ await (0, fs_extra_1.copy)(defaultLocaleDir, `${netlifyConfig.build.publish}/`);
192
192
  }
193
- const defaultLocaleIndex = pathe_1.join(netlifyConfig.build.publish, `${i18n.defaultLocale}.html`);
194
- const indexHtml = pathe_1.join(netlifyConfig.build.publish, 'index.html');
195
- if (fs_extra_1.existsSync(defaultLocaleIndex) && !fs_extra_1.existsSync(indexHtml)) {
193
+ const defaultLocaleIndex = (0, pathe_1.join)(netlifyConfig.build.publish, `${i18n.defaultLocale}.html`);
194
+ const indexHtml = (0, pathe_1.join)(netlifyConfig.build.publish, 'index.html');
195
+ if ((0, fs_extra_1.existsSync)(defaultLocaleIndex) && !(0, fs_extra_1.existsSync)(indexHtml)) {
196
196
  try {
197
- await fs_extra_1.copy(defaultLocaleIndex, indexHtml, { overwrite: false });
198
- await fs_extra_1.copy(pathe_1.join(netlifyConfig.build.publish, `${i18n.defaultLocale}.json`), pathe_1.join(netlifyConfig.build.publish, 'index.json'), { overwrite: false });
197
+ await (0, fs_extra_1.copy)(defaultLocaleIndex, indexHtml, { overwrite: false });
198
+ await (0, fs_extra_1.copy)((0, pathe_1.join)(netlifyConfig.build.publish, `${i18n.defaultLocale}.json`), (0, pathe_1.join)(netlifyConfig.build.publish, 'index.json'), { overwrite: false });
199
199
  }
200
200
  catch { }
201
201
  }
202
202
  }
203
203
  if (shortRevalidateRoutes.length !== 0) {
204
- console.log(outdent_1.outdent `
204
+ console.log((0, outdent_1.outdent) `
205
205
  The following routes use "revalidate" values of under ${constants_1.MINIMUM_REVALIDATE_SECONDS} seconds, which is not supported.
206
206
  They will use a revalidate time of ${constants_1.MINIMUM_REVALIDATE_SECONDS} seconds instead.
207
207
  `);
@@ -217,16 +217,16 @@ const moveStaticPages = async ({ netlifyConfig, target, i18n, }) => {
217
217
  };
218
218
  exports.moveStaticPages = moveStaticPages;
219
219
  const patchFile = async ({ file, from, to }) => {
220
- if (!fs_extra_1.existsSync(file)) {
220
+ if (!(0, fs_extra_1.existsSync)(file)) {
221
221
  return;
222
222
  }
223
- const content = await fs_extra_1.readFile(file, 'utf8');
223
+ const content = await (0, fs_extra_1.readFile)(file, 'utf8');
224
224
  if (content.includes(to)) {
225
225
  return;
226
226
  }
227
227
  const newContent = content.replace(from, to);
228
- await fs_extra_1.writeFile(`${file}.orig`, content);
229
- await fs_extra_1.writeFile(file, newContent);
228
+ await (0, fs_extra_1.writeFile)(`${file}.orig`, content);
229
+ await (0, fs_extra_1.writeFile)(file, newContent);
230
230
  };
231
231
  const getServerFile = (root) => {
232
232
  let serverFile;
@@ -262,8 +262,8 @@ exports.patchNextFiles = patchNextFiles;
262
262
  const unpatchNextFiles = async (root) => {
263
263
  const serverFile = getServerFile(root);
264
264
  const origFile = `${serverFile}.orig`;
265
- if (fs_extra_1.existsSync(origFile)) {
266
- await fs_extra_1.move(origFile, serverFile, { overwrite: true });
265
+ if ((0, fs_extra_1.existsSync)(origFile)) {
266
+ await (0, fs_extra_1.move)(origFile, serverFile, { overwrite: true });
267
267
  }
268
268
  };
269
269
  exports.unpatchNextFiles = unpatchNextFiles;
@@ -274,9 +274,9 @@ const movePublicFiles = async ({ appDir, outdir, publish, }) => {
274
274
  // If it exists, copy the files from the public folder there in order to include
275
275
  // any files that were generated during the build. Otherwise, copy the public
276
276
  // directory from the original app directory.
277
- const publicDir = outdir ? pathe_1.join(appDir, outdir, 'public') : pathe_1.join(appDir, 'public');
278
- if (fs_extra_1.existsSync(publicDir)) {
279
- await fs_extra_1.copy(publicDir, `${publish}/`);
277
+ const publicDir = outdir ? (0, pathe_1.join)(appDir, outdir, 'public') : (0, pathe_1.join)(appDir, 'public');
278
+ if ((0, fs_extra_1.existsSync)(publicDir)) {
279
+ await (0, fs_extra_1.copy)(publicDir, `${publish}/`);
280
280
  }
281
281
  };
282
282
  exports.movePublicFiles = movePublicFiles;
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.setupImageFunction = exports.generatePagesResolver = exports.generateFunctions = void 0;
7
+ const node_bridge_1 = __importDefault(require("@vercel/node-bridge"));
4
8
  const fs_extra_1 = require("fs-extra");
5
9
  const pathe_1 = require("pathe");
6
10
  const constants_1 = require("../constants");
@@ -8,15 +12,14 @@ const getHandler_1 = require("../templates/getHandler");
8
12
  const getPageResolver_1 = require("../templates/getPageResolver");
9
13
  const generateFunctions = async ({ FUNCTIONS_SRC = constants_1.DEFAULT_FUNCTIONS_SRC, INTERNAL_FUNCTIONS_SRC, PUBLISH_DIR }, appDir) => {
10
14
  const functionsDir = INTERNAL_FUNCTIONS_SRC || FUNCTIONS_SRC;
11
- const bridgeFile = require.resolve('@vercel/node/dist/bridge');
12
- const functionDir = pathe_1.join(process.cwd(), functionsDir, constants_1.HANDLER_FUNCTION_NAME);
13
- const publishDir = pathe_1.relative(functionDir, pathe_1.join(process.cwd(), PUBLISH_DIR));
15
+ const functionDir = (0, pathe_1.join)(process.cwd(), functionsDir, constants_1.HANDLER_FUNCTION_NAME);
16
+ const publishDir = (0, pathe_1.relative)(functionDir, (0, pathe_1.join)(process.cwd(), PUBLISH_DIR));
14
17
  const writeHandler = async (func, isODB) => {
15
- const handlerSource = await getHandler_1.getHandler({ isODB, publishDir, appDir: pathe_1.relative(functionDir, appDir) });
16
- await fs_extra_1.ensureDir(pathe_1.join(functionsDir, func));
17
- await fs_extra_1.writeFile(pathe_1.join(functionsDir, func, `${func}.js`), handlerSource);
18
- await fs_extra_1.copyFile(bridgeFile, pathe_1.join(functionsDir, func, 'bridge.js'));
19
- await fs_extra_1.copyFile(pathe_1.join(__dirname, '..', '..', 'lib', 'templates', 'handlerUtils.js'), pathe_1.join(functionsDir, func, 'handlerUtils.js'));
18
+ const handlerSource = await (0, getHandler_1.getHandler)({ isODB, publishDir, appDir: (0, pathe_1.relative)(functionDir, appDir) });
19
+ await (0, fs_extra_1.ensureDir)((0, pathe_1.join)(functionsDir, func));
20
+ await (0, fs_extra_1.writeFile)((0, pathe_1.join)(functionsDir, func, `${func}.js`), handlerSource);
21
+ await (0, fs_extra_1.copyFile)(node_bridge_1.default, (0, pathe_1.join)(functionsDir, func, 'bridge.js'));
22
+ await (0, fs_extra_1.copyFile)((0, pathe_1.join)(__dirname, '..', '..', 'lib', 'templates', 'handlerUtils.js'), (0, pathe_1.join)(functionsDir, func, 'handlerUtils.js'));
20
23
  };
21
24
  await writeHandler(constants_1.HANDLER_FUNCTION_NAME, false);
22
25
  await writeHandler(constants_1.ODB_FUNCTION_NAME, true);
@@ -28,25 +31,25 @@ exports.generateFunctions = generateFunctions;
28
31
  */
29
32
  const generatePagesResolver = async ({ constants: { INTERNAL_FUNCTIONS_SRC, FUNCTIONS_SRC = constants_1.DEFAULT_FUNCTIONS_SRC, PUBLISH_DIR }, target, }) => {
30
33
  const functionsPath = INTERNAL_FUNCTIONS_SRC || FUNCTIONS_SRC;
31
- const jsSource = await getPageResolver_1.getPageResolver({
34
+ const jsSource = await (0, getPageResolver_1.getPageResolver)({
32
35
  publish: PUBLISH_DIR,
33
36
  target,
34
37
  });
35
- await fs_extra_1.writeFile(pathe_1.join(functionsPath, constants_1.ODB_FUNCTION_NAME, 'pages.js'), jsSource);
36
- await fs_extra_1.writeFile(pathe_1.join(functionsPath, constants_1.HANDLER_FUNCTION_NAME, 'pages.js'), jsSource);
38
+ await (0, fs_extra_1.writeFile)((0, pathe_1.join)(functionsPath, constants_1.ODB_FUNCTION_NAME, 'pages.js'), jsSource);
39
+ await (0, fs_extra_1.writeFile)((0, pathe_1.join)(functionsPath, constants_1.HANDLER_FUNCTION_NAME, 'pages.js'), jsSource);
37
40
  };
38
41
  exports.generatePagesResolver = generatePagesResolver;
39
42
  // Move our next/image function into the correct functions directory
40
43
  const setupImageFunction = async ({ constants: { INTERNAL_FUNCTIONS_SRC, FUNCTIONS_SRC = constants_1.DEFAULT_FUNCTIONS_SRC }, imageconfig = {}, netlifyConfig, basePath, }) => {
41
44
  const functionsPath = INTERNAL_FUNCTIONS_SRC || FUNCTIONS_SRC;
42
45
  const functionName = `${constants_1.IMAGE_FUNCTION_NAME}.js`;
43
- const functionDirectory = pathe_1.join(functionsPath, constants_1.IMAGE_FUNCTION_NAME);
44
- await fs_extra_1.ensureDir(functionDirectory);
45
- await fs_extra_1.writeJSON(pathe_1.join(functionDirectory, 'imageconfig.json'), {
46
+ const functionDirectory = (0, pathe_1.join)(functionsPath, constants_1.IMAGE_FUNCTION_NAME);
47
+ await (0, fs_extra_1.ensureDir)(functionDirectory);
48
+ await (0, fs_extra_1.writeJSON)((0, pathe_1.join)(functionDirectory, 'imageconfig.json'), {
46
49
  ...imageconfig,
47
50
  basePath: [basePath, constants_1.IMAGE_FUNCTION_NAME].join('/'),
48
51
  });
49
- await fs_extra_1.copyFile(pathe_1.join(__dirname, '..', '..', 'lib', 'templates', 'ipx.js'), pathe_1.join(functionDirectory, functionName));
52
+ await (0, fs_extra_1.copyFile)((0, pathe_1.join)(__dirname, '..', '..', 'lib', 'templates', 'ipx.js'), (0, pathe_1.join)(functionDirectory, functionName));
50
53
  const imagePath = imageconfig.path || '/_next/image';
51
54
  netlifyConfig.redirects.push({
52
55
  from: `${imagePath}*`,
@@ -1,11 +1,7 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.generateRedirects = exports.generateStaticRedirects = void 0;
7
4
  const fs_extra_1 = require("fs-extra");
8
- const globby_1 = __importDefault(require("globby"));
9
5
  const pathe_1 = require("pathe");
10
6
  const constants_1 = require("../constants");
11
7
  const utils_1 = require("./utils");
@@ -45,8 +41,9 @@ const generateStaticRedirects = ({ netlifyConfig, nextConfig: { i18n, basePath }
45
41
  }
46
42
  };
47
43
  exports.generateStaticRedirects = generateStaticRedirects;
48
- const generateRedirects = async ({ netlifyConfig, nextConfig: { i18n, basePath, trailingSlash, appDir }, }) => {
49
- const { dynamicRoutes, routes: staticRoutes } = await fs_extra_1.readJSON(pathe_1.join(netlifyConfig.build.publish, 'prerender-manifest.json'));
44
+ const generateRedirects = async ({ netlifyConfig, nextConfig: { i18n, basePath, trailingSlash, appDir }, buildId, }) => {
45
+ const { dynamicRoutes: prerenderedDynamicRoutes, routes: prerenderedStaticRoutes } = await (0, fs_extra_1.readJSON)((0, pathe_1.join)(netlifyConfig.build.publish, 'prerender-manifest.json'));
46
+ const { dynamicRoutes, staticRoutes } = await (0, fs_extra_1.readJSON)((0, pathe_1.join)(netlifyConfig.build.publish, 'routes-manifest.json'));
50
47
  netlifyConfig.redirects.push(...constants_1.HIDDEN_PATHS.map((path) => ({
51
48
  from: `${basePath}${path}`,
52
49
  to: '/404.html',
@@ -56,78 +53,71 @@ const generateRedirects = async ({ netlifyConfig, nextConfig: { i18n, basePath,
56
53
  if (i18n && i18n.localeDetection !== false) {
57
54
  netlifyConfig.redirects.push(...generateLocaleRedirects({ i18n, basePath, trailingSlash }));
58
55
  }
59
- const dataRedirects = [];
60
- const pageRedirects = [];
61
- const isrRedirects = [];
62
- const dynamicRouteEntries = Object.entries(dynamicRoutes);
63
- const staticRouteEntries = Object.entries(staticRoutes);
64
- staticRouteEntries.forEach(([route, { dataRoute, initialRevalidateSeconds }]) => {
65
- // Only look for revalidate as we need to rewrite these to SSR rather than ODB
56
+ // This is only used in prod, so dev uses `next dev` directly
57
+ netlifyConfig.redirects.push(
58
+ // API routes always need to be served from the regular function
59
+ ...(0, utils_1.getApiRewrites)(basePath),
60
+ // Preview mode gets forced to the function, to bypass pre-rendered pages, but static files need to be skipped
61
+ ...(await (0, utils_1.getPreviewRewrites)({ basePath, appDir })));
62
+ const staticRouteEntries = Object.entries(prerenderedStaticRoutes);
63
+ const staticRoutePaths = new Set();
64
+ // First add all static ISR routes
65
+ staticRouteEntries.forEach(([route, { initialRevalidateSeconds }]) => {
66
+ if ((0, utils_1.isApiRoute)(route)) {
67
+ return;
68
+ }
69
+ staticRoutePaths.add(route);
66
70
  if (initialRevalidateSeconds === false) {
67
71
  // These can be ignored, as they're static files handled by the CDN
68
72
  return;
69
73
  }
74
+ // The default locale is served from the root, not the localised path
70
75
  if ((i18n === null || i18n === void 0 ? void 0 : i18n.defaultLocale) && route.startsWith(`/${i18n.defaultLocale}/`)) {
71
76
  route = route.slice(i18n.defaultLocale.length + 1);
77
+ staticRoutePaths.add(route);
78
+ netlifyConfig.redirects.push(...(0, utils_1.redirectsForNextRouteWithData)({
79
+ route,
80
+ dataRoute: (0, utils_1.routeToDataRoute)(route, buildId, i18n.defaultLocale),
81
+ basePath,
82
+ to: constants_1.ODB_FUNCTION_PATH,
83
+ force: true,
84
+ }));
85
+ }
86
+ else {
87
+ // ISR routes use the ODB handler
88
+ netlifyConfig.redirects.push(
89
+ // No i18n, because the route is already localized
90
+ ...(0, utils_1.redirectsForNextRoute)({ route, basePath, to: constants_1.ODB_FUNCTION_PATH, force: true, buildId, i18n: null }));
72
91
  }
73
- isrRedirects.push(...utils_1.netlifyRoutesForNextRoute(dataRoute), ...utils_1.netlifyRoutesForNextRoute(route));
74
92
  });
75
- dynamicRouteEntries.forEach(([route, { dataRoute, fallback }]) => {
76
- // Add redirects if fallback is "null" (aka blocking) or true/a string
77
- if (fallback === false) {
93
+ // Add rewrites for all static SSR routes. This is Next 12+
94
+ staticRoutes === null || staticRoutes === void 0 ? void 0 : staticRoutes.forEach((route) => {
95
+ if (staticRoutePaths.has(route.page) || (0, utils_1.isApiRoute)(route.page)) {
96
+ // Prerendered static routes are either handled by the CDN or are ISR
78
97
  return;
79
98
  }
80
- pageRedirects.push(...utils_1.netlifyRoutesForNextRoute(route));
81
- dataRedirects.push(...utils_1.netlifyRoutesForNextRoute(dataRoute));
99
+ netlifyConfig.redirects.push(...(0, utils_1.redirectsForNextRoute)({ route: route.page, buildId, basePath, to: constants_1.HANDLER_FUNCTION_PATH, i18n }));
82
100
  });
83
- const publicFiles = await globby_1.default('**/*', { cwd: pathe_1.join(appDir, 'public') });
84
- // This is only used in prod, so dev uses `next dev` directly
85
- netlifyConfig.redirects.push(
86
- // API routes always need to be served from the regular function
87
- {
88
- from: `${basePath}/api`,
89
- to: constants_1.HANDLER_FUNCTION_PATH,
90
- status: 200,
91
- }, {
92
- from: `${basePath}/api/*`,
93
- to: constants_1.HANDLER_FUNCTION_PATH,
94
- status: 200,
95
- },
96
- // Preview mode gets forced to the function, to bypass pre-rendered pages, but static files need to be skipped
97
- ...publicFiles.map((file) => ({
98
- from: `${basePath}/${file}`,
99
- // This is a no-op, but we do it to stop it matching the following rule
100
- to: `${basePath}/${file}`,
101
- conditions: { Cookie: ['__prerender_bypass', '__next_preview_data'] },
102
- status: 200,
103
- })), {
101
+ // Add rewrites for all dynamic routes (both SSR and ISR)
102
+ dynamicRoutes.forEach((route) => {
103
+ if ((0, utils_1.isApiRoute)(route.page)) {
104
+ return;
105
+ }
106
+ if (route.page in prerenderedDynamicRoutes) {
107
+ const { fallback } = prerenderedDynamicRoutes[route.page];
108
+ const { to, status } = (0, utils_1.targetForFallback)(fallback);
109
+ netlifyConfig.redirects.push(...(0, utils_1.redirectsForNextRoute)({ buildId, route: route.page, basePath, to, status, i18n }));
110
+ }
111
+ else {
112
+ // If the route isn't prerendered, it's SSR
113
+ netlifyConfig.redirects.push(...(0, utils_1.redirectsForNextRoute)({ route: route.page, buildId, basePath, to: constants_1.HANDLER_FUNCTION_PATH, i18n }));
114
+ }
115
+ });
116
+ // Final fallback
117
+ netlifyConfig.redirects.push({
104
118
  from: `${basePath}/*`,
105
119
  to: constants_1.HANDLER_FUNCTION_PATH,
106
120
  status: 200,
107
- conditions: { Cookie: ['__prerender_bypass', '__next_preview_data'] },
108
- force: true,
109
- },
110
- // ISR redirects are handled by the regular function. Forced to avoid pre-rendered pages
111
- ...isrRedirects.map((redirect) => ({
112
- from: `${basePath}${redirect}`,
113
- to: constants_1.ODB_FUNCTION_PATH,
114
- status: 200,
115
- force: true,
116
- })),
117
- // These are pages with fallback set, which need an ODB
118
- // Data redirects go first, to avoid conflict with splat redirects
119
- ...dataRedirects.map((redirect) => ({
120
- from: `${basePath}${redirect}`,
121
- to: constants_1.ODB_FUNCTION_PATH,
122
- status: 200,
123
- })),
124
- // ...then all the other fallback pages
125
- ...pageRedirects.map((redirect) => ({
126
- from: `${basePath}${redirect}`,
127
- to: constants_1.ODB_FUNCTION_PATH,
128
- status: 200,
129
- })),
130
- // Everything else is handled by the regular function
131
- { from: `${basePath}/*`, to: constants_1.HANDLER_FUNCTION_PATH, status: 200 });
121
+ });
132
122
  };
133
123
  exports.generateRedirects = generateRedirects;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });