@netlify/edge-bundler 7.0.0 → 7.1.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/dist/node/bundler.test.js +25 -10
- package/dist/node/declaration.d.ts +2 -0
- package/dist/node/declaration.test.js +7 -0
- package/dist/node/import_map.js +1 -1
- package/dist/node/manifest.d.ts +13 -10
- package/dist/node/manifest.js +22 -7
- package/dist/node/manifest.test.js +17 -0
- package/dist/test/util.js +2 -3
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
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';
|
|
4
5
|
import { deleteAsync } from 'del';
|
|
5
6
|
import tmp from 'tmp-promise';
|
|
6
7
|
import { test, expect, vi } from 'vitest';
|
|
@@ -277,32 +278,46 @@ test('Loads declarations and import maps from the deploy configuration', async (
|
|
|
277
278
|
expect(generatedFiles.length).toBe(2);
|
|
278
279
|
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
279
280
|
const manifest = JSON.parse(manifestFile);
|
|
280
|
-
const { bundles } = manifest;
|
|
281
|
+
const { bundles, routes } = manifest;
|
|
281
282
|
expect(bundles.length).toBe(1);
|
|
282
283
|
expect(bundles[0].format).toBe('eszip2');
|
|
283
284
|
expect(generatedFiles.includes(bundles[0].asset)).toBe(true);
|
|
285
|
+
// respects excludedPath from deploy config
|
|
286
|
+
expect(routes[1].excluded_pattern).toEqual('^/func2/skip/?$');
|
|
284
287
|
await cleanup();
|
|
285
288
|
});
|
|
286
289
|
test("Ignores entries in `importMapPaths` that don't point to an existing import map file", async () => {
|
|
287
290
|
const systemLogger = vi.fn();
|
|
288
291
|
const { basePath, cleanup, distPath } = await useFixture('with_import_maps');
|
|
289
|
-
const sourceDirectory = join(basePath, 'functions');
|
|
290
|
-
|
|
291
|
-
const
|
|
292
|
+
const sourceDirectory = join(basePath, 'user-functions');
|
|
293
|
+
// Creating import map file
|
|
294
|
+
const importMap = await tmp.file();
|
|
295
|
+
const importMapContents = {
|
|
296
|
+
imports: {
|
|
297
|
+
helper: pathToFileURL(join(basePath, 'helper.ts')).toString(),
|
|
298
|
+
},
|
|
299
|
+
scopes: {
|
|
300
|
+
[pathToFileURL(join(sourceDirectory, 'func3')).toString()]: {
|
|
301
|
+
helper: pathToFileURL(join(basePath, 'helper2.ts')).toString(),
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
await fs.writeFile(importMap.path, JSON.stringify(importMapContents));
|
|
306
|
+
const nonExistingImportMapPath = join(distPath, 'some-file-that-does-not-exist.json');
|
|
307
|
+
const result = await bundle([sourceDirectory], distPath, [
|
|
292
308
|
{
|
|
293
309
|
function: 'func1',
|
|
294
310
|
path: '/func1',
|
|
295
311
|
},
|
|
296
|
-
]
|
|
297
|
-
const result = await bundle([sourceDirectory], distPath, declarations, {
|
|
312
|
+
], {
|
|
298
313
|
basePath,
|
|
299
|
-
|
|
300
|
-
importMapPaths: [importMapPath],
|
|
314
|
+
importMapPaths: [nonExistingImportMapPath, importMap.path],
|
|
301
315
|
systemLogger,
|
|
302
316
|
});
|
|
303
317
|
const generatedFiles = await fs.readdir(distPath);
|
|
304
|
-
expect(result.functions.length).toBe(
|
|
318
|
+
expect(result.functions.length).toBe(2);
|
|
305
319
|
expect(generatedFiles.length).toBe(2);
|
|
306
|
-
expect(systemLogger).toHaveBeenCalledWith(`Did not find an import map file at '${
|
|
320
|
+
expect(systemLogger).toHaveBeenCalledWith(`Did not find an import map file at '${nonExistingImportMapPath}'.`);
|
|
307
321
|
await cleanup();
|
|
322
|
+
await importMap.cleanup();
|
|
308
323
|
});
|
|
@@ -7,9 +7,11 @@ interface BaseDeclaration {
|
|
|
7
7
|
}
|
|
8
8
|
type DeclarationWithPath = BaseDeclaration & {
|
|
9
9
|
path: string;
|
|
10
|
+
excludedPath?: string;
|
|
10
11
|
};
|
|
11
12
|
type DeclarationWithPattern = BaseDeclaration & {
|
|
12
13
|
pattern: string;
|
|
14
|
+
excludedPattern?: string;
|
|
13
15
|
};
|
|
14
16
|
type Declaration = DeclarationWithPath | DeclarationWithPattern;
|
|
15
17
|
export declare const getDeclarationsFromConfig: (tomlDeclarations: Declaration[], functionsConfig: Record<string, FunctionConfig>, deployConfig: DeployConfig) => Declaration[];
|
|
@@ -92,3 +92,10 @@ test('In-source config works if path property is an empty array with cache value
|
|
|
92
92
|
const expectedDeclarations = [{ function: 'json', path: '/json-toml', cache: 'manual' }];
|
|
93
93
|
expect(getDeclarationsFromConfig(tomlConfig, funcConfig, deployConfig)).toEqual(expectedDeclarations);
|
|
94
94
|
});
|
|
95
|
+
test('netlify.toml-defined excludedPath are respected', () => {
|
|
96
|
+
const tomlConfig = [{ function: 'geolocation', path: '/geo/*', excludedPath: '/geo/exclude' }];
|
|
97
|
+
const funcConfig = {};
|
|
98
|
+
const expectedDeclarations = [{ function: 'geolocation', path: '/geo/*', excludedPath: '/geo/exclude' }];
|
|
99
|
+
const declarations = getDeclarationsFromConfig(tomlConfig, funcConfig, deployConfig);
|
|
100
|
+
expect(declarations).toEqual(expectedDeclarations);
|
|
101
|
+
});
|
package/dist/node/import_map.js
CHANGED
package/dist/node/manifest.d.ts
CHANGED
|
@@ -9,6 +9,12 @@ interface GenerateManifestOptions {
|
|
|
9
9
|
importMap?: string;
|
|
10
10
|
layers?: Layer[];
|
|
11
11
|
}
|
|
12
|
+
interface Route {
|
|
13
|
+
function: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
pattern: string;
|
|
16
|
+
excluded_pattern?: string;
|
|
17
|
+
}
|
|
12
18
|
interface Manifest {
|
|
13
19
|
bundler_version: string;
|
|
14
20
|
bundles: {
|
|
@@ -20,16 +26,13 @@ interface Manifest {
|
|
|
20
26
|
name: string;
|
|
21
27
|
flag: string;
|
|
22
28
|
}[];
|
|
23
|
-
routes:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
name?: string;
|
|
31
|
-
pattern: string;
|
|
32
|
-
}[];
|
|
29
|
+
routes: Route[];
|
|
30
|
+
post_cache_routes: Route[];
|
|
31
|
+
}
|
|
32
|
+
interface Route {
|
|
33
|
+
function: string;
|
|
34
|
+
name?: string;
|
|
35
|
+
pattern: string;
|
|
33
36
|
}
|
|
34
37
|
declare const generateManifest: ({ bundles, declarations, functions, importMap, layers, }: GenerateManifestOptions) => Manifest;
|
|
35
38
|
interface WriteManifestOptions {
|
package/dist/node/manifest.js
CHANGED
|
@@ -3,6 +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 serializePattern = (regex) => regex.source.replace(/\\\//g, '/');
|
|
6
7
|
const generateManifest = ({ bundles = [], declarations = [], functions, importMap, layers = [], }) => {
|
|
7
8
|
const preCacheRoutes = [];
|
|
8
9
|
const postCacheRoutes = [];
|
|
@@ -12,12 +13,15 @@ const generateManifest = ({ bundles = [], declarations = [], functions, importMa
|
|
|
12
13
|
return;
|
|
13
14
|
}
|
|
14
15
|
const pattern = getRegularExpression(declaration);
|
|
15
|
-
const serializablePattern = pattern.source.replace(/\\\//g, '/');
|
|
16
16
|
const route = {
|
|
17
17
|
function: func.name,
|
|
18
18
|
name: declaration.name,
|
|
19
|
-
pattern:
|
|
19
|
+
pattern: serializePattern(pattern),
|
|
20
20
|
};
|
|
21
|
+
const excludedPattern = getExcludedRegularExpression(declaration);
|
|
22
|
+
if (excludedPattern) {
|
|
23
|
+
route.excluded_pattern = serializePattern(excludedPattern);
|
|
24
|
+
}
|
|
21
25
|
if (declaration.cache === "manual" /* Cache.Manual */) {
|
|
22
26
|
postCacheRoutes.push(route);
|
|
23
27
|
}
|
|
@@ -39,19 +43,30 @@ const generateManifest = ({ bundles = [], declarations = [], functions, importMa
|
|
|
39
43
|
};
|
|
40
44
|
return manifest;
|
|
41
45
|
};
|
|
42
|
-
const
|
|
43
|
-
if ('pattern' in declaration) {
|
|
44
|
-
return new RegExp(declaration.pattern);
|
|
45
|
-
}
|
|
46
|
+
const pathToRegularExpression = (path) => {
|
|
46
47
|
// We use the global flag so that `globToRegExp` will not wrap the expression
|
|
47
48
|
// with `^` and `$`. We'll do that ourselves.
|
|
48
|
-
const regularExpression = globToRegExp(
|
|
49
|
+
const regularExpression = globToRegExp(path, { flags: 'g' });
|
|
49
50
|
// Wrapping the expression source with `^` and `$`. Also, adding an optional
|
|
50
51
|
// trailing slash, so that a declaration of `path: "/foo"` matches requests
|
|
51
52
|
// for both `/foo` and `/foo/`.
|
|
52
53
|
const normalizedSource = `^${regularExpression.source}\\/?$`;
|
|
53
54
|
return new RegExp(normalizedSource);
|
|
54
55
|
};
|
|
56
|
+
const getRegularExpression = (declaration) => {
|
|
57
|
+
if ('pattern' in declaration) {
|
|
58
|
+
return new RegExp(declaration.pattern);
|
|
59
|
+
}
|
|
60
|
+
return pathToRegularExpression(declaration.path);
|
|
61
|
+
};
|
|
62
|
+
const getExcludedRegularExpression = (declaration) => {
|
|
63
|
+
if ('pattern' in declaration && declaration.excludedPattern) {
|
|
64
|
+
return new RegExp(declaration.excludedPattern);
|
|
65
|
+
}
|
|
66
|
+
if ('path' in declaration && declaration.excludedPath) {
|
|
67
|
+
return pathToRegularExpression(declaration.excludedPath);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
55
70
|
const writeManifest = async ({ bundles, declarations = [], distDirectory, functions, importMap, layers, }) => {
|
|
56
71
|
const manifest = generateManifest({ bundles, declarations, functions, importMap, layers });
|
|
57
72
|
const manifestPath = join(distDirectory, 'manifest.json');
|
|
@@ -42,6 +42,23 @@ test('Generates a manifest with display names', () => {
|
|
|
42
42
|
expect(manifest.routes).toEqual(expectedRoutes);
|
|
43
43
|
expect(manifest.bundler_version).toBe(env.npm_package_version);
|
|
44
44
|
});
|
|
45
|
+
test('Generates a manifest with excluded paths and patterns', () => {
|
|
46
|
+
const functions = [
|
|
47
|
+
{ name: 'func-1', path: '/path/to/func-1.ts' },
|
|
48
|
+
{ name: 'func-2', path: '/path/to/func-2.ts' },
|
|
49
|
+
];
|
|
50
|
+
const declarations = [
|
|
51
|
+
{ function: 'func-1', name: 'Display Name', path: '/f1/*', excludedPath: '/f1/exclude' },
|
|
52
|
+
{ function: 'func-2', pattern: '^/f2/.*/?$', excludedPattern: '^/f2/exclude$' },
|
|
53
|
+
];
|
|
54
|
+
const manifest = generateManifest({ bundles: [], declarations, functions });
|
|
55
|
+
const expectedRoutes = [
|
|
56
|
+
{ function: 'func-1', name: 'Display Name', pattern: '^/f1/.*/?$', excluded_pattern: '^/f1/exclude/?$' },
|
|
57
|
+
{ function: 'func-2', pattern: '^/f2/.*/?$', excluded_pattern: '^/f2/exclude$' },
|
|
58
|
+
];
|
|
59
|
+
expect(manifest.routes).toEqual(expectedRoutes);
|
|
60
|
+
expect(manifest.bundler_version).toBe(env.npm_package_version);
|
|
61
|
+
});
|
|
45
62
|
test('Excludes functions for which there are function files but no matching config declarations', () => {
|
|
46
63
|
const bundle1 = {
|
|
47
64
|
extension: '.ext2',
|
package/dist/test/util.js
CHANGED
|
@@ -12,13 +12,12 @@ const url = new URL(import.meta.url);
|
|
|
12
12
|
const dirname = fileURLToPath(url);
|
|
13
13
|
const fixturesDir = resolve(dirname, '..', 'fixtures');
|
|
14
14
|
const useFixture = async (fixtureName) => {
|
|
15
|
-
const tmpDir = await tmp.dir();
|
|
16
|
-
const cleanup = () => fs.rmdir(tmpDir.path, { recursive: true });
|
|
15
|
+
const tmpDir = await tmp.dir({ unsafeCleanup: true });
|
|
17
16
|
const fixtureDir = resolve(fixturesDir, fixtureName);
|
|
18
17
|
const distPath = join(tmpDir.path, '.netlify', 'edge-functions-dist');
|
|
19
18
|
return {
|
|
20
19
|
basePath: fixtureDir,
|
|
21
|
-
cleanup,
|
|
20
|
+
cleanup: tmpDir.cleanup,
|
|
22
21
|
distPath,
|
|
23
22
|
};
|
|
24
23
|
};
|