@blocklet/pages-kit-block-studio 0.5.55 → 0.6.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.
@@ -205,7 +205,7 @@ router.get('/api/pages', async (req, res) => {
205
205
  return res.status(400).json({ message: 'Either did or projectId is required' });
206
206
  } catch (error) {
207
207
  console.error('Error fetching pages:', error);
208
- return res.status(500).json({ message: 'Internal server error' });
208
+ return res.status(400).json({ message: 'Internal server error' });
209
209
  }
210
210
  });
211
211
 
@@ -115,7 +115,7 @@ initBlockStudioRouter.get('/', async (req, res) => {
115
115
  return res.json(metadata);
116
116
  }
117
117
  catch (error) {
118
- return res.status(500).json({ error: 'Failed to read file' });
118
+ return res.status(400).json({ error: 'Failed to read file' });
119
119
  }
120
120
  });
121
121
  initBlockStudioRouter.post('/', async (req, res) => {
@@ -163,7 +163,7 @@ initBlockStudioRouter.post('/', async (req, res) => {
163
163
  return res.json({ success: true, content: mergedContent, message: 'Updated' });
164
164
  }
165
165
  catch (error) {
166
- return res.status(500).json({ error: 'Failed to write file' });
166
+ return res.status(400).json({ error: 'Failed to write file' });
167
167
  }
168
168
  });
169
169
  initBlockStudioRouter.post('/create', async (req, res) => {
@@ -225,7 +225,7 @@ initBlockStudioRouter.post('/create', async (req, res) => {
225
225
  }
226
226
  catch (error) {
227
227
  console.error('Failed to create block:', error);
228
- return res.status(500).json({ error: 'Failed to create block' });
228
+ return res.status(400).json({ error: 'Failed to create block' });
229
229
  }
230
230
  });
231
231
  initBlockStudioRouter.get('/resources', async (req, res) => {
@@ -319,7 +319,7 @@ initBlockStudioRouter.post('/properties-to-interface', async (req, res) => {
319
319
  }
320
320
  catch (conversionError) {
321
321
  console.error('Failed to convert properties to interface:', conversionError);
322
- return res.status(500).json({
322
+ return res.status(400).json({
323
323
  success: false,
324
324
  error: `Failed to convert properties to interface: ${conversionError.message}`,
325
325
  });
@@ -327,7 +327,7 @@ initBlockStudioRouter.post('/properties-to-interface', async (req, res) => {
327
327
  }
328
328
  catch (error) {
329
329
  console.error('Failed to generate interface:', error);
330
- return res.status(500).json({
330
+ return res.status(400).json({
331
331
  success: false,
332
332
  error: `Failed to generate interface: ${error.message}`,
333
333
  });
@@ -385,7 +385,7 @@ initBlockStudioRouter.post('/interface-to-properties', async (req, res) => {
385
385
  }
386
386
  catch (conversionError) {
387
387
  console.error('Failed to convert interface to properties:', conversionError);
388
- return res.status(500).json({
388
+ return res.status(400).json({
389
389
  success: false,
390
390
  error: `Failed to convert interface to properties: ${conversionError.message}`,
391
391
  });
@@ -393,7 +393,7 @@ initBlockStudioRouter.post('/interface-to-properties', async (req, res) => {
393
393
  }
394
394
  catch (error) {
395
395
  console.error('Failed to generate metadata:', error);
396
- return res.status(500).json({
396
+ return res.status(400).json({
397
397
  success: false,
398
398
  error: `Failed to generate metadata: ${error.message}`,
399
399
  });
@@ -455,7 +455,7 @@ initBlockStudioRouter.delete('/delete', async (req, res) => {
455
455
  }
456
456
  catch (deleteError) {
457
457
  console.error('Failed to delete component directory:', deleteError);
458
- return res.status(500).json({
458
+ return res.status(400).json({
459
459
  success: false,
460
460
  error: `Failed to delete component directory: ${deleteError.message}`,
461
461
  });
@@ -463,7 +463,7 @@ initBlockStudioRouter.delete('/delete', async (req, res) => {
463
463
  }
464
464
  catch (error) {
465
465
  console.error('Failed to delete component:', error);
466
- return res.status(500).json({
466
+ return res.status(400).json({
467
467
  success: false,
468
468
  error: `Failed to delete component: ${error.message}`,
469
469
  });
@@ -250,7 +250,7 @@ initResourceRouter.post('/', async (req, res) => {
250
250
  }
251
251
  catch (error) {
252
252
  console.error('Build failed:', error);
253
- res.status(500).json({ error: 'Build failed' });
253
+ res.status(400).json({ error: 'Build failed' });
254
254
  }
255
255
  });
256
256
  export default initResourceRouter;
@@ -208,20 +208,24 @@ const ComparisonPreviewDialog = ({ open, title, leftTitle, leftContent, rightTit
208
208
  Toast.error(t('themeTranslations.operationFailed'));
209
209
  }
210
210
  };
211
- return (_jsxs(Dialog, { open: open, onClose: onClose, maxWidth: "md", fullWidth: true, children: [_jsx(DialogTitle, { children: title }), _jsx(DialogContent, { children: _jsxs(Box, { children: [_jsxs(Box, { sx: { display: 'flex', flexDirection: 'row', mb: 2 }, children: [_jsxs(Box, { sx: { flex: 1, mr: 1 }, children: [_jsx(Typography, { variant: "subtitle2", sx: { mb: 1 }, children: leftTitle }), _jsx(TextField, { multiline: true, fullWidth: true, rows: 10, InputProps: {
212
- readOnly: true,
213
- }, value: leftContent, sx: {
211
+ return (_jsxs(Dialog, { open: open, onClose: onClose, maxWidth: "md", fullWidth: true, children: [_jsx(DialogTitle, { children: title }), _jsx(DialogContent, { children: _jsxs(Box, { children: [_jsxs(Box, { sx: { display: 'flex', flexDirection: 'row', mb: 2 }, children: [_jsxs(Box, { sx: { flex: 1, mr: 1 }, children: [_jsx(Typography, { variant: "subtitle2", sx: { mb: 1 }, children: leftTitle }), _jsx(TextField, { multiline: true, fullWidth: true, rows: 10, value: leftContent, sx: {
214
212
  '& .MuiOutlinedInput-root': {
215
213
  fontFamily: 'monospace',
216
214
  fontSize: '0.875rem',
217
215
  },
218
- } })] }), _jsxs(Box, { sx: { flex: 1, ml: 1 }, children: [_jsx(Typography, { variant: "subtitle2", sx: { mb: 1 }, children: rightTitle }), _jsx(TextField, { multiline: true, fullWidth: true, rows: 10, InputProps: {
219
- readOnly: true,
220
- }, value: rightContent, sx: {
216
+ }, slotProps: {
217
+ input: {
218
+ readOnly: true,
219
+ },
220
+ } })] }), _jsxs(Box, { sx: { flex: 1, ml: 1 }, children: [_jsx(Typography, { variant: "subtitle2", sx: { mb: 1 }, children: rightTitle }), _jsx(TextField, { multiline: true, fullWidth: true, rows: 10, value: rightContent, sx: {
221
221
  '& .MuiOutlinedInput-root': {
222
222
  fontFamily: 'monospace',
223
223
  fontSize: '0.875rem',
224
224
  },
225
+ }, slotProps: {
226
+ input: {
227
+ readOnly: true,
228
+ },
225
229
  } })] })] }), _jsx(Typography, { variant: "body2", sx: { mt: 2, color: 'text.secondary' }, children: description })] }) }), _jsxs(Box, { sx: { display: 'flex', justifyContent: 'flex-end', p: 2 }, children: [_jsx(Button, { variant: "outlined", onClick: onClose, sx: { mr: 1 }, children: t('themeTranslations.cancel') }), _jsx(Button, { variant: "contained", onClick: handleConfirm, disabled: loading, children: loading ? _jsx(CircularProgress, { size: 24 }) : t('themeTranslations.confirmUpdate') })] })] }));
226
230
  };
227
231
  function Layout({ loadState, loadedData }) {
@@ -483,7 +487,11 @@ function Layout({ loadState, loadedData }) {
483
487
  triggerRerender();
484
488
  }, [JSON.stringify(mergedPropertiesValues), JSON.stringify(mergedAllBlocks), state.metadata.id, locale]);
485
489
  const DraggingSplitPlaceholder = useMemo(() => {
486
- return (_jsx(Box, { p: 1.5, width: "100%", height: "100%", children: _jsx(Skeleton, { variant: "rectangular", height: "100%", sx: { borderRadius: 1 } }) }));
490
+ return (_jsx(Box, { sx: {
491
+ p: 1.5,
492
+ width: '100%',
493
+ height: '100%',
494
+ }, children: _jsx(Skeleton, { variant: "rectangular", height: "100%", sx: { borderRadius: 1 } }) }));
487
495
  }, []);
488
496
  // Move item function for drag and drop
489
497
  const moveItem = useCallback((dragIndex, hoverIndex) => {
@@ -570,7 +578,16 @@ function Layout({ loadState, loadedData }) {
570
578
  if (state.draggingSplitPane) {
571
579
  return DraggingSplitPlaceholder;
572
580
  }
573
- return (_jsxs(Stack, { height: "100%", children: [_jsxs(Stack, { gap: 1, direction: "row", alignItems: "center", sx: { pt: 2, pr: 1, pl: 0.5, pb: 1 }, children: [_jsx(TextField, { placeholder: t('themeTranslations.search'), sx: { minWidth: 60, flex: 1 }, onChange: (e) => {
581
+ return (_jsxs(Stack, { sx: {
582
+ height: '100%',
583
+ }, children: [_jsxs(Stack, { direction: "row", sx: {
584
+ gap: 1,
585
+ alignItems: 'center',
586
+ pt: 2,
587
+ pr: 1,
588
+ pl: 0.5,
589
+ pb: 1,
590
+ }, children: [_jsx(TextField, { placeholder: t('themeTranslations.search'), sx: { minWidth: 60, flex: 1 }, onChange: (e) => {
574
591
  state.searchValue = e.target.value;
575
592
  } }), hasCustomSort && (_jsx(Tooltip, { title: t('themeTranslations.resetToAlphabeticalSort'), children: _jsx(IconButton, { size: "small", onClick: () => {
576
593
  setCustomSortOrder([]);
@@ -605,12 +622,27 @@ function Layout({ loadState, loadedData }) {
605
622
  }
606
623
  }, onDelete: handleDeleteBlock, index: index, moveItem: moveItem, showDragHandle: true, routes: routes }, route));
607
624
  })
608
- .filter(Boolean) })) : (_jsx(Box, { display: "flex", justifyContent: "center", alignItems: "center", height: "100%", sx: { p: 3 }, children: _jsxs(Stack, { alignItems: "center", spacing: 3, sx: { textAlign: 'center' }, children: [_jsx(Box, { component: "img", src: "https://api.iconify.design/material-symbols:folder-open-outline.svg", sx: {
625
+ .filter(Boolean) })) : (_jsx(Box, { sx: {
626
+ display: 'flex',
627
+ justifyContent: 'center',
628
+ alignItems: 'center',
629
+ height: '100%',
630
+ p: 3,
631
+ }, children: _jsxs(Stack, { spacing: 3, sx: {
632
+ alignItems: 'center',
633
+ textAlign: 'center',
634
+ }, children: [_jsx(Box, { component: "img", src: "https://api.iconify.design/material-symbols:folder-open-outline.svg", sx: {
609
635
  width: 48,
610
636
  height: 48,
611
637
  opacity: 0.5,
612
638
  filter: 'grayscale(100%)',
613
- }, alt: "No components" }), _jsx(Typography, { variant: "h6", color: "text.primary", sx: { fontWeight: 600 }, children: t('themeTranslations.noComponentsFound') }), _jsx(Typography, { variant: "body2", color: "text.secondary", sx: { maxWidth: 200 }, children: t('themeTranslations.createFirstComponent') }), _jsx(Button, { variant: "contained", startIcon: _jsx(AddIcon, {}), onClick: () => {
639
+ }, alt: "No components" }), _jsx(Typography, { variant: "h6", sx: {
640
+ color: 'text.primary',
641
+ fontWeight: 600,
642
+ }, children: t('themeTranslations.noComponentsFound') }), _jsx(Typography, { variant: "body2", sx: {
643
+ color: 'text.secondary',
644
+ maxWidth: 200,
645
+ }, children: t('themeTranslations.createFirstComponent') }), _jsx(Button, { variant: "contained", startIcon: _jsx(AddIcon, {}), onClick: () => {
614
646
  state.createBlockOpen = true;
615
647
  }, sx: { mt: 2 }, children: t('themeTranslations.createComponent') })] }) }))] }));
616
648
  }, [
@@ -635,7 +667,13 @@ function Layout({ loadState, loadedData }) {
635
667
  return null;
636
668
  }
637
669
  if (loadState.type === 'load-error') {
638
- return (_jsx(Box, { width: "100%", height: "100%", display: "flex", justifyContent: "center", alignItems: "center", children: _jsx(Alert, { severity: "error", variant: "filled", children: t('themeTranslations.failedLoadCode') }) }));
670
+ return (_jsx(Box, { sx: {
671
+ width: '100%',
672
+ height: '100%',
673
+ display: 'flex',
674
+ justifyContent: 'center',
675
+ alignItems: 'center',
676
+ }, children: _jsx(Alert, { severity: "error", variant: "filled", children: t('themeTranslations.failedLoadCode') }) }));
639
677
  }
640
678
  // 从 URL 获取初始组件 ID 和语言
641
679
  const url = new URL(window.location.href);
@@ -649,7 +687,13 @@ function Layout({ loadState, loadedData }) {
649
687
  }
650
688
  // 没有匹配到路由,使用欢迎页面
651
689
  if (notSelectedBlock) {
652
- return (_jsxs(Box, { width: "100%", height: "100%", display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", sx: {
690
+ return (_jsxs(Box, { sx: {
691
+ width: '100%',
692
+ height: '100%',
693
+ display: 'flex',
694
+ flexDirection: 'column',
695
+ justifyContent: 'center',
696
+ alignItems: 'center',
653
697
  backgroundColor: 'background.default',
654
698
  p: 3,
655
699
  textAlign: 'center',
@@ -841,12 +885,18 @@ function Layout({ loadState, loadedData }) {
841
885
  justifyContent: 'center',
842
886
  alignItems: 'center',
843
887
  p: 3,
844
- }, children: _jsxs(Stack, { alignItems: "center", spacing: 2, sx: {
888
+ }, children: _jsxs(Stack, { spacing: 2, sx: {
889
+ alignItems: 'center',
845
890
  textAlign: 'center',
846
891
  bgcolor: 'background.default',
847
892
  borderRadius: 2,
848
893
  p: 3,
849
- }, children: [_jsx(SettingsIcon, { sx: { fontSize: 48, color: 'primary.main' } }), _jsxs(Stack, { spacing: 1, children: [_jsx(Typography, { variant: "h6", color: "primary.main", sx: { fontWeight: 600 }, children: t('themeTranslations.componentPropertiesTitle') }), _jsx(Typography, { variant: "body2", color: "text.secondary", children: t('themeTranslations.selectComponentToConfigureProperties') })] })] }) })), _jsx(ListItem, { children: _jsx(Box, { sx: { width: '100%' }, children: _jsx(BasicInfo, { config: state.metadata }) }) }), _jsx(ListItem, { children: _jsxs(Box, { sx: { width: '100%' }, children: [_jsx(PropertiesConfig, { config: state.metadata, currentLocale: locale, defaultLocale: defaultLocale, allComponents: mergedAllBlocks, onUpdateConfig: (updater) => {
894
+ }, children: [_jsx(SettingsIcon, { sx: { fontSize: 48, color: 'primary.main' } }), _jsxs(Stack, { spacing: 1, children: [_jsx(Typography, { variant: "h6", sx: {
895
+ color: 'primary.main',
896
+ fontWeight: 600,
897
+ }, children: t('themeTranslations.componentPropertiesTitle') }), _jsx(Typography, { variant: "body2", sx: {
898
+ color: 'text.secondary',
899
+ }, children: t('themeTranslations.selectComponentToConfigureProperties') })] })] }) })), _jsx(ListItem, { children: _jsx(Box, { sx: { width: '100%' }, children: _jsx(BasicInfo, { config: state.metadata }) }) }), _jsx(ListItem, { children: _jsxs(Box, { sx: { width: '100%' }, children: [_jsx(PropertiesConfig, { config: state.metadata, currentLocale: locale, defaultLocale: defaultLocale, allComponents: mergedAllBlocks, onUpdateConfig: (updater) => {
850
900
  updater(state.metadata);
851
901
  }, useI18nEditor: false }), _jsxs(Stack, { direction: "column", spacing: 1, sx: { mt: 1 }, children: [_jsx(Button, { variant: "contained", size: "small", color: "primary", onClick: async () => {
852
902
  try {
@@ -23,14 +23,35 @@ VIRTUAL_MODULE_ID, readHtmlFiles, generateComponent, } from './vite-plugin-html-
23
23
  import { importTransformPlugin } from './vite-plugin-import-transform';
24
24
  // const BUILTIN_MODULES_VAR = '__PAGES_KIT_BUILTIN_MODULES__';
25
25
  // logger.log('BUILTIN_MODULES_VAR', BUILTIN_MODULES_VAR);
26
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
27
- const isMatchAfterSlachExternals = (_id) => {
26
+ // 检查模块ID是否匹配外部依赖(包括子路径)
27
+ const isMatchAfterSlachExternals = (id, externals) => {
28
+ // 精确匹配
29
+ if (externals[id]) {
30
+ return true;
31
+ }
32
+ // 子路径匹配,特别处理 React 相关模块
33
+ const reactModules = ['react', 'react-dom', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'react-dom/client'];
34
+ // 检查是否是 React 相关模块的子路径
35
+ for (const reactModule of reactModules) {
36
+ if (id === reactModule || id.startsWith(`${reactModule}/`)) {
37
+ return true;
38
+ }
39
+ }
40
+ // 检查其他外部依赖的子路径
41
+ for (const externalModule of Object.keys(externals)) {
42
+ if (id.startsWith(`${externalModule}/`)) {
43
+ return true;
44
+ }
45
+ }
28
46
  return false;
29
47
  };
30
48
  const defaultBlockExternals = {
31
- // 核心 React 相关
49
+ // 核心 React 相关 - 确保完全外部化
32
50
  react: '@blocklet/pages-kit/builtin/react',
33
51
  'react-dom': '@blocklet/pages-kit/builtin/react-dom',
52
+ 'react-dom/client': '@blocklet/pages-kit/builtin/react-dom',
53
+ 'react/jsx-runtime': '@blocklet/pages-kit/builtin/react',
54
+ 'react/jsx-dev-runtime': '@blocklet/pages-kit/builtin/react',
34
55
  'react-router-dom': '@blocklet/pages-kit/builtin/react-router-dom',
35
56
  'react-hook-form': '@blocklet/pages-kit/builtin/react-hook-form',
36
57
  'react-wrap-balancer': '@blocklet/pages-kit/builtin/react-wrap-balancer',
@@ -102,14 +123,6 @@ export function initBlockStudioPlugins(options) {
102
123
  externalMappings = options.blockExternals;
103
124
  }
104
125
  setBlockEntryFilesPattern(entryFilesPattern);
105
- logger.log('initBlockStudioPlugins options: ', {
106
- cwd: workingDir,
107
- watchFilesDir,
108
- entryFilesPattern: getBlockEntryFilesPattern(),
109
- pagesDir,
110
- blockExternals: externalMappings, // 添加日志输出
111
- transpileBuiltinModule,
112
- });
113
126
  // 为 globals 创建一个无前缀的版本
114
127
  const pathMappings = Object.fromEntries(Object.entries(externalMappings).filter(([, value]) => !value.startsWith('window.') && value.length > 0));
115
128
  const externalGlobalMappings = Object.fromEntries(Object.entries(externalMappings).filter(([, value]) => value.startsWith('window.') && value.length > 0));
@@ -118,12 +131,32 @@ export function initBlockStudioPlugins(options) {
118
131
  if (!value?.length) {
119
132
  return [];
120
133
  }
134
+ // 特殊处理 React 相关模块
135
+ const reactGlobals = {
136
+ react: 'React',
137
+ 'react-dom': 'ReactDOM',
138
+ 'react/jsx-runtime': 'React',
139
+ 'react/jsx-dev-runtime': 'React',
140
+ 'react-dom/client': 'ReactDOM',
141
+ };
142
+ if (reactGlobals[key]) {
143
+ return [key, reactGlobals[key]];
144
+ }
121
145
  // 移除 "window." 前缀并转换为首字母大写的驼峰式
122
146
  const rawName = String(key);
123
147
  const globalName = upperFirst(camelCase(rawName));
124
148
  return [key, globalName];
125
149
  })
126
150
  .filter((item) => item.length > 0));
151
+ logger.log('initBlockStudioPlugins options: ', {
152
+ cwd: workingDir,
153
+ watchFilesDir,
154
+ entryFilesPattern: getBlockEntryFilesPattern(),
155
+ pagesDir,
156
+ blockExternals: externalMappings,
157
+ globalsMappings,
158
+ transpileBuiltinModule,
159
+ });
127
160
  const filterModules = process.argv.includes('--filter')
128
161
  ? process.argv[process.argv.indexOf('--filter') + 1]?.split(',')
129
162
  : null;
@@ -202,10 +235,14 @@ export function initBlockStudioPlugins(options) {
202
235
  ..._config?.build?.rollupOptions,
203
236
  external: _config?.build?.rollupOptions?.external ||
204
237
  ((id) => {
205
- // 是否匹配后缀
206
- const isMatchAfterSlash = isMatchAfterSlachExternals(id);
238
+ // 使用改进的外部依赖检查
239
+ const isExternal = isMatchAfterSlachExternals(id, externalMappings);
240
+ if (isExternal) {
241
+ return true;
242
+ }
243
+ // 兼容原有逻辑
207
244
  const skipList = [...Object.keys(externalMappings)];
208
- if (skipList.some((item) => (isMatchAfterSlash && id.startsWith(`${item}/`)) || id === item)) {
245
+ if (skipList.some((item) => id === item)) {
209
246
  return true;
210
247
  }
211
248
  return false;