@netlify/edge-bundler 5.3.3 → 5.5.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.
- package/deno/bundle.ts +2 -2
- package/deno/lib/stage2.ts +9 -4
- package/dist/node/bundle.d.ts +0 -1
- package/dist/node/bundler.js +2 -1
- package/dist/node/bundler.test.js +9 -46
- package/dist/node/config.test.js +2 -4
- package/dist/node/formats/eszip.js +4 -22
- package/dist/node/formats/javascript.js +1 -1
- package/dist/node/import_map.d.ts +4 -2
- package/dist/node/import_map.js +24 -14
- package/dist/node/import_map.test.js +43 -6
- package/dist/node/manifest.d.ts +4 -4
- package/dist/node/manifest.js +4 -4
- package/dist/node/server/server.js +1 -1
- package/dist/shared/consts.d.ts +1 -0
- package/dist/shared/consts.js +1 -0
- package/dist/shared/stage2.d.ts +1 -1
- package/dist/test/util.js +4 -5
- package/package.json +2 -2
- package/shared/consts.ts +1 -0
- package/shared/stage2.ts +1 -1
package/deno/bundle.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { writeStage2 } from './lib/stage2.ts'
|
|
2
2
|
|
|
3
3
|
const [payload] = Deno.args
|
|
4
|
-
const { basePath, destPath, externals, functions,
|
|
4
|
+
const { basePath, destPath, externals, functions, importMapData } = JSON.parse(payload)
|
|
5
5
|
|
|
6
|
-
await writeStage2({ basePath, destPath, externals, functions,
|
|
6
|
+
await writeStage2({ basePath, destPath, externals, functions, importMapData })
|
package/deno/lib/stage2.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { build, LoadResponse } from 'https://deno.land/x/eszip@v0.28.0/mod.ts'
|
|
|
3
3
|
import * as path from 'https://deno.land/std@0.127.0/path/mod.ts'
|
|
4
4
|
|
|
5
5
|
import type { InputFunction, WriteStage2Options } from '../../shared/stage2.ts'
|
|
6
|
-
import { virtualRoot } from '../../shared/consts.ts'
|
|
6
|
+
import { importMapSpecifier, virtualRoot } from '../../shared/consts.ts'
|
|
7
7
|
import { PUBLIC_SPECIFIER, STAGE2_SPECIFIER } from './consts.ts'
|
|
8
8
|
import { inlineModule, loadFromVirtualRoot, loadWithRetry } from './common.ts'
|
|
9
9
|
|
|
@@ -63,7 +63,7 @@ const getVirtualPath = (basePath: string, filePath: string) => {
|
|
|
63
63
|
return url
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
const stage2Loader = (basePath: string, functions: InputFunction[], externals: Set<string
|
|
66
|
+
const stage2Loader = (basePath: string, functions: InputFunction[], externals: Set<string>, importMapData?: string) => {
|
|
67
67
|
return async (specifier: string): Promise<LoadResponse | undefined> => {
|
|
68
68
|
if (specifier === STAGE2_SPECIFIER) {
|
|
69
69
|
const stage2Entry = getStage2Entry(basePath, functions)
|
|
@@ -71,6 +71,10 @@ const stage2Loader = (basePath: string, functions: InputFunction[], externals: S
|
|
|
71
71
|
return inlineModule(specifier, stage2Entry)
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
if (specifier === importMapSpecifier && importMapData !== undefined) {
|
|
75
|
+
return inlineModule(specifier, importMapData)
|
|
76
|
+
}
|
|
77
|
+
|
|
74
78
|
if (specifier === PUBLIC_SPECIFIER || externals.has(specifier)) {
|
|
75
79
|
return {
|
|
76
80
|
kind: 'external',
|
|
@@ -86,8 +90,9 @@ const stage2Loader = (basePath: string, functions: InputFunction[], externals: S
|
|
|
86
90
|
}
|
|
87
91
|
}
|
|
88
92
|
|
|
89
|
-
const writeStage2 = async ({ basePath, destPath, externals, functions,
|
|
90
|
-
const
|
|
93
|
+
const writeStage2 = async ({ basePath, destPath, externals, functions, importMapData }: WriteStage2Options) => {
|
|
94
|
+
const importMapURL = importMapData ? importMapSpecifier : undefined
|
|
95
|
+
const loader = stage2Loader(basePath, functions, new Set(externals), importMapData)
|
|
91
96
|
const bytes = await build([STAGE2_SPECIFIER], loader, importMapURL)
|
|
92
97
|
const directory = path.dirname(destPath)
|
|
93
98
|
|
package/dist/node/bundle.d.ts
CHANGED
package/dist/node/bundler.js
CHANGED
|
@@ -2,6 +2,7 @@ import { promises as fs } from 'fs';
|
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import commonPathPrefix from 'common-path-prefix';
|
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
|
5
|
+
import { importMapSpecifier } from '../shared/consts.js';
|
|
5
6
|
import { DenoBridge } from './bridge.js';
|
|
6
7
|
import { getFunctionConfig } from './config.js';
|
|
7
8
|
import { getDeclarationsFromConfig } from './declaration.js';
|
|
@@ -76,7 +77,7 @@ const bundle = async (sourceDirectories, distDirectory, tomlDeclarations = [], {
|
|
|
76
77
|
declarations,
|
|
77
78
|
distDirectory,
|
|
78
79
|
functions,
|
|
79
|
-
|
|
80
|
+
importMap: importMapSpecifier,
|
|
80
81
|
layers: deployConfig.layers,
|
|
81
82
|
});
|
|
82
83
|
if (distImportMapPath) {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { promises as fs } from 'fs';
|
|
2
2
|
import { join, resolve } from 'path';
|
|
3
3
|
import process from 'process';
|
|
4
|
-
import { pathToFileURL } from 'url';
|
|
5
4
|
import { deleteAsync } from 'del';
|
|
6
5
|
import tmp from 'tmp-promise';
|
|
7
6
|
import { test, expect } from 'vitest';
|
|
7
|
+
import { importMapSpecifier } from '../shared/consts.js';
|
|
8
8
|
import { useFixture } from '../test/util.js';
|
|
9
9
|
import { BundleError } from './bundle_error.js';
|
|
10
10
|
import { bundle } from './bundler.js';
|
|
@@ -25,8 +25,7 @@ test('Produces an ESZIP bundle', async () => {
|
|
|
25
25
|
});
|
|
26
26
|
const generatedFiles = await fs.readdir(distPath);
|
|
27
27
|
expect(result.functions.length).toBe(1);
|
|
28
|
-
|
|
29
|
-
expect(generatedFiles.length).toBe(3);
|
|
28
|
+
expect(generatedFiles.length).toBe(2);
|
|
30
29
|
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
31
30
|
const manifest = JSON.parse(manifestFile);
|
|
32
31
|
expect(() => validateManifest(manifest)).not.toThrowError();
|
|
@@ -34,7 +33,7 @@ test('Produces an ESZIP bundle', async () => {
|
|
|
34
33
|
expect(bundles.length).toBe(1);
|
|
35
34
|
expect(bundles[0].format).toBe('eszip2');
|
|
36
35
|
expect(generatedFiles.includes(bundles[0].asset)).toBe(true);
|
|
37
|
-
expect(importMapURL).toBe(
|
|
36
|
+
expect(importMapURL).toBe(importMapSpecifier);
|
|
38
37
|
await cleanup();
|
|
39
38
|
});
|
|
40
39
|
test('Uses the vendored eszip module instead of fetching it from deno.land', async () => {
|
|
@@ -52,8 +51,7 @@ test('Uses the vendored eszip module instead of fetching it from deno.land', asy
|
|
|
52
51
|
});
|
|
53
52
|
const generatedFiles = await fs.readdir(distPath);
|
|
54
53
|
expect(result.functions.length).toBe(1);
|
|
55
|
-
|
|
56
|
-
expect(generatedFiles.length).toBe(3);
|
|
54
|
+
expect(generatedFiles.length).toBe(2);
|
|
57
55
|
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
58
56
|
const manifest = JSON.parse(manifestFile);
|
|
59
57
|
const { bundles } = manifest;
|
|
@@ -140,8 +138,7 @@ test('Uses the cache directory as the `DENO_DIR` value if the `edge_functions_ca
|
|
|
140
138
|
const result1 = await bundle([sourceDirectory], distPath, declarations, options);
|
|
141
139
|
const outFiles1 = await fs.readdir(distPath);
|
|
142
140
|
expect(result1.functions.length).toBe(1);
|
|
143
|
-
|
|
144
|
-
expect(outFiles1.length).toBe(3);
|
|
141
|
+
expect(outFiles1.length).toBe(2);
|
|
145
142
|
try {
|
|
146
143
|
await fs.readdir(join(cacheDir.path, 'deno_dir'));
|
|
147
144
|
}
|
|
@@ -157,8 +154,7 @@ test('Uses the cache directory as the `DENO_DIR` value if the `edge_functions_ca
|
|
|
157
154
|
});
|
|
158
155
|
const outFiles2 = await fs.readdir(distPath);
|
|
159
156
|
expect(result2.functions.length).toBe(1);
|
|
160
|
-
|
|
161
|
-
expect(outFiles2.length).toBe(3);
|
|
157
|
+
expect(outFiles2.length).toBe(2);
|
|
162
158
|
const denoDir2 = await fs.readdir(join(cacheDir.path, 'deno_dir'));
|
|
163
159
|
expect(denoDir2.includes('gen')).toBe(true);
|
|
164
160
|
await cleanup();
|
|
@@ -178,8 +174,7 @@ test('Supports import maps with relative paths', async () => {
|
|
|
178
174
|
});
|
|
179
175
|
const generatedFiles = await fs.readdir(distPath);
|
|
180
176
|
expect(result.functions.length).toBe(1);
|
|
181
|
-
|
|
182
|
-
expect(generatedFiles.length).toBe(3);
|
|
177
|
+
expect(generatedFiles.length).toBe(2);
|
|
183
178
|
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
184
179
|
const manifest = JSON.parse(manifestFile);
|
|
185
180
|
const { bundles } = manifest;
|
|
@@ -247,8 +242,7 @@ test('Processes a function that imports a custom layer', async () => {
|
|
|
247
242
|
});
|
|
248
243
|
const generatedFiles = await fs.readdir(distPath);
|
|
249
244
|
expect(result.functions.length).toBe(1);
|
|
250
|
-
|
|
251
|
-
expect(generatedFiles.length).toBe(3);
|
|
245
|
+
expect(generatedFiles.length).toBe(2);
|
|
252
246
|
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
253
247
|
const manifest = JSON.parse(manifestFile);
|
|
254
248
|
const { bundles, layers } = manifest;
|
|
@@ -273,8 +267,7 @@ test('Loads declarations and import maps from the deploy configuration', async (
|
|
|
273
267
|
});
|
|
274
268
|
const generatedFiles = await fs.readdir(distPath);
|
|
275
269
|
expect(result.functions.length).toBe(2);
|
|
276
|
-
|
|
277
|
-
expect(generatedFiles.length).toBe(3);
|
|
270
|
+
expect(generatedFiles.length).toBe(2);
|
|
278
271
|
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
279
272
|
const manifest = JSON.parse(manifestFile);
|
|
280
273
|
const { bundles } = manifest;
|
|
@@ -283,33 +276,3 @@ test('Loads declarations and import maps from the deploy configuration', async (
|
|
|
283
276
|
expect(generatedFiles.includes(bundles[0].asset)).toBe(true);
|
|
284
277
|
await cleanup();
|
|
285
278
|
});
|
|
286
|
-
test('Uses an absolute URL for the import map when the dist directory is not a child of the base path', async () => {
|
|
287
|
-
const { basePath, cleanup } = await useFixture('with_import_maps');
|
|
288
|
-
const { path: distPath } = await tmp.dir();
|
|
289
|
-
const declarations = [
|
|
290
|
-
{
|
|
291
|
-
function: 'func1',
|
|
292
|
-
path: '/func1',
|
|
293
|
-
},
|
|
294
|
-
];
|
|
295
|
-
const sourceDirectory = join(basePath, 'functions');
|
|
296
|
-
const result = await bundle([sourceDirectory], distPath, declarations, {
|
|
297
|
-
basePath,
|
|
298
|
-
configPath: join(sourceDirectory, 'config.json'),
|
|
299
|
-
});
|
|
300
|
-
const generatedFiles = await fs.readdir(distPath);
|
|
301
|
-
expect(result.functions.length).toBe(1);
|
|
302
|
-
// ESZIP, manifest and import map.
|
|
303
|
-
expect(generatedFiles.length).toBe(3);
|
|
304
|
-
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
305
|
-
const manifest = JSON.parse(manifestFile);
|
|
306
|
-
expect(() => validateManifest(manifest)).not.toThrowError();
|
|
307
|
-
const { bundles, import_map: importMapURL } = manifest;
|
|
308
|
-
expect(bundles.length).toBe(1);
|
|
309
|
-
expect(bundles[0].format).toBe('eszip2');
|
|
310
|
-
expect(generatedFiles.includes(bundles[0].asset)).toBe(true);
|
|
311
|
-
const importMapPath = join(distPath, 'import_map.json');
|
|
312
|
-
expect(importMapURL).toBe(pathToFileURL(importMapPath).toString());
|
|
313
|
-
await cleanup();
|
|
314
|
-
await fs.rm(distPath, { recursive: true });
|
|
315
|
-
});
|
package/dist/node/config.test.js
CHANGED
|
@@ -131,8 +131,7 @@ test('Ignores function paths from the in-source `config` function if the feature
|
|
|
131
131
|
});
|
|
132
132
|
const generatedFiles = await fs.readdir(distPath);
|
|
133
133
|
expect(result.functions.length).toBe(6);
|
|
134
|
-
|
|
135
|
-
expect(generatedFiles.length).toBe(3);
|
|
134
|
+
expect(generatedFiles.length).toBe(2);
|
|
136
135
|
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
137
136
|
const manifest = JSON.parse(manifestFile);
|
|
138
137
|
const { bundles, routes } = manifest;
|
|
@@ -165,8 +164,7 @@ test('Loads function paths from the in-source `config` function', async () => {
|
|
|
165
164
|
});
|
|
166
165
|
const generatedFiles = await fs.readdir(distPath);
|
|
167
166
|
expect(result.functions.length).toBe(6);
|
|
168
|
-
|
|
169
|
-
expect(generatedFiles.length).toBe(3);
|
|
167
|
+
expect(generatedFiles.length).toBe(2);
|
|
170
168
|
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
171
169
|
const manifest = JSON.parse(manifestFile);
|
|
172
170
|
const { bundles, routes, post_cache_routes: postCacheRoutes } = manifest;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { join
|
|
2
|
-
import { pathToFileURL } from 'url';
|
|
1
|
+
import { join } from 'path';
|
|
3
2
|
import { virtualRoot } from '../../shared/consts.js';
|
|
4
3
|
import { BundleFormat } from '../bundle.js';
|
|
5
4
|
import { wrapBundleError } from '../bundle_error.js';
|
|
@@ -10,13 +9,13 @@ const bundleESZIP = async ({ basePath, buildID, debug, deno, distDirectory, exte
|
|
|
10
9
|
const extension = '.eszip';
|
|
11
10
|
const destPath = join(distDirectory, `${buildID}${extension}`);
|
|
12
11
|
const { bundler, importMap: bundlerImportMap } = getESZIPPaths();
|
|
13
|
-
const
|
|
12
|
+
const importMapData = JSON.stringify(importMap.getContents(basePath, virtualRoot));
|
|
14
13
|
const payload = {
|
|
15
14
|
basePath,
|
|
16
15
|
destPath,
|
|
17
16
|
externals,
|
|
18
17
|
functions,
|
|
19
|
-
|
|
18
|
+
importMapData,
|
|
20
19
|
};
|
|
21
20
|
const flags = ['--allow-all', '--no-config', `--import-map=${bundlerImportMap}`];
|
|
22
21
|
if (!debug) {
|
|
@@ -29,24 +28,7 @@ const bundleESZIP = async ({ basePath, buildID, debug, deno, distDirectory, exte
|
|
|
29
28
|
throw wrapBundleError(wrapNpmImportError(error), { format: 'eszip' });
|
|
30
29
|
}
|
|
31
30
|
const hash = await getFileHash(destPath);
|
|
32
|
-
return { extension, format: BundleFormat.ESZIP2, hash
|
|
33
|
-
};
|
|
34
|
-
// Takes an import map, writes it to a file on disk, and gets its URL relative
|
|
35
|
-
// to the ESZIP root (i.e. using the virtual root prefix).
|
|
36
|
-
const createUserImportMap = async (importMap, basePath, distDirectory) => {
|
|
37
|
-
const destPath = join(distDirectory, 'import_map.json');
|
|
38
|
-
await importMap.writeToFile(destPath);
|
|
39
|
-
const virtualPath = relative(basePath, destPath);
|
|
40
|
-
// If the dist directory is not a child of the base path, we can't represent
|
|
41
|
-
// the relative path as a file URL (because something like 'file://../foo' is
|
|
42
|
-
// not valid). This should never happen, but it's best to leave the absolute
|
|
43
|
-
// path untransformed to avoid getting a build error due to a missing import
|
|
44
|
-
// map.
|
|
45
|
-
if (virtualPath.startsWith('..')) {
|
|
46
|
-
return pathToFileURL(destPath).toString();
|
|
47
|
-
}
|
|
48
|
-
const importMapURL = new URL(virtualPath, virtualRoot);
|
|
49
|
-
return importMapURL.toString();
|
|
31
|
+
return { extension, format: BundleFormat.ESZIP2, hash };
|
|
50
32
|
};
|
|
51
33
|
const getESZIPPaths = () => {
|
|
52
34
|
const denoPath = join(getPackagePath(), 'deno');
|
|
@@ -3,7 +3,7 @@ import { join } from 'path';
|
|
|
3
3
|
import { env } from 'process';
|
|
4
4
|
import { pathToFileURL } from 'url';
|
|
5
5
|
import { deleteAsync } from 'del';
|
|
6
|
-
const BOOTSTRAP_LATEST = 'https://
|
|
6
|
+
const BOOTSTRAP_LATEST = 'https://639708f6d7f813000870695c--edge.netlify.com/bootstrap/index-combined.ts';
|
|
7
7
|
const defaultFormatExportTypeError = (name) => `The Edge Function "${name}" has failed to load. Does it have a function as the default export?`;
|
|
8
8
|
const defaultFormatImpoortError = (name) => `There was an error with Edge Function "${name}".`;
|
|
9
9
|
const generateStage2 = async ({ distDirectory, fileName, formatExportTypeError, formatImportError, functions, }) => {
|
|
@@ -6,12 +6,14 @@ interface ImportMapFile {
|
|
|
6
6
|
declare class ImportMap {
|
|
7
7
|
files: ImportMapFile[];
|
|
8
8
|
constructor(files?: ImportMapFile[]);
|
|
9
|
-
static resolve(importMapFile: ImportMapFile,
|
|
9
|
+
static resolve(importMapFile: ImportMapFile, basePath?: string, prefix?: string): {
|
|
10
10
|
imports: Record<string, string>;
|
|
11
11
|
scopes?: import("@import-maps/resolve/types/src/types").ParsedScopesMap | undefined;
|
|
12
12
|
};
|
|
13
13
|
add(file: ImportMapFile): void;
|
|
14
|
-
getContents(
|
|
14
|
+
getContents(basePath?: string, prefix?: string): {
|
|
15
|
+
imports: Record<string, string>;
|
|
16
|
+
};
|
|
15
17
|
toDataURL(): string;
|
|
16
18
|
writeToFile(path: string): Promise<void>;
|
|
17
19
|
}
|
package/dist/node/import_map.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Buffer } from 'buffer';
|
|
2
2
|
import { promises as fs } from 'fs';
|
|
3
|
-
import { dirname,
|
|
3
|
+
import { dirname, posix, relative, sep } from 'path';
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
5
5
|
import { parse } from '@import-maps/resolve';
|
|
6
6
|
const INTERNAL_IMPORTS = {
|
|
@@ -17,7 +17,7 @@ class ImportMap {
|
|
|
17
17
|
}
|
|
18
18
|
// Transforms an import map by making any relative paths use a different path
|
|
19
19
|
// as a base.
|
|
20
|
-
static resolve(importMapFile,
|
|
20
|
+
static resolve(importMapFile, basePath, prefix = 'file://') {
|
|
21
21
|
const { baseURL, ...importMap } = importMapFile;
|
|
22
22
|
const parsedImportMap = parse(importMap, baseURL);
|
|
23
23
|
const { imports = {} } = parsedImportMap;
|
|
@@ -29,13 +29,23 @@ class ImportMap {
|
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
// If this is a file URL, we might want to transform it to use another
|
|
32
|
-
//
|
|
33
|
-
if (url.protocol === 'file:' &&
|
|
32
|
+
// base path, as long as one is provided.
|
|
33
|
+
if (url.protocol === 'file:' && basePath !== undefined) {
|
|
34
|
+
const path = fileURLToPath(url);
|
|
35
|
+
const relativePath = relative(basePath, path);
|
|
36
|
+
if (relativePath.startsWith('..')) {
|
|
37
|
+
throw new Error(`Import map cannot reference '${path}' as it's outside of the base directory '${basePath}'`);
|
|
38
|
+
}
|
|
34
39
|
// We want to use POSIX paths for the import map regardless of the OS
|
|
35
40
|
// we're building in.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
let normalizedPath = relativePath.split(sep).join(posix.sep);
|
|
42
|
+
// If the original URL had a trailing slash, ensure the normalized path
|
|
43
|
+
// has one too.
|
|
44
|
+
if (normalizedPath !== '' && url.pathname.endsWith(posix.sep) && !normalizedPath.endsWith(posix.sep)) {
|
|
45
|
+
normalizedPath += posix.sep;
|
|
46
|
+
}
|
|
47
|
+
const newURL = new URL(normalizedPath, prefix);
|
|
48
|
+
newImports[specifier] = newURL.toString();
|
|
39
49
|
return;
|
|
40
50
|
}
|
|
41
51
|
newImports[specifier] = url.toString();
|
|
@@ -45,10 +55,10 @@ class ImportMap {
|
|
|
45
55
|
add(file) {
|
|
46
56
|
this.files.push(file);
|
|
47
57
|
}
|
|
48
|
-
getContents(
|
|
58
|
+
getContents(basePath, prefix) {
|
|
49
59
|
let imports = {};
|
|
50
60
|
this.files.forEach((file) => {
|
|
51
|
-
const importMap = ImportMap.resolve(file,
|
|
61
|
+
const importMap = ImportMap.resolve(file, basePath, prefix);
|
|
52
62
|
imports = { ...imports, ...importMap.imports };
|
|
53
63
|
});
|
|
54
64
|
// Internal imports must come last, because we need to guarantee that
|
|
@@ -57,20 +67,20 @@ class ImportMap {
|
|
|
57
67
|
const [specifier, url] = internalImport;
|
|
58
68
|
imports[specifier] = url;
|
|
59
69
|
});
|
|
60
|
-
|
|
70
|
+
return {
|
|
61
71
|
imports,
|
|
62
72
|
};
|
|
63
|
-
return JSON.stringify(contents);
|
|
64
73
|
}
|
|
65
74
|
toDataURL() {
|
|
66
|
-
const
|
|
75
|
+
const data = JSON.stringify(this.getContents());
|
|
76
|
+
const encodedImportMap = Buffer.from(data).toString('base64');
|
|
67
77
|
return `data:application/json;base64,${encodedImportMap}`;
|
|
68
78
|
}
|
|
69
79
|
async writeToFile(path) {
|
|
70
80
|
const distDirectory = dirname(path);
|
|
71
81
|
await fs.mkdir(distDirectory, { recursive: true });
|
|
72
|
-
const contents = this.getContents(
|
|
73
|
-
await fs.writeFile(path, contents);
|
|
82
|
+
const contents = this.getContents();
|
|
83
|
+
await fs.writeFile(path, JSON.stringify(contents));
|
|
74
84
|
}
|
|
75
85
|
}
|
|
76
86
|
const readFile = async (path) => {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
1
2
|
import { join } from 'path';
|
|
2
3
|
import { cwd } from 'process';
|
|
3
4
|
import { pathToFileURL } from 'url';
|
|
5
|
+
import tmp from 'tmp-promise';
|
|
4
6
|
import { test, expect } from 'vitest';
|
|
5
7
|
import { ImportMap } from './import_map.js';
|
|
6
8
|
test('Handles import maps with full URLs without specifying a base URL', () => {
|
|
@@ -18,12 +20,12 @@ test('Handles import maps with full URLs without specifying a base URL', () => {
|
|
|
18
20
|
},
|
|
19
21
|
};
|
|
20
22
|
const map = new ImportMap([inputFile1, inputFile2]);
|
|
21
|
-
const { imports } =
|
|
23
|
+
const { imports } = map.getContents();
|
|
22
24
|
expect(imports['netlify:edge']).toBe('https://edge.netlify.com/v1/index.ts');
|
|
23
25
|
expect(imports['alias:jamstack']).toBe('https://jamstack.org/');
|
|
24
26
|
expect(imports['alias:pets']).toBe('https://petsofnetlify.com/');
|
|
25
27
|
});
|
|
26
|
-
test('Resolves relative paths to absolute paths if a
|
|
28
|
+
test('Resolves relative paths to absolute paths if a base path is not provided', () => {
|
|
27
29
|
const basePath = join(cwd(), 'my-cool-site', 'import-map.json');
|
|
28
30
|
const inputFile1 = {
|
|
29
31
|
baseURL: pathToFileURL(basePath),
|
|
@@ -32,12 +34,12 @@ test('Resolves relative paths to absolute paths if a root path is not provided',
|
|
|
32
34
|
},
|
|
33
35
|
};
|
|
34
36
|
const map = new ImportMap([inputFile1]);
|
|
35
|
-
const { imports } =
|
|
37
|
+
const { imports } = map.getContents();
|
|
36
38
|
const expectedPath = join(cwd(), 'my-cool-site', 'heart', 'pets');
|
|
37
39
|
expect(imports['netlify:edge']).toBe('https://edge.netlify.com/v1/index.ts');
|
|
38
40
|
expect(imports['alias:pets']).toBe(`${pathToFileURL(expectedPath).toString()}/`);
|
|
39
41
|
});
|
|
40
|
-
test('Transforms relative paths so that they
|
|
42
|
+
test('Transforms relative paths so that they become relative to the base path', () => {
|
|
41
43
|
const basePath = join(cwd(), 'my-cool-site', 'import-map.json');
|
|
42
44
|
const inputFile1 = {
|
|
43
45
|
baseURL: pathToFileURL(basePath),
|
|
@@ -45,8 +47,43 @@ test('Transforms relative paths so that they use the root path as a base', () =>
|
|
|
45
47
|
'alias:pets': './heart/pets/',
|
|
46
48
|
},
|
|
47
49
|
};
|
|
50
|
+
// Without a prefix.
|
|
51
|
+
const map1 = new ImportMap([inputFile1]);
|
|
52
|
+
const { imports: imports1 } = map1.getContents(cwd());
|
|
53
|
+
expect(imports1['netlify:edge']).toBe('https://edge.netlify.com/v1/index.ts');
|
|
54
|
+
expect(imports1['alias:pets']).toBe('file:///my-cool-site/heart/pets/');
|
|
55
|
+
// With a prefix.
|
|
56
|
+
const map2 = new ImportMap([inputFile1]);
|
|
57
|
+
const { imports: imports2 } = map2.getContents(cwd(), 'file:///root/');
|
|
58
|
+
expect(imports2['netlify:edge']).toBe('https://edge.netlify.com/v1/index.ts');
|
|
59
|
+
expect(imports2['alias:pets']).toBe('file:///root/my-cool-site/heart/pets/');
|
|
60
|
+
});
|
|
61
|
+
test('Throws when an import map uses a relative path to reference a file outside of the base path', () => {
|
|
62
|
+
const basePath = join(cwd(), 'my-cool-site');
|
|
63
|
+
const inputFile1 = {
|
|
64
|
+
baseURL: pathToFileURL(join(basePath, 'import_map.json')),
|
|
65
|
+
imports: {
|
|
66
|
+
'alias:file': '../file.js',
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
const map = new ImportMap([inputFile1]);
|
|
70
|
+
expect(() => map.getContents(basePath)).toThrowError(`Import map cannot reference '${join(cwd(), 'file.js')}' as it's outside of the base directory '${basePath}'`);
|
|
71
|
+
});
|
|
72
|
+
test('Writes import map file to disk', async () => {
|
|
73
|
+
const file = await tmp.file();
|
|
74
|
+
const basePath = join(cwd(), 'my-cool-site', 'import-map.json');
|
|
75
|
+
const inputFile1 = {
|
|
76
|
+
baseURL: pathToFileURL(basePath),
|
|
77
|
+
imports: {
|
|
78
|
+
'alias:pets': './heart/pets/file.ts',
|
|
79
|
+
},
|
|
80
|
+
};
|
|
48
81
|
const map = new ImportMap([inputFile1]);
|
|
49
|
-
|
|
82
|
+
await map.writeToFile(file.path);
|
|
83
|
+
const createdFile = await fs.readFile(file.path, 'utf8');
|
|
84
|
+
const { imports } = JSON.parse(createdFile);
|
|
85
|
+
const expectedPath = join(cwd(), 'my-cool-site', 'heart', 'pets', 'file.ts');
|
|
86
|
+
await file.cleanup();
|
|
50
87
|
expect(imports['netlify:edge']).toBe('https://edge.netlify.com/v1/index.ts');
|
|
51
|
-
expect(imports['alias:pets']).toBe(
|
|
88
|
+
expect(imports['alias:pets']).toBe(pathToFileURL(expectedPath).toString());
|
|
52
89
|
});
|
package/dist/node/manifest.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ interface GenerateManifestOptions {
|
|
|
6
6
|
bundles?: Bundle[];
|
|
7
7
|
declarations?: Declaration[];
|
|
8
8
|
functions: EdgeFunction[];
|
|
9
|
-
|
|
9
|
+
importMap?: string;
|
|
10
10
|
layers?: Layer[];
|
|
11
11
|
}
|
|
12
12
|
interface Manifest {
|
|
@@ -31,14 +31,14 @@ interface Manifest {
|
|
|
31
31
|
pattern: string;
|
|
32
32
|
}[];
|
|
33
33
|
}
|
|
34
|
-
declare const generateManifest: ({ bundles, declarations, functions,
|
|
34
|
+
declare const generateManifest: ({ bundles, declarations, functions, importMap, layers, }: GenerateManifestOptions) => Manifest;
|
|
35
35
|
interface WriteManifestOptions {
|
|
36
36
|
bundles: Bundle[];
|
|
37
37
|
declarations: Declaration[];
|
|
38
38
|
distDirectory: string;
|
|
39
39
|
functions: EdgeFunction[];
|
|
40
|
-
|
|
40
|
+
importMap?: string;
|
|
41
41
|
layers?: Layer[];
|
|
42
42
|
}
|
|
43
|
-
declare const writeManifest: ({ bundles, declarations, distDirectory, functions,
|
|
43
|
+
declare const writeManifest: ({ bundles, declarations, distDirectory, functions, importMap, layers, }: WriteManifestOptions) => Promise<Manifest>;
|
|
44
44
|
export { generateManifest, Manifest, writeManifest };
|
package/dist/node/manifest.js
CHANGED
|
@@ -3,7 +3,7 @@ import { join } from 'path';
|
|
|
3
3
|
import globToRegExp from 'glob-to-regexp';
|
|
4
4
|
import { getPackageVersion } from './package_json.js';
|
|
5
5
|
import { nonNullable } from './utils/non_nullable.js';
|
|
6
|
-
const generateManifest = ({ bundles = [], declarations = [], functions,
|
|
6
|
+
const generateManifest = ({ bundles = [], declarations = [], functions, importMap, layers = [], }) => {
|
|
7
7
|
const preCacheRoutes = [];
|
|
8
8
|
const postCacheRoutes = [];
|
|
9
9
|
declarations.forEach((declaration) => {
|
|
@@ -35,7 +35,7 @@ const generateManifest = ({ bundles = [], declarations = [], functions, importMa
|
|
|
35
35
|
post_cache_routes: postCacheRoutes.filter(nonNullable),
|
|
36
36
|
bundler_version: getPackageVersion(),
|
|
37
37
|
layers,
|
|
38
|
-
import_map:
|
|
38
|
+
import_map: importMap,
|
|
39
39
|
};
|
|
40
40
|
return manifest;
|
|
41
41
|
};
|
|
@@ -52,8 +52,8 @@ const getRegularExpression = (declaration) => {
|
|
|
52
52
|
const normalizedSource = `^${regularExpression.source}\\/?$`;
|
|
53
53
|
return new RegExp(normalizedSource);
|
|
54
54
|
};
|
|
55
|
-
const writeManifest = async ({ bundles, declarations = [], distDirectory, functions,
|
|
56
|
-
const manifest = generateManifest({ bundles, declarations, functions,
|
|
55
|
+
const writeManifest = async ({ bundles, declarations = [], distDirectory, functions, importMap, layers, }) => {
|
|
56
|
+
const manifest = generateManifest({ bundles, declarations, functions, importMap, layers });
|
|
57
57
|
const manifestPath = join(distDirectory, 'manifest.json');
|
|
58
58
|
await fs.writeFile(manifestPath, JSON.stringify(manifest));
|
|
59
59
|
return manifest;
|
|
@@ -70,7 +70,7 @@ const serve = async ({ certificatePath, debug, distImportMapPath, inspectSetting
|
|
|
70
70
|
await ensureLatestTypes(deno, logger);
|
|
71
71
|
// Creating an ImportMap instance with any import maps supplied by the user,
|
|
72
72
|
// if any.
|
|
73
|
-
const importMap = new ImportMap(importMaps
|
|
73
|
+
const importMap = new ImportMap(importMaps);
|
|
74
74
|
const flags = ['--allow-all', '--unstable', `--import-map=${importMap.toDataURL()}`, '--no-config'];
|
|
75
75
|
if (certificatePath) {
|
|
76
76
|
flags.push(`--cert=${certificatePath}`);
|
package/dist/shared/consts.d.ts
CHANGED
package/dist/shared/consts.js
CHANGED
package/dist/shared/stage2.d.ts
CHANGED
package/dist/test/util.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { promises as fs } from 'fs';
|
|
2
2
|
import { join, resolve } from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
|
-
import cpy from 'cpy';
|
|
5
4
|
import tmp from 'tmp-promise';
|
|
6
5
|
import { getLogger } from '../node/logger.js';
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
const testLogger = getLogger(() => {
|
|
7
|
+
// no-op
|
|
8
|
+
});
|
|
9
9
|
const url = new URL(import.meta.url);
|
|
10
10
|
const dirname = fileURLToPath(url);
|
|
11
11
|
const fixturesDir = resolve(dirname, '..', 'fixtures');
|
|
@@ -13,10 +13,9 @@ const useFixture = async (fixtureName) => {
|
|
|
13
13
|
const tmpDir = await tmp.dir();
|
|
14
14
|
const cleanup = () => fs.rmdir(tmpDir.path, { recursive: true });
|
|
15
15
|
const fixtureDir = resolve(fixturesDir, fixtureName);
|
|
16
|
-
await cpy(`${fixtureDir}/**`, tmpDir.path);
|
|
17
16
|
const distPath = join(tmpDir.path, '.netlify', 'edge-functions-dist');
|
|
18
17
|
return {
|
|
19
|
-
basePath:
|
|
18
|
+
basePath: fixtureDir,
|
|
20
19
|
cleanup,
|
|
21
20
|
distPath,
|
|
22
21
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/edge-bundler",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.5.0",
|
|
4
4
|
"description": "Intelligently prepare Netlify Edge Functions for deployment",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/node/index.js",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"nock": "^13.2.4",
|
|
67
67
|
"tar": "^6.1.11",
|
|
68
68
|
"typescript": "^4.5.4",
|
|
69
|
-
"vite": "^
|
|
69
|
+
"vite": "^4.0.0",
|
|
70
70
|
"vitest": "^0.25.0"
|
|
71
71
|
},
|
|
72
72
|
"engines": {
|
package/shared/consts.ts
CHANGED
package/shared/stage2.ts
CHANGED