@netlify/edge-bundler 5.2.0 → 5.3.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/lib/stage2.ts +2 -1
- package/dist/node/bundle.d.ts +1 -0
- package/dist/node/bundler.js +1 -0
- package/dist/node/bundler.test.js +81 -67
- package/dist/node/config.d.ts +1 -1
- package/dist/node/config.test.js +21 -19
- package/dist/node/declaration.js +26 -4
- package/dist/node/declaration.test.js +43 -6
- package/dist/node/formats/eszip.js +15 -7
- package/dist/node/import_map.d.ts +5 -2
- package/dist/node/import_map.js +32 -9
- package/dist/node/import_map.test.js +24 -5
- package/dist/node/manifest.d.ts +9 -6
- package/dist/node/manifest.js +4 -3
- package/dist/shared/consts.d.ts +1 -0
- package/dist/shared/consts.js +1 -0
- package/dist/test/util.d.ts +6 -1
- package/dist/test/util.js +17 -2
- package/package.json +3 -1
- package/shared/consts.ts +1 -0
package/deno/lib/stage2.ts
CHANGED
|
@@ -3,7 +3,8 @@ 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 {
|
|
6
|
+
import { virtualRoot } from '../../shared/consts.ts'
|
|
7
|
+
import { PUBLIC_SPECIFIER, STAGE2_SPECIFIER } from './consts.ts'
|
|
7
8
|
import { inlineModule, loadFromVirtualRoot, loadWithRetry } from './common.ts'
|
|
8
9
|
|
|
9
10
|
interface FunctionReference {
|
package/dist/node/bundle.d.ts
CHANGED
package/dist/node/bundler.js
CHANGED
|
@@ -4,62 +4,65 @@ import process from 'process';
|
|
|
4
4
|
import { deleteAsync } from 'del';
|
|
5
5
|
import tmp from 'tmp-promise';
|
|
6
6
|
import { test, expect } from 'vitest';
|
|
7
|
-
import {
|
|
7
|
+
import { useFixture } from '../test/util.js';
|
|
8
8
|
import { BundleError } from './bundle_error.js';
|
|
9
9
|
import { bundle } from './bundler.js';
|
|
10
10
|
import { isNodeError } from './utils/error.js';
|
|
11
11
|
test('Produces an ESZIP bundle', async () => {
|
|
12
|
-
const
|
|
13
|
-
const tmpDir = await tmp.dir();
|
|
12
|
+
const { basePath, cleanup, distPath } = await useFixture('with_import_maps');
|
|
14
13
|
const declarations = [
|
|
15
14
|
{
|
|
16
15
|
function: 'func1',
|
|
17
16
|
path: '/func1',
|
|
18
17
|
},
|
|
19
18
|
];
|
|
20
|
-
const
|
|
21
|
-
|
|
19
|
+
const sourceDirectory = join(basePath, 'functions');
|
|
20
|
+
const result = await bundle([sourceDirectory], distPath, declarations, {
|
|
21
|
+
basePath,
|
|
22
22
|
configPath: join(sourceDirectory, 'config.json'),
|
|
23
23
|
});
|
|
24
|
-
const generatedFiles = await fs.readdir(
|
|
24
|
+
const generatedFiles = await fs.readdir(distPath);
|
|
25
25
|
expect(result.functions.length).toBe(1);
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
// ESZIP, manifest and import map.
|
|
27
|
+
expect(generatedFiles.length).toBe(3);
|
|
28
|
+
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
28
29
|
const manifest = JSON.parse(manifestFile);
|
|
29
|
-
const { bundles } = manifest;
|
|
30
|
+
const { bundles, import_map: importMapURL } = manifest;
|
|
30
31
|
expect(bundles.length).toBe(1);
|
|
31
32
|
expect(bundles[0].format).toBe('eszip2');
|
|
32
33
|
expect(generatedFiles.includes(bundles[0].asset)).toBe(true);
|
|
33
|
-
|
|
34
|
+
expect(importMapURL).toBe('file:///root/.netlify/edge-functions-dist/import_map.json');
|
|
35
|
+
await cleanup();
|
|
34
36
|
});
|
|
35
37
|
test('Uses the vendored eszip module instead of fetching it from deno.land', async () => {
|
|
36
|
-
const
|
|
37
|
-
const tmpDir = await tmp.dir();
|
|
38
|
+
const { basePath, cleanup, distPath } = await useFixture('with_import_maps');
|
|
38
39
|
const declarations = [
|
|
39
40
|
{
|
|
40
41
|
function: 'func1',
|
|
41
42
|
path: '/func1',
|
|
42
43
|
},
|
|
43
44
|
];
|
|
44
|
-
const
|
|
45
|
-
|
|
45
|
+
const sourceDirectory = join(basePath, 'functions');
|
|
46
|
+
const result = await bundle([sourceDirectory], distPath, declarations, {
|
|
47
|
+
basePath,
|
|
46
48
|
configPath: join(sourceDirectory, 'config.json'),
|
|
47
49
|
});
|
|
48
|
-
const generatedFiles = await fs.readdir(
|
|
50
|
+
const generatedFiles = await fs.readdir(distPath);
|
|
49
51
|
expect(result.functions.length).toBe(1);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
// ESZIP, manifest and import map.
|
|
53
|
+
expect(generatedFiles.length).toBe(3);
|
|
54
|
+
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
52
55
|
const manifest = JSON.parse(manifestFile);
|
|
53
56
|
const { bundles } = manifest;
|
|
54
57
|
expect(bundles.length).toBe(1);
|
|
55
58
|
expect(bundles[0].format).toBe('eszip2');
|
|
56
59
|
expect(generatedFiles.includes(bundles[0].asset)).toBe(true);
|
|
57
|
-
await
|
|
60
|
+
await cleanup();
|
|
58
61
|
});
|
|
59
62
|
test('Adds a custom error property to user errors during bundling', async () => {
|
|
60
63
|
expect.assertions(2);
|
|
61
|
-
const
|
|
62
|
-
const
|
|
64
|
+
const { basePath, cleanup, distPath } = await useFixture('invalid_functions');
|
|
65
|
+
const sourceDirectory = join(basePath, 'functions');
|
|
63
66
|
const declarations = [
|
|
64
67
|
{
|
|
65
68
|
function: 'func1',
|
|
@@ -67,7 +70,7 @@ test('Adds a custom error property to user errors during bundling', async () =>
|
|
|
67
70
|
},
|
|
68
71
|
];
|
|
69
72
|
try {
|
|
70
|
-
await bundle([sourceDirectory],
|
|
73
|
+
await bundle([sourceDirectory], distPath, declarations, { basePath });
|
|
71
74
|
}
|
|
72
75
|
catch (error) {
|
|
73
76
|
expect(error).toBeInstanceOf(BundleError);
|
|
@@ -79,11 +82,14 @@ test('Adds a custom error property to user errors during bundling', async () =>
|
|
|
79
82
|
type: 'functionsBundling',
|
|
80
83
|
});
|
|
81
84
|
}
|
|
85
|
+
finally {
|
|
86
|
+
await cleanup();
|
|
87
|
+
}
|
|
82
88
|
});
|
|
83
89
|
test('Prints a nice error message when user tries importing NPM module', async () => {
|
|
84
90
|
expect.assertions(2);
|
|
85
|
-
const
|
|
86
|
-
const
|
|
91
|
+
const { basePath, cleanup, distPath } = await useFixture('imports_npm_module');
|
|
92
|
+
const sourceDirectory = join(basePath, 'functions');
|
|
87
93
|
const declarations = [
|
|
88
94
|
{
|
|
89
95
|
function: 'func1',
|
|
@@ -91,18 +97,21 @@ test('Prints a nice error message when user tries importing NPM module', async (
|
|
|
91
97
|
},
|
|
92
98
|
];
|
|
93
99
|
try {
|
|
94
|
-
await bundle([sourceDirectory],
|
|
100
|
+
await bundle([sourceDirectory], distPath, declarations, { basePath });
|
|
95
101
|
}
|
|
96
102
|
catch (error) {
|
|
97
103
|
expect(error).toBeInstanceOf(BundleError);
|
|
98
104
|
expect(error.message).toEqual(`It seems like you're trying to import an npm module. This is only supported in Deno via CDNs like esm.sh. Have you tried 'import mod from "https://esm.sh/p-retry"'?`);
|
|
99
105
|
}
|
|
106
|
+
finally {
|
|
107
|
+
await cleanup();
|
|
108
|
+
}
|
|
100
109
|
});
|
|
101
110
|
test('Does not add a custom error property to system errors during bundling', async () => {
|
|
102
111
|
expect.assertions(1);
|
|
103
112
|
try {
|
|
104
113
|
// @ts-expect-error Sending bad input to `bundle` to force a system error.
|
|
105
|
-
await bundle([123, 321],
|
|
114
|
+
await bundle([123, 321], '/some/directory', declarations);
|
|
106
115
|
}
|
|
107
116
|
catch (error) {
|
|
108
117
|
expect(error).not.toBeInstanceOf(BundleError);
|
|
@@ -110,8 +119,8 @@ test('Does not add a custom error property to system errors during bundling', as
|
|
|
110
119
|
});
|
|
111
120
|
test('Uses the cache directory as the `DENO_DIR` value if the `edge_functions_cache_deno_dir` feature flag is set', async () => {
|
|
112
121
|
expect.assertions(6);
|
|
113
|
-
const
|
|
114
|
-
const
|
|
122
|
+
const { basePath, cleanup, distPath } = await useFixture('with_import_maps');
|
|
123
|
+
const sourceDirectory = join(basePath, 'functions');
|
|
115
124
|
const cacheDir = await tmp.dir();
|
|
116
125
|
const declarations = [
|
|
117
126
|
{
|
|
@@ -120,15 +129,16 @@ test('Uses the cache directory as the `DENO_DIR` value if the `edge_functions_ca
|
|
|
120
129
|
},
|
|
121
130
|
];
|
|
122
131
|
const options = {
|
|
123
|
-
basePath
|
|
132
|
+
basePath,
|
|
124
133
|
cacheDirectory: cacheDir.path,
|
|
125
134
|
configPath: join(sourceDirectory, 'config.json'),
|
|
126
135
|
};
|
|
127
136
|
// Run #1, feature flag off: The directory should not be populated.
|
|
128
|
-
const result1 = await bundle([sourceDirectory],
|
|
129
|
-
const outFiles1 = await fs.readdir(
|
|
137
|
+
const result1 = await bundle([sourceDirectory], distPath, declarations, options);
|
|
138
|
+
const outFiles1 = await fs.readdir(distPath);
|
|
130
139
|
expect(result1.functions.length).toBe(1);
|
|
131
|
-
|
|
140
|
+
// ESZIP, manifest and import map.
|
|
141
|
+
expect(outFiles1.length).toBe(3);
|
|
132
142
|
try {
|
|
133
143
|
await fs.readdir(join(cacheDir.path, 'deno_dir'));
|
|
134
144
|
}
|
|
@@ -136,46 +146,48 @@ test('Uses the cache directory as the `DENO_DIR` value if the `edge_functions_ca
|
|
|
136
146
|
expect(error).toBeInstanceOf(Error);
|
|
137
147
|
}
|
|
138
148
|
// Run #2, feature flag on: The directory should be populated.
|
|
139
|
-
const result2 = await bundle([sourceDirectory],
|
|
149
|
+
const result2 = await bundle([sourceDirectory], distPath, declarations, {
|
|
140
150
|
...options,
|
|
141
151
|
featureFlags: {
|
|
142
152
|
edge_functions_cache_deno_dir: true,
|
|
143
153
|
},
|
|
144
154
|
});
|
|
145
|
-
const outFiles2 = await fs.readdir(
|
|
155
|
+
const outFiles2 = await fs.readdir(distPath);
|
|
146
156
|
expect(result2.functions.length).toBe(1);
|
|
147
|
-
|
|
157
|
+
// ESZIP, manifest and import map.
|
|
158
|
+
expect(outFiles2.length).toBe(3);
|
|
148
159
|
const denoDir2 = await fs.readdir(join(cacheDir.path, 'deno_dir'));
|
|
149
160
|
expect(denoDir2.includes('gen')).toBe(true);
|
|
150
|
-
await
|
|
161
|
+
await cleanup();
|
|
151
162
|
});
|
|
152
163
|
test('Supports import maps with relative paths', async () => {
|
|
153
|
-
const
|
|
154
|
-
const
|
|
164
|
+
const { basePath, cleanup, distPath } = await useFixture('with_import_maps');
|
|
165
|
+
const sourceDirectory = join(basePath, 'functions');
|
|
155
166
|
const declarations = [
|
|
156
167
|
{
|
|
157
168
|
function: 'func1',
|
|
158
169
|
path: '/func1',
|
|
159
170
|
},
|
|
160
171
|
];
|
|
161
|
-
const result = await bundle([sourceDirectory],
|
|
162
|
-
basePath
|
|
172
|
+
const result = await bundle([sourceDirectory], distPath, declarations, {
|
|
173
|
+
basePath,
|
|
163
174
|
configPath: join(sourceDirectory, 'config.json'),
|
|
164
175
|
});
|
|
165
|
-
const generatedFiles = await fs.readdir(
|
|
176
|
+
const generatedFiles = await fs.readdir(distPath);
|
|
166
177
|
expect(result.functions.length).toBe(1);
|
|
167
|
-
|
|
168
|
-
|
|
178
|
+
// ESZIP, manifest and import map.
|
|
179
|
+
expect(generatedFiles.length).toBe(3);
|
|
180
|
+
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
169
181
|
const manifest = JSON.parse(manifestFile);
|
|
170
182
|
const { bundles } = manifest;
|
|
171
183
|
expect(bundles.length).toBe(1);
|
|
172
184
|
expect(bundles[0].format).toBe('eszip2');
|
|
173
185
|
expect(generatedFiles.includes(bundles[0].asset)).toBe(true);
|
|
174
|
-
await
|
|
186
|
+
await cleanup();
|
|
175
187
|
});
|
|
176
188
|
test('Ignores any user-defined `deno.json` files', async () => {
|
|
177
|
-
const
|
|
178
|
-
const
|
|
189
|
+
const { basePath, cleanup, distPath } = await useFixture('with_import_maps');
|
|
190
|
+
const sourceDirectory = join(basePath, 'functions');
|
|
179
191
|
const declarations = [
|
|
180
192
|
{
|
|
181
193
|
function: 'func1',
|
|
@@ -209,15 +221,16 @@ test('Ignores any user-defined `deno.json` files', async () => {
|
|
|
209
221
|
}
|
|
210
222
|
}
|
|
211
223
|
await fs.writeFile(denoConfigPath, JSON.stringify(denoConfig));
|
|
212
|
-
expect(() => bundle([
|
|
213
|
-
basePath
|
|
214
|
-
configPath: join(
|
|
224
|
+
expect(() => bundle([sourceDirectory], distPath, declarations, {
|
|
225
|
+
basePath,
|
|
226
|
+
configPath: join(sourceDirectory, 'config.json'),
|
|
215
227
|
})).not.toThrow();
|
|
216
|
-
await
|
|
228
|
+
await cleanup();
|
|
229
|
+
await deleteAsync([denoConfigPath, importMapFile.path], { force: true });
|
|
217
230
|
});
|
|
218
231
|
test('Processes a function that imports a custom layer', async () => {
|
|
219
|
-
const
|
|
220
|
-
const
|
|
232
|
+
const { basePath, cleanup, distPath } = await useFixture('with_layers');
|
|
233
|
+
const sourceDirectory = join(basePath, 'functions');
|
|
221
234
|
const declarations = [
|
|
222
235
|
{
|
|
223
236
|
function: 'func1',
|
|
@@ -225,44 +238,45 @@ test('Processes a function that imports a custom layer', async () => {
|
|
|
225
238
|
},
|
|
226
239
|
];
|
|
227
240
|
const layer = { name: 'layer:test', flag: 'edge-functions-layer-test' };
|
|
228
|
-
const result = await bundle([sourceDirectory],
|
|
229
|
-
basePath
|
|
241
|
+
const result = await bundle([sourceDirectory], distPath, declarations, {
|
|
242
|
+
basePath,
|
|
230
243
|
configPath: join(sourceDirectory, 'config.json'),
|
|
231
244
|
});
|
|
232
|
-
const generatedFiles = await fs.readdir(
|
|
245
|
+
const generatedFiles = await fs.readdir(distPath);
|
|
233
246
|
expect(result.functions.length).toBe(1);
|
|
234
|
-
|
|
235
|
-
|
|
247
|
+
// ESZIP, manifest and import map.
|
|
248
|
+
expect(generatedFiles.length).toBe(3);
|
|
249
|
+
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
236
250
|
const manifest = JSON.parse(manifestFile);
|
|
237
251
|
const { bundles, layers } = manifest;
|
|
238
252
|
expect(bundles.length).toBe(1);
|
|
239
253
|
expect(bundles[0].format).toBe('eszip2');
|
|
240
254
|
expect(generatedFiles.includes(bundles[0].asset)).toBe(true);
|
|
241
255
|
expect(layers).toEqual([layer]);
|
|
242
|
-
await
|
|
256
|
+
await cleanup();
|
|
243
257
|
});
|
|
244
258
|
test('Loads declarations and import maps from the deploy configuration', async () => {
|
|
245
|
-
const
|
|
246
|
-
const tmpDir = await tmp.dir();
|
|
259
|
+
const { basePath, cleanup, distPath } = await useFixture('with_deploy_config');
|
|
247
260
|
const declarations = [
|
|
248
261
|
{
|
|
249
262
|
function: 'func1',
|
|
250
263
|
path: '/func1',
|
|
251
264
|
},
|
|
252
265
|
];
|
|
253
|
-
const directories = [join(
|
|
254
|
-
const result = await bundle(directories,
|
|
255
|
-
basePath
|
|
256
|
-
configPath: join(
|
|
266
|
+
const directories = [join(basePath, 'netlify', 'edge-functions'), join(basePath, '.netlify', 'edge-functions')];
|
|
267
|
+
const result = await bundle(directories, distPath, declarations, {
|
|
268
|
+
basePath,
|
|
269
|
+
configPath: join(basePath, '.netlify', 'edge-functions', 'config.json'),
|
|
257
270
|
});
|
|
258
|
-
const generatedFiles = await fs.readdir(
|
|
271
|
+
const generatedFiles = await fs.readdir(distPath);
|
|
259
272
|
expect(result.functions.length).toBe(2);
|
|
260
|
-
|
|
261
|
-
|
|
273
|
+
// ESZIP, manifest and import map.
|
|
274
|
+
expect(generatedFiles.length).toBe(3);
|
|
275
|
+
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
262
276
|
const manifest = JSON.parse(manifestFile);
|
|
263
277
|
const { bundles } = manifest;
|
|
264
278
|
expect(bundles.length).toBe(1);
|
|
265
279
|
expect(bundles[0].format).toBe('eszip2');
|
|
266
280
|
expect(generatedFiles.includes(bundles[0].asset)).toBe(true);
|
|
267
|
-
await
|
|
281
|
+
await cleanup();
|
|
268
282
|
});
|
package/dist/node/config.d.ts
CHANGED
|
@@ -8,6 +8,6 @@ export declare const enum Cache {
|
|
|
8
8
|
}
|
|
9
9
|
export interface FunctionConfig {
|
|
10
10
|
cache?: Cache;
|
|
11
|
-
path?: string;
|
|
11
|
+
path?: string | string[];
|
|
12
12
|
}
|
|
13
13
|
export declare const getFunctionConfig: (func: EdgeFunction, importMap: ImportMap, deno: DenoBridge, log: Logger) => Promise<FunctionConfig>;
|
package/dist/node/config.test.js
CHANGED
|
@@ -4,7 +4,7 @@ import { pathToFileURL } from 'url';
|
|
|
4
4
|
import { deleteAsync } from 'del';
|
|
5
5
|
import tmp from 'tmp-promise';
|
|
6
6
|
import { test, expect, vi } from 'vitest';
|
|
7
|
-
import { fixturesDir } from '../test/util.js';
|
|
7
|
+
import { fixturesDir, useFixture } from '../test/util.js';
|
|
8
8
|
import { DenoBridge } from './bridge.js';
|
|
9
9
|
import { bundle } from './bundler.js';
|
|
10
10
|
import { getFunctionConfig } from './config.js';
|
|
@@ -121,30 +121,31 @@ test('`getFunctionConfig` extracts configuration properties from function file',
|
|
|
121
121
|
await deleteAsync(tmpDir, { force: true });
|
|
122
122
|
});
|
|
123
123
|
test('Ignores function paths from the in-source `config` function if the feature flag is off', async () => {
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
const
|
|
124
|
+
const { basePath, cleanup, distPath } = await useFixture('with_config');
|
|
125
|
+
const userDirectory = resolve(basePath, 'netlify', 'edge-functions');
|
|
126
|
+
const internalDirectory = resolve(basePath, '.netlify', 'edge-functions');
|
|
127
127
|
const declarations = [];
|
|
128
|
-
const result = await bundle([internalDirectory, userDirectory],
|
|
129
|
-
basePath
|
|
128
|
+
const result = await bundle([internalDirectory, userDirectory], distPath, declarations, {
|
|
129
|
+
basePath,
|
|
130
130
|
configPath: join(internalDirectory, 'config.json'),
|
|
131
131
|
});
|
|
132
|
-
const generatedFiles = await fs.readdir(
|
|
132
|
+
const generatedFiles = await fs.readdir(distPath);
|
|
133
133
|
expect(result.functions.length).toBe(6);
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
// ESZIP, manifest and import map.
|
|
135
|
+
expect(generatedFiles.length).toBe(3);
|
|
136
|
+
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
136
137
|
const manifest = JSON.parse(manifestFile);
|
|
137
138
|
const { bundles, routes } = manifest;
|
|
138
139
|
expect(bundles.length).toBe(1);
|
|
139
140
|
expect(bundles[0].format).toBe('eszip2');
|
|
140
141
|
expect(generatedFiles.includes(bundles[0].asset)).toBe(true);
|
|
141
142
|
expect(routes.length).toBe(0);
|
|
142
|
-
await
|
|
143
|
+
await cleanup();
|
|
143
144
|
});
|
|
144
145
|
test('Loads function paths from the in-source `config` function', async () => {
|
|
145
|
-
const
|
|
146
|
-
const
|
|
147
|
-
const
|
|
146
|
+
const { basePath, cleanup, distPath } = await useFixture('with_config');
|
|
147
|
+
const userDirectory = resolve(basePath, 'netlify', 'edge-functions');
|
|
148
|
+
const internalDirectory = resolve(basePath, '.netlify', 'edge-functions');
|
|
148
149
|
const declarations = [
|
|
149
150
|
{
|
|
150
151
|
function: 'framework-func2',
|
|
@@ -155,17 +156,18 @@ test('Loads function paths from the in-source `config` function', async () => {
|
|
|
155
156
|
path: '/user-func2',
|
|
156
157
|
},
|
|
157
158
|
];
|
|
158
|
-
const result = await bundle([internalDirectory, userDirectory],
|
|
159
|
-
basePath
|
|
159
|
+
const result = await bundle([internalDirectory, userDirectory], distPath, declarations, {
|
|
160
|
+
basePath,
|
|
160
161
|
configPath: join(internalDirectory, 'config.json'),
|
|
161
162
|
featureFlags: {
|
|
162
163
|
edge_functions_config_export: true,
|
|
163
164
|
},
|
|
164
165
|
});
|
|
165
|
-
const generatedFiles = await fs.readdir(
|
|
166
|
+
const generatedFiles = await fs.readdir(distPath);
|
|
166
167
|
expect(result.functions.length).toBe(6);
|
|
167
|
-
|
|
168
|
-
|
|
168
|
+
// ESZIP, manifest and import map.
|
|
169
|
+
expect(generatedFiles.length).toBe(3);
|
|
170
|
+
const manifestFile = await fs.readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
169
171
|
const manifest = JSON.parse(manifestFile);
|
|
170
172
|
const { bundles, routes, post_cache_routes: postCacheRoutes } = manifest;
|
|
171
173
|
expect(bundles.length).toBe(1);
|
|
@@ -179,7 +181,7 @@ test('Loads function paths from the in-source `config` function', async () => {
|
|
|
179
181
|
expect(routes[4]).toEqual({ function: 'user-func3', pattern: '^/user-func3/?$' });
|
|
180
182
|
expect(postCacheRoutes.length).toBe(1);
|
|
181
183
|
expect(postCacheRoutes[0]).toEqual({ function: 'user-func4', pattern: '^/user-func4/?$' });
|
|
182
|
-
await
|
|
184
|
+
await cleanup();
|
|
183
185
|
});
|
|
184
186
|
test('Passes validation if default export exists and is a function', async () => {
|
|
185
187
|
const { path: tmpDir } = await tmp.dir();
|
package/dist/node/declaration.js
CHANGED
|
@@ -7,16 +7,38 @@ export const getDeclarationsFromConfig = (tomlDeclarations, functionsConfig, dep
|
|
|
7
7
|
// a function configuration object, we replace the path because that object
|
|
8
8
|
// takes precedence.
|
|
9
9
|
for (const declaration of [...tomlDeclarations, ...deployConfig.declarations]) {
|
|
10
|
-
const config =
|
|
10
|
+
const config = functionsConfig[declaration.function];
|
|
11
|
+
// If no config is found, add the declaration as is
|
|
12
|
+
if (!config) {
|
|
13
|
+
declarations.push(declaration);
|
|
14
|
+
// If we have a path specified as either a string or non-empty array
|
|
15
|
+
// create a declaration for each path
|
|
16
|
+
}
|
|
17
|
+
else if ((_a = config.path) === null || _a === void 0 ? void 0 : _a.length) {
|
|
18
|
+
const paths = Array.isArray(config.path) ? config.path : [config.path];
|
|
19
|
+
paths.forEach((path) => {
|
|
20
|
+
declarations.push({ ...declaration, ...config, path });
|
|
21
|
+
});
|
|
22
|
+
// With an in-source config without a path, add the config to the declaration
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
26
|
+
const { path, ...rest } = config;
|
|
27
|
+
declarations.push({ ...declaration, ...rest });
|
|
28
|
+
}
|
|
11
29
|
functionsVisited.add(declaration.function);
|
|
12
|
-
declarations.push({ ...declaration, ...config });
|
|
13
30
|
}
|
|
14
31
|
// Finally, we must create declarations for functions that are not declared
|
|
15
32
|
// in the TOML at all.
|
|
16
33
|
for (const name in functionsConfig) {
|
|
17
|
-
const {
|
|
34
|
+
const { ...config } = functionsConfig[name];
|
|
35
|
+
const { path } = functionsConfig[name];
|
|
36
|
+
// If we have path specified create a declaration for each path
|
|
18
37
|
if (!functionsVisited.has(name) && path) {
|
|
19
|
-
|
|
38
|
+
const paths = Array.isArray(path) ? path : [path];
|
|
39
|
+
paths.forEach((singlePath) => {
|
|
40
|
+
declarations.push({ ...config, function: name, path: singlePath });
|
|
41
|
+
});
|
|
20
42
|
}
|
|
21
43
|
}
|
|
22
44
|
return declarations;
|
|
@@ -5,29 +5,30 @@ const deployConfig = {
|
|
|
5
5
|
declarations: [],
|
|
6
6
|
layers: [],
|
|
7
7
|
};
|
|
8
|
-
test('In
|
|
8
|
+
test('In-source config takes precedence over netlify.toml config', () => {
|
|
9
9
|
const tomlConfig = [
|
|
10
10
|
{ function: 'geolocation', path: '/geo', cache: 'off' },
|
|
11
11
|
{ function: 'json', path: '/json', cache: 'manual' },
|
|
12
12
|
];
|
|
13
13
|
const funcConfig = {
|
|
14
|
-
geolocation: { path: '/geo-isc', cache: 'manual' },
|
|
14
|
+
geolocation: { path: ['/geo-isc', '/*'], cache: 'manual' },
|
|
15
15
|
json: { path: '/json', cache: 'off' },
|
|
16
16
|
};
|
|
17
17
|
const expectedDeclarations = [
|
|
18
18
|
{ function: 'geolocation', path: '/geo-isc', cache: 'manual' },
|
|
19
|
+
{ function: 'geolocation', path: '/*', cache: 'manual' },
|
|
19
20
|
{ function: 'json', path: '/json', cache: 'off' },
|
|
20
21
|
];
|
|
21
22
|
const declarations = getDeclarationsFromConfig(tomlConfig, funcConfig, deployConfig);
|
|
22
23
|
expect(declarations).toEqual(expectedDeclarations);
|
|
23
24
|
});
|
|
24
|
-
test("Declarations don't break if no in
|
|
25
|
+
test("Declarations don't break if no in-source config is provided", () => {
|
|
25
26
|
const tomlConfig = [
|
|
26
27
|
{ function: 'geolocation', path: '/geo', cache: 'off' },
|
|
27
28
|
{ function: 'json', path: '/json', cache: 'manual' },
|
|
28
29
|
];
|
|
29
30
|
const funcConfig = {
|
|
30
|
-
geolocation: { path: '/geo-isc', cache: 'manual' },
|
|
31
|
+
geolocation: { path: ['/geo-isc'], cache: 'manual' },
|
|
31
32
|
json: {},
|
|
32
33
|
};
|
|
33
34
|
const expectedDeclarations = [
|
|
@@ -37,10 +38,10 @@ test("Declarations don't break if no in source config is provided", () => {
|
|
|
37
38
|
const declarations = getDeclarationsFromConfig(tomlConfig, funcConfig, deployConfig);
|
|
38
39
|
expect(declarations).toEqual(expectedDeclarations);
|
|
39
40
|
});
|
|
40
|
-
test('In
|
|
41
|
+
test('In-source config works independent of the netlify.toml file if a path is defined and otherwise if no path is set', () => {
|
|
41
42
|
const tomlConfig = [{ function: 'geolocation', path: '/geo', cache: 'off' }];
|
|
42
43
|
const funcConfigWithPath = {
|
|
43
|
-
json: { path: '/json', cache: 'off' },
|
|
44
|
+
json: { path: ['/json', '/json-isc'], cache: 'off' },
|
|
44
45
|
};
|
|
45
46
|
const funcConfigWithoutPath = {
|
|
46
47
|
json: { cache: 'off' },
|
|
@@ -48,6 +49,7 @@ test('In source config works independent of the netlify.toml file if a path is d
|
|
|
48
49
|
const expectedDeclarationsWithISCPath = [
|
|
49
50
|
{ function: 'geolocation', path: '/geo', cache: 'off' },
|
|
50
51
|
{ function: 'json', path: '/json', cache: 'off' },
|
|
52
|
+
{ function: 'json', path: '/json-isc', cache: 'off' },
|
|
51
53
|
];
|
|
52
54
|
const expectedDeclarationsWithoutISCPath = [{ function: 'geolocation', path: '/geo', cache: 'off' }];
|
|
53
55
|
const declarationsWithISCPath = getDeclarationsFromConfig(tomlConfig, funcConfigWithPath, deployConfig);
|
|
@@ -55,3 +57,38 @@ test('In source config works independent of the netlify.toml file if a path is d
|
|
|
55
57
|
const declarationsWithoutISCPath = getDeclarationsFromConfig(tomlConfig, funcConfigWithoutPath, deployConfig);
|
|
56
58
|
expect(declarationsWithoutISCPath).toEqual(expectedDeclarationsWithoutISCPath);
|
|
57
59
|
});
|
|
60
|
+
test('In-source config works if only the cache config property is set', () => {
|
|
61
|
+
const tomlConfig = [{ function: 'geolocation', path: '/geo', cache: 'off' }];
|
|
62
|
+
const funcConfig = {
|
|
63
|
+
geolocation: { cache: 'manual' },
|
|
64
|
+
};
|
|
65
|
+
const expectedDeclarations = [{ function: 'geolocation', path: '/geo', cache: 'manual' }];
|
|
66
|
+
expect(getDeclarationsFromConfig(tomlConfig, funcConfig, deployConfig)).toEqual(expectedDeclarations);
|
|
67
|
+
});
|
|
68
|
+
test("In-source config path property works if it's not an array", () => {
|
|
69
|
+
const tomlConfig = [{ function: 'json', path: '/json-toml', cache: 'off' }];
|
|
70
|
+
const funcConfig = {
|
|
71
|
+
json: { path: '/json', cache: 'manual' },
|
|
72
|
+
};
|
|
73
|
+
const expectedDeclarations = [{ function: 'json', path: '/json', cache: 'manual' }];
|
|
74
|
+
expect(getDeclarationsFromConfig(tomlConfig, funcConfig, deployConfig)).toEqual(expectedDeclarations);
|
|
75
|
+
});
|
|
76
|
+
test("In-source config path property works if it's not an array and it's not present in toml or deploy config", () => {
|
|
77
|
+
const tomlConfig = [{ function: 'geolocation', path: '/geo', cache: 'off' }];
|
|
78
|
+
const funcConfig = {
|
|
79
|
+
json: { path: '/json-isc', cache: 'manual' },
|
|
80
|
+
};
|
|
81
|
+
const expectedDeclarations = [
|
|
82
|
+
{ function: 'geolocation', path: '/geo', cache: 'off' },
|
|
83
|
+
{ function: 'json', path: '/json-isc', cache: 'manual' },
|
|
84
|
+
];
|
|
85
|
+
expect(getDeclarationsFromConfig(tomlConfig, funcConfig, deployConfig)).toEqual(expectedDeclarations);
|
|
86
|
+
});
|
|
87
|
+
test('In-source config works if path property is an empty array with cache value specified', () => {
|
|
88
|
+
const tomlConfig = [{ function: 'json', path: '/json-toml', cache: 'off' }];
|
|
89
|
+
const funcConfig = {
|
|
90
|
+
json: { path: [], cache: 'manual' },
|
|
91
|
+
};
|
|
92
|
+
const expectedDeclarations = [{ function: 'json', path: '/json-toml', cache: 'manual' }];
|
|
93
|
+
expect(getDeclarationsFromConfig(tomlConfig, funcConfig, deployConfig)).toEqual(expectedDeclarations);
|
|
94
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { join } from 'path';
|
|
1
|
+
import { join, relative } from 'path';
|
|
2
|
+
import { virtualRoot } from '../../shared/consts.js';
|
|
2
3
|
import { BundleFormat } from '../bundle.js';
|
|
3
4
|
import { wrapBundleError } from '../bundle_error.js';
|
|
4
5
|
import { wrapNpmImportError } from '../npm_import_error.js';
|
|
@@ -8,20 +9,18 @@ const bundleESZIP = async ({ basePath, buildID, debug, deno, distDirectory, exte
|
|
|
8
9
|
const extension = '.eszip';
|
|
9
10
|
const destPath = join(distDirectory, `${buildID}${extension}`);
|
|
10
11
|
const { bundler, importMap: bundlerImportMap } = getESZIPPaths();
|
|
12
|
+
const importMapURL = await createUserImportMap(importMap, basePath, distDirectory);
|
|
11
13
|
const payload = {
|
|
12
14
|
basePath,
|
|
13
15
|
destPath,
|
|
14
16
|
externals,
|
|
15
17
|
functions,
|
|
16
|
-
importMapURL
|
|
18
|
+
importMapURL,
|
|
17
19
|
};
|
|
18
|
-
const flags = ['--allow-all', '--no-config'];
|
|
20
|
+
const flags = ['--allow-all', '--no-config', `--import-map=${bundlerImportMap}`];
|
|
19
21
|
if (!debug) {
|
|
20
22
|
flags.push('--quiet');
|
|
21
23
|
}
|
|
22
|
-
// To actually vendor the eszip module, we need to supply the import map that
|
|
23
|
-
// redirects `https://deno.land/` URLs to the local files.
|
|
24
|
-
flags.push(`--import-map=${bundlerImportMap}`);
|
|
25
24
|
try {
|
|
26
25
|
await deno.run(['run', ...flags, bundler, JSON.stringify(payload)], { pipeOutput: true });
|
|
27
26
|
}
|
|
@@ -29,7 +28,16 @@ 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 };
|
|
31
|
+
return { extension, format: BundleFormat.ESZIP2, hash, importMapURL };
|
|
32
|
+
};
|
|
33
|
+
// Takes an import map, writes it to a file on disk, and gets its URL relative
|
|
34
|
+
// to the ESZIP root (i.e. using the virtual root prefix).
|
|
35
|
+
const createUserImportMap = async (importMap, basePath, distDirectory) => {
|
|
36
|
+
const destPath = join(distDirectory, 'import_map.json');
|
|
37
|
+
await importMap.writeToFile(destPath);
|
|
38
|
+
const relativePath = relative(basePath, destPath);
|
|
39
|
+
const importMapURL = new URL(relativePath, virtualRoot);
|
|
40
|
+
return importMapURL.toString();
|
|
33
41
|
};
|
|
34
42
|
const getESZIPPaths = () => {
|
|
35
43
|
const denoPath = join(getPackagePath(), 'deno');
|
|
@@ -6,9 +6,12 @@ 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, rootPath?: string): {
|
|
10
|
+
imports: Record<string, string>;
|
|
11
|
+
scopes?: import("@import-maps/resolve/types/src/types").ParsedScopesMap | undefined;
|
|
12
|
+
};
|
|
10
13
|
add(file: ImportMapFile): void;
|
|
11
|
-
getContents(): string;
|
|
14
|
+
getContents(rootPath?: string): string;
|
|
12
15
|
toDataURL(): string;
|
|
13
16
|
writeToFile(path: string): Promise<void>;
|
|
14
17
|
}
|
package/dist/node/import_map.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Buffer } from 'buffer';
|
|
2
2
|
import { promises as fs } from 'fs';
|
|
3
|
-
import { dirname } from 'path';
|
|
4
|
-
import { pathToFileURL } from 'url';
|
|
3
|
+
import { dirname, isAbsolute, posix, relative, sep } from 'path';
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
5
5
|
import { parse } from '@import-maps/resolve';
|
|
6
6
|
const INTERNAL_IMPORTS = {
|
|
7
|
-
'netlify:edge':
|
|
7
|
+
'netlify:edge': 'https://edge.netlify.com/v1/index.ts',
|
|
8
8
|
};
|
|
9
9
|
// ImportMap can take several import map files and merge them into a final
|
|
10
10
|
// import map object, also adding the internal imports in the right order.
|
|
@@ -15,18 +15,40 @@ class ImportMap {
|
|
|
15
15
|
this.add(file);
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
// Transforms an import map by making any relative paths use a different path
|
|
19
|
+
// as a base.
|
|
20
|
+
static resolve(importMapFile, rootPath) {
|
|
19
21
|
const { baseURL, ...importMap } = importMapFile;
|
|
20
22
|
const parsedImportMap = parse(importMap, baseURL);
|
|
21
|
-
|
|
23
|
+
const { imports = {} } = parsedImportMap;
|
|
24
|
+
const newImports = {};
|
|
25
|
+
Object.keys(imports).forEach((specifier) => {
|
|
26
|
+
const url = imports[specifier];
|
|
27
|
+
// If there's no URL, don't even add the specifier to the final imports.
|
|
28
|
+
if (url === null) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// If this is a file URL, we might want to transform it to use another
|
|
32
|
+
// root path, as long as that root path is defined.
|
|
33
|
+
if (url.protocol === 'file:' && rootPath !== undefined) {
|
|
34
|
+
// We want to use POSIX paths for the import map regardless of the OS
|
|
35
|
+
// we're building in.
|
|
36
|
+
const path = relative(rootPath, fileURLToPath(url)).split(sep).join(posix.sep);
|
|
37
|
+
const value = isAbsolute(path) ? path : `.${posix.sep}${path}`;
|
|
38
|
+
newImports[specifier] = value;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
newImports[specifier] = url.toString();
|
|
42
|
+
});
|
|
43
|
+
return { ...parsedImportMap, imports: newImports };
|
|
22
44
|
}
|
|
23
45
|
add(file) {
|
|
24
46
|
this.files.push(file);
|
|
25
47
|
}
|
|
26
|
-
getContents() {
|
|
48
|
+
getContents(rootPath) {
|
|
27
49
|
let imports = {};
|
|
28
50
|
this.files.forEach((file) => {
|
|
29
|
-
const importMap = ImportMap.resolve(file);
|
|
51
|
+
const importMap = ImportMap.resolve(file, rootPath);
|
|
30
52
|
imports = { ...imports, ...importMap.imports };
|
|
31
53
|
});
|
|
32
54
|
// Internal imports must come last, because we need to guarantee that
|
|
@@ -45,8 +67,9 @@ class ImportMap {
|
|
|
45
67
|
return `data:application/json;base64,${encodedImportMap}`;
|
|
46
68
|
}
|
|
47
69
|
async writeToFile(path) {
|
|
48
|
-
|
|
49
|
-
|
|
70
|
+
const distDirectory = dirname(path);
|
|
71
|
+
await fs.mkdir(distDirectory, { recursive: true });
|
|
72
|
+
const contents = this.getContents(distDirectory);
|
|
50
73
|
await fs.writeFile(path, contents);
|
|
51
74
|
}
|
|
52
75
|
}
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
import { join } from 'path';
|
|
2
|
+
import { cwd } from 'process';
|
|
3
|
+
import { pathToFileURL } from 'url';
|
|
1
4
|
import { test, expect } from 'vitest';
|
|
2
5
|
import { ImportMap } from './import_map.js';
|
|
3
6
|
test('Handles import maps with full URLs without specifying a base URL', () => {
|
|
7
|
+
const basePath = join(cwd(), 'my-cool-site', 'import-map.json');
|
|
4
8
|
const inputFile1 = {
|
|
5
|
-
baseURL:
|
|
9
|
+
baseURL: pathToFileURL(basePath),
|
|
6
10
|
imports: {
|
|
7
11
|
'alias:jamstack': 'https://jamstack.org',
|
|
8
12
|
},
|
|
9
13
|
};
|
|
10
14
|
const inputFile2 = {
|
|
11
|
-
baseURL:
|
|
15
|
+
baseURL: pathToFileURL(basePath),
|
|
12
16
|
imports: {
|
|
13
17
|
'alias:pets': 'https://petsofnetlify.com/',
|
|
14
18
|
},
|
|
@@ -19,15 +23,30 @@ test('Handles import maps with full URLs without specifying a base URL', () => {
|
|
|
19
23
|
expect(imports['alias:jamstack']).toBe('https://jamstack.org/');
|
|
20
24
|
expect(imports['alias:pets']).toBe('https://petsofnetlify.com/');
|
|
21
25
|
});
|
|
22
|
-
test('
|
|
26
|
+
test('Resolves relative paths to absolute paths if a root path is not provided', () => {
|
|
27
|
+
const basePath = join(cwd(), 'my-cool-site', 'import-map.json');
|
|
23
28
|
const inputFile1 = {
|
|
24
|
-
baseURL:
|
|
29
|
+
baseURL: pathToFileURL(basePath),
|
|
25
30
|
imports: {
|
|
26
31
|
'alias:pets': './heart/pets/',
|
|
27
32
|
},
|
|
28
33
|
};
|
|
29
34
|
const map = new ImportMap([inputFile1]);
|
|
30
35
|
const { imports } = JSON.parse(map.getContents());
|
|
36
|
+
const expectedPath = join(cwd(), 'my-cool-site', 'heart', 'pets');
|
|
31
37
|
expect(imports['netlify:edge']).toBe('https://edge.netlify.com/v1/index.ts');
|
|
32
|
-
expect(imports['alias:pets']).toBe(
|
|
38
|
+
expect(imports['alias:pets']).toBe(`${pathToFileURL(expectedPath).toString()}/`);
|
|
39
|
+
});
|
|
40
|
+
test('Transforms relative paths so that they use the root path as a base', () => {
|
|
41
|
+
const basePath = join(cwd(), 'my-cool-site', 'import-map.json');
|
|
42
|
+
const inputFile1 = {
|
|
43
|
+
baseURL: pathToFileURL(basePath),
|
|
44
|
+
imports: {
|
|
45
|
+
'alias:pets': './heart/pets/',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
const map = new ImportMap([inputFile1]);
|
|
49
|
+
const { imports } = JSON.parse(map.getContents(cwd()));
|
|
50
|
+
expect(imports['netlify:edge']).toBe('https://edge.netlify.com/v1/index.ts');
|
|
51
|
+
expect(imports['alias:pets']).toBe('./my-cool-site/heart/pets');
|
|
33
52
|
});
|
package/dist/node/manifest.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ interface GenerateManifestOptions {
|
|
|
6
6
|
bundles?: Bundle[];
|
|
7
7
|
declarations?: Declaration[];
|
|
8
8
|
functions: EdgeFunction[];
|
|
9
|
+
importMapURL?: string;
|
|
9
10
|
layers?: Layer[];
|
|
10
11
|
}
|
|
11
12
|
interface Manifest {
|
|
@@ -14,6 +15,11 @@ interface Manifest {
|
|
|
14
15
|
asset: string;
|
|
15
16
|
format: string;
|
|
16
17
|
}[];
|
|
18
|
+
import_map?: string;
|
|
19
|
+
layers: {
|
|
20
|
+
name: string;
|
|
21
|
+
flag: string;
|
|
22
|
+
}[];
|
|
17
23
|
routes: {
|
|
18
24
|
function: string;
|
|
19
25
|
name?: string;
|
|
@@ -24,18 +30,15 @@ interface Manifest {
|
|
|
24
30
|
name?: string;
|
|
25
31
|
pattern: string;
|
|
26
32
|
}[];
|
|
27
|
-
layers: {
|
|
28
|
-
name: string;
|
|
29
|
-
flag: string;
|
|
30
|
-
}[];
|
|
31
33
|
}
|
|
32
|
-
declare const generateManifest: ({ bundles, declarations, functions, layers }: GenerateManifestOptions) => Manifest;
|
|
34
|
+
declare const generateManifest: ({ bundles, declarations, functions, importMapURL, layers, }: GenerateManifestOptions) => Manifest;
|
|
33
35
|
interface WriteManifestOptions {
|
|
34
36
|
bundles: Bundle[];
|
|
35
37
|
declarations: Declaration[];
|
|
36
38
|
distDirectory: string;
|
|
37
39
|
functions: EdgeFunction[];
|
|
40
|
+
importMapURL?: string;
|
|
38
41
|
layers?: Layer[];
|
|
39
42
|
}
|
|
40
|
-
declare const writeManifest: ({ bundles, declarations, distDirectory, functions, layers, }: WriteManifestOptions) => Promise<Manifest>;
|
|
43
|
+
declare const writeManifest: ({ bundles, declarations, distDirectory, functions, importMapURL, layers, }: WriteManifestOptions) => Promise<Manifest>;
|
|
41
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, layers = [] }) => {
|
|
6
|
+
const generateManifest = ({ bundles = [], declarations = [], functions, importMapURL, layers = [], }) => {
|
|
7
7
|
const preCacheRoutes = [];
|
|
8
8
|
const postCacheRoutes = [];
|
|
9
9
|
declarations.forEach((declaration) => {
|
|
@@ -35,6 +35,7 @@ const generateManifest = ({ bundles = [], declarations = [], functions, layers =
|
|
|
35
35
|
post_cache_routes: postCacheRoutes.filter(nonNullable),
|
|
36
36
|
bundler_version: getPackageVersion(),
|
|
37
37
|
layers,
|
|
38
|
+
import_map: importMapURL,
|
|
38
39
|
};
|
|
39
40
|
return manifest;
|
|
40
41
|
};
|
|
@@ -51,8 +52,8 @@ const getRegularExpression = (declaration) => {
|
|
|
51
52
|
const normalizedSource = `^${regularExpression.source}\\/?$`;
|
|
52
53
|
return new RegExp(normalizedSource);
|
|
53
54
|
};
|
|
54
|
-
const writeManifest = async ({ bundles, declarations = [], distDirectory, functions, layers, }) => {
|
|
55
|
-
const manifest = generateManifest({ bundles, declarations, functions, layers });
|
|
55
|
+
const writeManifest = async ({ bundles, declarations = [], distDirectory, functions, importMapURL, layers, }) => {
|
|
56
|
+
const manifest = generateManifest({ bundles, declarations, functions, importMapURL, layers });
|
|
56
57
|
const manifestPath = join(distDirectory, 'manifest.json');
|
|
57
58
|
await fs.writeFile(manifestPath, JSON.stringify(manifest));
|
|
58
59
|
return manifest;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const virtualRoot = "file:///root/";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const virtualRoot = 'file:///root/';
|
package/dist/test/util.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
declare const testLogger: import("../node/logger.js").Logger;
|
|
2
2
|
declare const fixturesDir: string;
|
|
3
|
-
|
|
3
|
+
declare const useFixture: (fixtureName: string) => Promise<{
|
|
4
|
+
basePath: string;
|
|
5
|
+
cleanup: () => Promise<void>;
|
|
6
|
+
distPath: string;
|
|
7
|
+
}>;
|
|
8
|
+
export { fixturesDir, testLogger, useFixture };
|
package/dist/test/util.js
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { join, resolve } from 'path';
|
|
2
3
|
import { fileURLToPath } from 'url';
|
|
4
|
+
import cpy from 'cpy';
|
|
5
|
+
import tmp from 'tmp-promise';
|
|
3
6
|
import { getLogger } from '../node/logger.js';
|
|
4
7
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
5
8
|
const testLogger = getLogger(() => { });
|
|
6
9
|
const url = new URL(import.meta.url);
|
|
7
10
|
const dirname = fileURLToPath(url);
|
|
8
11
|
const fixturesDir = resolve(dirname, '..', 'fixtures');
|
|
9
|
-
|
|
12
|
+
const useFixture = async (fixtureName) => {
|
|
13
|
+
const tmpDir = await tmp.dir();
|
|
14
|
+
const cleanup = () => fs.rmdir(tmpDir.path, { recursive: true });
|
|
15
|
+
const fixtureDir = resolve(fixturesDir, fixtureName);
|
|
16
|
+
await cpy(`${fixtureDir}/**`, tmpDir.path);
|
|
17
|
+
const distPath = join(tmpDir.path, '.netlify', 'edge-functions-dist');
|
|
18
|
+
return {
|
|
19
|
+
basePath: tmpDir.path,
|
|
20
|
+
cleanup,
|
|
21
|
+
distPath,
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export { fixturesDir, testLogger, useFixture };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/edge-bundler",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"description": "Intelligently prepare Netlify Edge Functions for deployment",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/node/index.js",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"test:dev": "run-s test:dev:*",
|
|
30
30
|
"test:ci": "run-s test:ci:*",
|
|
31
31
|
"test:dev:vitest": "cross-env FORCE_COLOR=0 vitest run",
|
|
32
|
+
"test:dev:vitest:watch": "cross-env FORCE_COLOR=0 vitest watch",
|
|
32
33
|
"test:dev:deno": "deno test --allow-all deno",
|
|
33
34
|
"test:ci:vitest": "cross-env FORCE_COLOR=0 vitest run",
|
|
34
35
|
"test:ci:deno": "deno test --allow-all deno",
|
|
@@ -59,6 +60,7 @@
|
|
|
59
60
|
"@types/uuid": "^8.3.4",
|
|
60
61
|
"@vitest/coverage-c8": "^0.25.0",
|
|
61
62
|
"archiver": "^5.3.1",
|
|
63
|
+
"cpy": "^9.0.1",
|
|
62
64
|
"cross-env": "^7.0.3",
|
|
63
65
|
"husky": "^8.0.0",
|
|
64
66
|
"nock": "^13.2.4",
|
package/shared/consts.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const virtualRoot = 'file:///root/'
|