@netlify/plugin-nextjs 4.29.3-appdir.0 → 4.29.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.
- package/lib/helpers/edge.js +13 -30
- package/lib/helpers/files.js +15 -15
- package/lib/helpers/functions.js +5 -5
- package/lib/index.js +3 -6
- package/lib/templates/getApiHandler.js +1 -1
- package/lib/templates/getHandler.js +7 -2
- package/lib/templates/handlerUtils.js +6 -7
- package/package.json +2 -2
- package/src/templates/edge/next-dev.js +11 -0
- package/src/templates/edge/runtime.ts +1 -7
package/lib/helpers/edge.js
CHANGED
|
@@ -3,7 +3,7 @@ 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.writeEdgeFunctions = exports.writeDevEdgeFunction = exports.cleanupEdgeFunctions = exports.
|
|
6
|
+
exports.writeEdgeFunctions = exports.writeDevEdgeFunction = exports.cleanupEdgeFunctions = exports.loadMiddlewareManifest = void 0;
|
|
7
7
|
/* eslint-disable max-lines */
|
|
8
8
|
const fs_1 = require("fs");
|
|
9
9
|
const path_1 = require("path");
|
|
@@ -13,15 +13,14 @@ const fs_extra_1 = require("fs-extra");
|
|
|
13
13
|
const outdent_1 = require("outdent");
|
|
14
14
|
const config_1 = require("./config");
|
|
15
15
|
const matchers_1 = require("./matchers");
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const loadMiddlewareManifest = (netlifyConfig) => {
|
|
17
|
+
const middlewarePath = (0, path_1.resolve)(netlifyConfig.build.publish, 'server', 'middleware-manifest.json');
|
|
18
|
+
if (!(0, fs_1.existsSync)(middlewarePath)) {
|
|
19
|
+
return null;
|
|
19
20
|
}
|
|
21
|
+
return (0, fs_extra_1.readJson)(middlewarePath);
|
|
20
22
|
};
|
|
21
|
-
const loadMiddlewareManifest = (netlifyConfig) => maybeLoadJson((0, path_1.resolve)(netlifyConfig.build.publish, 'server', 'middleware-manifest.json'));
|
|
22
23
|
exports.loadMiddlewareManifest = loadMiddlewareManifest;
|
|
23
|
-
const loadAppPathRoutesManifest = (netlifyConfig) => maybeLoadJson((0, path_1.resolve)(netlifyConfig.build.publish, 'app-path-routes-manifest.json'));
|
|
24
|
-
exports.loadAppPathRoutesManifest = loadAppPathRoutesManifest;
|
|
25
24
|
/**
|
|
26
25
|
* Convert the Next middleware name into a valid Edge Function name
|
|
27
26
|
*/
|
|
@@ -36,9 +35,6 @@ import {
|
|
|
36
35
|
// Deno defines "window", but naughty libraries think this means it's a browser
|
|
37
36
|
delete globalThis.window
|
|
38
37
|
globalThis.process = { env: {...Deno.env.toObject(), NEXT_RUNTIME: 'edge', 'NEXT_PRIVATE_MINIMAL_MODE': '1' } }
|
|
39
|
-
globalThis.EdgeRuntime = "netlify-edge"
|
|
40
|
-
// Next uses "self" as a function-scoped global-like object
|
|
41
|
-
const self = {}
|
|
42
38
|
let _ENTRIES = {}
|
|
43
39
|
|
|
44
40
|
// Next.js uses this extension to the Headers API implemented by Cloudflare workerd
|
|
@@ -70,6 +66,10 @@ const fetch = async (url, init) => {
|
|
|
70
66
|
}
|
|
71
67
|
}
|
|
72
68
|
|
|
69
|
+
// Next edge runtime uses "self" as a function-scoped global-like object, but some of the older polyfills expect it to equal globalThis
|
|
70
|
+
// See https://nextjs.org/docs/basic-features/supported-browsers-features#polyfills
|
|
71
|
+
const self = { ...globalThis, fetch }
|
|
72
|
+
|
|
73
73
|
`;
|
|
74
74
|
// Slightly different spacing in different versions!
|
|
75
75
|
const IMPORT_UNSUPPORTED = [
|
|
@@ -109,7 +109,7 @@ const getMiddlewareBundle = async ({ edgeFunctionDefinition, netlifyConfig, }) =
|
|
|
109
109
|
};
|
|
110
110
|
const getEdgeTemplatePath = (file) => (0, path_1.join)(__dirname, '..', '..', 'src', 'templates', 'edge', file);
|
|
111
111
|
const copyEdgeSourceFile = ({ file, target, edgeFunctionDir, }) => fs_1.promises.copyFile(getEdgeTemplatePath(file), (0, path_1.join)(edgeFunctionDir, target !== null && target !== void 0 ? target : file));
|
|
112
|
-
const writeEdgeFunction = async ({ edgeFunctionDefinition, edgeFunctionRoot, netlifyConfig,
|
|
112
|
+
const writeEdgeFunction = async ({ edgeFunctionDefinition, edgeFunctionRoot, netlifyConfig, nextConfig, }) => {
|
|
113
113
|
const name = sanitizeName(edgeFunctionDefinition.name);
|
|
114
114
|
const edgeFunctionDir = (0, path_1.join)(edgeFunctionRoot, name);
|
|
115
115
|
const bundle = await getMiddlewareBundle({
|
|
@@ -137,19 +137,11 @@ const writeEdgeFunction = async ({ edgeFunctionDefinition, edgeFunctionRoot, net
|
|
|
137
137
|
else {
|
|
138
138
|
matchers.push(...edgeFunctionDefinition.matchers);
|
|
139
139
|
}
|
|
140
|
-
// If the EF matches a page, it's an app dir page so needs a matcher too
|
|
141
|
-
// The object will be empty if appDir isn't enabled in the Next config
|
|
142
|
-
if (pageRegexMap && edgeFunctionDefinition.page in appPathRoutesManifest) {
|
|
143
|
-
const regexp = pageRegexMap.get(appPathRoutesManifest[edgeFunctionDefinition.page]);
|
|
144
|
-
if (regexp) {
|
|
145
|
-
matchers.push({ regexp });
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
140
|
await (0, fs_extra_1.writeJson)((0, path_1.join)(edgeFunctionDir, 'matchers.json'), matchers);
|
|
149
141
|
// We add a defintion for each matching path
|
|
150
142
|
return matchers.map((matcher) => {
|
|
151
143
|
const pattern = (0, matchers_1.stripLookahead)(matcher.regexp);
|
|
152
|
-
return { function: name, pattern, name: edgeFunctionDefinition.name
|
|
144
|
+
return { function: name, pattern, name: edgeFunctionDefinition.name };
|
|
153
145
|
});
|
|
154
146
|
};
|
|
155
147
|
const cleanupEdgeFunctions = ({ INTERNAL_EDGE_FUNCTIONS_SRC = '.netlify/edge-functions', }) => (0, fs_extra_1.emptyDir)(INTERNAL_EDGE_FUNCTIONS_SRC);
|
|
@@ -177,7 +169,7 @@ exports.writeDevEdgeFunction = writeDevEdgeFunction;
|
|
|
177
169
|
/**
|
|
178
170
|
* Writes Edge Functions for the Next middleware
|
|
179
171
|
*/
|
|
180
|
-
const writeEdgeFunctions = async (
|
|
172
|
+
const writeEdgeFunctions = async (netlifyConfig) => {
|
|
181
173
|
const manifest = {
|
|
182
174
|
functions: [],
|
|
183
175
|
version: 1,
|
|
@@ -224,22 +216,13 @@ const writeEdgeFunctions = async ({ netlifyConfig, routesManifest, }) => {
|
|
|
224
216
|
// Older versions of the manifest format don't have the functions field
|
|
225
217
|
// No, the version field was not incremented
|
|
226
218
|
if (typeof middlewareManifest.functions === 'object') {
|
|
227
|
-
// When using the app dir, we also need to check if the EF matches a page
|
|
228
|
-
const appPathRoutesManifest = await (0, exports.loadAppPathRoutesManifest)(netlifyConfig);
|
|
229
|
-
const pageRegexMap = new Map([...(routesManifest.dynamicRoutes || []), ...(routesManifest.staticRoutes || [])].map((route) => [
|
|
230
|
-
route.page,
|
|
231
|
-
route.regex,
|
|
232
|
-
]));
|
|
233
219
|
for (const edgeFunctionDefinition of Object.values(middlewareManifest.functions)) {
|
|
234
220
|
usesEdge = true;
|
|
235
221
|
const functionDefinitions = await writeEdgeFunction({
|
|
236
222
|
edgeFunctionDefinition,
|
|
237
223
|
edgeFunctionRoot,
|
|
238
224
|
netlifyConfig,
|
|
239
|
-
pageRegexMap,
|
|
240
|
-
appPathRoutesManifest,
|
|
241
225
|
nextConfig,
|
|
242
|
-
cache: 'manual',
|
|
243
226
|
});
|
|
244
227
|
manifest.functions.push(...functionDefinitions);
|
|
245
228
|
}
|
package/lib/helpers/files.js
CHANGED
|
@@ -70,6 +70,7 @@ exports.getMiddleware = getMiddleware;
|
|
|
70
70
|
const moveStaticPages = async ({ netlifyConfig, target, i18n, basePath, }) => {
|
|
71
71
|
console.log('Moving static page files to serve from CDN...');
|
|
72
72
|
const outputDir = (0, pathe_1.join)(netlifyConfig.build.publish, target === 'server' ? 'server' : 'serverless');
|
|
73
|
+
const root = (0, pathe_1.join)(outputDir, 'pages');
|
|
73
74
|
const buildId = (0, fs_extra_1.readFileSync)((0, pathe_1.join)(netlifyConfig.build.publish, 'BUILD_ID'), 'utf8').trim();
|
|
74
75
|
const dataDir = (0, pathe_1.join)('_next', 'data', buildId);
|
|
75
76
|
await (0, fs_extra_1.ensureDir)((0, pathe_1.join)(netlifyConfig.build.publish, dataDir));
|
|
@@ -91,17 +92,14 @@ const moveStaticPages = async ({ netlifyConfig, target, i18n, basePath, }) => {
|
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
});
|
|
94
|
-
|
|
95
|
+
const files = [];
|
|
95
96
|
const filesManifest = {};
|
|
96
97
|
const moveFile = async (file) => {
|
|
97
|
-
// Strip the initial 'app' or 'pages' directory from the output path
|
|
98
|
-
const pathname = file.split('/').slice(1).join('/');
|
|
99
|
-
// .rsc data files go next to the html file
|
|
100
98
|
const isData = file.endsWith('.json');
|
|
101
|
-
const source = (0, pathe_1.join)(
|
|
102
|
-
const targetFile = isData ? (0, pathe_1.join)(dataDir,
|
|
99
|
+
const source = (0, pathe_1.join)(root, file);
|
|
100
|
+
const targetFile = isData ? (0, pathe_1.join)(dataDir, file) : file;
|
|
103
101
|
const targetPath = basePath ? (0, pathe_1.join)(basePath, targetFile) : targetFile;
|
|
104
|
-
|
|
102
|
+
files.push(file);
|
|
105
103
|
filesManifest[file] = targetPath;
|
|
106
104
|
const dest = (0, pathe_1.join)(netlifyConfig.build.publish, targetPath);
|
|
107
105
|
try {
|
|
@@ -112,8 +110,8 @@ const moveStaticPages = async ({ netlifyConfig, target, i18n, basePath, }) => {
|
|
|
112
110
|
}
|
|
113
111
|
};
|
|
114
112
|
// Move all static files, except error documents and nft manifests
|
|
115
|
-
const pages = await (0, globby_1.default)(['{
|
|
116
|
-
cwd:
|
|
113
|
+
const pages = await (0, globby_1.default)(['**/*.{html,json}', '!**/(500|404|*.js.nft).{html,json}'], {
|
|
114
|
+
cwd: root,
|
|
117
115
|
dot: true,
|
|
118
116
|
});
|
|
119
117
|
const matchingMiddleware = new Set();
|
|
@@ -151,7 +149,7 @@ const moveStaticPages = async ({ netlifyConfig, target, i18n, basePath, }) => {
|
|
|
151
149
|
return limit(moveFile, filePath);
|
|
152
150
|
});
|
|
153
151
|
await Promise.all(promises);
|
|
154
|
-
console.log(`Moved ${
|
|
152
|
+
console.log(`Moved ${files.length} files`);
|
|
155
153
|
if (matchedPages.size !== 0) {
|
|
156
154
|
console.log((0, chalk_1.yellowBright)((0, outdent_1.outdent) `
|
|
157
155
|
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.
|
|
@@ -276,11 +274,13 @@ const getServerFile = (root, includeBase = true) => {
|
|
|
276
274
|
/**
|
|
277
275
|
* Find the source file for a given page route
|
|
278
276
|
*/
|
|
279
|
-
const getSourceFileForPage = (page,
|
|
280
|
-
for (const
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
277
|
+
const getSourceFileForPage = (page, roots) => {
|
|
278
|
+
for (const root of roots) {
|
|
279
|
+
for (const extension of SOURCE_FILE_EXTENSIONS) {
|
|
280
|
+
const file = (0, pathe_1.join)(root, `${page}.${extension}`);
|
|
281
|
+
if ((0, fs_extra_1.existsSync)(file)) {
|
|
282
|
+
return file;
|
|
283
|
+
}
|
|
284
284
|
}
|
|
285
285
|
}
|
|
286
286
|
console.log('Could not find source file for page', page);
|
package/lib/helpers/functions.js
CHANGED
|
@@ -20,13 +20,10 @@ const utils_1 = require("./utils");
|
|
|
20
20
|
const generateFunctions = async ({ FUNCTIONS_SRC = constants_1.DEFAULT_FUNCTIONS_SRC, INTERNAL_FUNCTIONS_SRC, PUBLISH_DIR }, appDir, apiRoutes) => {
|
|
21
21
|
const publish = (0, pathe_1.resolve)(PUBLISH_DIR);
|
|
22
22
|
const functionsDir = (0, pathe_1.resolve)(INTERNAL_FUNCTIONS_SRC || FUNCTIONS_SRC);
|
|
23
|
+
console.log({ functionsDir });
|
|
23
24
|
const functionDir = (0, pathe_1.join)(functionsDir, constants_1.HANDLER_FUNCTION_NAME);
|
|
24
25
|
const publishDir = (0, pathe_1.relative)(functionDir, publish);
|
|
25
26
|
for (const { route, config, compiled } of apiRoutes) {
|
|
26
|
-
// Don't write a lambda if the runtime is edge
|
|
27
|
-
if (config.runtime === 'experimental-edge') {
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
27
|
const apiHandlerSource = await (0, getApiHandler_1.getApiHandler)({
|
|
31
28
|
page: route,
|
|
32
29
|
config,
|
|
@@ -126,9 +123,12 @@ exports.setupImageFunction = setupImageFunction;
|
|
|
126
123
|
const getApiRouteConfigs = async (publish, baseDir) => {
|
|
127
124
|
const pages = await (0, fs_extra_1.readJSON)((0, pathe_1.join)(publish, 'server', 'pages-manifest.json'));
|
|
128
125
|
const apiRoutes = Object.keys(pages).filter((page) => page.startsWith('/api/'));
|
|
126
|
+
// two possible places
|
|
127
|
+
// Ref: https://nextjs.org/docs/advanced-features/src-directory
|
|
129
128
|
const pagesDir = (0, pathe_1.join)(baseDir, 'pages');
|
|
129
|
+
const srcPagesDir = (0, pathe_1.join)(baseDir, 'src', 'pages');
|
|
130
130
|
return await Promise.all(apiRoutes.map(async (apiRoute) => {
|
|
131
|
-
const filePath = (0, files_1.getSourceFileForPage)(apiRoute, pagesDir);
|
|
131
|
+
const filePath = (0, files_1.getSourceFileForPage)(apiRoute, [pagesDir, srcPagesDir]);
|
|
132
132
|
return { route: apiRoute, config: await (0, analysis_1.extractConfigFromFile)(filePath), compiled: pages[apiRoute] };
|
|
133
133
|
}));
|
|
134
134
|
};
|
package/lib/index.js
CHANGED
|
@@ -44,7 +44,7 @@ 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
|
});
|
|
@@ -118,7 +118,7 @@ const plugin = {
|
|
|
118
118
|
buildId,
|
|
119
119
|
apiRoutes,
|
|
120
120
|
});
|
|
121
|
-
await (0, edge_1.writeEdgeFunctions)(
|
|
121
|
+
await (0, edge_1.writeEdgeFunctions)(netlifyConfig);
|
|
122
122
|
},
|
|
123
123
|
async onPostBuild({ netlifyConfig: { build: { publish }, redirects, headers, }, utils: { status, cache, functions, build: { failBuild }, }, constants: { FUNCTIONS_DIST }, }) {
|
|
124
124
|
await (0, cache_1.saveCache)({ cache, publish });
|
|
@@ -134,14 +134,11 @@ const plugin = {
|
|
|
134
134
|
await (0, verification_1.checkForOldFunctions)({ functions });
|
|
135
135
|
await (0, verification_1.checkZipSize)((0, path_1.join)(FUNCTIONS_DIST, `${constants_1.ODB_FUNCTION_NAME}.zip`));
|
|
136
136
|
const nextConfig = await (0, config_1.getNextConfig)({ publish, failBuild });
|
|
137
|
-
const { basePath, appDir
|
|
137
|
+
const { basePath, appDir } = nextConfig;
|
|
138
138
|
(0, config_1.generateCustomHeaders)(nextConfig, headers);
|
|
139
139
|
(0, verification_1.warnForProblematicUserRewrites)({ basePath, redirects });
|
|
140
140
|
(0, verification_1.warnForRootRedirects)({ appDir });
|
|
141
141
|
await (0, functions_1.warnOnApiRoutes)({ FUNCTIONS_DIST });
|
|
142
|
-
if (experimental === null || experimental === void 0 ? void 0 : experimental.appDir) {
|
|
143
|
-
console.log('🧪 Thank you for testing "appDir" support on Netlify. For known issues and to give feedback, visit https://ntl.fyi/next-13-feedback');
|
|
144
|
-
}
|
|
145
142
|
},
|
|
146
143
|
};
|
|
147
144
|
// The types haven't been updated yet
|
|
@@ -105,7 +105,7 @@ const getApiHandler = ({ page, config, publishDir = '../../../.next', appDir = '
|
|
|
105
105
|
const { config } = require("${publishDir}/required-server-files.json")
|
|
106
106
|
let staticManifest
|
|
107
107
|
const path = require("path");
|
|
108
|
-
const pageRoot = path.resolve(path.join(__dirname, "${publishDir}", "
|
|
108
|
+
const pageRoot = path.resolve(path.join(__dirname, "${publishDir}", "serverless", "pages"));
|
|
109
109
|
const handler = (${makeHandler.toString()})(config, "${appDir}", pageRoot, ${JSON.stringify(page)})
|
|
110
110
|
exports.handler = ${config.type === "experimental-scheduled" /* ApiRouteType.SCHEDULED */ ? `schedule(${JSON.stringify(config.schedule)}, handler);` : 'handler'}
|
|
111
111
|
`;
|
|
@@ -37,7 +37,9 @@ const makeHandler = (conf, app, pageRoot, staticManifest = [], mode = 'ssr') =>
|
|
|
37
37
|
for (const [key, value] of Object.entries(conf.env)) {
|
|
38
38
|
process.env[key] = String(value);
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
// Set during the request as it needs the host header. Hoisted so we can define the function once
|
|
41
|
+
let base;
|
|
42
|
+
augmentFsModule({ promises, staticManifest, pageRoot, getBase: () => base });
|
|
41
43
|
// We memoize this because it can be shared between requests, but don't instantiate it until
|
|
42
44
|
// the first request because we need the host and port.
|
|
43
45
|
let bridge;
|
|
@@ -47,6 +49,9 @@ const makeHandler = (conf, app, pageRoot, staticManifest = [], mode = 'ssr') =>
|
|
|
47
49
|
}
|
|
48
50
|
const url = new URL(event.rawUrl);
|
|
49
51
|
const port = Number.parseInt(url.port) || 80;
|
|
52
|
+
const { host } = event.headers;
|
|
53
|
+
const protocol = event.headers['x-forwarded-proto'] || 'http';
|
|
54
|
+
base = `${protocol}://${host}`;
|
|
50
55
|
const NextServer = getNextServer();
|
|
51
56
|
const nextServer = new NextServer({
|
|
52
57
|
conf,
|
|
@@ -144,7 +149,7 @@ const getHandler = ({ isODB = false, publishDir = '../../../.next', appDir = '..
|
|
|
144
149
|
staticManifest = require("${publishDir}/static-manifest.json")
|
|
145
150
|
} catch {}
|
|
146
151
|
const path = require("path");
|
|
147
|
-
const pageRoot = path.resolve(path.join(__dirname, "${publishDir}", "server"));
|
|
152
|
+
const pageRoot = path.resolve(path.join(__dirname, "${publishDir}", config.target === "server" ? "server" : "serverless", "pages"));
|
|
148
153
|
exports.handler = ${isODB
|
|
149
154
|
? `builder((${makeHandler.toString()})(config, "${appDir}", pageRoot, staticManifest, 'odb'));`
|
|
150
155
|
: `(${makeHandler.toString()})(config, "${appDir}", pageRoot, staticManifest, 'ssr');`}
|
|
@@ -75,7 +75,7 @@ exports.getMultiValueHeaders = getMultiValueHeaders;
|
|
|
75
75
|
/**
|
|
76
76
|
* Monkey-patch the fs module to download missing files from the CDN
|
|
77
77
|
*/
|
|
78
|
-
const augmentFsModule = ({ promises, staticManifest, pageRoot, }) => {
|
|
78
|
+
const augmentFsModule = ({ promises, staticManifest, pageRoot, getBase, }) => {
|
|
79
79
|
// Only do this if we have some static files moved to the CDN
|
|
80
80
|
if (staticManifest.length === 0) {
|
|
81
81
|
return;
|
|
@@ -93,23 +93,22 @@ const augmentFsModule = ({ promises, staticManifest, pageRoot, }) => {
|
|
|
93
93
|
const statsOrig = promises.stat;
|
|
94
94
|
// ...then money-patch it to see if it's requesting a CDN file
|
|
95
95
|
promises.readFile = (async (file, options) => {
|
|
96
|
-
|
|
97
|
-
const baseUrl = process.env.CONTEXT === 'production' ? process.env.URL : process.env.DEPLOY_PRIME_URL;
|
|
96
|
+
const base = getBase();
|
|
98
97
|
// We only care about page files
|
|
99
98
|
if (file.startsWith(pageRoot)) {
|
|
100
|
-
// We only want the part after
|
|
99
|
+
// We only want the part after `pages/`
|
|
101
100
|
const filePath = file.slice(pageRoot.length + 1);
|
|
102
101
|
// Is it in the CDN and not local?
|
|
103
102
|
if (staticFiles.has(filePath) && !(0, fs_1.existsSync)(file)) {
|
|
104
103
|
// This name is safe to use, because it's one that was already created by Next
|
|
105
104
|
const cacheFile = path_1.default.join(cacheDir, filePath);
|
|
106
|
-
const url = `${
|
|
105
|
+
const url = `${base}/${staticFiles.get(filePath)}`;
|
|
107
106
|
// If it's already downloading we can wait for it to finish
|
|
108
107
|
if (downloadPromises.has(url)) {
|
|
109
108
|
await downloadPromises.get(url);
|
|
110
109
|
}
|
|
111
110
|
// Have we already cached it? We download every time if running locally to avoid staleness
|
|
112
|
-
if ((!(0, fs_1.existsSync)(cacheFile) || process.env.NETLIFY_DEV) &&
|
|
111
|
+
if ((!(0, fs_1.existsSync)(cacheFile) || process.env.NETLIFY_DEV) && base) {
|
|
113
112
|
await promises.mkdir(path_1.default.dirname(cacheFile), { recursive: true });
|
|
114
113
|
try {
|
|
115
114
|
// Append the path to our host and we can load it like a regular page
|
|
@@ -130,7 +129,7 @@ const augmentFsModule = ({ promises, staticManifest, pageRoot, }) => {
|
|
|
130
129
|
promises.stat = ((file, options) => {
|
|
131
130
|
// We only care about page files
|
|
132
131
|
if (file.startsWith(pageRoot)) {
|
|
133
|
-
// We only want the part after
|
|
132
|
+
// We only want the part after `pages/`
|
|
134
133
|
const cacheFile = path_1.default.join(cacheDir, file.slice(pageRoot.length + 1));
|
|
135
134
|
if ((0, fs_1.existsSync)(cacheFile)) {
|
|
136
135
|
return statsOrig(cacheFile, options);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/plugin-nextjs",
|
|
3
|
-
"version": "4.29.3
|
|
3
|
+
"version": "4.29.3",
|
|
4
4
|
"description": "Run Next.js seamlessly on Netlify",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@delucis/if-env": "^1.1.2",
|
|
39
|
-
"@netlify/build": "^28.4.
|
|
39
|
+
"@netlify/build": "^28.4.5",
|
|
40
40
|
"@types/fs-extra": "^9.0.13",
|
|
41
41
|
"@types/jest": "^27.4.1",
|
|
42
42
|
"@types/merge-stream": "^1.1.2",
|
|
@@ -6,6 +6,17 @@ import { buildResponse } from '../edge-shared/utils.ts'
|
|
|
6
6
|
globalThis.NFRequestContextMap ||= new Map()
|
|
7
7
|
globalThis.__dirname = fromFileUrl(new URL('./', import.meta.url)).slice(0, -1)
|
|
8
8
|
|
|
9
|
+
// Next.js uses this extension to the Headers API implemented by Cloudflare workerd
|
|
10
|
+
if (!('getAll' in Headers.prototype)) {
|
|
11
|
+
Headers.prototype.getAll = function getAll(name) {
|
|
12
|
+
name = name.toLowerCase()
|
|
13
|
+
if (name !== 'set-cookie') {
|
|
14
|
+
throw new Error('Headers.getAll is only supported for Set-Cookie')
|
|
15
|
+
}
|
|
16
|
+
return [...this.entries()].filter(([key]) => key === name).map(([, value]) => value)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
9
20
|
// Check if a file exists, given a relative path
|
|
10
21
|
const exists = async (relativePath) => {
|
|
11
22
|
const path = fromFileUrl(new URL(relativePath, import.meta.url))
|
|
@@ -13,12 +13,6 @@ export interface FetchEventResult {
|
|
|
13
13
|
waitUntil: Promise<any>
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export interface I18NConfig {
|
|
17
|
-
defaultLocale: string
|
|
18
|
-
localeDetection?: false
|
|
19
|
-
locales: string[]
|
|
20
|
-
}
|
|
21
|
-
|
|
22
16
|
export interface RequestData {
|
|
23
17
|
geo?: {
|
|
24
18
|
city?: string
|
|
@@ -33,7 +27,7 @@ export interface RequestData {
|
|
|
33
27
|
method: string
|
|
34
28
|
nextConfig?: {
|
|
35
29
|
basePath?: string
|
|
36
|
-
i18n?:
|
|
30
|
+
i18n?: Record<string, unknown>
|
|
37
31
|
trailingSlash?: boolean
|
|
38
32
|
}
|
|
39
33
|
page?: {
|