@netlify/edge-bundler 4.4.3 → 5.0.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/consts.ts +0 -1
- package/deno/lib/stage2.ts +5 -5
- package/dist/node/bundler.d.ts +3 -7
- package/dist/node/bundler.js +19 -33
- package/dist/node/bundler.test.js +38 -101
- package/dist/node/config.test.js +2 -6
- package/dist/node/declaration.d.ts +2 -1
- package/dist/node/declaration.js +6 -6
- package/dist/node/declaration.test.js +9 -4
- package/dist/node/deploy_config.d.ts +10 -0
- package/dist/node/deploy_config.js +45 -0
- package/dist/node/deploy_config.test.d.ts +1 -0
- package/dist/node/deploy_config.test.js +50 -0
- package/dist/node/feature_flags.js +0 -1
- package/dist/node/formats/eszip.d.ts +2 -1
- package/dist/node/formats/eszip.js +2 -1
- package/dist/node/formats/javascript.d.ts +2 -15
- package/dist/node/formats/javascript.js +3 -44
- package/dist/node/import_map.d.ts +4 -2
- package/dist/node/import_map.js +38 -11
- package/dist/node/server/server.js +1 -2
- package/dist/node/utils/error.d.ts +2 -0
- package/dist/node/utils/error.js +2 -0
- package/dist/shared/stage2.d.ts +1 -0
- package/package.json +1 -1
- package/shared/stage2.ts +1 -0
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, functions, importMapURL } = JSON.parse(payload)
|
|
4
|
+
const { basePath, destPath, externals, functions, importMapURL } = JSON.parse(payload)
|
|
5
5
|
|
|
6
|
-
await writeStage2({ basePath, destPath, functions, importMapURL })
|
|
6
|
+
await writeStage2({ basePath, destPath, externals, functions, importMapURL })
|
package/deno/lib/consts.ts
CHANGED
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 {
|
|
6
|
+
import { PUBLIC_SPECIFIER, STAGE2_SPECIFIER, virtualRoot } from './consts.ts'
|
|
7
7
|
import { inlineModule, loadFromVirtualRoot, loadWithRetry } from './common.ts'
|
|
8
8
|
|
|
9
9
|
interface FunctionReference {
|
|
@@ -62,7 +62,7 @@ const getVirtualPath = (basePath: string, filePath: string) => {
|
|
|
62
62
|
return url
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
const stage2Loader = (basePath: string, functions: InputFunction[]) => {
|
|
65
|
+
const stage2Loader = (basePath: string, functions: InputFunction[], externals: Set<string>) => {
|
|
66
66
|
return async (specifier: string): Promise<LoadResponse | undefined> => {
|
|
67
67
|
if (specifier === STAGE2_SPECIFIER) {
|
|
68
68
|
const stage2Entry = getStage2Entry(basePath, functions)
|
|
@@ -70,7 +70,7 @@ const stage2Loader = (basePath: string, functions: InputFunction[]) => {
|
|
|
70
70
|
return inlineModule(specifier, stage2Entry)
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
if (specifier === PUBLIC_SPECIFIER ||
|
|
73
|
+
if (specifier === PUBLIC_SPECIFIER || externals.has(specifier)) {
|
|
74
74
|
return {
|
|
75
75
|
kind: 'external',
|
|
76
76
|
specifier,
|
|
@@ -85,8 +85,8 @@ const stage2Loader = (basePath: string, functions: InputFunction[]) => {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
const writeStage2 = async ({ basePath, destPath, functions, importMapURL }: WriteStage2Options) => {
|
|
89
|
-
const loader = stage2Loader(basePath, functions)
|
|
88
|
+
const writeStage2 = async ({ basePath, destPath, externals, functions, importMapURL }: WriteStage2Options) => {
|
|
89
|
+
const loader = stage2Loader(basePath, functions, new Set(externals))
|
|
90
90
|
const bytes = await build([STAGE2_SPECIFIER], loader, importMapURL)
|
|
91
91
|
const directory = path.dirname(destPath)
|
|
92
92
|
|
package/dist/node/bundler.d.ts
CHANGED
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
import { OnAfterDownloadHook, OnBeforeDownloadHook } from './bridge.js';
|
|
2
2
|
import { Declaration } from './declaration.js';
|
|
3
|
-
import { EdgeFunction } from './edge_function.js';
|
|
4
3
|
import { FeatureFlags } from './feature_flags.js';
|
|
5
|
-
import { ImportMapFile } from './import_map.js';
|
|
6
|
-
import { Layer } from './layer.js';
|
|
7
4
|
import { LogFunction } from './logger.js';
|
|
8
5
|
interface BundleOptions {
|
|
9
6
|
basePath?: string;
|
|
10
7
|
cacheDirectory?: string;
|
|
8
|
+
configPath?: string;
|
|
11
9
|
debug?: boolean;
|
|
12
10
|
distImportMapPath?: string;
|
|
13
11
|
featureFlags?: FeatureFlags;
|
|
14
|
-
importMaps?: ImportMapFile[];
|
|
15
|
-
layers?: Layer[];
|
|
16
12
|
onAfterDownload?: OnAfterDownloadHook;
|
|
17
13
|
onBeforeDownload?: OnBeforeDownloadHook;
|
|
18
14
|
systemLogger?: LogFunction;
|
|
19
15
|
}
|
|
20
|
-
declare const bundle: (sourceDirectories: string[], distDirectory: string, tomlDeclarations?: Declaration[], { basePath: inputBasePath, cacheDirectory, debug, distImportMapPath, featureFlags: inputFeatureFlags,
|
|
21
|
-
functions: EdgeFunction[];
|
|
16
|
+
declare const bundle: (sourceDirectories: string[], distDirectory: string, tomlDeclarations?: Declaration[], { basePath: inputBasePath, cacheDirectory, configPath, debug, distImportMapPath, featureFlags: inputFeatureFlags, onAfterDownload, onBeforeDownload, systemLogger, }?: BundleOptions) => Promise<{
|
|
17
|
+
functions: import("./edge_function.js").EdgeFunction[];
|
|
22
18
|
manifest: import("./manifest.js").Manifest;
|
|
23
19
|
}>;
|
|
24
20
|
export { bundle };
|
package/dist/node/bundler.js
CHANGED
|
@@ -5,37 +5,15 @@ import { v4 as uuidv4 } from 'uuid';
|
|
|
5
5
|
import { DenoBridge } from './bridge.js';
|
|
6
6
|
import { getFunctionConfig } from './config.js';
|
|
7
7
|
import { getDeclarationsFromConfig } from './declaration.js';
|
|
8
|
+
import { load as loadDeployConfig } from './deploy_config.js';
|
|
8
9
|
import { getFlags } from './feature_flags.js';
|
|
9
10
|
import { findFunctions } from './finder.js';
|
|
10
11
|
import { bundle as bundleESZIP } from './formats/eszip.js';
|
|
11
|
-
import { bundle as bundleJS } from './formats/javascript.js';
|
|
12
12
|
import { ImportMap } from './import_map.js';
|
|
13
13
|
import { getLogger } from './logger.js';
|
|
14
14
|
import { writeManifest } from './manifest.js';
|
|
15
15
|
import { ensureLatestTypes } from './types.js';
|
|
16
|
-
const
|
|
17
|
-
if (featureFlags.edge_functions_produce_eszip) {
|
|
18
|
-
return bundleESZIP({
|
|
19
|
-
basePath,
|
|
20
|
-
buildID,
|
|
21
|
-
debug,
|
|
22
|
-
deno,
|
|
23
|
-
distDirectory,
|
|
24
|
-
featureFlags,
|
|
25
|
-
functions,
|
|
26
|
-
importMap,
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
return bundleJS({
|
|
30
|
-
buildID,
|
|
31
|
-
debug,
|
|
32
|
-
deno,
|
|
33
|
-
distDirectory,
|
|
34
|
-
functions,
|
|
35
|
-
importMap,
|
|
36
|
-
});
|
|
37
|
-
};
|
|
38
|
-
const bundle = async (sourceDirectories, distDirectory, tomlDeclarations = [], { basePath: inputBasePath, cacheDirectory, debug, distImportMapPath, featureFlags: inputFeatureFlags, importMaps, layers, onAfterDownload, onBeforeDownload, systemLogger, } = {}) => {
|
|
16
|
+
const bundle = async (sourceDirectories, distDirectory, tomlDeclarations = [], { basePath: inputBasePath, cacheDirectory, configPath, debug, distImportMapPath, featureFlags: inputFeatureFlags, onAfterDownload, onBeforeDownload, systemLogger, } = {}) => {
|
|
39
17
|
const logger = getLogger(systemLogger, debug);
|
|
40
18
|
const featureFlags = getFlags(inputFeatureFlags);
|
|
41
19
|
const options = {
|
|
@@ -55,19 +33,27 @@ const bundle = async (sourceDirectories, distDirectory, tomlDeclarations = [], {
|
|
|
55
33
|
// compute until we run the bundle process. For now, we'll use a random ID
|
|
56
34
|
// to create the bundle artifacts and rename them later.
|
|
57
35
|
const buildID = uuidv4();
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
const
|
|
36
|
+
// Loading any configuration options from the deploy configuration API, if it
|
|
37
|
+
// exists.
|
|
38
|
+
const deployConfig = await loadDeployConfig(configPath, logger);
|
|
39
|
+
// Layers are marked as externals in the ESZIP, so that those specifiers are
|
|
40
|
+
// not actually included in the bundle.
|
|
41
|
+
const externals = deployConfig.layers.map((layer) => layer.name);
|
|
42
|
+
const importMap = new ImportMap();
|
|
43
|
+
if (deployConfig.importMap) {
|
|
44
|
+
importMap.add(deployConfig.importMap);
|
|
45
|
+
}
|
|
61
46
|
const functions = await findFunctions(sourceDirectories);
|
|
62
|
-
const functionBundle = await
|
|
47
|
+
const functionBundle = await bundleESZIP({
|
|
63
48
|
basePath,
|
|
64
49
|
buildID,
|
|
65
50
|
debug,
|
|
66
51
|
deno,
|
|
67
52
|
distDirectory,
|
|
53
|
+
externals,
|
|
68
54
|
functions,
|
|
69
|
-
importMap,
|
|
70
55
|
featureFlags,
|
|
56
|
+
importMap,
|
|
71
57
|
});
|
|
72
58
|
// The final file name of the bundles contains a SHA256 hash of the contents,
|
|
73
59
|
// which we can only compute now that the files have been generated. So let's
|
|
@@ -82,15 +68,15 @@ const bundle = async (sourceDirectories, distDirectory, tomlDeclarations = [], {
|
|
|
82
68
|
}));
|
|
83
69
|
// Creating a hash of function names to configuration objects.
|
|
84
70
|
const functionsWithConfig = functions.reduce((acc, func, index) => ({ ...acc, [func.name]: functionsConfig[index] }), {});
|
|
85
|
-
// Creating a final declarations array by combining the TOML
|
|
86
|
-
//
|
|
87
|
-
const declarations = getDeclarationsFromConfig(tomlDeclarations, functionsWithConfig);
|
|
71
|
+
// Creating a final declarations array by combining the TOML file with the
|
|
72
|
+
// deploy configuration API and the in-source configuration.
|
|
73
|
+
const declarations = getDeclarationsFromConfig(tomlDeclarations, functionsWithConfig, deployConfig);
|
|
88
74
|
const manifest = await writeManifest({
|
|
89
75
|
bundles: [functionBundle],
|
|
90
76
|
declarations,
|
|
91
77
|
distDirectory,
|
|
92
78
|
functions,
|
|
93
|
-
layers,
|
|
79
|
+
layers: deployConfig.layers,
|
|
94
80
|
});
|
|
95
81
|
if (distImportMapPath) {
|
|
96
82
|
await importMap.writeToFile(distImportMapPath);
|
|
@@ -1,14 +1,14 @@
|
|
|
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';
|
|
8
7
|
import { fixturesDir } from '../test/util.js';
|
|
9
8
|
import { BundleError } from './bundle_error.js';
|
|
10
9
|
import { bundle } from './bundler.js';
|
|
11
|
-
|
|
10
|
+
import { isNodeError } from './utils/error.js';
|
|
11
|
+
test('Produces an ESZIP bundle', async () => {
|
|
12
12
|
const sourceDirectory = resolve(fixturesDir, 'with_import_maps', 'functions');
|
|
13
13
|
const tmpDir = await tmp.dir();
|
|
14
14
|
const declarations = [
|
|
@@ -19,49 +19,7 @@ test('Produces a JavaScript bundle and a manifest file', async () => {
|
|
|
19
19
|
];
|
|
20
20
|
const result = await bundle([sourceDirectory], tmpDir.path, declarations, {
|
|
21
21
|
basePath: fixturesDir,
|
|
22
|
-
|
|
23
|
-
{
|
|
24
|
-
baseURL: pathToFileURL(join(fixturesDir, 'import-map.json')),
|
|
25
|
-
imports: {
|
|
26
|
-
'alias:helper': pathToFileURL(join(fixturesDir, 'helper.ts')).toString(),
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
});
|
|
31
|
-
const generatedFiles = await fs.readdir(tmpDir.path);
|
|
32
|
-
expect(result.functions.length).toBe(1);
|
|
33
|
-
expect(generatedFiles.length).toBe(2);
|
|
34
|
-
const manifestFile = await fs.readFile(resolve(tmpDir.path, 'manifest.json'), 'utf8');
|
|
35
|
-
const manifest = JSON.parse(manifestFile);
|
|
36
|
-
const { bundles } = manifest;
|
|
37
|
-
expect(bundles.length).toBe(1);
|
|
38
|
-
expect(bundles[0].format).toBe('js');
|
|
39
|
-
expect(generatedFiles.includes(bundles[0].asset)).toBe(true);
|
|
40
|
-
expect(result.manifest).toEqual(manifest);
|
|
41
|
-
await fs.rmdir(tmpDir.path, { recursive: true });
|
|
42
|
-
});
|
|
43
|
-
test('Produces only a ESZIP bundle when the `edge_functions_produce_eszip` feature flag is set', async () => {
|
|
44
|
-
const sourceDirectory = resolve(fixturesDir, 'with_import_maps', 'functions');
|
|
45
|
-
const tmpDir = await tmp.dir();
|
|
46
|
-
const declarations = [
|
|
47
|
-
{
|
|
48
|
-
function: 'func1',
|
|
49
|
-
path: '/func1',
|
|
50
|
-
},
|
|
51
|
-
];
|
|
52
|
-
const result = await bundle([sourceDirectory], tmpDir.path, declarations, {
|
|
53
|
-
basePath: fixturesDir,
|
|
54
|
-
featureFlags: {
|
|
55
|
-
edge_functions_produce_eszip: true,
|
|
56
|
-
},
|
|
57
|
-
importMaps: [
|
|
58
|
-
{
|
|
59
|
-
baseURL: pathToFileURL(join(fixturesDir, 'import-map.json')),
|
|
60
|
-
imports: {
|
|
61
|
-
'alias:helper': pathToFileURL(join(fixturesDir, 'helper.ts')).toString(),
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
],
|
|
22
|
+
configPath: join(sourceDirectory, 'config.json'),
|
|
65
23
|
});
|
|
66
24
|
const generatedFiles = await fs.readdir(tmpDir.path);
|
|
67
25
|
expect(result.functions.length).toBe(1);
|
|
@@ -85,17 +43,7 @@ test('Uses the vendored eszip module instead of fetching it from deno.land', asy
|
|
|
85
43
|
];
|
|
86
44
|
const result = await bundle([sourceDirectory], tmpDir.path, declarations, {
|
|
87
45
|
basePath: fixturesDir,
|
|
88
|
-
|
|
89
|
-
edge_functions_produce_eszip: true,
|
|
90
|
-
},
|
|
91
|
-
importMaps: [
|
|
92
|
-
{
|
|
93
|
-
baseURL: pathToFileURL(join(fixturesDir, 'import-map.json')),
|
|
94
|
-
imports: {
|
|
95
|
-
'alias:helper': pathToFileURL(join(fixturesDir, 'helper.ts')).toString(),
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
],
|
|
46
|
+
configPath: join(sourceDirectory, 'config.json'),
|
|
99
47
|
});
|
|
100
48
|
const generatedFiles = await fs.readdir(tmpDir.path);
|
|
101
49
|
expect(result.functions.length).toBe(1);
|
|
@@ -125,7 +73,7 @@ test('Adds a custom error property to user errors during bundling', async () =>
|
|
|
125
73
|
expect(error).toBeInstanceOf(BundleError);
|
|
126
74
|
expect(error.customErrorInfo).toEqual({
|
|
127
75
|
location: {
|
|
128
|
-
format: '
|
|
76
|
+
format: 'eszip',
|
|
129
77
|
runtime: 'deno',
|
|
130
78
|
},
|
|
131
79
|
type: 'functionsBundling',
|
|
@@ -143,11 +91,7 @@ test('Prints a nice error message when user tries importing NPM module', async (
|
|
|
143
91
|
},
|
|
144
92
|
];
|
|
145
93
|
try {
|
|
146
|
-
await bundle([sourceDirectory], tmpDir.path, declarations
|
|
147
|
-
featureFlags: {
|
|
148
|
-
edge_functions_produce_eszip: true,
|
|
149
|
-
},
|
|
150
|
-
});
|
|
94
|
+
await bundle([sourceDirectory], tmpDir.path, declarations);
|
|
151
95
|
}
|
|
152
96
|
catch (error) {
|
|
153
97
|
expect(error).toBeInstanceOf(BundleError);
|
|
@@ -165,7 +109,7 @@ test('Does not add a custom error property to system errors during bundling', as
|
|
|
165
109
|
}
|
|
166
110
|
});
|
|
167
111
|
test('Uses the cache directory as the `DENO_DIR` value if the `edge_functions_cache_deno_dir` feature flag is set', async () => {
|
|
168
|
-
expect.assertions(
|
|
112
|
+
expect.assertions(6);
|
|
169
113
|
const sourceDirectory = resolve(fixturesDir, 'with_import_maps', 'functions');
|
|
170
114
|
const outDir = await tmp.dir();
|
|
171
115
|
const cacheDir = await tmp.dir();
|
|
@@ -178,14 +122,7 @@ test('Uses the cache directory as the `DENO_DIR` value if the `edge_functions_ca
|
|
|
178
122
|
const options = {
|
|
179
123
|
basePath: fixturesDir,
|
|
180
124
|
cacheDirectory: cacheDir.path,
|
|
181
|
-
|
|
182
|
-
{
|
|
183
|
-
baseURL: pathToFileURL(join(fixturesDir, 'import-map.json')),
|
|
184
|
-
imports: {
|
|
185
|
-
'alias:helper': pathToFileURL(join(fixturesDir, 'helper.ts')).toString(),
|
|
186
|
-
},
|
|
187
|
-
},
|
|
188
|
-
],
|
|
125
|
+
configPath: join(sourceDirectory, 'config.json'),
|
|
189
126
|
};
|
|
190
127
|
// Run #1, feature flag off: The directory should not be populated.
|
|
191
128
|
const result1 = await bundle([sourceDirectory], outDir.path, declarations, options);
|
|
@@ -209,7 +146,6 @@ test('Uses the cache directory as the `DENO_DIR` value if the `edge_functions_ca
|
|
|
209
146
|
expect(result2.functions.length).toBe(1);
|
|
210
147
|
expect(outFiles2.length).toBe(2);
|
|
211
148
|
const denoDir2 = await fs.readdir(join(cacheDir.path, 'deno_dir'));
|
|
212
|
-
expect(denoDir2.includes('deps')).toBe(true);
|
|
213
149
|
expect(denoDir2.includes('gen')).toBe(true);
|
|
214
150
|
await fs.rmdir(outDir.path, { recursive: true });
|
|
215
151
|
});
|
|
@@ -224,17 +160,7 @@ test('Supports import maps with relative paths', async () => {
|
|
|
224
160
|
];
|
|
225
161
|
const result = await bundle([sourceDirectory], tmpDir.path, declarations, {
|
|
226
162
|
basePath: fixturesDir,
|
|
227
|
-
|
|
228
|
-
edge_functions_produce_eszip: true,
|
|
229
|
-
},
|
|
230
|
-
importMaps: [
|
|
231
|
-
{
|
|
232
|
-
baseURL: pathToFileURL(join(fixturesDir, 'import-map.json')),
|
|
233
|
-
imports: {
|
|
234
|
-
'alias:helper': './helper.ts',
|
|
235
|
-
},
|
|
236
|
-
},
|
|
237
|
-
],
|
|
163
|
+
configPath: join(sourceDirectory, 'config.json'),
|
|
238
164
|
});
|
|
239
165
|
const generatedFiles = await fs.readdir(tmpDir.path);
|
|
240
166
|
expect(result.functions.length).toBe(1);
|
|
@@ -278,25 +204,14 @@ test('Ignores any user-defined `deno.json` files', async () => {
|
|
|
278
204
|
throw new Error(`The file at '${denoConfigPath} would be overwritten by this test. Please move the file to a different location and try again.'`);
|
|
279
205
|
}
|
|
280
206
|
catch (error) {
|
|
281
|
-
|
|
282
|
-
if (error.code !== 'ENOENT') {
|
|
207
|
+
if (isNodeError(error) && error.code !== 'ENOENT') {
|
|
283
208
|
throw error;
|
|
284
209
|
}
|
|
285
210
|
}
|
|
286
211
|
await fs.writeFile(denoConfigPath, JSON.stringify(denoConfig));
|
|
287
212
|
expect(() => bundle([join(fixtureDir, 'functions')], tmpDir.path, declarations, {
|
|
288
213
|
basePath: fixturesDir,
|
|
289
|
-
|
|
290
|
-
edge_functions_produce_eszip: true,
|
|
291
|
-
},
|
|
292
|
-
importMaps: [
|
|
293
|
-
{
|
|
294
|
-
baseURL: pathToFileURL(join(fixturesDir, 'import-map.json')),
|
|
295
|
-
imports: {
|
|
296
|
-
'alias:helper': pathToFileURL(join(fixturesDir, 'helper.ts')).toString(),
|
|
297
|
-
},
|
|
298
|
-
},
|
|
299
|
-
],
|
|
214
|
+
configPath: join(fixtureDir, 'functions', 'config.json'),
|
|
300
215
|
})).not.toThrow();
|
|
301
216
|
await deleteAsync([tmpDir.path, denoConfigPath, importMapFile.path], { force: true });
|
|
302
217
|
});
|
|
@@ -309,13 +224,10 @@ test('Processes a function that imports a custom layer', async () => {
|
|
|
309
224
|
path: '/func1',
|
|
310
225
|
},
|
|
311
226
|
];
|
|
312
|
-
const layer = { name: 'test', flag: 'edge-functions-layer-test' };
|
|
227
|
+
const layer = { name: 'layer:test', flag: 'edge-functions-layer-test' };
|
|
313
228
|
const result = await bundle([sourceDirectory], tmpDir.path, declarations, {
|
|
314
229
|
basePath: fixturesDir,
|
|
315
|
-
|
|
316
|
-
edge_functions_produce_eszip: true,
|
|
317
|
-
},
|
|
318
|
-
layers: [layer],
|
|
230
|
+
configPath: join(sourceDirectory, 'config.json'),
|
|
319
231
|
});
|
|
320
232
|
const generatedFiles = await fs.readdir(tmpDir.path);
|
|
321
233
|
expect(result.functions.length).toBe(1);
|
|
@@ -329,3 +241,28 @@ test('Processes a function that imports a custom layer', async () => {
|
|
|
329
241
|
expect(layers).toEqual([layer]);
|
|
330
242
|
await fs.rmdir(tmpDir.path, { recursive: true });
|
|
331
243
|
});
|
|
244
|
+
test('Loads declarations and import maps from the deploy configuration', async () => {
|
|
245
|
+
const fixtureDir = resolve(fixturesDir, 'with_deploy_config');
|
|
246
|
+
const tmpDir = await tmp.dir();
|
|
247
|
+
const declarations = [
|
|
248
|
+
{
|
|
249
|
+
function: 'func1',
|
|
250
|
+
path: '/func1',
|
|
251
|
+
},
|
|
252
|
+
];
|
|
253
|
+
const directories = [join(fixtureDir, 'netlify', 'edge-functions'), join(fixtureDir, '.netlify', 'edge-functions')];
|
|
254
|
+
const result = await bundle(directories, tmpDir.path, declarations, {
|
|
255
|
+
basePath: fixtureDir,
|
|
256
|
+
configPath: join(fixtureDir, '.netlify', 'edge-functions', 'config.json'),
|
|
257
|
+
});
|
|
258
|
+
const generatedFiles = await fs.readdir(tmpDir.path);
|
|
259
|
+
expect(result.functions.length).toBe(2);
|
|
260
|
+
expect(generatedFiles.length).toBe(2);
|
|
261
|
+
const manifestFile = await fs.readFile(resolve(tmpDir.path, 'manifest.json'), 'utf8');
|
|
262
|
+
const manifest = JSON.parse(manifestFile);
|
|
263
|
+
const { bundles } = manifest;
|
|
264
|
+
expect(bundles.length).toBe(1);
|
|
265
|
+
expect(bundles[0].format).toBe('eszip2');
|
|
266
|
+
expect(generatedFiles.includes(bundles[0].asset)).toBe(true);
|
|
267
|
+
await fs.rmdir(tmpDir.path, { recursive: true });
|
|
268
|
+
});
|
package/dist/node/config.test.js
CHANGED
|
@@ -127,10 +127,7 @@ test('Ignores function paths from the in-source `config` function if the feature
|
|
|
127
127
|
const declarations = [];
|
|
128
128
|
const result = await bundle([internalDirectory, userDirectory], tmpDir.path, declarations, {
|
|
129
129
|
basePath: fixturesDir,
|
|
130
|
-
|
|
131
|
-
edge_functions_produce_eszip: true,
|
|
132
|
-
},
|
|
133
|
-
importMaps: [importMapFile],
|
|
130
|
+
configPath: join(internalDirectory, 'config.json'),
|
|
134
131
|
});
|
|
135
132
|
const generatedFiles = await fs.readdir(tmpDir.path);
|
|
136
133
|
expect(result.functions.length).toBe(6);
|
|
@@ -160,11 +157,10 @@ test('Loads function paths from the in-source `config` function', async () => {
|
|
|
160
157
|
];
|
|
161
158
|
const result = await bundle([internalDirectory, userDirectory], tmpDir.path, declarations, {
|
|
162
159
|
basePath: fixturesDir,
|
|
160
|
+
configPath: join(internalDirectory, 'config.json'),
|
|
163
161
|
featureFlags: {
|
|
164
162
|
edge_functions_config_export: true,
|
|
165
|
-
edge_functions_produce_eszip: true,
|
|
166
163
|
},
|
|
167
|
-
importMaps: [importMapFile],
|
|
168
164
|
});
|
|
169
165
|
const generatedFiles = await fs.readdir(tmpDir.path);
|
|
170
166
|
expect(result.functions.length).toBe(6);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FunctionConfig } from './config.js';
|
|
2
|
+
import type { DeployConfig } from './deploy_config.js';
|
|
2
3
|
interface BaseDeclaration {
|
|
3
4
|
cache?: string;
|
|
4
5
|
function: string;
|
|
@@ -11,5 +12,5 @@ type DeclarationWithPattern = BaseDeclaration & {
|
|
|
11
12
|
pattern: string;
|
|
12
13
|
};
|
|
13
14
|
type Declaration = DeclarationWithPath | DeclarationWithPattern;
|
|
14
|
-
export declare const getDeclarationsFromConfig: (tomlDeclarations: Declaration[], functionsConfig: Record<string, FunctionConfig
|
|
15
|
+
export declare const getDeclarationsFromConfig: (tomlDeclarations: Declaration[], functionsConfig: Record<string, FunctionConfig>, deployConfig: DeployConfig) => Declaration[];
|
|
15
16
|
export { Declaration, DeclarationWithPath, DeclarationWithPattern };
|
package/dist/node/declaration.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export const getDeclarationsFromConfig = (tomlDeclarations, functionsConfig) => {
|
|
1
|
+
export const getDeclarationsFromConfig = (tomlDeclarations, functionsConfig, deployConfig) => {
|
|
2
2
|
var _a;
|
|
3
3
|
const declarations = [];
|
|
4
4
|
const functionsVisited = new Set();
|
|
5
|
-
// We start by iterating over all the TOML
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// precedence.
|
|
9
|
-
for (const declaration of tomlDeclarations) {
|
|
5
|
+
// We start by iterating over all the declarations in the TOML file and in
|
|
6
|
+
// the deploy configuration file. For any declaration for which we also have
|
|
7
|
+
// a function configuration object, we replace the path because that object
|
|
8
|
+
// takes precedence.
|
|
9
|
+
for (const declaration of [...tomlDeclarations, ...deployConfig.declarations]) {
|
|
10
10
|
const config = (_a = functionsConfig[declaration.function]) !== null && _a !== void 0 ? _a : {};
|
|
11
11
|
functionsVisited.add(declaration.function);
|
|
12
12
|
declarations.push({ ...declaration, ...config });
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { test, expect } from 'vitest';
|
|
2
2
|
import { getDeclarationsFromConfig } from './declaration.js';
|
|
3
|
+
// TODO: Add tests with the deploy config.
|
|
4
|
+
const deployConfig = {
|
|
5
|
+
declarations: [],
|
|
6
|
+
layers: [],
|
|
7
|
+
};
|
|
3
8
|
test('In source config takes precedence over netlify.toml config', () => {
|
|
4
9
|
const tomlConfig = [
|
|
5
10
|
{ function: 'geolocation', path: '/geo', cache: 'off' },
|
|
@@ -13,7 +18,7 @@ test('In source config takes precedence over netlify.toml config', () => {
|
|
|
13
18
|
{ function: 'geolocation', path: '/geo-isc', cache: 'manual' },
|
|
14
19
|
{ function: 'json', path: '/json', cache: 'off' },
|
|
15
20
|
];
|
|
16
|
-
const declarations = getDeclarationsFromConfig(tomlConfig, funcConfig);
|
|
21
|
+
const declarations = getDeclarationsFromConfig(tomlConfig, funcConfig, deployConfig);
|
|
17
22
|
expect(declarations).toEqual(expectedDeclarations);
|
|
18
23
|
});
|
|
19
24
|
test("Declarations don't break if no in source config is provided", () => {
|
|
@@ -29,7 +34,7 @@ test("Declarations don't break if no in source config is provided", () => {
|
|
|
29
34
|
{ function: 'geolocation', path: '/geo-isc', cache: 'manual' },
|
|
30
35
|
{ function: 'json', path: '/json', cache: 'manual' },
|
|
31
36
|
];
|
|
32
|
-
const declarations = getDeclarationsFromConfig(tomlConfig, funcConfig);
|
|
37
|
+
const declarations = getDeclarationsFromConfig(tomlConfig, funcConfig, deployConfig);
|
|
33
38
|
expect(declarations).toEqual(expectedDeclarations);
|
|
34
39
|
});
|
|
35
40
|
test('In source config works independent of the netlify.toml file if a path is defined and otherwise if no path is set', () => {
|
|
@@ -45,8 +50,8 @@ test('In source config works independent of the netlify.toml file if a path is d
|
|
|
45
50
|
{ function: 'json', path: '/json', cache: 'off' },
|
|
46
51
|
];
|
|
47
52
|
const expectedDeclarationsWithoutISCPath = [{ function: 'geolocation', path: '/geo', cache: 'off' }];
|
|
48
|
-
const declarationsWithISCPath = getDeclarationsFromConfig(tomlConfig, funcConfigWithPath);
|
|
49
|
-
const declarationsWithoutISCPath = getDeclarationsFromConfig(tomlConfig, funcConfigWithoutPath);
|
|
53
|
+
const declarationsWithISCPath = getDeclarationsFromConfig(tomlConfig, funcConfigWithPath, deployConfig);
|
|
50
54
|
expect(declarationsWithISCPath).toEqual(expectedDeclarationsWithISCPath);
|
|
55
|
+
const declarationsWithoutISCPath = getDeclarationsFromConfig(tomlConfig, funcConfigWithoutPath, deployConfig);
|
|
51
56
|
expect(declarationsWithoutISCPath).toEqual(expectedDeclarationsWithoutISCPath);
|
|
52
57
|
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Declaration } from './declaration.js';
|
|
2
|
+
import { ImportMapFile } from './import_map.js';
|
|
3
|
+
import type { Layer } from './layer.js';
|
|
4
|
+
import type { Logger } from './logger.js';
|
|
5
|
+
export interface DeployConfig {
|
|
6
|
+
declarations: Declaration[];
|
|
7
|
+
importMap?: ImportMapFile;
|
|
8
|
+
layers: Layer[];
|
|
9
|
+
}
|
|
10
|
+
export declare const load: (path: string | undefined, logger: Logger) => Promise<DeployConfig>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { dirname, resolve } from 'path';
|
|
3
|
+
import { readFile as readImportMap } from './import_map.js';
|
|
4
|
+
import { isNodeError } from './utils/error.js';
|
|
5
|
+
export const load = async (path, logger) => {
|
|
6
|
+
if (path === undefined) {
|
|
7
|
+
return {
|
|
8
|
+
declarations: [],
|
|
9
|
+
layers: [],
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const data = await fs.readFile(path, 'utf8');
|
|
14
|
+
const config = JSON.parse(data);
|
|
15
|
+
return parse(config, path);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (isNodeError(error) && error.code !== 'ENOENT') {
|
|
19
|
+
logger.system('Error while parsing internal edge functions manifest:', error);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
declarations: [],
|
|
24
|
+
layers: [],
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
const parse = async (data, path) => {
|
|
28
|
+
var _a, _b;
|
|
29
|
+
if (data.version !== 1) {
|
|
30
|
+
throw new Error(`Unsupported file version: ${data.version}`);
|
|
31
|
+
}
|
|
32
|
+
const config = {
|
|
33
|
+
declarations: (_a = data.functions) !== null && _a !== void 0 ? _a : [],
|
|
34
|
+
layers: (_b = data.layers) !== null && _b !== void 0 ? _b : [],
|
|
35
|
+
};
|
|
36
|
+
if (data.import_map) {
|
|
37
|
+
const importMapPath = resolve(dirname(path), data.import_map);
|
|
38
|
+
const importMap = await readImportMap(importMapPath);
|
|
39
|
+
return {
|
|
40
|
+
...config,
|
|
41
|
+
importMap,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return config;
|
|
45
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { cwd } from 'process';
|
|
4
|
+
import { pathToFileURL } from 'url';
|
|
5
|
+
import tmp from 'tmp-promise';
|
|
6
|
+
import { test, expect } from 'vitest';
|
|
7
|
+
import { load } from './deploy_config.js';
|
|
8
|
+
import { getLogger } from './logger.js';
|
|
9
|
+
const logger = getLogger(console.log);
|
|
10
|
+
test('Returns an empty config object if there is no file at the given path', async () => {
|
|
11
|
+
const mockPath = join(cwd(), 'some-directory', `a-file-that-does-not-exist-${Date.now()}.json`);
|
|
12
|
+
const config = await load(mockPath, logger);
|
|
13
|
+
expect(config.declarations).toEqual([]);
|
|
14
|
+
expect(config.layers).toEqual([]);
|
|
15
|
+
});
|
|
16
|
+
test('Returns a config object with declarations, layers, and import map', async () => {
|
|
17
|
+
var _a, _b;
|
|
18
|
+
const importMapFile = await tmp.file();
|
|
19
|
+
const importMap = {
|
|
20
|
+
imports: {
|
|
21
|
+
'https://deno.land/': 'https://black.hole/',
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
await fs.writeFile(importMapFile.path, JSON.stringify(importMap));
|
|
25
|
+
const configFile = await tmp.file();
|
|
26
|
+
const config = {
|
|
27
|
+
functions: [
|
|
28
|
+
{
|
|
29
|
+
function: 'func1',
|
|
30
|
+
path: '/func1',
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
layers: [
|
|
34
|
+
{
|
|
35
|
+
name: 'layer1',
|
|
36
|
+
flag: 'edge_functions_layer1_url',
|
|
37
|
+
local: 'https://some-url.netlify.app/mod.ts',
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
import_map: importMapFile.path,
|
|
41
|
+
version: 1,
|
|
42
|
+
};
|
|
43
|
+
await fs.writeFile(configFile.path, JSON.stringify(config));
|
|
44
|
+
const parsedConfig = await load(configFile.path, logger);
|
|
45
|
+
expect(parsedConfig.declarations).toEqual(config.functions);
|
|
46
|
+
expect(parsedConfig.layers).toEqual(config.layers);
|
|
47
|
+
expect(parsedConfig.importMap).toBeTruthy();
|
|
48
|
+
expect((_a = parsedConfig.importMap) === null || _a === void 0 ? void 0 : _a.baseURL).toEqual(pathToFileURL(importMapFile.path));
|
|
49
|
+
expect((_b = parsedConfig.importMap) === null || _b === void 0 ? void 0 : _b.imports).toEqual(importMap.imports);
|
|
50
|
+
});
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const defaultFlags = {
|
|
2
2
|
edge_functions_cache_deno_dir: false,
|
|
3
3
|
edge_functions_config_export: false,
|
|
4
|
-
edge_functions_produce_eszip: false,
|
|
5
4
|
};
|
|
6
5
|
const getFlags = (input = {}, flags = defaultFlags) => Object.entries(flags).reduce((result, [key, defaultValue]) => ({
|
|
7
6
|
...result,
|
|
@@ -9,9 +9,10 @@ interface BundleESZIPOptions {
|
|
|
9
9
|
debug?: boolean;
|
|
10
10
|
deno: DenoBridge;
|
|
11
11
|
distDirectory: string;
|
|
12
|
+
externals: string[];
|
|
12
13
|
featureFlags: FeatureFlags;
|
|
13
14
|
functions: EdgeFunction[];
|
|
14
15
|
importMap: ImportMap;
|
|
15
16
|
}
|
|
16
|
-
declare const bundleESZIP: ({ basePath, buildID, debug, deno, distDirectory, functions, importMap, }: BundleESZIPOptions) => Promise<Bundle>;
|
|
17
|
+
declare const bundleESZIP: ({ basePath, buildID, debug, deno, distDirectory, externals, functions, importMap, }: BundleESZIPOptions) => Promise<Bundle>;
|
|
17
18
|
export { bundleESZIP as bundle };
|
|
@@ -4,13 +4,14 @@ import { wrapBundleError } from '../bundle_error.js';
|
|
|
4
4
|
import { wrapNpmImportError } from '../npm_import_error.js';
|
|
5
5
|
import { getPackagePath } from '../package_json.js';
|
|
6
6
|
import { getFileHash } from '../utils/sha256.js';
|
|
7
|
-
const bundleESZIP = async ({ basePath, buildID, debug, deno, distDirectory, functions, importMap, }) => {
|
|
7
|
+
const bundleESZIP = async ({ basePath, buildID, debug, deno, distDirectory, externals, functions, importMap, }) => {
|
|
8
8
|
const extension = '.eszip';
|
|
9
9
|
const destPath = join(distDirectory, `${buildID}${extension}`);
|
|
10
10
|
const { bundler, importMap: bundlerImportMap } = getESZIPPaths();
|
|
11
11
|
const payload = {
|
|
12
12
|
basePath,
|
|
13
13
|
destPath,
|
|
14
|
+
externals,
|
|
14
15
|
functions,
|
|
15
16
|
importMapURL: importMap.toDataURL(),
|
|
16
17
|
};
|
|
@@ -1,30 +1,17 @@
|
|
|
1
|
-
import { DenoBridge } from '../bridge.js';
|
|
2
|
-
import { Bundle } from '../bundle.js';
|
|
3
1
|
import { EdgeFunction } from '../edge_function.js';
|
|
4
|
-
import { ImportMap } from '../import_map.js';
|
|
5
2
|
import type { FormatFunction } from '../server/server.js';
|
|
6
|
-
interface BundleJSOptions {
|
|
7
|
-
buildID: string;
|
|
8
|
-
debug?: boolean;
|
|
9
|
-
deno: DenoBridge;
|
|
10
|
-
distDirectory: string;
|
|
11
|
-
functions: EdgeFunction[];
|
|
12
|
-
importMap: ImportMap;
|
|
13
|
-
}
|
|
14
|
-
declare const bundleJS: ({ buildID, debug, deno, distDirectory, functions, importMap, }: BundleJSOptions) => Promise<Bundle>;
|
|
15
3
|
interface GenerateStage2Options {
|
|
16
4
|
distDirectory: string;
|
|
17
5
|
fileName: string;
|
|
18
6
|
formatExportTypeError?: FormatFunction;
|
|
19
7
|
formatImportError?: FormatFunction;
|
|
20
8
|
functions: EdgeFunction[];
|
|
21
|
-
type?: 'local' | 'production';
|
|
22
9
|
}
|
|
23
|
-
declare const generateStage2: ({ distDirectory, fileName, formatExportTypeError, formatImportError, functions,
|
|
10
|
+
declare const generateStage2: ({ distDirectory, fileName, formatExportTypeError, formatImportError, functions, }: GenerateStage2Options) => Promise<string>;
|
|
24
11
|
declare const getBootstrapURL: () => string;
|
|
25
12
|
interface GetLocalEntryPointOptions {
|
|
26
13
|
formatExportTypeError?: FormatFunction;
|
|
27
14
|
formatImportError?: FormatFunction;
|
|
28
15
|
}
|
|
29
16
|
declare const getLocalEntryPoint: (functions: EdgeFunction[], { formatExportTypeError, formatImportError, }: GetLocalEntryPointOptions) => string;
|
|
30
|
-
export {
|
|
17
|
+
export { generateStage2, getBootstrapURL, getLocalEntryPoint };
|
|
@@ -3,37 +3,13 @@ import { join } from 'path';
|
|
|
3
3
|
import { env } from 'process';
|
|
4
4
|
import { pathToFileURL } from 'url';
|
|
5
5
|
import { deleteAsync } from 'del';
|
|
6
|
-
import { BundleFormat } from '../bundle.js';
|
|
7
|
-
import { wrapBundleError } from '../bundle_error.js';
|
|
8
|
-
import { wrapNpmImportError } from '../npm_import_error.js';
|
|
9
|
-
import { getFileHash } from '../utils/sha256.js';
|
|
10
6
|
const BOOTSTRAP_LATEST = 'https://637cf7ce9214b300099b3aa8--edge.netlify.com/bootstrap/index-combined.ts';
|
|
11
|
-
const bundleJS = async ({ buildID, debug, deno, distDirectory, functions, importMap, }) => {
|
|
12
|
-
const stage2Path = await generateStage2({ distDirectory, functions, fileName: `${buildID}-pre.js` });
|
|
13
|
-
const extension = '.js';
|
|
14
|
-
const jsBundlePath = join(distDirectory, `${buildID}${extension}`);
|
|
15
|
-
const flags = [`--import-map=${importMap.toDataURL()}`, '--no-config'];
|
|
16
|
-
if (!debug) {
|
|
17
|
-
flags.push('--quiet');
|
|
18
|
-
}
|
|
19
|
-
try {
|
|
20
|
-
await deno.run(['bundle', ...flags, stage2Path, jsBundlePath], { pipeOutput: true });
|
|
21
|
-
}
|
|
22
|
-
catch (error) {
|
|
23
|
-
throw wrapBundleError(wrapNpmImportError(error), { format: 'javascript' });
|
|
24
|
-
}
|
|
25
|
-
await fs.unlink(stage2Path);
|
|
26
|
-
const hash = await getFileHash(jsBundlePath);
|
|
27
|
-
return { extension, format: BundleFormat.JS, hash };
|
|
28
|
-
};
|
|
29
7
|
const defaultFormatExportTypeError = (name) => `The Edge Function "${name}" has failed to load. Does it have a function as the default export?`;
|
|
30
8
|
const defaultFormatImpoortError = (name) => `There was an error with Edge Function "${name}".`;
|
|
31
|
-
const generateStage2 = async ({ distDirectory, fileName, formatExportTypeError, formatImportError, functions,
|
|
9
|
+
const generateStage2 = async ({ distDirectory, fileName, formatExportTypeError, formatImportError, functions, }) => {
|
|
32
10
|
await deleteAsync(distDirectory, { force: true });
|
|
33
11
|
await fs.mkdir(distDirectory, { recursive: true });
|
|
34
|
-
const entryPoint =
|
|
35
|
-
? getLocalEntryPoint(functions, { formatExportTypeError, formatImportError })
|
|
36
|
-
: getProductionEntryPoint(functions);
|
|
12
|
+
const entryPoint = getLocalEntryPoint(functions, { formatExportTypeError, formatImportError });
|
|
37
13
|
const stage2Path = join(distDirectory, fileName);
|
|
38
14
|
await fs.writeFile(stage2Path, entryPoint);
|
|
39
15
|
return stage2Path;
|
|
@@ -69,21 +45,4 @@ const getLocalEntryPoint = (functions, { formatExportTypeError = defaultFormatEx
|
|
|
69
45
|
const bootCall = `boot(functions, metadata);`;
|
|
70
46
|
return [bootImport, declaration, ...imports, bootCall].join('\n\n');
|
|
71
47
|
};
|
|
72
|
-
|
|
73
|
-
const bootImport = `import { boot } from "${getBootstrapURL()}";`;
|
|
74
|
-
const lines = functions.map((func, index) => {
|
|
75
|
-
const importName = `func${index}`;
|
|
76
|
-
const exportLine = `"${func.name}": ${importName}`;
|
|
77
|
-
const url = pathToFileURL(func.path);
|
|
78
|
-
return {
|
|
79
|
-
exportLine,
|
|
80
|
-
importLine: `import ${importName} from "${url}";`,
|
|
81
|
-
};
|
|
82
|
-
});
|
|
83
|
-
const importLines = lines.map(({ importLine }) => importLine).join('\n');
|
|
84
|
-
const exportLines = lines.map(({ exportLine }) => exportLine).join(', ');
|
|
85
|
-
const exportDeclaration = `const functions = {${exportLines}};`;
|
|
86
|
-
const defaultExport = 'boot(functions);';
|
|
87
|
-
return [bootImport, importLines, exportDeclaration, defaultExport].join('\n\n');
|
|
88
|
-
};
|
|
89
|
-
export { bundleJS as bundle, generateStage2, getBootstrapURL, getLocalEntryPoint };
|
|
48
|
+
export { generateStage2, getBootstrapURL, getLocalEntryPoint };
|
|
@@ -4,12 +4,14 @@ interface ImportMapFile {
|
|
|
4
4
|
scopes?: Record<string, Record<string, string>>;
|
|
5
5
|
}
|
|
6
6
|
declare class ImportMap {
|
|
7
|
-
|
|
7
|
+
files: ImportMapFile[];
|
|
8
8
|
constructor(files?: ImportMapFile[]);
|
|
9
9
|
static resolve(importMapFile: ImportMapFile): import("@import-maps/resolve/types/src/types").ParsedImportMap;
|
|
10
|
+
add(file: ImportMapFile): void;
|
|
10
11
|
getContents(): string;
|
|
11
12
|
toDataURL(): string;
|
|
12
13
|
writeToFile(path: string): Promise<void>;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
+
declare const readFile: (path: string) => Promise<ImportMapFile>;
|
|
16
|
+
export { ImportMap, readFile };
|
|
15
17
|
export type { ImportMapFile };
|
package/dist/node/import_map.js
CHANGED
|
@@ -1,14 +1,31 @@
|
|
|
1
1
|
import { Buffer } from 'buffer';
|
|
2
2
|
import { promises as fs } from 'fs';
|
|
3
3
|
import { dirname } from 'path';
|
|
4
|
+
import { pathToFileURL } from 'url';
|
|
4
5
|
import { parse } from '@import-maps/resolve';
|
|
5
6
|
const INTERNAL_IMPORTS = {
|
|
6
7
|
'netlify:edge': new URL('https://edge.netlify.com/v1/index.ts'),
|
|
7
8
|
};
|
|
9
|
+
// ImportMap can take several import map files and merge them into a final
|
|
10
|
+
// import map object, also adding the internal imports in the right order.
|
|
8
11
|
class ImportMap {
|
|
9
12
|
constructor(files = []) {
|
|
10
|
-
|
|
13
|
+
this.files = [];
|
|
11
14
|
files.forEach((file) => {
|
|
15
|
+
this.add(file);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
static resolve(importMapFile) {
|
|
19
|
+
const { baseURL, ...importMap } = importMapFile;
|
|
20
|
+
const parsedImportMap = parse(importMap, baseURL);
|
|
21
|
+
return parsedImportMap;
|
|
22
|
+
}
|
|
23
|
+
add(file) {
|
|
24
|
+
this.files.push(file);
|
|
25
|
+
}
|
|
26
|
+
getContents() {
|
|
27
|
+
let imports = {};
|
|
28
|
+
this.files.forEach((file) => {
|
|
12
29
|
const importMap = ImportMap.resolve(file);
|
|
13
30
|
imports = { ...imports, ...importMap.imports };
|
|
14
31
|
});
|
|
@@ -18,16 +35,8 @@ class ImportMap {
|
|
|
18
35
|
const [specifier, url] = internalImport;
|
|
19
36
|
imports[specifier] = url;
|
|
20
37
|
});
|
|
21
|
-
this.imports = imports;
|
|
22
|
-
}
|
|
23
|
-
static resolve(importMapFile) {
|
|
24
|
-
const { baseURL, ...importMap } = importMapFile;
|
|
25
|
-
const parsedImportMap = parse(importMap, baseURL);
|
|
26
|
-
return parsedImportMap;
|
|
27
|
-
}
|
|
28
|
-
getContents() {
|
|
29
38
|
const contents = {
|
|
30
|
-
imports
|
|
39
|
+
imports,
|
|
31
40
|
};
|
|
32
41
|
return JSON.stringify(contents);
|
|
33
42
|
}
|
|
@@ -41,4 +50,22 @@ class ImportMap {
|
|
|
41
50
|
await fs.writeFile(path, contents);
|
|
42
51
|
}
|
|
43
52
|
}
|
|
44
|
-
|
|
53
|
+
const readFile = async (path) => {
|
|
54
|
+
const baseURL = pathToFileURL(path);
|
|
55
|
+
try {
|
|
56
|
+
const data = await fs.readFile(path, 'utf8');
|
|
57
|
+
const importMap = JSON.parse(data);
|
|
58
|
+
return {
|
|
59
|
+
...importMap,
|
|
60
|
+
baseURL,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// no-op
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
baseURL,
|
|
68
|
+
imports: {},
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
export { ImportMap, readFile };
|
|
@@ -19,7 +19,6 @@ const prepareServer = ({ deno, distDirectory, flags: denoFlags, formatExportType
|
|
|
19
19
|
functions,
|
|
20
20
|
formatExportTypeError,
|
|
21
21
|
formatImportError,
|
|
22
|
-
type: 'local',
|
|
23
22
|
});
|
|
24
23
|
try {
|
|
25
24
|
// This command will print a JSON object with all the modules found in
|
|
@@ -71,7 +70,7 @@ const serve = async ({ certificatePath, debug, distImportMapPath, inspectSetting
|
|
|
71
70
|
await ensureLatestTypes(deno, logger);
|
|
72
71
|
// Creating an ImportMap instance with any import maps supplied by the user,
|
|
73
72
|
// if any.
|
|
74
|
-
const importMap = new ImportMap(importMaps);
|
|
73
|
+
const importMap = new ImportMap(importMaps !== null && importMaps !== void 0 ? importMaps : []);
|
|
75
74
|
const flags = ['--allow-all', '--unstable', `--import-map=${importMap.toDataURL()}`, '--no-config'];
|
|
76
75
|
if (certificatePath) {
|
|
77
76
|
flags.push(`--cert=${certificatePath}`);
|
package/dist/shared/stage2.d.ts
CHANGED
package/package.json
CHANGED