@netlify/edge-bundler 14.9.4 → 14.9.6
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.
|
@@ -14,5 +14,5 @@ interface BundleTarballOptions {
|
|
|
14
14
|
importMap: ImportMap;
|
|
15
15
|
vendorDirectory?: string;
|
|
16
16
|
}
|
|
17
|
-
export declare const bundle: ({
|
|
17
|
+
export declare const bundle: ({ buildID, deno, distDirectory, functions, importMap, vendorDirectory, }: BundleTarballOptions) => Promise<Bundle>;
|
|
18
18
|
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { promises as fs } from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
3
4
|
import commonPathPrefix from 'common-path-prefix';
|
|
4
5
|
import * as tar from 'tar';
|
|
5
6
|
import tmp from 'tmp-promise';
|
|
@@ -8,55 +9,77 @@ import { listRecursively } from '../utils/fs.js';
|
|
|
8
9
|
import { getFileHash } from '../utils/sha256.js';
|
|
9
10
|
const TARBALL_EXTENSION = '.tar.gz';
|
|
10
11
|
const getUnixPath = (input) => input.split(path.sep).join('/');
|
|
11
|
-
export const bundle = async ({
|
|
12
|
+
export const bundle = async ({ buildID, deno, distDirectory, functions, importMap, vendorDirectory, }) => {
|
|
12
13
|
const bundleDir = await tmp.dir({ unsafeCleanup: true });
|
|
13
14
|
const cleanup = [bundleDir.cleanup];
|
|
14
|
-
let denoDir = vendorDirectory ? path.join(vendorDirectory, 'deno_dir') : undefined;
|
|
15
|
-
if (!denoDir) {
|
|
16
|
-
const tmpDir = await tmp.dir({ unsafeCleanup: true });
|
|
17
|
-
denoDir = tmpDir.path;
|
|
18
|
-
cleanup.push(tmpDir.cleanup);
|
|
19
|
-
}
|
|
20
15
|
const manifest = {
|
|
21
16
|
functions: {},
|
|
22
17
|
version: 1,
|
|
23
18
|
};
|
|
24
19
|
const entryPoints = functions.map((func) => func.path);
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
//
|
|
30
|
-
|
|
20
|
+
// Use deno info to get the module graph and identify which local files are actually needed.
|
|
21
|
+
// This avoids copying unnecessary files (like node_modules) that happen to be under commonPath.
|
|
22
|
+
// If module graph analysis fails, fall back to copying files from entry point directories.
|
|
23
|
+
const sourceFiles = await getRequiredSourceFiles(deno, entryPoints, importMap);
|
|
24
|
+
// Find the common path prefix for all source files (entry points + their local imports).
|
|
25
|
+
// This ensures imports to sibling directories (e.g., ../internal/) are included.
|
|
26
|
+
// When using a single file, `commonPathPrefix` returns an empty string, so we use
|
|
27
|
+
// the path of the first entry point's directory.
|
|
28
|
+
const commonPath = commonPathPrefix(sourceFiles) || path.dirname(entryPoints[0]);
|
|
29
|
+
// Build the manifest mapping function names to their relative paths
|
|
31
30
|
for (const func of functions) {
|
|
32
31
|
const relativePath = path.relative(commonPath, func.path);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
manifest.functions[func.name] = getUnixPath(relativePath);
|
|
33
|
+
}
|
|
34
|
+
for (const sourceFile of sourceFiles) {
|
|
35
|
+
const relativePath = path.relative(commonPath, sourceFile);
|
|
36
|
+
const destPath = path.join(bundleDir.path, relativePath);
|
|
37
|
+
await fs.mkdir(path.dirname(destPath), { recursive: true });
|
|
38
|
+
await fs.copyFile(sourceFile, destPath);
|
|
39
39
|
}
|
|
40
|
+
// Vendor all dependencies in the bundle directory
|
|
40
41
|
await deno.run([
|
|
41
|
-
'
|
|
42
|
+
'install',
|
|
42
43
|
'--import-map',
|
|
43
44
|
importMap.withNodeBuiltins().toDataURL(),
|
|
44
45
|
'--quiet',
|
|
45
|
-
'--code-splitting',
|
|
46
46
|
'--allow-import',
|
|
47
47
|
'--node-modules-dir=manual',
|
|
48
|
-
'--
|
|
49
|
-
|
|
50
|
-
...functions.map((func) => func.path),
|
|
48
|
+
'--vendor',
|
|
49
|
+
'--entrypoint',
|
|
50
|
+
...functions.map((func) => path.relative(commonPath, func.path)),
|
|
51
51
|
], {
|
|
52
|
-
cwd:
|
|
52
|
+
cwd: bundleDir.path,
|
|
53
53
|
});
|
|
54
|
+
// Build prefix mappings to transform file:// URLs to relative paths
|
|
55
|
+
const npmVendorDir = '.netlify-npm-vendor';
|
|
56
|
+
const prefixes = {};
|
|
57
|
+
// Copy pre-bundled npm modules from vendorDirectory if present.
|
|
58
|
+
// This supports the legacy approach where npm packages are pre-bundled and mapped
|
|
59
|
+
// via import map. Modern code could use npm: specifiers instead, which Deno handles
|
|
60
|
+
// natively via `deno install --vendor`.
|
|
61
|
+
if (vendorDirectory) {
|
|
62
|
+
prefixes[pathToFileURL(vendorDirectory + path.sep).href] = `./${npmVendorDir}/`;
|
|
63
|
+
// Copy files from vendor directory
|
|
64
|
+
const vendorFiles = await listRecursively(vendorDirectory);
|
|
65
|
+
for (const vendorFile of vendorFiles) {
|
|
66
|
+
const relativePath = path.relative(vendorDirectory, vendorFile);
|
|
67
|
+
const destPath = path.join(bundleDir.path, npmVendorDir, relativePath);
|
|
68
|
+
await fs.mkdir(path.dirname(destPath), { recursive: true });
|
|
69
|
+
await fs.copyFile(vendorFile, destPath);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Map common path to relative paths
|
|
73
|
+
prefixes[pathToFileURL(commonPath + path.sep).href] = './';
|
|
74
|
+
// Get import map contents with file:// URLs transformed to relative paths
|
|
75
|
+
const importMapContents = importMap.getContents(prefixes);
|
|
76
|
+
// Create deno.json with import map contents for runtime resolution
|
|
77
|
+
const denoConfigPath = path.join(bundleDir.path, 'deno.json');
|
|
78
|
+
const denoConfigContents = JSON.stringify(importMapContents);
|
|
79
|
+
await fs.writeFile(denoConfigPath, denoConfigContents);
|
|
54
80
|
const manifestPath = path.join(bundleDir.path, '___netlify-edge-functions.json');
|
|
55
81
|
const manifestContents = JSON.stringify(manifest);
|
|
56
82
|
await fs.writeFile(manifestPath, manifestContents);
|
|
57
|
-
const denoConfigPath = path.join(bundleDir.path, 'deno.json');
|
|
58
|
-
const denoConfigContents = JSON.stringify(importMap.getContentsWithRelativePaths());
|
|
59
|
-
await fs.writeFile(denoConfigPath, denoConfigContents);
|
|
60
83
|
const tarballPath = path.join(distDirectory, buildID + TARBALL_EXTENSION);
|
|
61
84
|
await fs.mkdir(path.dirname(tarballPath), { recursive: true });
|
|
62
85
|
// List files to include in the tarball as paths relative to the bundle dir.
|
|
@@ -84,3 +107,45 @@ export const bundle = async ({ basePath, buildID, deno, distDirectory, functions
|
|
|
84
107
|
hash,
|
|
85
108
|
};
|
|
86
109
|
};
|
|
110
|
+
/**
|
|
111
|
+
* Uses deno info to get the module graph and extract only the local source files
|
|
112
|
+
* that are actually needed by the entry points. This avoids copying unnecessary
|
|
113
|
+
* files (like node_modules, .next, etc.) that may be under the common path.
|
|
114
|
+
*
|
|
115
|
+
* If deno info fails, falls back to copying files from the directories containing
|
|
116
|
+
* the entry points (not the entire common path).
|
|
117
|
+
*/
|
|
118
|
+
async function getRequiredSourceFiles(deno, entryPoints, importMap) {
|
|
119
|
+
const localFiles = new Set();
|
|
120
|
+
const importMapDataUrl = importMap.withNodeBuiltins().toDataURL();
|
|
121
|
+
// Run deno info for each entry point and combine the results
|
|
122
|
+
for (const entryPoint of entryPoints) {
|
|
123
|
+
try {
|
|
124
|
+
const { stdout } = await deno.run([
|
|
125
|
+
'info',
|
|
126
|
+
'--json',
|
|
127
|
+
'--import-map',
|
|
128
|
+
importMapDataUrl,
|
|
129
|
+
pathToFileURL(entryPoint).href,
|
|
130
|
+
]);
|
|
131
|
+
const graph = JSON.parse(stdout);
|
|
132
|
+
// Extract all local files from the module graph
|
|
133
|
+
for (const module of graph.modules) {
|
|
134
|
+
if (module.specifier.startsWith('file://')) {
|
|
135
|
+
const filePath = fileURLToPath(module.specifier);
|
|
136
|
+
localFiles.add(filePath);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// If deno info fails for this entry point, fall back to copying files
|
|
142
|
+
// from its directory
|
|
143
|
+
const dir = path.dirname(entryPoint);
|
|
144
|
+
const files = await listRecursively(dir);
|
|
145
|
+
for (const file of files) {
|
|
146
|
+
localFiles.add(file);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return Array.from(localFiles).sort();
|
|
151
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/edge-bundler",
|
|
3
|
-
"version": "14.9.
|
|
3
|
+
"version": "14.9.6",
|
|
4
4
|
"description": "Intelligently prepare Netlify Edge Functions for deployment",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/node/index.js",
|
|
@@ -79,5 +79,5 @@
|
|
|
79
79
|
"urlpattern-polyfill": "8.0.2",
|
|
80
80
|
"uuid": "^11.0.0"
|
|
81
81
|
},
|
|
82
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "3b7249e4fd7ea006bf473b4953c17312369d1973"
|
|
83
83
|
}
|