fusee-framework 1.8.0 → 1.9.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 +64 -3
- package/app/benchmark/vite.config.js +23 -0
- package/auto-imports.d.ts +4 -0
- package/bin/create-fusee-linux +0 -0
- package/bin/create-fusee-mac-arm64 +0 -0
- package/bin/create-fusee-mac-intel +0 -0
- package/bin/create-fusee-win.exe +0 -0
- package/bin/create-fusee.exe +0 -0
- package/create-fusee-go/internal/assets/embed/framework/auto-import-preset.js +15 -9
- package/create-fusee-go/internal/assets/embed/framework/core/async-context.js +27 -0
- package/create-fusee-go/internal/assets/embed/framework/core/compiler/ast.js +167 -0
- package/create-fusee-go/internal/assets/embed/framework/core/compiler/errors-list.js +47 -0
- package/create-fusee-go/internal/assets/embed/framework/core/compiler/errors.js +107 -0
- package/create-fusee-go/internal/assets/embed/framework/core/compiler/generator.js +363 -0
- package/create-fusee-go/internal/assets/embed/framework/core/compiler/lexer.js +347 -0
- package/create-fusee-go/internal/assets/embed/framework/core/compiler/main-compiler.js +115 -0
- package/create-fusee-go/internal/assets/embed/framework/core/compiler/parser.js +414 -0
- package/create-fusee-go/internal/assets/embed/framework/core/compiler/plugins/actions-plugin.js +263 -0
- package/create-fusee-go/internal/assets/embed/framework/core/compiler/plugins/compiler-plugin.d.ts +5 -0
- package/create-fusee-go/internal/assets/embed/framework/core/compiler/plugins/compiler-plugin.js +45 -0
- package/create-fusee-go/internal/assets/embed/framework/core/compiler/plugins/file-router-plugin.js +301 -0
- package/create-fusee-go/internal/assets/embed/framework/core/compiler/plugins/router-plugin.js +196 -0
- package/create-fusee-go/internal/assets/embed/framework/core/compiler/transformer.js +398 -0
- package/create-fusee-go/internal/assets/embed/framework/core/component.js +61 -23
- package/create-fusee-go/internal/assets/embed/framework/core/di.js +187 -0
- package/create-fusee-go/internal/assets/embed/framework/core/directives.js +40 -96
- package/create-fusee-go/internal/assets/embed/framework/core/evaluator.js +1 -1
- package/create-fusee-go/internal/assets/embed/framework/core/h.js +430 -0
- package/create-fusee-go/internal/assets/embed/framework/core/hydration.js +83 -0
- package/create-fusee-go/internal/assets/embed/framework/core/reconcile.js +151 -0
- package/create-fusee-go/internal/assets/embed/framework/core/signal.js +269 -0
- package/create-fusee-go/internal/assets/embed/framework/core/store.js +322 -81
- package/create-fusee-go/internal/assets/embed/framework/index.js +5 -3
- package/create-fusee-go/internal/assets/embed/framework/router/file-router.js +1 -1
- package/create-fusee-go/internal/assets/embed/framework/router/router.js +113 -21
- package/create-fusee-go/internal/assets/embed/framework/server/actions.js +173 -0
- package/create-fusee-go/internal/assets/embed/framework/server/actions.server.js +88 -0
- package/create-fusee-go/internal/assets/embed/framework/server/index.js +18 -0
- package/create-fusee-go/internal/assets/embed/framework/types/actions.d.ts +50 -0
- package/create-fusee-go/internal/assets/embed/framework/types/actions.server.d.ts +36 -0
- package/create-fusee-go/internal/assets/embed/framework/types/compiler/ast.d.ts +166 -0
- package/create-fusee-go/internal/assets/embed/framework/types/compiler/errors-codes.d.ts +23 -0
- package/create-fusee-go/internal/assets/embed/framework/types/compiler/errors.d.ts +43 -0
- package/create-fusee-go/internal/assets/embed/framework/types/compiler/generator.d.ts +8 -0
- package/create-fusee-go/internal/assets/embed/framework/types/compiler/h.d.ts +46 -0
- package/create-fusee-go/internal/assets/embed/framework/types/compiler/lexer.d.ts +27 -0
- package/create-fusee-go/internal/assets/embed/framework/types/compiler/main-compiler.d.ts +60 -0
- package/create-fusee-go/internal/assets/embed/framework/types/compiler/parser.d.ts +4 -0
- package/create-fusee-go/internal/assets/embed/framework/types/compiler/plugins/actions.d.ts +30 -0
- package/create-fusee-go/internal/assets/embed/framework/types/compiler/plugins/compiler-plugin.d.ts +5 -0
- package/create-fusee-go/internal/assets/embed/framework/types/compiler/plugins/file-router-plugins.d.ts +32 -0
- package/create-fusee-go/internal/assets/embed/framework/types/compiler/plugins/router-plugin.d.ts +24 -0
- package/create-fusee-go/internal/assets/embed/framework/types/compiler/transformer.d.ts +28 -0
- package/create-fusee-go/internal/assets/embed/framework/types/component.d.ts +89 -88
- package/create-fusee-go/internal/assets/embed/framework/types/di.d.ts +43 -0
- package/create-fusee-go/internal/assets/embed/framework/types/hydration.d.ts +30 -0
- package/create-fusee-go/internal/assets/embed/framework/types/index.d.ts +38 -22
- package/create-fusee-go/internal/assets/embed/framework/types/reconcile.d.ts +7 -0
- package/create-fusee-go/internal/assets/embed/framework/types/router.d.ts +11 -1
- package/create-fusee-go/internal/assets/embed/framework/types/server.d.ts +11 -0
- package/create-fusee-go/internal/assets/embed/framework/types/signal.d.ts +142 -79
- package/create-fusee-go/internal/assets/embed/framework/types/store.d.ts +66 -8
- package/framework/auto-import-preset.js +3 -1
- package/framework/core/async-context.js +27 -0
- package/framework/core/compiler/ast.js +167 -0
- package/framework/core/compiler/errors-list.js +47 -0
- package/framework/core/compiler/errors.js +107 -0
- package/framework/core/compiler/generator.js +363 -0
- package/framework/core/compiler/lexer.js +347 -0
- package/framework/core/compiler/main-compiler.js +115 -0
- package/framework/core/compiler/parser.js +414 -0
- package/framework/core/compiler/plugins/actions-plugin.js +263 -0
- package/framework/core/compiler/plugins/compiler-plugin.d.ts +5 -0
- package/framework/core/compiler/plugins/compiler-plugin.js +45 -0
- package/framework/core/compiler/plugins/file-router-plugin.js +301 -0
- package/framework/core/compiler/plugins/router-plugin.js +196 -0
- package/framework/core/compiler/transformer.js +398 -0
- package/framework/core/component.js +34 -10
- package/framework/core/evaluator.js +1 -1
- package/framework/core/h.js +430 -0
- package/framework/core/hydration.js +83 -0
- package/framework/core/signal.js +17 -15
- package/framework/server/actions.js +173 -0
- package/framework/server/actions.server.js +88 -0
- package/framework/server/index.js +18 -0
- package/framework/types/actions.d.ts +50 -0
- package/framework/types/actions.server.d.ts +36 -0
- package/framework/types/compiler/ast.d.ts +166 -0
- package/framework/types/compiler/errors-codes.d.ts +23 -0
- package/framework/types/compiler/errors.d.ts +43 -0
- package/framework/types/compiler/generator.d.ts +8 -0
- package/framework/types/compiler/h.d.ts +46 -0
- package/framework/types/compiler/lexer.d.ts +27 -0
- package/framework/types/compiler/main-compiler.d.ts +60 -0
- package/framework/types/compiler/parser.d.ts +4 -0
- package/framework/types/compiler/plugins/actions.d.ts +30 -0
- package/framework/types/compiler/plugins/compiler-plugin.d.ts +5 -0
- package/framework/types/compiler/plugins/file-router-plugins.d.ts +32 -0
- package/framework/types/compiler/plugins/router-plugin.d.ts +24 -0
- package/framework/types/compiler/transformer.d.ts +28 -0
- package/framework/types/hydration.d.ts +30 -0
- package/framework/types/index.d.ts +6 -0
- package/framework/types/server.d.ts +11 -0
- package/framework/types/signal.d.ts +2 -7
- package/ghid_go_fusee_integrat_go1_26.txt +276 -0
- package/ghid_rust_fusee_rust_1_95_0.txt +1118 -0
- package/package.json +44 -36
- package/vite.config.js +65 -53
- package/create-fusee-go/internal/assets/embed/framework/bin/create-fusee.js +0 -199
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { RootNode } from './ast.js'
|
|
2
|
+
import type { Token } from './lexer.js'
|
|
3
|
+
import type { CompileWarning } from './errors.js'
|
|
4
|
+
import type { CompileError } from './errors.js'
|
|
5
|
+
|
|
6
|
+
export interface CompileOptions {
|
|
7
|
+
components?: string[] | Set<string>
|
|
8
|
+
runtimePath?: string
|
|
9
|
+
filename?: string
|
|
10
|
+
throwOnWarning?: boolean
|
|
11
|
+
scope?: string[]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface CompileResult {
|
|
15
|
+
code: string
|
|
16
|
+
ast: RootNode
|
|
17
|
+
tokens: Token[]
|
|
18
|
+
warnings: CompileWarning[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ParseOnlyResult {
|
|
22
|
+
ast: RootNode
|
|
23
|
+
tokens: Token[]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface BatchEntry {
|
|
27
|
+
id: string
|
|
28
|
+
source: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface BatchResult {
|
|
32
|
+
id: string
|
|
33
|
+
code: string | null
|
|
34
|
+
warnings: CompileWarning[]
|
|
35
|
+
error: CompileError | null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export declare function compile(source: string, options?: CompileOptions): CompileResult
|
|
39
|
+
export declare function parseOnly(source: string, options?: Pick<CompileOptions, 'components'>): ParseOnlyResult
|
|
40
|
+
export declare function transformOnly(ast: RootNode, options?: Pick<CompileOptions, 'components' | 'scope'> & { source?: string }): { ast: RootNode; warnings: CompileWarning[] }
|
|
41
|
+
export declare function compileBatch(templates: BatchEntry[], sharedOptions?: CompileOptions): BatchResult[]
|
|
42
|
+
|
|
43
|
+
export interface FuseePluginOptions {
|
|
44
|
+
runtimePath?: string
|
|
45
|
+
components?: string[]
|
|
46
|
+
scope?: string[]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export declare function fuseePlugin(options?: FuseePluginOptions): {
|
|
50
|
+
name: 'vite-plugin-fusee'
|
|
51
|
+
transform(src: string, id: string): { code: string; map: null } | null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { fileRouterPlugin } from './plugins/file-router-plugin.js'
|
|
55
|
+
export { actionsPlugin } from './plugins/actions-plugin.js'
|
|
56
|
+
export { routerPlugin } from './plugins/router-plugin.js'
|
|
57
|
+
export { fuseeCompilerPlugin } from './plugins/compiler-plugin.js'
|
|
58
|
+
export { compileFileRoutes, generateRoutesModule, generateRouteTypes, validateRoutes as validateFileRoutes } from './plugins/file-router-plugin.js'
|
|
59
|
+
export { validateActions, generateClientStubs, generateServerRoutes, generateActionTypes } from './plugins/actions-plugin.js'
|
|
60
|
+
export { validateRoutes, generateRouterTypes } from './plugins/router-plugin.js'
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface ActionsPluginOptions {
|
|
2
|
+
serverActionsFile?: string
|
|
3
|
+
clientActionsFile?: string
|
|
4
|
+
baseUrl?: string
|
|
5
|
+
typesOutput?: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ActionDef {
|
|
9
|
+
name: string
|
|
10
|
+
exportName: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ActionValidationResult {
|
|
14
|
+
warnings: string[]
|
|
15
|
+
errors: string[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export declare function actionsPlugin(options?: ActionsPluginOptions): {
|
|
19
|
+
name: 'vite-plugin-fusee-actions'
|
|
20
|
+
configResolved(config: { root: string }): void
|
|
21
|
+
resolveId(id: string): string | undefined
|
|
22
|
+
load(id: string): Promise<string | null>
|
|
23
|
+
buildEnd(): Promise<void>
|
|
24
|
+
handleHotUpdate(ctx: { file: string; server: unknown }): void
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export declare function validateActions(serverActions: ActionDef[], clientActions: string[]): ActionValidationResult
|
|
28
|
+
export declare function generateClientStubs(actions: ActionDef[], options?: { baseUrl?: string }): string
|
|
29
|
+
export declare function generateServerRoutes(actions: ActionDef[], options?: { serverActionsFile?: string; baseUrl?: string }): string
|
|
30
|
+
export declare function generateActionTypes(actions: ActionDef[]): string
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface FileRouterPluginOptions {
|
|
2
|
+
pagesDir?: string
|
|
3
|
+
loadingComponent?: unknown
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface RouteNode {
|
|
7
|
+
path: string
|
|
8
|
+
filePath?: string
|
|
9
|
+
children?: RouteNode[]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface RouteValidationResult {
|
|
13
|
+
warnings: string[]
|
|
14
|
+
errors: string[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface ImportEntry {
|
|
18
|
+
varName: string
|
|
19
|
+
filePath: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export declare function fileRouterPlugin(options?: FileRouterPluginOptions): {
|
|
23
|
+
name: 'vite-plugin-fusee-file-router'
|
|
24
|
+
buildStart(): Promise<void>
|
|
25
|
+
resolveId(id: string): string | undefined
|
|
26
|
+
load(id: string): Promise<string | null>
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export declare function compileFileRoutes(files: string[], options?: { pagesDir?: string }): RouteNode[]
|
|
30
|
+
export declare function generateRoutesModule(routes: RouteNode[], pagesDir?: string): string
|
|
31
|
+
export declare function validateRoutes(routes: RouteNode[]): RouteValidationResult
|
|
32
|
+
export declare function generateRouteTypes(routes: RouteNode[]): string
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface RouterPluginOptions {
|
|
2
|
+
typesOutput?: string
|
|
3
|
+
pagesDir?: string
|
|
4
|
+
strict?: boolean
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface RouteNode {
|
|
8
|
+
path: string
|
|
9
|
+
filePath?: string
|
|
10
|
+
children?: RouteNode[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface RouteValidationResult {
|
|
14
|
+
warnings: string[]
|
|
15
|
+
errors: string[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export declare function routerPlugin(options?: RouterPluginOptions): {
|
|
19
|
+
name: 'vite-plugin-fusee-router'
|
|
20
|
+
generateBundle(): Promise<void>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export declare function validateRoutes(routes: RouteNode[]): RouteValidationResult
|
|
24
|
+
export declare function generateRouterTypes(routes: RouteNode[]): string
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { RootNode } from './ast.js'
|
|
2
|
+
import type { CompileWarning } from './errors.js'
|
|
3
|
+
|
|
4
|
+
export interface TransformOptions {
|
|
5
|
+
components?: Set<string>
|
|
6
|
+
source?: string
|
|
7
|
+
scope?: string[]
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface TransformResult {
|
|
11
|
+
ast: RootNode
|
|
12
|
+
warnings: CompileWarning[]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Run all transformer steps on the Root AST (mutates in-place).
|
|
17
|
+
*
|
|
18
|
+
* Steps:
|
|
19
|
+
* 1. markStatic — bottom-up static marking
|
|
20
|
+
* 2. hoistStatic — collect f-once + multi-static-child subtrees
|
|
21
|
+
* 3. chainConditionals — f-if / f-else-if / f-else -> IfNode
|
|
22
|
+
* 4. validateFor — warn on f-for without :key (T002)
|
|
23
|
+
* 5. validateModel — warn on f-model on non-input (T003)
|
|
24
|
+
* 6. validateComponents — warn on unregistered component (T004)
|
|
25
|
+
* 7. analyseScope — resolve identifiers (needs `scope`)
|
|
26
|
+
* 8. validateExpressions — warn on unknown identifiers (S001) + static :key (S002)
|
|
27
|
+
*/
|
|
28
|
+
export declare function transform(ast: RootNode, options?: TransformOptions): TransformResult
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface HydrationCacheEntry {
|
|
2
|
+
data: unknown
|
|
3
|
+
updatedAt: number
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export type HydrationSnapshot = Record<string, Record<string, HydrationCacheEntry>>
|
|
7
|
+
export declare function _registerResourceCache(
|
|
8
|
+
resourceKey: string,
|
|
9
|
+
cache: Map<string, HydrationCacheEntry>
|
|
10
|
+
): void
|
|
11
|
+
|
|
12
|
+
export declare function extractHydrationData(): HydrationSnapshot
|
|
13
|
+
export declare function dehydrate(snapshot?: HydrationSnapshot): string
|
|
14
|
+
export declare function loadHydration(snapshot: HydrationSnapshot): void
|
|
15
|
+
export declare function hydrateFromWindow(): void
|
|
16
|
+
export declare function getHydratedEntries(resourceKey: string): Map<string, HydrationCacheEntry> | null
|
|
17
|
+
export declare function isHydrationFresh(
|
|
18
|
+
resourceKey: string,
|
|
19
|
+
cacheKey: string,
|
|
20
|
+
staleTime?: number
|
|
21
|
+
): boolean
|
|
22
|
+
|
|
23
|
+
export declare function clearHydration(): void
|
|
24
|
+
export declare function getHydrationSnapshot(): HydrationSnapshot
|
|
25
|
+
|
|
26
|
+
declare global {
|
|
27
|
+
interface Window {
|
|
28
|
+
__FUSEE_HYDRATION__?: HydrationSnapshot
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -8,6 +8,8 @@ export * from './store'
|
|
|
8
8
|
export * from './event-delegation'
|
|
9
9
|
export * from './di'
|
|
10
10
|
export * from './reconcile'
|
|
11
|
+
export * from './actions'
|
|
12
|
+
export * from './actions.server'
|
|
11
13
|
|
|
12
14
|
declare global {
|
|
13
15
|
type Signal<T = any> = import('./signal').Signal<T>
|
|
@@ -30,3 +32,7 @@ declare global {
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
export as namespace Fusee
|
|
35
|
+
|
|
36
|
+
declare module '*.template.html' {
|
|
37
|
+
export const render: (_ctx: any, _components: any) => any[]
|
|
38
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface RequestContext {
|
|
2
|
+
inFlightMaps: {
|
|
3
|
+
byKey: Map<string, Promise<any>>
|
|
4
|
+
byFetcher: WeakMap<Function, Map<string, Promise<any>>>
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export declare function createRequestContext(): RequestContext
|
|
9
|
+
export declare function withRequestContext<T>(ctx: RequestContext, fn: () => T): T
|
|
10
|
+
export declare function getInFlightStore(): RequestContext['inFlightMaps']
|
|
11
|
+
export declare function isSSRContext(): boolean
|
|
@@ -60,11 +60,6 @@ export interface WatchOptions {
|
|
|
60
60
|
equals?: (a: any, b: any) => boolean;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
export interface ResourceOptions {
|
|
64
|
-
staleTime?: number;
|
|
65
|
-
key?: string | number;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
63
|
export type ResourceAccessor<T> = {
|
|
69
64
|
(): T | undefined;
|
|
70
65
|
read(): T;
|
|
@@ -116,13 +111,13 @@ export declare function onCleanup(fn: () => void): void
|
|
|
116
111
|
|
|
117
112
|
export function resource<T, R = any>(
|
|
118
113
|
fetcher: (input: R) => Promise<T>,
|
|
119
|
-
options?:
|
|
114
|
+
options?: ResourceOptions
|
|
120
115
|
): ResourceReturn<T, R>;
|
|
121
116
|
|
|
122
117
|
export function resource<T, R>(
|
|
123
118
|
source: () => R,
|
|
124
119
|
fetcher: (input: R) => Promise<T>,
|
|
125
|
-
options?:
|
|
120
|
+
options?: ResourceOptions
|
|
126
121
|
): ResourceReturn<T, R>;
|
|
127
122
|
|
|
128
123
|
export function createSuspense<T>(
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
Ghid integrat: Construirea serverului Fusee în Go 1.26 — ghid tehnic detaliat și bune practici
|
|
2
|
+
|
|
3
|
+
Scopul acestui fișier
|
|
4
|
+
- Un ghid tehnic complet, în limba română, pentru construirea serverului Fusee în Go (versiunea 1.26). Integrează cele două ghiduri anterioare: un ghid general pentru server Fusee în Go și un ghid tehnic actualizat specific Go 1.26.
|
|
5
|
+
- Public țintă: student CS care dezvoltă Fusee (framework JS cu reactivitate fină) și are nevoie de un backend scalabil în Go pentru orchestrare compilare, servire artefacte, build pipeline, caching, multi-tenant, observabilitate și securitate.
|
|
6
|
+
|
|
7
|
+
Sumar rapid
|
|
8
|
+
1. Motivație pentru Go
|
|
9
|
+
2. Ce e nou în Go 1.26 și implicații practice
|
|
10
|
+
3. Reguli explicite pentru editorul AI / echipă
|
|
11
|
+
4. Setup și toolchain (Go 1.26)
|
|
12
|
+
5. Arhitectură recomandată proiect
|
|
13
|
+
6. Concurență în Go: modele, pattern-uri și scenarii Fusee
|
|
14
|
+
7. Implementări concrete: worker pool, errgroup, rate limiting, backpressure
|
|
15
|
+
8. HTTP server design și API pentru Fusee
|
|
16
|
+
9. Job orchestration: sync vs async, cache, deduplicare, multi-tenant
|
|
17
|
+
10. Securitate, izolare runner, sandboxing
|
|
18
|
+
11. Observabilitate, tracing și profilare (incl. goroutine leak profile 1.26)
|
|
19
|
+
12. Testing: unit, integration, golden, differential, leak tests
|
|
20
|
+
13. CI/CD, Dockerfile, producție
|
|
21
|
+
14. Performanță și optimizări practice
|
|
22
|
+
15. Anti-patterns și greșeli comune
|
|
23
|
+
16. Checklist de migrare JS → Go
|
|
24
|
+
17. Plan de învățare și implementare 90+ zile
|
|
25
|
+
18. Resurse și linkuri utile
|
|
26
|
+
|
|
27
|
+
1) De ce Go pentru serverul Fusee
|
|
28
|
+
- Simplitate, viteza de dezvoltare și ecosistem pentru servere networked.
|
|
29
|
+
- Model de concurență ușor de folosit (goroutines + channels) ideal pentru orchestration.
|
|
30
|
+
- Toolchain stabil, cross-compilation simplă, suport bun pentru containerizare și cloud native.
|
|
31
|
+
- Go 1.26 aduce optimizări GC și instrumente utile (goroutine leak profile) care ajută la construirea unui server robust.
|
|
32
|
+
|
|
33
|
+
2) Ce e nou în Go 1.26 (rezumat relevant)
|
|
34
|
+
- Green Tea garbage collector activ implicit (reduce overhead GC pentru alocări mici și concu- intensive).
|
|
35
|
+
- `errors.AsType[E error](err)` — verificări tip-sigure pentru erori.
|
|
36
|
+
- `new(expr)` — permite `new` cu expresii (utile pentru pointere inițializate inline în DTO-uri).
|
|
37
|
+
- Experimental: `simd/archsimd`, `runtime/secret`, `goroutineleak` profile.
|
|
38
|
+
- `go fix` modernizat — automatizări pentru modernizarea codului.
|
|
39
|
+
Referințe oficiale: https://go.dev/doc/go1.26 și https://go.dev/blog/go1.26
|
|
40
|
+
|
|
41
|
+
3) Reguli explicite pentru editorul AI / echipă
|
|
42
|
+
- Propagă `context.Context` în toate apelurile I/O, job-run și comunicare între componente.
|
|
43
|
+
- Nu lansa goroutine fără mecanism de oprire: folosește `context`, `WaitGroup`, canale, `errgroup`.
|
|
44
|
+
- Nu inventa API extern: folosește API-uri documentate; întreabă dacă nu e sigur.
|
|
45
|
+
- Evită variabile globale mutabile; folosește injecție de dependență (constructori de tip NewXxx).
|
|
46
|
+
- Error handling explicit: returnează erori, folosește `errors.Is`/`errors.AsType`.
|
|
47
|
+
- Nu folosi panic pentru control-flow; folosește recover centralizat la boundary-uri HTTP.
|
|
48
|
+
- Aplică backpressure — canale cu buffer limitat, rate-limiter (token bucket), cozi finite.
|
|
49
|
+
- Testează tot: unit tests, integration tests, benchmark-uri și leak tests (goroutineleak profile).
|
|
50
|
+
|
|
51
|
+
4) Setup & toolchain pentru Go 1.26
|
|
52
|
+
- Instalează Go 1.26 de pe https://go.dev/dl/ (sau managerul preferat). Setează `GOPATH` doar dacă ai nevoie; folosește `go mod`.
|
|
53
|
+
- Inițializează modul:
|
|
54
|
+
- `go mod init github.com/yourorg/fusee-server`
|
|
55
|
+
- Asigură `go 1.26` în `go.mod` (editează manual dacă `go mod init` a creat o versiune inferioară)
|
|
56
|
+
- Instrumente recomandate:
|
|
57
|
+
- `gofmt` (format), `go vet`, `golangci-lint`, `staticcheck`
|
|
58
|
+
- `go test` + `-race` pentru detecție race conditions
|
|
59
|
+
- `pprof` (profilare CPU/memorie) și `GOEXPERIMENT=goroutineleakprofile` pentru leak detection în CI/dev
|
|
60
|
+
- `minio` pentru test local S3, `redis` pentru cache/metadate
|
|
61
|
+
- `docker` / `kind` / `testcontainers` pentru e2e
|
|
62
|
+
|
|
63
|
+
5) Structura recomandată proiect
|
|
64
|
+
- cmd/fusee-server/main.go
|
|
65
|
+
- internal/server (HTTP server, middleware)
|
|
66
|
+
- internal/api (handlers, DTO, validation)
|
|
67
|
+
- internal/compile (orchestrare job-uri, queue)
|
|
68
|
+
- internal/worker (worker pool, runners)
|
|
69
|
+
- pkg/storage (S3 adapter), pkg/cache (in-memory + Redis)
|
|
70
|
+
- pkg/observability (metrics/tracing wrappers)
|
|
71
|
+
- test/ (fixtures, golden)
|
|
72
|
+
|
|
73
|
+
6) Concurența în Go — concepte și pattern-uri esențiale
|
|
74
|
+
- Goroutine: `go fn()` — unitate ușoară de execuție. Nu sunt gratuite.
|
|
75
|
+
- Channel: comunicare sincronă/asincronă între goroutine. Folosește canale buffered pentru backpressure.
|
|
76
|
+
- select: multiplexare pe canale + context.Done() pentru cancel.
|
|
77
|
+
- sync.WaitGroup: sincronizare pentru grupuri de goroutine.
|
|
78
|
+
- sync.Mutex / RWMutex / atomic: folosirea cu atenție când state partajat.
|
|
79
|
+
- errgroup: colectare erori din mai multe goroutine, propagare cancel.
|
|
80
|
+
|
|
81
|
+
Pattern-uri utile:
|
|
82
|
+
- Worker pool — pentru job-uri compilare.
|
|
83
|
+
- Fan-out/fan-in — paralelizare taskuri independente.
|
|
84
|
+
- Owner-per-shard — pentru a evita lock contention.
|
|
85
|
+
- Circuit breaker + retry with backoff — pentru dependențe instabile.
|
|
86
|
+
|
|
87
|
+
7) Exemple concrete (cod schematic) — worker pool și orchestration
|
|
88
|
+
- Exemplar worker pool (robust, cu ctx, timeout și wg):
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
package worker
|
|
92
|
+
|
|
93
|
+
import (
|
|
94
|
+
"context"
|
|
95
|
+
"sync"
|
|
96
|
+
"time"
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
type Job struct {
|
|
100
|
+
ID string
|
|
101
|
+
Input []byte
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
type Result struct {
|
|
105
|
+
JobID string
|
|
106
|
+
Err error
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
func StartWorkers(ctx context.Context, n int, jobs <-chan Job, results chan<- Result, wg *sync.WaitGroup) {
|
|
110
|
+
for i := 0; i < n; i++ {
|
|
111
|
+
wg.Add(1)
|
|
112
|
+
go func(workerID int) {
|
|
113
|
+
defer wg.Done()
|
|
114
|
+
for {
|
|
115
|
+
select {
|
|
116
|
+
case <-ctx.Done():
|
|
117
|
+
return
|
|
118
|
+
case job, ok := <-jobs:
|
|
119
|
+
if !ok { return }
|
|
120
|
+
jobCtx, cancel := context.WithTimeout(ctx, 5*time.Minute)
|
|
121
|
+
resErr := processJob(jobCtx, job)
|
|
122
|
+
cancel()
|
|
123
|
+
select {
|
|
124
|
+
case results <- Result{JobID: job.ID, Err: resErr}:
|
|
125
|
+
case <-ctx.Done():
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}(i)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// processJob este funcția de lucru care trebuie să respecte contextul
|
|
135
|
+
func processJob(ctx context.Context, j Job) error {
|
|
136
|
+
// implementare: build, write artifact to S3, update DB
|
|
137
|
+
return nil
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Observații:
|
|
142
|
+
- Folosește `jobCtx` cu timeout specific pentru fiecare job.
|
|
143
|
+
- Rezultatele pot fi stocate în DB sau trimise pe canal `results`.
|
|
144
|
+
- `wg` este așteptat la shutdown pentru a evita goroutine leaks.
|
|
145
|
+
|
|
146
|
+
8) HTTP server design & endpoint-uri recomandate
|
|
147
|
+
- Endpoints cheie:
|
|
148
|
+
- POST /compile → acceptă request, validează, calculează hash input, verifică cache, enquează job asincron și returnează 202 + job_id (sau 200 + artifact dacă e cache hit)
|
|
149
|
+
- GET /compile/{id}/status → starea jobului
|
|
150
|
+
- GET /assets/{hash} → serve artifact (WASM/JS) cu headers CDN
|
|
151
|
+
- /metrics, /debug/pprof/*, /healthz, /readyz
|
|
152
|
+
- Principii handler:
|
|
153
|
+
- Handlers mici: parse, validate, convert DTO, call service layer, write response
|
|
154
|
+
- Middleware pentru logging, tracing, recover (panic->500), rate-limit
|
|
155
|
+
|
|
156
|
+
Exemplu handler schematic:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
func (s *Server) compileHandler(w http.ResponseWriter, r *http.Request) {
|
|
160
|
+
ctx := r.Context()
|
|
161
|
+
var req CompileRequest
|
|
162
|
+
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
163
|
+
http.Error(w, "invalid JSON", http.StatusBadRequest)
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
if !s.limiter.Allow() {
|
|
167
|
+
http.Error(w, "rate limit", http.StatusTooManyRequests)
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
key := s.computeHash(req)
|
|
171
|
+
if art, ok := s.cache.Get(key); ok {
|
|
172
|
+
w.Header().Set("Content-Type", "application/wasm")
|
|
173
|
+
w.Write(art)
|
|
174
|
+
return
|
|
175
|
+
}
|
|
176
|
+
jobID, err := s.queue.Enqueue(ctx, req)
|
|
177
|
+
if err != nil {
|
|
178
|
+
http.Error(w, "internal", http.StatusInternalServerError)
|
|
179
|
+
return
|
|
180
|
+
}
|
|
181
|
+
w.WriteHeader(http.StatusAccepted)
|
|
182
|
+
json.NewEncoder(w).Encode(map[string]string{"job_id": jobID})
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
9) Job orchestration: sync vs async, cache & deduplicare
|
|
187
|
+
- Dev: permită compilare sync cu timeout curat (feedback rapid).
|
|
188
|
+
- Prod: async cu job queue și worker pool; returnează 202. Stochează artefactele în object store.
|
|
189
|
+
- Deduplicare: folosește hash funcțional (deterministic) din input (source + flags) pentru a evita recompilări.
|
|
190
|
+
- Stochează metadate în Redis/DB (status, retrier count, last error, artifact URL).
|
|
191
|
+
|
|
192
|
+
10) Securitate și izolare
|
|
193
|
+
- Rulează build-runner în containere sandbox (firecracker, gVisor, k8s Jobs) sau procese izolate.
|
|
194
|
+
- Limitările resurselor: cgroup limits, ulimit pentru procese runner.
|
|
195
|
+
- Validare input: never trust client input — sanitize, size limits, timeouts.
|
|
196
|
+
- TLS & auth pentru API, rate-limit per tenant.
|
|
197
|
+
|
|
198
|
+
11) Observabilitate, tracing și profilare
|
|
199
|
+
- Logging: zap/zerolog (structured logs). Include trace_id, job_id, tenant_id în log fields.
|
|
200
|
+
- Metrics: Prometheus client — counters, histograms (compile_duration_seconds), gauges (job_queue_length).
|
|
201
|
+
- Tracing: OpenTelemetry — trace request flow: HTTP -> queue -> worker -> storage.
|
|
202
|
+
- Profilare: pprof endpoints. Go 1.26 pprof UI default la flamegraph. Activează `goroutineleakprofile` în test/CI pentru leak detection.
|
|
203
|
+
|
|
204
|
+
12) Testare recomandată
|
|
205
|
+
- Unit tests (table-driven) pentru serviciile pure.
|
|
206
|
+
- Mocks pentru dependințe I/O (storage, redis) cu `github.com/golang/mock` sau `testify/mock`.
|
|
207
|
+
- Integration tests cu MinIO/Redis în container (testcontainers).
|
|
208
|
+
- Golden tests pentru output codgen (compare generated JS/WASM bytes).
|
|
209
|
+
- Differential tests: compară comportamentul JS-based compiler cu runner (Rust/WASM) dacă există.
|
|
210
|
+
- Leak tests: rulează workload mic + colectează goroutineleak profile și asigură că nu apar goroutine leaked.
|
|
211
|
+
|
|
212
|
+
13) CI/CD și Docker
|
|
213
|
+
- Docker multistage build; folosește `CGO_ENABLED=0` pentru binare statice (dacă nu folosești cgo).
|
|
214
|
+
- GitHub Actions / GitLab CI: lint -> unit tests -> build -> container -> smoke tests (integration), optional: run goroutine leak profile in CI smoke stage.
|
|
215
|
+
- Exemple Dockerfile (multistage):
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
FROM golang:1.26 AS builder
|
|
219
|
+
WORKDIR /src
|
|
220
|
+
COPY go.mod go.sum ./
|
|
221
|
+
RUN go mod download
|
|
222
|
+
COPY . .
|
|
223
|
+
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -o /app/cmd/fusee-server ./cmd/fusee-server
|
|
224
|
+
|
|
225
|
+
FROM gcr.io/distroless/static-debian11
|
|
226
|
+
COPY --from=builder /app/cmd/fusee-server /usr/local/bin/fusee-server
|
|
227
|
+
EXPOSE 8080
|
|
228
|
+
ENTRYPOINT ["/usr/local/bin/fusee-server"]
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
14) Performanță & optimizări
|
|
232
|
+
- Măsoară cu pprof înainte de optimizare.
|
|
233
|
+
- Evită alocările repetate: folosește `sync.Pool` pentru buffers mari.
|
|
234
|
+
- Sharding pentru a reduce lock contention.
|
|
235
|
+
- Folosește canale pentru coordonare când se potrivește, dar evită blocking pe canale necontrolate.
|
|
236
|
+
- Dacă e nevoie de operații vectorizate, poți explora `simd/archsimd` (experimental) sau implementări native în Rust pentru codgen.
|
|
237
|
+
|
|
238
|
+
15) Anti-patterns de evitat
|
|
239
|
+
- Goroutine leaks (pornite fără mecanism de oprire).
|
|
240
|
+
- Folosirea `panic` pentru flow control.
|
|
241
|
+
- Variabile globale mutabile pentru state aplicație.
|
|
242
|
+
- Blocking pe canale nebuffered în contexte fără timeout.
|
|
243
|
+
- Ignorarea contextului în apeluri externe.
|
|
244
|
+
|
|
245
|
+
16) Checklist migrare JS -> Go (server)
|
|
246
|
+
- Definește API contract (OpenAPI)
|
|
247
|
+
- Generare DTO în Go
|
|
248
|
+
- Implementare handlers pure și service layer
|
|
249
|
+
- Job queue + worker pool + cache/dedup
|
|
250
|
+
- Storage artifacts (S3) + CDN headers
|
|
251
|
+
- Observability (metrics, tracing) și health endpoints
|
|
252
|
+
- Security review + sandboxing runner
|
|
253
|
+
- Tests: unit/integration/golden/leak
|
|
254
|
+
|
|
255
|
+
17) Plan 90 zile (orientativ)
|
|
256
|
+
- Săptămâna 1-2: setup proiect, basic HTTP + middleware, DTO
|
|
257
|
+
- Săptămâna 3-4: implementare job queue simplu, worker pool, sync compile dev mode
|
|
258
|
+
- Săptămâna 5-6: integrate storage (MinIO), cache (Redis), dedup
|
|
259
|
+
- Săptămâna 7-8: add rate limiter, multi-tenant basics, health & metrics
|
|
260
|
+
- Săptămâna 9-10: tracing OTel, pprof, goroutine leak tests în CI
|
|
261
|
+
- Săptămâna 11-12: CI/CD, Docker image, smoke e2e, performance tuning
|
|
262
|
+
|
|
263
|
+
18) Resurse și linkuri utile
|
|
264
|
+
- Go 1.26 Release Notes: https://go.dev/doc/go1.26
|
|
265
|
+
- Go blog: https://go.dev/blog/go1.26
|
|
266
|
+
- Effective Go: https://go.dev/doc/effective_go
|
|
267
|
+
- golang.org/x/sync/errgroup: https://pkg.go.dev/golang.org/x/sync/errgroup
|
|
268
|
+
- golang.org/x/time/rate: https://pkg.go.dev/golang.org/x/time/rate
|
|
269
|
+
- Prometheus client: https://github.com/prometheus/client_golang
|
|
270
|
+
- OpenTelemetry Go: https://opentelemetry.io/docs/instrumentation/go/
|
|
271
|
+
|
|
272
|
+
Concluzie
|
|
273
|
+
- Construirea serverului Fusee în Go 1.26 aduce beneficii de performanță, scalabilitate și o experiență solidă de dezvoltare. Folosește `context` pe scară largă, gestionează cu grijă goroutine-urile, instrumentează observabilitatea și asigură izolare pentru runner.
|
|
274
|
+
- Go 1.26 oferă instrumente adiționale (goroutine leak profile, `errors.AsType`, Green Tea GC) care, folosite corect, îți vor ușura munca și îmbunătăți fiabilitatea.
|
|
275
|
+
|
|
276
|
+
Dacă dorești, pot salva acest fișier ca `ghid_go_fusee_integrat_go1_26.txt` și ți-l pot pune la dispoziție pentru descărcare. De asemenea pot genera o versiune v2 care include un repo template complet (fișiere `main.go`, `server` package, worker example), workflow GitHub Actions și setări `golangci-lint`.
|