Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/build/tests/edge_functions/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@ for (const variant of FLAG_VARIANTS) {
if (platform !== 'win32') {
test.serial(variant.id + ' - handles failure when bundling Edge Functions', async (t) => {
const output = await new Fixture('./fixtures/functions_invalid').withFlags(variant.flags).runWithBuild()
t.snapshot(normalizeOutput(output))
t.snapshot(
normalizeOutput(output.replace(/"?[a-zA-Z0-9\\/.-_]*deno-tarball[/\\]deno[a-zA-Z0-9\\/.-_]*"?/g, 'deno')),
)
})
}

Expand Down
22 changes: 15 additions & 7 deletions packages/edge-bundler/node/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ const DENO_VERSION_FILE = 'version.txt'

export const LEGACY_DENO_VERSION_RANGE = '1.39.0 - 2.2.4'

export const TARBALL_DENO_VERSION_RANGE = '2.3.1'

// When updating DENO_VERSION_RANGE, ensure that the deno version
// on the netlify/buildbot build image satisfies this range!
// https://github.com/netlify/buildbot/blob/f9c03c9dcb091d6570e9d0778381560d469e78ad/build-image/noble/Dockerfile#L410
Expand All @@ -42,6 +44,11 @@ export interface ProcessRef {

interface RunOptions {
cwd?: string
// Overrides the `DENO_DIR` for this invocation only, taking precedence over
// the bridge-level `denoDir`. Used to point a single command (e.g. `deno
// cache`) at a bundle-local cache without affecting other commands that
// should keep using the shared, cross-build cache.
denoDir?: string
env?: NodeJS.ProcessEnv
extendEnv?: boolean
pipeOutput?: boolean
Expand Down Expand Up @@ -246,11 +253,12 @@ To install Deno manually: https://ntl.fyi/install-deno`,
return { global: false, path: downloadedPath }
}

getEnvironmentVariables(inputEnv: NodeJS.ProcessEnv = {}) {
getEnvironmentVariables(inputEnv: NodeJS.ProcessEnv = {}, denoDirOverride?: string) {
const env: NodeJS.ProcessEnv = { ...inputEnv }

if (this.denoDir !== undefined) {
env.DENO_DIR = this.denoDir
const denoDir = denoDirOverride ?? this.denoDir
if (denoDir !== undefined) {
env.DENO_DIR = denoDir
}

// Ensure PATH is always set as otherwise we are not able to find the global deno binary
Expand All @@ -263,10 +271,10 @@ To install Deno manually: https://ntl.fyi/install-deno`,
// process, awaiting its execution.
async run(
args: string[],
{ cwd, env: inputEnv, extendEnv = true, rejectOnExitCode = true, stderr, stdout }: RunOptions = {},
{ cwd, denoDir, env: inputEnv, extendEnv = true, rejectOnExitCode = true, stderr, stdout }: RunOptions = {},
) {
const { path: binaryPath } = await this.getBinaryPath()
const env = this.getEnvironmentVariables(inputEnv)
const env = this.getEnvironmentVariables(inputEnv, denoDir)
const options: Options = { cwd, env, extendEnv, reject: rejectOnExitCode }

return DenoBridge.runWithBinary(binaryPath, args, { options, stderr, stdout })
Expand All @@ -277,10 +285,10 @@ To install Deno manually: https://ntl.fyi/install-deno`,
async runInBackground(
args: string[],
ref?: ProcessRef,
{ env: inputEnv, extendEnv = true, pipeOutput, stderr, stdout }: RunOptions = {},
{ denoDir, env: inputEnv, extendEnv = true, pipeOutput, stderr, stdout }: RunOptions = {},
) {
const { path: binaryPath } = await this.getBinaryPath()
const env = this.getEnvironmentVariables(inputEnv)
const env = this.getEnvironmentVariables(inputEnv, denoDir)
const options: Options = { env, extendEnv }
const ps = DenoBridge.runWithBinary(binaryPath, args, { options, pipeOutput, stderr, stdout })

Expand Down
60 changes: 53 additions & 7 deletions packages/edge-bundler/node/bundler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,54 @@
await cleanup()
})

test('Includes a relocated Deno cache (DENO_DIR) in the tarball', async () => {
const { basePath, cleanup, distPath } = await useFixture('imports_node_builtin', { copyDirectory: true })
const declarations: Declaration[] = [
{
function: 'func1',
path: '/func1',
},
]

await bundle([join(basePath, 'netlify/edge-functions')], distPath, declarations, {
basePath,
configPath: join(basePath, '.netlify/edge-functions/config.json'),
featureFlags: {
edge_bundler_generate_tarball: true,
},
})

const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8')
const manifest = JSON.parse(manifestFile)
const tarballPath = join(distPath, manifest.bundles[0].asset)

const entries: string[] = []
await tar.list({
file: tarballPath,
onReadEntry: (entry) => {
entries.push(entry.path)
},
})

// The transpiled local function should be cached under the runtime mount
// path (`gen/file/platform/...`), not the arbitrary bundling path.
expect(entries).toContain('./.deno_dir/gen/file/platform/func1.ts.js')

const genFileEntries = entries.filter((entry) => entry.startsWith('./.deno_dir/gen/file/'))
expect(genFileEntries.length).toBeGreaterThan(0)

// No `gen/file` entry should leak a bundling-time absolute path; they must
// all live under the relocated `platform/` directory.
for (const entry of genFileEntries) {
expect(entry.startsWith('./.deno_dir/gen/file/platform/')).toBe(true)
}

// The absolute-path-keyed dependency-analysis cache should be dropped.
expect(entries.some((entry) => entry.includes('dep_analysis_cache'))).toBe(false)

await cleanup()
})

test('Using npm and remote modules', async () => {
const systemLogger = vi.fn()
const { basePath, cleanup, distPath } = await useFixture('imports_npm_module', { copyDirectory: true })
Expand Down Expand Up @@ -1039,7 +1087,7 @@
systemLogger,
})

expect(systemLogger).toHaveBeenCalledWith('Dry run: Eszip and tarball bundle generated successfully.')

Check failure on line 1090 in packages/edge-bundler/node/bundler.test.ts

View workflow job for this annotation

GitHub Actions / test (windows-2025, 22, v2.8.0)

node/bundler.test.ts > Produces a tarball bundle > Dry-run tarball generation flag enabled > Includes tarball in bundles when generation succeeds

AssertionError: expected "spy" to be called with arguments: [ Array(1) ] Received: 1st spy call: [ - "Dry run: Eszip and tarball bundle generated successfully.", + "Local version of types is up-to-date:", + "6a16c0912c6c5600086a3bed", ] 2nd spy call: [ - "Dry run: Eszip and tarball bundle generated successfully.", + "No globalVersion or semver not satisfied. globalVersion: 2.8.0, versionRange: 2.3.1", ] 3rd spy call: [ - "Dry run: Eszip and tarball bundle generated successfully.", + "Using cached Deno CLI from", + "C:\\Users\\runneradmin\\AppData\\Roaming\\netlify\\Config\\deno-tarball\\deno.exe", ] 4th spy call: [ - "Dry run: Eszip and tarball bundle generated successfully.", + "No globalVersion or semver not satisfied. globalVersion: 2.8.0, versionRange: 2.3.1", ] 5th spy call: [ - "Dry run: Eszip and tarball bundle generated successfully.", + "Using cached Deno CLI from", + "C:\\Users\\runneradmin\\AppData\\Roaming\\netlify\\Config\\deno-tarball\\deno.exe", ] 6th spy call: [ - "Dry run: Eszip and tarball bundle generated successfully.", + "No globalVersion or semver not satisfied. globalVersion: 2.8.0, versionRange: 2.3.1", ] 7th spy call: [ - "Dry run: Eszip and tarball bundle generated successfully.", + "Using cached Deno CLI from", + "C:\\Users\\runneradmin\\AppData\\Roaming\\netlify\\Config\\deno-tarball\\deno.exe", ] 8th spy call: [ - "Dry run: Eszip and tarball bundle generated successfully.", + "Using global installation of Deno CLI", ] 9th spy call: [ - "Dry run: Eszip and tarball bundle generated successfully.", + "Using global installation of Deno CLI", ] 10th spy call: [ - "Dry run: Eszip and tarball bundle generated successfully.", + "Dry run: Eszip successful, tarball bundle generation failed: Expected Deno to emit transpiled local files at C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\tmp-5456-EWDYcmZxv2BL\\.deno_dir\\gen\\file\\C:\\Users\\runneradmin\\AppData\\Local\\Temp\\tmp-5456-EWDYcmZxv2BL, but the directory was not found", ] Number of calls: 10 ❯ node/bundler.test.ts:1090:30

const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8')
const manifest = JSON.parse(manifestFile)
Expand Down Expand Up @@ -1174,7 +1222,7 @@
edge_bundler_generate_tarball: true,
},
}),
).resolves.not.toThrow()

Check failure on line 1225 in packages/edge-bundler/node/bundler.test.ts

View workflow job for this annotation

GitHub Actions / test (windows-2025, 22, v2.8.0)

node/bundler.test.ts > Produces a tarball bundle > With @ prefixed local import filenames

AssertionError: promise rejected "Error: Expected Deno to emit transpiled l…" instead of resolving ❯ node/bundler.test.ts:1225:7 Caused by: Caused by: Error: Expected Deno to emit transpiled local files at C:\Users\RUNNER~1\AppData\Local\Temp\tmp-5456-MvIBzgK8I5Gf\.deno_dir\gen\file\C:\Users\runneradmin\AppData\Local\Temp\tmp-5456-MvIBzgK8I5Gf, but the directory was not found ❯ relocateGenFileCache node/formats/tarball.ts:117:11 ❯ createDenoCache node/formats/tarball.ts:93:3 ❯ bundle node/formats/tarball.ts:272:3 ❯ node/bundler.ts:146:16 ❯ Module.bundle node/bundler.ts:174:31 ❯ node/bundler.test.ts:1218:7

const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8')
const manifest = JSON.parse(manifestFile)
Expand Down Expand Up @@ -1355,13 +1403,11 @@
expect(entries).toContain('./func1.ts')

// The vendored deno_dom WASM payload must be present in the tarball.
// Deno <2.6 vendors `.wasm` imports under a `.d.mts` extension (with a
// content-hash suffix); 2.6+ keeps the original `.wasm` extension.
const denoDomVendorPrefix = './vendor/deno.land/x/deno_dom@v0.1.56/build/deno-wasm/'
const expectedWasmEntry = lt(denoVersion, '2.6.0')
? `${denoDomVendorPrefix}#deno-wasm_bg.wasm_d2792.d.mts`
: `${denoDomVendorPrefix}deno-wasm_bg.wasm`
expect(entries).toContain(expectedWasmEntry)
// Tarball bundling always vendors with the runtime-matched Deno (see
// `TARBALL_DENO_VERSION_RANGE`), independent of the local Deno running
// these tests. That version is <2.6, which vendors `.wasm` imports under a
// hashed `.d.mts` name.
expect(entries).toContain('./vendor/deno.land/x/deno_dom@v0.1.56/build/deno-wasm/#deno-wasm_bg.wasm_d2792.d.mts')

const eszipPath = join(distPath, manifest.bundles[1].asset)
const eszipResult = await runESZIP(eszipPath)
Expand Down
24 changes: 23 additions & 1 deletion packages/edge-bundler/node/bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
OnAfterDownloadHook,
OnBeforeDownloadHook,
LEGACY_DENO_VERSION_RANGE,
TARBALL_DENO_VERSION_RANGE,
} from './bridge.js'
import type { Bundle } from './bundle.js'
import { FunctionConfig, getFunctionConfig } from './config.js'
Expand Down Expand Up @@ -133,6 +134,11 @@ export const bundle = async (
let finalizeTarballBundle: Awaited<ReturnType<typeof bundleTarball>> | undefined

if (featureFlags.edge_bundler_generate_tarball || featureFlags.edge_bundler_dry_run_generate_tarball) {
// Tarball bundles are executed at runtime by a Deno version matching
// `TARBALL_DENO_VERSION_RANGE`, so we bundle them with that same version to
// keep the produced module graph and Deno cache compatible.
const denoTarball = createTarballDenoBridge(options)

const tarballInitialPromise = (async () => {
const start = Date.now()

Expand All @@ -141,7 +147,7 @@ export const bundle = async (
basePath,
buildID,
debug,
deno,
deno: denoTarball,
distDirectory,
functions,
featureFlags,
Expand Down Expand Up @@ -276,6 +282,22 @@ export const bundle = async (
return { functions, manifest }
}

// Builds a `DenoBridge` pinned to the Deno version used to run tarball bundles
// at runtime (`TARBALL_DENO_VERSION_RANGE`). It reuses the shared options
// (including `denoDir`, so the module download cache is shared across builds)
// but downloads its binary into a dedicated directory so it doesn't clash with
// the default bridge's binary, which targets a different version range.
const createTarballDenoBridge = (options: DenoOptions) => {
const binaryCacheDirectory =
options.cacheDirectory === undefined ? getPathInHome('deno-tarball') : join(options.cacheDirectory, 'deno-tarball')

return new DenoBridge({
...options,
cacheDirectory: binaryCacheDirectory,
versionRange: TARBALL_DENO_VERSION_RANGE,
})
}

interface GetFunctionConfigsOptions {
deno: DenoBridge
importMap: ImportMap
Expand Down
109 changes: 109 additions & 0 deletions packages/edge-bundler/node/formats/tarball.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,105 @@

const getUnixPath = (input: string) => input.split(path.sep).join('/')

// Name of the Deno cache directory (DENO_DIR) we create inside the bundle. The
// runtime points `DENO_DIR` at this directory once the bundle is mounted.
const DENO_DIR_NAME = '.deno_dir'

// The directory (relative to the filesystem root) the bundle is mounted at when
// executed at runtime. Deno keys the transpiled output of local source files by
// their absolute path under `gen/file/`, so cache entries are relocated from the
// (arbitrary) bundling path to this path to remain resolvable at runtime.
const RUNTIME_MOUNT_DIR = 'platform'

// Subdirectory of DENO_DIR holding Deno's emit cache: the transpiled JS output
// of non-JS sources (TypeScript, JSX). Deno calls this the `gen` cache (the
// `EmitCache`, surfaced as the emit/TypeScript cache in `deno info`). Shipping
// it lets the runtime skip transpiling those sources on cold start, and it's the
// only DENO_DIR artifact we keep β€” see `pruneDenoDirToGen`.
const DENO_EMIT_CACHE_DIR = 'gen'

interface CreateDenoCacheOptions {
deno: DenoBridge
bundleDirPath: string
denoConfigPath: string
entrypoints: string[]
}

/**
* Runs `deno cache` to populate a DENO_DIR inside the bundle, then rewrites it
* so it's usable from the runtime mount path. The cache lets the runtime skip
* transpiling (and re-downloading) modules on cold start.
*/
const createDenoCache = async ({ deno, bundleDirPath, denoConfigPath, entrypoints }: CreateDenoCacheOptions) => {
console.log('[dev-log] Creating Deno cache for tarball bundle...')
const denoDir = path.join(bundleDirPath, DENO_DIR_NAME)

// `--vendor` makes Deno resolve dependencies from the vendor directory, just
// like the runtime does, so the cached output lines up with runtime resolution.
// `--config` loads the import map from the generated deno.json. `--allow-import`
// permits fetching from hosts outside Deno's default allow-list (mirroring how
// the runtime and the vendoring step are invoked).
await deno.run(['cache', '--allow-import', '--vendor', '--config', denoConfigPath, ...entrypoints], {
cwd: bundleDirPath,
denoDir,
})

await relocateGenFileCache(bundleDirPath, denoDir)
await pruneDenoDirToGen(denoDir)
}

/**
* Deno stores the transpiled output of local source files under
* `<DENO_DIR>/gen/file/<absolute source path>`, using the real (symlink-resolved)
* path. Because the bundle is created at an arbitrary path but mounted at
* `/<RUNTIME_MOUNT_DIR>` at runtime, we move that subtree so the entries match the
* runtime paths. Remote and vendored modules are cached under `gen/https/<hash>`
* (content-addressed) and need no relocation.
*/
const relocateGenFileCache = async (bundleDirPath: string, denoDir: string) => {
const genFileDir = path.join(denoDir, DENO_EMIT_CACHE_DIR, 'file')

// Deno resolves symlinks before computing the cache path (e.g. on macOS
// `/var` -> `/private/var`), so we resolve the bundle path the same way to
// locate the subtree it emitted.
const realBundleDirPath = await fs.realpath(bundleDirPath)
const segments = realBundleDirPath.split(path.sep).filter(Boolean)
const source = path.join(genFileDir, ...segments)
const destination = path.join(genFileDir, RUNTIME_MOUNT_DIR)

if (!existsSync(source)) {
throw new Error(`Expected Deno to emit transpiled local files at ${source}, but the directory was not found`)

Check failure on line 117 in packages/edge-bundler/node/formats/tarball.ts

View workflow job for this annotation

GitHub Actions / test (windows-2025, 22, v2.8.0)

node/bundler.test.ts > Produces a tarball bundle > Importing from root vendor directory is handled

Error: Expected Deno to emit transpiled local files at C:\Users\RUNNER~1\AppData\Local\Temp\tmp-5456-S1zsCxY61eAZ\.deno_dir\gen\file\C:\Users\runneradmin\AppData\Local\Temp\tmp-5456-S1zsCxY61eAZ, but the directory was not found ❯ relocateGenFileCache node/formats/tarball.ts:117:11 ❯ createDenoCache node/formats/tarball.ts:93:3 ❯ bundle node/formats/tarball.ts:272:3 ❯ node/bundler.ts:146:16 ❯ Module.bundle node/bundler.ts:174:31 ❯ node/bundler.test.ts:1258:7

Check failure on line 117 in packages/edge-bundler/node/formats/tarball.ts

View workflow job for this annotation

GitHub Actions / test (windows-2025, 22, v2.8.0)

node/bundler.test.ts > Produces a tarball bundle > npm + http modules with import assertions

Error: Expected Deno to emit transpiled local files at C:\Users\RUNNER~1\AppData\Local\Temp\tmp-5456-wN1aocxonc2c\.deno_dir\gen\file\C:\Users\runneradmin\AppData\Local\Temp\tmp-5456-wN1aocxonc2c, but the directory was not found ❯ relocateGenFileCache node/formats/tarball.ts:117:11 ❯ createDenoCache node/formats/tarball.ts:93:3 ❯ bundle node/formats/tarball.ts:272:3 ❯ node/bundler.ts:146:16 ❯ Module.bundle node/bundler.ts:174:31 ❯ node/bundler.test.ts:1164:7

Check failure on line 117 in packages/edge-bundler/node/formats/tarball.ts

View workflow job for this annotation

GitHub Actions / test (windows-2025, 22, v2.8.0)

node/bundler.test.ts > Produces a tarball bundle > Rewrites import assertions

Error: Expected Deno to emit transpiled local files at C:\Users\RUNNER~1\AppData\Local\Temp\tmp-5456-ApIMM5mBiH23\.deno_dir\gen\file\C:\Users\runneradmin\AppData\Local\Temp\tmp-5456-ApIMM5mBiH23, but the directory was not found ❯ relocateGenFileCache node/formats/tarball.ts:117:11 ❯ createDenoCache node/formats/tarball.ts:93:3 ❯ bundle node/formats/tarball.ts:272:3 ❯ node/bundler.ts:146:16 ❯ Module.bundle node/bundler.ts:174:31 ❯ node/bundler.test.ts:1039:7

Check failure on line 117 in packages/edge-bundler/node/formats/tarball.ts

View workflow job for this annotation

GitHub Actions / test (windows-2025, 22, v2.8.0)

node/bundler.test.ts > Produces a tarball bundle > Rewrites bare specifier imports to resolved URLs

Error: Expected Deno to emit transpiled local files at C:\Users\RUNNER~1\AppData\Local\Temp\tmp-5456-0QnaefM18iVO\.deno_dir\gen\file\C:\Users\runneradmin\AppData\Local\Temp\tmp-5456-0QnaefM18iVO, but the directory was not found ❯ relocateGenFileCache node/formats/tarball.ts:117:11 ❯ createDenoCache node/formats/tarball.ts:93:3 ❯ bundle node/formats/tarball.ts:272:3 ❯ node/bundler.ts:146:16 ❯ Module.bundle node/bundler.ts:174:31 ❯ node/bundler.test.ts:999:7

Check failure on line 117 in packages/edge-bundler/node/formats/tarball.ts

View workflow job for this annotation

GitHub Actions / test (windows-2025, 22, v2.8.0)

node/bundler.test.ts > Produces a tarball bundle > With imports from sibling directories

Error: Expected Deno to emit transpiled local files at C:\Users\RUNNER~1\AppData\Local\Temp\tmp-5456-v2SyItt1RLjn\.deno_dir\gen\file\C:\Users\runneradmin\AppData\Local\Temp\tmp-5456-v2SyItt1RLjn, but the directory was not found ❯ relocateGenFileCache node/formats/tarball.ts:117:11 ❯ createDenoCache node/formats/tarball.ts:93:3 ❯ bundle node/formats/tarball.ts:272:3 ❯ node/bundler.ts:146:16 ❯ Module.bundle node/bundler.ts:174:31 ❯ node/bundler.test.ts:947:7

Check failure on line 117 in packages/edge-bundler/node/formats/tarball.ts

View workflow job for this annotation

GitHub Actions / test (windows-2025, 22, v2.8.0)

node/bundler.test.ts > Produces a tarball bundle > Using npm and remote modules

Error: Expected Deno to emit transpiled local files at C:\Users\RUNNER~1\AppData\Local\Temp\tmp-5456-qFVMQ13TKPID\.deno_dir\gen\file\C:\Users\runneradmin\AppData\Local\Temp\tmp-5456-qFVMQ13TKPID, but the directory was not found ❯ relocateGenFileCache node/formats/tarball.ts:117:11 ❯ createDenoCache node/formats/tarball.ts:93:3 ❯ bundle node/formats/tarball.ts:272:3 ❯ node/bundler.ts:146:16 ❯ Module.bundle node/bundler.ts:174:31 ❯ node/bundler.test.ts:879:7

Check failure on line 117 in packages/edge-bundler/node/formats/tarball.ts

View workflow job for this annotation

GitHub Actions / test (windows-2025, 22, v2.8.0)

node/bundler.test.ts > Produces a tarball bundle > Includes a relocated Deno cache (DENO_DIR) in the tarball

Error: Expected Deno to emit transpiled local files at C:\Users\RUNNER~1\AppData\Local\Temp\tmp-5456-X1GvTU8TDJpl\.deno_dir\gen\file\C:\Users\runneradmin\AppData\Local\Temp\tmp-5456-X1GvTU8TDJpl, but the directory was not found ❯ relocateGenFileCache node/formats/tarball.ts:117:11 ❯ createDenoCache node/formats/tarball.ts:93:3 ❯ bundle node/formats/tarball.ts:272:3 ❯ node/bundler.ts:146:16 ❯ Module.bundle node/bundler.ts:174:31 ❯ node/bundler.test.ts:828:7

Check failure on line 117 in packages/edge-bundler/node/formats/tarball.ts

View workflow job for this annotation

GitHub Actions / test (windows-2025, 22, v2.8.0)

node/bundler.test.ts > Produces a tarball bundle > With only local imports

Error: Expected Deno to emit transpiled local files at C:\Users\RUNNER~1\AppData\Local\Temp\tmp-5456-KfiIAWnpqSyn\.deno_dir\gen\file\C:\Users\runneradmin\AppData\Local\Temp\tmp-5456-KfiIAWnpqSyn, but the directory was not found ❯ relocateGenFileCache node/formats/tarball.ts:117:11 ❯ createDenoCache node/formats/tarball.ts:93:3 ❯ bundle node/formats/tarball.ts:272:3 ❯ node/bundler.ts:146:16 ❯ Module.bundle node/bundler.ts:174:31 ❯ node/bundler.test.ts:772:7
}

await fs.rename(source, destination)

// Remove the now-empty leading directories (e.g. `gen/file/private/...`) left
// behind by the move so they don't end up in the tarball.
if (segments[0] !== RUNTIME_MOUNT_DIR) {
await fs.rm(path.join(genFileDir, segments[0]), { recursive: true, force: true })
}
}

/**
* Prunes the DENO_DIR down to just the emit cache (`DENO_EMIT_CACHE_DIR`) β€” the
* transpiled output we actually want to ship. We use an allowlist (keep the emit
* cache) rather than a blocklist (drop known-bad entries) so we stay robust to
* future Deno versions writing new, non-portable artifacts into the cache.
* Everything else Deno puts there is either regenerated on demand (e.g. the
* `dep_analysis_cache*` SQLite DBs, which key modules by absolute path and so
* wouldn't match runtime paths) or redundant with the vendored sources already
* in the bundle (`remote/` stays empty under `--vendor`).
*/
const pruneDenoDirToGen = async (denoDir: string) => {
const entries = await fs.readdir(denoDir)

await Promise.all(
entries
.filter((entry) => entry !== DENO_EMIT_CACHE_DIR)
.map((entry) => fs.rm(path.join(denoDir, entry), { recursive: true, force: true })),
)
}

export const bundle = async ({
buildID,
deno,
Expand Down Expand Up @@ -167,6 +266,16 @@
}
}

// Produce a Deno cache (DENO_DIR) inside the bundle so the runtime can skip
// downloading and transpiling modules on cold start, and include it in the
// tarball.
await createDenoCache({
deno,
bundleDirPath: bundleDir.path,
denoConfigPath,
entrypoints: Object.values(initialManifest.functions),
})

// First stage of bundling is now done. To finalize bundling we require functionConfig, routes and postCacheRoutes
// so we could inject those into bundle manifest. Tarball bundling is done in 2-step process process to preserve ordering
// and potential errors messages that could be thrown to make sure we don't impact behaviors. Otherwise we would throw different
Expand Down
Loading