@barefootjs/hono 0.2.0 → 0.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/dist/app.d.ts +35 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +12 -7
- package/dist/scripts.js +12 -7
- package/package.json +4 -4
- package/src/__tests__/import-map.test.ts +88 -0
- package/src/app.ts +55 -8
package/dist/app.d.ts
CHANGED
|
@@ -63,14 +63,48 @@ export interface BarefootBuildManifest {
|
|
|
63
63
|
*/
|
|
64
64
|
export declare function manifestToScriptUrls(manifest: BarefootBuildManifest, base: string): string[];
|
|
65
65
|
export declare function relPathFromComponentsBase(p: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* Shape of `barefoot-externals.json`, written by `bf build` when
|
|
68
|
+
* `externals` / `bundleEntries` are configured. Only the fields
|
|
69
|
+
* `BfImportMap` consumes are typed here; the build also emits an
|
|
70
|
+
* `externals` array (the `--external` list) which the importmap
|
|
71
|
+
* doesn't need. Fields are optional so a partial/hand-written
|
|
72
|
+
* manifest still type-checks. See issue #1639.
|
|
73
|
+
*/
|
|
74
|
+
export interface BarefootExternalsManifest {
|
|
75
|
+
/** Entries for the `<script type="importmap">`. */
|
|
76
|
+
importmap?: {
|
|
77
|
+
imports?: Record<string, string>;
|
|
78
|
+
};
|
|
79
|
+
/** URLs to emit as `<link rel="modulepreload">`. */
|
|
80
|
+
preloads?: string[];
|
|
81
|
+
}
|
|
66
82
|
export interface BfImportMapProps {
|
|
67
83
|
/** Base URL where the runtime + component bundles are served. */
|
|
68
84
|
base: string;
|
|
85
|
+
/**
|
|
86
|
+
* Contents of `barefoot-externals.json` (import it and pass it
|
|
87
|
+
* through). Its `importmap.imports` are merged on top of the
|
|
88
|
+
* built-in `@barefootjs/client*` mappings so islands importing
|
|
89
|
+
* configured externals (e.g. `zod`, `@barefootjs/form`) resolve in
|
|
90
|
+
* the browser. When omitted, only the `@barefootjs/client*`
|
|
91
|
+
* mappings are emitted — the pre-#1639 behavior.
|
|
92
|
+
*/
|
|
93
|
+
externals?: BarefootExternalsManifest;
|
|
94
|
+
/**
|
|
95
|
+
* Whether to also emit `<link rel="modulepreload">` for the
|
|
96
|
+
* manifest's `preloads`. Defaults to `true`; set `false` to emit
|
|
97
|
+
* the importmap only.
|
|
98
|
+
*/
|
|
99
|
+
preload?: boolean;
|
|
69
100
|
}
|
|
70
101
|
/**
|
|
71
102
|
* Emits the `<script type="importmap">` that maps the bare
|
|
72
103
|
* `@barefootjs/client` / `@barefootjs/client/runtime` specifiers to
|
|
73
|
-
* the runtime bundle
|
|
104
|
+
* the runtime bundle, plus any externals from `barefoot-externals.json`
|
|
105
|
+
* passed via the `externals` prop. Also emits `<link rel="modulepreload">`
|
|
106
|
+
* for the manifest's `preloads` unless `preload` is `false`. Place in
|
|
107
|
+
* `<head>`.
|
|
74
108
|
*/
|
|
75
109
|
export declare function BfImportMap(props: BfImportMapProps): HtmlEscapedString | Promise<HtmlEscapedString>;
|
|
76
110
|
export interface BfScriptsProps {
|
package/dist/app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAE7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAQxD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACpC,CAAC,aAAa,EAAE,MAAM,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,SAAS,CAAA;CAChF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,qBAAqB,EAC/B,IAAI,EAAE,MAAM,GACX,MAAM,EAAE,CAWV;AAED,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3D;AAID,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAE7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAQxD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACpC,CAAC,aAAa,EAAE,MAAM,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,SAAS,CAAA;CAChF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,qBAAqB,EAC/B,IAAI,EAAE,MAAM,GACX,MAAM,EAAE,CAWV;AAED,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3D;AAID;;;;;;;GAOG;AACH,MAAM,WAAW,yBAAyB;IACxC,mDAAmD;IACnD,SAAS,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAA;IAChD,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,yBAAyB,CAAA;IACrC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAkBnG;AAOD,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAA;IACZ,6DAA6D;IAC7D,QAAQ,EAAE,qBAAqB,CAAA;CAChC;AAQD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAa/F;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,GAAE,gBAAqB,GAAG,iBAAiB,GAAG,IAAI,CAelF;AAID,MAAM,WAAW,wBAAwB;IACvC,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;;OAMG;IACH,OAAO,EAAE,OAAO,CAAA;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,wBAAwB,GAAG,iBAAiB,CAanF"}
|
package/dist/app.js
CHANGED
|
@@ -84,13 +84,18 @@ function relPathFromComponentsBase(p) {
|
|
|
84
84
|
}
|
|
85
85
|
function BfImportMap(props) {
|
|
86
86
|
const base = props.base.replace(/\/$/, "");
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
});
|
|
93
|
-
|
|
87
|
+
const imports = {
|
|
88
|
+
"@barefootjs/client": `${base}/barefoot.js`,
|
|
89
|
+
"@barefootjs/client/runtime": `${base}/barefoot.js`,
|
|
90
|
+
...props.externals?.importmap?.imports ?? {}
|
|
91
|
+
};
|
|
92
|
+
const json = JSON.stringify({ imports });
|
|
93
|
+
const preloads = props.preload === false ? [] : props.externals?.preloads ?? [];
|
|
94
|
+
const links = preloads.map((href) => `<link rel="modulepreload" href="${escapeAttr(href)}">`).join("");
|
|
95
|
+
return html`<script type="importmap">${raw(json)}</script>${raw(links)}`;
|
|
96
|
+
}
|
|
97
|
+
function escapeAttr(value) {
|
|
98
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
94
99
|
}
|
|
95
100
|
var __bfEmptyManifestWarned = false;
|
|
96
101
|
function BfScripts(props) {
|
package/dist/scripts.js
CHANGED
|
@@ -84,13 +84,18 @@ function relPathFromComponentsBase(p) {
|
|
|
84
84
|
}
|
|
85
85
|
function BfImportMap(props) {
|
|
86
86
|
const base = props.base.replace(/\/$/, "");
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
});
|
|
93
|
-
|
|
87
|
+
const imports = {
|
|
88
|
+
"@barefootjs/client": `${base}/barefoot.js`,
|
|
89
|
+
"@barefootjs/client/runtime": `${base}/barefoot.js`,
|
|
90
|
+
...props.externals?.importmap?.imports ?? {}
|
|
91
|
+
};
|
|
92
|
+
const json = JSON.stringify({ imports });
|
|
93
|
+
const preloads = props.preload === false ? [] : props.externals?.preloads ?? [];
|
|
94
|
+
const links = preloads.map((href) => `<link rel="modulepreload" href="${escapeAttr(href)}">`).join("");
|
|
95
|
+
return html`<script type="importmap">${raw(json)}</script>${raw(links)}`;
|
|
96
|
+
}
|
|
97
|
+
function escapeAttr(value) {
|
|
98
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
94
99
|
}
|
|
95
100
|
var __bfEmptyManifestWarned = false;
|
|
96
101
|
function BfScripts(props) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/hono",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Hono integration for BarefootJS",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -101,9 +101,9 @@
|
|
|
101
101
|
"directory": "packages/adapter-hono"
|
|
102
102
|
},
|
|
103
103
|
"peerDependencies": {
|
|
104
|
-
"@barefootjs/client": "0.2.0",
|
|
105
|
-
"@barefootjs/jsx": "0.2.0",
|
|
106
|
-
"@barefootjs/shared": "0.2.0",
|
|
104
|
+
"@barefootjs/client": ">=0.2.0",
|
|
105
|
+
"@barefootjs/jsx": ">=0.2.0",
|
|
106
|
+
"@barefootjs/shared": ">=0.2.0",
|
|
107
107
|
"hono": "^4.0.0"
|
|
108
108
|
},
|
|
109
109
|
"devDependencies": {
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BfImportMap tests
|
|
3
|
+
*
|
|
4
|
+
* Verifies the importmap merges configured externals from
|
|
5
|
+
* `barefoot-externals.json` (issue #1639) and emits modulepreload
|
|
6
|
+
* links, while preserving the pre-#1639 `@barefootjs/client*` defaults
|
|
7
|
+
* when no externals are passed.
|
|
8
|
+
*/
|
|
9
|
+
import { describe, test, expect } from 'bun:test'
|
|
10
|
+
import { BfImportMap, type BarefootExternalsManifest } from '../app'
|
|
11
|
+
|
|
12
|
+
function parseImportMap(html: string): Record<string, string> {
|
|
13
|
+
const match = html.match(/<script type="importmap">(.*?)<\/script>/s)
|
|
14
|
+
if (!match) throw new Error(`no importmap in: ${html}`)
|
|
15
|
+
return JSON.parse(match[1]).imports
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe('BfImportMap', () => {
|
|
19
|
+
test('emits @barefootjs/client defaults when no externals passed', () => {
|
|
20
|
+
const html = String(BfImportMap({ base: '/components' }))
|
|
21
|
+
expect(parseImportMap(html)).toEqual({
|
|
22
|
+
'@barefootjs/client': '/components/barefoot.js',
|
|
23
|
+
'@barefootjs/client/runtime': '/components/barefoot.js',
|
|
24
|
+
})
|
|
25
|
+
expect(html).not.toContain('modulepreload')
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test('strips trailing slash from base', () => {
|
|
29
|
+
const html = String(BfImportMap({ base: '/components/' }))
|
|
30
|
+
expect(parseImportMap(html)['@barefootjs/client']).toBe('/components/barefoot.js')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('merges externals importmap on top of the client defaults', () => {
|
|
34
|
+
const externals: BarefootExternalsManifest = {
|
|
35
|
+
importmap: {
|
|
36
|
+
imports: {
|
|
37
|
+
zod: 'https://esm.sh/zod@4.4.3',
|
|
38
|
+
'@barefootjs/form': '/components/form.js',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
preloads: [],
|
|
42
|
+
}
|
|
43
|
+
const imports = parseImportMap(String(BfImportMap({ base: '/components', externals })))
|
|
44
|
+
expect(imports).toEqual({
|
|
45
|
+
'@barefootjs/client': '/components/barefoot.js',
|
|
46
|
+
'@barefootjs/client/runtime': '/components/barefoot.js',
|
|
47
|
+
zod: 'https://esm.sh/zod@4.4.3',
|
|
48
|
+
'@barefootjs/form': '/components/form.js',
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test('manifest @barefootjs/client mapping wins over the prop-derived one', () => {
|
|
53
|
+
const externals: BarefootExternalsManifest = {
|
|
54
|
+
importmap: { imports: { '@barefootjs/client': '/vendor/barefoot.js' } },
|
|
55
|
+
}
|
|
56
|
+
const imports = parseImportMap(String(BfImportMap({ base: '/components', externals })))
|
|
57
|
+
expect(imports['@barefootjs/client']).toBe('/vendor/barefoot.js')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test('emits modulepreload links for manifest preloads', () => {
|
|
61
|
+
const externals: BarefootExternalsManifest = {
|
|
62
|
+
importmap: { imports: {} },
|
|
63
|
+
preloads: ['/components/form.js', 'https://esm.sh/zod@4.4.3'],
|
|
64
|
+
}
|
|
65
|
+
const html = String(BfImportMap({ base: '/components', externals }))
|
|
66
|
+
expect(html).toContain('<link rel="modulepreload" href="/components/form.js">')
|
|
67
|
+
expect(html).toContain('<link rel="modulepreload" href="https://esm.sh/zod@4.4.3">')
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
test('preload=false suppresses modulepreload links', () => {
|
|
71
|
+
const externals: BarefootExternalsManifest = {
|
|
72
|
+
preloads: ['/components/form.js'],
|
|
73
|
+
}
|
|
74
|
+
const html = String(BfImportMap({ base: '/components', externals, preload: false }))
|
|
75
|
+
expect(html).not.toContain('modulepreload')
|
|
76
|
+
// importmap still emitted
|
|
77
|
+
expect(parseImportMap(html)['@barefootjs/client']).toBe('/components/barefoot.js')
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
test('escapes double quotes in preload hrefs', () => {
|
|
81
|
+
const externals: BarefootExternalsManifest = {
|
|
82
|
+
preloads: ['/components/"onerror=alert(1).js'],
|
|
83
|
+
}
|
|
84
|
+
const html = String(BfImportMap({ base: '/components', externals }))
|
|
85
|
+
expect(html).not.toContain('"onerror=alert(1)')
|
|
86
|
+
expect(html).toContain('"onerror=alert(1)')
|
|
87
|
+
})
|
|
88
|
+
})
|
package/src/app.ts
CHANGED
|
@@ -88,25 +88,72 @@ export function relPathFromComponentsBase(p: string): string {
|
|
|
88
88
|
|
|
89
89
|
// ── JSX components ─────────────────────────────────────────────────────────
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Shape of `barefoot-externals.json`, written by `bf build` when
|
|
93
|
+
* `externals` / `bundleEntries` are configured. Only the fields
|
|
94
|
+
* `BfImportMap` consumes are typed here; the build also emits an
|
|
95
|
+
* `externals` array (the `--external` list) which the importmap
|
|
96
|
+
* doesn't need. Fields are optional so a partial/hand-written
|
|
97
|
+
* manifest still type-checks. See issue #1639.
|
|
98
|
+
*/
|
|
99
|
+
export interface BarefootExternalsManifest {
|
|
100
|
+
/** Entries for the `<script type="importmap">`. */
|
|
101
|
+
importmap?: { imports?: Record<string, string> }
|
|
102
|
+
/** URLs to emit as `<link rel="modulepreload">`. */
|
|
103
|
+
preloads?: string[]
|
|
104
|
+
}
|
|
105
|
+
|
|
91
106
|
export interface BfImportMapProps {
|
|
92
107
|
/** Base URL where the runtime + component bundles are served. */
|
|
93
108
|
base: string
|
|
109
|
+
/**
|
|
110
|
+
* Contents of `barefoot-externals.json` (import it and pass it
|
|
111
|
+
* through). Its `importmap.imports` are merged on top of the
|
|
112
|
+
* built-in `@barefootjs/client*` mappings so islands importing
|
|
113
|
+
* configured externals (e.g. `zod`, `@barefootjs/form`) resolve in
|
|
114
|
+
* the browser. When omitted, only the `@barefootjs/client*`
|
|
115
|
+
* mappings are emitted — the pre-#1639 behavior.
|
|
116
|
+
*/
|
|
117
|
+
externals?: BarefootExternalsManifest
|
|
118
|
+
/**
|
|
119
|
+
* Whether to also emit `<link rel="modulepreload">` for the
|
|
120
|
+
* manifest's `preloads`. Defaults to `true`; set `false` to emit
|
|
121
|
+
* the importmap only.
|
|
122
|
+
*/
|
|
123
|
+
preload?: boolean
|
|
94
124
|
}
|
|
95
125
|
|
|
96
126
|
/**
|
|
97
127
|
* Emits the `<script type="importmap">` that maps the bare
|
|
98
128
|
* `@barefootjs/client` / `@barefootjs/client/runtime` specifiers to
|
|
99
|
-
* the runtime bundle
|
|
129
|
+
* the runtime bundle, plus any externals from `barefoot-externals.json`
|
|
130
|
+
* passed via the `externals` prop. Also emits `<link rel="modulepreload">`
|
|
131
|
+
* for the manifest's `preloads` unless `preload` is `false`. Place in
|
|
132
|
+
* `<head>`.
|
|
100
133
|
*/
|
|
101
134
|
export function BfImportMap(props: BfImportMapProps): HtmlEscapedString | Promise<HtmlEscapedString> {
|
|
102
135
|
const base = props.base.replace(/\/$/, '')
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
136
|
+
// Built-in defaults first, then manifest imports so a configured
|
|
137
|
+
// `@barefootjs/client` mapping (emitted by `bf build` against the
|
|
138
|
+
// build's `externalsBasePath`) wins over the prop-derived one.
|
|
139
|
+
const imports: Record<string, string> = {
|
|
140
|
+
'@barefootjs/client': `${base}/barefoot.js`,
|
|
141
|
+
'@barefootjs/client/runtime': `${base}/barefoot.js`,
|
|
142
|
+
...(props.externals?.importmap?.imports ?? {}),
|
|
143
|
+
}
|
|
144
|
+
const json = JSON.stringify({ imports })
|
|
145
|
+
|
|
146
|
+
const preloads = props.preload === false ? [] : props.externals?.preloads ?? []
|
|
147
|
+
const links = preloads
|
|
148
|
+
.map((href) => `<link rel="modulepreload" href="${escapeAttr(href)}">`)
|
|
149
|
+
.join('')
|
|
150
|
+
|
|
151
|
+
return html`<script type="importmap">${raw(json)}</script>${raw(links)}`
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Minimal double-quoted-attribute escaping for config-derived URLs. */
|
|
155
|
+
function escapeAttr(value: string): string {
|
|
156
|
+
return value.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<')
|
|
110
157
|
}
|
|
111
158
|
|
|
112
159
|
export interface BfScriptsProps {
|