From 678a29d9c8d407c26eaa24d6ccf4ab0447bdd637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Bou=C3=A7as?= Date: Tue, 29 Jul 2025 14:59:17 +0100 Subject: [PATCH 1/4] chore: add test --- packages/edge-bundler/node/bundler.test.ts | 30 ++++++++++++++++++- .../with_import_assert/functions/dict.json | 3 ++ .../with_import_assert/functions/func1.ts | 4 +++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 packages/edge-bundler/test/fixtures/with_import_assert/functions/dict.json create mode 100644 packages/edge-bundler/test/fixtures/with_import_assert/functions/func1.ts diff --git a/packages/edge-bundler/node/bundler.test.ts b/packages/edge-bundler/node/bundler.test.ts index c73601c1c1..a0c52b78ad 100644 --- a/packages/edge-bundler/node/bundler.test.ts +++ b/packages/edge-bundler/node/bundler.test.ts @@ -598,7 +598,7 @@ test('Loads npm modules in a monorepo setup', async () => { await rm(vendorDirectory.path, { force: true, recursive: true }) }) -test('Loads JSON modules', async () => { +test('Loads JSON modules with `with` attribute', async () => { const { basePath, cleanup, distPath } = await useFixture('imports_json') const sourceDirectory = join(basePath, 'functions') const declarations: Declaration[] = [ @@ -625,6 +625,34 @@ test('Loads JSON modules', async () => { await rm(vendorDirectory.path, { force: true, recursive: true }) }) +testnly('Loads JSON modules with `assert` attribute', async () => { + const { basePath, cleanup, distPath } = await useFixture('with_import_assert') + const sourceDirectory = join(basePath, 'functions') + const declarations: Declaration[] = [ + { + function: 'func1', + path: '/func1', + }, + ] + const vendorDirectory = await tmp.dir() + + await bundle([sourceDirectory], distPath, declarations, { + basePath, + debug: true, + vendorDirectory: vendorDirectory.path, + }) + + const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8') + const manifest = JSON.parse(manifestFile) + const bundlePath = join(distPath, manifest.bundles[0].asset) + const { func1 } = await runESZIP(bundlePath, vendorDirectory.path) + + expect(func1).toBe(`{"foo":"bar"}`) + + await cleanup() + await rm(vendorDirectory.path, { force: true, recursive: true }) +}) + test('Supports TSX and process.env', async () => { const { basePath, cleanup, distPath } = await useFixture('tsx') const sourceDirectory = join(basePath, 'functions') diff --git a/packages/edge-bundler/test/fixtures/with_import_assert/functions/dict.json b/packages/edge-bundler/test/fixtures/with_import_assert/functions/dict.json new file mode 100644 index 0000000000..b42f309e7a --- /dev/null +++ b/packages/edge-bundler/test/fixtures/with_import_assert/functions/dict.json @@ -0,0 +1,3 @@ +{ + "foo": "bar" +} \ No newline at end of file diff --git a/packages/edge-bundler/test/fixtures/with_import_assert/functions/func1.ts b/packages/edge-bundler/test/fixtures/with_import_assert/functions/func1.ts new file mode 100644 index 0000000000..1471989aaf --- /dev/null +++ b/packages/edge-bundler/test/fixtures/with_import_assert/functions/func1.ts @@ -0,0 +1,4 @@ +import dict from './dict.json' assert { type: "json" } + + +export default async () => Response.json(dict) From d1dc564617e86d67e29c46fc6862072186ecfd40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Bou=C3=A7as?= Date: Wed, 30 Jul 2025 12:32:21 +0100 Subject: [PATCH 2/4] feat: emit system log for import assertions --- packages/edge-bundler/node/bundler.test.ts | 16 ++++++++++------ packages/edge-bundler/node/config.ts | 9 +++++++-- packages/edge-bundler/test/util.ts | 11 +++++++---- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/packages/edge-bundler/node/bundler.test.ts b/packages/edge-bundler/node/bundler.test.ts index 05cb87db74..3fec72306f 100644 --- a/packages/edge-bundler/node/bundler.test.ts +++ b/packages/edge-bundler/node/bundler.test.ts @@ -1,5 +1,4 @@ import { Buffer } from 'buffer' -import { execSync } from 'node:child_process' import { access, readdir, readFile, rm, writeFile } from 'fs/promises' import { join, resolve } from 'path' import process from 'process' @@ -10,7 +9,7 @@ import tmp from 'tmp-promise' import { test, expect, vi, describe } from 'vitest' import { importMapSpecifier } from '../shared/consts.js' -import { runESZIP, runTarball, useFixture } from '../test/util.js' +import { denoVersion, runESZIP, runTarball, useFixture } from '../test/util.js' import { BundleError } from './bundle_error.js' import { bundle, BundleOptions } from './bundler.js' @@ -626,7 +625,10 @@ test('Loads JSON modules with `with` attribute', async () => { await rm(vendorDirectory.path, { force: true, recursive: true }) }) -testnly('Loads JSON modules with `assert` attribute', async () => { +// We can't run this on versions above 2.0.0 because the bundling will fail +// entirely, and what we're asserting here is that we emit a system log when +// import assertions are detected on successful builds. +test.skipIf(lt(denoVersion, '2.0.0'))('Emits a system log when import assertions are used', async () => { const { basePath, cleanup, distPath } = await useFixture('with_import_assert') const sourceDirectory = join(basePath, 'functions') const declarations: Declaration[] = [ @@ -636,10 +638,11 @@ testnly('Loads JSON modules with `assert` attribute', async () => { }, ] const vendorDirectory = await tmp.dir() + const systemLogger = vi.fn() await bundle([sourceDirectory], distPath, declarations, { basePath, - debug: true, + systemLogger, vendorDirectory: vendorDirectory.path, }) @@ -649,6 +652,9 @@ testnly('Loads JSON modules with `assert` attribute', async () => { const { func1 } = await runESZIP(bundlePath, vendorDirectory.path) expect(func1).toBe(`{"foo":"bar"}`) + expect(systemLogger).toHaveBeenCalledWith( + `Edge function uses import assertions: ${join(sourceDirectory, 'func1.ts')}`, + ) await cleanup() await rm(vendorDirectory.path, { force: true, recursive: true }) @@ -722,8 +728,6 @@ test('Loads edge functions from the Frameworks API', async () => { await cleanup() }) -const denoVersion = execSync('deno eval --no-lock "console.log(Deno.version.deno)"').toString() - describe.skipIf(lt(denoVersion, '2.4.2'))( 'Produces a tarball bundle', () => { diff --git a/packages/edge-bundler/node/config.ts b/packages/edge-bundler/node/config.ts index cc64c1df12..df76405915 100644 --- a/packages/edge-bundler/node/config.ts +++ b/packages/edge-bundler/node/config.ts @@ -96,11 +96,12 @@ export const getFunctionConfig = async ({ // with the extractor. const collector = await tmp.file() + // Retrieving the version of Deno. + const version = new SemVer((await deno.getBinaryVersion((await deno.getBinaryPath({ silent: true })).path)) || '') + // The extractor will use its exit code to signal different error scenarios, // based on the list of exit codes we send as an argument. We then capture // the exit code to know exactly what happened and guide people accordingly. - const version = new SemVer((await deno.getBinaryVersion((await deno.getBinaryPath({ silent: true })).path)) || '') - const { exitCode, stderr, stdout } = await deno.run( [ 'run', @@ -121,6 +122,10 @@ export const getFunctionConfig = async ({ { rejectOnExitCode: false }, ) + if (stderr.includes('Import assertions are deprecated')) { + log.system(`Edge function uses import assertions: ${func.path}`) + } + if (exitCode !== ConfigExitCode.Success) { handleConfigError(func, exitCode, stderr, log) diff --git a/packages/edge-bundler/test/util.ts b/packages/edge-bundler/test/util.ts index 0b54dc55d1..e0e56c643d 100644 --- a/packages/edge-bundler/test/util.ts +++ b/packages/edge-bundler/test/util.ts @@ -1,7 +1,8 @@ -import { promises as fs } from 'fs' -import { join, resolve } from 'path' -import { stderr, stdout } from 'process' -import { fileURLToPath, pathToFileURL } from 'url' +import { execSync } from 'node:child_process' +import { promises as fs } from 'node:fs' +import { join, resolve } from 'node:path' +import { stderr, stdout } from 'node:process' +import { fileURLToPath, pathToFileURL } from 'node:url' import cpy from 'cpy' import { execa } from 'execa' @@ -169,3 +170,5 @@ export const runTarball = async (tarballPath: string) => { return JSON.parse(result.stdout) } + +export const denoVersion = execSync('deno eval --no-lock "console.log(Deno.version.deno)"').toString() From 0a7500d216ff728abf8f6840e58f15e7ffa84986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Bou=C3=A7as?= Date: Wed, 30 Jul 2025 12:35:22 +0100 Subject: [PATCH 3/4] chore: doh --- packages/edge-bundler/node/bundler.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/edge-bundler/node/bundler.test.ts b/packages/edge-bundler/node/bundler.test.ts index 3fec72306f..b33afda11a 100644 --- a/packages/edge-bundler/node/bundler.test.ts +++ b/packages/edge-bundler/node/bundler.test.ts @@ -4,7 +4,7 @@ import { join, resolve } from 'path' import process from 'process' import { pathToFileURL } from 'url' -import { lt } from 'semver' +import { gte, lt } from 'semver' import tmp from 'tmp-promise' import { test, expect, vi, describe } from 'vitest' @@ -628,7 +628,7 @@ test('Loads JSON modules with `with` attribute', async () => { // We can't run this on versions above 2.0.0 because the bundling will fail // entirely, and what we're asserting here is that we emit a system log when // import assertions are detected on successful builds. -test.skipIf(lt(denoVersion, '2.0.0'))('Emits a system log when import assertions are used', async () => { +test.skipIf(gte(denoVersion, '2.0.0'))('Emits a system log when import assertions are used', async () => { const { basePath, cleanup, distPath } = await useFixture('with_import_assert') const sourceDirectory = join(basePath, 'functions') const declarations: Declaration[] = [ From a57b64badcd3c64c19b7713ca6d740c0b644b946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Bou=C3=A7as?= Date: Wed, 30 Jul 2025 15:10:56 +0100 Subject: [PATCH 4/4] chore: adjust version check --- packages/edge-bundler/node/bundler.test.ts | 60 ++++++++++++---------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/packages/edge-bundler/node/bundler.test.ts b/packages/edge-bundler/node/bundler.test.ts index b33afda11a..a1bfd32ec6 100644 --- a/packages/edge-bundler/node/bundler.test.ts +++ b/packages/edge-bundler/node/bundler.test.ts @@ -627,38 +627,42 @@ test('Loads JSON modules with `with` attribute', async () => { // We can't run this on versions above 2.0.0 because the bundling will fail // entirely, and what we're asserting here is that we emit a system log when -// import assertions are detected on successful builds. -test.skipIf(gte(denoVersion, '2.0.0'))('Emits a system log when import assertions are used', async () => { - const { basePath, cleanup, distPath } = await useFixture('with_import_assert') - const sourceDirectory = join(basePath, 'functions') - const declarations: Declaration[] = [ - { - function: 'func1', - path: '/func1', - }, - ] - const vendorDirectory = await tmp.dir() - const systemLogger = vi.fn() +// import assertions are detected on successful builds. Also, running it on +// earlier versions won't work either, since those won't even show a warning. +test.skipIf(lt(denoVersion, '1.46.3') || gte(denoVersion, '2.0.0'))( + 'Emits a system log when import assertions are used', + async () => { + const { basePath, cleanup, distPath } = await useFixture('with_import_assert') + const sourceDirectory = join(basePath, 'functions') + const declarations: Declaration[] = [ + { + function: 'func1', + path: '/func1', + }, + ] + const vendorDirectory = await tmp.dir() + const systemLogger = vi.fn() - await bundle([sourceDirectory], distPath, declarations, { - basePath, - systemLogger, - vendorDirectory: vendorDirectory.path, - }) + await bundle([sourceDirectory], distPath, declarations, { + basePath, + systemLogger, + vendorDirectory: vendorDirectory.path, + }) - const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8') - const manifest = JSON.parse(manifestFile) - const bundlePath = join(distPath, manifest.bundles[0].asset) - const { func1 } = await runESZIP(bundlePath, vendorDirectory.path) + const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8') + const manifest = JSON.parse(manifestFile) + const bundlePath = join(distPath, manifest.bundles[0].asset) + const { func1 } = await runESZIP(bundlePath, vendorDirectory.path) - expect(func1).toBe(`{"foo":"bar"}`) - expect(systemLogger).toHaveBeenCalledWith( - `Edge function uses import assertions: ${join(sourceDirectory, 'func1.ts')}`, - ) + expect(func1).toBe(`{"foo":"bar"}`) + expect(systemLogger).toHaveBeenCalledWith( + `Edge function uses import assertions: ${join(sourceDirectory, 'func1.ts')}`, + ) - await cleanup() - await rm(vendorDirectory.path, { force: true, recursive: true }) -}) + await cleanup() + await rm(vendorDirectory.path, { force: true, recursive: true }) + }, +) test('Supports TSX and process.env', async () => { const { basePath, cleanup, distPath } = await useFixture('tsx')