fusee-framework 0.1.0-alpha.1 → 1.0.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/README.md +76 -8
- package/app/components/Counter.js +111 -34
- package/app/components/Counter.ts +99 -0
- package/app/components/CounterSection.js +34 -0
- package/app/components/CounterSection.ts +45 -0
- package/app/components/UserForm.js +31 -0
- package/app/components/UserForm.ts +38 -0
- package/app/main.js +2 -2
- package/app/main.ts +15 -0
- package/app/routes/About.js +17 -17
- package/app/routes/About.ts +29 -0
- package/app/routes/Home.js +22 -17
- package/app/routes/Home.ts +34 -0
- package/framework/bin/create-fusee.js +147 -0
- package/framework/core/compiler.js +214 -0
- package/framework/core/component.js +98 -107
- package/framework/core/directives.js +335 -0
- package/framework/core/evaluator.js +67 -0
- package/framework/core/signal.js +125 -40
- package/framework/index.d.ts +3 -0
- package/framework/index.js +1 -1
- package/framework/router/router.js +52 -43
- package/framework/types/compiler.d.ts +25 -0
- package/framework/types/component.d.ts +44 -0
- package/framework/types/directives.d.ts +32 -0
- package/framework/types/evaluator.d.ts +15 -0
- package/framework/types/index.d.ts +9 -0
- package/framework/types/router.d.ts +17 -0
- package/framework/types/signal.d.ts +30 -0
- package/index.html +75 -8
- package/package.json +14 -3
- package/tsconfig.json +38 -0
- package/vite.config.js +35 -0
|
@@ -1,69 +1,78 @@
|
|
|
1
|
-
// ─── Hash-based SPA Router ────────────────────────────────────────────────────
|
|
2
|
-
// Routes are declared as: { path: '/about', component: AboutComponent }
|
|
3
|
-
// Navigation via <a href="#/about"> or router.navigate('/about')
|
|
4
|
-
|
|
5
1
|
let _routes = []
|
|
6
2
|
let _outlet = null
|
|
7
3
|
let _currentInstance = null
|
|
8
4
|
|
|
9
5
|
export function createRouter(routes) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
_routes = routes
|
|
7
|
+
|
|
8
|
+
const handler = () => _resolve()
|
|
9
|
+
window.addEventListener('hashchange', handler)
|
|
10
|
+
|
|
11
|
+
if (document.readyState === 'loading') {
|
|
12
|
+
window.addEventListener('DOMContentLoaded', handler)
|
|
13
|
+
} else {
|
|
14
|
+
_resolve()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
navigate,
|
|
19
|
+
destroy() {
|
|
20
|
+
window.removeEventListener('hashchange', handler)
|
|
21
|
+
window.removeEventListener('DOMContentLoaded', handler)
|
|
22
|
+
if (_currentInstance) {
|
|
23
|
+
try {
|
|
24
|
+
_currentInstance.unmount()
|
|
25
|
+
} catch {}
|
|
26
|
+
}
|
|
27
|
+
_routes = []
|
|
28
|
+
_outlet = null
|
|
29
|
+
_currentInstance = null
|
|
30
|
+
}
|
|
31
|
+
}
|
|
19
32
|
}
|
|
20
33
|
|
|
21
34
|
export function navigate(path) {
|
|
22
|
-
|
|
35
|
+
window.location.hash = path
|
|
23
36
|
}
|
|
24
37
|
|
|
25
|
-
// ── Mount outlet ──────────────────────────────────────────────────────────────
|
|
26
|
-
// Call this with the DOM element that acts as <router-outlet>
|
|
27
38
|
export function mountOutlet(el) {
|
|
28
|
-
|
|
29
|
-
|
|
39
|
+
_outlet = el
|
|
40
|
+
_resolve()
|
|
30
41
|
}
|
|
31
42
|
|
|
32
|
-
// ── Internal resolution ───────────────────────────────────────────────────────
|
|
33
43
|
function _resolve() {
|
|
34
|
-
|
|
44
|
+
if (!_outlet) {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
35
47
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const path = hash.startsWith('#') ? hash.slice(1) || '/' : '/'
|
|
48
|
+
const hash = window.location.hash
|
|
49
|
+
const path = hash.startsWith('#') ? hash.slice(1) || '/' : '/'
|
|
39
50
|
|
|
40
|
-
|
|
51
|
+
const matched = _routes.find(r => _matchPath(r.path, path))
|
|
41
52
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
53
|
+
if (!matched) {
|
|
54
|
+
_outlet.innerHTML = `<p style="color:red">[framework] No route matched for "${path}"</p>`
|
|
55
|
+
return
|
|
56
|
+
}
|
|
46
57
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
58
|
+
if (_currentInstance) {
|
|
59
|
+
try { _currentInstance.unmount() } catch {}
|
|
60
|
+
}
|
|
51
61
|
|
|
52
|
-
|
|
62
|
+
_outlet.innerHTML = ''
|
|
53
63
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
const componentFn = matched.component
|
|
65
|
+
_currentInstance = componentFn()
|
|
66
|
+
_currentInstance.render(_outlet)
|
|
57
67
|
}
|
|
58
68
|
|
|
59
|
-
// Simple path matching — supports exact paths and :param segments
|
|
60
69
|
function _matchPath(routePath, actualPath) {
|
|
61
|
-
|
|
62
|
-
|
|
70
|
+
const routeParts = routePath.split('/').filter(Boolean)
|
|
71
|
+
const actualParts = actualPath.split('/').filter(Boolean)
|
|
63
72
|
|
|
64
|
-
|
|
73
|
+
if (routeParts.length !== actualParts.length) return false
|
|
65
74
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
75
|
+
return routeParts.every((part, i) =>
|
|
76
|
+
part.startsWith(':') || part === actualParts[i]
|
|
77
|
+
)
|
|
69
78
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ComponentResult, ComponentFactory } from './component'
|
|
2
|
+
|
|
3
|
+
export function mountTemplate(
|
|
4
|
+
template: string,
|
|
5
|
+
container: HTMLElement,
|
|
6
|
+
context: ComponentResult,
|
|
7
|
+
components: Record<string, ComponentFactory>
|
|
8
|
+
): { effects: (() => void)[] }
|
|
9
|
+
|
|
10
|
+
export function compileNode(
|
|
11
|
+
node: HTMLElement,
|
|
12
|
+
context: ComponentResult,
|
|
13
|
+
components: Record<string, ComponentFactory>,
|
|
14
|
+
effects: (() => void)[]
|
|
15
|
+
): void
|
|
16
|
+
|
|
17
|
+
function processTextNodes(root: HTMLElement, context: ComponentResult, effects: (() => void)[]): void
|
|
18
|
+
function processAttrBindings(root: HTMLElement, context: ComponentResult, effects: (() => void)[]): void
|
|
19
|
+
|
|
20
|
+
function bindComponents(
|
|
21
|
+
container: HTMLElement,
|
|
22
|
+
components: Record<string, ComponentFactory>,
|
|
23
|
+
context: ComponentResult,
|
|
24
|
+
effects: (() => void)[]
|
|
25
|
+
): void
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// ─── Component Types ─────────────────────────────────────────────────────────
|
|
2
|
+
|
|
3
|
+
export type ComponentProps = Record<string, any>
|
|
4
|
+
|
|
5
|
+
export type EmptyProps = Record<string, never>
|
|
6
|
+
|
|
7
|
+
export type PropSchema = string[] | Record<string, PropConfig>
|
|
8
|
+
|
|
9
|
+
export type PropConfig = {
|
|
10
|
+
type?: FunctionConstructor | StringConstructor | NumberConstructor | BooleanConstructor
|
|
11
|
+
default?: any | (() => any)
|
|
12
|
+
required?: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type ComponentInstance = {
|
|
16
|
+
props: ComponentProps
|
|
17
|
+
_mountHooks: (() => void)[]
|
|
18
|
+
_unmountHooks: (() => void)[]
|
|
19
|
+
_effects: import('./signal').EffectRunner[]
|
|
20
|
+
_element: HTMLElement | null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type ComponentResult = {
|
|
24
|
+
template: string
|
|
25
|
+
[key: string]: any
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type ComponentOptions<TProps = ComponentProps> = {
|
|
29
|
+
props?: PropSchema
|
|
30
|
+
components?: Record<string, ComponentFactory<any>>
|
|
31
|
+
setup: (props: TProps) => ComponentResult
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type ComponentFactory<TProps = ComponentProps> = (props?: TProps) => ComponentApi
|
|
35
|
+
|
|
36
|
+
export type ComponentApi = {
|
|
37
|
+
render: (container: HTMLElement) => ComponentInstance
|
|
38
|
+
unmount: () => void
|
|
39
|
+
instance: ComponentInstance
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export declare function onMount(fn: () => void): void
|
|
43
|
+
export declare function onUnmount(fn: () => void): void
|
|
44
|
+
export declare function defineComponent<TProps = EmptyProps>(options: ComponentOptions<TProps>): ComponentFactory<TProps>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ComponentResult, ComponentFactory } from './component'
|
|
2
|
+
|
|
3
|
+
export function processDirectives(
|
|
4
|
+
root: HTMLElement,
|
|
5
|
+
context: ComponentResult,
|
|
6
|
+
components: Record<string, ComponentFactory>,
|
|
7
|
+
effects: (() => void)[]
|
|
8
|
+
): void
|
|
9
|
+
|
|
10
|
+
export function processRefs(root: HTMLElement, context: ComponentResult): void
|
|
11
|
+
|
|
12
|
+
export function processModel(root: HTMLElement, context: ComponentResult, effects: (() => void)[]): void
|
|
13
|
+
|
|
14
|
+
export function processFor(
|
|
15
|
+
root: HTMLElement,
|
|
16
|
+
context: ComponentResult,
|
|
17
|
+
components: Record<string, ComponentFactory>,
|
|
18
|
+
effects: (() => void)[]
|
|
19
|
+
): void
|
|
20
|
+
|
|
21
|
+
export function processIf(
|
|
22
|
+
root: HTMLElement,
|
|
23
|
+
context: ComponentResult,
|
|
24
|
+
components: Record<string, ComponentFactory>,
|
|
25
|
+
effects: (() => void)[]
|
|
26
|
+
): void
|
|
27
|
+
|
|
28
|
+
export function processShow(root: HTMLElement, context: ComponentResult, effects: (() => void)[]): void
|
|
29
|
+
export function processHtml(root: HTMLElement, context: ComponentResult, effects: (() => void)[]): void
|
|
30
|
+
export function processText(root: HTMLElement, context: ComponentResult, effects: (() => void)[]): void
|
|
31
|
+
export function processEvents(root: HTMLElement, context: ComponentResult): void
|
|
32
|
+
export function processCloak(root: HTMLElement): void
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ComponentResult } from './component'
|
|
2
|
+
|
|
3
|
+
export type InterpolationPart = {
|
|
4
|
+
type: 'static' | 'dynamic'
|
|
5
|
+
value?: string
|
|
6
|
+
key?: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const MUSTACHE_RE: RegExp
|
|
10
|
+
|
|
11
|
+
export function evaluateExpression(expr: string, context: Record<string, any>, extraContext?: Record<string, any>): any
|
|
12
|
+
|
|
13
|
+
export function parseInterpolation(str: string): InterpolationPart[]
|
|
14
|
+
|
|
15
|
+
export function sanitizeAttr(name: string, value: string): string
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// ─── Router Types ─────────────────────────────────────────────────────────────
|
|
2
|
+
|
|
3
|
+
import type { ComponentApi } from './component'
|
|
4
|
+
|
|
5
|
+
export type Route = {
|
|
6
|
+
path: string
|
|
7
|
+
component: () => ComponentApi
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type Router = {
|
|
11
|
+
navigate: (path: string) => void
|
|
12
|
+
destroy: () => void
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export declare function createRouter(routes: Route[]): Router
|
|
16
|
+
export declare function navigate(path: string): void
|
|
17
|
+
export declare function mountOutlet(el: HTMLElement): void
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// ─── Signal Types ────────────────────────────────────────────────────────────
|
|
2
|
+
|
|
3
|
+
export type SignalAccessor<T> = {
|
|
4
|
+
(): T;
|
|
5
|
+
(newValue: T): void;
|
|
6
|
+
isSignal: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type ComputedAccessor<T> = {
|
|
10
|
+
(): T;
|
|
11
|
+
isSignal: boolean;
|
|
12
|
+
readonly: true;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type Signal<T = any> = SignalAccessor<T>
|
|
16
|
+
export type Computed<T = any> = ComputedAccessor<T>
|
|
17
|
+
|
|
18
|
+
type EffectRunner = {
|
|
19
|
+
(): void;
|
|
20
|
+
deps: Set<Set<EffectRunner>>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export declare function signal<T>(initialValue: T): Signal<T>
|
|
24
|
+
export declare function effect(fn: () => void): () => void
|
|
25
|
+
export declare function computed<T>(fn: () => T): Computed<T>
|
|
26
|
+
export declare function batch<T>(fn: () => T): T
|
|
27
|
+
export declare function untrack<T>(fn: () => T): T
|
|
28
|
+
|
|
29
|
+
declare function setEffectHook(fn: (eff: any) => void): void
|
|
30
|
+
|
package/index.html
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="ro">
|
|
3
|
+
|
|
3
4
|
<head>
|
|
4
5
|
<meta charset="UTF-8" />
|
|
5
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
7
|
<title>MyFramework — SPA Demo</title>
|
|
7
8
|
<style>
|
|
8
|
-
*,
|
|
9
|
+
*,
|
|
10
|
+
*::before,
|
|
11
|
+
*::after {
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
margin: 0;
|
|
14
|
+
padding: 0;
|
|
15
|
+
}
|
|
9
16
|
|
|
10
17
|
body {
|
|
11
18
|
font-family: system-ui, sans-serif;
|
|
@@ -23,12 +30,18 @@
|
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
nav a {
|
|
26
|
-
color: #
|
|
33
|
+
color: #ff3333; /* Link-urile sunt acum roșii */
|
|
27
34
|
text-decoration: none;
|
|
28
35
|
font-weight: 500;
|
|
29
36
|
}
|
|
30
37
|
|
|
31
|
-
|
|
38
|
+
/* Temă Red Fusée */
|
|
39
|
+
#app h1 { color: #ff3333; text-shadow: 0 0 20px rgba(255, 51, 51, 0.4); margin-bottom: 1rem; }
|
|
40
|
+
#app p { color: #ff9999; opacity: 0.9; }
|
|
41
|
+
|
|
42
|
+
nav a:hover {
|
|
43
|
+
color: #fff;
|
|
44
|
+
}
|
|
32
45
|
|
|
33
46
|
#app {
|
|
34
47
|
padding: 2rem;
|
|
@@ -36,8 +49,16 @@
|
|
|
36
49
|
margin: 0 auto;
|
|
37
50
|
}
|
|
38
51
|
|
|
39
|
-
.page h1 {
|
|
40
|
-
|
|
52
|
+
.page h1 {
|
|
53
|
+
margin-bottom: 1rem;
|
|
54
|
+
font-size: 1.8rem;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.page p {
|
|
58
|
+
margin-bottom: 0.5rem;
|
|
59
|
+
color: #aaa;
|
|
60
|
+
line-height: 1.6;
|
|
61
|
+
}
|
|
41
62
|
|
|
42
63
|
.counter {
|
|
43
64
|
margin-top: 2rem;
|
|
@@ -48,7 +69,13 @@
|
|
|
48
69
|
display: inline-block;
|
|
49
70
|
}
|
|
50
71
|
|
|
51
|
-
.counter h2 {
|
|
72
|
+
.counter h2 {
|
|
73
|
+
margin-bottom: 1rem;
|
|
74
|
+
font-size: 1rem;
|
|
75
|
+
color: #888;
|
|
76
|
+
text-transform: uppercase;
|
|
77
|
+
letter-spacing: 0.1em;
|
|
78
|
+
}
|
|
52
79
|
|
|
53
80
|
.value {
|
|
54
81
|
font-size: 4rem !important;
|
|
@@ -83,15 +110,51 @@
|
|
|
83
110
|
transition: background 0.15s;
|
|
84
111
|
}
|
|
85
112
|
|
|
86
|
-
.actions button:hover {
|
|
113
|
+
.actions button:hover {
|
|
114
|
+
background: #2a2a3a;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.primary-btn {
|
|
118
|
+
padding: 0.6rem 1.25rem;
|
|
119
|
+
border: none;
|
|
120
|
+
background: #8b8bff;
|
|
121
|
+
color: #fff;
|
|
122
|
+
font-weight: 600;
|
|
123
|
+
border-radius: 6px;
|
|
124
|
+
cursor: pointer;
|
|
125
|
+
font-size: 1rem;
|
|
126
|
+
transition: background 0.15s, transform 0.1s;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.primary-btn:hover {
|
|
130
|
+
background: #7171e5;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.primary-btn:active {
|
|
134
|
+
transform: scale(0.97);
|
|
135
|
+
}
|
|
87
136
|
|
|
88
137
|
.status {
|
|
89
138
|
margin-top: 1rem;
|
|
90
139
|
font-size: 0.8rem;
|
|
91
140
|
color: #4caf50 !important;
|
|
92
141
|
}
|
|
142
|
+
|
|
143
|
+
.positive {
|
|
144
|
+
color: #8b8bff !important;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.negative {
|
|
148
|
+
color: #ff6b6b !important;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.actions button:disabled {
|
|
152
|
+
opacity: 0.3;
|
|
153
|
+
cursor: not-allowed;
|
|
154
|
+
}
|
|
93
155
|
</style>
|
|
94
156
|
</head>
|
|
157
|
+
|
|
95
158
|
<body>
|
|
96
159
|
<nav>
|
|
97
160
|
<a href="#/">Home</a>
|
|
@@ -99,5 +162,9 @@
|
|
|
99
162
|
</nav>
|
|
100
163
|
<div id="app"></div>
|
|
101
164
|
<script type="module" src="./app/main.js"></script>
|
|
165
|
+
<!-- For TypeScript: compile with `npx tsc` then change to: -->
|
|
166
|
+
<!-- <script type="module" src="./dist/app/main.js"></script> -->
|
|
167
|
+
|
|
102
168
|
</body>
|
|
103
|
-
|
|
169
|
+
|
|
170
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fusee-framework",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Fusée - Signals-first JS Framework | Peak Performance",
|
|
5
5
|
"main": "framework/index.js",
|
|
6
|
+
"types": "framework/types/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"create-fusee-app": "./framework/bin/create-fusee.js"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
6
11
|
"scripts": {
|
|
12
|
+
"dev": "vite",
|
|
13
|
+
"build": "vite build",
|
|
14
|
+
"preview": "vite preview",
|
|
7
15
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
16
|
},
|
|
9
17
|
"keywords": [],
|
|
10
18
|
"author": "",
|
|
11
19
|
"license": "MIT",
|
|
12
|
-
"type": "commonjs",
|
|
13
20
|
"repository": {
|
|
14
21
|
"type": "git",
|
|
15
22
|
"url": "git+https://github.com/SebiSomu/fusee.git"
|
|
16
23
|
},
|
|
17
24
|
"publishConfig": {
|
|
18
25
|
"registry": "https://registry.npmjs.org/"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"typescript": "^6.0.2",
|
|
29
|
+
"vite": "^5.0.0"
|
|
19
30
|
}
|
|
20
|
-
}
|
|
31
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ES2020",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
7
|
+
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"checkJs": false,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"noImplicitAny": false,
|
|
12
|
+
"strictNullChecks": true,
|
|
13
|
+
|
|
14
|
+
"outDir": "./dist",
|
|
15
|
+
"rootDir": ".",
|
|
16
|
+
"removeComments": true,
|
|
17
|
+
"sourceMap": true,
|
|
18
|
+
|
|
19
|
+
"esModuleInterop": true,
|
|
20
|
+
"skipLibCheck": true,
|
|
21
|
+
"forceConsistentCasingInFileNames": true,
|
|
22
|
+
|
|
23
|
+
"declaration": true,
|
|
24
|
+
"declarationDir": "./dist/types",
|
|
25
|
+
|
|
26
|
+
"resolveJsonModule": true
|
|
27
|
+
},
|
|
28
|
+
"include": [
|
|
29
|
+
"app/**/*",
|
|
30
|
+
"framework/**/*"
|
|
31
|
+
],
|
|
32
|
+
"exclude": [
|
|
33
|
+
"node_modules",
|
|
34
|
+
"dist",
|
|
35
|
+
"**/*.test.ts",
|
|
36
|
+
"**/*.spec.ts"
|
|
37
|
+
]
|
|
38
|
+
}
|
package/vite.config.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
// Directorul rădăcină al proiectului
|
|
6
|
+
root: '.',
|
|
7
|
+
|
|
8
|
+
// Alias-uri pentru import-uri mai curate
|
|
9
|
+
// În loc de '../../framework/index.js' poți scrie '@fusee'
|
|
10
|
+
resolve: {
|
|
11
|
+
alias: {
|
|
12
|
+
'@fusee': path.resolve(__dirname, './framework'),
|
|
13
|
+
'@app': path.resolve(__dirname, './app'),
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
// Config pentru server-ul de development
|
|
18
|
+
server: {
|
|
19
|
+
port: 3000,
|
|
20
|
+
open: true, // Deschide browserul automat
|
|
21
|
+
hmr: true, // Hot Module Replacement
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
// Config pentru build de producție
|
|
25
|
+
build: {
|
|
26
|
+
outDir: 'dist',
|
|
27
|
+
emptyOutDir: true,
|
|
28
|
+
|
|
29
|
+
rollupOptions: {
|
|
30
|
+
input: {
|
|
31
|
+
main: path.resolve(__dirname, 'index.html'),
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
})
|