@absolutejs/absolute 0.12.5 → 0.13.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/CLAUDE.md +56 -0
- package/LICENSE +24 -24
- package/README.md +163 -163
- package/dist/constants.d.ts +0 -1
- package/dist/index.js +6 -45
- package/dist/index.js.map +26 -27
- package/eslint.config.mjs +234 -234
- package/package.json +6 -6
- package/tsconfig.build.json +20 -20
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
AbsoluteJS is a full-stack, type-safe meta-framework for building web applications with TypeScript. It provides universal server-side rendering (SSR) for multiple frontend frameworks (React, Svelte, Vue, HTML, HTMX) powered by Bun and Elysia.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bun run typecheck # TypeScript type checking (no emit)
|
|
13
|
+
bun run format # Prettier formatting
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Architecture
|
|
17
|
+
|
|
18
|
+
### Build Pipeline (`src/core/build.ts`)
|
|
19
|
+
|
|
20
|
+
The central orchestrator. A single `build()` call scans, compiles, and bundles all frameworks:
|
|
21
|
+
|
|
22
|
+
1. **Path validation** → `validateSafePath()` prevents directory traversal
|
|
23
|
+
2. **React index generation** → creates hydration entry points in `indexes/`
|
|
24
|
+
3. **Asset copy** + optional **Tailwind compilation**
|
|
25
|
+
4. **Entry point scanning** → `scanEntryPoints()` globs each framework directory
|
|
26
|
+
5. **Framework compilation** → Svelte (`compileSvelte`), Vue (`compileVue`) each produce SSR + client variants
|
|
27
|
+
6. **Bun bundling** (3 passes): server (target=bun), client (target=browser, minified), CSS
|
|
28
|
+
7. **Manifest generation** → maps filenames (PascalCased via `toPascal`) to hashed asset paths
|
|
29
|
+
8. **HTML asset path updating** → regex-based injection of hashed paths
|
|
30
|
+
9. **Cleanup** → removes `compiled/` intermediates unless `preserveIntermediateFiles` is set
|
|
31
|
+
|
|
32
|
+
### Key Modules
|
|
33
|
+
|
|
34
|
+
- **`src/core/pageHandlers.ts`** — `handleReactPageRequest`, `handleSveltePageRequest`, `handleVuePageRequest`, `handleHTMLPageRequest`, `handleHTMXPageRequest`. Each renders SSR HTML with hydration scripts.
|
|
35
|
+
- **`src/core/lookup.ts`** — `asset(manifest, name)` resolves build manifest entries.
|
|
36
|
+
- **`src/build/`** — Individual compilation steps: `compileSvelte.ts`, `compileVue.ts`, `generateManifest.ts`, `generateReactIndexes.ts`, `scanEntryPoints.ts`, `updateAssetPaths.ts`.
|
|
37
|
+
- **`src/plugins/networking.ts`** — Elysia plugin for server startup with HOST/PORT config and LAN binding (`--host` flag).
|
|
38
|
+
- **`src/utils/`** — Path validation, string transforms (`toPascal`/`toKebab`), head element generation, environment variable loading (`getEnv`).
|
|
39
|
+
- **`src/types.ts`** — `BuildConfig`, `BuildOptions`, `PropsOf<T>`, `Prettify<T>`.
|
|
40
|
+
|
|
41
|
+
### Framework SSR Pattern
|
|
42
|
+
|
|
43
|
+
All frameworks follow the same pattern: server renders HTML → props serialized to `window.__INITIAL_PROPS__` → client hydrates with framework-specific entry point. Hydration indexes are auto-generated during build.
|
|
44
|
+
|
|
45
|
+
### Configuration Type
|
|
46
|
+
|
|
47
|
+
`BuildConfig` accepts optional directory paths for each framework (`reactDirectory`, `svelteDirectory`, `vueDirectory`, `htmlDirectory`, `htmxDirectory`), plus `buildDirectory`, `assetsDirectory`, `tailwind` config, and `options`.
|
|
48
|
+
|
|
49
|
+
## Code Conventions
|
|
50
|
+
|
|
51
|
+
- **ESLint plugin `eslint-plugin-absolute`** enforces strict rules: max nesting depth of 1, min variable name length of 3 (exceptions: `_`, `id`, `db`, `OK`), explicit return types, sorted exports/keys, no default exports (except config files)
|
|
52
|
+
- **Prettier**: 4-space tabs, 80 char width, single quotes, trailing commas off, semicolons on
|
|
53
|
+
- **TypeScript**: strict mode, ESNext target, bundler module resolution, decorator support enabled
|
|
54
|
+
- **Barrel exports**: `index.ts` files re-export alphabetically from each module directory
|
|
55
|
+
- **No default imports** from `react` or `bun` (enforced by linter)
|
|
56
|
+
- Elysia plugin pattern for server extensibility
|
package/LICENSE
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
```
|
|
2
|
-
# Creative Commons Attribution-NonCommercial 4.0 International License (CC BY-NC 4.0)
|
|
3
|
-
|
|
4
|
-
By using this project, you agree to the following terms under the Creative Commons Attribution-NonCommercial 4.0 International License.
|
|
5
|
-
|
|
6
|
-
## License Summary
|
|
7
|
-
This license allows you to:
|
|
8
|
-
- **Share**: Copy and redistribute the material in any medium or format.
|
|
9
|
-
- **Adapt**: Remix, transform, and build upon the material.
|
|
10
|
-
|
|
11
|
-
**Under the following conditions**:
|
|
12
|
-
- **Attribution**: You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
|
|
13
|
-
- **Non-Commercial**: You may not use the material for commercial purposes.
|
|
14
|
-
|
|
15
|
-
## Full License Text
|
|
16
|
-
The full license text can be found at: https://creativecommons.org/licenses/by-nc/4.0/legalcode
|
|
17
|
-
|
|
18
|
-
## Contact Information for Commercial Use
|
|
19
|
-
For commercial use, licensing inquiries, or additional permissions, please contact:
|
|
20
|
-
Alex Kahn
|
|
21
|
-
alexkahndev@gmail.com
|
|
22
|
-
alexkahndev.github.io
|
|
23
|
-
```
|
|
24
|
-
|
|
1
|
+
```
|
|
2
|
+
# Creative Commons Attribution-NonCommercial 4.0 International License (CC BY-NC 4.0)
|
|
3
|
+
|
|
4
|
+
By using this project, you agree to the following terms under the Creative Commons Attribution-NonCommercial 4.0 International License.
|
|
5
|
+
|
|
6
|
+
## License Summary
|
|
7
|
+
This license allows you to:
|
|
8
|
+
- **Share**: Copy and redistribute the material in any medium or format.
|
|
9
|
+
- **Adapt**: Remix, transform, and build upon the material.
|
|
10
|
+
|
|
11
|
+
**Under the following conditions**:
|
|
12
|
+
- **Attribution**: You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
|
|
13
|
+
- **Non-Commercial**: You may not use the material for commercial purposes.
|
|
14
|
+
|
|
15
|
+
## Full License Text
|
|
16
|
+
The full license text can be found at: https://creativecommons.org/licenses/by-nc/4.0/legalcode
|
|
17
|
+
|
|
18
|
+
## Contact Information for Commercial Use
|
|
19
|
+
For commercial use, licensing inquiries, or additional permissions, please contact:
|
|
20
|
+
Alex Kahn
|
|
21
|
+
alexkahndev@gmail.com
|
|
22
|
+
alexkahndev.github.io
|
|
23
|
+
```
|
|
24
|
+
|
package/README.md
CHANGED
|
@@ -1,163 +1,163 @@
|
|
|
1
|
-
# AbsoluteJS
|
|
2
|
-
|
|
3
|
-
Full‑stack, **type‑safe** batteries‑included platform that lets you **server‑side render _any_ modern front‑end**—React, Svelte, plain HTML, HTMX (Vue & Angular coming)—with a single Bun‑powered build step.
|
|
4
|
-
|
|
5
|
-
[](https://bun.sh)
|
|
6
|
-
[](https://elysiajs.com)
|
|
7
|
-

|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## Why Absolute JS?
|
|
12
|
-
|
|
13
|
-
- **Universal SSR.** Bring your favourite UI layer; Absolute JS handles bundling, hydration, and HTML streaming.
|
|
14
|
-
- **One build, one manifest.** Call `build()` once—get a manifest mapping every page’s client and server assets, ready to wire into routes.
|
|
15
|
-
- **End‑to‑end type safety.** A unified source of truth for your types—from the database, through the server, and all the way to the client—so you can be certain of the data shape at every step.
|
|
16
|
-
- **Zero‑config philosophy.** Point the build at your folders; sane defaults light up everything else.
|
|
17
|
-
- **Plugin power.** Extend with standard Elysia plugins—ship auth, logging, i18n, and more. First‑party: `absolute-auth`, `networkingPlugin`.
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## Requirements
|
|
22
|
-
|
|
23
|
-
| Tool | Version | Purpose |
|
|
24
|
-
| ---------- | ------- | ------------------------------------------- |
|
|
25
|
-
| **Bun** | ≥ 1.2 | Runtime, bundler, and TypeScript transpiler |
|
|
26
|
-
| **Elysia** | latest | Web server & middleware platform |
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Installation
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
bun add @absolutejs/absolute
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
## Quick Start
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
// example/server.ts
|
|
42
|
-
import { staticPlugin } from '@elysiajs/static';
|
|
43
|
-
import { Elysia } from 'elysia';
|
|
44
|
-
import { file } from 'bun';
|
|
45
|
-
import { build } from 'absolutejs/core/build';
|
|
46
|
-
import {
|
|
47
|
-
handleHTMLPageRequest,
|
|
48
|
-
handleReactPageRequest,
|
|
49
|
-
handleSveltePageRequest
|
|
50
|
-
} from 'absolutejs/core/pageHandlers';
|
|
51
|
-
|
|
52
|
-
import { ReactExample } from './react/pages/ReactExample';
|
|
53
|
-
import SvelteExample from './svelte/pages/SvelteExample.svelte';
|
|
54
|
-
import { networkingPlugin } from 'absolutejs';
|
|
55
|
-
|
|
56
|
-
const manifest = await build({
|
|
57
|
-
assetsDirectory: 'example/assets',
|
|
58
|
-
buildDirectory: 'example/build',
|
|
59
|
-
htmlDirectory: 'example/html',
|
|
60
|
-
htmxDirectory: 'example/htmx',
|
|
61
|
-
reactDirectory: 'example/react',
|
|
62
|
-
svelteDirectory: 'example/svelte',
|
|
63
|
-
options: { preserveIntermediateFiles: true }
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
if (!manifest) throw new Error('Manifest generation failed');
|
|
67
|
-
|
|
68
|
-
let counter = 0;
|
|
69
|
-
|
|
70
|
-
export const server = new Elysia()
|
|
71
|
-
.use(staticPlugin({ assets: './example/build', prefix: '' }))
|
|
72
|
-
|
|
73
|
-
// HTML
|
|
74
|
-
.get('/', () =>
|
|
75
|
-
handleHTMLPageRequest('./example/build/html/pages/HtmlExample.html')
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
// React
|
|
79
|
-
.get('/react', () =>
|
|
80
|
-
handleReactPageRequest(ReactExample, manifest['ReactExampleIndex'], {
|
|
81
|
-
test: 123
|
|
82
|
-
})
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
// Svelte
|
|
86
|
-
.get('/svelte', () =>
|
|
87
|
-
handleSveltePageRequest(SvelteExample, manifest, { test: 456 })
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
// HTMX demo
|
|
91
|
-
.get('/htmx', () => file('./example/build/htmx/HtmxHome.html'))
|
|
92
|
-
.get('/htmx/increment', () => new Response(String(++counter)))
|
|
93
|
-
|
|
94
|
-
.use(networkingPlugin)
|
|
95
|
-
.on('error', (error) => {
|
|
96
|
-
const { request } = error;
|
|
97
|
-
console.error(
|
|
98
|
-
`Server error on ${request.method} ${request.url}: ${error.message}`
|
|
99
|
-
);
|
|
100
|
-
});
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### How it works
|
|
104
|
-
|
|
105
|
-
1. **`build()`** scans your project, bundles each framework, and returns a **manifest** that has the server, and client assets required to serve each route.
|
|
106
|
-
2. Route handlers (`handleReactPageRequest`, `handleSveltePageRequest`, …) stream HTML and inject scripts/assets based on that manifest.
|
|
107
|
-
3. The static plugin serves all compiled files from `/build`.
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## Plugin System
|
|
112
|
-
|
|
113
|
-
Absolute JS piggybacks on the [Elysia plugin API](https://elysiajs.com/plugins). Any Elysia plugin works out of the box; Absolute adds helpers for:
|
|
114
|
-
|
|
115
|
-
| Plugin | Description |
|
|
116
|
-
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
117
|
-
| **`absolute-auth`** | Full OAuth2 flow configured with 66 providers and allows full customizability with event handlers |
|
|
118
|
-
| **`networkingPlugin`** | Starts your Elysia server with HOST/PORT defaults and adds a --host flag to toggle listening on localhost or your LAN interface |
|
|
119
|
-
|
|
120
|
-
---
|
|
121
|
-
|
|
122
|
-
## Configuration Philosophy
|
|
123
|
-
|
|
124
|
-
Everything funnels through a single `build()` call:
|
|
125
|
-
|
|
126
|
-
```ts
|
|
127
|
-
await build({
|
|
128
|
-
reactDirectory: 'src/react',
|
|
129
|
-
svelteDirectory: 'src/svelte',
|
|
130
|
-
htmlDirectory: 'src/html',
|
|
131
|
-
htmxDirectory: 'src/htmx',
|
|
132
|
-
assetsDirectory: 'public/assets',
|
|
133
|
-
options: { preserveIntermediateFiles: false }
|
|
134
|
-
});
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
No separate config files or environment variables—just explicit arguments with sensible defaults.
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
## Roadmap
|
|
142
|
-
|
|
143
|
-
- **Angular** handlers
|
|
144
|
-
- Prisma support
|
|
145
|
-
- Biome support
|
|
146
|
-
- Hot‑reload development server
|
|
147
|
-
- First‑class Docker images & hosting recipes
|
|
148
|
-
|
|
149
|
-
---
|
|
150
|
-
|
|
151
|
-
## Contributing
|
|
152
|
-
|
|
153
|
-
Pull requests and issues are welcome! Whether it’s a new plugin, framework handler, or docs improvement:
|
|
154
|
-
|
|
155
|
-
1. Fork & branch.
|
|
156
|
-
2. `bun install && bun test`.
|
|
157
|
-
3. Submit a PR with a clear description.
|
|
158
|
-
|
|
159
|
-
---
|
|
160
|
-
|
|
161
|
-
## License
|
|
162
|
-
|
|
163
|
-
Creative Commons **CC BY‑NC 4.0** – see [`LICENSE`](./LICENSE) for details.
|
|
1
|
+
# AbsoluteJS
|
|
2
|
+
|
|
3
|
+
Full‑stack, **type‑safe** batteries‑included platform that lets you **server‑side render _any_ modern front‑end**—React, Svelte, plain HTML, HTMX (Vue & Angular coming)—with a single Bun‑powered build step.
|
|
4
|
+
|
|
5
|
+
[](https://bun.sh)
|
|
6
|
+
[](https://elysiajs.com)
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Why Absolute JS?
|
|
12
|
+
|
|
13
|
+
- **Universal SSR.** Bring your favourite UI layer; Absolute JS handles bundling, hydration, and HTML streaming.
|
|
14
|
+
- **One build, one manifest.** Call `build()` once—get a manifest mapping every page’s client and server assets, ready to wire into routes.
|
|
15
|
+
- **End‑to‑end type safety.** A unified source of truth for your types—from the database, through the server, and all the way to the client—so you can be certain of the data shape at every step.
|
|
16
|
+
- **Zero‑config philosophy.** Point the build at your folders; sane defaults light up everything else.
|
|
17
|
+
- **Plugin power.** Extend with standard Elysia plugins—ship auth, logging, i18n, and more. First‑party: `absolute-auth`, `networkingPlugin`.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Requirements
|
|
22
|
+
|
|
23
|
+
| Tool | Version | Purpose |
|
|
24
|
+
| ---------- | ------- | ------------------------------------------- |
|
|
25
|
+
| **Bun** | ≥ 1.2 | Runtime, bundler, and TypeScript transpiler |
|
|
26
|
+
| **Elysia** | latest | Web server & middleware platform |
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
bun add @absolutejs/absolute
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
// example/server.ts
|
|
42
|
+
import { staticPlugin } from '@elysiajs/static';
|
|
43
|
+
import { Elysia } from 'elysia';
|
|
44
|
+
import { file } from 'bun';
|
|
45
|
+
import { build } from 'absolutejs/core/build';
|
|
46
|
+
import {
|
|
47
|
+
handleHTMLPageRequest,
|
|
48
|
+
handleReactPageRequest,
|
|
49
|
+
handleSveltePageRequest
|
|
50
|
+
} from 'absolutejs/core/pageHandlers';
|
|
51
|
+
|
|
52
|
+
import { ReactExample } from './react/pages/ReactExample';
|
|
53
|
+
import SvelteExample from './svelte/pages/SvelteExample.svelte';
|
|
54
|
+
import { networkingPlugin } from 'absolutejs';
|
|
55
|
+
|
|
56
|
+
const manifest = await build({
|
|
57
|
+
assetsDirectory: 'example/assets',
|
|
58
|
+
buildDirectory: 'example/build',
|
|
59
|
+
htmlDirectory: 'example/html',
|
|
60
|
+
htmxDirectory: 'example/htmx',
|
|
61
|
+
reactDirectory: 'example/react',
|
|
62
|
+
svelteDirectory: 'example/svelte',
|
|
63
|
+
options: { preserveIntermediateFiles: true }
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
if (!manifest) throw new Error('Manifest generation failed');
|
|
67
|
+
|
|
68
|
+
let counter = 0;
|
|
69
|
+
|
|
70
|
+
export const server = new Elysia()
|
|
71
|
+
.use(staticPlugin({ assets: './example/build', prefix: '' }))
|
|
72
|
+
|
|
73
|
+
// HTML
|
|
74
|
+
.get('/', () =>
|
|
75
|
+
handleHTMLPageRequest('./example/build/html/pages/HtmlExample.html')
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
// React
|
|
79
|
+
.get('/react', () =>
|
|
80
|
+
handleReactPageRequest(ReactExample, manifest['ReactExampleIndex'], {
|
|
81
|
+
test: 123
|
|
82
|
+
})
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
// Svelte
|
|
86
|
+
.get('/svelte', () =>
|
|
87
|
+
handleSveltePageRequest(SvelteExample, manifest, { test: 456 })
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
// HTMX demo
|
|
91
|
+
.get('/htmx', () => file('./example/build/htmx/HtmxHome.html'))
|
|
92
|
+
.get('/htmx/increment', () => new Response(String(++counter)))
|
|
93
|
+
|
|
94
|
+
.use(networkingPlugin)
|
|
95
|
+
.on('error', (error) => {
|
|
96
|
+
const { request } = error;
|
|
97
|
+
console.error(
|
|
98
|
+
`Server error on ${request.method} ${request.url}: ${error.message}`
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### How it works
|
|
104
|
+
|
|
105
|
+
1. **`build()`** scans your project, bundles each framework, and returns a **manifest** that has the server, and client assets required to serve each route.
|
|
106
|
+
2. Route handlers (`handleReactPageRequest`, `handleSveltePageRequest`, …) stream HTML and inject scripts/assets based on that manifest.
|
|
107
|
+
3. The static plugin serves all compiled files from `/build`.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Plugin System
|
|
112
|
+
|
|
113
|
+
Absolute JS piggybacks on the [Elysia plugin API](https://elysiajs.com/plugins). Any Elysia plugin works out of the box; Absolute adds helpers for:
|
|
114
|
+
|
|
115
|
+
| Plugin | Description |
|
|
116
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
117
|
+
| **`absolute-auth`** | Full OAuth2 flow configured with 66 providers and allows full customizability with event handlers |
|
|
118
|
+
| **`networkingPlugin`** | Starts your Elysia server with HOST/PORT defaults and adds a --host flag to toggle listening on localhost or your LAN interface |
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Configuration Philosophy
|
|
123
|
+
|
|
124
|
+
Everything funnels through a single `build()` call:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
await build({
|
|
128
|
+
reactDirectory: 'src/react',
|
|
129
|
+
svelteDirectory: 'src/svelte',
|
|
130
|
+
htmlDirectory: 'src/html',
|
|
131
|
+
htmxDirectory: 'src/htmx',
|
|
132
|
+
assetsDirectory: 'public/assets',
|
|
133
|
+
options: { preserveIntermediateFiles: false }
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
No separate config files or environment variables—just explicit arguments with sensible defaults.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Roadmap
|
|
142
|
+
|
|
143
|
+
- **Angular** handlers
|
|
144
|
+
- Prisma support
|
|
145
|
+
- Biome support
|
|
146
|
+
- Hot‑reload development server
|
|
147
|
+
- First‑class Docker images & hosting recipes
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Contributing
|
|
152
|
+
|
|
153
|
+
Pull requests and issues are welcome! Whether it’s a new plugin, framework handler, or docs improvement:
|
|
154
|
+
|
|
155
|
+
1. Fork & branch.
|
|
156
|
+
2. `bun install && bun test`.
|
|
157
|
+
3. Submit a PR with a clear description.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
Creative Commons **CC BY‑NC 4.0** – see [`LICENSE`](./LICENSE) for details.
|
package/dist/constants.d.ts
CHANGED
|
@@ -10,4 +10,3 @@ export declare const TWO_THIRDS: number;
|
|
|
10
10
|
export declare const DEFAULT_PORT = 3000;
|
|
11
11
|
export declare const DEFAULT_CHUNK_SIZE = 16384;
|
|
12
12
|
export declare const BUN_BUILD_WARNING_SUPPRESSION = "wildcard sideEffects are not supported yet";
|
|
13
|
-
export declare const ANGULAR_BUILD_WARNING_SUPPRESSION = "@angular/common/package.json";
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,6 @@ var TWO_THIRDS = 2 / 3;
|
|
|
12
12
|
var DEFAULT_PORT = 3000;
|
|
13
13
|
var DEFAULT_CHUNK_SIZE = 16384;
|
|
14
14
|
var BUN_BUILD_WARNING_SUPPRESSION = "wildcard sideEffects are not supported yet";
|
|
15
|
-
var ANGULAR_BUILD_WARNING_SUPPRESSION = "@angular/common/package.json";
|
|
16
15
|
// src/core/build.ts
|
|
17
16
|
import { copyFileSync, cpSync, mkdirSync } from "fs";
|
|
18
17
|
import { rm as rm3 } from "fs/promises";
|
|
@@ -294,7 +293,7 @@ var compileVue = async (entryPoints, vueRootDir) => {
|
|
|
294
293
|
const clientOutputFile = join2(clientOutputDir, relative2(vueRootDir, entryPath).replace(/\\/g, "/").replace(/\.vue$/, ".js"));
|
|
295
294
|
await mkdir2(dirname2(indexOutputFile), { recursive: true });
|
|
296
295
|
await write2(indexOutputFile, [
|
|
297
|
-
`import Comp from "${relative2(dirname2(indexOutputFile), clientOutputFile)}";`,
|
|
296
|
+
`import Comp from "${relative2(dirname2(indexOutputFile), clientOutputFile).replace(/\\/g, "/")}";`,
|
|
298
297
|
'import { createSSRApp } from "vue";',
|
|
299
298
|
"const props = window.__INITIAL_PROPS__ ?? {};",
|
|
300
299
|
'createSSRApp(Comp, props).mount("#root");'
|
|
@@ -328,7 +327,7 @@ var compileVue = async (entryPoints, vueRootDir) => {
|
|
|
328
327
|
import { extname as extname2 } from "path";
|
|
329
328
|
var generateManifest = (outputs, buildPath) => outputs.reduce((manifest, artifact) => {
|
|
330
329
|
let relative3 = artifact.path.startsWith(buildPath) ? artifact.path.slice(buildPath.length) : artifact.path;
|
|
331
|
-
relative3 = relative3.replace(/^\/+/, "");
|
|
330
|
+
relative3 = relative3.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
332
331
|
const segments = relative3.split("/");
|
|
333
332
|
const fileWithHash = segments.pop();
|
|
334
333
|
if (!fileWithHash)
|
|
@@ -393,7 +392,7 @@ var generateReactIndexFiles = async (reactPagesDirectory, reactIndexesDirectory)
|
|
|
393
392
|
// src/build/outputLogs.ts
|
|
394
393
|
var outputLogs = (logs) => {
|
|
395
394
|
for (const log of logs) {
|
|
396
|
-
if (log.message.includes(BUN_BUILD_WARNING_SUPPRESSION)
|
|
395
|
+
if (log.message.includes(BUN_BUILD_WARNING_SUPPRESSION))
|
|
397
396
|
continue;
|
|
398
397
|
if (log.level === "error")
|
|
399
398
|
console.error(log);
|
|
@@ -575,7 +574,6 @@ var build = async ({
|
|
|
575
574
|
const htmxCssEntries = htmxDir ? await scanEntryPoints(join5(htmxDir, "styles"), "*.css") : [];
|
|
576
575
|
const reactCssEntries = reactDir ? await scanEntryPoints(join5(reactDir, "styles"), "*.css") : [];
|
|
577
576
|
const svelteCssEntries = svelteDir ? await scanEntryPoints(join5(svelteDir, "styles"), "*.css") : [];
|
|
578
|
-
const angularCssEntries = angularDir ? await scanEntryPoints(join5(angularDir, "styles"), "*.css") : [];
|
|
579
577
|
const { svelteServerPaths, svelteClientPaths } = svelteDir ? await compileSvelte(svelteEntries, svelteDir) : { svelteClientPaths: [], svelteServerPaths: [] };
|
|
580
578
|
const { vueServerPaths, vueIndexPaths, vueCssPaths } = vueDir ? await compileVue(vueEntries, vueDir) : { vueCssPaths: [], vueIndexPaths: [], vueServerPaths: [] };
|
|
581
579
|
const serverEntryPoints = [...svelteServerPaths, ...vueServerPaths];
|
|
@@ -590,8 +588,7 @@ var build = async ({
|
|
|
590
588
|
...reactCssEntries,
|
|
591
589
|
...svelteCssEntries,
|
|
592
590
|
...htmlCssEntries,
|
|
593
|
-
...htmxCssEntries
|
|
594
|
-
...angularCssEntries
|
|
591
|
+
...htmxCssEntries
|
|
595
592
|
];
|
|
596
593
|
if (serverEntryPoints.length === 0 && clientEntryPoints.length === 0 && htmxDir === undefined) {
|
|
597
594
|
console.warn("No entry points found, manifest will be empty.");
|
|
@@ -761,30 +758,6 @@ var renderToReadableStream = async (component, props, {
|
|
|
761
758
|
}
|
|
762
759
|
};
|
|
763
760
|
|
|
764
|
-
// src/svelte/renderToString.ts
|
|
765
|
-
import { render as render2 } from "svelte/server";
|
|
766
|
-
var renderToString = (component, props, {
|
|
767
|
-
bootstrapScriptContent,
|
|
768
|
-
bootstrapScripts = [],
|
|
769
|
-
bootstrapModules = [],
|
|
770
|
-
nonce,
|
|
771
|
-
onError = console.error
|
|
772
|
-
} = {}) => {
|
|
773
|
-
try {
|
|
774
|
-
const { head, body } = typeof props === "undefined" ? render2(component) : render2(component, { props });
|
|
775
|
-
const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
|
|
776
|
-
const scripts = [
|
|
777
|
-
bootstrapScriptContent && `<script${nonceAttr}>${escapeScriptContent(bootstrapScriptContent)}</script>`,
|
|
778
|
-
...bootstrapScripts.map((src) => `<script${nonceAttr} src="${src}"></script>`),
|
|
779
|
-
...bootstrapModules.map((src) => `<script${nonceAttr} type="module" src="${src}"></script>`)
|
|
780
|
-
].filter(Boolean).join("");
|
|
781
|
-
return `<!DOCTYPE html><html lang="en"><head>${head}</head><body>${body}${scripts}</body></html>`;
|
|
782
|
-
} catch (error) {
|
|
783
|
-
onError(error);
|
|
784
|
-
throw error;
|
|
785
|
-
}
|
|
786
|
-
};
|
|
787
|
-
|
|
788
761
|
// src/core/pageHandlers.ts
|
|
789
762
|
var handleReactPageRequest = async (pageComponent, index, ...props) => {
|
|
790
763
|
const [maybeProps] = props;
|
|
@@ -798,17 +771,6 @@ var handleReactPageRequest = async (pageComponent, index, ...props) => {
|
|
|
798
771
|
});
|
|
799
772
|
};
|
|
800
773
|
var handleSveltePageRequest = async (_PageComponent, pagePath, indexPath, props) => {
|
|
801
|
-
const Zone = globalThis.Zone;
|
|
802
|
-
if (Zone && Zone.current) {
|
|
803
|
-
const { default: ImportedPageComponent2 } = await import(pagePath);
|
|
804
|
-
const html = renderToString(ImportedPageComponent2, props, {
|
|
805
|
-
bootstrapModules: indexPath ? [indexPath] : [],
|
|
806
|
-
bootstrapScriptContent: `window.__INITIAL_PROPS__=${JSON.stringify(props)}`
|
|
807
|
-
});
|
|
808
|
-
return new Response(html, {
|
|
809
|
-
headers: { "Content-Type": "text/html" }
|
|
810
|
-
});
|
|
811
|
-
}
|
|
812
774
|
const { default: ImportedPageComponent } = await import(pagePath);
|
|
813
775
|
const stream = await renderToReadableStream(ImportedPageComponent, props, {
|
|
814
776
|
bootstrapModules: indexPath ? [indexPath] : [],
|
|
@@ -948,9 +910,8 @@ export {
|
|
|
948
910
|
HOURS_IN_DAY,
|
|
949
911
|
DEFAULT_PORT,
|
|
950
912
|
DEFAULT_CHUNK_SIZE,
|
|
951
|
-
BUN_BUILD_WARNING_SUPPRESSION
|
|
952
|
-
ANGULAR_BUILD_WARNING_SUPPRESSION
|
|
913
|
+
BUN_BUILD_WARNING_SUPPRESSION
|
|
953
914
|
};
|
|
954
915
|
|
|
955
|
-
//# debugId=
|
|
916
|
+
//# debugId=E4E62E702FF838A264756E2164756E21
|
|
956
917
|
//# sourceMappingURL=index.js.map
|