abret 0.1.2 → 0.1.4
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/chunk-m2mdqvmd.js +82 -0
- package/dist/html.js +3 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -72
- package/dist/middleware/static/index.d.ts +0 -4
- package/dist/middleware/static/index.js +0 -3
- package/dist/middleware/transpiler/index.d.ts +28 -0
- package/dist/middleware/transpiler/index.js +298 -0
- package/package.json +7 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
runWithContext
|
|
4
|
+
} from "./chunk-xw5b0251.js";
|
|
5
|
+
|
|
6
|
+
// src/index.ts
|
|
7
|
+
var wrapWithMiddleware = (handler, middlewares) => {
|
|
8
|
+
return (req, server) => {
|
|
9
|
+
return runWithContext(() => {
|
|
10
|
+
if (middlewares.length === 0) {
|
|
11
|
+
return handler(req, server);
|
|
12
|
+
}
|
|
13
|
+
let index = 0;
|
|
14
|
+
const next = () => {
|
|
15
|
+
if (index < middlewares.length) {
|
|
16
|
+
const middleware = middlewares[index++];
|
|
17
|
+
if (middleware)
|
|
18
|
+
return middleware(req, server, next);
|
|
19
|
+
}
|
|
20
|
+
return handler(req, server);
|
|
21
|
+
};
|
|
22
|
+
return next();
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
var wrapRouteValue = (value, middlewares) => {
|
|
27
|
+
if (middlewares.length === 0) {
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
if (value instanceof Response) {
|
|
31
|
+
return wrapWithMiddleware(() => value, middlewares);
|
|
32
|
+
}
|
|
33
|
+
if (typeof value === "function") {
|
|
34
|
+
return wrapWithMiddleware(value, middlewares);
|
|
35
|
+
}
|
|
36
|
+
if (typeof value === "object" && value !== null) {
|
|
37
|
+
const wrappedMethods = {};
|
|
38
|
+
for (const [method, methodHandler] of Object.entries(value)) {
|
|
39
|
+
if (methodHandler instanceof Response) {
|
|
40
|
+
wrappedMethods[method] = wrapWithMiddleware(() => methodHandler, middlewares);
|
|
41
|
+
} else if (typeof methodHandler === "function") {
|
|
42
|
+
wrappedMethods[method] = wrapWithMiddleware(methodHandler, middlewares);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return wrappedMethods;
|
|
46
|
+
}
|
|
47
|
+
return value;
|
|
48
|
+
};
|
|
49
|
+
var createRoute = (path, value, ...middlewares) => {
|
|
50
|
+
const wrappedValue = wrapRouteValue(value, middlewares);
|
|
51
|
+
return { [path]: wrappedValue };
|
|
52
|
+
};
|
|
53
|
+
var createMiddleware = (fn) => fn;
|
|
54
|
+
var composeMiddlewares = (...middlewares) => {
|
|
55
|
+
return (req, server, finalNext) => {
|
|
56
|
+
let index = 0;
|
|
57
|
+
const next = () => {
|
|
58
|
+
if (index < middlewares.length) {
|
|
59
|
+
const middleware = middlewares[index++];
|
|
60
|
+
if (middleware)
|
|
61
|
+
return middleware(req, server, next);
|
|
62
|
+
}
|
|
63
|
+
return finalNext();
|
|
64
|
+
};
|
|
65
|
+
return next();
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
var mergeRoutes = (...routes) => {
|
|
69
|
+
return Object.assign({}, ...routes);
|
|
70
|
+
};
|
|
71
|
+
var createRouteGroup = (prefix, middlewares = []) => {
|
|
72
|
+
return (path, value) => {
|
|
73
|
+
let fullPath = `/${prefix}/${path}`.replace(/\/+/g, "/");
|
|
74
|
+
if (fullPath.length > 1 && fullPath.endsWith("/")) {
|
|
75
|
+
fullPath = fullPath.slice(0, -1);
|
|
76
|
+
}
|
|
77
|
+
const normalizedPath = fullPath || "/";
|
|
78
|
+
return createRoute(normalizedPath, value, ...middlewares);
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export { createRoute, createMiddleware, composeMiddlewares, mergeRoutes, createRouteGroup };
|
package/dist/html.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import {
|
|
3
|
-
getContextStore
|
|
4
|
-
} from "./chunk-xw5b0251.js";
|
|
5
2
|
import {
|
|
6
3
|
AsyncBuffer,
|
|
7
4
|
Fragment,
|
|
8
5
|
SafeString,
|
|
9
6
|
VNode
|
|
10
7
|
} from "./chunk-m9t91z6h.js";
|
|
8
|
+
import {
|
|
9
|
+
getContextStore
|
|
10
|
+
} from "./chunk-xw5b0251.js";
|
|
11
11
|
|
|
12
12
|
// src/html.ts
|
|
13
13
|
class HTMLResponse extends Response {
|
package/dist/index.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ export type RouteValue<P extends string = string, S = undefined> = Bun.Serve.Bas
|
|
|
33
33
|
* );
|
|
34
34
|
* ```
|
|
35
35
|
*/
|
|
36
|
-
export declare const createRoute: <P extends string
|
|
36
|
+
export declare const createRoute: <P extends `/${string}`, S = undefined>(path: P, value: RouteValue<P, S>, ...middlewares: Middleware<P, S>[]) => Record<P, RouteValue<P, S>>;
|
|
37
37
|
/**
|
|
38
38
|
* Helper to create a middleware function with proper typing
|
|
39
39
|
*
|
|
@@ -100,4 +100,4 @@ type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) exten
|
|
|
100
100
|
* );
|
|
101
101
|
* ```
|
|
102
102
|
*/
|
|
103
|
-
export declare const createRouteGroup: <Prefix extends string
|
|
103
|
+
export declare const createRouteGroup: <Prefix extends `/${string}`, S = undefined>(prefix: Prefix, middlewares?: Middleware<string, S>[]) => <P extends `/${string}` | "">(path: P, value: RouteValue<string, S>) => Record<`/${string}`, RouteValue<`/${string}`, S>>;
|
package/dist/index.js
CHANGED
|
@@ -1,82 +1,17 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
import {
|
|
3
|
+
composeMiddlewares,
|
|
4
|
+
createMiddleware,
|
|
5
|
+
createRoute,
|
|
6
|
+
createRouteGroup,
|
|
7
|
+
mergeRoutes
|
|
8
|
+
} from "./chunk-m2mdqvmd.js";
|
|
2
9
|
import {
|
|
3
10
|
createContext,
|
|
4
11
|
runWithContext,
|
|
5
12
|
runWithContextValue,
|
|
6
13
|
useContext
|
|
7
14
|
} from "./chunk-xw5b0251.js";
|
|
8
|
-
|
|
9
|
-
// src/index.ts
|
|
10
|
-
var wrapWithMiddleware = (handler, middlewares) => {
|
|
11
|
-
return (req, server) => {
|
|
12
|
-
return runWithContext(() => {
|
|
13
|
-
if (middlewares.length === 0) {
|
|
14
|
-
return handler(req, server);
|
|
15
|
-
}
|
|
16
|
-
let index = 0;
|
|
17
|
-
const next = () => {
|
|
18
|
-
if (index < middlewares.length) {
|
|
19
|
-
const middleware = middlewares[index++];
|
|
20
|
-
if (middleware)
|
|
21
|
-
return middleware(req, server, next);
|
|
22
|
-
}
|
|
23
|
-
return handler(req, server);
|
|
24
|
-
};
|
|
25
|
-
return next();
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
};
|
|
29
|
-
var wrapRouteValue = (value, middlewares) => {
|
|
30
|
-
if (middlewares.length === 0) {
|
|
31
|
-
return value;
|
|
32
|
-
}
|
|
33
|
-
if (value instanceof Response) {
|
|
34
|
-
return wrapWithMiddleware(() => value, middlewares);
|
|
35
|
-
}
|
|
36
|
-
if (typeof value === "function") {
|
|
37
|
-
return wrapWithMiddleware(value, middlewares);
|
|
38
|
-
}
|
|
39
|
-
if (typeof value === "object" && value !== null) {
|
|
40
|
-
const wrappedMethods = {};
|
|
41
|
-
for (const [method, methodHandler] of Object.entries(value)) {
|
|
42
|
-
if (methodHandler instanceof Response) {
|
|
43
|
-
wrappedMethods[method] = wrapWithMiddleware(() => methodHandler, middlewares);
|
|
44
|
-
} else if (typeof methodHandler === "function") {
|
|
45
|
-
wrappedMethods[method] = wrapWithMiddleware(methodHandler, middlewares);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return wrappedMethods;
|
|
49
|
-
}
|
|
50
|
-
return value;
|
|
51
|
-
};
|
|
52
|
-
var createRoute = (path, value, ...middlewares) => {
|
|
53
|
-
const wrappedValue = wrapRouteValue(value, middlewares);
|
|
54
|
-
return { [path]: wrappedValue };
|
|
55
|
-
};
|
|
56
|
-
var createMiddleware = (fn) => fn;
|
|
57
|
-
var composeMiddlewares = (...middlewares) => {
|
|
58
|
-
return (req, server, finalNext) => {
|
|
59
|
-
let index = 0;
|
|
60
|
-
const next = () => {
|
|
61
|
-
if (index < middlewares.length) {
|
|
62
|
-
const middleware = middlewares[index++];
|
|
63
|
-
if (middleware)
|
|
64
|
-
return middleware(req, server, next);
|
|
65
|
-
}
|
|
66
|
-
return finalNext();
|
|
67
|
-
};
|
|
68
|
-
return next();
|
|
69
|
-
};
|
|
70
|
-
};
|
|
71
|
-
var mergeRoutes = (...routes) => {
|
|
72
|
-
return Object.assign({}, ...routes);
|
|
73
|
-
};
|
|
74
|
-
var createRouteGroup = (prefix, middlewares = []) => {
|
|
75
|
-
return (path, value) => {
|
|
76
|
-
const fullPath = `${prefix}${path}`;
|
|
77
|
-
return createRoute(fullPath, value, ...middlewares);
|
|
78
|
-
};
|
|
79
|
-
};
|
|
80
15
|
export {
|
|
81
16
|
useContext,
|
|
82
17
|
runWithContextValue,
|
|
@@ -19,10 +19,6 @@ export type ServeStaticOptions = {
|
|
|
19
19
|
* Extension (without dot) -> Mime Type
|
|
20
20
|
*/
|
|
21
21
|
mimes?: Record<string, string>;
|
|
22
|
-
/**
|
|
23
|
-
* Callback when file is not found.
|
|
24
|
-
*/
|
|
25
|
-
onNotFound?: (path: string, req: Request) => void;
|
|
26
22
|
};
|
|
27
23
|
/**
|
|
28
24
|
* Middleware to serve static files using Bun.file
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
interface TranspilerOptions {
|
|
2
|
+
/** Directory where source files (.ts, .tsx) are located */
|
|
3
|
+
sourcePath: string;
|
|
4
|
+
/** URL prefix to intercept (e.g., "/_modules") */
|
|
5
|
+
staticBasePath: string;
|
|
6
|
+
/** Optional sub-path for vendor modules. Defaults to 'vendor' */
|
|
7
|
+
vendorPath?: string;
|
|
8
|
+
/** Optional list of modules to bundle on startup */
|
|
9
|
+
prewarm?: string[];
|
|
10
|
+
/** Minify local modules. Defaults to false (recommended for dev) */
|
|
11
|
+
minify?: boolean;
|
|
12
|
+
/** Browser cache TTL for local modules in seconds. Defaults to 0 */
|
|
13
|
+
localMaxAge?: number;
|
|
14
|
+
/** Global identifier replacements */
|
|
15
|
+
define?: Record<string, string>;
|
|
16
|
+
/** Map modules to global variables (e.g., { 'react': 'React' }) */
|
|
17
|
+
globals?: Record<string, string>;
|
|
18
|
+
/** Automatically fallback to esm.sh if package is not found locally */
|
|
19
|
+
cdnFallback?: boolean;
|
|
20
|
+
/** Additional Bun plugins */
|
|
21
|
+
plugins?: any[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Transpiler middleware that handles on-the-fly TS/TSX transpilation
|
|
25
|
+
* and automatic npm module bundling (vendor modules).
|
|
26
|
+
*/
|
|
27
|
+
export declare const transpiler: (options: TranspilerOptions) => import("../..").Middleware<string, undefined>;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
createMiddleware
|
|
4
|
+
} from "../../chunk-m2mdqvmd.js";
|
|
5
|
+
import"../../chunk-xw5b0251.js";
|
|
6
|
+
|
|
7
|
+
// src/middleware/transpiler/index.ts
|
|
8
|
+
import { existsSync, mkdirSync, statSync } from "fs";
|
|
9
|
+
import path from "path";
|
|
10
|
+
var transpiler = (options) => {
|
|
11
|
+
const {
|
|
12
|
+
sourcePath,
|
|
13
|
+
staticBasePath,
|
|
14
|
+
vendorPath = "vendor",
|
|
15
|
+
prewarm = [],
|
|
16
|
+
minify = false,
|
|
17
|
+
localMaxAge = 0,
|
|
18
|
+
define = {},
|
|
19
|
+
globals = {},
|
|
20
|
+
cdnFallback = false,
|
|
21
|
+
plugins = []
|
|
22
|
+
} = options;
|
|
23
|
+
const cacheDir = path.resolve(process.cwd(), "node_modules", ".transpiler");
|
|
24
|
+
const basePrefix = staticBasePath.endsWith("/") ? staticBasePath : `${staticBasePath}/`;
|
|
25
|
+
const vendorPrefix = `${basePrefix}${vendorPath.replace(/^\/|\/$/g, "")}/`;
|
|
26
|
+
if (!existsSync(cacheDir)) {
|
|
27
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
const publicEnv = {};
|
|
30
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
31
|
+
if (key.startsWith("PUBLIC_")) {
|
|
32
|
+
publicEnv[`process.env.${key}`] = JSON.stringify(value);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const defaultDefine = {
|
|
36
|
+
"process.env.NODE_ENV": JSON.stringify("development"),
|
|
37
|
+
...publicEnv,
|
|
38
|
+
...define
|
|
39
|
+
};
|
|
40
|
+
const activeBundles = new Map;
|
|
41
|
+
function resolveModulePath(moduleName) {
|
|
42
|
+
if (globals[moduleName])
|
|
43
|
+
return moduleName;
|
|
44
|
+
try {
|
|
45
|
+
Bun.resolveSync(moduleName, process.cwd());
|
|
46
|
+
return `${basePrefix}${vendorPath.replace(/^\/|\/$/g, "")}/${moduleName}`;
|
|
47
|
+
} catch {
|
|
48
|
+
if (cdnFallback) {
|
|
49
|
+
return `https://esm.sh/${moduleName}`;
|
|
50
|
+
}
|
|
51
|
+
return `${basePrefix}${vendorPath.replace(/^\/|\/$/g, "")}/${moduleName}`;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function bundleVendorModule(moduleName) {
|
|
55
|
+
const cacheKey = moduleName.replace(/\//g, "__");
|
|
56
|
+
const cachedFile = path.join(cacheDir, `${cacheKey}.js`);
|
|
57
|
+
if (existsSync(cachedFile))
|
|
58
|
+
return;
|
|
59
|
+
if (activeBundles.has(cacheKey)) {
|
|
60
|
+
return activeBundles.get(cacheKey);
|
|
61
|
+
}
|
|
62
|
+
const promise = (async () => {
|
|
63
|
+
if (existsSync(cachedFile))
|
|
64
|
+
return;
|
|
65
|
+
try {
|
|
66
|
+
const entryPoint = Bun.resolveSync(moduleName, process.cwd());
|
|
67
|
+
const globalsPlugin = {
|
|
68
|
+
name: "abret-globals",
|
|
69
|
+
setup(build) {
|
|
70
|
+
for (const moduleName2 of Object.keys(globals)) {
|
|
71
|
+
build.onResolve({ filter: new RegExp(`^${moduleName2}$`) }, () => ({
|
|
72
|
+
path: moduleName2,
|
|
73
|
+
namespace: "abret-globals"
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
build.onLoad({ filter: /.*/, namespace: "abret-globals" }, (args) => {
|
|
77
|
+
const gName = globals[args.path];
|
|
78
|
+
return {
|
|
79
|
+
contents: `export default globalThis.${gName}; export const ${gName} = globalThis.${gName};`,
|
|
80
|
+
loader: "js"
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const result = await Bun.build({
|
|
86
|
+
entrypoints: [entryPoint],
|
|
87
|
+
target: "browser",
|
|
88
|
+
format: "esm",
|
|
89
|
+
minify: true,
|
|
90
|
+
define: defaultDefine,
|
|
91
|
+
plugins: [
|
|
92
|
+
globalsPlugin,
|
|
93
|
+
{
|
|
94
|
+
name: "abret-external-vendor",
|
|
95
|
+
setup(build) {
|
|
96
|
+
build.onResolve({ filter: /^[^./]/ }, (args) => {
|
|
97
|
+
if (args.path === moduleName || globals[args.path])
|
|
98
|
+
return null;
|
|
99
|
+
return { path: args.path, external: true };
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
...plugins
|
|
104
|
+
]
|
|
105
|
+
});
|
|
106
|
+
if (!result.success || result.outputs.length === 0) {
|
|
107
|
+
console.error(`[Abret] Failed to bundle vendor module: ${moduleName}`, result.logs);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const output = result.outputs[0];
|
|
111
|
+
if (!output)
|
|
112
|
+
return;
|
|
113
|
+
const rawContent = await output.text();
|
|
114
|
+
const content = rawContent.replace(/((?:import|export)\s*[\s\S]*?from\s*['"]|import\s*\(['"])([^'"]+)(['"]\)?)/g, (match, prefix, path2, suffix) => {
|
|
115
|
+
if (/^(https?:|(?:\/\/))/.test(path2))
|
|
116
|
+
return match;
|
|
117
|
+
if (!path2.startsWith(".") && !path2.startsWith("/")) {
|
|
118
|
+
return `${prefix}${resolveModulePath(path2)}${suffix}`;
|
|
119
|
+
}
|
|
120
|
+
return match;
|
|
121
|
+
});
|
|
122
|
+
await Bun.write(cachedFile, content);
|
|
123
|
+
console.log(`[Abret] Pre-bundled: ${moduleName}`);
|
|
124
|
+
} catch (err) {
|
|
125
|
+
console.error(`[Abret] Error bundling ${moduleName}:`, err);
|
|
126
|
+
} finally {
|
|
127
|
+
activeBundles.delete(cacheKey);
|
|
128
|
+
}
|
|
129
|
+
})();
|
|
130
|
+
activeBundles.set(cacheKey, promise);
|
|
131
|
+
return promise;
|
|
132
|
+
}
|
|
133
|
+
if (prewarm.length > 0) {
|
|
134
|
+
for (const moduleName of prewarm) {
|
|
135
|
+
bundleVendorModule(moduleName);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return createMiddleware(async (req, _server, next) => {
|
|
139
|
+
const url = new URL(req.url);
|
|
140
|
+
const pathname = url.pathname;
|
|
141
|
+
if (!pathname.startsWith(basePrefix) && pathname !== staticBasePath) {
|
|
142
|
+
return next();
|
|
143
|
+
}
|
|
144
|
+
if (pathname.startsWith(vendorPrefix)) {
|
|
145
|
+
const moduleName = pathname.slice(vendorPrefix.length);
|
|
146
|
+
const cacheKey = moduleName.replace(/\//g, "__");
|
|
147
|
+
const cachedFile = path.join(cacheDir, `${cacheKey}.js`);
|
|
148
|
+
if (existsSync(cachedFile)) {
|
|
149
|
+
return new Response(Bun.file(cachedFile), {
|
|
150
|
+
headers: {
|
|
151
|
+
"Content-Type": "application/javascript",
|
|
152
|
+
"Cache-Control": "public, max-age=31536000, immutable"
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
await bundleVendorModule(moduleName);
|
|
157
|
+
if (existsSync(cachedFile)) {
|
|
158
|
+
return new Response(Bun.file(cachedFile), {
|
|
159
|
+
headers: {
|
|
160
|
+
"Content-Type": "application/javascript",
|
|
161
|
+
"Cache-Control": "public, max-age=31536000, immutable"
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return next();
|
|
166
|
+
}
|
|
167
|
+
const internalPath = pathname.slice(basePrefix.length);
|
|
168
|
+
const extname = path.extname(internalPath);
|
|
169
|
+
let sourceFile = "";
|
|
170
|
+
let contentType = "application/javascript";
|
|
171
|
+
if (extname === ".css") {
|
|
172
|
+
const p = path.join(path.resolve(sourcePath), internalPath);
|
|
173
|
+
if (existsSync(p)) {
|
|
174
|
+
sourceFile = p;
|
|
175
|
+
contentType = "text/css";
|
|
176
|
+
}
|
|
177
|
+
} else {
|
|
178
|
+
const baseFileName = internalPath.endsWith(".js") ? internalPath.slice(0, -3) : internalPath;
|
|
179
|
+
const possibleExtensions = [".tsx", ".ts", ".jsx", ".js"];
|
|
180
|
+
for (const ext of possibleExtensions) {
|
|
181
|
+
const p = path.join(path.resolve(sourcePath), (baseFileName.startsWith("/") ? baseFileName.slice(1) : baseFileName) + ext);
|
|
182
|
+
if (existsSync(p)) {
|
|
183
|
+
sourceFile = p;
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (sourceFile) {
|
|
189
|
+
const sourceStat = statSync(sourceFile);
|
|
190
|
+
const fastEtag = `W/"${sourceStat.size}-${sourceStat.mtimeMs}-${minify}"`;
|
|
191
|
+
if (req.headers.get("if-none-match") === fastEtag) {
|
|
192
|
+
return new Response(null, { status: 304 });
|
|
193
|
+
}
|
|
194
|
+
const lockKey = `local:${sourceFile}:${fastEtag}`;
|
|
195
|
+
if (activeBundles.has(lockKey)) {
|
|
196
|
+
const result = await activeBundles.get(lockKey);
|
|
197
|
+
return new Response(result.content, {
|
|
198
|
+
headers: {
|
|
199
|
+
"Content-Type": result.contentType,
|
|
200
|
+
ETag: fastEtag,
|
|
201
|
+
"Cache-Control": localMaxAge > 0 ? `public, max-age=${localMaxAge}` : "no-cache"
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
const buildPromise = (async () => {
|
|
206
|
+
try {
|
|
207
|
+
const buildResult = await Bun.build({
|
|
208
|
+
entrypoints: [sourceFile],
|
|
209
|
+
target: "browser",
|
|
210
|
+
format: "esm",
|
|
211
|
+
minify,
|
|
212
|
+
define: defaultDefine,
|
|
213
|
+
external: ["*"],
|
|
214
|
+
plugins: [
|
|
215
|
+
{
|
|
216
|
+
name: "abret-globals-local",
|
|
217
|
+
setup(build) {
|
|
218
|
+
for (const moduleName of Object.keys(globals)) {
|
|
219
|
+
build.onResolve({ filter: new RegExp(`^${moduleName}$`) }, () => ({
|
|
220
|
+
path: moduleName,
|
|
221
|
+
namespace: "abret-globals"
|
|
222
|
+
}));
|
|
223
|
+
}
|
|
224
|
+
build.onLoad({ filter: /.*/, namespace: "abret-globals" }, (args) => {
|
|
225
|
+
const gName = globals[args.path];
|
|
226
|
+
return {
|
|
227
|
+
contents: `export default globalThis.${gName};`,
|
|
228
|
+
loader: "js"
|
|
229
|
+
};
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
...plugins
|
|
234
|
+
]
|
|
235
|
+
});
|
|
236
|
+
if (!buildResult.success || buildResult.outputs.length === 0) {
|
|
237
|
+
throw new Error(`Build failed: ${buildResult.logs.map((l) => l.message).join(", ")}`);
|
|
238
|
+
}
|
|
239
|
+
const output = buildResult.outputs[0];
|
|
240
|
+
if (!output)
|
|
241
|
+
throw new Error("No output generated");
|
|
242
|
+
const transpiledCode = await output.text();
|
|
243
|
+
if (contentType === "text/css") {
|
|
244
|
+
return { content: transpiledCode, contentType };
|
|
245
|
+
}
|
|
246
|
+
const finalCode = transpiledCode.replace(/((?:import|export)\s*[\s\S]*?from\s*['"]|import\s*\(['"])([^'"]+)(['"]\)?)/g, (match, prefix, path2, suffix) => {
|
|
247
|
+
if (/^(https?:|(?:\/\/))/.test(path2))
|
|
248
|
+
return match;
|
|
249
|
+
if (!path2.startsWith(".") && !path2.startsWith("/")) {
|
|
250
|
+
return `${prefix}${resolveModulePath(path2)}${suffix}`;
|
|
251
|
+
}
|
|
252
|
+
if (path2.startsWith(".") && !path2.split("/").pop()?.includes(".")) {
|
|
253
|
+
return `${prefix}${path2}.js${suffix}`;
|
|
254
|
+
}
|
|
255
|
+
return match;
|
|
256
|
+
});
|
|
257
|
+
return { content: finalCode, contentType };
|
|
258
|
+
} finally {
|
|
259
|
+
activeBundles.delete(lockKey);
|
|
260
|
+
}
|
|
261
|
+
})();
|
|
262
|
+
activeBundles.set(lockKey, buildPromise);
|
|
263
|
+
try {
|
|
264
|
+
const finalResult = await buildPromise;
|
|
265
|
+
return new Response(finalResult.content, {
|
|
266
|
+
headers: {
|
|
267
|
+
"Content-Type": finalResult.contentType,
|
|
268
|
+
ETag: fastEtag,
|
|
269
|
+
"Cache-Control": localMaxAge > 0 ? `public, max-age=${localMaxAge}` : "no-cache"
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
} catch (err) {
|
|
273
|
+
const errorMessage = err.message || "Unknown transpilation error";
|
|
274
|
+
console.error(`[Abret] ${errorMessage} for ${sourceFile}`);
|
|
275
|
+
return new Response(`console.error("[Abret] Build Error in ${sourceFile}:", ${JSON.stringify(errorMessage)});
|
|
276
|
+
if (typeof document !== 'undefined') {
|
|
277
|
+
const div = document.createElement('div');
|
|
278
|
+
div.style.position = 'fixed';
|
|
279
|
+
div.style.top = '0';
|
|
280
|
+
div.style.left = '0';
|
|
281
|
+
div.style.width = '100%';
|
|
282
|
+
div.style.padding = '1rem';
|
|
283
|
+
div.style.background = '#fee2e2';
|
|
284
|
+
div.style.color = '#991b1b';
|
|
285
|
+
div.style.borderBottom = '1px solid #ef4444';
|
|
286
|
+
div.style.zIndex = '999999';
|
|
287
|
+
div.style.fontFamily = 'monospace';
|
|
288
|
+
div.innerText = "[Abret] Build Error in ${sourceFile.split("/").pop()}: " + ${JSON.stringify(errorMessage)};
|
|
289
|
+
document.body.appendChild(div);
|
|
290
|
+
}`, { headers: { "Content-Type": "application/javascript" } });
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return next();
|
|
294
|
+
});
|
|
295
|
+
};
|
|
296
|
+
export {
|
|
297
|
+
transpiler
|
|
298
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "abret",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Fast, type-safe web framework for Bun with built-in JSX and middleware support.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Arisris",
|
|
@@ -52,6 +52,10 @@
|
|
|
52
52
|
"./middleware/static": {
|
|
53
53
|
"types": "./dist/middleware/static/index.d.ts",
|
|
54
54
|
"import": "./dist/middleware/static/index.js"
|
|
55
|
+
},
|
|
56
|
+
"./middleware/transpiler": {
|
|
57
|
+
"types": "./dist/middleware/transpiler/index.d.ts",
|
|
58
|
+
"import": "./dist/middleware/transpiler/index.js"
|
|
55
59
|
}
|
|
56
60
|
},
|
|
57
61
|
"scripts": {
|
|
@@ -63,7 +67,9 @@
|
|
|
63
67
|
},
|
|
64
68
|
"devDependencies": {
|
|
65
69
|
"@biomejs/biome": "2.3.12",
|
|
70
|
+
"@preact/signals": "^2.6.2",
|
|
66
71
|
"@types/bun": "latest",
|
|
72
|
+
"preact": "^10.28.3",
|
|
67
73
|
"typescript": "^5"
|
|
68
74
|
}
|
|
69
75
|
}
|