@netlify/plugin-nextjs 5.5.1 → 5.7.0-ipx.0
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/dist/build/content/server.js +1 -1
- package/dist/build/functions/edge.js +5 -4
- package/dist/build/functions/ipx.js +83 -0
- package/dist/build/functions/server.js +8 -9
- package/dist/build/image-cdn.js +64 -59
- package/dist/build/plugin-context.js +16 -0
- package/dist/build/templates/ipx-edge-accept-handler.ts +13 -0
- package/dist/build/templates/ipx.ts +11 -0
- package/dist/build/verification.js +2 -3
- package/dist/esm-chunks/{package-SHOGGUO3.js → package-O63J727E.js} +8 -4
- package/dist/index.js +1 -1
- package/dist/run/handlers/tracing.js +1 -1
- package/edge-runtime/lib/next-request.ts +28 -0
- package/edge-runtime/lib/util.ts +14 -0
- package/edge-runtime/middleware.ts +7 -3
- package/package.json +5 -2
|
@@ -169,7 +169,7 @@ var copyNextDependencies = async (ctx) => {
|
|
|
169
169
|
await tracer.withActiveSpan("copyNextDependencies", async () => {
|
|
170
170
|
const entries = await readdir(ctx.standaloneDir);
|
|
171
171
|
const promises = entries.map(async (entry) => {
|
|
172
|
-
if (entry ===
|
|
172
|
+
if (entry === ctx.nextDistDir) {
|
|
173
173
|
return;
|
|
174
174
|
}
|
|
175
175
|
const src = join(ctx.standaloneDir, entry);
|
|
@@ -392,6 +392,7 @@ var import_path_to_regexp = __toESM(require_dist(), 1);
|
|
|
392
392
|
import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
393
393
|
import { dirname, join } from "node:path";
|
|
394
394
|
import { EDGE_HANDLER_NAME } from "../plugin-context.js";
|
|
395
|
+
import { createIpxEdgeAcceptHandler } from "./ipx.js";
|
|
395
396
|
var writeEdgeManifest = async (ctx, manifest) => {
|
|
396
397
|
await mkdir(ctx.edgeFunctionsDir, { recursive: true });
|
|
397
398
|
await writeFile(join(ctx.edgeFunctionsDir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
@@ -431,10 +432,7 @@ var writeHandlerFile = async (ctx, { matchers, name }) => {
|
|
|
431
432
|
const handlerDirectory = join(ctx.edgeFunctionsDir, handlerName);
|
|
432
433
|
const handlerRuntimeDirectory = join(handlerDirectory, "edge-runtime");
|
|
433
434
|
await copyRuntime(ctx, handlerDirectory);
|
|
434
|
-
await writeFile(
|
|
435
|
-
join(handlerRuntimeDirectory, "matchers.json"),
|
|
436
|
-
JSON.stringify(augmentMatchers(matchers, ctx))
|
|
437
|
-
);
|
|
435
|
+
await writeFile(join(handlerRuntimeDirectory, "matchers.json"), JSON.stringify(matchers));
|
|
438
436
|
const minimalNextConfig = {
|
|
439
437
|
basePath: nextConfig.basePath,
|
|
440
438
|
i18n: nextConfig.i18n,
|
|
@@ -516,6 +514,9 @@ var createEdgeHandlers = async (ctx) => {
|
|
|
516
514
|
version: 1,
|
|
517
515
|
functions: netlifyDefinitions
|
|
518
516
|
};
|
|
517
|
+
if (ctx.imageService === "ipx") {
|
|
518
|
+
await createIpxEdgeAcceptHandler(ctx, netlifyManifest);
|
|
519
|
+
}
|
|
519
520
|
await writeEdgeManifest(ctx, netlifyManifest);
|
|
520
521
|
};
|
|
521
522
|
export {
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
|
|
2
|
+
var require = await (async () => {
|
|
3
|
+
var { createRequire } = await import("node:module");
|
|
4
|
+
return createRequire(import.meta.url);
|
|
5
|
+
})();
|
|
6
|
+
|
|
7
|
+
import "../../esm-chunks/chunk-OEQOKJGE.js";
|
|
8
|
+
|
|
9
|
+
// src/build/functions/ipx.ts
|
|
10
|
+
import { cp, mkdir, writeFile } from "fs/promises";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
import { IPX_HANDLER_NAME } from "../plugin-context.js";
|
|
13
|
+
var sanitizeEdgePath = (imagesPath) => new URL(imagesPath, process.env.URL || "http://n").pathname;
|
|
14
|
+
var getAdjustedImageConfig = (ctx) => {
|
|
15
|
+
return {
|
|
16
|
+
...ctx.buildConfig.images,
|
|
17
|
+
basePath: [ctx.buildConfig.basePath, IPX_HANDLER_NAME].join("/")
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
var createIpxHandler = async (ctx) => {
|
|
21
|
+
await mkdir(ctx.ipxHandlerRootDir, { recursive: true });
|
|
22
|
+
await cp(
|
|
23
|
+
join(ctx.pluginDir, "dist/build/templates/ipx.ts"),
|
|
24
|
+
join(ctx.ipxHandlerRootDir, "_ipx.ts")
|
|
25
|
+
);
|
|
26
|
+
await writeFile(
|
|
27
|
+
join(ctx.ipxHandlerRootDir, "imageconfig.json"),
|
|
28
|
+
JSON.stringify(getAdjustedImageConfig(ctx))
|
|
29
|
+
);
|
|
30
|
+
await writeFile(
|
|
31
|
+
join(ctx.ipxHandlerRootDir, "_ipx.json"),
|
|
32
|
+
JSON.stringify({
|
|
33
|
+
version: 1,
|
|
34
|
+
config: {
|
|
35
|
+
name: "next/image handler",
|
|
36
|
+
generator: `${ctx.pluginName}@${ctx.pluginVersion}`,
|
|
37
|
+
timeout: 120
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
);
|
|
41
|
+
ctx.netlifyConfig.redirects.push(
|
|
42
|
+
{
|
|
43
|
+
from: ctx.buildConfig.images.path,
|
|
44
|
+
// eslint-disable-next-line id-length
|
|
45
|
+
query: { url: ":url", w: ":width", q: ":quality" },
|
|
46
|
+
to: `${ctx.buildConfig.basePath}/${IPX_HANDLER_NAME}/w_:width,q_:quality/:url`,
|
|
47
|
+
status: 301
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
from: `${ctx.buildConfig.basePath}/${IPX_HANDLER_NAME}/*`,
|
|
51
|
+
to: `/.netlify/builders/${IPX_HANDLER_NAME}`,
|
|
52
|
+
status: 200
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
var createIpxEdgeAcceptHandler = async (ctx, netlifyManifest) => {
|
|
57
|
+
await mkdir(ctx.ipxEdgeHandlerRootDir, { recursive: true });
|
|
58
|
+
await cp(
|
|
59
|
+
join(ctx.pluginDir, "dist/build/templates/ipx-edge-accept-handler.ts"),
|
|
60
|
+
join(ctx.ipxEdgeHandlerRootDir, "index.ts")
|
|
61
|
+
);
|
|
62
|
+
await writeFile(
|
|
63
|
+
join(ctx.ipxEdgeHandlerRootDir, "imageconfig.json"),
|
|
64
|
+
JSON.stringify(getAdjustedImageConfig(ctx))
|
|
65
|
+
);
|
|
66
|
+
netlifyManifest.functions.push({
|
|
67
|
+
function: IPX_HANDLER_NAME,
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
69
|
+
// @ts-ignore
|
|
70
|
+
name: "next/image handler",
|
|
71
|
+
path: ctx.buildConfig.images.path ? sanitizeEdgePath(ctx.buildConfig.images.path) : "/_next/image",
|
|
72
|
+
generator: `${ctx.pluginName}@${ctx.pluginVersion}`
|
|
73
|
+
});
|
|
74
|
+
netlifyManifest.layers ??= [];
|
|
75
|
+
netlifyManifest.layers.push({
|
|
76
|
+
name: `https://ipx-edge-function-layer.netlify.app/mod.ts`,
|
|
77
|
+
flag: "ipx-edge-function-layer-url"
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
export {
|
|
81
|
+
createIpxEdgeAcceptHandler,
|
|
82
|
+
createIpxHandler
|
|
83
|
+
};
|
|
@@ -61,10 +61,16 @@ var copyHandlerDependencies = async (ctx) => {
|
|
|
61
61
|
)
|
|
62
62
|
);
|
|
63
63
|
}
|
|
64
|
+
promises.push(
|
|
65
|
+
writeFile(
|
|
66
|
+
join(ctx.serverHandlerRuntimeModulesDir, "package.json"),
|
|
67
|
+
JSON.stringify({ type: "module" })
|
|
68
|
+
)
|
|
69
|
+
);
|
|
64
70
|
const fileList = await (0, import_fast_glob.glob)("dist/**/*", { cwd: ctx.pluginDir });
|
|
65
71
|
for (const filePath of fileList) {
|
|
66
72
|
promises.push(
|
|
67
|
-
cp(join(ctx.pluginDir, filePath), join(ctx.
|
|
73
|
+
cp(join(ctx.pluginDir, filePath), join(ctx.serverHandlerRuntimeModulesDir, filePath), {
|
|
68
74
|
recursive: true,
|
|
69
75
|
force: true
|
|
70
76
|
})
|
|
@@ -90,12 +96,6 @@ var writeHandlerManifest = async (ctx) => {
|
|
|
90
96
|
"utf-8"
|
|
91
97
|
);
|
|
92
98
|
};
|
|
93
|
-
var writePackageMetadata = async (ctx) => {
|
|
94
|
-
await writeFile(
|
|
95
|
-
join(ctx.serverHandlerRootDir, "package.json"),
|
|
96
|
-
JSON.stringify({ type: "module" })
|
|
97
|
-
);
|
|
98
|
-
};
|
|
99
99
|
var applyTemplateVariables = (template, variables) => {
|
|
100
100
|
return Object.entries(variables).reduce((acc, [key, value]) => {
|
|
101
101
|
return acc.replaceAll(key, value);
|
|
@@ -126,12 +126,11 @@ var clearStaleServerHandlers = async (ctx) => {
|
|
|
126
126
|
};
|
|
127
127
|
var createServerHandler = async (ctx) => {
|
|
128
128
|
await tracer.withActiveSpan("createServerHandler", async () => {
|
|
129
|
-
await mkdir(join(ctx.
|
|
129
|
+
await mkdir(join(ctx.serverHandlerRuntimeModulesDir), { recursive: true });
|
|
130
130
|
await copyNextServerCode(ctx);
|
|
131
131
|
await copyNextDependencies(ctx);
|
|
132
132
|
await copyHandlerDependencies(ctx);
|
|
133
133
|
await writeHandlerManifest(ctx);
|
|
134
|
-
await writePackageMetadata(ctx);
|
|
135
134
|
await writeHandlerFile(ctx);
|
|
136
135
|
await verifyHandlerDirStructure(ctx);
|
|
137
136
|
});
|
package/dist/build/image-cdn.js
CHANGED
|
@@ -1528,6 +1528,7 @@ var require_picomatch2 = __commonJS({
|
|
|
1528
1528
|
|
|
1529
1529
|
// src/build/image-cdn.ts
|
|
1530
1530
|
var import_picomatch = __toESM(require_picomatch2(), 1);
|
|
1531
|
+
import { createIpxHandler } from "./functions/ipx.js";
|
|
1531
1532
|
function generateRegexFromPattern(pattern) {
|
|
1532
1533
|
return (0, import_picomatch.makeRe)(pattern).source;
|
|
1533
1534
|
}
|
|
@@ -1538,67 +1539,71 @@ var setImageConfig = async (ctx) => {
|
|
|
1538
1539
|
if (imageLoader !== "default") {
|
|
1539
1540
|
return;
|
|
1540
1541
|
}
|
|
1541
|
-
ctx.
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
//
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
if (remotePatterns
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1542
|
+
if (ctx.imageService === "ipx") {
|
|
1543
|
+
await createIpxHandler(ctx);
|
|
1544
|
+
} else {
|
|
1545
|
+
ctx.netlifyConfig.redirects.push(
|
|
1546
|
+
{
|
|
1547
|
+
from: imageEndpointPath,
|
|
1548
|
+
// w and q are too short to be used as params with id-length rule
|
|
1549
|
+
// but we are forced to do so because of the next/image loader decides on their names
|
|
1550
|
+
// eslint-disable-next-line id-length
|
|
1551
|
+
query: { url: ":url", w: ":width", q: ":quality" },
|
|
1552
|
+
to: "/.netlify/images?url=:url&w=:width&q=:quality",
|
|
1553
|
+
status: 200
|
|
1554
|
+
},
|
|
1555
|
+
// when migrating from @netlify/plugin-nextjs@4 image redirect to ipx might be cached in the browser
|
|
1556
|
+
{
|
|
1557
|
+
from: "/_ipx/*",
|
|
1558
|
+
// w and q are too short to be used as params with id-length rule
|
|
1559
|
+
// but we are forced to do so because of the next/image loader decides on their names
|
|
1560
|
+
// eslint-disable-next-line id-length
|
|
1561
|
+
query: { url: ":url", w: ":width", q: ":quality" },
|
|
1562
|
+
to: "/.netlify/images?url=:url&w=:width&q=:quality",
|
|
1563
|
+
status: 200
|
|
1564
|
+
}
|
|
1565
|
+
);
|
|
1566
|
+
if (remotePatterns?.length !== 0 || domains?.length !== 0) {
|
|
1567
|
+
ctx.netlifyConfig.images ||= { remote_images: [] };
|
|
1568
|
+
ctx.netlifyConfig.images.remote_images ||= [];
|
|
1569
|
+
if (remotePatterns && remotePatterns.length !== 0) {
|
|
1570
|
+
for (const remotePattern of remotePatterns) {
|
|
1571
|
+
let { protocol, hostname, port, pathname } = remotePattern;
|
|
1572
|
+
if (pathname) {
|
|
1573
|
+
pathname = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
1574
|
+
}
|
|
1575
|
+
const combinedRemotePattern = `${protocol ?? "http?(s)"}://${hostname}${port ? `:${port}` : ""}${pathname ?? "/**"}`;
|
|
1576
|
+
try {
|
|
1577
|
+
ctx.netlifyConfig.images.remote_images.push(
|
|
1578
|
+
generateRegexFromPattern(combinedRemotePattern)
|
|
1579
|
+
);
|
|
1580
|
+
} catch (error) {
|
|
1581
|
+
ctx.failBuild(
|
|
1582
|
+
`Failed to generate Image CDN remote image regex from Next.js remote pattern: ${JSON.stringify(
|
|
1583
|
+
{ remotePattern, combinedRemotePattern },
|
|
1584
|
+
null,
|
|
1585
|
+
2
|
|
1586
|
+
)}`,
|
|
1587
|
+
error
|
|
1588
|
+
);
|
|
1589
|
+
}
|
|
1585
1590
|
}
|
|
1586
1591
|
}
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1592
|
+
if (domains && domains.length !== 0) {
|
|
1593
|
+
for (const domain of domains) {
|
|
1594
|
+
const patternFromDomain = `http?(s)://${domain}/**`;
|
|
1595
|
+
try {
|
|
1596
|
+
ctx.netlifyConfig.images.remote_images.push(generateRegexFromPattern(patternFromDomain));
|
|
1597
|
+
} catch (error) {
|
|
1598
|
+
ctx.failBuild(
|
|
1599
|
+
`Failed to generate Image CDN remote image regex from Next.js domain: ${JSON.stringify(
|
|
1600
|
+
{ domain, patternFromDomain },
|
|
1601
|
+
null,
|
|
1602
|
+
2
|
|
1603
|
+
)}`,
|
|
1604
|
+
error
|
|
1605
|
+
);
|
|
1606
|
+
}
|
|
1602
1607
|
}
|
|
1603
1608
|
}
|
|
1604
1609
|
}
|
|
@@ -23,6 +23,7 @@ var MODULE_DIR = fileURLToPath(new URL(".", import.meta.url));
|
|
|
23
23
|
var PLUGIN_DIR = join(MODULE_DIR, "../..");
|
|
24
24
|
var DEFAULT_PUBLISH_DIR = ".next";
|
|
25
25
|
var SERVER_HANDLER_NAME = "___netlify-server-handler";
|
|
26
|
+
var IPX_HANDLER_NAME = "_ipx";
|
|
26
27
|
var EDGE_HANDLER_NAME = "___netlify-edge-handler";
|
|
27
28
|
var PluginContext = class {
|
|
28
29
|
featureFlags;
|
|
@@ -116,6 +117,9 @@ var PluginContext = class {
|
|
|
116
117
|
const REQUIRED_BUILD_VERSION = ">=29.41.5";
|
|
117
118
|
return (0, import_semver.satisfies)(this.buildVersion, REQUIRED_BUILD_VERSION, { includePrerelease: true });
|
|
118
119
|
}
|
|
120
|
+
get imageService() {
|
|
121
|
+
return "ipx";
|
|
122
|
+
}
|
|
119
123
|
/**
|
|
120
124
|
* Absolute path of the directory containing the files for the serverless lambda function
|
|
121
125
|
* `.netlify/functions-internal`
|
|
@@ -127,12 +131,19 @@ var PluginContext = class {
|
|
|
127
131
|
get serverHandlerRootDir() {
|
|
128
132
|
return join(this.serverFunctionsDir, SERVER_HANDLER_NAME);
|
|
129
133
|
}
|
|
134
|
+
/** Absolute path of the ipx handler */
|
|
135
|
+
get ipxHandlerRootDir() {
|
|
136
|
+
return join(this.serverFunctionsDir, IPX_HANDLER_NAME);
|
|
137
|
+
}
|
|
130
138
|
get serverHandlerDir() {
|
|
131
139
|
if (this.relativeAppDir.length === 0) {
|
|
132
140
|
return this.serverHandlerRootDir;
|
|
133
141
|
}
|
|
134
142
|
return join(this.serverHandlerRootDir, this.distDirParent);
|
|
135
143
|
}
|
|
144
|
+
get serverHandlerRuntimeModulesDir() {
|
|
145
|
+
return join(this.serverHandlerDir, ".netlify");
|
|
146
|
+
}
|
|
136
147
|
get nextServerHandler() {
|
|
137
148
|
if (this.relativeAppDir.length !== 0) {
|
|
138
149
|
return join(this.lambdaWorkingDirectory, ".netlify/dist/run/handlers/server.js");
|
|
@@ -150,6 +161,10 @@ var PluginContext = class {
|
|
|
150
161
|
get edgeHandlerDir() {
|
|
151
162
|
return join(this.edgeFunctionsDir, EDGE_HANDLER_NAME);
|
|
152
163
|
}
|
|
164
|
+
/** Absolute path of the ipx edge handler */
|
|
165
|
+
get ipxEdgeHandlerRootDir() {
|
|
166
|
+
return join(this.edgeFunctionsDir, IPX_HANDLER_NAME);
|
|
167
|
+
}
|
|
153
168
|
constructor(options) {
|
|
154
169
|
this.constants = options.constants;
|
|
155
170
|
this.featureFlags = options.featureFlags;
|
|
@@ -273,6 +288,7 @@ var PluginContext = class {
|
|
|
273
288
|
};
|
|
274
289
|
export {
|
|
275
290
|
EDGE_HANDLER_NAME,
|
|
291
|
+
IPX_HANDLER_NAME,
|
|
276
292
|
PluginContext,
|
|
277
293
|
SERVER_HANDLER_NAME
|
|
278
294
|
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2
|
+
// @ts-ignore
|
|
3
|
+
import { getHandler } from 'https://ipx-edge-function-layer.netlify.app/mod.ts'
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
6
|
+
// @ts-ignore Injected at build time
|
|
7
|
+
import imageconfig from './imageconfig.json' assert { type: 'json' }
|
|
8
|
+
|
|
9
|
+
export default getHandler({
|
|
10
|
+
formats: imageconfig?.formats,
|
|
11
|
+
basePath: imageconfig?.basePath,
|
|
12
|
+
imageCDNCompat: true,
|
|
13
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createIPXHandler } from '@netlify/ipx'
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
4
|
+
// @ts-ignore Injected at build time
|
|
5
|
+
import { basePath, domains, remotePatterns } from './imageconfig.json'
|
|
6
|
+
|
|
7
|
+
export const handler = createIPXHandler({
|
|
8
|
+
basePath,
|
|
9
|
+
domains,
|
|
10
|
+
remotePatterns,
|
|
11
|
+
})
|
|
@@ -103,11 +103,10 @@ async function verifyNetlifyFormsWorkaround(ctx) {
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
function verifyNetlifyForms(ctx, html) {
|
|
106
|
-
if (
|
|
107
|
-
|
|
106
|
+
if (process.env.NETLIFY_NEXT_VERIFY_FORMS !== "0" && process.env.NETLIFY_NEXT_VERIFY_FORMS?.toUpperCase() !== "FALSE" && !verifications.has("netlifyFormsWorkaround") && formDetectionRegex.test(html)) {
|
|
107
|
+
ctx.failBuild(
|
|
108
108
|
"@netlify/plugin-nextjs@5 requires migration steps to support Netlify Forms. Refer to https://ntl.fyi/next-runtime-forms-migration for migration example."
|
|
109
109
|
);
|
|
110
|
-
verifications.add("netlifyForms");
|
|
111
110
|
}
|
|
112
111
|
}
|
|
113
112
|
export {
|
|
@@ -8,7 +8,7 @@ import "./chunk-OEQOKJGE.js";
|
|
|
8
8
|
|
|
9
9
|
// package.json
|
|
10
10
|
var name = "@netlify/plugin-nextjs";
|
|
11
|
-
var version = "5.
|
|
11
|
+
var version = "5.7.0-ipx.0";
|
|
12
12
|
var description = "Run Next.js seamlessly on Netlify";
|
|
13
13
|
var main = "./dist/index.js";
|
|
14
14
|
var type = "module";
|
|
@@ -55,15 +55,18 @@ var bugs = {
|
|
|
55
55
|
url: "https://github.com/netlify/next-runtime/issues"
|
|
56
56
|
};
|
|
57
57
|
var homepage = "https://github.com/netlify/next-runtime#readme";
|
|
58
|
+
var dependencies = {
|
|
59
|
+
"@netlify/ipx": "^1.4.6"
|
|
60
|
+
};
|
|
58
61
|
var devDependencies = {
|
|
59
62
|
"@fastly/http-compute-js": "1.1.4",
|
|
60
63
|
"@netlify/blobs": "^7.3.0",
|
|
61
64
|
"@netlify/build": "^29.50.2",
|
|
62
65
|
"@netlify/edge-bundler": "^12.1.1",
|
|
63
|
-
"@netlify/edge-functions": "^2.
|
|
66
|
+
"@netlify/edge-functions": "^2.10.0",
|
|
64
67
|
"@netlify/eslint-config-node": "^7.0.1",
|
|
65
68
|
"@netlify/functions": "^2.8.1",
|
|
66
|
-
"@netlify/serverless-functions-api": "^1.
|
|
69
|
+
"@netlify/serverless-functions-api": "^1.22.0",
|
|
67
70
|
"@netlify/zip-it-and-ship-it": "^9.37.3",
|
|
68
71
|
"@opentelemetry/api": "^1.8.0",
|
|
69
72
|
"@opentelemetry/exporter-trace-otlp-http": "^0.51.0",
|
|
@@ -104,7 +107,6 @@ var clean_package = {
|
|
|
104
107
|
indent: 2,
|
|
105
108
|
remove: [
|
|
106
109
|
"clean-package",
|
|
107
|
-
"dependencies",
|
|
108
110
|
"devDependencies",
|
|
109
111
|
"scripts"
|
|
110
112
|
]
|
|
@@ -123,6 +125,7 @@ var package_default = {
|
|
|
123
125
|
license,
|
|
124
126
|
bugs,
|
|
125
127
|
homepage,
|
|
128
|
+
dependencies,
|
|
126
129
|
devDependencies,
|
|
127
130
|
"clean-package": clean_package
|
|
128
131
|
};
|
|
@@ -130,6 +133,7 @@ export {
|
|
|
130
133
|
bugs,
|
|
131
134
|
clean_package as "clean-package",
|
|
132
135
|
package_default as default,
|
|
136
|
+
dependencies,
|
|
133
137
|
description,
|
|
134
138
|
devDependencies,
|
|
135
139
|
engines,
|
package/dist/index.js
CHANGED
|
@@ -62,7 +62,7 @@ var onBuild = async (options) => {
|
|
|
62
62
|
await saveBuildCache(ctx);
|
|
63
63
|
}
|
|
64
64
|
if (ctx.buildConfig.output === "export") {
|
|
65
|
-
return copyStaticExport(ctx);
|
|
65
|
+
return Promise.all([copyStaticExport(ctx), setImageConfig(ctx)]);
|
|
66
66
|
}
|
|
67
67
|
await verifyAdvancedAPIRoutes(ctx);
|
|
68
68
|
await verifyNetlifyFormsWorkaround(ctx);
|
|
@@ -67385,7 +67385,7 @@ var import_semantic_conventions = __toESM(require_src(), 1);
|
|
|
67385
67385
|
import { getLogger } from "./request-context.cjs";
|
|
67386
67386
|
var {
|
|
67387
67387
|
default: { version, name }
|
|
67388
|
-
} = await import("../../esm-chunks/package-
|
|
67388
|
+
} = await import("../../esm-chunks/package-O63J727E.js");
|
|
67389
67389
|
var sdk = new import_sdk_node.NodeSDK({
|
|
67390
67390
|
resource: new import_resources.Resource({
|
|
67391
67391
|
[import_semantic_conventions.SEMRESATTRS_SERVICE_NAME]: name,
|
|
@@ -2,6 +2,7 @@ import type { Context } from '@netlify/edge-functions'
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
addBasePath,
|
|
5
|
+
addLocale,
|
|
5
6
|
addTrailingSlash,
|
|
6
7
|
normalizeDataUrl,
|
|
7
8
|
normalizeLocalePath,
|
|
@@ -73,6 +74,33 @@ const normalizeRequestURL = (
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
export const localizeRequest = (
|
|
78
|
+
url: URL,
|
|
79
|
+
nextConfig?: {
|
|
80
|
+
basePath?: string
|
|
81
|
+
i18n?: I18NConfig | null
|
|
82
|
+
},
|
|
83
|
+
): { localizedUrl: URL; locale?: string } => {
|
|
84
|
+
const localizedUrl = new URL(url)
|
|
85
|
+
localizedUrl.pathname = removeBasePath(localizedUrl.pathname, nextConfig?.basePath)
|
|
86
|
+
|
|
87
|
+
// Detect the locale from the URL
|
|
88
|
+
const { detectedLocale } = normalizeLocalePath(localizedUrl.pathname, nextConfig?.i18n?.locales)
|
|
89
|
+
|
|
90
|
+
// Add the locale to the URL if not already present
|
|
91
|
+
localizedUrl.pathname = addLocale(
|
|
92
|
+
localizedUrl.pathname,
|
|
93
|
+
detectedLocale ?? nextConfig?.i18n?.defaultLocale,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
localizedUrl.pathname = addBasePath(localizedUrl.pathname, nextConfig?.basePath)
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
localizedUrl,
|
|
100
|
+
locale: detectedLocale,
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
76
104
|
export const buildNextRequest = (
|
|
77
105
|
request: Request,
|
|
78
106
|
context: Context,
|
package/edge-runtime/lib/util.ts
CHANGED
|
@@ -29,6 +29,20 @@ export const addBasePath = (path: string, basePath?: string) => {
|
|
|
29
29
|
return path
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
// add locale prefix if not present, allowing for locale fallbacks
|
|
33
|
+
export const addLocale = (path: string, locale?: string) => {
|
|
34
|
+
if (
|
|
35
|
+
locale &&
|
|
36
|
+
path.toLowerCase() !== `/${locale.toLowerCase()}` &&
|
|
37
|
+
!path.toLowerCase().startsWith(`/${locale.toLowerCase()}/`) &&
|
|
38
|
+
!path.startsWith(`/api/`) &&
|
|
39
|
+
!path.startsWith(`/_next/`)
|
|
40
|
+
) {
|
|
41
|
+
return `/${locale}${path}`
|
|
42
|
+
}
|
|
43
|
+
return path
|
|
44
|
+
}
|
|
45
|
+
|
|
32
46
|
// https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/i18n/normalize-locale-path.ts
|
|
33
47
|
|
|
34
48
|
export interface PathLocale {
|
|
@@ -5,7 +5,7 @@ import nextConfig from './next.config.json' with { type: 'json' }
|
|
|
5
5
|
|
|
6
6
|
import { InternalHeaders } from './lib/headers.ts'
|
|
7
7
|
import { logger, LogLevel } from './lib/logging.ts'
|
|
8
|
-
import { buildNextRequest, RequestData } from './lib/next-request.ts'
|
|
8
|
+
import { buildNextRequest, localizeRequest, RequestData } from './lib/next-request.ts'
|
|
9
9
|
import { buildResponse, FetchEventResult } from './lib/response.ts'
|
|
10
10
|
import {
|
|
11
11
|
getMiddlewareRouteMatcher,
|
|
@@ -31,8 +31,8 @@ export async function handleMiddleware(
|
|
|
31
31
|
context: Context,
|
|
32
32
|
nextHandler: NextHandler,
|
|
33
33
|
) {
|
|
34
|
-
const nextRequest = buildNextRequest(request, context, nextConfig)
|
|
35
34
|
const url = new URL(request.url)
|
|
35
|
+
|
|
36
36
|
const reqLogger = logger
|
|
37
37
|
.withLogLevel(
|
|
38
38
|
request.headers.has(InternalHeaders.NFDebugLogging) ? LogLevel.Debug : LogLevel.Log,
|
|
@@ -40,16 +40,20 @@ export async function handleMiddleware(
|
|
|
40
40
|
.withFields({ url_path: url.pathname })
|
|
41
41
|
.withRequestID(request.headers.get(InternalHeaders.NFRequestID))
|
|
42
42
|
|
|
43
|
+
const { localizedUrl } = localizeRequest(url, nextConfig)
|
|
43
44
|
// While we have already checked the path when mapping to the edge function,
|
|
44
45
|
// Next.js supports extra rules that we need to check here too, because we
|
|
45
46
|
// might be running an edge function for a path we should not. If we find
|
|
46
47
|
// that's the case, short-circuit the execution.
|
|
47
|
-
if (
|
|
48
|
+
if (
|
|
49
|
+
!matchesMiddleware(localizedUrl.pathname, request, searchParamsToUrlQuery(url.searchParams))
|
|
50
|
+
) {
|
|
48
51
|
reqLogger.debug('Aborting middleware due to runtime rules')
|
|
49
52
|
|
|
50
53
|
return
|
|
51
54
|
}
|
|
52
55
|
|
|
56
|
+
const nextRequest = buildNextRequest(request, context, nextConfig)
|
|
53
57
|
try {
|
|
54
58
|
const result = await nextHandler({ request: nextRequest })
|
|
55
59
|
const response = await buildResponse({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/plugin-nextjs",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.7.0-ipx.0",
|
|
4
4
|
"description": "Run Next.js seamlessly on Netlify",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -26,5 +26,8 @@
|
|
|
26
26
|
"bugs": {
|
|
27
27
|
"url": "https://github.com/netlify/next-runtime/issues"
|
|
28
28
|
},
|
|
29
|
-
"homepage": "https://github.com/netlify/next-runtime#readme"
|
|
29
|
+
"homepage": "https://github.com/netlify/next-runtime#readme",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@netlify/ipx": "^1.4.6"
|
|
32
|
+
}
|
|
30
33
|
}
|