round-core 0.1.2 → 0.1.3
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/package.json +13 -8
- package/src/cli.js +609 -0
- package/src/compiler/index.js +2 -0
- package/src/compiler/transformer.js +525 -0
- package/src/compiler/vite-plugin.d.ts +8 -0
- package/src/compiler/vite-plugin.js +472 -0
- package/src/index.js +42 -0
- package/src/runtime/context.js +101 -0
- package/src/runtime/dom.js +401 -0
- package/src/runtime/error-boundary.js +48 -0
- package/src/runtime/error-reporter.js +13 -0
- package/src/runtime/error-store.js +85 -0
- package/src/runtime/errors.js +152 -0
- package/src/runtime/lifecycle.js +140 -0
- package/src/runtime/router.js +475 -0
- package/src/runtime/signals.js +484 -0
- package/src/runtime/store.js +215 -0
- package/src/runtime/suspense.js +128 -0
- package/dist/cli.js +0 -607
- package/dist/index.js +0 -2071
- package/dist/vite-plugin.js +0 -883
- /package/{dist → src}/index.d.ts +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { signal } from './signals.js';
|
|
2
|
+
import { createElement, Fragment } from './dom.js';
|
|
3
|
+
import { createContext } from './context.js';
|
|
4
|
+
|
|
5
|
+
function isPromiseLike(v) {
|
|
6
|
+
return v && (typeof v === 'object' || typeof v === 'function') && typeof v.then === 'function';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const SuspenseContext = createContext(null);
|
|
10
|
+
export { SuspenseContext };
|
|
11
|
+
|
|
12
|
+
export function lazy(loader) {
|
|
13
|
+
if (typeof loader !== 'function') {
|
|
14
|
+
throw new Error('lazy(loader) expects a function that returns a Promise');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let status = 'uninitialized';
|
|
18
|
+
let promise = null;
|
|
19
|
+
let component = null;
|
|
20
|
+
let error = null;
|
|
21
|
+
|
|
22
|
+
function pickComponent(mod) {
|
|
23
|
+
if (!mod) return null;
|
|
24
|
+
if (typeof mod === 'function') return mod;
|
|
25
|
+
if (typeof mod.default === 'function') return mod.default;
|
|
26
|
+
if (typeof mod.Counter === 'function') return mod.Counter;
|
|
27
|
+
|
|
28
|
+
const fns = [];
|
|
29
|
+
for (const k of Object.keys(mod)) {
|
|
30
|
+
if (typeof mod[k] === 'function') fns.push(mod[k]);
|
|
31
|
+
}
|
|
32
|
+
if (fns.length === 1) return fns[0];
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return function LazyComponent(props = {}) {
|
|
37
|
+
if (status === 'resolved') {
|
|
38
|
+
return createElement(component, props);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (status === 'rejected') {
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!promise) {
|
|
46
|
+
status = 'pending';
|
|
47
|
+
try {
|
|
48
|
+
promise = Promise.resolve(loader())
|
|
49
|
+
.then((mod) => {
|
|
50
|
+
const resolved = pickComponent(mod);
|
|
51
|
+
if (typeof resolved !== 'function') {
|
|
52
|
+
throw new Error('lazy() loaded module does not export a component');
|
|
53
|
+
}
|
|
54
|
+
component = resolved;
|
|
55
|
+
status = 'resolved';
|
|
56
|
+
})
|
|
57
|
+
.catch((e) => {
|
|
58
|
+
error = e instanceof Error ? e : new Error(String(e));
|
|
59
|
+
status = 'rejected';
|
|
60
|
+
});
|
|
61
|
+
} catch (e) {
|
|
62
|
+
error = e instanceof Error ? e : new Error(String(e));
|
|
63
|
+
status = 'rejected';
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
throw promise;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function Suspense(props = {}) {
|
|
73
|
+
const tick = signal(0);
|
|
74
|
+
const pending = new Set();
|
|
75
|
+
|
|
76
|
+
// Track promises we are currently waiting for to avoid re-adding them or flickering
|
|
77
|
+
const waiting = new Set();
|
|
78
|
+
|
|
79
|
+
const child = Array.isArray(props.children) ? props.children[0] : props.children;
|
|
80
|
+
const childFn = typeof child === 'function' ? child : () => child;
|
|
81
|
+
|
|
82
|
+
const register = (promise) => {
|
|
83
|
+
if (!waiting.has(promise)) {
|
|
84
|
+
waiting.add(promise);
|
|
85
|
+
pending.add(promise);
|
|
86
|
+
promise.then(
|
|
87
|
+
() => {
|
|
88
|
+
waiting.delete(promise);
|
|
89
|
+
pending.delete(promise);
|
|
90
|
+
tick(tick.peek() + 1);
|
|
91
|
+
},
|
|
92
|
+
() => {
|
|
93
|
+
waiting.delete(promise);
|
|
94
|
+
pending.delete(promise);
|
|
95
|
+
tick(tick.peek() + 1);
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
return createElement(SuspenseContext.Provider, {
|
|
102
|
+
value: { register }
|
|
103
|
+
}, () => {
|
|
104
|
+
// Read tick to re-render when promises resolve
|
|
105
|
+
tick();
|
|
106
|
+
|
|
107
|
+
// If pending promises, show fallback depending on strategy.
|
|
108
|
+
|
|
109
|
+
if (pending.size > 0) {
|
|
110
|
+
return props.fallback ?? null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const res = childFn();
|
|
115
|
+
if (isPromiseLike(res)) {
|
|
116
|
+
register(res);
|
|
117
|
+
return props.fallback ?? null;
|
|
118
|
+
}
|
|
119
|
+
return res ?? null;
|
|
120
|
+
} catch (e) {
|
|
121
|
+
if (isPromiseLike(e)) {
|
|
122
|
+
register(e);
|
|
123
|
+
return props.fallback ?? null;
|
|
124
|
+
}
|
|
125
|
+
throw e;
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|