@hyperspan/framework 1.0.0-alpha.8 → 1.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/src/plugins.ts DELETED
@@ -1,94 +0,0 @@
1
- import type { Hyperspan as HS } from './types';
2
- import { JS_PUBLIC_PATH, JS_IMPORT_MAP } from './client/js';
3
- import { assetHash } from './utils';
4
- import { IS_PROD } from './server';
5
- import { join } from 'node:path';
6
-
7
- export const CSS_PUBLIC_PATH = '/_hs/css';
8
- const CLIENT_JS_CACHE = new Map<string, string>();
9
- const EXPORT_REGEX = /export\{(.*)\}/g;
10
-
11
- /**
12
- * Hyperspan Client JS Plugin
13
- */
14
- export function clientJSPlugin(): HS.Plugin {
15
- return async (config: HS.Config) => {
16
- // Define a Bun plugin to handle .client.ts files
17
- await Bun.plugin({
18
- name: 'Hyperspan Client JS Loader',
19
- async setup(build) {
20
- // when a .client.ts file is imported...
21
- build.onLoad({ filter: /\.client\.ts$/ }, async (args) => {
22
- const jsId = assetHash(args.path);
23
-
24
- // Cache: Avoid re-processing the same file
25
- if (IS_PROD && CLIENT_JS_CACHE.has(jsId)) {
26
- return {
27
- contents: CLIENT_JS_CACHE.get(jsId) || '',
28
- loader: 'js',
29
- };
30
- }
31
-
32
- // We need to build the file to ensure we can ship it to the client with dependencies
33
- // Ironic, right? Calling Bun.build() inside of a plugin that runs on Bun.build()?
34
- const result = await Bun.build({
35
- entrypoints: [args.path],
36
- outdir: join(config.publicDir, JS_PUBLIC_PATH),
37
- naming: IS_PROD ? '[dir]/[name]-[hash].[ext]' : undefined,
38
- external: Array.from(JS_IMPORT_MAP.keys()),
39
- minify: IS_PROD,
40
- format: 'esm',
41
- target: 'browser',
42
- env: 'APP_PUBLIC_*',
43
- });
44
-
45
- // Add output file to import map
46
- const esmName = String(result.outputs[0].path.split('/').reverse()[0]).replace('.js', '');
47
- JS_IMPORT_MAP.set(esmName, `${JS_PUBLIC_PATH}/${esmName}.js`);
48
-
49
- // Get the contents of the file to extract the exports
50
- const contents = await result.outputs[0].text();
51
- const exportLine = EXPORT_REGEX.exec(contents);
52
-
53
- let exports = '{}';
54
- if (exportLine) {
55
- const exportName = exportLine[1];
56
- exports =
57
- '{' +
58
- exportName
59
- .split(',')
60
- .map((name) => name.trim().split(' as '))
61
- .map(([name, alias]) => `${alias === 'default' ? 'default as ' + name : alias}`)
62
- .join(', ') +
63
- '}';
64
- }
65
- const fnArgs = exports.replace(/(\w+)\s*as\s*(\w+)/g, '$1: $2');
66
-
67
- // Export a special object that can be used to render the client JS as a script tag
68
- const moduleCode = `// hyperspan:processed
69
- import { functionToString } from '@hyperspan/framework/client/js';
70
-
71
- // hyperspan:client-js-plugin
72
- export const __CLIENT_JS = {
73
- id: "${jsId}",
74
- esmName: "${esmName}",
75
- sourceFile: "${args.path}",
76
- outputFile: "${result.outputs[0].path}",
77
- renderScriptTag: ({ loadScript }) => {
78
- const fn = loadScript ? (typeof loadScript === 'string' ? loadScript : \`const fn = \${functionToString(loadScript)}; fn(${fnArgs});\`) : '';
79
- return \`<script type="module" data-source-id="${jsId}">import ${exports} from "${esmName}";\n\${fn}</script>\`;
80
- },
81
- }
82
- `;
83
-
84
- CLIENT_JS_CACHE.set(jsId, moduleCode);
85
-
86
- return {
87
- contents: moduleCode,
88
- loader: 'js',
89
- };
90
- });
91
- },
92
- });
93
- };
94
- }