@cruxjs/app 0.0.6 β 0.0.7
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 +565 -529
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
</div>
|
|
9
9
|
|
|
10
10
|
<div align="center">
|
|
11
|
-
<img src="https://img.shields.io/badge/v-0.0.
|
|
12
|
-
<img src="https://img.shields.io/badge/π₯-@cruxjs-black"
|
|
11
|
+
<img src="https://img.shields.io/badge/v-0.0.7-black"/>
|
|
12
|
+
<a href="https://github.com/cruxjs-org"><img src="https://img.shields.io/badge/π₯-@cruxjs-black"/></a>
|
|
13
13
|
<br>
|
|
14
|
+
<img src="https://img.shields.io/badge/coverage-~%25-brightgreen" alt="Test Coverage" />
|
|
14
15
|
<img src="https://img.shields.io/github/issues/cruxjs-org/app?style=flat" alt="Github Repo Issues" />
|
|
15
16
|
<img src="https://img.shields.io/github/stars/cruxjs-org/app?style=social" alt="GitHub Repo stars" />
|
|
16
17
|
</div>
|
|
@@ -22,602 +23,636 @@
|
|
|
22
23
|
|
|
23
24
|
<!-- βββββββββββββββββββββββββββββββ DOC βββββββββββββββββββββββββββββββ -->
|
|
24
25
|
|
|
25
|
-
- ##
|
|
26
|
-
|
|
27
|
-
> **_CruxJS is a full-stack framework orchestrator built on [@minejs](https://github.com/minejs-org) that empowers developers to build modern web applications with **zero configuration**. It orchestrates without dictatingβproviding a plugin-based architecture where you control the flow._**
|
|
26
|
+
- ## Overview π
|
|
28
27
|
|
|
29
|
-
-
|
|
28
|
+
- #### Why ?
|
|
29
|
+
> To provide a unified full-stack framework that orchestrates server configuration, client builds, i18n, styling, SPA integration, and plugins in a single declarative configuration with zero boilerplate.
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
- #### When ?
|
|
32
|
+
> When you need a production-ready full-stack application with:
|
|
33
|
+
> - Server configuration (port, logging, middleware)
|
|
34
|
+
> - Automatic client bundling with Bun
|
|
35
|
+
> - Style preprocessing (SCSS/Sass)
|
|
36
|
+
> - i18n setup and configuration
|
|
37
|
+
> - SPA plugin integration
|
|
38
|
+
> - Plugin system for extensibility
|
|
39
|
+
> - Unified lifecycle management
|
|
32
40
|
|
|
33
|
-
|
|
34
|
-
# Install CruxJS App
|
|
35
|
-
hmm i @cruxjs/app
|
|
41
|
+
> When you want to build modern full-stack SPAs without framework complexity.
|
|
36
42
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
```
|
|
43
|
+
<br>
|
|
44
|
+
<br>
|
|
40
45
|
|
|
41
|
-
|
|
46
|
+
- ## Quick Start π₯
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
import { createApp, type AppConfig } from '@cruxjs/app';
|
|
45
|
-
|
|
46
|
-
const config: AppConfig = {
|
|
47
|
-
debug: true,
|
|
48
|
-
|
|
49
|
-
// Server configuration
|
|
50
|
-
server: {
|
|
51
|
-
port: 3000,
|
|
52
|
-
host: 'localhost'
|
|
53
|
-
},
|
|
54
|
-
|
|
55
|
-
// Client build configuration (bundles with Bun)
|
|
56
|
-
client: {
|
|
57
|
-
entry: './src/client/browser.tsx',
|
|
58
|
-
output: './src/shared/static/dist/js',
|
|
59
|
-
minify: true,
|
|
60
|
-
sourcemap: false
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
// UI library (installs from npm and exports min.css)
|
|
64
|
-
ui: {
|
|
65
|
-
package: '@mineui/core',
|
|
66
|
-
output: './src/shared/static/dist/css'
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
// Custom styles (compiles SCSS/CSS)
|
|
70
|
-
style: {
|
|
71
|
-
entry: './src/client/ui/style/index.scss',
|
|
72
|
-
output: './src/shared/static/dist/css/extra.css',
|
|
73
|
-
minify: true,
|
|
74
|
-
sourcemap: false
|
|
75
|
-
},
|
|
76
|
-
|
|
77
|
-
// Static files serving
|
|
78
|
-
static: {
|
|
79
|
-
path: '/static',
|
|
80
|
-
directory: './src/shared/static',
|
|
81
|
-
maxAge: 3600
|
|
82
|
-
},
|
|
83
|
-
|
|
84
|
-
// Plugins (SPA, API routes, databases, etc.)
|
|
85
|
-
plugins: [/* your plugins */]
|
|
86
|
-
};
|
|
48
|
+
> install [`hmm`](https://github.com/minejs-org/hmm) first.
|
|
87
49
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
50
|
+
```bash
|
|
51
|
+
# in your terminal
|
|
52
|
+
hmm i @cruxjs/app
|
|
53
|
+
```
|
|
92
54
|
|
|
93
|
-
<
|
|
55
|
+
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> </div>
|
|
94
56
|
|
|
95
|
-
-
|
|
57
|
+
- #### Setup
|
|
96
58
|
|
|
97
|
-
|
|
59
|
+
> Create your application configuration in a single file:
|
|
98
60
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
61
|
+
```typescript
|
|
62
|
+
import { createApp, AppConfig } from '@cruxjs/app';
|
|
63
|
+
import { serverSPA } from '@cruxjs/spa';
|
|
64
|
+
|
|
65
|
+
const appConfig: AppConfig = {
|
|
66
|
+
debug : true,
|
|
67
|
+
|
|
68
|
+
// Server configuration
|
|
69
|
+
server: {
|
|
70
|
+
port : 3000,
|
|
71
|
+
host : 'localhost',
|
|
72
|
+
logging: {
|
|
73
|
+
level : 'info',
|
|
74
|
+
pretty : true
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
// Static files
|
|
79
|
+
static: {
|
|
80
|
+
path : '/static',
|
|
81
|
+
directory : './src/shared/static',
|
|
82
|
+
maxAge : 3600
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
// Client build configuration
|
|
86
|
+
client: {
|
|
87
|
+
entry : './src/app/client.ts',
|
|
88
|
+
output : './src/shared/static/dist/js',
|
|
89
|
+
minify : true,
|
|
90
|
+
sourcemap : false
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
// i18n configuration
|
|
94
|
+
i18n: {
|
|
95
|
+
defaultLanguage : 'en',
|
|
96
|
+
supportedLanguages : ['en', 'ar'],
|
|
97
|
+
basePath : './src/shared/static/dist/i18n'
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
// Style build configuration
|
|
101
|
+
style: {
|
|
102
|
+
entry : './src/app/ui/style/index.scss',
|
|
103
|
+
output : './src/shared/static/dist/css/min.css',
|
|
104
|
+
minify : true
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
plugins : []
|
|
108
|
+
};
|
|
116
109
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
import { createApp, type AppConfig } from '@cruxjs/app';
|
|
122
|
-
import { serverSPA } from '@cruxplug/spa';
|
|
123
|
-
|
|
124
|
-
const spaPlugin = serverSPA({
|
|
125
|
-
baseUrl: 'http://localhost:3000',
|
|
126
|
-
clientEntry: './src/client/browser.tsx',
|
|
127
|
-
clientScriptPath: ['/static/dist/js/browser.js'],
|
|
128
|
-
clientStylePath: ['/static/dist/css/min.css', '/static/dist/css/extra.css'],
|
|
129
|
-
|
|
130
|
-
// SEO & E-E-A-T configuration
|
|
131
|
-
author: 'Your Team',
|
|
132
|
-
authorUrl: 'https://example.com/about',
|
|
133
|
-
defaultDescription: 'Your app description',
|
|
134
|
-
defaultKeywords: ['key', 'words'],
|
|
135
|
-
|
|
136
|
-
enableAutoNotFound: true,
|
|
137
|
-
pages: [
|
|
138
|
-
{
|
|
139
|
-
title: 'Home',
|
|
140
|
-
path: '/',
|
|
141
|
-
description: 'Welcome',
|
|
142
|
-
keywords: ['home']
|
|
143
|
-
}
|
|
144
|
-
],
|
|
145
|
-
errorPages: [
|
|
146
|
-
{
|
|
147
|
-
statusCode: 404,
|
|
148
|
-
title: '404 - Not Found',
|
|
149
|
-
path: '/404'
|
|
150
|
-
}
|
|
151
|
-
]
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
const config: AppConfig = {
|
|
155
|
-
debug: true,
|
|
156
|
-
|
|
157
|
-
server: {
|
|
158
|
-
port: 3000,
|
|
159
|
-
host: 'localhost',
|
|
160
|
-
logging: { level: 'info', pretty: true }
|
|
161
|
-
},
|
|
162
|
-
|
|
163
|
-
// Build configuration
|
|
164
|
-
client: {
|
|
165
|
-
entry: './src/client/browser.tsx',
|
|
166
|
-
output: './src/shared/static/dist/js',
|
|
167
|
-
minify: true
|
|
168
|
-
},
|
|
169
|
-
|
|
170
|
-
ui: {
|
|
171
|
-
package: '@mineui/core',
|
|
172
|
-
output: './src/shared/static/dist/css'
|
|
173
|
-
},
|
|
174
|
-
|
|
175
|
-
style: {
|
|
176
|
-
entry: './src/client/ui/style/index.scss',
|
|
177
|
-
output: './src/shared/static/dist/css/extra.css',
|
|
178
|
-
minify: true
|
|
179
|
-
},
|
|
180
|
-
|
|
181
|
-
static: {
|
|
182
|
-
path: '/static',
|
|
183
|
-
directory: './src/shared/static',
|
|
184
|
-
maxAge: 3600
|
|
185
|
-
},
|
|
186
|
-
|
|
187
|
-
plugins: [spaPlugin]
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
const app = createApp(config);
|
|
191
|
-
await app.start();
|
|
192
|
-
```
|
|
110
|
+
// Create and start app
|
|
111
|
+
const app = createApp(appConfig);
|
|
112
|
+
app.start();
|
|
113
|
+
```
|
|
193
114
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
**src/client/browser.tsx**
|
|
197
|
-
```typescript
|
|
198
|
-
import { mount } from '@minejs/jsx';
|
|
199
|
-
import { App } from './ui/App';
|
|
200
|
-
import { ClientManager } from '@cruxjs/client';
|
|
201
|
-
import { HomePage } from './ui/pages/HomePage';
|
|
202
|
-
import { NotFoundPage } from './ui/pages/NotFoundPage';
|
|
203
|
-
|
|
204
|
-
const clientManager = new ClientManager({
|
|
205
|
-
debug: true,
|
|
206
|
-
routes: {
|
|
207
|
-
'/': HomePage,
|
|
208
|
-
'/about': AboutPage,
|
|
209
|
-
// ...more routes
|
|
210
|
-
},
|
|
211
|
-
notFoundComponent: NotFoundPage,
|
|
212
|
-
errorComponent: ErrorPage
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
(async () => {
|
|
216
|
-
await clientManager.boot();
|
|
217
|
-
mount(<App />, '#app');
|
|
218
|
-
await clientManager.ready('#app-main');
|
|
219
|
-
})();
|
|
220
|
-
```
|
|
115
|
+
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> </div>
|
|
116
|
+
<br>
|
|
221
117
|
|
|
222
|
-
|
|
118
|
+
- #### Usage
|
|
223
119
|
|
|
224
|
-
|
|
225
|
-
```typescript
|
|
226
|
-
import type { RouteDefinition } from '@cruxjs/app';
|
|
120
|
+
> Add plugins and configure SPA:
|
|
227
121
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
122
|
+
```typescript
|
|
123
|
+
// Create SPA plugin
|
|
124
|
+
const spaPlugin = serverSPA({
|
|
125
|
+
baseUrl : 'http://localhost:3000',
|
|
126
|
+
clientEntry : './src/app/client.ts',
|
|
127
|
+
clientScriptPath : ['/static/dist/js/client.js'],
|
|
128
|
+
clientStylePath : ['/static/dist/css/min.css'],
|
|
129
|
+
|
|
130
|
+
pages: [
|
|
131
|
+
{
|
|
132
|
+
title : 'Home',
|
|
133
|
+
path : '/',
|
|
134
|
+
description : 'Welcome to our app'
|
|
135
|
+
}
|
|
136
|
+
],
|
|
137
|
+
|
|
138
|
+
autoBootstrapClient : true
|
|
139
|
+
}, appConfig);
|
|
140
|
+
|
|
141
|
+
// Add plugin to app
|
|
142
|
+
appConfig.plugins.push(spaPlugin);
|
|
143
|
+
|
|
144
|
+
// Start app
|
|
145
|
+
const app = createApp(appConfig);
|
|
146
|
+
app.start();
|
|
147
|
+
```
|
|
246
148
|
|
|
247
|
-
|
|
149
|
+
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> </div>
|
|
150
|
+
|
|
151
|
+
- #### Server Configuration
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
server: {
|
|
155
|
+
// Port and host
|
|
156
|
+
port : 3000,
|
|
157
|
+
host : 'localhost',
|
|
158
|
+
|
|
159
|
+
// Logging configuration
|
|
160
|
+
logging: {
|
|
161
|
+
level : 'info', // 'debug' | 'info' | 'warn' | 'error'
|
|
162
|
+
pretty : true // Pretty-print logs
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
// CORS configuration (optional)
|
|
166
|
+
cors: {
|
|
167
|
+
origin : 'http://localhost:3000',
|
|
168
|
+
credentials : true
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
// Middleware (optional)
|
|
172
|
+
middleware: [
|
|
173
|
+
// Add custom middleware here
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
- #### Client Build Configuration
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
client: {
|
|
182
|
+
// Entry file for client bundle
|
|
183
|
+
entry : './src/app/client.ts',
|
|
184
|
+
|
|
185
|
+
// Output directory
|
|
186
|
+
output : './src/shared/static/dist/js',
|
|
187
|
+
|
|
188
|
+
// Build options
|
|
189
|
+
minify : true, // Minify bundle
|
|
190
|
+
sourcemap : false, // Generate source maps
|
|
191
|
+
target : 'browser', // Build target (browser, node, etc.)
|
|
192
|
+
external : [], // External dependencies
|
|
193
|
+
|
|
194
|
+
// Custom build configuration
|
|
195
|
+
define: {
|
|
196
|
+
'process.env.VERSION': '"1.0.0"'
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
- #### i18n Configuration
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
i18n: {
|
|
205
|
+
// Default language
|
|
206
|
+
defaultLanguage : 'en',
|
|
207
|
+
|
|
208
|
+
// Supported languages
|
|
209
|
+
supportedLanguages : ['en', 'ar', 'fr', 'de'],
|
|
210
|
+
|
|
211
|
+
// Base path for translation files
|
|
212
|
+
basePath : './src/shared/static/dist/i18n',
|
|
213
|
+
|
|
214
|
+
// Custom storage (optional)
|
|
215
|
+
storage : 'localStorage'
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
- #### Style Build Configuration
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
style: {
|
|
223
|
+
// Entry SCSS/Sass file
|
|
224
|
+
entry : './src/app/ui/style/index.scss',
|
|
225
|
+
|
|
226
|
+
// Output CSS file
|
|
227
|
+
output : './src/shared/static/dist/css/min.css',
|
|
228
|
+
|
|
229
|
+
// Build options
|
|
230
|
+
minify : true, // Minify CSS
|
|
231
|
+
sourcemap : false, // Generate source maps
|
|
232
|
+
|
|
233
|
+
// Include paths
|
|
234
|
+
includePaths: [
|
|
235
|
+
'./src/app/ui/components'
|
|
236
|
+
]
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
- #### Middleware
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
// Add custom middleware for request/response handling
|
|
244
|
+
server: {
|
|
245
|
+
middleware: [
|
|
246
|
+
{
|
|
247
|
+
path : '/api/*',
|
|
248
|
+
handler : async (req, res) => {
|
|
249
|
+
// Custom API handling
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
- #### Plugins
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
// Create custom plugins
|
|
260
|
+
const myPlugin = {
|
|
261
|
+
name : 'my-plugin',
|
|
262
|
+
version : '1.0.0',
|
|
263
|
+
|
|
264
|
+
onRegister : async (app) => {
|
|
265
|
+
console.log('Plugin registered');
|
|
266
|
+
},
|
|
267
|
+
|
|
268
|
+
onAwake : async (ctx) => {
|
|
269
|
+
console.log('Plugin awake');
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
onStart : async (ctx) => {
|
|
273
|
+
console.log('Plugin starting');
|
|
274
|
+
},
|
|
275
|
+
|
|
276
|
+
onReady : async (ctx) => {
|
|
277
|
+
console.log('Plugin ready');
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
appConfig.plugins.push(myPlugin);
|
|
282
|
+
```
|
|
248
283
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
// Import UI library variables (if available)
|
|
252
|
-
@import '@mineui/core/scss/variables';
|
|
284
|
+
<br>
|
|
285
|
+
<br>
|
|
253
286
|
|
|
254
|
-
|
|
255
|
-
body {
|
|
256
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
257
|
-
margin: 0;
|
|
258
|
-
padding: 0;
|
|
259
|
-
}
|
|
287
|
+
- ## Complete Example π
|
|
260
288
|
|
|
261
|
-
.
|
|
262
|
-
display: flex;
|
|
263
|
-
flex-direction: column;
|
|
264
|
-
min-height: 100vh;
|
|
265
|
-
}
|
|
289
|
+
- ### src/index.ts
|
|
266
290
|
|
|
267
|
-
|
|
268
|
-
|
|
291
|
+
```typescript
|
|
292
|
+
import { createApp, AppConfig } from '@cruxjs/app';
|
|
293
|
+
import { serverSPA } from '@cruxjs/spa';
|
|
294
|
+
|
|
295
|
+
import * as HomePage from './app/ui/pages/home';
|
|
296
|
+
import * as ErrorPage from './app/ui/pages/error';
|
|
297
|
+
|
|
298
|
+
const appConfig: AppConfig = {
|
|
299
|
+
debug: true,
|
|
300
|
+
|
|
301
|
+
server: {
|
|
302
|
+
port : 3000,
|
|
303
|
+
host : 'localhost',
|
|
304
|
+
logging: {
|
|
305
|
+
level : 'info',
|
|
306
|
+
pretty : true
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
static: {
|
|
311
|
+
path : '/static',
|
|
312
|
+
directory : './src/shared/static',
|
|
313
|
+
maxAge : 3600,
|
|
314
|
+
index : ['index.html']
|
|
315
|
+
},
|
|
316
|
+
|
|
317
|
+
client: {
|
|
318
|
+
entry : './src/app/client.ts',
|
|
319
|
+
output : './src/shared/static/dist/js',
|
|
320
|
+
minify : true,
|
|
321
|
+
sourcemap : false,
|
|
322
|
+
},
|
|
323
|
+
|
|
324
|
+
i18n: {
|
|
325
|
+
defaultLanguage : 'en',
|
|
326
|
+
supportedLanguages : ['en', 'ar'],
|
|
327
|
+
basePath : './src/shared/static/dist/i18n'
|
|
328
|
+
},
|
|
329
|
+
|
|
330
|
+
style: {
|
|
331
|
+
entry : './src/app/ui/style/index.scss',
|
|
332
|
+
output : './src/shared/static/dist/css/min.css',
|
|
333
|
+
minify : true,
|
|
334
|
+
sourcemap : false,
|
|
335
|
+
},
|
|
336
|
+
|
|
337
|
+
plugins : []
|
|
338
|
+
};
|
|
269
339
|
|
|
270
|
-
|
|
340
|
+
const spaPlugin = serverSPA({
|
|
341
|
+
baseUrl : 'http://localhost:3000',
|
|
342
|
+
clientEntry : './src/app/client.ts',
|
|
343
|
+
clientScriptPath : ['/static/dist/js/client.js'],
|
|
344
|
+
clientStylePath : ['/static/dist/css/min.css'],
|
|
271
345
|
|
|
272
|
-
|
|
346
|
+
author : 'Your Name',
|
|
347
|
+
authorUrl : 'https://github.com/yourname',
|
|
348
|
+
defaultDescription : 'My CruxJS Application',
|
|
349
|
+
defaultKeywords : ['cruxjs', 'framework', 'spa'],
|
|
273
350
|
|
|
274
|
-
|
|
275
|
-
|
|
351
|
+
pages : [HomePage.meta],
|
|
352
|
+
errorPages : [ErrorPage.meta],
|
|
353
|
+
enableAutoNotFound : true,
|
|
354
|
+
autoBootstrapClient : true
|
|
355
|
+
}, appConfig);
|
|
276
356
|
|
|
277
|
-
|
|
278
|
-
- Client is built using Bun's bundler
|
|
279
|
-
- UI library (e.g., @mineui/core) is installed and CSS is extracted
|
|
280
|
-
- Custom SCSS/CSS is compiled using Dart Sass
|
|
281
|
-
- Databases are initialized with plugin schemas
|
|
282
|
-
- i18n is set up
|
|
357
|
+
appConfig.plugins.push(spaPlugin);
|
|
283
358
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
src/shared/static/dist/
|
|
287
|
-
βββ js/
|
|
288
|
-
β βββ browser.js (bundled client)
|
|
289
|
-
βββ css/
|
|
290
|
-
βββ min.css (UI library CSS)
|
|
291
|
-
βββ extra.css (compiled custom styles)
|
|
359
|
+
const app = createApp(appConfig);
|
|
360
|
+
app.start();
|
|
292
361
|
```
|
|
293
362
|
|
|
294
|
-
-
|
|
295
|
-
- Server is created with @minejs/server
|
|
296
|
-
- Routes are merged (user routes + plugin routes)
|
|
297
|
-
- Middleware stack is built
|
|
298
|
-
- Static files handler is configured
|
|
363
|
+
- ### Directory Structure
|
|
299
364
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
365
|
+
```
|
|
366
|
+
src/
|
|
367
|
+
βββ index.ts # Main app config & entry
|
|
368
|
+
βββ app/
|
|
369
|
+
β βββ client.ts # Client config
|
|
370
|
+
β βββ ui/
|
|
371
|
+
β βββ pages/
|
|
372
|
+
β β βββ home.tsx # Home page component
|
|
373
|
+
β β βββ error.tsx # Error page component
|
|
374
|
+
β βββ style/
|
|
375
|
+
β βββ index.scss # Global styles
|
|
376
|
+
βββ shared/
|
|
377
|
+
βββ static/
|
|
378
|
+
βββ img/
|
|
379
|
+
β βββ logo.png
|
|
380
|
+
βββ dist/
|
|
381
|
+
βββ js/ # Client bundle output
|
|
382
|
+
βββ css/ # Style output
|
|
383
|
+
βββ i18n/ # Translations
|
|
384
|
+
```
|
|
303
385
|
|
|
304
386
|
<br>
|
|
387
|
+
<br>
|
|
388
|
+
|
|
389
|
+
- ## Lifecycle Hooks π
|
|
305
390
|
|
|
306
|
-
- ## Building Your App π οΈ
|
|
307
|
-
|
|
308
|
-
### Client Build (JavaScript)
|
|
309
|
-
```typescript
|
|
310
|
-
client: {
|
|
311
|
-
entry: './src/client/browser.tsx',
|
|
312
|
-
output: './src/shared/static/dist/js',
|
|
313
|
-
target: 'browser', // or 'bun'
|
|
314
|
-
minify: true, // Minify in production
|
|
315
|
-
sourcemap: false, // Source maps in development
|
|
316
|
-
external: [] // Dependencies to exclude
|
|
317
|
-
}
|
|
318
|
-
```
|
|
319
|
-
Uses Bun's bundler to create optimized JavaScript bundles.
|
|
320
|
-
|
|
321
|
-
### UI Library Build (CSS from npm)
|
|
322
|
-
```typescript
|
|
323
|
-
ui: {
|
|
324
|
-
package: '@mineui/core', // Any npm package
|
|
325
|
-
output: './src/shared/static/dist/css'
|
|
326
|
-
}
|
|
327
|
-
```
|
|
328
|
-
- Installs the UI package from npm
|
|
329
|
-
- Extracts `dist/mineui.css` and copies it as `min.css`
|
|
330
|
-
- Perfect for pre-built component libraries
|
|
331
|
-
|
|
332
|
-
### Styles Build (SCSS to CSS)
|
|
333
|
-
```typescript
|
|
334
|
-
style: {
|
|
335
|
-
entry: './src/client/ui/style/index.scss',
|
|
336
|
-
output: './src/shared/static/dist/css/extra.css',
|
|
337
|
-
minify: true,
|
|
338
|
-
sourcemap: false
|
|
339
|
-
}
|
|
340
391
|
```
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
392
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
393
|
+
β β
|
|
394
|
+
β createApp(config) β
|
|
395
|
+
β β
|
|
396
|
+
ββ INITIALIZE Phase β
|
|
397
|
+
β ββ Load configuration β
|
|
398
|
+
β ββ Initialize plugins β
|
|
399
|
+
β ββ Setup server β
|
|
400
|
+
β β
|
|
401
|
+
ββ BUILD Phase (in background) β
|
|
402
|
+
β ββ Build client bundle (Bun) β
|
|
403
|
+
β ββ Build styles (Sass) β
|
|
404
|
+
β ββ Setup i18n system β
|
|
405
|
+
β ββ Run plugin onRegister hooks β
|
|
406
|
+
β β
|
|
407
|
+
ββ AWAKE Phase β
|
|
408
|
+
β ββ Register routes β
|
|
409
|
+
β ββ Run plugin onAwake hooks β
|
|
410
|
+
β ββ Verify configuration β
|
|
411
|
+
β β
|
|
412
|
+
ββ START Phase β
|
|
413
|
+
β ββ Start HTTP server β
|
|
414
|
+
β ββ Run plugin onStart hooks β
|
|
415
|
+
β ββ Listen on configured port β
|
|
416
|
+
β β
|
|
417
|
+
ββ READY Phase β
|
|
418
|
+
ββ Run plugin onReady hooks β
|
|
419
|
+
ββ Server accepting requests β
|
|
420
|
+
ββ SPA fully operational β
|
|
360
421
|
```
|
|
361
422
|
|
|
362
423
|
<br>
|
|
424
|
+
<br>
|
|
363
425
|
|
|
364
|
-
- ##
|
|
426
|
+
- ## API Reference π
|
|
365
427
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
```typescript
|
|
369
|
-
createApp(config, {
|
|
370
|
-
onAwake: async (ctx) => {
|
|
371
|
-
// Databases ready, client built, plugins initialized
|
|
372
|
-
// Perfect for: seed data, cache warming
|
|
373
|
-
const db = ctx.databases.get('default');
|
|
374
|
-
await db.query('INSERT INTO ...');
|
|
375
|
-
},
|
|
376
|
-
|
|
377
|
-
onStart: async (ctx) => {
|
|
378
|
-
// Server created, routes merged, middleware ready
|
|
379
|
-
// Perfect for: logging setup, route inspection
|
|
380
|
-
console.log(`${ctx.routes.length} routes registered`);
|
|
381
|
-
},
|
|
382
|
-
|
|
383
|
-
onReady: async (ctx) => {
|
|
384
|
-
// Server listening and ready
|
|
385
|
-
// Perfect for: external service notifications
|
|
386
|
-
const url = `http://${ctx.config.server.host}:${ctx.config.server.port}`;
|
|
387
|
-
console.log(`π Live at ${url}`);
|
|
388
|
-
},
|
|
389
|
-
|
|
390
|
-
onFinish: async (ctx) => {
|
|
391
|
-
// Graceful shutdown
|
|
392
|
-
// Perfect for: cleanup, connection closing
|
|
393
|
-
},
|
|
394
|
-
|
|
395
|
-
onError: async (ctx, phase, error) => {
|
|
396
|
-
// Error handling across all phases
|
|
397
|
-
console.error(`Error in ${phase}:`, error);
|
|
398
|
-
}
|
|
399
|
-
});
|
|
400
|
-
```
|
|
428
|
+
- ### AppConfig
|
|
401
429
|
|
|
402
|
-
|
|
430
|
+
```typescript
|
|
431
|
+
interface AppConfig {
|
|
432
|
+
// Debug mode
|
|
433
|
+
debug? : boolean;
|
|
434
|
+
|
|
435
|
+
// Server configuration (REQUIRED)
|
|
436
|
+
server: {
|
|
437
|
+
port : number;
|
|
438
|
+
host : string;
|
|
439
|
+
logging?: {
|
|
440
|
+
level : 'debug' | 'info' | 'warn' | 'error';
|
|
441
|
+
pretty? : boolean;
|
|
442
|
+
};
|
|
443
|
+
cors? : CorsConfig;
|
|
444
|
+
middleware? : Middleware[];
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
// Static files serving
|
|
448
|
+
static?: {
|
|
449
|
+
path : string; // URL path for static files
|
|
450
|
+
directory : string; // File system directory
|
|
451
|
+
maxAge? : number; // Cache duration (seconds)
|
|
452
|
+
index? : string[]; // Index files to serve
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
// Client build configuration
|
|
456
|
+
client?: {
|
|
457
|
+
entry : string;
|
|
458
|
+
output : string;
|
|
459
|
+
minify? : boolean;
|
|
460
|
+
sourcemap? : boolean;
|
|
461
|
+
target? : string;
|
|
462
|
+
external? : string[];
|
|
463
|
+
define? : Record<string, any>;
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
// i18n configuration
|
|
467
|
+
i18n? : I18nConfig;
|
|
468
|
+
|
|
469
|
+
// Style build configuration
|
|
470
|
+
style?: {
|
|
471
|
+
entry : string;
|
|
472
|
+
output : string;
|
|
473
|
+
minify? : boolean;
|
|
474
|
+
sourcemap? : boolean;
|
|
475
|
+
includePaths? : string[];
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
// Plugins
|
|
479
|
+
plugins? : CruxPlugin[];
|
|
480
|
+
|
|
481
|
+
// UI library configuration (optional)
|
|
482
|
+
ui?: {
|
|
483
|
+
package : string; // e.g., '@mineui/core'
|
|
484
|
+
output : string; // Output directory
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
// Database configuration (optional)
|
|
488
|
+
db? : DatabaseConfig;
|
|
489
|
+
}
|
|
490
|
+
```
|
|
403
491
|
|
|
404
|
-
|
|
492
|
+
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> </div>
|
|
405
493
|
|
|
406
|
-
|
|
494
|
+
- ### Application Instance
|
|
407
495
|
|
|
408
|
-
|
|
409
|
-
|
|
496
|
+
```typescript
|
|
497
|
+
const app = createApp(config);
|
|
410
498
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
version: '1.0.0',
|
|
499
|
+
// Start the application
|
|
500
|
+
app.start();
|
|
414
501
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
{
|
|
418
|
-
method: 'GET',
|
|
419
|
-
path: '/plugin/status',
|
|
420
|
-
handler: async (ctx) => ctx.json({ status: 'ok' })
|
|
421
|
-
}
|
|
422
|
-
],
|
|
423
|
-
|
|
424
|
-
// Define database schemas
|
|
425
|
-
schemas: [
|
|
426
|
-
{
|
|
427
|
-
name: 'my_table',
|
|
428
|
-
columns: [
|
|
429
|
-
{ name: 'id', type: 'INTEGER PRIMARY KEY' },
|
|
430
|
-
{ name: 'data', type: 'TEXT' }
|
|
431
|
-
]
|
|
432
|
-
}
|
|
433
|
-
],
|
|
434
|
-
|
|
435
|
-
// Register middleware
|
|
436
|
-
middleware: {
|
|
437
|
-
'my-middleware': async (ctx, next) => {
|
|
438
|
-
console.log('Before request');
|
|
439
|
-
const result = await next();
|
|
440
|
-
console.log('After request');
|
|
441
|
-
return result;
|
|
442
|
-
}
|
|
443
|
-
},
|
|
444
|
-
|
|
445
|
-
// Hook into lifecycle
|
|
446
|
-
hooks: {
|
|
447
|
-
onAwake: async (ctx) => console.log('Plugin awake'),
|
|
448
|
-
onStart: async (ctx) => console.log('Plugin start'),
|
|
449
|
-
onReady: async (ctx) => console.log('Plugin ready'),
|
|
450
|
-
onShutdown: async (ctx) => console.log('Plugin shutdown')
|
|
451
|
-
}
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
// Use in config
|
|
455
|
-
const config: AppConfig = {
|
|
456
|
-
plugins: [myPlugin]
|
|
457
|
-
};
|
|
458
|
-
```
|
|
502
|
+
// Get configuration
|
|
503
|
+
app.getConfig();
|
|
459
504
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
- More coming soon...
|
|
505
|
+
// Register a plugin
|
|
506
|
+
app.use(plugin);
|
|
463
507
|
|
|
464
|
-
|
|
508
|
+
// Get a plugin instance
|
|
509
|
+
app.getPlugin('plugin-name');
|
|
465
510
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
Configure one or multiple databases:
|
|
469
|
-
|
|
470
|
-
```typescript
|
|
471
|
-
const config: AppConfig = {
|
|
472
|
-
database: [
|
|
473
|
-
{
|
|
474
|
-
name: 'primary',
|
|
475
|
-
connection: './data/primary.db',
|
|
476
|
-
schema: './src/schemas/primary.ts'
|
|
477
|
-
},
|
|
478
|
-
{
|
|
479
|
-
name: 'cache',
|
|
480
|
-
connection: './data/cache.db',
|
|
481
|
-
schema: './src/schemas/cache.ts'
|
|
482
|
-
}
|
|
483
|
-
]
|
|
484
|
-
};
|
|
511
|
+
// Access logger
|
|
512
|
+
app.logger.info('Message');
|
|
485
513
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
514
|
+
// Access database (if configured)
|
|
515
|
+
app.db?.query('SELECT * FROM users');
|
|
516
|
+
|
|
517
|
+
// Access plugin registry
|
|
518
|
+
app.plugins.getAll();
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
- ### Plugin Interface
|
|
522
|
+
|
|
523
|
+
```typescript
|
|
524
|
+
interface CruxPlugin {
|
|
525
|
+
name : string;
|
|
526
|
+
version : string;
|
|
527
|
+
routes? : RouteDefinition[];
|
|
528
|
+
middleware? : AppMiddleware[];
|
|
529
|
+
|
|
530
|
+
onRegister? : (app: AppInstance) => Promise<void>;
|
|
531
|
+
onAwake? : (ctx: LifecycleContext) => Promise<void>;
|
|
532
|
+
onStart? : (ctx: LifecycleContext) => Promise<void>;
|
|
533
|
+
onReady? : (ctx: LifecycleContext) => Promise<void>;
|
|
534
|
+
onShutdown? : (ctx: LifecycleContext) => Promise<void>;
|
|
535
|
+
}
|
|
536
|
+
```
|
|
491
537
|
|
|
492
538
|
<br>
|
|
539
|
+
<br>
|
|
493
540
|
|
|
494
|
-
- ##
|
|
541
|
+
- ## Best Practices β¨
|
|
495
542
|
|
|
496
|
-
|
|
543
|
+
- #### Configuration Structure
|
|
497
544
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
}
|
|
506
|
-
};
|
|
507
|
-
```
|
|
545
|
+
```typescript
|
|
546
|
+
// β
DO: Keep configuration centralized
|
|
547
|
+
const appConfig: AppConfig = {
|
|
548
|
+
debug : process.env.DEBUG === 'true',
|
|
549
|
+
server : { port: parseInt(process.env.PORT || '3000') },
|
|
550
|
+
// ... rest of config
|
|
551
|
+
};
|
|
508
552
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
βββ fr.json
|
|
515
|
-
βββ es.json
|
|
516
|
-
```
|
|
553
|
+
// β DON'T: Scatter configuration
|
|
554
|
+
const app = createApp({});
|
|
555
|
+
app.config.server.port = 3000;
|
|
556
|
+
app.config.client.entry = './src/app/client.ts';
|
|
557
|
+
```
|
|
517
558
|
|
|
518
|
-
|
|
559
|
+
- #### Plugin Usage
|
|
519
560
|
|
|
520
|
-
|
|
561
|
+
```typescript
|
|
562
|
+
// β
DO: Define plugins before creating app
|
|
563
|
+
const plugins = [
|
|
564
|
+
spaPlugin,
|
|
565
|
+
authPlugin,
|
|
566
|
+
analyticsPlugin
|
|
567
|
+
];
|
|
568
|
+
|
|
569
|
+
const app = createApp({
|
|
570
|
+
plugins,
|
|
571
|
+
// ... rest of config
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
// β DON'T: Add plugins after app creation
|
|
575
|
+
app.use(plugin);
|
|
576
|
+
```
|
|
521
577
|
|
|
522
|
-
|
|
578
|
+
- #### Static Files
|
|
523
579
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
580
|
+
```typescript
|
|
581
|
+
// β
DO: Use static configuration
|
|
582
|
+
static: {
|
|
583
|
+
path : '/static',
|
|
584
|
+
directory : './src/shared/static',
|
|
585
|
+
maxAge : 3600
|
|
586
|
+
}
|
|
528
587
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
host?: string; // Default: 'localhost'
|
|
533
|
-
logging?: {
|
|
534
|
-
level?: 'debug' | 'info' | 'warn' | 'error';
|
|
535
|
-
pretty?: boolean;
|
|
536
|
-
};
|
|
537
|
-
};
|
|
538
|
-
|
|
539
|
-
// Client build (Bun bundler)
|
|
540
|
-
client?: {
|
|
541
|
-
entry: string; // Entry point (e.g., './src/client/browser.tsx')
|
|
542
|
-
output: string; // Output directory
|
|
543
|
-
target?: 'browser' | 'bun';
|
|
544
|
-
minify?: boolean; // Default: !debug
|
|
545
|
-
sourcemap?: boolean; // Default: debug
|
|
546
|
-
external?: string[]; // Don't bundle these
|
|
547
|
-
};
|
|
548
|
-
|
|
549
|
-
// UI Library (npm package)
|
|
550
|
-
ui?: {
|
|
551
|
-
package: string; // Package name (e.g., '@mineui/core')
|
|
552
|
-
output: string; // CSS output directory
|
|
553
|
-
};
|
|
554
|
-
|
|
555
|
-
// Custom styles (SCSS/CSS)
|
|
556
|
-
style?: {
|
|
557
|
-
entry: string; // Entry SCSS/CSS file
|
|
558
|
-
output: string; // CSS output file (e.g., 'extra.css')
|
|
559
|
-
minify?: boolean; // Default: !debug
|
|
560
|
-
sourcemap?: boolean; // Default: debug
|
|
561
|
-
};
|
|
562
|
-
|
|
563
|
-
// Static files
|
|
564
|
-
static?: {
|
|
565
|
-
path: string; // Web path (e.g., '/static')
|
|
566
|
-
directory: string; // Disk directory
|
|
567
|
-
maxAge?: number; // Cache duration in seconds
|
|
568
|
-
index?: string[]; // Default files
|
|
569
|
-
};
|
|
570
|
-
|
|
571
|
-
// Database configuration
|
|
572
|
-
database?: DatabaseConfig | DatabaseConfig[];
|
|
573
|
-
|
|
574
|
-
// Internationalization
|
|
575
|
-
i18n?: {
|
|
576
|
-
defaultLanguage: string;
|
|
577
|
-
supportedLanguages: string[];
|
|
578
|
-
basePath?: string;
|
|
579
|
-
fileExtension?: string; // Default: 'json'
|
|
580
|
-
};
|
|
581
|
-
|
|
582
|
-
// Inline routes
|
|
583
|
-
routes?: RouteDefinition[];
|
|
584
|
-
|
|
585
|
-
// Plugins
|
|
586
|
-
plugins?: CruxPlugin[];
|
|
587
|
-
|
|
588
|
-
// Custom middleware
|
|
589
|
-
middlewares?: Record<string, AppMiddleware>;
|
|
590
|
-
}
|
|
591
|
-
```
|
|
588
|
+
// β DON'T: Manual middleware setup
|
|
589
|
+
app.use(express.static('./src/shared/static'));
|
|
590
|
+
```
|
|
592
591
|
|
|
593
|
-
|
|
592
|
+
- #### Build Configuration
|
|
593
|
+
|
|
594
|
+
```typescript
|
|
595
|
+
// β
DO: Configure builds in appConfig
|
|
596
|
+
client: {
|
|
597
|
+
entry : './src/app/client.ts',
|
|
598
|
+
output : './dist/js',
|
|
599
|
+
minify : !config.debug
|
|
600
|
+
}
|
|
594
601
|
|
|
602
|
+
// β DON'T: Rely on external build tools
|
|
603
|
+
// Use webpack/vite separately
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
- #### Error Handling
|
|
607
|
+
|
|
608
|
+
```typescript
|
|
609
|
+
// β
DO: Define error pages via SPA plugin
|
|
610
|
+
const spaPlugin = serverSPA({
|
|
611
|
+
errorPages: [
|
|
612
|
+
{
|
|
613
|
+
statusCode : 404,
|
|
614
|
+
title : 'Not Found',
|
|
615
|
+
path : '/*'
|
|
616
|
+
}
|
|
617
|
+
]
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
// β DON'T: Manual error handlers
|
|
621
|
+
app.get('*', (req, res) => {
|
|
622
|
+
res.status(404).send('Not found');
|
|
623
|
+
});
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
<br>
|
|
595
627
|
<br>
|
|
596
628
|
|
|
597
|
-
- ##
|
|
629
|
+
- ## Integration with Other CruxJS Libraries π
|
|
598
630
|
|
|
599
|
-
|
|
631
|
+
> @cruxjs/app integrates seamlessly with:
|
|
600
632
|
|
|
601
|
-
|
|
602
|
-
|
|
633
|
+
- **[@cruxjs/spa](https://github.com/cruxjs-org/spa)**
|
|
634
|
+
> SPA plugin for server-side rendering and routing
|
|
603
635
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
onStart: async (ctx) => { /* ... */ },
|
|
607
|
-
onReady: async (ctx) => { /* ... */ },
|
|
608
|
-
onFinish: async (ctx) => { /* ... */ },
|
|
609
|
-
onError: async (ctx, phase, error) => { /* ... */ }
|
|
610
|
-
});
|
|
636
|
+
- **[@cruxjs/client](https://github.com/cruxjs-org/client)**
|
|
637
|
+
> Client-side application manager with routing and lifecycle
|
|
611
638
|
|
|
612
|
-
|
|
613
|
-
|
|
639
|
+
- **[@cruxjs/base](https://github.com/cruxjs-org/base)**
|
|
640
|
+
> Base types and plugin system
|
|
641
|
+
|
|
642
|
+
- **[@minejs/i18n](https://github.com/minejs-org/i18n)**
|
|
643
|
+
> i18n system (automatic setup)
|
|
644
|
+
|
|
645
|
+
- **[@minejs/server](https://github.com/minejs-org/server)**
|
|
646
|
+
> HTTP server (automatic setup)
|
|
614
647
|
|
|
615
|
-
|
|
648
|
+
- **[@minejs/browser](https://github.com/minejs-org/browser)**
|
|
649
|
+
> Browser utilities
|
|
616
650
|
|
|
617
|
-
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
-
|
|
651
|
+
- **Bun**
|
|
652
|
+
> Client bundler (automatic client builds)
|
|
653
|
+
|
|
654
|
+
- **Sass**
|
|
655
|
+
>Style preprocessing (automatic style builds)
|
|
621
656
|
|
|
622
657
|
<!-- βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ -->
|
|
623
658
|
|
|
@@ -625,6 +660,7 @@
|
|
|
625
660
|
|
|
626
661
|
<!-- βββββββββββββββββββββββββββββββ END βββββββββββββββββββββββββββββββ -->
|
|
627
662
|
|
|
663
|
+
<br>
|
|
628
664
|
<br>
|
|
629
665
|
|
|
630
666
|
---
|