create-bose 0.1.0 → 0.1.1
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/README.md +42 -0
- package/index.js +301 -168
- package/package.json +32 -31
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# create-bose
|
|
2
|
+
|
|
3
|
+
> Scaffold a new [Bosejs](https://github.com/ChandanBose666/Bosejs) application instantly.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx create-bose my-app
|
|
9
|
+
cd my-app
|
|
10
|
+
npm install
|
|
11
|
+
npm run dev
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Then open `http://localhost:5173`.
|
|
15
|
+
|
|
16
|
+
## What gets created
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
my-app/
|
|
20
|
+
├── src/
|
|
21
|
+
│ └── pages/
|
|
22
|
+
│ ├── index.js # Home — signals, lazy chunks, css$(), bose:bind
|
|
23
|
+
│ └── about.md # Docs — markdown routing with frontmatter
|
|
24
|
+
├── vite.config.js
|
|
25
|
+
├── package.json
|
|
26
|
+
└── .gitignore
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## What the scaffold demonstrates
|
|
30
|
+
|
|
31
|
+
| Feature | Where |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `useSignal` + `bose:bind` | `index.js` — counter synced to DOM |
|
|
34
|
+
| `$()` lazy chunk extraction | `index.js` — increment/decrement/reset |
|
|
35
|
+
| `css$()` scoped styles | `index.js` — all styling via css$() |
|
|
36
|
+
| `bose:state` serialization | `index.js` — state embedded in HTML |
|
|
37
|
+
| Markdown routing | `about.md` — `.md` file → `/about` route |
|
|
38
|
+
| File-based routing | Both pages — automatic URL mapping |
|
|
39
|
+
|
|
40
|
+
## License
|
|
41
|
+
|
|
42
|
+
MIT © [Bosejs Contributors](https://github.com/ChandanBose666/Bosejs)
|
package/index.js
CHANGED
|
@@ -1,168 +1,301 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
|
|
5
|
-
const projectName = process.argv[2] || 'my-bose-app';
|
|
6
|
-
const targetDir = path.resolve(process.cwd(), projectName);
|
|
7
|
-
|
|
8
|
-
console.log(`\nCreating a new Bose app in ${targetDir}...\n`);
|
|
9
|
-
|
|
10
|
-
if (fs.existsSync(targetDir)) {
|
|
11
|
-
console.error(`Error: Directory "${projectName}" already exists. Choose a different name.`);
|
|
12
|
-
process.exit(1);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// ── Helpers
|
|
16
|
-
|
|
17
|
-
function write(filePath, content) {
|
|
18
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
19
|
-
fs.writeFileSync(filePath, content);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function file(...segments) {
|
|
23
|
-
return path.join(targetDir, ...segments);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// ── package.json
|
|
27
|
-
|
|
28
|
-
write(file('package.json'), JSON.stringify({
|
|
29
|
-
name: projectName,
|
|
30
|
-
version: '0.1.0',
|
|
31
|
-
private: true,
|
|
32
|
-
type: 'module',
|
|
33
|
-
scripts: {
|
|
34
|
-
dev: 'vite',
|
|
35
|
-
build: 'vite build',
|
|
36
|
-
preview: 'vite preview',
|
|
37
|
-
},
|
|
38
|
-
dependencies: {
|
|
39
|
-
'@bosejs/core': 'latest',
|
|
40
|
-
'@bosejs/state': 'latest',
|
|
41
|
-
},
|
|
42
|
-
devDependencies: {
|
|
43
|
-
vite: 'latest',
|
|
44
|
-
},
|
|
45
|
-
}, null, 2));
|
|
46
|
-
|
|
47
|
-
// ── vite.config.js
|
|
48
|
-
|
|
49
|
-
write(file('vite.config.js'), `\
|
|
50
|
-
import { defineConfig } from 'vite';
|
|
51
|
-
import bosePlugin from '@bosejs/core';
|
|
52
|
-
|
|
53
|
-
export default defineConfig({
|
|
54
|
-
plugins: [bosePlugin()],
|
|
55
|
-
});
|
|
56
|
-
`);
|
|
57
|
-
|
|
58
|
-
// ── src/pages/index.js
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
bose
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
const projectName = process.argv[2] || 'my-bose-app';
|
|
6
|
+
const targetDir = path.resolve(process.cwd(), projectName);
|
|
7
|
+
|
|
8
|
+
console.log(`\nCreating a new Bose app in ${targetDir}...\n`);
|
|
9
|
+
|
|
10
|
+
if (fs.existsSync(targetDir)) {
|
|
11
|
+
console.error(`Error: Directory "${projectName}" already exists. Choose a different name.`);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
function write(filePath, content) {
|
|
18
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
19
|
+
fs.writeFileSync(filePath, content);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function file(...segments) {
|
|
23
|
+
return path.join(targetDir, ...segments);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ── package.json ──────────────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
write(file('package.json'), JSON.stringify({
|
|
29
|
+
name: projectName,
|
|
30
|
+
version: '0.1.0',
|
|
31
|
+
private: true,
|
|
32
|
+
type: 'module',
|
|
33
|
+
scripts: {
|
|
34
|
+
dev: 'vite',
|
|
35
|
+
build: 'vite build',
|
|
36
|
+
preview: 'vite preview',
|
|
37
|
+
},
|
|
38
|
+
dependencies: {
|
|
39
|
+
'@bosejs/core': 'latest',
|
|
40
|
+
'@bosejs/state': 'latest',
|
|
41
|
+
},
|
|
42
|
+
devDependencies: {
|
|
43
|
+
vite: 'latest',
|
|
44
|
+
},
|
|
45
|
+
}, null, 2));
|
|
46
|
+
|
|
47
|
+
// ── vite.config.js ────────────────────────────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
write(file('vite.config.js'), `\
|
|
50
|
+
import { defineConfig } from 'vite';
|
|
51
|
+
import bosePlugin from '@bosejs/core';
|
|
52
|
+
|
|
53
|
+
export default defineConfig({
|
|
54
|
+
plugins: [bosePlugin()],
|
|
55
|
+
});
|
|
56
|
+
`);
|
|
57
|
+
|
|
58
|
+
// ── src/pages/index.js ────────────────────────────────────────────────────────
|
|
59
|
+
// Home page — showcases: useSignal, $(), bose:bind, bose:state, css$()
|
|
60
|
+
// Route: /
|
|
61
|
+
|
|
62
|
+
write(file('src', 'pages', 'index.js'), `\
|
|
63
|
+
import { useSignal } from '@bosejs/state';
|
|
64
|
+
|
|
65
|
+
export default function Home() {
|
|
66
|
+
// useSignal — reactive state. The compiler injects a stable ID so the
|
|
67
|
+
// runtime can sync any DOM node bound with bose:bind after resumption.
|
|
68
|
+
const count = useSignal(0);
|
|
69
|
+
|
|
70
|
+
// css$() — scoped styles extracted at build time. Zero runtime overhead.
|
|
71
|
+
// Class names are hashed so there are no collisions across components.
|
|
72
|
+
const s = css$(\`
|
|
73
|
+
.wrap { font-family: system-ui, sans-serif; min-height: 100vh; background: #020617; color: #f8fafc; margin: 0; }
|
|
74
|
+
.nav { display: flex; justify-content: space-between; align-items: center; padding: 1.25rem 2rem; border-bottom: 1px solid #1e293b; }
|
|
75
|
+
.brand { font-weight: 800; font-size: 1.2rem; color: #f8fafc; text-decoration: none; }
|
|
76
|
+
.links a { color: #94a3b8; text-decoration: none; font-size: 0.9rem; margin-left: 1.5rem; }
|
|
77
|
+
.links a:hover { color: #f8fafc; }
|
|
78
|
+
.hero { text-align: center; padding: 4rem 2rem 2.5rem; }
|
|
79
|
+
.title { font-size: clamp(2rem, 6vw, 3.75rem); font-weight: 900; margin: 0 0 1rem; }
|
|
80
|
+
.sub { color: #94a3b8; font-size: 1.1rem; max-width: 500px; margin: 0 auto 2rem; line-height: 1.7; }
|
|
81
|
+
.pills { display: flex; gap: 0.6rem; justify-content: center; flex-wrap: wrap; margin-bottom: 3rem; }
|
|
82
|
+
.pill { padding: 0.3rem 0.85rem; border-radius: 99px; font-size: 0.75rem; font-weight: 600; }
|
|
83
|
+
.pBlue { background: #172554; color: #93c5fd; }
|
|
84
|
+
.pPurple { background: #2e1065; color: #c4b5fd; }
|
|
85
|
+
.pGreen { background: #14532d; color: #86efac; }
|
|
86
|
+
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 1.25rem; max-width: 840px; margin: 0 auto 3.5rem; padding: 0 2rem; }
|
|
87
|
+
.card { background: #0f172a; border: 1px solid #1e293b; border-radius: 0.75rem; padding: 1.5rem; }
|
|
88
|
+
.icon { font-size: 1.5rem; margin-bottom: 0.6rem; }
|
|
89
|
+
.ctitle { font-size: 0.95rem; font-weight: 700; margin: 0 0 0.4rem; }
|
|
90
|
+
.cbody { font-size: 0.85rem; color: #64748b; line-height: 1.6; margin: 0; }
|
|
91
|
+
.demo { text-align: center; padding: 0 2rem 2.5rem; }
|
|
92
|
+
.hint { color: #475569; font-size: 0.82rem; margin-bottom: 1.25rem; }
|
|
93
|
+
.num { font-size: 6rem; font-weight: 900; color: #6366f1; line-height: 1; margin-bottom: 1.25rem; }
|
|
94
|
+
.row { display: flex; gap: 0.75rem; justify-content: center; }
|
|
95
|
+
.btn { padding: 0.65rem 1.5rem; border-radius: 0.5rem; border: 1px solid #334155; background: #1e293b; color: #f8fafc; font-size: 1.1rem; cursor: pointer; }
|
|
96
|
+
.btnP { background: #6366f1; border-color: #6366f1; }
|
|
97
|
+
.foot { text-align: center; padding: 2rem; border-top: 1px solid #1e293b; color: #475569; font-size: 0.85rem; }
|
|
98
|
+
.foot a { color: #6366f1; text-decoration: none; }
|
|
99
|
+
\`);
|
|
100
|
+
|
|
101
|
+
// $() — global compiler marker. No import needed.
|
|
102
|
+
// Each closure is extracted into its own lazy JS chunk at build time.
|
|
103
|
+
// 0 bytes of JS ship with the page — chunks are fetched on first use.
|
|
104
|
+
const increment = $(() => { count.value++; });
|
|
105
|
+
const decrement = $(() => { count.value--; });
|
|
106
|
+
const reset = $(() => { count.value = 0; });
|
|
107
|
+
|
|
108
|
+
return \`
|
|
109
|
+
<div class="\${s.wrap}">
|
|
110
|
+
|
|
111
|
+
<nav class="\${s.nav}">
|
|
112
|
+
<a href="/" class="\${s.brand}">Bosejs</a>
|
|
113
|
+
<div class="\${s.links}">
|
|
114
|
+
<a href="/">Home</a>
|
|
115
|
+
<a href="/about">About</a>
|
|
116
|
+
</div>
|
|
117
|
+
</nav>
|
|
118
|
+
|
|
119
|
+
<div class="\${s.hero}">
|
|
120
|
+
<h1 class="\${s.title}">Resumable Islands</h1>
|
|
121
|
+
<p class="\${s.sub}">
|
|
122
|
+
Zero JS on page load. Closures extracted at build time,
|
|
123
|
+
resumed on first interaction — no hydration, no virtual DOM.
|
|
124
|
+
</p>
|
|
125
|
+
<div class="\${s.pills}">
|
|
126
|
+
<span class="\${s.pill} \${s.pBlue}">Zero Hydration</span>
|
|
127
|
+
<span class="\${s.pill} \${s.pPurple}">Lazy Chunks</span>
|
|
128
|
+
<span class="\${s.pill} \${s.pGreen}">Fine-Grained Signals</span>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
|
|
132
|
+
<div class="\${s.cards}">
|
|
133
|
+
<div class="\${s.card}">
|
|
134
|
+
<div class="\${s.icon}">⚡</div>
|
|
135
|
+
<p class="\${s.ctitle}">Zero Hydration</p>
|
|
136
|
+
<p class="\${s.cbody}">State is serialized into HTML. The browser resumes execution — never re-runs your code.</p>
|
|
137
|
+
</div>
|
|
138
|
+
<div class="\${s.card}">
|
|
139
|
+
<div class="\${s.icon}">✂️</div>
|
|
140
|
+
<p class="\${s.ctitle}">Automatic Code Splitting</p>
|
|
141
|
+
<p class="\${s.cbody}">Wrap any logic in <code>\$()</code> and the compiler extracts it into a lazy chunk — 0 bytes until needed.</p>
|
|
142
|
+
</div>
|
|
143
|
+
<div class="\${s.card}">
|
|
144
|
+
<div class="\${s.icon}">🔗</div>
|
|
145
|
+
<p class="\${s.ctitle}">Reactive Signals</p>
|
|
146
|
+
<p class="\${s.cbody}"><code>useSignal</code> creates fine-grained reactive state. DOM updates are surgical — no diffing.</p>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<div class="\${s.demo}">
|
|
151
|
+
<p class="\${s.hint}">Open DevTools → Network → click a button to see the lazy chunk load</p>
|
|
152
|
+
<!-- bose:bind keeps this span in sync with the 'count' signal -->
|
|
153
|
+
<div class="\${s.num}">
|
|
154
|
+
<span bose:bind="count">\${count.value}</span>
|
|
155
|
+
</div>
|
|
156
|
+
<div class="\${s.row}">
|
|
157
|
+
<button class="\${s.btn}"
|
|
158
|
+
bose:on:click="\${decrement.chunk}"
|
|
159
|
+
bose:state='\${JSON.stringify({ count: count.value })}'>−</button>
|
|
160
|
+
<button class="\${s.btn}"
|
|
161
|
+
bose:on:click="\${reset.chunk}"
|
|
162
|
+
bose:state='\${JSON.stringify({ count: count.value })}'>Reset</button>
|
|
163
|
+
<button class="\${s.btn} \${s.btnP}"
|
|
164
|
+
bose:on:click="\${increment.chunk}"
|
|
165
|
+
bose:state='\${JSON.stringify({ count: count.value })}'>+</button>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
<div class="\${s.foot}">
|
|
170
|
+
<a href="/about">Read the docs →</a>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
</div>
|
|
174
|
+
\`;
|
|
175
|
+
}
|
|
176
|
+
`);
|
|
177
|
+
|
|
178
|
+
// ── src/pages/about.md ────────────────────────────────────────────────────────
|
|
179
|
+
// Markdown page — showcases file-based routing with .md files.
|
|
180
|
+
// Route: /about
|
|
181
|
+
|
|
182
|
+
write(file('src', 'pages', 'about.md'), `\
|
|
183
|
+
---
|
|
184
|
+
title: About Bosejs
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
# About Bosejs
|
|
188
|
+
|
|
189
|
+
Bosejs combines Astro's Islands Architecture with Qwik's Resumability to deliver
|
|
190
|
+
web pages that ship **zero JavaScript** until the user interacts.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## How it works
|
|
195
|
+
|
|
196
|
+
1. **You write standard JS** — functions, closures, signals. No new syntax to learn.
|
|
197
|
+
2. **The compiler shreds it** — every \`$()\` closure is extracted into its own chunk at build time.
|
|
198
|
+
3. **HTML ships with 0 JS** — event handlers live as HTML attributes; state is serialized inline.
|
|
199
|
+
4. **On first interaction** — the runtime fetches only the chunk needed. Execution resumes instantly.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Core concepts
|
|
204
|
+
|
|
205
|
+
### \`$()\` — Lazy closure extraction
|
|
206
|
+
|
|
207
|
+
Wrap any event handler in \`$()\`. The Babel compiler extracts it into a separate JS file.
|
|
208
|
+
No import needed — \`$\` is a global injected by the framework.
|
|
209
|
+
|
|
210
|
+
\`\`\`js
|
|
211
|
+
const increment = $(() => {
|
|
212
|
+
count.value++;
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// In your HTML:
|
|
216
|
+
// bose:on:click="\${increment.chunk}"
|
|
217
|
+
\`\`\`
|
|
218
|
+
|
|
219
|
+
### \`useSignal\` — Reactive state
|
|
220
|
+
|
|
221
|
+
Fine-grained reactive state from \`@bosejs/state\`. DOM nodes bound with
|
|
222
|
+
\`bose:bind\` update surgically when the signal changes — no re-render, no diffing.
|
|
223
|
+
|
|
224
|
+
\`\`\`js
|
|
225
|
+
import { useSignal } from '@bosejs/state';
|
|
226
|
+
|
|
227
|
+
const count = useSignal(0);
|
|
228
|
+
// <span bose:bind="count">\${count.value}</span>
|
|
229
|
+
\`\`\`
|
|
230
|
+
|
|
231
|
+
### \`bose:state\` — Serialized context
|
|
232
|
+
|
|
233
|
+
State is embedded directly in HTML so the chunk always has the context it needs
|
|
234
|
+
on resumption — even after the page has been cached or served from a CDN.
|
|
235
|
+
|
|
236
|
+
\`\`\`html
|
|
237
|
+
<button
|
|
238
|
+
bose:on:click="\${increment.chunk}"
|
|
239
|
+
bose:state='{"count":0}'>
|
|
240
|
+
+
|
|
241
|
+
</button>
|
|
242
|
+
\`\`\`
|
|
243
|
+
|
|
244
|
+
### \`css$()\` — Scoped styles
|
|
245
|
+
|
|
246
|
+
Write CSS next to your component. Styles are extracted at build time and scoped
|
|
247
|
+
automatically. Zero runtime overhead.
|
|
248
|
+
|
|
249
|
+
\`\`\`js
|
|
250
|
+
const s = css$(\`.btn { background: #6366f1; color: white; }\`);
|
|
251
|
+
// <button class="\${s.btn}">Click me</button>
|
|
252
|
+
\`\`\`
|
|
253
|
+
|
|
254
|
+
### File-based routing
|
|
255
|
+
|
|
256
|
+
Drop a file in \`src/pages/\` and it becomes a route automatically.
|
|
257
|
+
|
|
258
|
+
| File | Route |
|
|
259
|
+
|---|---|
|
|
260
|
+
| \`src/pages/index.js\` | \`/\` |
|
|
261
|
+
| \`src/pages/about.md\` | \`/about\` |
|
|
262
|
+
| \`src/pages/product/[id].js\` | \`/product/123\` |
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Packages
|
|
267
|
+
|
|
268
|
+
| Package | You install? | Role |
|
|
269
|
+
|---|---|---|
|
|
270
|
+
| \`@bosejs/core\` | ✅ Yes | Vite plugin — routing, SSR, dev server |
|
|
271
|
+
| \`@bosejs/state\` | ✅ Yes | Signals — \`useSignal\` |
|
|
272
|
+
| \`@bosejs/compiler\` | 🔧 Auto | Babel plugin — extracts \`$()\` closures |
|
|
273
|
+
| \`@bosejs/runtime\` | 🔧 Auto | Tiny browser loader — resumes event handlers |
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
[← Back to home](/)
|
|
278
|
+
`);
|
|
279
|
+
|
|
280
|
+
// ── .gitignore ────────────────────────────────────────────────────────────────
|
|
281
|
+
|
|
282
|
+
write(file('.gitignore'), `\
|
|
283
|
+
node_modules/
|
|
284
|
+
dist/
|
|
285
|
+
public/chunks/
|
|
286
|
+
bose-error.log
|
|
287
|
+
.env*.local
|
|
288
|
+
`);
|
|
289
|
+
|
|
290
|
+
// ── Done ──────────────────────────────────────────────────────────────────────
|
|
291
|
+
|
|
292
|
+
const steps = [
|
|
293
|
+
` cd ${projectName}`,
|
|
294
|
+
` npm install`,
|
|
295
|
+
` npm run dev`,
|
|
296
|
+
];
|
|
297
|
+
|
|
298
|
+
console.log('Done! Next steps:\n');
|
|
299
|
+
console.log(steps.join('\n'));
|
|
300
|
+
console.log('\nThen open http://localhost:5173\n');
|
|
301
|
+
console.log('Pages:\n / → Home (signals, lazy chunks, css$)\n /about → Docs (markdown routing)\n');
|
package/package.json
CHANGED
|
@@ -1,31 +1,32 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "create-bose",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Scaffold a new Bose framework application.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"bin": {
|
|
7
|
-
"create-bose": "index.js"
|
|
8
|
-
},
|
|
9
|
-
"files": [
|
|
10
|
-
"index.js",
|
|
11
|
-
"LICENSE"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "create-bose",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Scaffold a new Bose framework application.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-bose": "index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js",
|
|
11
|
+
"LICENSE",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18.0.0"
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/bosejs/bosejs.git",
|
|
23
|
+
"directory": "packages/create-bose"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"bose",
|
|
27
|
+
"scaffold",
|
|
28
|
+
"cli",
|
|
29
|
+
"create"
|
|
30
|
+
],
|
|
31
|
+
"license": "MIT"
|
|
32
|
+
}
|