@effindomv2/create-fui-as-app 0.1.3 → 0.1.4
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/build/templates/hello/asconfig.json +24 -0
- package/build/templates/hello/harness.ts +9 -0
- package/build/templates/hello/index.html +98 -0
- package/build/templates/hello/package.json +32 -0
- package/build/templates/hello/scripts/prepare-runtime.ts +18 -0
- package/build/templates/hello/scripts/smoke.ts +15 -0
- package/build/templates/hello/src/App.ts +7 -0
- package/build/templates/hello/src/Fui.ts +1 -0
- package/build/templates/hello/src/FuiBrowser.ts +1 -0
- package/build/templates/hello/src/FuiExports.ts +1 -0
- package/build/templates/hello/src/FuiPrimitives.ts +1 -0
- package/build/templates/hello/src/HelloWorld.ts +105 -0
- package/build/templates/hello/src/generated/HostEvents.ts +20 -0
- package/build/templates/hello/src/generated/HostServices.ts +8 -0
- package/build/templates/hello/src/host/host-events.ts +22 -0
- package/build/templates/hello/src/host/host-services.ts +18 -0
- package/build/templates/hello/tsconfig.json +9 -0
- package/build/templates/mvc/asconfig.json +24 -0
- package/build/templates/mvc/harness.ts +40 -0
- package/build/templates/mvc/index.html +11 -0
- package/build/templates/mvc/package.json +34 -0
- package/build/templates/mvc/route-shell.html +56 -0
- package/build/templates/mvc/scripts/prepare-runtime.ts +22 -0
- package/build/templates/mvc/scripts/smoke.ts +18 -0
- package/build/templates/mvc/src/Fui.ts +1 -0
- package/build/templates/mvc/src/FuiBrowser.ts +1 -0
- package/build/templates/mvc/src/FuiExports.ts +1 -0
- package/build/templates/mvc/src/FuiPrimitives.ts +1 -0
- package/build/templates/mvc/src/generated/HostEvents.ts +20 -0
- package/build/templates/mvc/src/generated/HostServices.ts +8 -0
- package/build/templates/mvc/src/host/host-events.ts +22 -0
- package/build/templates/mvc/src/host/host-services.ts +17 -0
- package/build/templates/mvc/src/routes/mvc/pages/home/HomeController.ts +55 -0
- package/build/templates/mvc/src/routes/mvc/pages/home/HomeModel.ts +8 -0
- package/build/templates/mvc/src/routes/mvc/pages/home/HomeView.ts +76 -0
- package/build/templates/mvc/src/routes/mvc/pages/settings/SettingsController.ts +27 -0
- package/build/templates/mvc/src/routes/mvc/pages/settings/SettingsModel.ts +6 -0
- package/build/templates/mvc/src/routes/mvc/pages/settings/SettingsView.ts +61 -0
- package/build/templates/mvc/src/routes/mvc/shared/design-system/MvcNavPill.ts +42 -0
- package/build/templates/mvc/src/routes/mvc/shared/design-system/MvcPrimaryButton.ts +19 -0
- package/build/templates/mvc/src/routes/mvc/shared/routes.ts +22 -0
- package/build/templates/mvc/src/routes/mvc_home.ts +20 -0
- package/build/templates/mvc/src/routes/mvc_settings.ts +20 -0
- package/build/templates/mvc/tsconfig.json +9 -0
- package/dist/scripts/sync-templates.d.ts +1 -0
- package/dist/scripts/sync-templates.js +297 -0
- package/dist/src/scaffold.d.ts +2 -0
- package/dist/src/scaffold.js +50 -5
- package/dist/src/templates.d.ts +2 -1
- package/dist/src/templates.js +39 -228
- package/dist/src/versions.d.ts +1 -1
- package/dist/src/versions.js +1 -1
- package/dist/tests/scaffold.test.js +26 -0
- package/package.json +6 -3
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"targets": {
|
|
3
|
+
"debug": {
|
|
4
|
+
"debug": true,
|
|
5
|
+
"exportRuntime": true,
|
|
6
|
+
"bindings": "esm",
|
|
7
|
+
"outFile": "public/app.wasm",
|
|
8
|
+
"sourceMap": true,
|
|
9
|
+
"textFile": "public/app.wat"
|
|
10
|
+
},
|
|
11
|
+
"release": {
|
|
12
|
+
"exportRuntime": true,
|
|
13
|
+
"bindings": "esm",
|
|
14
|
+
"optimizeLevel": 3,
|
|
15
|
+
"outFile": "public/app.wasm",
|
|
16
|
+
"shrinkLevel": 1,
|
|
17
|
+
"sourceMap": false,
|
|
18
|
+
"textFile": "public/app.wat"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"options": {
|
|
22
|
+
"runtime": "stub"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { startHarness } from './src/FuiBrowser';
|
|
2
|
+
import { appHostEvents } from './src/host/host-events';
|
|
3
|
+
import { appHostServices } from './src/host/host-services';
|
|
4
|
+
|
|
5
|
+
startHarness({
|
|
6
|
+
wasmPath: './app.wasm',
|
|
7
|
+
hostEvents: appHostEvents,
|
|
8
|
+
hostServices: appHostServices,
|
|
9
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>FUI-AS Hello World</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
color-scheme: light dark;
|
|
10
|
+
font-family: Inter, "Segoe UI", system-ui, -apple-system, sans-serif;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
html,
|
|
14
|
+
body {
|
|
15
|
+
width: 100%;
|
|
16
|
+
height: 100%;
|
|
17
|
+
margin: 0;
|
|
18
|
+
padding: 0;
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
background: #0f172a;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.app-shell {
|
|
24
|
+
position: fixed;
|
|
25
|
+
inset: 0;
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
canvas {
|
|
30
|
+
box-sizing: border-box;
|
|
31
|
+
display: block;
|
|
32
|
+
width: 100%;
|
|
33
|
+
height: 100%;
|
|
34
|
+
outline: none;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.effindom-loading-overlay {
|
|
38
|
+
position: absolute;
|
|
39
|
+
inset: 0;
|
|
40
|
+
display: grid;
|
|
41
|
+
place-items: center;
|
|
42
|
+
padding: 18px;
|
|
43
|
+
box-sizing: border-box;
|
|
44
|
+
background: color-mix(in srgb, Canvas 35%, transparent);
|
|
45
|
+
backdrop-filter: blur(10px);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.effindom-loading-overlay[hidden] {
|
|
49
|
+
display: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.effindom-loading-card {
|
|
53
|
+
max-width: 420px;
|
|
54
|
+
padding: 20px;
|
|
55
|
+
border-radius: 14px;
|
|
56
|
+
border: 1px solid color-mix(in srgb, CanvasText 20%, transparent);
|
|
57
|
+
background: color-mix(in srgb, Canvas 85%, transparent);
|
|
58
|
+
text-align: center;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.effindom-loading-kicker {
|
|
62
|
+
margin: 0 0 8px;
|
|
63
|
+
font-size: 11px;
|
|
64
|
+
letter-spacing: 0.1em;
|
|
65
|
+
text-transform: uppercase;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.effindom-loading-title {
|
|
69
|
+
margin: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.effindom-loading-detail {
|
|
73
|
+
margin: 8px 0 0;
|
|
74
|
+
opacity: 0.85;
|
|
75
|
+
}
|
|
76
|
+
</style>
|
|
77
|
+
</head>
|
|
78
|
+
<body>
|
|
79
|
+
<section class="app-shell" data-effindom-canvas-size-source>
|
|
80
|
+
<canvas id="fui-canvas"></canvas>
|
|
81
|
+
<div
|
|
82
|
+
class="effindom-loading-overlay"
|
|
83
|
+
id="effindom-loading-overlay"
|
|
84
|
+
data-state="loading"
|
|
85
|
+
aria-live="polite"
|
|
86
|
+
aria-hidden="false">
|
|
87
|
+
<div class="effindom-loading-card">
|
|
88
|
+
<p class="effindom-loading-kicker">EffinDom backstage</p>
|
|
89
|
+
<h2 class="effindom-loading-title" id="effindom-loading-title">Teaching the pixels their lines...</h2>
|
|
90
|
+
<p class="effindom-loading-detail" id="effindom-loading-detail">The runtime orchestra is tuning up behind the canvas.</p>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</section>
|
|
94
|
+
<script src="./effindom-runtime-config.js"></script>
|
|
95
|
+
<script src="./bridge.js"></script>
|
|
96
|
+
<script type="module" src="./harness.js"></script>
|
|
97
|
+
</body>
|
|
98
|
+
</html>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PACKAGE_NAME__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Scaffolded FUI-AS hello-world app",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "npm run generate:host && npm run build:assets && npm run build:wasm && npm run build:harness",
|
|
9
|
+
"build:assets": "tsx scripts/prepare-runtime.ts",
|
|
10
|
+
"build:wasm": "asc src/App.ts --config asconfig.json --target release",
|
|
11
|
+
"build:harness": "esbuild harness.ts --bundle --format=esm --platform=browser --outfile=public/harness.js",
|
|
12
|
+
"generate:host-services": "tsx ./node_modules/@effindomv2/fui-as/scripts/generate-host-services.ts src/host/host-services.ts appHostServices src/generated/HostServices.ts ../FuiPrimitives",
|
|
13
|
+
"generate:host-events": "tsx ./node_modules/@effindomv2/fui-as/scripts/generate-host-events.ts src/host/host-events.ts appHostEvents src/generated/HostEvents.ts ../FuiPrimitives",
|
|
14
|
+
"generate:host": "npm run generate:host-services && npm run generate:host-events",
|
|
15
|
+
"watch": "chokidar \"src/**/*.ts\" \"harness.ts\" \"index.html\" \"asconfig.json\" -c \"npm run build\"",
|
|
16
|
+
"serve": "http-server public -p 8080 -c-1",
|
|
17
|
+
"dev": "npm run build && concurrently -k -n watch,serve \"npm run watch\" \"npm run serve\"",
|
|
18
|
+
"test": "npm run build && tsx scripts/smoke.ts"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@effindomv2/fui-as": "__FUI_AS_VERSION__",
|
|
22
|
+
"@effindomv2/runtime": "__RUNTIME_VERSION__"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"assemblyscript": "0.28.17",
|
|
26
|
+
"chokidar-cli": "^3.0.0",
|
|
27
|
+
"concurrently": "^9.2.1",
|
|
28
|
+
"esbuild": "^0.27.7",
|
|
29
|
+
"http-server": "^14.1.1",
|
|
30
|
+
"tsx": "^4.20.6"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { copyFileSync, cpSync, existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
const outputDir = "public";
|
|
4
|
+
rmSync(outputDir, { recursive: true, force: true });
|
|
5
|
+
mkdirSync(`${outputDir}/runtime`, { recursive: true });
|
|
6
|
+
|
|
7
|
+
cpSync("node_modules/@effindomv2/runtime/dist", `${outputDir}/runtime/dist`, { recursive: true });
|
|
8
|
+
cpSync("node_modules/@effindomv2/runtime/dist/fonts", `${outputDir}/runtime/fonts`, { recursive: true });
|
|
9
|
+
copyFileSync("node_modules/@effindomv2/runtime/dist/bridge.js", `${outputDir}/bridge.js`);
|
|
10
|
+
if (existsSync("node_modules/@effindomv2/runtime/dist/bridge.js.map")) {
|
|
11
|
+
copyFileSync("node_modules/@effindomv2/runtime/dist/bridge.js.map", `${outputDir}/bridge.js.map`);
|
|
12
|
+
}
|
|
13
|
+
writeFileSync(
|
|
14
|
+
`${outputDir}/effindom-runtime-config.js`,
|
|
15
|
+
'window.__effindomRuntime = Object.assign({}, window.__effindomRuntime, { manifestUrl: "./runtime/dist/effindom.v2.manifest.json" });\n',
|
|
16
|
+
"utf8",
|
|
17
|
+
);
|
|
18
|
+
copyFileSync("index.html", `${outputDir}/index.html`);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { accessSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
const expectedFiles = [
|
|
4
|
+
"public/index.html",
|
|
5
|
+
"public/harness.js",
|
|
6
|
+
"public/app.wasm",
|
|
7
|
+
"public/bridge.js",
|
|
8
|
+
"public/effindom-runtime-config.js",
|
|
9
|
+
"public/runtime/dist/effindom.v2.manifest.json",
|
|
10
|
+
"public/runtime/fonts/NotoSans-Regular.ttf",
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
for (const filePath of expectedFiles) {
|
|
14
|
+
accessSync(filePath);
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../node_modules/@effindomv2/fui-as/src/Fui";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../node_modules/@effindomv2/fui-as/browser/src/index";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../node_modules/@effindomv2/fui-as/src/FuiExports";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../node_modules/@effindomv2/fui-as/src/FuiPrimitives";
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AlignItems,
|
|
3
|
+
Button,
|
|
4
|
+
Column,
|
|
5
|
+
JustifyContent,
|
|
6
|
+
rgb,
|
|
7
|
+
SelectionArea,
|
|
8
|
+
Text,
|
|
9
|
+
TextAlign,
|
|
10
|
+
Unit,
|
|
11
|
+
} from "./Fui";
|
|
12
|
+
import { Callback1 } from "./FuiPrimitives";
|
|
13
|
+
import { onAppClockTick } from "./generated/HostEvents";
|
|
14
|
+
import { appClockNowUnixSeconds } from "./generated/HostServices";
|
|
15
|
+
|
|
16
|
+
class ClockTickHandler extends Callback1<i32> {
|
|
17
|
+
private readonly owner: HelloWorld;
|
|
18
|
+
|
|
19
|
+
constructor(owner: HelloWorld) {
|
|
20
|
+
super();
|
|
21
|
+
this.owner = owner;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
invoke(value: i32): void {
|
|
25
|
+
this.owner.setEventTime(value);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
class HelloWorld {
|
|
30
|
+
private clickCount: i32 = 0;
|
|
31
|
+
private readonly counterLabel: Text = new Text("Clicked 0 times");
|
|
32
|
+
private readonly hostServiceLabel: Text = new Text("Host service time: -");
|
|
33
|
+
private readonly hostEventLabel: Text = new Text("Host event tick: -");
|
|
34
|
+
private readonly clockTickHandler: ClockTickHandler = new ClockTickHandler(this);
|
|
35
|
+
|
|
36
|
+
constructor() {
|
|
37
|
+
this.counterLabel.fontSize(20.0);
|
|
38
|
+
this.hostServiceLabel.fontSize(14.0).textColor(rgb(191, 219, 254));
|
|
39
|
+
this.hostEventLabel.fontSize(14.0).textColor(rgb(134, 239, 172));
|
|
40
|
+
this.refreshHostServiceTime();
|
|
41
|
+
onAppClockTick(this.clockTickHandler);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private refreshHostServiceTime(): void {
|
|
45
|
+
const seconds = appClockNowUnixSeconds();
|
|
46
|
+
this.hostServiceLabel.text("Host service time: " + seconds.toString());
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private setEventTime(seconds: i32): void {
|
|
50
|
+
this.hostEventLabel.text("Host event tick: " + seconds.toString());
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
buildPage(): SelectionArea {
|
|
54
|
+
|
|
55
|
+
const title = new Text("Hello world from FUI-AS")
|
|
56
|
+
.fontSize(36.0)
|
|
57
|
+
.textAlign(TextAlign.Center)
|
|
58
|
+
.width(100.0, Unit.Percent);
|
|
59
|
+
|
|
60
|
+
const subtitle = new Text("A tiny app in two files: App.ts + HelloWorld.ts")
|
|
61
|
+
.fontSize(16.0)
|
|
62
|
+
.textAlign(TextAlign.Center)
|
|
63
|
+
.width(100.0, Unit.Percent);
|
|
64
|
+
|
|
65
|
+
const button = new Button("Click me")
|
|
66
|
+
.margin(0.0, 18.0, 0.0, 12.0)
|
|
67
|
+
.onClickWith<HelloWorld>(this, owner => {
|
|
68
|
+
owner.clickCount += 1;
|
|
69
|
+
owner.counterLabel.text(
|
|
70
|
+
"Clicked " + owner.clickCount.toString() + " time" + (owner.clickCount == 1 ? "" : "s"),
|
|
71
|
+
);
|
|
72
|
+
owner.refreshHostServiceTime();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const note = new Text(
|
|
76
|
+
"For production apps, move to an explicit MVC structure once screens, state, or host integration grows.",
|
|
77
|
+
)
|
|
78
|
+
.fontSize(14.0)
|
|
79
|
+
.textAlign(TextAlign.Center)
|
|
80
|
+
.width(680.0, Unit.Pixel);
|
|
81
|
+
|
|
82
|
+
return new SelectionArea()
|
|
83
|
+
.fillWidth()
|
|
84
|
+
.fillHeight()
|
|
85
|
+
.child(
|
|
86
|
+
Column(
|
|
87
|
+
title,
|
|
88
|
+
subtitle,
|
|
89
|
+
button,
|
|
90
|
+
this.counterLabel,
|
|
91
|
+
this.hostServiceLabel,
|
|
92
|
+
this.hostEventLabel,
|
|
93
|
+
note)
|
|
94
|
+
.fillWidth()
|
|
95
|
+
.fillHeight()
|
|
96
|
+
.padding(24.0, 24.0, 24.0, 24.0)
|
|
97
|
+
.justifyContent(JustifyContent.Center)
|
|
98
|
+
.alignItems(AlignItems.Center))
|
|
99
|
+
.bgColor(rgb(0, 0, 0)) as SelectionArea;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function createHelloWorldPage(): SelectionArea {
|
|
104
|
+
return new HelloWorld().buildPage();
|
|
105
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Generated from the scaffold host-events definition.
|
|
2
|
+
import { Callback0, Callback1, Callback2 } from "../FuiPrimitives";
|
|
3
|
+
|
|
4
|
+
let __appClockTickHandler: Callback1<i32> | null = null;
|
|
5
|
+
|
|
6
|
+
export function onAppClockTick(callback: Callback1<i32> | null): void {
|
|
7
|
+
__appClockTickHandler = callback;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function clearAppClockTick(): void {
|
|
11
|
+
__appClockTickHandler = null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function __fui_host_event_appClockTick(arg0: i32): void {
|
|
15
|
+
const callback = __appClockTickHandler;
|
|
16
|
+
if (callback === null) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
callback.invoke(arg0);
|
|
20
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Generated from the scaffold host-services definition.
|
|
2
|
+
|
|
3
|
+
@external("fui_host_service", "appClockNowUnixSeconds")
|
|
4
|
+
declare function __host_appClockNowUnixSeconds(): i32;
|
|
5
|
+
|
|
6
|
+
export function appClockNowUnixSeconds(): i32 {
|
|
7
|
+
return __host_appClockNowUnixSeconds();
|
|
8
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineHostEvents, hostEvent } from "../FuiBrowser";
|
|
2
|
+
|
|
3
|
+
function nowUnixSeconds(): number {
|
|
4
|
+
return Math.floor(Date.now() / 1000);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const appHostEvents = defineHostEvents({
|
|
8
|
+
// Host events are push notifications from browser host -> AssemblyScript.
|
|
9
|
+
// subscribe(...) returns an optional disposer used by the harness on teardown.
|
|
10
|
+
appClock: {
|
|
11
|
+
tick: hostEvent({
|
|
12
|
+
args: ["i32"],
|
|
13
|
+
subscribe: (emit) => {
|
|
14
|
+
emit(nowUnixSeconds());
|
|
15
|
+
const timer = setInterval(() => {
|
|
16
|
+
emit(nowUnixSeconds());
|
|
17
|
+
}, 1000);
|
|
18
|
+
return () => clearInterval(timer);
|
|
19
|
+
},
|
|
20
|
+
}),
|
|
21
|
+
},
|
|
22
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineHostServices, hostService } from "../FuiBrowser";
|
|
2
|
+
|
|
3
|
+
function nowUnixSeconds(): number {
|
|
4
|
+
return Math.floor(Date.now() / 1000);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const appHostServices = defineHostServices({
|
|
8
|
+
// Host services are request/response calls from AssemblyScript -> browser host.
|
|
9
|
+
// Keep names domain-oriented so generated wrappers read naturally:
|
|
10
|
+
// appClock.nowUnixSeconds() -> appClockNowUnixSeconds().
|
|
11
|
+
appClock: {
|
|
12
|
+
nowUnixSeconds: hostService({
|
|
13
|
+
args: [],
|
|
14
|
+
returns: "i32",
|
|
15
|
+
implementation: (): number => nowUnixSeconds(),
|
|
16
|
+
}),
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"targets": {
|
|
3
|
+
"debug": {
|
|
4
|
+
"debug": true,
|
|
5
|
+
"exportRuntime": true,
|
|
6
|
+
"bindings": "esm",
|
|
7
|
+
"outFile": "public/app.wasm",
|
|
8
|
+
"sourceMap": true,
|
|
9
|
+
"textFile": "public/app.wat"
|
|
10
|
+
},
|
|
11
|
+
"release": {
|
|
12
|
+
"exportRuntime": true,
|
|
13
|
+
"bindings": "esm",
|
|
14
|
+
"optimizeLevel": 3,
|
|
15
|
+
"outFile": "public/app.wasm",
|
|
16
|
+
"shrinkLevel": 1,
|
|
17
|
+
"sourceMap": false,
|
|
18
|
+
"textFile": "public/app.wat"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"options": {
|
|
22
|
+
"runtime": "stub"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { startRoutedHarness, type HarnessExports, type RoutedHarnessRoute } from './src/FuiBrowser';
|
|
2
|
+
import { appHostEvents } from './src/host/host-events';
|
|
3
|
+
import { appHostServices } from './src/host/host-services';
|
|
4
|
+
|
|
5
|
+
type MvcRouteExports = HarnessExports & {
|
|
6
|
+
__runApp(): void;
|
|
7
|
+
__disposeApp?(): void;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const routePrefix = window.location.pathname.startsWith('/v2/fui-as/demo-mvc/') ? '/v2/fui-as/demo-mvc' : '';
|
|
11
|
+
const routes: readonly RoutedHarnessRoute[] = [
|
|
12
|
+
{
|
|
13
|
+
routePath: `${routePrefix}/mvc-home/`,
|
|
14
|
+
wasmPath: `${routePrefix}/mvc-home.wasm`,
|
|
15
|
+
title: 'MVC Home',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
routePath: `${routePrefix}/mvc-settings/`,
|
|
19
|
+
wasmPath: `${routePrefix}/mvc-settings.wasm`,
|
|
20
|
+
title: 'MVC Settings',
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
startRoutedHarness<MvcRouteExports>({
|
|
25
|
+
shellId: 'fui-mvc',
|
|
26
|
+
routeBase: routes[0].routePath,
|
|
27
|
+
routes,
|
|
28
|
+
recreateRuntimeOnWarmRouteSwap: true,
|
|
29
|
+
showLoadingOverlay(isWarmRouteSwap): boolean {
|
|
30
|
+
return !isWarmRouteSwap;
|
|
31
|
+
},
|
|
32
|
+
run(exports): void {
|
|
33
|
+
exports.__runApp();
|
|
34
|
+
},
|
|
35
|
+
onDispose(exports): void {
|
|
36
|
+
exports.__disposeApp?.();
|
|
37
|
+
},
|
|
38
|
+
hostEvents: appHostEvents,
|
|
39
|
+
hostServices: appHostServices,
|
|
40
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta http-equiv="refresh" content="0; url=/mvc-home/" />
|
|
6
|
+
<title>FUI-AS MVC App</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<p>Redirecting to <a href="/mvc-home/">/mvc-home/</a>…</p>
|
|
10
|
+
</body>
|
|
11
|
+
</html>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PACKAGE_NAME__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Scaffolded FUI-AS MVC app",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "npm run generate:host && npm run build:assets && npm run build:wasm && npm run build:harness",
|
|
9
|
+
"build:assets": "tsx scripts/prepare-runtime.ts",
|
|
10
|
+
"build:wasm": "npm run build:wasm:home && npm run build:wasm:settings",
|
|
11
|
+
"build:wasm:home": "asc src/routes/mvc_home.ts --config asconfig.json --target release --outFile public/mvc-home.wasm",
|
|
12
|
+
"build:wasm:settings": "asc src/routes/mvc_settings.ts --config asconfig.json --target release --outFile public/mvc-settings.wasm",
|
|
13
|
+
"build:harness": "esbuild harness.ts --bundle --format=esm --platform=browser --outfile=public/harness.js",
|
|
14
|
+
"generate:host-services": "tsx ./node_modules/@effindomv2/fui-as/scripts/generate-host-services.ts src/host/host-services.ts appHostServices src/generated/HostServices.ts ../FuiPrimitives",
|
|
15
|
+
"generate:host-events": "tsx ./node_modules/@effindomv2/fui-as/scripts/generate-host-events.ts src/host/host-events.ts appHostEvents src/generated/HostEvents.ts ../FuiPrimitives",
|
|
16
|
+
"generate:host": "npm run generate:host-services && npm run generate:host-events",
|
|
17
|
+
"watch": "chokidar \"src/**/*.ts\" \"harness.ts\" \"route-shell.html\" \"index.html\" \"asconfig.json\" -c \"npm run build\"",
|
|
18
|
+
"serve": "http-server public -p 8080 -c-1",
|
|
19
|
+
"dev": "npm run build && concurrently -k -n watch,serve \"npm run watch\" \"npm run serve\"",
|
|
20
|
+
"test": "npm run build && tsx scripts/smoke.ts"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@effindomv2/fui-as": "__FUI_AS_VERSION__",
|
|
24
|
+
"@effindomv2/runtime": "__RUNTIME_VERSION__"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"assemblyscript": "0.28.17",
|
|
28
|
+
"chokidar-cli": "^3.0.0",
|
|
29
|
+
"concurrently": "^9.2.1",
|
|
30
|
+
"esbuild": "^0.27.7",
|
|
31
|
+
"http-server": "^14.1.1",
|
|
32
|
+
"tsx": "^4.20.6"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<base href="../" />
|
|
7
|
+
<title>FUI-AS MVC Demo</title>
|
|
8
|
+
<style>
|
|
9
|
+
html, body {
|
|
10
|
+
margin: 0;
|
|
11
|
+
width: 100%;
|
|
12
|
+
height: 100%;
|
|
13
|
+
overflow: hidden;
|
|
14
|
+
background: #020617;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
main {
|
|
18
|
+
width: 100%;
|
|
19
|
+
height: 100%;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
canvas {
|
|
23
|
+
display: block;
|
|
24
|
+
width: 100%;
|
|
25
|
+
height: 100%;
|
|
26
|
+
background: #020617;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.effindom-loading-overlay {
|
|
30
|
+
position: fixed;
|
|
31
|
+
inset: 0;
|
|
32
|
+
display: grid;
|
|
33
|
+
place-items: center;
|
|
34
|
+
color: #e2e8f0;
|
|
35
|
+
background: rgba(2, 6, 23, 0.75);
|
|
36
|
+
z-index: 2;
|
|
37
|
+
font-family: system-ui, sans-serif;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.effindom-loading-overlay[hidden] {
|
|
41
|
+
display: none;
|
|
42
|
+
}
|
|
43
|
+
</style>
|
|
44
|
+
</head>
|
|
45
|
+
<body>
|
|
46
|
+
<main data-effindom-canvas-size-source>
|
|
47
|
+
<canvas id="fui-canvas"></canvas>
|
|
48
|
+
</main>
|
|
49
|
+
<div class="effindom-loading-overlay" id="effindom-loading-overlay" data-state="loading">
|
|
50
|
+
<div>Loading MVC demo…</div>
|
|
51
|
+
</div>
|
|
52
|
+
<script src="./effindom-runtime-config.js"></script>
|
|
53
|
+
<script src="./bridge.js"></script>
|
|
54
|
+
<script type="module" src="./harness.js"></script>
|
|
55
|
+
</body>
|
|
56
|
+
</html>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { copyFileSync, cpSync, existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
const outputDir = "public";
|
|
4
|
+
rmSync(outputDir, { recursive: true, force: true });
|
|
5
|
+
mkdirSync(`${outputDir}/runtime`, { recursive: true });
|
|
6
|
+
mkdirSync(`${outputDir}/mvc-home`, { recursive: true });
|
|
7
|
+
mkdirSync(`${outputDir}/mvc-settings`, { recursive: true });
|
|
8
|
+
|
|
9
|
+
cpSync("node_modules/@effindomv2/runtime/dist", `${outputDir}/runtime/dist`, { recursive: true });
|
|
10
|
+
cpSync("node_modules/@effindomv2/runtime/dist/fonts", `${outputDir}/runtime/fonts`, { recursive: true });
|
|
11
|
+
copyFileSync("node_modules/@effindomv2/runtime/dist/bridge.js", `${outputDir}/bridge.js`);
|
|
12
|
+
if (existsSync("node_modules/@effindomv2/runtime/dist/bridge.js.map")) {
|
|
13
|
+
copyFileSync("node_modules/@effindomv2/runtime/dist/bridge.js.map", `${outputDir}/bridge.js.map`);
|
|
14
|
+
}
|
|
15
|
+
writeFileSync(
|
|
16
|
+
`${outputDir}/effindom-runtime-config.js`,
|
|
17
|
+
'window.__effindomRuntime = Object.assign({}, window.__effindomRuntime, { manifestUrl: "./runtime/dist/effindom.v2.manifest.json" });\n',
|
|
18
|
+
"utf8",
|
|
19
|
+
);
|
|
20
|
+
copyFileSync("index.html", `${outputDir}/index.html`);
|
|
21
|
+
copyFileSync("route-shell.html", `${outputDir}/mvc-home/index.html`);
|
|
22
|
+
copyFileSync("route-shell.html", `${outputDir}/mvc-settings/index.html`);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { accessSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
const expectedFiles = [
|
|
4
|
+
"public/index.html",
|
|
5
|
+
"public/harness.js",
|
|
6
|
+
"public/mvc-home/index.html",
|
|
7
|
+
"public/mvc-settings/index.html",
|
|
8
|
+
"public/mvc-home.wasm",
|
|
9
|
+
"public/mvc-settings.wasm",
|
|
10
|
+
"public/bridge.js",
|
|
11
|
+
"public/effindom-runtime-config.js",
|
|
12
|
+
"public/runtime/dist/effindom.v2.manifest.json",
|
|
13
|
+
"public/runtime/fonts/NotoSans-Regular.ttf",
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
for (const filePath of expectedFiles) {
|
|
17
|
+
accessSync(filePath);
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../node_modules/@effindomv2/fui-as/src/Fui";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../node_modules/@effindomv2/fui-as/browser/src/index";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../node_modules/@effindomv2/fui-as/src/FuiExports";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../node_modules/@effindomv2/fui-as/src/FuiPrimitives";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Generated from the scaffold host-events definition.
|
|
2
|
+
import { Callback0, Callback1, Callback2 } from "../FuiPrimitives";
|
|
3
|
+
|
|
4
|
+
let __appClockTickHandler: Callback1<i32> | null = null;
|
|
5
|
+
|
|
6
|
+
export function onAppClockTick(callback: Callback1<i32> | null): void {
|
|
7
|
+
__appClockTickHandler = callback;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function clearAppClockTick(): void {
|
|
11
|
+
__appClockTickHandler = null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function __fui_host_event_appClockTick(arg0: i32): void {
|
|
15
|
+
const callback = __appClockTickHandler;
|
|
16
|
+
if (callback === null) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
callback.invoke(arg0);
|
|
20
|
+
}
|