@netlify/edge-bundler 9.0.0 → 9.2.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.
@@ -18,7 +18,7 @@ class DenoBridge {
18
18
  this.cacheDirectory = (_a = options.cacheDirectory) !== null && _a !== void 0 ? _a : getPathInHome('deno-cli');
19
19
  this.debug = (_b = options.debug) !== null && _b !== void 0 ? _b : false;
20
20
  this.denoDir = options.denoDir;
21
- this.logger = (_c = options.logger) !== null && _c !== void 0 ? _c : getLogger(undefined, options.debug);
21
+ this.logger = (_c = options.logger) !== null && _c !== void 0 ? _c : getLogger(undefined, undefined, options.debug);
22
22
  this.onAfterDownload = options.onAfterDownload;
23
23
  this.onBeforeDownload = options.onBeforeDownload;
24
24
  this.useGlobal = (_d = options.useGlobal) !== null && _d !== void 0 ? _d : true;
@@ -16,9 +16,10 @@ export interface BundleOptions {
16
16
  onAfterDownload?: OnAfterDownloadHook;
17
17
  onBeforeDownload?: OnBeforeDownloadHook;
18
18
  systemLogger?: LogFunction;
19
+ userLogger?: LogFunction;
19
20
  vendorDirectory?: string;
20
21
  }
21
- export declare const bundle: (sourceDirectories: string[], distDirectory: string, tomlDeclarations?: Declaration[], { basePath: inputBasePath, cacheDirectory, configPath, debug, distImportMapPath, featureFlags: inputFeatureFlags, importMapPaths, internalSrcFolder, onAfterDownload, onBeforeDownload, systemLogger, vendorDirectory, }?: BundleOptions) => Promise<{
22
+ export declare const bundle: (sourceDirectories: string[], distDirectory: string, tomlDeclarations?: Declaration[], { basePath: inputBasePath, cacheDirectory, configPath, debug, distImportMapPath, featureFlags: inputFeatureFlags, importMapPaths, internalSrcFolder, onAfterDownload, onBeforeDownload, userLogger, systemLogger, vendorDirectory, }?: BundleOptions) => Promise<{
22
23
  functions: EdgeFunction[];
23
24
  manifest: import("./manifest.js").Manifest;
24
25
  }>;
@@ -15,8 +15,8 @@ import { getLogger } from './logger.js';
15
15
  import { writeManifest } from './manifest.js';
16
16
  import { vendorNPMSpecifiers } from './npm_dependencies.js';
17
17
  import { ensureLatestTypes } from './types.js';
18
- export const bundle = async (sourceDirectories, distDirectory, tomlDeclarations = [], { basePath: inputBasePath, cacheDirectory, configPath, debug, distImportMapPath, featureFlags: inputFeatureFlags, importMapPaths = [], internalSrcFolder, onAfterDownload, onBeforeDownload, systemLogger, vendorDirectory, } = {}) => {
19
- const logger = getLogger(systemLogger, debug);
18
+ export const bundle = async (sourceDirectories, distDirectory, tomlDeclarations = [], { basePath: inputBasePath, cacheDirectory, configPath, debug, distImportMapPath, featureFlags: inputFeatureFlags, importMapPaths = [], internalSrcFolder, onAfterDownload, onBeforeDownload, userLogger, systemLogger, vendorDirectory, } = {}) => {
19
+ const logger = getLogger(systemLogger, userLogger, debug);
20
20
  const featureFlags = getFlags(inputFeatureFlags);
21
21
  const options = {
22
22
  debug,
@@ -398,6 +398,7 @@ test('Handles imports with the `node:` prefix', async () => {
398
398
  await cleanup();
399
399
  });
400
400
  test('Loads npm modules from bare specifiers', async () => {
401
+ const systemLogger = vi.fn();
401
402
  const { basePath, cleanup, distPath } = await useFixture('imports_npm_module');
402
403
  const sourceDirectory = join(basePath, 'functions');
403
404
  const declarations = [
@@ -412,7 +413,9 @@ test('Loads npm modules from bare specifiers', async () => {
412
413
  featureFlags: { edge_functions_npm_modules: true },
413
414
  importMapPaths: [join(basePath, 'import_map.json')],
414
415
  vendorDirectory: vendorDirectory.path,
416
+ systemLogger,
415
417
  });
418
+ expect(systemLogger.mock.calls.find((call) => call[0] === 'Could not track dependencies in edge function:')).toBeUndefined();
416
419
  const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8');
417
420
  const manifest = JSON.parse(manifestFile);
418
421
  const bundlePath = join(distPath, manifest.bundles[0].asset);
@@ -3,7 +3,7 @@ import { basename, extname, join, parse } from 'path';
3
3
  import { nonNullable } from './utils/non_nullable.js';
4
4
  // the order of the allowed extensions is also the order we remove duplicates
5
5
  // with a lower index meaning a higher precedence over the others
6
- const ALLOWED_EXTENSIONS = ['.js', '.jsx', '.ts', '.tsx'];
6
+ const ALLOWED_EXTENSIONS = ['.js', '.jsx', '.mjs', '.mts', '.ts', '.tsx'];
7
7
  export const removeDuplicatesByExtension = (functions) => {
8
8
  const seen = new Map();
9
9
  return Object.values(functions.reduce((acc, path) => {
@@ -3,6 +3,6 @@ interface Logger {
3
3
  system: LogFunction;
4
4
  user: LogFunction;
5
5
  }
6
- declare const getLogger: (systemLogger?: LogFunction, debug?: boolean) => Logger;
6
+ declare const getLogger: (systemLogger?: LogFunction, userLogger?: LogFunction, debug?: boolean) => Logger;
7
7
  export { getLogger };
8
8
  export type { LogFunction, Logger };
@@ -1,14 +1,15 @@
1
1
  const noopLogger = () => {
2
2
  // no-op
3
3
  };
4
- const getLogger = (systemLogger, debug = false) => {
4
+ const getLogger = (systemLogger, userLogger, debug = false) => {
5
5
  // If there is a system logger configured, we'll use that. If there isn't,
6
6
  // we'll pipe system logs to stdout if `debug` is enabled and swallow them
7
7
  // otherwise.
8
8
  const system = systemLogger !== null && systemLogger !== void 0 ? systemLogger : (debug ? console.log : noopLogger);
9
+ const user = userLogger !== null && userLogger !== void 0 ? userLogger : console.log;
9
10
  return {
10
11
  system,
11
- user: console.log,
12
+ user,
12
13
  };
13
14
  };
14
15
  export { getLogger };
@@ -8,23 +8,30 @@ afterEach(() => {
8
8
  // Restoring global `console.log`.
9
9
  console.log = consoleLog;
10
10
  });
11
- test('Prints user logs to stdout', () => {
11
+ test('Prints user logs to stdout if no user logger is provided', () => {
12
12
  const mockConsoleLog = vi.fn();
13
13
  console.log = mockConsoleLog;
14
- const logger1 = getLogger(noopLogger, true);
15
- const logger2 = getLogger(noopLogger, false);
14
+ const logger1 = getLogger(noopLogger, undefined, true);
15
+ const logger2 = getLogger(noopLogger, undefined, false);
16
16
  logger1.user('Hello with `debug: true`');
17
17
  logger2.user('Hello with `debug: false`');
18
18
  expect(mockConsoleLog).toHaveBeenCalledTimes(2);
19
19
  expect(mockConsoleLog).toHaveBeenNthCalledWith(1, 'Hello with `debug: true`');
20
20
  expect(mockConsoleLog).toHaveBeenNthCalledWith(2, 'Hello with `debug: false`');
21
21
  });
22
+ test('Prints user logs to user logger provided', () => {
23
+ const userLogger = vi.fn();
24
+ const logger = getLogger(noopLogger, userLogger, true);
25
+ logger.user('Hello!');
26
+ expect(userLogger).toHaveBeenCalledTimes(1);
27
+ expect(userLogger).toHaveBeenNthCalledWith(1, 'Hello!');
28
+ });
22
29
  test('Prints system logs to the system logger provided', () => {
23
30
  const mockSystemLog = vi.fn();
24
31
  const mockConsoleLog = vi.fn();
25
32
  console.log = mockSystemLog;
26
- const logger1 = getLogger(mockSystemLog, true);
27
- const logger2 = getLogger(mockSystemLog, false);
33
+ const logger1 = getLogger(mockSystemLog, undefined, true);
34
+ const logger2 = getLogger(mockSystemLog, undefined, false);
28
35
  logger1.system('Hello with `debug: true`');
29
36
  logger2.system('Hello with `debug: false`');
30
37
  expect(mockConsoleLog).toHaveBeenCalledTimes(0);
@@ -35,8 +42,8 @@ test('Prints system logs to the system logger provided', () => {
35
42
  test('Prints system logs to stdout if there is no system logger provided and `debug` is enabled', () => {
36
43
  const mockConsoleLog = vi.fn();
37
44
  console.log = mockConsoleLog;
38
- const logger1 = getLogger(undefined, true);
39
- const logger2 = getLogger(undefined, false);
45
+ const logger1 = getLogger(undefined, undefined, true);
46
+ const logger2 = getLogger(undefined, undefined, false);
40
47
  logger1.system('Hello with `debug: true`');
41
48
  logger2.system('Hello with `debug: false`');
42
49
  expect(mockConsoleLog).toHaveBeenCalledTimes(1);
@@ -15,7 +15,7 @@ export declare const vendorNPMSpecifiers: ({ basePath, directory, functions, imp
15
15
  cleanup: () => Promise<void>;
16
16
  directory: string;
17
17
  importMap: {
18
- baseURL: import("node:url").URL;
18
+ baseURL: import("url").URL;
19
19
  imports: Record<string, string>;
20
20
  };
21
21
  } | undefined>;
@@ -49,7 +49,7 @@ export const getDependencyTrackerPlugin = (specifiers, importMap, baseURL) => ({
49
49
  if (specifier.startsWith(npmPrefix)) {
50
50
  return { external: true };
51
51
  }
52
- const isLocalImport = specifier.startsWith(path.sep) || specifier.startsWith('.');
52
+ const isLocalImport = specifier.startsWith(path.sep) || specifier.startsWith('.') || path.isAbsolute(specifier);
53
53
  // If this is a local import, return so that esbuild visits that path.
54
54
  if (isLocalImport) {
55
55
  return result;
@@ -105,6 +105,7 @@ export const vendorNPMSpecifiers = async ({ basePath, directory, functions, impo
105
105
  platform: 'node',
106
106
  plugins: [getDependencyTrackerPlugin(specifiers, importMap.getContentsWithURLObjects(), pathToFileURL(basePath))],
107
107
  write: false,
108
+ format: 'esm',
108
109
  });
109
110
  }
110
111
  catch (error) {
@@ -115,7 +116,6 @@ export const vendorNPMSpecifiers = async ({ basePath, directory, functions, impo
115
116
  if (specifiers.size === 0) {
116
117
  return;
117
118
  }
118
- logger.user('You are using npm modules in Edge Functions, which is an experimental feature. Learn more at https://ntl.fyi/edge-functions-npm.');
119
119
  // To bundle an entire module and all its dependencies, create a barrel file
120
120
  // where we re-export everything from that specifier. We do this for every
121
121
  // specifier, and each of these files will become entry points to esbuild.
@@ -6,6 +6,7 @@
6
6
  import { OnAfterDownloadHook, OnBeforeDownloadHook } from '../bridge.js';
7
7
  import { FunctionConfig } from '../config.js';
8
8
  import type { EdgeFunction } from '../edge_function.js';
9
+ import type { FeatureFlags } from '../feature_flags.js';
9
10
  import { LogFunction } from '../logger.js';
10
11
  export type FormatFunction = (name: string) => string;
11
12
  interface StartServerOptions {
@@ -22,6 +23,7 @@ interface ServeOptions {
22
23
  certificatePath?: string;
23
24
  debug?: boolean;
24
25
  distImportMapPath?: string;
26
+ featureFlags?: FeatureFlags;
25
27
  inspectSettings?: InspectSettings;
26
28
  importMapPaths?: string[];
27
29
  onAfterDownload?: OnAfterDownloadHook;
@@ -30,9 +32,11 @@ interface ServeOptions {
30
32
  formatImportError?: FormatFunction;
31
33
  port: number;
32
34
  servePath: string;
35
+ userLogger?: LogFunction;
33
36
  systemLogger?: LogFunction;
34
37
  }
35
- export declare const serve: ({ basePath, bootstrapURL, certificatePath, debug, distImportMapPath, inspectSettings, formatExportTypeError, formatImportError, importMapPaths, onAfterDownload, onBeforeDownload, port, servePath, systemLogger, }: ServeOptions) => Promise<(functions: EdgeFunction[], env?: NodeJS.ProcessEnv, options?: StartServerOptions) => Promise<{
38
+ export declare const serve: ({ basePath, bootstrapURL, certificatePath, debug, distImportMapPath, inspectSettings, featureFlags, formatExportTypeError, formatImportError, importMapPaths, onAfterDownload, onBeforeDownload, port, servePath, userLogger, systemLogger, }: ServeOptions) => Promise<(functions: EdgeFunction[], env?: NodeJS.ProcessEnv, options?: StartServerOptions) => Promise<{
39
+ features: Record<string, boolean>;
36
40
  functionsConfig: FunctionConfig[];
37
41
  graph: any;
38
42
  success: boolean;
@@ -6,7 +6,7 @@ import { getLogger } from '../logger.js';
6
6
  import { vendorNPMSpecifiers } from '../npm_dependencies.js';
7
7
  import { ensureLatestTypes } from '../types.js';
8
8
  import { killProcess, waitForServer } from './util.js';
9
- const prepareServer = ({ basePath, bootstrapURL, deno, distDirectory, distImportMapPath, flags: denoFlags, formatExportTypeError, formatImportError, importMap: baseImportMap, logger, port, }) => {
9
+ const prepareServer = ({ basePath, bootstrapURL, deno, distDirectory, distImportMapPath, featureFlags, flags: denoFlags, formatExportTypeError, formatImportError, importMap: baseImportMap, logger, port, }) => {
10
10
  const processRef = {};
11
11
  const startServer = async (functions, env = {}, options = {}) => {
12
12
  if ((processRef === null || processRef === void 0 ? void 0 : processRef.ps) !== undefined) {
@@ -21,16 +21,20 @@ const prepareServer = ({ basePath, bootstrapURL, deno, distDirectory, distImport
21
21
  formatExportTypeError,
22
22
  formatImportError,
23
23
  });
24
+ const features = {};
24
25
  const importMap = baseImportMap.clone();
25
- const vendor = await vendorNPMSpecifiers({
26
- basePath,
27
- directory: distDirectory,
28
- functions: functions.map(({ path }) => path),
29
- importMap,
30
- logger,
31
- });
32
- if (vendor) {
33
- importMap.add(vendor.importMap);
26
+ if (featureFlags === null || featureFlags === void 0 ? void 0 : featureFlags.edge_functions_npm_modules) {
27
+ const vendor = await vendorNPMSpecifiers({
28
+ basePath,
29
+ directory: distDirectory,
30
+ functions: functions.map(({ path }) => path),
31
+ importMap,
32
+ logger,
33
+ });
34
+ if (vendor) {
35
+ features.npmModules = true;
36
+ importMap.add(vendor.importMap);
37
+ }
34
38
  }
35
39
  try {
36
40
  // This command will print a JSON object with all the modules found in
@@ -62,6 +66,7 @@ const prepareServer = ({ basePath, bootstrapURL, deno, distDirectory, distImport
62
66
  }
63
67
  const success = await waitForServer(port, processRef.ps);
64
68
  return {
69
+ features,
65
70
  functionsConfig,
66
71
  graph,
67
72
  success,
@@ -69,8 +74,8 @@ const prepareServer = ({ basePath, bootstrapURL, deno, distDirectory, distImport
69
74
  };
70
75
  return startServer;
71
76
  };
72
- export const serve = async ({ basePath, bootstrapURL, certificatePath, debug, distImportMapPath, inspectSettings, formatExportTypeError, formatImportError, importMapPaths = [], onAfterDownload, onBeforeDownload, port, servePath, systemLogger, }) => {
73
- const logger = getLogger(systemLogger, debug);
77
+ export const serve = async ({ basePath, bootstrapURL, certificatePath, debug, distImportMapPath, inspectSettings, featureFlags, formatExportTypeError, formatImportError, importMapPaths = [], onAfterDownload, onBeforeDownload, port, servePath, userLogger, systemLogger, }) => {
78
+ const logger = getLogger(systemLogger, userLogger, debug);
74
79
  const deno = new DenoBridge({
75
80
  debug,
76
81
  logger,
@@ -107,6 +112,7 @@ export const serve = async ({ basePath, bootstrapURL, certificatePath, debug, di
107
112
  deno,
108
113
  distDirectory: servePath,
109
114
  distImportMapPath,
115
+ featureFlags,
110
116
  flags,
111
117
  formatExportTypeError,
112
118
  formatImportError,
@@ -39,9 +39,10 @@ test('Starts a server and serves requests for edge functions', async () => {
39
39
  const options = {
40
40
  getFunctionsConfig: true,
41
41
  };
42
- const { functionsConfig, graph, success } = await server(functions, {
42
+ const { features, functionsConfig, graph, success } = await server(functions, {
43
43
  very_secret_secret: 'i love netlify',
44
44
  }, options);
45
+ expect(features).toEqual({});
45
46
  expect(success).toBe(true);
46
47
  expect(functionsConfig).toEqual([{ path: '/my-function' }, {}, { path: '/global-netlify' }]);
47
48
  for (const key in functions) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/edge-bundler",
3
- "version": "9.0.0",
3
+ "version": "9.2.0",
4
4
  "description": "Intelligently prepare Netlify Edge Functions for deployment",
5
5
  "type": "module",
6
6
  "main": "./dist/node/index.js",
@@ -79,7 +79,7 @@
79
79
  "better-ajv-errors": "^1.2.0",
80
80
  "common-path-prefix": "^3.0.0",
81
81
  "env-paths": "^3.0.0",
82
- "esbuild": "0.19.2",
82
+ "esbuild": "0.19.4",
83
83
  "execa": "^6.0.0",
84
84
  "find-up": "^6.3.0",
85
85
  "get-port": "^6.1.2",