@netlify/edge-bundler 12.2.2 → 12.3.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.
@@ -1,7 +1,7 @@
1
1
  import { type WriteStream } from 'fs';
2
2
  import { ExecaChildProcess } from 'execa';
3
3
  import { Logger } from './logger.js';
4
- declare const DENO_VERSION_RANGE = "1.37.0 - 1.44.4";
4
+ declare const DENO_VERSION_RANGE = "1.39.0 - 1.46.3";
5
5
  type OnBeforeDownloadHook = () => void | Promise<void>;
6
6
  type OnAfterDownloadHook = (error?: Error) => void | Promise<void>;
7
7
  interface DenoOptions {
@@ -9,11 +9,10 @@ import { getPathInHome } from './home_path.js';
9
9
  import { getLogger } from './logger.js';
10
10
  import { getBinaryExtension } from './platform.js';
11
11
  const DENO_VERSION_FILE = 'version.txt';
12
- // When updating DENO_VERSION_RANGE, ensure that the deno version installed in the
13
- // build-image/buildbot does satisfy this range!
14
- // We're pinning the range because of an issue with v1.45.0 of the Deno CLI:
15
- // https://linear.app/netlify/issue/FRP-775/deno-cli-v1450-causing-issues
16
- const DENO_VERSION_RANGE = '1.37.0 - 1.44.4';
12
+ // When updating DENO_VERSION_RANGE, ensure that the deno version
13
+ // on the netlify/buildbot build image satisfies this range!
14
+ // https://github.com/netlify/buildbot/blob/f9c03c9dcb091d6570e9d0778381560d469e78ad/build-image/noble/Dockerfile#L410
15
+ const DENO_VERSION_RANGE = '1.39.0 - 1.46.3';
17
16
  class DenoBridge {
18
17
  constructor(options) {
19
18
  var _a, _b, _c, _d, _e;
@@ -355,6 +355,32 @@ test('Handles imports with the `node:` prefix', async () => {
355
355
  expect(func1).toBe('ok');
356
356
  await cleanup();
357
357
  });
358
+ test('Handles Node builtin imports without the `node:` prefix', async () => {
359
+ const { basePath, cleanup, distPath } = await useFixture('imports_node_builtin');
360
+ const userDirectory = join(basePath, 'netlify', 'edge-functions');
361
+ const result = await bundle([userDirectory], distPath, [], {
362
+ basePath,
363
+ importMapPaths: [join(userDirectory, 'import_map.json')],
364
+ });
365
+ const generatedFiles = await readdir(distPath);
366
+ expect(result.functions.length).toBe(1);
367
+ expect(generatedFiles.length).toBe(2);
368
+ const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8');
369
+ const manifest = JSON.parse(manifestFile);
370
+ expect(() => validateManifest(manifest)).not.toThrowError();
371
+ const { bundles, import_map: importMapURL, routes } = manifest;
372
+ expect(bundles.length).toBe(1);
373
+ expect(bundles[0].format).toBe('eszip2');
374
+ expect(generatedFiles.includes(bundles[0].asset)).toBe(true);
375
+ expect(importMapURL).toBe(importMapSpecifier);
376
+ expect(routes.length).toBe(1);
377
+ expect(routes[0].function).toBe('func1');
378
+ expect(routes[0].pattern).toBe('^/func1/?$');
379
+ const bundlePath = join(distPath, bundles[0].asset);
380
+ const { func1 } = await runESZIP(bundlePath);
381
+ expect(func1).toBe('ok');
382
+ await cleanup();
383
+ });
358
384
  test('Loads npm modules from bare specifiers', async () => {
359
385
  const systemLogger = vi.fn();
360
386
  const { basePath, cleanup, distPath } = await useFixture('imports_npm_module');
@@ -18,5 +18,5 @@ export declare const vendorNPMSpecifiers: ({ basePath, directory, functions, imp
18
18
  };
19
19
  npmSpecifiersWithExtraneousFiles: string[];
20
20
  outputFiles: string[];
21
- } | undefined>;
21
+ }>;
22
22
  export {};
@@ -185,10 +185,6 @@ export const vendorNPMSpecifiers = async ({ basePath, directory, functions, impo
185
185
  environment,
186
186
  rootPath,
187
187
  });
188
- // If we found no specifiers, there's nothing left to do here.
189
- if (Object.keys(npmSpecifiers).length === 0) {
190
- return;
191
- }
192
188
  // To bundle an entire module and all its dependencies, create a entrypoint file
193
189
  // where we re-export everything from that specifier. We do this for every
194
190
  // specifier, and each of these files will become entry points to esbuild.
@@ -198,39 +194,43 @@ export const vendorNPMSpecifiers = async ({ basePath, directory, functions, impo
198
194
  await fs.writeFile(filePath, code);
199
195
  return { filePath, specifier, types };
200
196
  }));
201
- const entryPoints = ops.map(({ filePath }) => filePath);
202
- // Bundle each of the entrypoints we created. We'll end up with a compiled
203
- // version of each, plus any chunks of shared code
204
- // between them (such that a common module isn't bundled twice).
205
- const { outputFiles } = await build({
206
- allowOverwrite: true,
207
- banner,
208
- bundle: true,
209
- entryPoints,
210
- format: 'esm',
211
- mainFields: ['module', 'browser', 'main'],
212
- logLevel: 'error',
213
- nodePaths,
214
- outdir: temporaryDirectory.path,
215
- platform: 'node',
216
- splitting: true,
217
- target: 'es2020',
218
- write: false,
219
- define: environment === 'production'
220
- ? {
221
- 'process.env.NODE_ENV': '"production"',
197
+ const outputFiles = [];
198
+ if (ops.length !== 0) {
199
+ const entryPoints = ops.map(({ filePath }) => filePath);
200
+ // Bundle each of the entrypoints we created. We'll end up with a compiled
201
+ // version of each, plus any chunks of shared code
202
+ // between them (such that a common module isn't bundled twice).
203
+ const { outputFiles: outputFilesFromEsBuild } = await build({
204
+ allowOverwrite: true,
205
+ banner,
206
+ bundle: true,
207
+ entryPoints,
208
+ format: 'esm',
209
+ mainFields: ['module', 'browser', 'main'],
210
+ logLevel: 'error',
211
+ nodePaths,
212
+ outdir: temporaryDirectory.path,
213
+ platform: 'node',
214
+ splitting: true,
215
+ target: 'es2020',
216
+ write: false,
217
+ define: environment === 'production'
218
+ ? {
219
+ 'process.env.NODE_ENV': '"production"',
220
+ }
221
+ : undefined,
222
+ });
223
+ outputFiles.push(...outputFilesFromEsBuild.map((file) => file.path));
224
+ await Promise.all(outputFilesFromEsBuild.map(async (file) => {
225
+ var _a;
226
+ const types = (_a = ops.find((op) => path.basename(file.path) === path.basename(op.filePath))) === null || _a === void 0 ? void 0 : _a.types;
227
+ let content = file.text;
228
+ if (types) {
229
+ content = `/// <reference types="${path.relative(path.dirname(file.path), types)}" />\n${content}`;
222
230
  }
223
- : undefined,
224
- });
225
- await Promise.all(outputFiles.map(async (file) => {
226
- var _a;
227
- const types = (_a = ops.find((op) => path.basename(file.path) === path.basename(op.filePath))) === null || _a === void 0 ? void 0 : _a.types;
228
- let content = file.text;
229
- if (types) {
230
- content = `/// <reference types="${path.relative(path.dirname(file.path), types)}" />\n${content}`;
231
- }
232
- await fs.writeFile(file.path, content);
233
- }));
231
+ await fs.writeFile(file.path, content);
232
+ }));
233
+ }
234
234
  // Add all Node.js built-ins to the import map, so any unprefixed specifiers
235
235
  // (e.g. `process`) resolve to the prefixed versions (e.g. `node:prefix`),
236
236
  // which Deno can process.
@@ -270,6 +270,6 @@ export const vendorNPMSpecifiers = async ({ basePath, directory, functions, impo
270
270
  directory: temporaryDirectory.path,
271
271
  importMap: newImportMap,
272
272
  npmSpecifiersWithExtraneousFiles,
273
- outputFiles: outputFiles.map((file) => file.path),
273
+ outputFiles,
274
274
  };
275
275
  };
@@ -1,5 +1,7 @@
1
+ import { platform } from 'os';
1
2
  import fetch from 'node-fetch';
2
3
  import waitFor from 'p-wait-for';
4
+ import { satisfies } from 'semver';
3
5
  // 1 second
4
6
  const SERVER_KILL_TIMEOUT = 1e3;
5
7
  // 1 second
@@ -29,9 +31,19 @@ const killProcess = (ps) => {
29
31
  return new Promise((resolve, reject) => {
30
32
  ps.on('close', resolve);
31
33
  ps.on('error', reject);
32
- ps.kill('SIGTERM', {
33
- forceKillAfterTimeout: SERVER_KILL_TIMEOUT,
34
- });
34
+ // On Windows with Node 21+, there's a bug where attempting to kill a child process
35
+ // results in an EPERM error. Ignore the error in that case.
36
+ // See: https://github.com/nodejs/node/issues/51766
37
+ // We also disable execa's `forceKillAfterTimeout` in this case
38
+ // which can cause unhandled rejection.
39
+ try {
40
+ ps.kill('SIGTERM', {
41
+ forceKillAfterTimeout: platform() === 'win32' && satisfies(process.version, '>=21') ? false : SERVER_KILL_TIMEOUT,
42
+ });
43
+ }
44
+ catch {
45
+ // no-op
46
+ }
35
47
  });
36
48
  };
37
49
  const waitForServer = async (port, ps) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/edge-bundler",
3
- "version": "12.2.2",
3
+ "version": "12.3.0",
4
4
  "description": "Intelligently prepare Netlify Edge Functions for deployment",
5
5
  "type": "module",
6
6
  "main": "./dist/node/index.js",
@@ -84,5 +84,5 @@
84
84
  "urlpattern-polyfill": "8.0.2",
85
85
  "uuid": "^9.0.0"
86
86
  },
87
- "gitHead": "11ec8d0f0bd573150a134cd9af077f5b56afdbb6"
87
+ "gitHead": "0b25c72f762393fa13a50e673a0fd48eb37f5120"
88
88
  }