@hyperspan/framework 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/client/js.ts +48 -31
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperspan/framework",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Hyperspan Web Framework",
5
5
  "main": "src/server.ts",
6
6
  "types": "src/server.ts",
package/src/client/js.ts CHANGED
@@ -10,6 +10,7 @@ export const JS_PUBLIC_PATH = '/_hs/js';
10
10
  export const JS_ISLAND_PUBLIC_PATH = '/_hs/js/islands';
11
11
  export const JS_IMPORT_MAP = new Map<string, string>();
12
12
  const CLIENT_JS_CACHE = new Map<string, { esmName: string, exports: string, fnArgs: string, publicPath: string }>();
13
+ const CLIENT_JS_BUILD_PROMISES = new Map<string, Promise<void>>();
13
14
  const EXPORT_REGEX = /export\{(.*)\}/g;
14
15
 
15
16
  /**
@@ -21,41 +22,57 @@ export async function buildClientJS(modulePathResolved: string): Promise<HS.Clie
21
22
 
22
23
  // Cache: Avoid re-processing the same file
23
24
  if (!CLIENT_JS_CACHE.has(assetHash)) {
24
- // Build the client JS module
25
- const result = await Bun.build({
26
- entrypoints: [modulePath],
27
- outdir: join(CWD, './public', JS_PUBLIC_PATH), // @TODO: Make this configurable... should be read from config file...
28
- naming: IS_PROD ? '[dir]/[name]-[hash].[ext]' : undefined,
29
- external: Array.from(JS_IMPORT_MAP.keys()),
30
- minify: true,
31
- format: 'esm',
32
- target: 'browser',
33
- env: 'APP_PUBLIC_*',
34
- });
25
+ const existingBuild = CLIENT_JS_BUILD_PROMISES.get(assetHash);
26
+ // Await the existing build promise if it exists (this can get called in parallel from Bun traversing imports)
27
+ if (existingBuild) {
28
+ await existingBuild;
29
+ } else {
30
+ const buildPromise = (async () => {
31
+ // Build the client JS module
32
+ const result = await Bun.build({
33
+ entrypoints: [modulePath],
34
+ outdir: join(CWD, './public', JS_PUBLIC_PATH), // @TODO: Make this configurable... should be read from config file...
35
+ naming: IS_PROD ? '[dir]/[name]-[hash].[ext]' : undefined,
36
+ external: Array.from(JS_IMPORT_MAP.keys()),
37
+ minify: true,
38
+ format: 'esm',
39
+ target: 'browser',
40
+ env: 'APP_PUBLIC_*',
41
+ });
35
42
 
36
- // Add output file to import map
37
- const esmName = String(result.outputs[0].path.split('/').reverse()[0]).replace('.js', '');
38
- const publicPath = `${JS_PUBLIC_PATH}/${esmName}.js`;
39
- JS_IMPORT_MAP.set(esmName, publicPath);
43
+ // Add output file to import map
44
+ const esmName = String(result.outputs[0].path.split('/').reverse()[0]).replace('.js', '');
45
+ const publicPath = `${JS_PUBLIC_PATH}/${esmName}.js`;
46
+ JS_IMPORT_MAP.set(esmName, publicPath);
40
47
 
41
- // Get the contents of the file to extract the exports
42
- const contents = await result.outputs[0].text();
43
- const exportLine = EXPORT_REGEX.exec(contents);
48
+ // Get the contents of the file to extract the exports
49
+ const contents = await result.outputs[0].text();
50
+ const exportLine = EXPORT_REGEX.exec(contents);
44
51
 
45
- let exports = '{}';
46
- if (exportLine) {
47
- const exportName = exportLine[1];
48
- exports =
49
- '{' +
50
- exportName
51
- .split(',')
52
- .map((name) => name.trim().split(' as '))
53
- .map(([name, alias]) => `${alias === 'default' ? 'default as ' + name : alias}`)
54
- .join(', ') +
55
- '}';
52
+ let exports = '{}';
53
+ if (exportLine) {
54
+ const exportName = exportLine[1];
55
+ exports =
56
+ '{' +
57
+ exportName
58
+ .split(',')
59
+ .map((name) => name.trim().split(' as '))
60
+ .map(([name, alias]) => `${alias === 'default' ? 'default as ' + name : alias}`)
61
+ .join(', ') +
62
+ '}';
63
+ }
64
+ const fnArgs = exports.replace(/(\w+)\s*as\s*(\w+)/g, '$1: $2');
65
+
66
+ CLIENT_JS_CACHE.set(assetHash, { esmName, exports, fnArgs, publicPath });
67
+ })();
68
+
69
+ CLIENT_JS_BUILD_PROMISES.set(assetHash, buildPromise);
70
+ try {
71
+ await buildPromise;
72
+ } finally {
73
+ CLIENT_JS_BUILD_PROMISES.delete(assetHash);
74
+ }
56
75
  }
57
- const fnArgs = exports.replace(/(\w+)\s*as\s*(\w+)/g, '$1: $2');
58
- CLIENT_JS_CACHE.set(assetHash, { esmName, exports, fnArgs, publicPath });
59
76
  }
60
77
 
61
78
  const { esmName, exports, fnArgs, publicPath } = CLIENT_JS_CACHE.get(assetHash)!;