@seanhogg/builderforce-webcontainers-core 2026.10.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/LICENSE +21 -0
- package/README.md +20 -0
- package/dist/attribution.d.ts +22 -0
- package/dist/attribution.d.ts.map +1 -0
- package/dist/attribution.js +50 -0
- package/dist/attribution.js.map +1 -0
- package/dist/compileScript.d.ts +31 -0
- package/dist/compileScript.d.ts.map +1 -0
- package/dist/compileScript.js +75 -0
- package/dist/compileScript.js.map +1 -0
- package/dist/detectProject.d.ts +16 -0
- package/dist/detectProject.d.ts.map +1 -0
- package/dist/detectProject.js +49 -0
- package/dist/detectProject.js.map +1 -0
- package/dist/devServer.d.ts +46 -0
- package/dist/devServer.d.ts.map +1 -0
- package/dist/devServer.js +136 -0
- package/dist/devServer.js.map +1 -0
- package/dist/html.d.ts +17 -0
- package/dist/html.d.ts.map +1 -0
- package/dist/html.js +46 -0
- package/dist/html.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/mime.d.ts +3 -0
- package/dist/mime.d.ts.map +1 -0
- package/dist/mime.js +35 -0
- package/dist/mime.js.map +1 -0
- package/dist/packageCdn.d.ts +19 -0
- package/dist/packageCdn.d.ts.map +1 -0
- package/dist/packageCdn.js +29 -0
- package/dist/packageCdn.js.map +1 -0
- package/dist/paths.d.ts +12 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +36 -0
- package/dist/paths.js.map +1 -0
- package/dist/projectConfig.d.ts +36 -0
- package/dist/projectConfig.d.ts.map +1 -0
- package/dist/projectConfig.js +155 -0
- package/dist/projectConfig.js.map +1 -0
- package/dist/resolve.d.ts +19 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +62 -0
- package/dist/resolve.js.map +1 -0
- package/dist/rewriteImports.d.ts +11 -0
- package/dist/rewriteImports.d.ts.map +1 -0
- package/dist/rewriteImports.js +28 -0
- package/dist/rewriteImports.js.map +1 -0
- package/dist/styleModules.d.ts +12 -0
- package/dist/styleModules.d.ts.map +1 -0
- package/dist/styleModules.js +53 -0
- package/dist/styleModules.js.map +1 -0
- package/dist/transformer.d.ts +42 -0
- package/dist/transformer.d.ts.map +1 -0
- package/dist/transformer.js +39 -0
- package/dist/transformer.js.map +1 -0
- package/dist/vfs.d.ts +57 -0
- package/dist/vfs.d.ts.map +1 -0
- package/dist/vfs.js +114 -0
- package/dist/vfs.js.map +1 -0
- package/package.json +67 -0
- package/src/attribution.ts +57 -0
- package/src/compileScript.ts +87 -0
- package/src/detectProject.ts +66 -0
- package/src/devServer.ts +156 -0
- package/src/html.ts +58 -0
- package/src/index.ts +20 -0
- package/src/mime.ts +36 -0
- package/src/packageCdn.ts +48 -0
- package/src/paths.ts +37 -0
- package/src/projectConfig.ts +157 -0
- package/src/resolve.ts +60 -0
- package/src/rewriteImports.ts +26 -0
- package/src/styleModules.ts +57 -0
- package/src/transformer.ts +76 -0
- package/src/vfs.ts +135 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sean Hogg
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# @seanhogg/builderforce-webcontainers-core
|
|
2
|
+
|
|
3
|
+
The runtime-agnostic dev server behind
|
|
4
|
+
[BuilderForce WebContainers](https://github.com/SeanHogg/builderforce-webcontainers).
|
|
5
|
+
It turns a project held in a `VirtualFileSystem` into browser-ready responses:
|
|
6
|
+
compiled ES modules, CSS/JSON/asset wrappers and the HTML document. It never
|
|
7
|
+
listens on anything; you call `handle(path, search)`.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import * as esbuild from 'esbuild';
|
|
11
|
+
import { VirtualFileSystem, DevServer, createEsbuildTransformer } from '@seanhogg/builderforce-webcontainers-core';
|
|
12
|
+
|
|
13
|
+
const fs = new VirtualFileSystem();
|
|
14
|
+
fs.mount({ 'index.html': '...', 'src/main.tsx': '...' });
|
|
15
|
+
const server = new DevServer({ fs, transformer: createEsbuildTransformer(esbuild), base: '/preview/' });
|
|
16
|
+
const res = await server.handle('/src/main.tsx'); // { status, headers, body }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
For the in-browser runtime, use
|
|
20
|
+
[`@seanhogg/builderforce-webcontainers`](../browser). MIT licensed.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The "Built with Builderforce.ai" badge, on by default in every preview.
|
|
3
|
+
*
|
|
4
|
+
* It is a DEFAULT, not a licence condition: the project stays MIT, and a host turns
|
|
5
|
+
* it off with `attribution: false`. Keeping it on is how this runtime pays for
|
|
6
|
+
* itself, and the README asks forks to leave it.
|
|
7
|
+
*
|
|
8
|
+
* The badge lives in a shadow root, so the previewed app's CSS can't restyle or hide
|
|
9
|
+
* it by accident and the badge's styles can't leak into the app. It follows the
|
|
10
|
+
* system light/dark preference and sits in the bottom-right corner, small enough
|
|
11
|
+
* not to cover app UI on a phone-width screen.
|
|
12
|
+
*/
|
|
13
|
+
export declare const ATTRIBUTION_URL = "https://builderforce.ai/?utm_source=webcontainers&utm_medium=badge&utm_campaign=preview";
|
|
14
|
+
export declare const ATTRIBUTION_LABEL = "Built with Builderforce.ai";
|
|
15
|
+
export interface AttributionOptions {
|
|
16
|
+
href?: string;
|
|
17
|
+
label?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function attributionScript(options?: AttributionOptions): string;
|
|
20
|
+
/** Append the badge before `</body>` (or at the end of a fragment). */
|
|
21
|
+
export declare function injectAttribution(html: string, options?: AttributionOptions): string;
|
|
22
|
+
//# sourceMappingURL=attribution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribution.d.ts","sourceRoot":"","sources":["../src/attribution.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,eAAe,4FAA4F,CAAC;AACzH,eAAO,MAAM,iBAAiB,+BAA+B,CAAC;AAE9D,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB,GAAG,MAAM,CA6B1E;AAED,uEAAuE;AACvE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAGpF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The "Built with Builderforce.ai" badge, on by default in every preview.
|
|
3
|
+
*
|
|
4
|
+
* It is a DEFAULT, not a licence condition: the project stays MIT, and a host turns
|
|
5
|
+
* it off with `attribution: false`. Keeping it on is how this runtime pays for
|
|
6
|
+
* itself, and the README asks forks to leave it.
|
|
7
|
+
*
|
|
8
|
+
* The badge lives in a shadow root, so the previewed app's CSS can't restyle or hide
|
|
9
|
+
* it by accident and the badge's styles can't leak into the app. It follows the
|
|
10
|
+
* system light/dark preference and sits in the bottom-right corner, small enough
|
|
11
|
+
* not to cover app UI on a phone-width screen.
|
|
12
|
+
*/
|
|
13
|
+
export const ATTRIBUTION_URL = 'https://builderforce.ai/?utm_source=webcontainers&utm_medium=badge&utm_campaign=preview';
|
|
14
|
+
export const ATTRIBUTION_LABEL = 'Built with Builderforce.ai';
|
|
15
|
+
export function attributionScript(options = {}) {
|
|
16
|
+
const href = JSON.stringify(options.href ?? ATTRIBUTION_URL);
|
|
17
|
+
const label = JSON.stringify(options.label ?? ATTRIBUTION_LABEL);
|
|
18
|
+
const css = [
|
|
19
|
+
':host{all:initial;position:fixed;right:8px;bottom:8px;z-index:2147483647}',
|
|
20
|
+
'a{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:999px;',
|
|
21
|
+
'font:500 12px/1.4 system-ui,-apple-system,Segoe UI,sans-serif;text-decoration:none;',
|
|
22
|
+
'background:rgba(255,255,255,.92);color:#1f2328;border:1px solid rgba(31,35,40,.15);',
|
|
23
|
+
'box-shadow:0 1px 3px rgba(0,0,0,.12)}',
|
|
24
|
+
'a:hover{text-decoration:underline}',
|
|
25
|
+
'@media (prefers-color-scheme:dark){a{background:rgba(22,27,34,.92);color:#e6edf3;border-color:rgba(230,237,243,.18)}}',
|
|
26
|
+
'@media print{:host{display:none}}',
|
|
27
|
+
].join('');
|
|
28
|
+
return `<script>(function(){
|
|
29
|
+
if (document.getElementById('bfwc-attribution')) return;
|
|
30
|
+
var mount = function () {
|
|
31
|
+
var host = document.createElement('bfwc-attribution');
|
|
32
|
+
host.id = 'bfwc-attribution';
|
|
33
|
+
var root = host.attachShadow({ mode: 'closed' });
|
|
34
|
+
var style = document.createElement('style');
|
|
35
|
+
style.textContent = ${JSON.stringify(css)};
|
|
36
|
+
var a = document.createElement('a');
|
|
37
|
+
a.href = ${href}; a.target = '_blank'; a.rel = 'noopener';
|
|
38
|
+
a.textContent = ${label};
|
|
39
|
+
root.appendChild(style); root.appendChild(a);
|
|
40
|
+
document.body.appendChild(host);
|
|
41
|
+
};
|
|
42
|
+
if (document.body) mount(); else addEventListener('DOMContentLoaded', mount);
|
|
43
|
+
})();</script>`;
|
|
44
|
+
}
|
|
45
|
+
/** Append the badge before `</body>` (or at the end of a fragment). */
|
|
46
|
+
export function injectAttribution(html, options) {
|
|
47
|
+
const badge = attributionScript(options);
|
|
48
|
+
return /<\/body>/i.test(html) ? html.replace(/<\/body>(?![\s\S]*<\/body>)/i, `${badge}\n</body>`) : html + badge;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=attribution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribution.js","sourceRoot":"","sources":["../src/attribution.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,yFAAyF,CAAC;AACzH,MAAM,CAAC,MAAM,iBAAiB,GAAG,4BAA4B,CAAC;AAO9D,MAAM,UAAU,iBAAiB,CAAC,UAA8B,EAAE;IAChE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,IAAI,eAAe,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,IAAI,iBAAiB,CAAC,CAAC;IACjE,MAAM,GAAG,GAAG;QACV,2EAA2E;QAC3E,wFAAwF;QACxF,qFAAqF;QACrF,qFAAqF;QACrF,uCAAuC;QACvC,oCAAoC;QACpC,uHAAuH;QACvH,mCAAmC;KACpC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACX,OAAO;;;;;;;0BAOiB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;;eAE9B,IAAI;sBACG,KAAK;;;;;eAKZ,CAAC;AAChB,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,OAA4B;IAC1E,MAAM,KAAK,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACzC,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,8BAA8B,EAAE,GAAG,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC;AACnH,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { VirtualFileSystem } from './vfs.js';
|
|
2
|
+
import type { ProjectConfig } from './projectConfig.js';
|
|
3
|
+
import type { PackageCdn } from './packageCdn.js';
|
|
4
|
+
import type { Transformer } from './transformer.js';
|
|
5
|
+
export interface CompileContext {
|
|
6
|
+
fs: VirtualFileSystem;
|
|
7
|
+
config: ProjectConfig;
|
|
8
|
+
cdn: PackageCdn;
|
|
9
|
+
transformer: Transformer;
|
|
10
|
+
/** Preview base URL, ending in `/`. */
|
|
11
|
+
base: string;
|
|
12
|
+
}
|
|
13
|
+
/** Vite-style import queries this runtime honours. */
|
|
14
|
+
export type ImportQuery = 'import' | 'raw' | 'url';
|
|
15
|
+
/**
|
|
16
|
+
* The URL a resolved VFS file is imported by. Scripts are served as-is; CSS and
|
|
17
|
+
* JSON need the `?import` JS wrapper; anything else imported from JS (images,
|
|
18
|
+
* fonts) exports its URL, as in Vite.
|
|
19
|
+
*/
|
|
20
|
+
export declare function moduleUrl(base: string, path: string, query?: ImportQuery): string;
|
|
21
|
+
/**
|
|
22
|
+
* Map one import specifier to the URL the browser should fetch. Undefined leaves
|
|
23
|
+
* it unchanged: URLs, `node:` builtins, and local paths that do not resolve (the
|
|
24
|
+
* browser's 404 then surfaces through the error bridge).
|
|
25
|
+
*/
|
|
26
|
+
export declare function mapSpecifier(ctx: CompileContext, fromDir: string, specifier: string): string | undefined;
|
|
27
|
+
/** Compile-time constants: Vite's `import.meta.env` and CRA's `process.env.REACT_APP_*`. */
|
|
28
|
+
export declare function buildDefine(config: ProjectConfig, base: string): Record<string, string>;
|
|
29
|
+
/** TS/JSX → an ES module whose imports point at preview and CDN URLs. */
|
|
30
|
+
export declare function compileScript(ctx: CompileContext, path: string): Promise<string>;
|
|
31
|
+
//# sourceMappingURL=compileScript.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compileScript.d.ts","sourceRoot":"","sources":["../src/compileScript.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAMpD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,iBAAiB,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,GAAG,EAAE,UAAU,CAAC;IAChB,WAAW,EAAE,WAAW,CAAC;IACzB,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,sDAAsD;AACtD,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC;AAEnD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,CAOjF;AASD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAYxG;AAED,4FAA4F;AAC5F,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASvF;AAED,yEAAyE;AACzE,wBAAsB,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAYtF"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { loaderFor } from './transformer.js';
|
|
2
|
+
import { dirname, extname } from './paths.js';
|
|
3
|
+
import { isBareSpecifier, resolveAlias, resolveLocal, splitPackageSpecifier } from './resolve.js';
|
|
4
|
+
import { rewriteImports } from './rewriteImports.js';
|
|
5
|
+
/**
|
|
6
|
+
* The URL a resolved VFS file is imported by. Scripts are served as-is; CSS and
|
|
7
|
+
* JSON need the `?import` JS wrapper; anything else imported from JS (images,
|
|
8
|
+
* fonts) exports its URL, as in Vite.
|
|
9
|
+
*/
|
|
10
|
+
export function moduleUrl(base, path, query) {
|
|
11
|
+
const url = base + path.slice(1);
|
|
12
|
+
if (query === 'raw' || query === 'url')
|
|
13
|
+
return `${url}?${query}`;
|
|
14
|
+
const ext = extname(path);
|
|
15
|
+
if (loaderFor(ext))
|
|
16
|
+
return url;
|
|
17
|
+
if (ext === '.css' || ext === '.json')
|
|
18
|
+
return `${url}?import`;
|
|
19
|
+
return `${url}?url`;
|
|
20
|
+
}
|
|
21
|
+
function splitQuery(specifier) {
|
|
22
|
+
const at = specifier.indexOf('?');
|
|
23
|
+
if (at < 0)
|
|
24
|
+
return { path: specifier };
|
|
25
|
+
const query = specifier.slice(at + 1);
|
|
26
|
+
return { path: specifier.slice(0, at), query: query === 'raw' || query === 'url' ? query : undefined };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Map one import specifier to the URL the browser should fetch. Undefined leaves
|
|
30
|
+
* it unchanged: URLs, `node:` builtins, and local paths that do not resolve (the
|
|
31
|
+
* browser's 404 then surfaces through the error bridge).
|
|
32
|
+
*/
|
|
33
|
+
export function mapSpecifier(ctx, fromDir, specifier) {
|
|
34
|
+
if (/^(https?:|data:|blob:|node:)/i.test(specifier))
|
|
35
|
+
return undefined;
|
|
36
|
+
const { path, query } = splitQuery(specifier);
|
|
37
|
+
if (isBareSpecifier(path)) {
|
|
38
|
+
const aliased = resolveAlias(ctx.fs, ctx.config.aliases, path);
|
|
39
|
+
if (aliased)
|
|
40
|
+
return moduleUrl(ctx.base, aliased, query);
|
|
41
|
+
const { name, subpath } = splitPackageSpecifier(path);
|
|
42
|
+
return ctx.cdn.urlFor(name, subpath);
|
|
43
|
+
}
|
|
44
|
+
const resolved = resolveLocal(ctx.fs, fromDir, path);
|
|
45
|
+
return resolved ? moduleUrl(ctx.base, resolved, query) : undefined;
|
|
46
|
+
}
|
|
47
|
+
/** Compile-time constants: Vite's `import.meta.env` and CRA's `process.env.REACT_APP_*`. */
|
|
48
|
+
export function buildDefine(config, base) {
|
|
49
|
+
const env = { MODE: 'development', DEV: true, PROD: false, SSR: false, BASE_URL: base };
|
|
50
|
+
const define = { 'process.env.NODE_ENV': '"development"' };
|
|
51
|
+
for (const [key, value] of Object.entries(config.env)) {
|
|
52
|
+
if (key.startsWith('VITE_'))
|
|
53
|
+
env[key] = value;
|
|
54
|
+
if (key.startsWith('VITE_') || key.startsWith('REACT_APP_'))
|
|
55
|
+
define[`process.env.${key}`] = JSON.stringify(value);
|
|
56
|
+
}
|
|
57
|
+
define['import.meta.env'] = JSON.stringify(env);
|
|
58
|
+
return define;
|
|
59
|
+
}
|
|
60
|
+
/** TS/JSX → an ES module whose imports point at preview and CDN URLs. */
|
|
61
|
+
export async function compileScript(ctx, path) {
|
|
62
|
+
const loader = loaderFor(extname(path));
|
|
63
|
+
if (!loader)
|
|
64
|
+
throw new Error(`Not a script: ${path}`);
|
|
65
|
+
const source = ctx.fs.readText(path) ?? '';
|
|
66
|
+
const { code } = await ctx.transformer.transform(source, {
|
|
67
|
+
loader,
|
|
68
|
+
sourcefile: path,
|
|
69
|
+
define: buildDefine(ctx.config, ctx.base),
|
|
70
|
+
jsx: ctx.config.jsx,
|
|
71
|
+
});
|
|
72
|
+
const fromDir = dirname(path);
|
|
73
|
+
return rewriteImports(code, (specifier) => mapSpecifier(ctx, fromDir, specifier));
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=compileScript.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compileScript.js","sourceRoot":"","sources":["../src/compileScript.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { VirtualFileSystem } from './vfs.js';
|
|
2
|
+
export type ProjectKind = 'vite' | 'cra' | 'static';
|
|
3
|
+
export interface ProjectProfile {
|
|
4
|
+
supported: boolean;
|
|
5
|
+
kind?: ProjectKind;
|
|
6
|
+
/** The HTML document served at `/`. */
|
|
7
|
+
htmlPath?: string;
|
|
8
|
+
/** Script injected when the HTML has no module entry of its own (CRA). */
|
|
9
|
+
entry?: string;
|
|
10
|
+
/** Files served from the site root, Vite/CRA `public/` convention. */
|
|
11
|
+
publicDir: string;
|
|
12
|
+
/** Why the project needs a full Node runtime instead — shown to the user. */
|
|
13
|
+
reason?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function detectProject(fs: VirtualFileSystem): ProjectProfile;
|
|
16
|
+
//# sourceMappingURL=detectProject.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detectProject.d.ts","sourceRoot":"","sources":["../src/detectProject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAGlD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEpD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAkCD,wBAAgB,aAAa,CAAC,EAAE,EAAE,iBAAiB,GAAG,cAAc,CAenE"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { RESOLVE_EXTENSIONS } from './resolve.js';
|
|
2
|
+
/**
|
|
3
|
+
* Frameworks that need a server or a compiler this runtime does not have yet.
|
|
4
|
+
* Data, not branches: supporting one later means deleting its row.
|
|
5
|
+
*/
|
|
6
|
+
const NEEDS_NODE = [
|
|
7
|
+
{ dependency: 'next', reason: 'Next.js needs its Node server.' },
|
|
8
|
+
{ dependency: 'nuxt', reason: 'Nuxt needs its Node server.' },
|
|
9
|
+
{ dependency: '@remix-run/dev', reason: 'Remix needs its Node server.' },
|
|
10
|
+
{ dependency: '@sveltejs/kit', reason: 'SvelteKit needs its Node server.' },
|
|
11
|
+
{ dependency: 'astro', reason: 'Astro needs its build pipeline.' },
|
|
12
|
+
{ dependency: 'svelte', reason: 'Svelte components need the Svelte compiler.' },
|
|
13
|
+
{ dependency: 'vue', reason: 'Vue single-file components need the Vue compiler.' },
|
|
14
|
+
];
|
|
15
|
+
const SERVER_ONLY = ['express', 'fastify', 'koa', '@nestjs/core', '@hapi/hapi'];
|
|
16
|
+
function readDependencyNames(fs) {
|
|
17
|
+
try {
|
|
18
|
+
const pkg = JSON.parse(fs.readText('/package.json') ?? '{}');
|
|
19
|
+
return new Set([...Object.keys(pkg.dependencies ?? {}), ...Object.keys(pkg.devDependencies ?? {})]);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return new Set();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function findEntry(fs) {
|
|
26
|
+
for (const stem of ['/src/index', '/src/main']) {
|
|
27
|
+
for (const ext of RESOLVE_EXTENSIONS)
|
|
28
|
+
if (fs.isFile(stem + ext))
|
|
29
|
+
return stem + ext;
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
export function detectProject(fs) {
|
|
34
|
+
const deps = readDependencyNames(fs);
|
|
35
|
+
const blocker = NEEDS_NODE.find((row) => deps.has(row.dependency));
|
|
36
|
+
if (blocker)
|
|
37
|
+
return { supported: false, publicDir: '/public', reason: blocker.reason };
|
|
38
|
+
if (fs.isFile('/index.html')) {
|
|
39
|
+
return { supported: true, kind: deps.has('vite') ? 'vite' : 'static', htmlPath: '/index.html', publicDir: '/public' };
|
|
40
|
+
}
|
|
41
|
+
if (fs.isFile('/public/index.html')) {
|
|
42
|
+
return { supported: true, kind: 'cra', htmlPath: '/public/index.html', entry: findEntry(fs), publicDir: '/public' };
|
|
43
|
+
}
|
|
44
|
+
if (SERVER_ONLY.some((name) => deps.has(name))) {
|
|
45
|
+
return { supported: false, publicDir: '/public', reason: 'This is a Node server app with no browser entry page.' };
|
|
46
|
+
}
|
|
47
|
+
return { supported: false, publicDir: '/public', reason: 'No index.html found at the project root or in public/.' };
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=detectProject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detectProject.js","sourceRoot":"","sources":["../src/detectProject.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { VirtualFileSystem } from './vfs.js';
|
|
2
|
+
import type { Transformer } from './transformer.js';
|
|
3
|
+
import type { PackageCdn } from './packageCdn.js';
|
|
4
|
+
import { type ProjectProfile } from './detectProject.js';
|
|
5
|
+
export interface ServedFile {
|
|
6
|
+
status: number;
|
|
7
|
+
headers: Record<string, string>;
|
|
8
|
+
body: string | Uint8Array;
|
|
9
|
+
}
|
|
10
|
+
export interface DevServerOptions {
|
|
11
|
+
fs: VirtualFileSystem;
|
|
12
|
+
transformer: Transformer;
|
|
13
|
+
/** The URL the preview is served under, ending in `/` (`/__bfwc/<id>/`). */
|
|
14
|
+
base: string;
|
|
15
|
+
/** Package CDN factory, given the project's dependency ranges. Default: esm.sh. */
|
|
16
|
+
cdn?: (dependencies: Record<string, string>) => PackageCdn;
|
|
17
|
+
/** The "Built with Builderforce.ai" badge in served pages. Default true. */
|
|
18
|
+
attribution?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The dev server: request path in, response out. It does not listen on anything —
|
|
22
|
+
* the host decides how requests arrive (a service worker in the browser, a plain
|
|
23
|
+
* function call in tests), which is what keeps it runtime-agnostic.
|
|
24
|
+
*
|
|
25
|
+
* Responses are cached per (file, query) and validated against the file's VFS
|
|
26
|
+
* version. Edits to an existing file evict only that file; creating or deleting a
|
|
27
|
+
* file, or touching a config file, clears everything, since either can change how
|
|
28
|
+
* OTHER files' imports resolve.
|
|
29
|
+
*/
|
|
30
|
+
export declare class DevServer {
|
|
31
|
+
private readonly options;
|
|
32
|
+
private config?;
|
|
33
|
+
private cdn?;
|
|
34
|
+
private profileCache?;
|
|
35
|
+
private readonly cache;
|
|
36
|
+
private readonly unwatch;
|
|
37
|
+
constructor(options: DevServerOptions);
|
|
38
|
+
dispose(): void;
|
|
39
|
+
profile(): ProjectProfile;
|
|
40
|
+
handle(requestPath: string, search?: string): Promise<ServedFile>;
|
|
41
|
+
private produce;
|
|
42
|
+
private serveDocument;
|
|
43
|
+
private context;
|
|
44
|
+
private onChange;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=devServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devServer.d.ts","sourceRoot":"","sources":["../src/devServer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGlD,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAQxE,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,iBAAiB,CAAC;IACtB,WAAW,EAAE,WAAW,CAAC;IACzB,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,GAAG,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,UAAU,CAAC;IAC3D,4EAA4E;IAC5E,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAqBD;;;;;;;;;GASG;AACH,qBAAa,SAAS;IAOR,OAAO,CAAC,QAAQ,CAAC,OAAO;IANpC,OAAO,CAAC,MAAM,CAAC,CAAgB;IAC/B,OAAO,CAAC,GAAG,CAAC,CAAa;IACzB,OAAO,CAAC,YAAY,CAAC,CAAiB;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4D;IAClF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;gBAER,OAAO,EAAE,gBAAgB;IAKtD,OAAO,IAAI,IAAI;IAKf,OAAO,IAAI,cAAc;IAInB,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,OAAO,CAAC,UAAU,CAAC;YA0BrD,OAAO;IAsBrB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,OAAO;IAOf,OAAO,CAAC,QAAQ;CAWjB"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { createEsmShCdn } from './packageCdn.js';
|
|
2
|
+
import { isConfigFile, readProjectConfig } from './projectConfig.js';
|
|
3
|
+
import { detectProject } from './detectProject.js';
|
|
4
|
+
import { compileScript } from './compileScript.js';
|
|
5
|
+
import { transformHtml } from './html.js';
|
|
6
|
+
import { cssToModule, jsonToModule, rawToModule, rewriteCssUrls, urlToModule } from './styleModules.js';
|
|
7
|
+
import { loaderFor } from './transformer.js';
|
|
8
|
+
import { extname, join, normalizePath } from './paths.js';
|
|
9
|
+
import { JS_MIME, mimeFor } from './mime.js';
|
|
10
|
+
const NO_STORE = { 'cache-control': 'no-store' };
|
|
11
|
+
function reply(status, contentType, body) {
|
|
12
|
+
return { status, headers: { 'content-type': contentType, ...NO_STORE }, body };
|
|
13
|
+
}
|
|
14
|
+
/** A module that throws — evaluated in the preview, it reaches the error bridge. */
|
|
15
|
+
function errorModule(message) {
|
|
16
|
+
return reply(200, JS_MIME, `throw new Error(${JSON.stringify(message)});`);
|
|
17
|
+
}
|
|
18
|
+
function parseQuery(search) {
|
|
19
|
+
const params = new URLSearchParams(search.startsWith('?') ? search.slice(1) : search);
|
|
20
|
+
if (params.has('raw'))
|
|
21
|
+
return 'raw';
|
|
22
|
+
if (params.has('url'))
|
|
23
|
+
return 'url';
|
|
24
|
+
if (params.has('import'))
|
|
25
|
+
return 'import';
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The dev server: request path in, response out. It does not listen on anything —
|
|
30
|
+
* the host decides how requests arrive (a service worker in the browser, a plain
|
|
31
|
+
* function call in tests), which is what keeps it runtime-agnostic.
|
|
32
|
+
*
|
|
33
|
+
* Responses are cached per (file, query) and validated against the file's VFS
|
|
34
|
+
* version. Edits to an existing file evict only that file; creating or deleting a
|
|
35
|
+
* file, or touching a config file, clears everything, since either can change how
|
|
36
|
+
* OTHER files' imports resolve.
|
|
37
|
+
*/
|
|
38
|
+
export class DevServer {
|
|
39
|
+
options;
|
|
40
|
+
config;
|
|
41
|
+
cdn;
|
|
42
|
+
profileCache;
|
|
43
|
+
cache = new Map();
|
|
44
|
+
unwatch;
|
|
45
|
+
constructor(options) {
|
|
46
|
+
this.options = options;
|
|
47
|
+
if (!options.base.endsWith('/'))
|
|
48
|
+
throw new Error('DevServer base must end with "/"');
|
|
49
|
+
this.unwatch = options.fs.watch((change) => this.onChange(change));
|
|
50
|
+
}
|
|
51
|
+
dispose() {
|
|
52
|
+
this.unwatch();
|
|
53
|
+
this.cache.clear();
|
|
54
|
+
}
|
|
55
|
+
profile() {
|
|
56
|
+
return (this.profileCache ??= detectProject(this.options.fs));
|
|
57
|
+
}
|
|
58
|
+
async handle(requestPath, search = '') {
|
|
59
|
+
const { fs } = this.options;
|
|
60
|
+
const path = normalizePath(decodeURIComponent(requestPath));
|
|
61
|
+
const query = parseQuery(search);
|
|
62
|
+
const profile = this.profile();
|
|
63
|
+
if (path === '/' || path === '/index.html' || path === profile.htmlPath)
|
|
64
|
+
return this.serveDocument(profile);
|
|
65
|
+
const publicPath = join(profile.publicDir, path);
|
|
66
|
+
const file = fs.isFile(path) ? path : fs.isFile(publicPath) ? publicPath : undefined;
|
|
67
|
+
if (!file) {
|
|
68
|
+
// An extension-less path is a client-side route: serve the app (SPA fallback).
|
|
69
|
+
if (!extname(path) && !query)
|
|
70
|
+
return this.serveDocument(profile);
|
|
71
|
+
return query || loaderFor(extname(path)) ? errorModule(`Cannot find module ${path}`) : reply(404, 'text/plain; charset=utf-8', `Not found: ${path}`);
|
|
72
|
+
}
|
|
73
|
+
const key = `${file}?${query ?? ''}`;
|
|
74
|
+
const version = fs.version(file) ?? 0;
|
|
75
|
+
const hit = this.cache.get(key);
|
|
76
|
+
if (hit && hit.version === version)
|
|
77
|
+
return hit.file;
|
|
78
|
+
const served = await this.produce(file, query);
|
|
79
|
+
this.cache.set(key, { version, file: served });
|
|
80
|
+
return served;
|
|
81
|
+
}
|
|
82
|
+
async produce(file, query) {
|
|
83
|
+
const { fs, base } = this.options;
|
|
84
|
+
const ext = extname(file);
|
|
85
|
+
try {
|
|
86
|
+
if (query === 'raw')
|
|
87
|
+
return reply(200, JS_MIME, rawToModule(fs.readText(file) ?? ''));
|
|
88
|
+
if (query === 'url')
|
|
89
|
+
return reply(200, JS_MIME, urlToModule(base + file.slice(1)));
|
|
90
|
+
if (ext === '.css') {
|
|
91
|
+
const css = rewriteCssUrls(fs, file, fs.readText(file) ?? '', base);
|
|
92
|
+
return query === 'import' ? reply(200, JS_MIME, cssToModule(file, css)) : reply(200, mimeFor(ext), css);
|
|
93
|
+
}
|
|
94
|
+
if (ext === '.json' && query === 'import')
|
|
95
|
+
return reply(200, JS_MIME, jsonToModule(fs.readText(file) ?? ''));
|
|
96
|
+
if (loaderFor(ext))
|
|
97
|
+
return reply(200, JS_MIME, await compileScript(this.context(), file));
|
|
98
|
+
if (ext === '.html' || ext === '.htm') {
|
|
99
|
+
return reply(200, mimeFor(ext), transformHtml(fs.readText(file) ?? '', { base, attribution: this.options.attribution }));
|
|
100
|
+
}
|
|
101
|
+
return reply(200, mimeFor(ext), fs.readFile(file) ?? '');
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
105
|
+
return query || loaderFor(ext) ? errorModule(`${file}: ${message}`) : reply(500, 'text/plain; charset=utf-8', message);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
serveDocument(profile) {
|
|
109
|
+
if (!profile.supported || !profile.htmlPath) {
|
|
110
|
+
return reply(501, 'text/html; charset=utf-8', `<!doctype html><meta charset="utf-8"><p>${profile.reason ?? 'Unsupported project.'}</p>`);
|
|
111
|
+
}
|
|
112
|
+
const html = this.options.fs.readText(profile.htmlPath) ?? '';
|
|
113
|
+
const { base, attribution } = this.options;
|
|
114
|
+
return reply(200, 'text/html; charset=utf-8', transformHtml(html, { base, entry: profile.entry, attribution }));
|
|
115
|
+
}
|
|
116
|
+
context() {
|
|
117
|
+
const { fs, transformer, base } = this.options;
|
|
118
|
+
this.config ??= readProjectConfig(fs);
|
|
119
|
+
this.cdn ??= (this.options.cdn ?? ((dependencies) => createEsmShCdn({ dependencies })))(this.config.dependencies);
|
|
120
|
+
return { fs, config: this.config, cdn: this.cdn, transformer, base };
|
|
121
|
+
}
|
|
122
|
+
onChange(change) {
|
|
123
|
+
const structural = change.type === 'remove' || change.created === true || isConfigFile(change.path) || extname(change.path) === '.html';
|
|
124
|
+
if (!structural) {
|
|
125
|
+
for (const key of [...this.cache.keys()])
|
|
126
|
+
if (key.startsWith(change.path + '?'))
|
|
127
|
+
this.cache.delete(key);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
this.cache.clear();
|
|
131
|
+
this.config = undefined;
|
|
132
|
+
this.cdn = undefined;
|
|
133
|
+
this.profileCache = undefined;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=devServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devServer.js","sourceRoot":"","sources":["../src/devServer.ts"],"names":[],"mappings":"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"}
|
package/dist/html.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const ERROR_MESSAGE_TYPE = "bfwc:error";
|
|
2
|
+
/**
|
|
3
|
+
* Runs first in the preview. Forwards uncaught errors and rejections to the host
|
|
4
|
+
* page (`window.parent`), which is how an editor — or an agent — learns the app
|
|
5
|
+
* crashed without scraping the iframe.
|
|
6
|
+
*/
|
|
7
|
+
export declare function errorBridgeScript(): string;
|
|
8
|
+
export interface HtmlOptions {
|
|
9
|
+
/** Preview base URL, ending in `/`. */
|
|
10
|
+
base: string;
|
|
11
|
+
/** Entry injected when the page has no module script. */
|
|
12
|
+
entry?: string;
|
|
13
|
+
/** The "Built with Builderforce.ai" badge. On unless explicitly `false`. */
|
|
14
|
+
attribution?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function transformHtml(html: string, options: HtmlOptions): string;
|
|
17
|
+
//# sourceMappingURL=html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../src/html.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,kBAAkB,eAAe,CAAC;AAE/C;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAS1C;AAKD,MAAM,WAAW,WAAW;IAC1B,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,MAAM,CAgBxE"}
|
package/dist/html.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prepare the project's HTML for the preview:
|
|
3
|
+
* • absolute `src`/`href` paths (`/src/main.tsx`) are re-rooted under the preview
|
|
4
|
+
* base, since the preview is served from a sub-path, not the origin root;
|
|
5
|
+
* • CRA's `%PUBLIC_URL%` placeholder is filled;
|
|
6
|
+
* • a page with no module script (CRA) gets its entry injected;
|
|
7
|
+
* • the error bridge is prepended, so runtime errors reach the host;
|
|
8
|
+
* • the attribution badge is appended unless the host turned it off.
|
|
9
|
+
*/
|
|
10
|
+
import { injectAttribution } from './attribution.js';
|
|
11
|
+
export const ERROR_MESSAGE_TYPE = 'bfwc:error';
|
|
12
|
+
/**
|
|
13
|
+
* Runs first in the preview. Forwards uncaught errors and rejections to the host
|
|
14
|
+
* page (`window.parent`), which is how an editor — or an agent — learns the app
|
|
15
|
+
* crashed without scraping the iframe.
|
|
16
|
+
*/
|
|
17
|
+
export function errorBridgeScript() {
|
|
18
|
+
return `<script>(function(){
|
|
19
|
+
var send = function (message, stack) {
|
|
20
|
+
try { parent.postMessage({ type: ${JSON.stringify(ERROR_MESSAGE_TYPE)}, message: String(message), stack: stack ? String(stack) : undefined, href: location.href }, '*'); } catch (_) {}
|
|
21
|
+
};
|
|
22
|
+
addEventListener('error', function (e) { send(e.message, e.error && e.error.stack); });
|
|
23
|
+
addEventListener('unhandledrejection', function (e) { var r = e.reason; send(r && r.message ? r.message : r, r && r.stack); });
|
|
24
|
+
window.process = window.process || { env: { NODE_ENV: 'development' } };
|
|
25
|
+
})();</script>`;
|
|
26
|
+
}
|
|
27
|
+
const ABSOLUTE_ATTR = /(\s(?:src|href)\s*=\s*)(["'])\/(?!\/)([^"']*)\2/gi;
|
|
28
|
+
const MODULE_SCRIPT = /<script\b[^>]*type\s*=\s*["']module["'][^>]*>/i;
|
|
29
|
+
export function transformHtml(html, options) {
|
|
30
|
+
const { base } = options;
|
|
31
|
+
// `%PUBLIC_URL%/logo.png` becomes root-absolute here and is re-rooted once below;
|
|
32
|
+
// filling in the base directly would let the re-rooting prefix it a second time.
|
|
33
|
+
let out = html.replace(/%PUBLIC_URL%/g, '');
|
|
34
|
+
out = out.replace(ABSOLUTE_ATTR, (_m, attr, quote, rest) => `${attr}${quote}${base}${rest}${quote}`);
|
|
35
|
+
if (options.entry && !MODULE_SCRIPT.test(out)) {
|
|
36
|
+
const tag = `<script type="module" src="${base}${options.entry.slice(1)}"></script>`;
|
|
37
|
+
out = /<\/body>/i.test(out) ? out.replace(/<\/body>/i, `${tag}\n</body>`) : out + tag;
|
|
38
|
+
}
|
|
39
|
+
if (options.attribution !== false)
|
|
40
|
+
out = injectAttribution(out);
|
|
41
|
+
const bridge = errorBridgeScript();
|
|
42
|
+
if (/<head[^>]*>/i.test(out))
|
|
43
|
+
return out.replace(/<head[^>]*>/i, (head) => `${head}\n${bridge}`);
|
|
44
|
+
return bridge + out;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=html.js.map
|
package/dist/html.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.js","sourceRoot":"","sources":["../src/html.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,MAAM,CAAC,MAAM,kBAAkB,GAAG,YAAY,CAAC;AAE/C;;;;GAIG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO;;uCAE8B,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC;;;;;eAK1D,CAAC;AAChB,CAAC;AAED,MAAM,aAAa,GAAG,mDAAmD,CAAC;AAC1E,MAAM,aAAa,GAAG,gDAAgD,CAAC;AAWvE,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,OAAoB;IAC9D,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IACzB,kFAAkF;IAClF,iFAAiF;IACjF,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;IAC5C,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,EAAE,EAAE,IAAY,EAAE,KAAa,EAAE,IAAY,EAAE,EAAE,CAAC,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,EAAE,CAAC,CAAC;IAE7H,IAAI,OAAO,CAAC,KAAK,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9C,MAAM,GAAG,GAAG,8BAA8B,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC;QACrF,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC;IACxF,CAAC;IACD,IAAI,OAAO,CAAC,WAAW,KAAK,KAAK;QAAE,GAAG,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAEhE,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAC;IACnC,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC;IACjG,OAAO,MAAM,GAAG,GAAG,CAAC;AACtB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export { VirtualFileSystem } from './vfs.js';
|
|
2
|
+
export type { FileContent, FileSystemTree, FlatFiles, FsChange } from './vfs.js';
|
|
3
|
+
export { normalizePath, dirname, basename, join, extname } from './paths.js';
|
|
4
|
+
export { DevServer } from './devServer.js';
|
|
5
|
+
export type { DevServerOptions, ServedFile } from './devServer.js';
|
|
6
|
+
export { detectProject } from './detectProject.js';
|
|
7
|
+
export type { ProjectKind, ProjectProfile } from './detectProject.js';
|
|
8
|
+
export { readProjectConfig, parseLooseJson, parseDotenv } from './projectConfig.js';
|
|
9
|
+
export type { ProjectConfig, PathAlias } from './projectConfig.js';
|
|
10
|
+
export { createEsmShCdn } from './packageCdn.js';
|
|
11
|
+
export type { PackageCdn, EsmShOptions } from './packageCdn.js';
|
|
12
|
+
export { createEsbuildTransformer, loaderFor } from './transformer.js';
|
|
13
|
+
export type { Transformer, TransformRequest, Loader, EsbuildLike } from './transformer.js';
|
|
14
|
+
export { rewriteImports } from './rewriteImports.js';
|
|
15
|
+
export { resolveLocal, resolveAlias, isBareSpecifier, splitPackageSpecifier, RESOLVE_EXTENSIONS } from './resolve.js';
|
|
16
|
+
export { compileScript, mapSpecifier, moduleUrl, buildDefine } from './compileScript.js';
|
|
17
|
+
export { transformHtml, errorBridgeScript, ERROR_MESSAGE_TYPE } from './html.js';
|
|
18
|
+
export { mimeFor } from './mime.js';
|
|
19
|
+
export { attributionScript, injectAttribution, ATTRIBUTION_URL, ATTRIBUTION_LABEL } from './attribution.js';
|
|
20
|
+
export type { AttributionOptions } from './attribution.js';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACpF,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC3F,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACtH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACzF,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACjF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC5G,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
|