@blocklet/pages-kit 0.4.16-beta.20250305-2 → 0.4.16-beta.20250309-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/lib/cjs/components/CustomComponentRenderer/ErrorComponent.js +40 -0
- package/lib/cjs/components/CustomComponentRenderer/index.js +3 -14
- package/lib/cjs/components/CustomComponentRenderer/state.js +117 -9
- package/lib/cjs/tsconfig.tsbuildinfo +1 -1
- package/lib/cjs/utils/inject-es-module-shims-options.js +16 -6
- package/lib/cjs/utils/inject-global-components.js +101 -53
- package/lib/cjs/utils/typescript/builtin-module-transformer.js +9 -9
- package/lib/esm/components/CustomComponentRenderer/ErrorComponent.js +36 -0
- package/lib/esm/components/CustomComponentRenderer/index.js +4 -15
- package/lib/esm/components/CustomComponentRenderer/state.js +118 -10
- package/lib/esm/tsconfig.tsbuildinfo +1 -1
- package/lib/esm/utils/inject-es-module-shims-options.js +14 -7
- package/lib/esm/utils/inject-global-components.js +101 -53
- package/lib/esm/utils/typescript/builtin-module-transformer.js +7 -8
- package/lib/types/components/CustomComponentRenderer/ErrorComponent.d.ts +14 -0
- package/lib/types/tsconfig.tsbuildinfo +1 -1
- package/lib/types/types/preload.d.ts +1 -1
- package/lib/types/utils/inject-es-module-shims-options.d.ts +1 -0
- package/lib/types/utils/typescript/builtin-module-transformer.d.ts +1 -0
- package/package.json +4 -4
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.injectESModulesShimsOptions = injectESModulesShimsOptions;
|
|
4
|
+
function injectESModulesShimsOptions() {
|
|
5
|
+
// if already initialized, return
|
|
6
|
+
if (window.esmsInitOptions) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
window.esmsInitOptions = {
|
|
10
|
+
shimMode: true,
|
|
11
|
+
polyfillEnable: ['css-modules', 'json-modules', 'wasm-modules', 'source-phase'],
|
|
12
|
+
skip: ['crypto-browserify', 'crypto'],
|
|
13
|
+
mapOverrides: true,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
// enable es-module-shims
|
|
17
|
+
injectESModulesShimsOptions();
|
|
@@ -22,15 +22,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
27
|
};
|
|
@@ -40,7 +31,6 @@ require("es-module-shims");
|
|
|
40
31
|
const react_1 = __importDefault(require("react"));
|
|
41
32
|
const ufo_1 = require("ufo");
|
|
42
33
|
const arcblockUx = __importStar(require("../builtin/arcblock/ux"));
|
|
43
|
-
const aiRuntime = __importStar(require("../builtin/async/ai-runtime"));
|
|
44
34
|
const imagePreview = __importStar(require("../builtin/async/image-preview"));
|
|
45
35
|
const reactMarkdown = __importStar(require("../builtin/async/react-markdown"));
|
|
46
36
|
const reactScrollToBottom = __importStar(require("../builtin/async/react-scroll-to-bottom"));
|
|
@@ -65,14 +55,20 @@ const zustand = __importStar(require("../builtin/zustand"));
|
|
|
65
55
|
const zustandMiddlewareImmer = __importStar(require("../builtin/zustand/middleware/immer"));
|
|
66
56
|
const CustomComponentRenderer_1 = __importDefault(require("../components/CustomComponentRenderer"));
|
|
67
57
|
const builtin_1 = require("../types/builtin");
|
|
58
|
+
const builtin_module_transformer_1 = require("./typescript/builtin-module-transformer");
|
|
68
59
|
// Initialize ES Module Shims before any imports
|
|
69
60
|
function injectGlobalComponents() {
|
|
61
|
+
var _a;
|
|
70
62
|
const win = window || {};
|
|
71
|
-
|
|
63
|
+
// if already initialized, return
|
|
64
|
+
if (win[builtin_1.BuiltinModulesGlobalVariableName]) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const enableShim = !!((_a = window === null || window === void 0 ? void 0 : window.esmsInitOptions) === null || _a === void 0 ? void 0 : _a.shimMode);
|
|
72
68
|
win.React = react_1.default;
|
|
73
|
-
//
|
|
69
|
+
// create module map
|
|
74
70
|
const modules = {
|
|
75
|
-
react,
|
|
71
|
+
React: react,
|
|
76
72
|
'@blocklet/pages-kit/builtin/pages-kit': { CustomComponentRenderer: CustomComponentRenderer_1.default },
|
|
77
73
|
'@blocklet/pages-kit/builtin/dayjs': dayjs,
|
|
78
74
|
'@blocklet/pages-kit/builtin/utils': utils,
|
|
@@ -97,55 +93,107 @@ function injectGlobalComponents() {
|
|
|
97
93
|
'@blocklet/pages-kit/builtin/async/react-markdown': reactMarkdown,
|
|
98
94
|
'@blocklet/pages-kit/builtin/async/react-syntax-highlighter': reactSyntaxHighlighter,
|
|
99
95
|
'@blocklet/pages-kit/builtin/async/image-preview': imagePreview,
|
|
100
|
-
'@blocklet/pages-kit/builtin/async/ai-runtime':
|
|
96
|
+
'@blocklet/pages-kit/builtin/async/ai-runtime': {
|
|
97
|
+
get: () => Promise.resolve().then(() => __importStar(require('../builtin/async/ai-runtime'))).catch((err) => {
|
|
98
|
+
console.error('Failed to load AI runtime', err);
|
|
99
|
+
return {};
|
|
100
|
+
}),
|
|
101
|
+
},
|
|
101
102
|
};
|
|
102
|
-
//
|
|
103
|
+
// set global variable
|
|
103
104
|
win[builtin_1.BuiltinModulesGlobalVariableName] = {
|
|
104
105
|
modules,
|
|
105
106
|
require(module) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
107
|
+
var _a;
|
|
108
|
+
// handle builtin module
|
|
109
|
+
const builtinModule = this.modules[module];
|
|
110
|
+
if (builtinModule) {
|
|
111
|
+
return builtinModule;
|
|
112
|
+
}
|
|
113
|
+
// handle relative path import
|
|
114
|
+
if ((0, builtin_module_transformer_1.isRelativeModule)(module)) {
|
|
115
|
+
const fileName = module.split('/').pop();
|
|
116
|
+
const fullUrl = (0, ufo_1.joinURL)(window.location.origin, ((_a = window === null || window === void 0 ? void 0 : window.blocklet) === null || _a === void 0 ? void 0 : _a.prefix) || '/', 'chunks', fileName);
|
|
117
|
+
if (enableShim) {
|
|
118
|
+
const mod = window.importShim(fullUrl);
|
|
119
|
+
return mod;
|
|
112
120
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (importShim) {
|
|
118
|
-
return yield importShim(fullUrl);
|
|
119
|
-
}
|
|
120
|
-
return yield Promise.resolve(`${fullUrl}`).then(s => __importStar(require(s)));
|
|
121
|
-
}
|
|
122
|
-
return null;
|
|
123
|
-
});
|
|
121
|
+
const mod = Promise.resolve(`${fullUrl}`).then(s => __importStar(require(s)));
|
|
122
|
+
return mod;
|
|
123
|
+
}
|
|
124
|
+
return null;
|
|
124
125
|
},
|
|
125
126
|
};
|
|
126
|
-
//
|
|
127
|
+
// create importmap
|
|
127
128
|
const setupImportMap = () => {
|
|
128
|
-
//
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
// 添加 resolve 配置
|
|
144
|
-
const importMap = {
|
|
145
|
-
imports,
|
|
129
|
+
// 计算模块的 hash 值作为缓存版本
|
|
130
|
+
const calculateModulesHash = () => {
|
|
131
|
+
// 只提取模块路径和导出的键名用于 hash 计算
|
|
132
|
+
const moduleStructure = Object.entries(modules).map(([path, mod]) => ({
|
|
133
|
+
path,
|
|
134
|
+
exports: Object.keys(mod).sort(),
|
|
135
|
+
}));
|
|
136
|
+
const str = JSON.stringify(moduleStructure);
|
|
137
|
+
// 简单的 hash 计算方法
|
|
138
|
+
let hash = 0;
|
|
139
|
+
for (let i = 0; i < str.length; i++) {
|
|
140
|
+
const char = str.charCodeAt(i);
|
|
141
|
+
hash = hash * 2 ** 5 - hash + char;
|
|
142
|
+
}
|
|
143
|
+
return hash.toString(16);
|
|
146
144
|
};
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
const cacheKey = 'pages-kit-import-map';
|
|
146
|
+
const moduleHash = calculateModulesHash();
|
|
147
|
+
// 获取 imports - 优先从缓存读取
|
|
148
|
+
const getImportsFromCache = () => {
|
|
149
|
+
try {
|
|
150
|
+
const cachedData = localStorage.getItem(cacheKey);
|
|
151
|
+
if (cachedData) {
|
|
152
|
+
const { hash, imports } = JSON.parse(cachedData);
|
|
153
|
+
if (hash === moduleHash) {
|
|
154
|
+
// eslint-disable-next-line no-console
|
|
155
|
+
console.log(`getImportsFromCache: ${hash}`, imports);
|
|
156
|
+
return imports; // 返回缓存的 imports
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (e) {
|
|
161
|
+
console.warn('Failed to load import map from cache', e);
|
|
162
|
+
}
|
|
163
|
+
return null; // 缓存无效
|
|
164
|
+
};
|
|
165
|
+
// 尝试从缓存获取或重新计算
|
|
166
|
+
const imports = getImportsFromCache() ||
|
|
167
|
+
Object.entries(modules).reduce((acc, [modulePath, moduleContent]) => {
|
|
168
|
+
const namedExports = Object.keys(moduleContent).filter((key) => key !== 'default');
|
|
169
|
+
const hasDefaultExport = 'default' in moduleContent;
|
|
170
|
+
// create module code
|
|
171
|
+
const moduleCode = `// GENERATED FILE. DO NOT EDIT.
|
|
172
|
+
const moduleSource = window['${builtin_1.BuiltinModulesGlobalVariableName}'].modules['${modulePath}'];
|
|
173
|
+
${namedExports.map((name) => `export const ${name} = moduleSource['${name}'];`).join('\n')}
|
|
174
|
+
export default ${hasDefaultExport ? 'moduleSource.default' : 'moduleSource'};
|
|
175
|
+
`;
|
|
176
|
+
// create base64 code
|
|
177
|
+
const base64Code = btoa(moduleCode);
|
|
178
|
+
acc[modulePath] = `data:application/javascript;base64,${base64Code}`;
|
|
179
|
+
return acc;
|
|
180
|
+
}, {});
|
|
181
|
+
// 如果是新计算的 imports,保存到缓存
|
|
182
|
+
if (!getImportsFromCache()) {
|
|
183
|
+
try {
|
|
184
|
+
localStorage.setItem(cacheKey, JSON.stringify({
|
|
185
|
+
hash: moduleHash,
|
|
186
|
+
imports,
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
189
|
+
catch (e) {
|
|
190
|
+
console.warn('Failed to cache import map', e);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// 添加 resolve 配置
|
|
194
|
+
const importMap = { imports };
|
|
195
|
+
if (enableShim) {
|
|
196
|
+
window.importShim.addImportMap(importMap);
|
|
149
197
|
}
|
|
150
198
|
else {
|
|
151
199
|
// fallback to create script tag
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createBuiltinModuleTransformer = void 0;
|
|
3
|
+
exports.createBuiltinModuleTransformer = exports.isRelativeModule = void 0;
|
|
4
4
|
const builtin_1 = require("../../types/builtin");
|
|
5
|
+
const isRelativeModule = (moduleSpecifier) => {
|
|
6
|
+
return moduleSpecifier.startsWith('./') || moduleSpecifier.startsWith('../');
|
|
7
|
+
};
|
|
8
|
+
exports.isRelativeModule = isRelativeModule;
|
|
5
9
|
const createBuiltinModuleTransformer = (ts) => (context) => (file) => {
|
|
6
10
|
const { factory } = context;
|
|
7
11
|
// 统一的模块导入收集器
|
|
8
12
|
const imports = [];
|
|
9
13
|
// check if the module is a target module
|
|
10
14
|
const isTargetModule = (moduleSpecifier) => {
|
|
11
|
-
return
|
|
12
|
-
moduleSpecifier.startsWith('./') ||
|
|
13
|
-
moduleSpecifier.startsWith('../'));
|
|
15
|
+
return moduleSpecifier.startsWith('@blocklet/pages-kit/builtin/') || (0, exports.isRelativeModule)(moduleSpecifier);
|
|
14
16
|
};
|
|
15
17
|
// filter and collect the import statements that need to be processed
|
|
16
18
|
const statements = file.statements.filter((s) => {
|
|
@@ -46,11 +48,9 @@ const createBuiltinModuleTransformer = (ts) => (context) => (file) => {
|
|
|
46
48
|
});
|
|
47
49
|
statements.unshift(...imports.flatMap((importInfo) => {
|
|
48
50
|
// call inject-global-components require method
|
|
49
|
-
const requireCall = factory.createCallExpression(factory.createPropertyAccessExpression(factory.
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
// create await expression to wait for the async result
|
|
53
|
-
const mod = factory.createAwaitExpression(requireCall);
|
|
51
|
+
const requireCall = factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier(builtin_1.BuiltinModulesGlobalVariableName), 'require'), undefined, [factory.createStringLiteral(importInfo.moduleName)]);
|
|
52
|
+
// create await expression if the module is ../ or ./
|
|
53
|
+
const mod = (0, exports.isRelativeModule)(importInfo.moduleName) ? factory.createAwaitExpression(requireCall) : requireCall;
|
|
54
54
|
return [
|
|
55
55
|
importInfo.name
|
|
56
56
|
? factory.createVariableStatement([], factory.createVariableDeclarationList([
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
13
|
+
import { Box, Typography, Button } from '@mui/material';
|
|
14
|
+
export const ComponentError = (_a) => {
|
|
15
|
+
var { title = 'Component Failed to Load', message, componentId, componentName, blockletId, blockletTitle, showHints = false, error, resetErrorBoundary } = _a, rest = __rest(_a, ["title", "message", "componentId", "componentName", "blockletId", "blockletTitle", "showHints", "error", "resetErrorBoundary"]);
|
|
16
|
+
// 如果提供了error但没有message,使用error.message
|
|
17
|
+
const displayMessage = message || (error ? error.message : 'Unknown error');
|
|
18
|
+
console.warn(rest);
|
|
19
|
+
return (_jsxs(Box, { sx: {
|
|
20
|
+
p: 3,
|
|
21
|
+
border: '1px dashed #d32f2f',
|
|
22
|
+
borderRadius: 1,
|
|
23
|
+
bgcolor: 'rgba(211, 47, 47, 0.04)',
|
|
24
|
+
display: 'flex',
|
|
25
|
+
flexDirection: 'column',
|
|
26
|
+
gap: 1,
|
|
27
|
+
}, children: [_jsx(Typography, { variant: "subtitle1", sx: { color: '#d32f2f', fontWeight: 500 }, children: title }), _jsx(Typography, { variant: "body2", sx: { color: 'text.secondary' }, children: displayMessage }), error && error.stack && process.env.NODE_ENV !== 'production' && (_jsx(Box, { component: "pre", sx: {
|
|
28
|
+
mt: 2,
|
|
29
|
+
p: 1,
|
|
30
|
+
bgcolor: 'rgba(0,0,0,0.04)',
|
|
31
|
+
borderRadius: 1,
|
|
32
|
+
fontSize: '0.75rem',
|
|
33
|
+
overflow: 'auto',
|
|
34
|
+
maxHeight: '200px',
|
|
35
|
+
}, children: error.stack })), showHints && (_jsxs(_Fragment, { children: [_jsx(Typography, { variant: "body2", sx: { color: 'text.secondary' }, children: "Please try the following:" }), _jsxs(Box, { component: "ul", sx: { m: 0, pl: 2 }, children: [componentId && (_jsxs(Typography, { component: "li", variant: "body2", sx: { color: 'text.secondary' }, children: ["Select component", ' ', _jsx(Box, { component: "span", sx: { fontWeight: 500 }, children: componentName !== null && componentName !== void 0 ? componentName : componentId }), ' ', "in settings or create this component."] })), (blockletId || blockletTitle) && (_jsxs(Typography, { component: "li", variant: "body2", sx: { color: 'text.secondary' }, children: ["Contact administrator to install", ' ', _jsx(Box, { component: "span", sx: { fontWeight: 500 }, children: blockletTitle !== null && blockletTitle !== void 0 ? blockletTitle : blockletId }), ' ', "Blocklet"] }))] })] })), resetErrorBoundary && (_jsx(Box, { sx: { mt: 2 }, children: _jsx(Button, { variant: "outlined", color: "error", size: "small", onClick: resetErrorBoundary, children: "Try Again" }) }))] }));
|
|
36
|
+
};
|
|
@@ -9,12 +9,12 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9
9
|
}
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
|
-
import { jsx as _jsx
|
|
13
|
-
import { Alert, Box, Typography } from '@mui/material';
|
|
12
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
13
|
import { ErrorBoundary } from 'react-error-boundary';
|
|
15
14
|
import { RenderNestedComponent } from '../../utils/property';
|
|
16
15
|
import BlockletReactComponentRenderer from './BlockletReactComponentRenderer';
|
|
17
16
|
import { DevProvider, useDev } from './DevProvider';
|
|
17
|
+
import { ComponentError } from './ErrorComponent';
|
|
18
18
|
import { useCustomComponentRenderer } from './context';
|
|
19
19
|
import { useComponent } from './state';
|
|
20
20
|
export * from './state';
|
|
@@ -25,14 +25,11 @@ export default function CustomComponentRenderer(_a) {
|
|
|
25
25
|
var { dev } = _a, props = __rest(_a, ["dev"]);
|
|
26
26
|
const inheritedDev = useDev();
|
|
27
27
|
const BuiltinComponent = BuiltinComponents[props.componentId];
|
|
28
|
-
return (_jsx(ErrorBoundary, { FallbackComponent: (props === null || props === void 0 ? void 0 : props.fallbackRender) ||
|
|
28
|
+
return (_jsx(ErrorBoundary, { FallbackComponent: (props === null || props === void 0 ? void 0 : props.fallbackRender) || ComponentError, resetKeys: [Date.now()], children: _jsx(DevProvider, { dev: dev !== null && dev !== void 0 ? dev : inheritedDev, children: BuiltinComponent ? (_jsx(BuiltinComponent, Object.assign({}, props))) : (_jsx(ComponentRenderer, Object.assign({}, props, { instanceId: (_b = props.instanceId) !== null && _b !== void 0 ? _b : props.componentId, renderType: props.renderType }))) }) }));
|
|
29
29
|
}
|
|
30
30
|
const BuiltinComponents = {
|
|
31
31
|
'blocklet-react-component': BlockletReactComponentRenderer,
|
|
32
32
|
};
|
|
33
|
-
function ErrorView({ error }) {
|
|
34
|
-
return (_jsx(Box, { children: _jsx(Alert, { severity: "error", children: error.message }) }));
|
|
35
|
-
}
|
|
36
33
|
function ComponentRenderer(_a) {
|
|
37
34
|
var _b;
|
|
38
35
|
var { renderCount = 0, blockletId, blockletTitle, componentName, renderType = 'view' } = _a, props = __rest(_a, ["renderCount", "blockletId", "blockletTitle", "componentName", "renderType"]);
|
|
@@ -57,15 +54,7 @@ function ComponentRenderer(_a) {
|
|
|
57
54
|
}
|
|
58
55
|
// if the component is not in the dev.components, it means the component is not loaded
|
|
59
56
|
if ((dev === null || dev === void 0 ? void 0 : dev.mode) === 'draft' && dev && ((_b = dev.components) === null || _b === void 0 ? void 0 : _b[props.componentId]) === undefined) {
|
|
60
|
-
return (
|
|
61
|
-
p: 3,
|
|
62
|
-
border: '1px dashed #d32f2f',
|
|
63
|
-
borderRadius: 1,
|
|
64
|
-
bgcolor: 'rgba(211, 47, 47, 0.04)',
|
|
65
|
-
display: 'flex',
|
|
66
|
-
flexDirection: 'column',
|
|
67
|
-
gap: 1,
|
|
68
|
-
}, children: [_jsx(Typography, { variant: "subtitle1", sx: { color: '#d32f2f', fontWeight: 500 }, children: "Component Failed to Load" }), _jsx(Typography, { variant: "body2", sx: { color: 'text.secondary' }, children: "Please try the following:" }), _jsxs(Box, { component: "ul", sx: { m: 0, pl: 2 }, children: [_jsxs(Typography, { component: "li", variant: "body2", sx: { color: 'text.secondary' }, children: ["Select component", ' ', _jsx(Box, { component: "span", sx: { fontWeight: 500 }, children: componentName !== null && componentName !== void 0 ? componentName : props.componentId }), ' ', "in settings or create this component."] }), (blockletId || blockletTitle) && (_jsxs(Typography, { component: "li", variant: "body2", sx: { color: 'text.secondary' }, children: ["Contact administrator to install", ' ', _jsx(Box, { component: "span", sx: { fontWeight: 500 }, children: blockletTitle !== null && blockletTitle !== void 0 ? blockletTitle : blockletId }), ' ', "Blocklet"] }))] })] }));
|
|
57
|
+
return (_jsx(ComponentError, { componentId: props.componentId, componentName: componentName, blockletId: blockletId, blockletTitle: blockletTitle, message: "Component not found in available components", showHints: true }));
|
|
69
58
|
}
|
|
70
59
|
return null;
|
|
71
60
|
}
|
|
@@ -20,9 +20,10 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
20
20
|
};
|
|
21
21
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
22
22
|
import { cx } from '@emotion/css';
|
|
23
|
+
import { Skeleton, Fade, Box } from '@mui/material';
|
|
23
24
|
import { isEmpty } from 'lodash';
|
|
24
25
|
import set from 'lodash/set';
|
|
25
|
-
import { useDeferredValue, useEffect, useRef, useState } from 'react';
|
|
26
|
+
import { useDeferredValue, useEffect, useRef, useState, useMemo } from 'react';
|
|
26
27
|
import { Helmet } from 'react-helmet';
|
|
27
28
|
import { joinURL } from 'ufo';
|
|
28
29
|
import { create } from 'zustand';
|
|
@@ -31,17 +32,109 @@ import { preloadComponents } from '../../api';
|
|
|
31
32
|
import { PreloadComponentScriptModule } from '../../types';
|
|
32
33
|
import { PreloadComponentsStateGlobalVariableName } from '../../types/preload';
|
|
33
34
|
import { mergeComponent, parsePropertyValue } from '../../utils/property';
|
|
35
|
+
import { ComponentError } from './ErrorComponent';
|
|
34
36
|
const PRELOAD_COMPONENTS_STATE = window[PreloadComponentsStateGlobalVariableName];
|
|
35
37
|
let states;
|
|
36
38
|
function importCustomComponent(m, { componentId }) {
|
|
39
|
+
// check if m is a Promise
|
|
40
|
+
if (m && typeof m.then === 'function') {
|
|
41
|
+
// handle Promise case
|
|
42
|
+
return (props) => {
|
|
43
|
+
const [loading, setLoading] = useState(true);
|
|
44
|
+
const [error, setError] = useState(null);
|
|
45
|
+
const [ResolvedComponent, setResolvedComponent] = useState(null);
|
|
46
|
+
// 只在组件首次加载时执行,避免重复加载
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
let isMounted = true;
|
|
49
|
+
const loadComponent = () => __awaiter(this, void 0, void 0, function* () {
|
|
50
|
+
try {
|
|
51
|
+
const result = yield m;
|
|
52
|
+
if (!isMounted)
|
|
53
|
+
return;
|
|
54
|
+
if (!result) {
|
|
55
|
+
setError(new Error(`Component ${componentId} resolved to empty value`));
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
const Component = importCustomComponent(result, { componentId });
|
|
59
|
+
if (Component) {
|
|
60
|
+
// 存储组件引用而不是渲染结果
|
|
61
|
+
setResolvedComponent(() => Component);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
setError(new Error(`Failed to resolve component ${componentId}`));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
if (!isMounted)
|
|
70
|
+
return;
|
|
71
|
+
console.error(`Component loading error (${componentId}):`, err);
|
|
72
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
if (isMounted) {
|
|
76
|
+
setLoading(false);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
loadComponent();
|
|
81
|
+
return () => {
|
|
82
|
+
isMounted = false;
|
|
83
|
+
};
|
|
84
|
+
}, []); // 仅在组件挂载时执行一次
|
|
85
|
+
// 使用useMemo缓存渲染内容,避免不必要的重计算
|
|
86
|
+
const content = useMemo(() => {
|
|
87
|
+
if (loading) {
|
|
88
|
+
return (_jsx(Box, { sx: { width: '100%', p: 1 }, children: _jsx(Skeleton, { variant: "rectangular", width: "100%", height: 40, animation: "wave" }) }));
|
|
89
|
+
}
|
|
90
|
+
if (error) {
|
|
91
|
+
return _jsx(ComponentError, { componentId: componentId, message: error.message });
|
|
92
|
+
}
|
|
93
|
+
// 动态渲染组件,但允许props更新传递
|
|
94
|
+
if (ResolvedComponent) {
|
|
95
|
+
return _jsx(ResolvedComponent, Object.assign({}, props));
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}, [loading, error, ResolvedComponent, props]);
|
|
99
|
+
return (_jsx(Fade, { in: !loading, timeout: 500, children: _jsx(Box, { children: content }) }));
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
// non-Promise case
|
|
103
|
+
// empty value check
|
|
104
|
+
if (!m) {
|
|
105
|
+
console.warn(`Component ${componentId} resolved to empty value`);
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
37
108
|
let Component;
|
|
38
109
|
const css = m.__PagesKit_CSS__;
|
|
39
|
-
|
|
110
|
+
// smart handle component
|
|
111
|
+
if (typeof m === 'function') {
|
|
112
|
+
// the function itself may be a component
|
|
40
113
|
Component = m;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
114
|
+
}
|
|
115
|
+
else if (m.default) {
|
|
116
|
+
// has default export
|
|
117
|
+
if (typeof m.default === 'function') {
|
|
118
|
+
// default is a function may be a component
|
|
119
|
+
Component = m.default;
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
// default is not a function, maybe a JSX element
|
|
123
|
+
Component = () => m.default;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else if (css) {
|
|
127
|
+
// has CSS but no valid component found
|
|
128
|
+
console.warn(`Component ${componentId} has CSS but no valid component found`);
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
// if a component is found and has CSS, wrap the component with styles
|
|
132
|
+
if (Component && css) {
|
|
133
|
+
const OriginalComponent = Component;
|
|
134
|
+
Component = (props) => (_jsxs(_Fragment, { children: [_jsx(Helmet, { children: _jsx("style", { children: css }) }), _jsx(OriginalComponent, Object.assign({}, props, { className: cx(props.className, `CustomComponent_${componentId}`) }))] }));
|
|
135
|
+
}
|
|
136
|
+
// keep aigneOutputValueSchema
|
|
137
|
+
if (Component && m.aigneOutputValueSchema) {
|
|
45
138
|
Component.aigneOutputValueSchema = m.aigneOutputValueSchema;
|
|
46
139
|
}
|
|
47
140
|
return Component;
|
|
@@ -73,14 +166,29 @@ export const customComponentStates = () => {
|
|
|
73
166
|
states !== null && states !== void 0 ? states : (states = create()(immer((set, get) => ({
|
|
74
167
|
state: {
|
|
75
168
|
config: Object.assign({}, PRELOAD_COMPONENTS_STATE === null || PRELOAD_COMPONENTS_STATE === void 0 ? void 0 : PRELOAD_COMPONENTS_STATE.config),
|
|
76
|
-
components: Object.fromEntries(Object.entries(Object.assign({}, PRELOAD_COMPONENTS_STATE === null || PRELOAD_COMPONENTS_STATE === void 0 ? void 0 : PRELOAD_COMPONENTS_STATE.components))
|
|
169
|
+
components: Object.fromEntries(Object.entries(Object.assign({}, PRELOAD_COMPONENTS_STATE === null || PRELOAD_COMPONENTS_STATE === void 0 ? void 0 : PRELOAD_COMPONENTS_STATE.components))
|
|
170
|
+
.map(([componentId, preload]) => {
|
|
77
171
|
let Component;
|
|
78
172
|
if (preload.componentModuleGlobalVariable) {
|
|
79
173
|
const m = window[preload.componentModuleGlobalVariable];
|
|
80
|
-
|
|
174
|
+
// handle the global variable
|
|
175
|
+
if (typeof m === 'function') {
|
|
176
|
+
try {
|
|
177
|
+
// call m() to get the component module
|
|
178
|
+
const modulePromiseOrObject = m();
|
|
179
|
+
Component = importCustomComponent(modulePromiseOrObject, { componentId });
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
console.error(`Failed to initialize component ${componentId}:`, err);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
console.warn(`Component global variable ${preload.componentModuleGlobalVariable} is not a function`);
|
|
187
|
+
}
|
|
81
188
|
}
|
|
82
189
|
return [componentId, Object.assign(Object.assign({}, preload), { Component })];
|
|
83
|
-
})
|
|
190
|
+
})
|
|
191
|
+
.filter((i) => !!i)),
|
|
84
192
|
instances: Object.assign({}, PRELOAD_COMPONENTS_STATE === null || PRELOAD_COMPONENTS_STATE === void 0 ? void 0 : PRELOAD_COMPONENTS_STATE.instances),
|
|
85
193
|
},
|
|
86
194
|
getComponent({ instanceId, componentId, locale }) {
|
|
@@ -273,7 +381,7 @@ export function transpileAndLoadScript(script) {
|
|
|
273
381
|
before: [createBuiltinModuleTransformer(ts)],
|
|
274
382
|
},
|
|
275
383
|
}).outputText;
|
|
276
|
-
//
|
|
384
|
+
// fallback to the original handling
|
|
277
385
|
const url = URL.createObjectURL(new Blob([compiled], { type: 'application/javascript' }));
|
|
278
386
|
try {
|
|
279
387
|
return yield import(/* @vite-ignore */ url);
|