@zero-bits/kernel 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 +119 -0
- package/dist/chunk-D4E5XKWD.js +482 -0
- package/dist/chunk-ETCJDJTI.cjs +482 -0
- package/dist/core/index.cjs +28 -0
- package/dist/core/index.d.cts +58 -0
- package/dist/core/index.d.ts +58 -0
- package/dist/core/index.js +28 -0
- package/dist/react/index.cjs +147 -0
- package/dist/react/index.d.cts +42 -0
- package/dist/react/index.d.ts +42 -0
- package/dist/react/index.js +147 -0
- package/dist/types-JlxTjSfC.d.cts +120 -0
- package/dist/types-JlxTjSfC.d.ts +120 -0
- package/package.json +38 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunkETCJDJTIcjs = require('../chunk-ETCJDJTI.cjs');
|
|
5
|
+
|
|
6
|
+
// src/react/PluginSlot.tsx
|
|
7
|
+
var _react = require('react'); var _react2 = _interopRequireDefault(_react);
|
|
8
|
+
var KernelContext = _react2.default.createContext(null);
|
|
9
|
+
function KernelProvider({ kernel, children }) {
|
|
10
|
+
return /* @__PURE__ */ _react2.default.createElement(KernelContext.Provider, { value: kernel }, children);
|
|
11
|
+
}
|
|
12
|
+
var PluginErrorBoundary = class extends _react2.default.Component {
|
|
13
|
+
constructor(props) {
|
|
14
|
+
super(props);
|
|
15
|
+
this.state = { error: null };
|
|
16
|
+
}
|
|
17
|
+
static getDerivedStateFromError(error) {
|
|
18
|
+
return { error };
|
|
19
|
+
}
|
|
20
|
+
render() {
|
|
21
|
+
if (this.state.error) {
|
|
22
|
+
if (this.props.fallback) return this.props.fallback(this.state.error);
|
|
23
|
+
const pluginError = new (0, _chunkETCJDJTIcjs.PluginError)(this.props.pluginName, `\u6E32\u67D3\u5D29\u6E83: ${this.state.error.message}`);
|
|
24
|
+
return /* @__PURE__ */ _react2.default.createElement(DefaultErrorUI, { pluginName: this.props.pluginName, error: pluginError, retry: () => this.setState({ error: null }) });
|
|
25
|
+
}
|
|
26
|
+
return this.props.children;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
function toPluginError(pluginName, err) {
|
|
30
|
+
if (err instanceof _chunkETCJDJTIcjs.PluginError) return err;
|
|
31
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
32
|
+
return new (0, _chunkETCJDJTIcjs.PluginError)(pluginName, message);
|
|
33
|
+
}
|
|
34
|
+
function DefaultErrorUI({ pluginName, error, retry }) {
|
|
35
|
+
return /* @__PURE__ */ _react2.default.createElement(
|
|
36
|
+
"div",
|
|
37
|
+
{
|
|
38
|
+
style: {
|
|
39
|
+
padding: "12px 16px",
|
|
40
|
+
border: "1px solid #ff4d4f",
|
|
41
|
+
borderRadius: 6,
|
|
42
|
+
color: "#ff4d4f",
|
|
43
|
+
background: "#fff2f0"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
/* @__PURE__ */ _react2.default.createElement("strong", { style: { fontSize: 14 } }, "\u63D2\u4EF6 [", pluginName, "] \u52A0\u8F7D\u5931\u8D25"),
|
|
47
|
+
/* @__PURE__ */ _react2.default.createElement("p", { style: { margin: "4px 0 8px", fontSize: 12, opacity: 0.85 } }, error.message),
|
|
48
|
+
/* @__PURE__ */ _react2.default.createElement(
|
|
49
|
+
"button",
|
|
50
|
+
{
|
|
51
|
+
onClick: retry,
|
|
52
|
+
style: {
|
|
53
|
+
background: "none",
|
|
54
|
+
border: "1px solid currentColor",
|
|
55
|
+
borderRadius: 4,
|
|
56
|
+
color: "inherit",
|
|
57
|
+
padding: "2px 8px",
|
|
58
|
+
cursor: "pointer",
|
|
59
|
+
fontSize: 12
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"\u91CD\u8BD5"
|
|
63
|
+
)
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
function RemotePluginLoader({
|
|
67
|
+
pluginName,
|
|
68
|
+
url,
|
|
69
|
+
styleUrls,
|
|
70
|
+
themeConfig,
|
|
71
|
+
fallback,
|
|
72
|
+
renderError,
|
|
73
|
+
restProps
|
|
74
|
+
}) {
|
|
75
|
+
const kernel = _react.useContext.call(void 0, KernelContext);
|
|
76
|
+
const [Component, setComponent] = _react.useState.call(void 0, null);
|
|
77
|
+
const [error, setError] = _react.useState.call(void 0, null);
|
|
78
|
+
const [retryCount, setRetryCount] = _react.useState.call(void 0, 0);
|
|
79
|
+
const styleUrlsKey = _nullishCoalesce(_optionalChain([styleUrls, 'optionalAccess', _ => _.join, 'call', _2 => _2(",")]), () => ( ""));
|
|
80
|
+
_react.useEffect.call(void 0, () => {
|
|
81
|
+
let alive = true;
|
|
82
|
+
const loadFn = kernel ? kernel.loadPlugin.bind(kernel) : _chunkETCJDJTIcjs.loadRemotePlugin;
|
|
83
|
+
loadFn(pluginName, { url, styleUrls: styleUrlsKey ? styleUrlsKey.split(",") : [] }).then((exports) => {
|
|
84
|
+
if (!alive) return;
|
|
85
|
+
const Comp = _nullishCoalesce(_optionalChain([exports, 'optionalAccess', _3 => _3.default]), () => ( exports));
|
|
86
|
+
setComponent(() => Comp);
|
|
87
|
+
setError(null);
|
|
88
|
+
}).catch((err) => {
|
|
89
|
+
if (alive) setError(toPluginError(pluginName, err));
|
|
90
|
+
});
|
|
91
|
+
return () => {
|
|
92
|
+
alive = false;
|
|
93
|
+
};
|
|
94
|
+
}, [pluginName, url, styleUrlsKey, retryCount, kernel]);
|
|
95
|
+
const handleRetry = () => {
|
|
96
|
+
setError(null);
|
|
97
|
+
setRetryCount((c) => c + 1);
|
|
98
|
+
};
|
|
99
|
+
if (error) return renderError ? renderError(error, handleRetry) : /* @__PURE__ */ _react2.default.createElement(DefaultErrorUI, { pluginName, error, retry: handleRetry });
|
|
100
|
+
if (!Component) return /* @__PURE__ */ _react2.default.createElement(_react2.default.Fragment, null, fallback);
|
|
101
|
+
return /* @__PURE__ */ _react2.default.createElement(
|
|
102
|
+
PluginErrorBoundary,
|
|
103
|
+
{
|
|
104
|
+
pluginName,
|
|
105
|
+
fallback: (err) => renderError ? renderError(toPluginError(pluginName, err), handleRetry) : void 0
|
|
106
|
+
},
|
|
107
|
+
/* @__PURE__ */ _react2.default.createElement(Component, { themeConfig, ...restProps })
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
function PluginSlot(props) {
|
|
111
|
+
const {
|
|
112
|
+
pluginName,
|
|
113
|
+
url,
|
|
114
|
+
styleUrls,
|
|
115
|
+
localComponent: LocalComponent,
|
|
116
|
+
themeConfig,
|
|
117
|
+
fallback = /* @__PURE__ */ _react2.default.createElement("span", { style: { color: "#bbb", fontSize: 12 } }, "\u63D2\u4EF6\u52A0\u8F7D\u4E2D..."),
|
|
118
|
+
renderError,
|
|
119
|
+
...restProps
|
|
120
|
+
} = props;
|
|
121
|
+
if (LocalComponent) {
|
|
122
|
+
return /* @__PURE__ */ _react2.default.createElement(_react.Suspense, { fallback }, /* @__PURE__ */ _react2.default.createElement(LocalComponent, { themeConfig, ...restProps }));
|
|
123
|
+
}
|
|
124
|
+
if (!url) {
|
|
125
|
+
const err = new (0, _chunkETCJDJTIcjs.PluginError)(pluginName, `\u63D2\u4EF6 [${pluginName}] \u5728\u751F\u4EA7\u73AF\u5883\u4E0B\u5FC5\u987B\u63D0\u4F9B url \u53C2\u6570`);
|
|
126
|
+
return renderError ? /* @__PURE__ */ _react2.default.createElement(_react2.default.Fragment, null, renderError(err, () => {
|
|
127
|
+
})) : /* @__PURE__ */ _react2.default.createElement(DefaultErrorUI, { pluginName, error: err, retry: () => {
|
|
128
|
+
} });
|
|
129
|
+
}
|
|
130
|
+
return /* @__PURE__ */ _react2.default.createElement(
|
|
131
|
+
RemotePluginLoader,
|
|
132
|
+
{
|
|
133
|
+
pluginName,
|
|
134
|
+
url,
|
|
135
|
+
styleUrls,
|
|
136
|
+
themeConfig,
|
|
137
|
+
fallback,
|
|
138
|
+
renderError,
|
|
139
|
+
restProps
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
exports.KernelContext = KernelContext; exports.KernelProvider = KernelProvider; exports.PluginSlot = PluginSlot;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { e as PluginError, a as KernelInstance } from '../types-JlxTjSfC.cjs';
|
|
3
|
+
|
|
4
|
+
interface PluginSlotProps<Theme = unknown> {
|
|
5
|
+
/** 插件唯一标识符(需与 rollup amd.id 一致) */
|
|
6
|
+
pluginName: string;
|
|
7
|
+
/** 远端插件 JS 地址(生产环境使用) */
|
|
8
|
+
url?: string;
|
|
9
|
+
/** 配套的远端 CSS 地址列表(生产环境使用) */
|
|
10
|
+
styleUrls?: string[];
|
|
11
|
+
/** 本地开发组件(由 dev-plugins alias 注入,完整保留 HMR) */
|
|
12
|
+
localComponent?: any;
|
|
13
|
+
/** 主题配置,透传给插件的 ConfigProvider(泛型,不强绑定 Antd) */
|
|
14
|
+
themeConfig?: Theme;
|
|
15
|
+
/** 加载中占位节点,默认为行内文字提示 */
|
|
16
|
+
fallback?: any;
|
|
17
|
+
/** 自定义错误渲染,接收分级 PluginError 和重试函数 */
|
|
18
|
+
renderError?: (err: PluginError, retry: () => void) => any;
|
|
19
|
+
/** 其余业务透传参数 */
|
|
20
|
+
[key: string]: any;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
declare const KernelContext: React.Context<KernelInstance | null>;
|
|
24
|
+
/**
|
|
25
|
+
* 内核提供者组件,用于将内核实例注入到组件树中,供子组件使用
|
|
26
|
+
* @param kernel 内核实例
|
|
27
|
+
* @param children 子元素
|
|
28
|
+
* @returns ReactNode
|
|
29
|
+
*/
|
|
30
|
+
declare function KernelProvider({ kernel, children }: {
|
|
31
|
+
kernel: KernelInstance;
|
|
32
|
+
children: React.ReactNode;
|
|
33
|
+
}): React.JSX.Element;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 插件插槽
|
|
37
|
+
* @param props 插件插槽参数
|
|
38
|
+
* @returns 插件组件
|
|
39
|
+
*/
|
|
40
|
+
declare function PluginSlot(props: PluginSlotProps): React.JSX.Element;
|
|
41
|
+
|
|
42
|
+
export { KernelContext, KernelProvider, PluginSlot, type PluginSlotProps };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { e as PluginError, a as KernelInstance } from '../types-JlxTjSfC.js';
|
|
3
|
+
|
|
4
|
+
interface PluginSlotProps<Theme = unknown> {
|
|
5
|
+
/** 插件唯一标识符(需与 rollup amd.id 一致) */
|
|
6
|
+
pluginName: string;
|
|
7
|
+
/** 远端插件 JS 地址(生产环境使用) */
|
|
8
|
+
url?: string;
|
|
9
|
+
/** 配套的远端 CSS 地址列表(生产环境使用) */
|
|
10
|
+
styleUrls?: string[];
|
|
11
|
+
/** 本地开发组件(由 dev-plugins alias 注入,完整保留 HMR) */
|
|
12
|
+
localComponent?: any;
|
|
13
|
+
/** 主题配置,透传给插件的 ConfigProvider(泛型,不强绑定 Antd) */
|
|
14
|
+
themeConfig?: Theme;
|
|
15
|
+
/** 加载中占位节点,默认为行内文字提示 */
|
|
16
|
+
fallback?: any;
|
|
17
|
+
/** 自定义错误渲染,接收分级 PluginError 和重试函数 */
|
|
18
|
+
renderError?: (err: PluginError, retry: () => void) => any;
|
|
19
|
+
/** 其余业务透传参数 */
|
|
20
|
+
[key: string]: any;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
declare const KernelContext: React.Context<KernelInstance | null>;
|
|
24
|
+
/**
|
|
25
|
+
* 内核提供者组件,用于将内核实例注入到组件树中,供子组件使用
|
|
26
|
+
* @param kernel 内核实例
|
|
27
|
+
* @param children 子元素
|
|
28
|
+
* @returns ReactNode
|
|
29
|
+
*/
|
|
30
|
+
declare function KernelProvider({ kernel, children }: {
|
|
31
|
+
kernel: KernelInstance;
|
|
32
|
+
children: React.ReactNode;
|
|
33
|
+
}): React.JSX.Element;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 插件插槽
|
|
37
|
+
* @param props 插件插槽参数
|
|
38
|
+
* @returns 插件组件
|
|
39
|
+
*/
|
|
40
|
+
declare function PluginSlot(props: PluginSlotProps): React.JSX.Element;
|
|
41
|
+
|
|
42
|
+
export { KernelContext, KernelProvider, PluginSlot, type PluginSlotProps };
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PluginError,
|
|
3
|
+
loadRemotePlugin
|
|
4
|
+
} from "../chunk-D4E5XKWD.js";
|
|
5
|
+
|
|
6
|
+
// src/react/PluginSlot.tsx
|
|
7
|
+
import React, { Suspense, useEffect, useState, useContext } from "react";
|
|
8
|
+
var KernelContext = React.createContext(null);
|
|
9
|
+
function KernelProvider({ kernel, children }) {
|
|
10
|
+
return /* @__PURE__ */ React.createElement(KernelContext.Provider, { value: kernel }, children);
|
|
11
|
+
}
|
|
12
|
+
var PluginErrorBoundary = class extends React.Component {
|
|
13
|
+
constructor(props) {
|
|
14
|
+
super(props);
|
|
15
|
+
this.state = { error: null };
|
|
16
|
+
}
|
|
17
|
+
static getDerivedStateFromError(error) {
|
|
18
|
+
return { error };
|
|
19
|
+
}
|
|
20
|
+
render() {
|
|
21
|
+
if (this.state.error) {
|
|
22
|
+
if (this.props.fallback) return this.props.fallback(this.state.error);
|
|
23
|
+
const pluginError = new PluginError(this.props.pluginName, `\u6E32\u67D3\u5D29\u6E83: ${this.state.error.message}`);
|
|
24
|
+
return /* @__PURE__ */ React.createElement(DefaultErrorUI, { pluginName: this.props.pluginName, error: pluginError, retry: () => this.setState({ error: null }) });
|
|
25
|
+
}
|
|
26
|
+
return this.props.children;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
function toPluginError(pluginName, err) {
|
|
30
|
+
if (err instanceof PluginError) return err;
|
|
31
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
32
|
+
return new PluginError(pluginName, message);
|
|
33
|
+
}
|
|
34
|
+
function DefaultErrorUI({ pluginName, error, retry }) {
|
|
35
|
+
return /* @__PURE__ */ React.createElement(
|
|
36
|
+
"div",
|
|
37
|
+
{
|
|
38
|
+
style: {
|
|
39
|
+
padding: "12px 16px",
|
|
40
|
+
border: "1px solid #ff4d4f",
|
|
41
|
+
borderRadius: 6,
|
|
42
|
+
color: "#ff4d4f",
|
|
43
|
+
background: "#fff2f0"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
/* @__PURE__ */ React.createElement("strong", { style: { fontSize: 14 } }, "\u63D2\u4EF6 [", pluginName, "] \u52A0\u8F7D\u5931\u8D25"),
|
|
47
|
+
/* @__PURE__ */ React.createElement("p", { style: { margin: "4px 0 8px", fontSize: 12, opacity: 0.85 } }, error.message),
|
|
48
|
+
/* @__PURE__ */ React.createElement(
|
|
49
|
+
"button",
|
|
50
|
+
{
|
|
51
|
+
onClick: retry,
|
|
52
|
+
style: {
|
|
53
|
+
background: "none",
|
|
54
|
+
border: "1px solid currentColor",
|
|
55
|
+
borderRadius: 4,
|
|
56
|
+
color: "inherit",
|
|
57
|
+
padding: "2px 8px",
|
|
58
|
+
cursor: "pointer",
|
|
59
|
+
fontSize: 12
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"\u91CD\u8BD5"
|
|
63
|
+
)
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
function RemotePluginLoader({
|
|
67
|
+
pluginName,
|
|
68
|
+
url,
|
|
69
|
+
styleUrls,
|
|
70
|
+
themeConfig,
|
|
71
|
+
fallback,
|
|
72
|
+
renderError,
|
|
73
|
+
restProps
|
|
74
|
+
}) {
|
|
75
|
+
const kernel = useContext(KernelContext);
|
|
76
|
+
const [Component, setComponent] = useState(null);
|
|
77
|
+
const [error, setError] = useState(null);
|
|
78
|
+
const [retryCount, setRetryCount] = useState(0);
|
|
79
|
+
const styleUrlsKey = styleUrls?.join(",") ?? "";
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
let alive = true;
|
|
82
|
+
const loadFn = kernel ? kernel.loadPlugin.bind(kernel) : loadRemotePlugin;
|
|
83
|
+
loadFn(pluginName, { url, styleUrls: styleUrlsKey ? styleUrlsKey.split(",") : [] }).then((exports) => {
|
|
84
|
+
if (!alive) return;
|
|
85
|
+
const Comp = exports?.default ?? exports;
|
|
86
|
+
setComponent(() => Comp);
|
|
87
|
+
setError(null);
|
|
88
|
+
}).catch((err) => {
|
|
89
|
+
if (alive) setError(toPluginError(pluginName, err));
|
|
90
|
+
});
|
|
91
|
+
return () => {
|
|
92
|
+
alive = false;
|
|
93
|
+
};
|
|
94
|
+
}, [pluginName, url, styleUrlsKey, retryCount, kernel]);
|
|
95
|
+
const handleRetry = () => {
|
|
96
|
+
setError(null);
|
|
97
|
+
setRetryCount((c) => c + 1);
|
|
98
|
+
};
|
|
99
|
+
if (error) return renderError ? renderError(error, handleRetry) : /* @__PURE__ */ React.createElement(DefaultErrorUI, { pluginName, error, retry: handleRetry });
|
|
100
|
+
if (!Component) return /* @__PURE__ */ React.createElement(React.Fragment, null, fallback);
|
|
101
|
+
return /* @__PURE__ */ React.createElement(
|
|
102
|
+
PluginErrorBoundary,
|
|
103
|
+
{
|
|
104
|
+
pluginName,
|
|
105
|
+
fallback: (err) => renderError ? renderError(toPluginError(pluginName, err), handleRetry) : void 0
|
|
106
|
+
},
|
|
107
|
+
/* @__PURE__ */ React.createElement(Component, { themeConfig, ...restProps })
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
function PluginSlot(props) {
|
|
111
|
+
const {
|
|
112
|
+
pluginName,
|
|
113
|
+
url,
|
|
114
|
+
styleUrls,
|
|
115
|
+
localComponent: LocalComponent,
|
|
116
|
+
themeConfig,
|
|
117
|
+
fallback = /* @__PURE__ */ React.createElement("span", { style: { color: "#bbb", fontSize: 12 } }, "\u63D2\u4EF6\u52A0\u8F7D\u4E2D..."),
|
|
118
|
+
renderError,
|
|
119
|
+
...restProps
|
|
120
|
+
} = props;
|
|
121
|
+
if (LocalComponent) {
|
|
122
|
+
return /* @__PURE__ */ React.createElement(Suspense, { fallback }, /* @__PURE__ */ React.createElement(LocalComponent, { themeConfig, ...restProps }));
|
|
123
|
+
}
|
|
124
|
+
if (!url) {
|
|
125
|
+
const err = new PluginError(pluginName, `\u63D2\u4EF6 [${pluginName}] \u5728\u751F\u4EA7\u73AF\u5883\u4E0B\u5FC5\u987B\u63D0\u4F9B url \u53C2\u6570`);
|
|
126
|
+
return renderError ? /* @__PURE__ */ React.createElement(React.Fragment, null, renderError(err, () => {
|
|
127
|
+
})) : /* @__PURE__ */ React.createElement(DefaultErrorUI, { pluginName, error: err, retry: () => {
|
|
128
|
+
} });
|
|
129
|
+
}
|
|
130
|
+
return /* @__PURE__ */ React.createElement(
|
|
131
|
+
RemotePluginLoader,
|
|
132
|
+
{
|
|
133
|
+
pluginName,
|
|
134
|
+
url,
|
|
135
|
+
styleUrls,
|
|
136
|
+
themeConfig,
|
|
137
|
+
fallback,
|
|
138
|
+
renderError,
|
|
139
|
+
restProps
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
export {
|
|
144
|
+
KernelContext,
|
|
145
|
+
KernelProvider,
|
|
146
|
+
PluginSlot
|
|
147
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 日志接口
|
|
3
|
+
*/
|
|
4
|
+
interface KernelLogger {
|
|
5
|
+
warn: (msg: string) => void;
|
|
6
|
+
error: (msg: string) => void;
|
|
7
|
+
}
|
|
8
|
+
interface KernelOptions {
|
|
9
|
+
/** 插件加载超时时间(ms),默认 10000 */
|
|
10
|
+
timeout?: number;
|
|
11
|
+
/** 网络失败自动重试次数,默认 2 */
|
|
12
|
+
retryCount?: number;
|
|
13
|
+
/** script 标签的 CSP nonce 值 */
|
|
14
|
+
nonce?: string;
|
|
15
|
+
/** false 时静默所有内部 warn/log,默认 true */
|
|
16
|
+
debug?: boolean;
|
|
17
|
+
/** 全局拦截器的命名空间前缀,默认 '__KERNEL__' */
|
|
18
|
+
namespace: string;
|
|
19
|
+
/** 自定义 logger,默认使用 console */
|
|
20
|
+
logger?: KernelLogger;
|
|
21
|
+
/** 插件开始加载时的钩子 */
|
|
22
|
+
onLoadStart?: (pluginName: string) => void;
|
|
23
|
+
/** 插件加载成功后的钩子 */
|
|
24
|
+
onLoadSuccess?: (pluginName: string) => void;
|
|
25
|
+
/** 插件加载失败后的全局错误钩子 */
|
|
26
|
+
onLoadError?: (pluginName: string, error: PluginError) => void;
|
|
27
|
+
}
|
|
28
|
+
interface ModuleEntry {
|
|
29
|
+
/** 已解析的模块实例(加载完成后赋值) */
|
|
30
|
+
module: any;
|
|
31
|
+
/** 模块加载的 Promise,挂起直到 definePlugin 回调完成 */
|
|
32
|
+
_promise: Promise<any>;
|
|
33
|
+
/** 外部控制的 resolve 方法(Deferred 模式) */
|
|
34
|
+
_resolve?: (value: any) => void;
|
|
35
|
+
/** 外部控制的 reject 方法(Deferred 模式) */
|
|
36
|
+
_reject?: (reason?: any) => void;
|
|
37
|
+
/** 同步标记:脚本解析完成前是否合法调用了 define */
|
|
38
|
+
_defineCalled?: boolean;
|
|
39
|
+
/** 当前条目的状态 */
|
|
40
|
+
status: 'pending' | 'resolved' | 'rejected';
|
|
41
|
+
/** 加载时使用的 url(用于缓存失效判断) */
|
|
42
|
+
url?: string;
|
|
43
|
+
}
|
|
44
|
+
interface PluginLoadOptions {
|
|
45
|
+
/** 插件主 JS 入口地址 */
|
|
46
|
+
url: string;
|
|
47
|
+
/** 可选的配套 CSS 样式地址列表 */
|
|
48
|
+
styleUrls?: string[];
|
|
49
|
+
}
|
|
50
|
+
interface KernelInstance {
|
|
51
|
+
/**
|
|
52
|
+
* 注册主应用的共享依赖(如 react、antd)
|
|
53
|
+
* 已注册过的模块默认不允许重复覆盖,传入 { force: true } 可强制覆盖
|
|
54
|
+
*/
|
|
55
|
+
regSharedModule(name: string, instance: any, options?: {
|
|
56
|
+
force?: boolean;
|
|
57
|
+
}): void;
|
|
58
|
+
/**
|
|
59
|
+
* 加载远端插件,返回其导出模块
|
|
60
|
+
* 内置:并发去重、URL 变更缓存失效、超时控制、指数退避重试、分级错误、生命周期钩子
|
|
61
|
+
*/
|
|
62
|
+
loadPlugin<T = any>(pluginName: string, options: PluginLoadOptions): Promise<T>;
|
|
63
|
+
/**
|
|
64
|
+
* 卸载插件,清除 registry 中的缓存
|
|
65
|
+
* 下次调用 loadPlugin 时会重新加载
|
|
66
|
+
*/
|
|
67
|
+
unloadPlugin(pluginName: string): void;
|
|
68
|
+
/**
|
|
69
|
+
* 预加载远端插件资源到浏览器缓存(不执行)
|
|
70
|
+
* @param options 插件地址或配置
|
|
71
|
+
*/
|
|
72
|
+
preloadPlugin(options: PluginLoadOptions): void;
|
|
73
|
+
/**
|
|
74
|
+
* 销毁内核实例,清空所有状态(用于测试隔离或多租户场景)
|
|
75
|
+
*/
|
|
76
|
+
destroy(): void;
|
|
77
|
+
/** 判断内核是否已完成初始化 */
|
|
78
|
+
isInitialized(): boolean;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 错误基类
|
|
82
|
+
*/
|
|
83
|
+
declare class PluginError extends Error {
|
|
84
|
+
readonly pluginName: string;
|
|
85
|
+
cause?: unknown;
|
|
86
|
+
constructor(pluginName: string, message: string);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 网络层错误:script 标签加载失败
|
|
90
|
+
*/
|
|
91
|
+
declare class PluginNetworkError extends PluginError {
|
|
92
|
+
constructor(pluginName: string, url: string, cause?: unknown);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 加载超时错误
|
|
96
|
+
*/
|
|
97
|
+
declare class PluginTimeoutError extends PluginError {
|
|
98
|
+
constructor(pluginName: string, timeout: number);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 依赖注入错误:插件声明的依赖在共享池中不存在
|
|
102
|
+
*/
|
|
103
|
+
declare class PluginDependencyError extends PluginError {
|
|
104
|
+
readonly dependency: string;
|
|
105
|
+
constructor(pluginName: string, dependency: string);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 执行错误:插件 factory 函数内部抛出异常
|
|
109
|
+
*/
|
|
110
|
+
declare class PluginExecutionError extends PluginError {
|
|
111
|
+
constructor(pluginName: string, cause?: unknown);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 引擎未初始化错误
|
|
115
|
+
*/
|
|
116
|
+
declare class KernelNotInitializedError extends Error {
|
|
117
|
+
constructor();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export { type KernelOptions as K, type ModuleEntry as M, type PluginLoadOptions as P, type KernelInstance as a, type KernelLogger as b, KernelNotInitializedError as c, PluginDependencyError as d, PluginError as e, PluginExecutionError as f, PluginNetworkError as g, PluginTimeoutError as h };
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 日志接口
|
|
3
|
+
*/
|
|
4
|
+
interface KernelLogger {
|
|
5
|
+
warn: (msg: string) => void;
|
|
6
|
+
error: (msg: string) => void;
|
|
7
|
+
}
|
|
8
|
+
interface KernelOptions {
|
|
9
|
+
/** 插件加载超时时间(ms),默认 10000 */
|
|
10
|
+
timeout?: number;
|
|
11
|
+
/** 网络失败自动重试次数,默认 2 */
|
|
12
|
+
retryCount?: number;
|
|
13
|
+
/** script 标签的 CSP nonce 值 */
|
|
14
|
+
nonce?: string;
|
|
15
|
+
/** false 时静默所有内部 warn/log,默认 true */
|
|
16
|
+
debug?: boolean;
|
|
17
|
+
/** 全局拦截器的命名空间前缀,默认 '__KERNEL__' */
|
|
18
|
+
namespace: string;
|
|
19
|
+
/** 自定义 logger,默认使用 console */
|
|
20
|
+
logger?: KernelLogger;
|
|
21
|
+
/** 插件开始加载时的钩子 */
|
|
22
|
+
onLoadStart?: (pluginName: string) => void;
|
|
23
|
+
/** 插件加载成功后的钩子 */
|
|
24
|
+
onLoadSuccess?: (pluginName: string) => void;
|
|
25
|
+
/** 插件加载失败后的全局错误钩子 */
|
|
26
|
+
onLoadError?: (pluginName: string, error: PluginError) => void;
|
|
27
|
+
}
|
|
28
|
+
interface ModuleEntry {
|
|
29
|
+
/** 已解析的模块实例(加载完成后赋值) */
|
|
30
|
+
module: any;
|
|
31
|
+
/** 模块加载的 Promise,挂起直到 definePlugin 回调完成 */
|
|
32
|
+
_promise: Promise<any>;
|
|
33
|
+
/** 外部控制的 resolve 方法(Deferred 模式) */
|
|
34
|
+
_resolve?: (value: any) => void;
|
|
35
|
+
/** 外部控制的 reject 方法(Deferred 模式) */
|
|
36
|
+
_reject?: (reason?: any) => void;
|
|
37
|
+
/** 同步标记:脚本解析完成前是否合法调用了 define */
|
|
38
|
+
_defineCalled?: boolean;
|
|
39
|
+
/** 当前条目的状态 */
|
|
40
|
+
status: 'pending' | 'resolved' | 'rejected';
|
|
41
|
+
/** 加载时使用的 url(用于缓存失效判断) */
|
|
42
|
+
url?: string;
|
|
43
|
+
}
|
|
44
|
+
interface PluginLoadOptions {
|
|
45
|
+
/** 插件主 JS 入口地址 */
|
|
46
|
+
url: string;
|
|
47
|
+
/** 可选的配套 CSS 样式地址列表 */
|
|
48
|
+
styleUrls?: string[];
|
|
49
|
+
}
|
|
50
|
+
interface KernelInstance {
|
|
51
|
+
/**
|
|
52
|
+
* 注册主应用的共享依赖(如 react、antd)
|
|
53
|
+
* 已注册过的模块默认不允许重复覆盖,传入 { force: true } 可强制覆盖
|
|
54
|
+
*/
|
|
55
|
+
regSharedModule(name: string, instance: any, options?: {
|
|
56
|
+
force?: boolean;
|
|
57
|
+
}): void;
|
|
58
|
+
/**
|
|
59
|
+
* 加载远端插件,返回其导出模块
|
|
60
|
+
* 内置:并发去重、URL 变更缓存失效、超时控制、指数退避重试、分级错误、生命周期钩子
|
|
61
|
+
*/
|
|
62
|
+
loadPlugin<T = any>(pluginName: string, options: PluginLoadOptions): Promise<T>;
|
|
63
|
+
/**
|
|
64
|
+
* 卸载插件,清除 registry 中的缓存
|
|
65
|
+
* 下次调用 loadPlugin 时会重新加载
|
|
66
|
+
*/
|
|
67
|
+
unloadPlugin(pluginName: string): void;
|
|
68
|
+
/**
|
|
69
|
+
* 预加载远端插件资源到浏览器缓存(不执行)
|
|
70
|
+
* @param options 插件地址或配置
|
|
71
|
+
*/
|
|
72
|
+
preloadPlugin(options: PluginLoadOptions): void;
|
|
73
|
+
/**
|
|
74
|
+
* 销毁内核实例,清空所有状态(用于测试隔离或多租户场景)
|
|
75
|
+
*/
|
|
76
|
+
destroy(): void;
|
|
77
|
+
/** 判断内核是否已完成初始化 */
|
|
78
|
+
isInitialized(): boolean;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 错误基类
|
|
82
|
+
*/
|
|
83
|
+
declare class PluginError extends Error {
|
|
84
|
+
readonly pluginName: string;
|
|
85
|
+
cause?: unknown;
|
|
86
|
+
constructor(pluginName: string, message: string);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 网络层错误:script 标签加载失败
|
|
90
|
+
*/
|
|
91
|
+
declare class PluginNetworkError extends PluginError {
|
|
92
|
+
constructor(pluginName: string, url: string, cause?: unknown);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 加载超时错误
|
|
96
|
+
*/
|
|
97
|
+
declare class PluginTimeoutError extends PluginError {
|
|
98
|
+
constructor(pluginName: string, timeout: number);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* 依赖注入错误:插件声明的依赖在共享池中不存在
|
|
102
|
+
*/
|
|
103
|
+
declare class PluginDependencyError extends PluginError {
|
|
104
|
+
readonly dependency: string;
|
|
105
|
+
constructor(pluginName: string, dependency: string);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 执行错误:插件 factory 函数内部抛出异常
|
|
109
|
+
*/
|
|
110
|
+
declare class PluginExecutionError extends PluginError {
|
|
111
|
+
constructor(pluginName: string, cause?: unknown);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 引擎未初始化错误
|
|
115
|
+
*/
|
|
116
|
+
declare class KernelNotInitializedError extends Error {
|
|
117
|
+
constructor();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export { type KernelOptions as K, type ModuleEntry as M, type PluginLoadOptions as P, type KernelInstance as a, type KernelLogger as b, KernelNotInitializedError as c, PluginDependencyError as d, PluginError as e, PluginExecutionError as f, PluginNetworkError as g, PluginTimeoutError as h };
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zero-bits/kernel",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A framework-agnostic kernel for plugin loading and dependency injection.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/core/index.d.ts",
|
|
9
|
+
"import": "./dist/core/index.js",
|
|
10
|
+
"require": "./dist/core/index.cjs"
|
|
11
|
+
},
|
|
12
|
+
"./react": {
|
|
13
|
+
"types": "./dist/react/index.d.ts",
|
|
14
|
+
"import": "./dist/react/index.js",
|
|
15
|
+
"require": "./dist/react/index.cjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public",
|
|
23
|
+
"registry": "https://registry.npmjs.org/"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsup",
|
|
27
|
+
"dev": "tsup --watch"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"react": ">=16.8.0",
|
|
31
|
+
"react-dom": ">=16.8.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/react": "^18.0.0",
|
|
35
|
+
"tsup": "^8.0.0",
|
|
36
|
+
"typescript": "^5.0.0"
|
|
37
|
+
}
|
|
38
|
+
}
|