@sveltejs/adapter-netlify 6.0.0 → 6.0.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.
Files changed (2) hide show
  1. package/index.js +97 -40
  2. package/package.json +3 -3
package/index.js CHANGED
@@ -191,7 +191,7 @@ async function generate_edge_functions({ builder }) {
191
191
  outfile: '.netlify/edge-functions/render.js',
192
192
  ...esbuild_config
193
193
  }),
194
- builder.hasServerInstrumentationFile?.() &&
194
+ builder.hasServerInstrumentationFile() &&
195
195
  esbuild.build({
196
196
  entryPoints: [`${builder.getServerDirectory()}/instrumentation.server.js`],
197
197
  outfile: '.netlify/edge/instrumentation.server.js',
@@ -199,8 +199,8 @@ async function generate_edge_functions({ builder }) {
199
199
  })
200
200
  ]);
201
201
 
202
- if (builder.hasServerInstrumentationFile?.()) {
203
- builder.instrument?.({
202
+ if (builder.hasServerInstrumentationFile()) {
203
+ builder.instrument({
204
204
  entrypoint: '.netlify/edge-functions/render.js',
205
205
  instrumentation: '.netlify/edge/instrumentation.server.js',
206
206
  start: '.netlify/edge/start.js'
@@ -237,20 +237,23 @@ function generate_lambda_functions({ builder, publish, split }) {
237
237
 
238
238
  const routes = [route];
239
239
 
240
+ /** @type {string[]} */
240
241
  const parts = [];
241
- // Netlify's syntax uses '*' and ':param' as "splats" and "placeholders"
242
- // https://docs.netlify.com/routing/redirects/redirect-options/#splats
242
+
243
+ // The parts should conform to URLPattern syntax
244
+ // https://docs.netlify.com/build/functions/get-started/?fn-language=ts&data-tab=TypeScript#route-requests
243
245
  for (const segment of route.segments) {
244
246
  if (segment.rest) {
245
247
  parts.push('*');
246
- break; // Netlify redirects don't allow anything after a *
247
248
  } else if (segment.dynamic) {
248
- parts.push(`:${parts.length}`);
249
+ // URLPattern requires params to start with letters
250
+ parts.push(`:param${parts.length}`);
249
251
  } else {
250
252
  parts.push(segment.content);
251
253
  }
252
254
  }
253
255
 
256
+ // Netlify handles trailing slashes for us, so we don't need to include them in the pattern
254
257
  const pattern = `/${parts.join('/')}`;
255
258
  const name =
256
259
  FUNCTION_PREFIX + (parts.join('-').replace(/[:.]/g, '_').replace('*', '__rest') || 'index');
@@ -269,43 +272,22 @@ function generate_lambda_functions({ builder, publish, split }) {
269
272
  }
270
273
  }
271
274
 
272
- const manifest = builder.generateManifest({
273
- relativePath: '../server',
274
- routes
275
+ generate_serverless_function({
276
+ builder,
277
+ routes,
278
+ patterns: [pattern, `${pattern === '/' ? '' : pattern}/__data.json`],
279
+ name
275
280
  });
276
-
277
- const fn = `import { init } from '../serverless.js';\n\nexport default init(${manifest});\n\nexport const config = {\n\tpath: "${pattern}",\n\texcludedPath: "/.netlify/*",\n\tpreferStatic: true\n};\n`;
278
-
279
- writeFileSync(`.netlify/functions-internal/${name}.mjs`, fn);
280
- if (builder.hasServerInstrumentationFile?.()) {
281
- builder.instrument?.({
282
- entrypoint: `.netlify/functions-internal/${name}.mjs`,
283
- instrumentation: '.netlify/server/instrumentation.server.js',
284
- start: `.netlify/functions-start/${name}.start.mjs`,
285
- module: {
286
- exports: ['default']
287
- }
288
- });
289
- }
290
281
  }
282
+
283
+ // TODO: add a catch-all to display a 404 page if no other functions are invoked, similar to the Vercel adapter
291
284
  } else {
292
- const manifest = builder.generateManifest({
293
- relativePath: '../server'
285
+ generate_serverless_function({
286
+ builder,
287
+ routes: undefined,
288
+ patterns: ['/*'],
289
+ name: `${FUNCTION_PREFIX}render`
294
290
  });
295
-
296
- const fn = `import { init } from '../serverless.js';\n\nexport default init(${manifest});\n\nexport const config = {\n\tpath: "/*",\n\texcludedPath: "/.netlify/*",\n\tpreferStatic: true\n};\n`;
297
-
298
- writeFileSync(`.netlify/functions-internal/${FUNCTION_PREFIX}render.mjs`, fn);
299
- if (builder.hasServerInstrumentationFile?.()) {
300
- builder.instrument?.({
301
- entrypoint: `.netlify/functions-internal/${FUNCTION_PREFIX}render.mjs`,
302
- instrumentation: '.netlify/server/instrumentation.server.js',
303
- start: `.netlify/functions-start/${FUNCTION_PREFIX}render.start.mjs`,
304
- module: {
305
- exports: ['default']
306
- }
307
- });
308
- }
309
291
  }
310
292
 
311
293
  // Copy user's custom _redirects file if it exists
@@ -386,3 +368,78 @@ function matches(a, b) {
386
368
  return b.length === 1 && b[0].rest;
387
369
  }
388
370
  }
371
+
372
+ /**
373
+ *
374
+ * @param {{
375
+ * builder: import('@sveltejs/kit').Builder,
376
+ * routes: import('@sveltejs/kit').RouteDefinition[] | undefined,
377
+ * patterns: string[],
378
+ * name: string
379
+ * }} opts
380
+ */
381
+ function generate_serverless_function({ builder, routes, patterns, name }) {
382
+ const manifest = builder.generateManifest({
383
+ relativePath: '../server',
384
+ routes
385
+ });
386
+
387
+ const fn = generate_serverless_function_module(manifest);
388
+ const config = generate_config_export(patterns);
389
+
390
+ if (builder.hasServerInstrumentationFile()) {
391
+ writeFileSync(`.netlify/functions-internal/${name}.mjs`, fn);
392
+ builder.instrument({
393
+ entrypoint: `.netlify/functions-internal/${name}.mjs`,
394
+ instrumentation: '.netlify/server/instrumentation.server.js',
395
+ start: `.netlify/functions-start/${name}.start.mjs`,
396
+ module: {
397
+ generateText: generate_traced_module(config)
398
+ }
399
+ });
400
+ } else {
401
+ writeFileSync(`.netlify/functions-internal/${name}.mjs`, `${fn}\n${config}`);
402
+ }
403
+ }
404
+
405
+ /**
406
+ * @param {string} manifest
407
+ * @returns {string}
408
+ */
409
+ function generate_serverless_function_module(manifest) {
410
+ return `\
411
+ import { init } from '../serverless.js';
412
+
413
+ export default init(${manifest});
414
+ `;
415
+ }
416
+
417
+ /**
418
+ * @param {string[]} patterns
419
+ * @returns {string}
420
+ */
421
+ function generate_config_export(patterns) {
422
+ // TODO: add a human friendly name for the function https://docs.netlify.com/build/frameworks/frameworks-api/#configuration-options-2
423
+ return `\
424
+ export const config = {
425
+ path: [${patterns.map((s) => JSON.stringify(s)).join(', ')}],
426
+ excludedPath: "/.netlify/*",
427
+ preferStatic: true
428
+ };
429
+ `;
430
+ }
431
+
432
+ /**
433
+ * @param {string} config
434
+ * @returns {(opts: { instrumentation: string; start: string }) => string}
435
+ */
436
+ function generate_traced_module(config) {
437
+ return ({ instrumentation, start }) => {
438
+ return `\
439
+ import './${instrumentation}';
440
+ const { default: _0 } = await import('./${start}');
441
+ export { _0 as default };
442
+
443
+ ${config}`;
444
+ };
445
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/adapter-netlify",
3
- "version": "6.0.0",
3
+ "version": "6.0.3",
4
4
  "description": "A SvelteKit adapter that creates a Netlify app",
5
5
  "keywords": [
6
6
  "adapter",
@@ -37,7 +37,7 @@
37
37
  "esbuild": "^0.25.4"
38
38
  },
39
39
  "devDependencies": {
40
- "@netlify/dev": "^4.8.8",
40
+ "@netlify/dev": "^4.11.2",
41
41
  "@netlify/edge-functions": "^3.0.0",
42
42
  "@netlify/functions": "^5.0.0",
43
43
  "@netlify/node-cookies": "^0.1.0",
@@ -50,7 +50,7 @@
50
50
  "rollup": "^4.14.2",
51
51
  "typescript": "^5.3.3",
52
52
  "vitest": "^4.0.0",
53
- "@sveltejs/kit": "^2.51.0"
53
+ "@sveltejs/kit": "^2.53.0"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "@sveltejs/kit": "^2.31.0"