@blocklet/pages-kit-block-studio 0.0.17 → 0.1.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.
Files changed (29) hide show
  1. package/lib/cjs/constants/index.js +12 -1
  2. package/lib/cjs/constants/new-block-template/@metadata.json +59 -0
  3. package/lib/cjs/constants/new-block-template/index.js +55 -0
  4. package/lib/cjs/constants/new-block-template/index.tsx +89 -0
  5. package/lib/cjs/middlewares/init-block-studio-router.js +47 -14
  6. package/lib/cjs/middlewares/init-resource-router.js +5 -1
  7. package/lib/cjs/plugins/vite-plugin-block-studio.js +29 -30
  8. package/lib/cjs/plugins/vite-plugin-html-transform.js +42 -2
  9. package/lib/cjs/tsconfig.tsbuildinfo +1 -1
  10. package/lib/cjs/utils/generate-wrapper-code.js +21 -25
  11. package/lib/cjs/utils/helper.js +39 -12
  12. package/lib/esm/constants/index.js +8 -0
  13. package/lib/esm/constants/new-block-template/@metadata.json +59 -0
  14. package/lib/esm/constants/new-block-template/index.js +50 -0
  15. package/lib/esm/constants/new-block-template/index.tsx +89 -0
  16. package/lib/esm/middlewares/init-block-studio-router.js +46 -13
  17. package/lib/esm/middlewares/init-resource-router.js +5 -1
  18. package/lib/esm/plugins/vite-plugin-block-studio.js +30 -31
  19. package/lib/esm/plugins/vite-plugin-html-transform.js +42 -4
  20. package/lib/esm/tsconfig.tsbuildinfo +1 -1
  21. package/lib/esm/utils/generate-wrapper-code.js +21 -25
  22. package/lib/esm/utils/helper.js +28 -6
  23. package/lib/types/constants/index.d.ts +7 -0
  24. package/lib/types/constants/new-block-template/index.d.ts +13 -0
  25. package/lib/types/plugins/vite-plugin-html-transform.d.ts +14 -0
  26. package/lib/types/tsconfig.tsbuildinfo +1 -1
  27. package/lib/types/utils/helper.d.ts +3 -4
  28. package/package.json +17 -5
  29. package/tsconfig.json +3 -1
@@ -1,9 +1,20 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MEDIA_KIT_RESOURCE_TYPE = exports.MEDIA_KIT_DID = exports.PAGES_KIT_BLOCK_STUDIO_RESOURCE_TYPE = exports.PAGES_KIT_BLOCK_STUDIO_DID = exports.PAGES_KIT_RESOURCE_TYPE = exports.PAGES_KIT_DID = void 0;
6
+ exports.DEFAULT_BLOCK_ENTRY_FILES_PATTERN = exports.NANOID_LENGTH = exports.PREVIEW_IMAGE_DIR = exports.METADATA_FILE_NAME = exports.libDir = exports.NEW_BLOCK_TEMPLATE_METADATA_PATH = exports.NEW_BLOCK_TEMPLATE_PATH = exports.MEDIA_KIT_RESOURCE_TYPE = exports.MEDIA_KIT_DID = exports.PAGES_KIT_BLOCK_STUDIO_RESOURCE_TYPE = exports.PAGES_KIT_BLOCK_STUDIO_DID = exports.PAGES_KIT_RESOURCE_TYPE = exports.PAGES_KIT_DID = void 0;
7
+ const path_1 = __importDefault(require("path"));
4
8
  exports.PAGES_KIT_DID = 'z8iZiDFg3vkkrPwsiba1TLXy3H9XHzFERsP8o';
5
9
  exports.PAGES_KIT_RESOURCE_TYPE = 'page';
6
10
  exports.PAGES_KIT_BLOCK_STUDIO_DID = 'z2qa7rr3eUyVnWp2PCxEVARuUfLFh6cE5V2xV';
7
11
  exports.PAGES_KIT_BLOCK_STUDIO_RESOURCE_TYPE = 'page';
8
12
  exports.MEDIA_KIT_DID = 'z8ia1mAXo8ZE7ytGF36L5uBf9kD2kenhqFGp9';
9
13
  exports.MEDIA_KIT_RESOURCE_TYPE = 'imgpack';
14
+ exports.NEW_BLOCK_TEMPLATE_PATH = path_1.default.join(__dirname, 'new-block-template', 'index.tsx');
15
+ exports.NEW_BLOCK_TEMPLATE_METADATA_PATH = path_1.default.join(__dirname, 'new-block-template', '@metadata.json');
16
+ exports.libDir = 'lib';
17
+ exports.METADATA_FILE_NAME = '@metadata.json';
18
+ exports.PREVIEW_IMAGE_DIR = '@preview-images';
19
+ exports.NANOID_LENGTH = 16;
20
+ exports.DEFAULT_BLOCK_ENTRY_FILES_PATTERN = 'src/**/index.{ts,tsx,html}';
@@ -0,0 +1,59 @@
1
+ {
2
+ "properties": {
3
+ "gs1rn5jmxfvpxptx": {
4
+ "index": 0,
5
+ "data": {
6
+ "id": "gs1rn5jmxfvpxptx",
7
+ "key": "title",
8
+ "locales": {
9
+ "zh": {
10
+ "name": "Title"
11
+ }
12
+ }
13
+ }
14
+ },
15
+ "9ajrz12ik7esfk1z": {
16
+ "index": 1,
17
+ "data": {
18
+ "id": "9ajrz12ik7esfk1z",
19
+ "key": "description",
20
+ "locales": {
21
+ "zh": {
22
+ "name": "Description",
23
+ "defaultValue": "Welcome to Pages Kit Block Studio"
24
+ }
25
+ }
26
+ }
27
+ },
28
+ "3ckcfvf6b7zyskk8": {
29
+ "index": 2,
30
+ "data": {
31
+ "id": "3ckcfvf6b7zyskk8",
32
+ "key": "logo",
33
+ "type": "url",
34
+ "locales": {
35
+ "zh": {
36
+ "defaultValue": {
37
+ "url": "/.well-known/service/blocklet/logo?imageFilter=convert&f=png&h=80",
38
+ "mediaKitUrl": "/.well-known/service/blocklet/logo?imageFilter=convert&f=png&h=80"
39
+ },
40
+ "name": "Logo"
41
+ }
42
+ }
43
+ }
44
+ },
45
+ "x3lqht8ikble1itx": {
46
+ "index": 3,
47
+ "data": {
48
+ "id": "x3lqht8ikble1itx",
49
+ "key": "copyright",
50
+ "locales": {
51
+ "zh": {
52
+ "defaultValue": "Powered by Pages Kit Block Studio"
53
+ }
54
+ },
55
+ "visible": false
56
+ }
57
+ }
58
+ }
59
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.EditComponent = void 0;
15
+ exports.default = HelloWorld;
16
+ const jsx_runtime_1 = require("react/jsx-runtime");
17
+ // default export
18
+ function HelloWorld({ title = 'Hello World', logo, description, copyright }) {
19
+ return ((0, jsx_runtime_1.jsxs)("div", { style: {
20
+ display: 'flex',
21
+ flexDirection: 'column',
22
+ alignItems: 'center',
23
+ padding: '16px 0',
24
+ }, children: [title && (0, jsx_runtime_1.jsx)("h1", { children: title }), logo && ((0, jsx_runtime_1.jsx)("img", { src: typeof logo === 'object' ? logo.url : logo, alt: "logo", style: {
25
+ margin: '16px 0',
26
+ maxWidth: '200px',
27
+ } })), description && ((0, jsx_runtime_1.jsx)("div", { style: {
28
+ color: '#666',
29
+ marginTop: '8px',
30
+ }, children: description })), copyright && ((0, jsx_runtime_1.jsx)("div", { style: {
31
+ color: '#999',
32
+ fontSize: '12px',
33
+ marginTop: '16px',
34
+ }, children: copyright }))] }));
35
+ }
36
+ // export edit component
37
+ const EditComponent = (_a) => {
38
+ var { onChange } = _a, props = __rest(_a, ["onChange"]);
39
+ return ((0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', flexDirection: 'column', gap: '16px' }, children: [(0, jsx_runtime_1.jsx)("div", { style: {
40
+ fontSize: '14px',
41
+ fontWeight: 500,
42
+ color: '#333',
43
+ padding: '8px 0',
44
+ borderBottom: '1px solid #eee',
45
+ }, children: "Footer Parameters" }), (0, jsx_runtime_1.jsx)("input", { id: "copyright-input", type: "text", style: {
46
+ width: '100%',
47
+ padding: '8px 12px',
48
+ border: '1px solid #ddd',
49
+ borderRadius: '4px',
50
+ fontSize: '14px',
51
+ transition: 'border-color 0.3s',
52
+ outline: 'none',
53
+ }, value: props.copyright || '', onChange: (e) => onChange === null || onChange === void 0 ? void 0 : onChange({ copyright: e.target.value }), placeholder: "Please Input Copyright" })] }));
54
+ };
55
+ exports.EditComponent = EditComponent;
@@ -0,0 +1,89 @@
1
+ import React from 'react';
2
+
3
+ export interface HelloWorldProps {
4
+ title?: string;
5
+ logo?: string | { url: string };
6
+ description?: string;
7
+ copyright?: string;
8
+ }
9
+
10
+ // default export
11
+ export default function HelloWorld({ title = 'Hello World', logo, description, copyright }: HelloWorldProps) {
12
+ return (
13
+ <div
14
+ style={{
15
+ display: 'flex',
16
+ flexDirection: 'column',
17
+ alignItems: 'center',
18
+ padding: '16px 0',
19
+ }}>
20
+ {title && <h1>{title}</h1>}
21
+ {logo && (
22
+ <img
23
+ src={typeof logo === 'object' ? logo.url : logo}
24
+ alt="logo"
25
+ style={{
26
+ margin: '16px 0',
27
+ maxWidth: '200px',
28
+ }}
29
+ />
30
+ )}
31
+ {description && (
32
+ <div
33
+ style={{
34
+ color: '#666',
35
+ marginTop: '8px',
36
+ }}>
37
+ {description}
38
+ </div>
39
+ )}
40
+ {copyright && (
41
+ <div
42
+ style={{
43
+ color: '#999',
44
+ fontSize: '12px',
45
+ marginTop: '16px',
46
+ }}>
47
+ {copyright}
48
+ </div>
49
+ )}
50
+ </div>
51
+ );
52
+ }
53
+
54
+ // export edit component
55
+ export const EditComponent: React.FC<HelloWorldProps & { onChange?: (value: HelloWorldProps) => void }> = ({
56
+ onChange,
57
+ ...props
58
+ }) => {
59
+ return (
60
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
61
+ <div
62
+ style={{
63
+ fontSize: '14px',
64
+ fontWeight: 500,
65
+ color: '#333',
66
+ padding: '8px 0',
67
+ borderBottom: '1px solid #eee',
68
+ }}>
69
+ Footer Parameters
70
+ </div>
71
+ <input
72
+ id="copyright-input"
73
+ type="text"
74
+ style={{
75
+ width: '100%',
76
+ padding: '8px 12px',
77
+ border: '1px solid #ddd',
78
+ borderRadius: '4px',
79
+ fontSize: '14px',
80
+ transition: 'border-color 0.3s',
81
+ outline: 'none',
82
+ }}
83
+ value={props.copyright || ''}
84
+ onChange={(e) => onChange?.({ copyright: e.target.value })}
85
+ placeholder="Please Input Copyright"
86
+ />
87
+ </div>
88
+ );
89
+ };
@@ -16,9 +16,8 @@ exports.initBlockStudioRouter = void 0;
16
16
  const express_1 = require("express");
17
17
  const fs_1 = __importDefault(require("fs"));
18
18
  const lodash_1 = require("lodash");
19
- const lodash_2 = require("lodash");
20
- const lodash_3 = require("lodash");
21
19
  const path_1 = __importDefault(require("path"));
20
+ const constants_1 = require("../constants");
22
21
  const helper_1 = require("../utils/helper");
23
22
  exports.initBlockStudioRouter = (0, express_1.Router)();
24
23
  const BINARY_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.ico', '.svg'];
@@ -45,11 +44,6 @@ exports.initBlockStudioRouter.get('/', (req, res) => __awaiter(void 0, void 0, v
45
44
  return fs_1.default.createReadStream(filePath).pipe(res);
46
45
  }
47
46
  const metadata = (0, helper_1.initializeMetadata)(filePath);
48
- const code = fs_1.default.readFileSync(filePath, 'utf8');
49
- if (code) {
50
- (0, lodash_3.set)(metadata, 'renderer.script', code);
51
- (0, lodash_3.set)(metadata, 'renderer.type', 'react-component');
52
- }
53
47
  return res.json(metadata);
54
48
  }
55
49
  catch (error) {
@@ -74,8 +68,6 @@ exports.initBlockStudioRouter.post('/', (req, res) => __awaiter(void 0, void 0,
74
68
  }
75
69
  const currentMetadata = (0, helper_1.initializeMetadata)(filePath);
76
70
  const mergedContent = Object.assign(Object.assign({}, currentMetadata), content);
77
- // remove renderer
78
- delete mergedContent.renderer;
79
71
  if ((0, lodash_1.isEqual)(currentMetadata, mergedContent)) {
80
72
  return res.json({ success: true, content: mergedContent, message: 'No changes' });
81
73
  }
@@ -98,15 +90,56 @@ exports.initBlockStudioRouter.post('/', (req, res) => __awaiter(void 0, void 0,
98
90
  return res.status(500).json({ error: 'Failed to write file' });
99
91
  }
100
92
  }));
93
+ exports.initBlockStudioRouter.post('/create', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
94
+ if (!helper_1.isDev) {
95
+ return res.status(403).json({ error: 'Only available in development mode' });
96
+ }
97
+ const { name, description } = req.body;
98
+ if (!name) {
99
+ return res.status(400).json({ error: 'Name is required' });
100
+ }
101
+ try {
102
+ const pattern = (0, helper_1.getBlockEntryFilesPattern)();
103
+ const baseDir = path_1.default.dirname(pattern.replace(/\*\*?/g, ''));
104
+ const blockDir = path_1.default.join(baseDir, name);
105
+ const metadataPath = path_1.default.join(blockDir, constants_1.METADATA_FILE_NAME);
106
+ const indexPath = path_1.default.join(blockDir, 'index.tsx');
107
+ // Check if block already exists
108
+ if (fs_1.default.existsSync(blockDir)) {
109
+ return res.status(409).json({ error: 'Block already exists' });
110
+ }
111
+ // Create block directory
112
+ fs_1.default.mkdirSync(blockDir, { recursive: true });
113
+ // Initialize metadata
114
+ let metadata = (0, helper_1.initializeMetadata)(metadataPath);
115
+ metadata.name = name;
116
+ metadata.description = description || '';
117
+ metadata.createdAt = new Date().toISOString();
118
+ metadata.updatedAt = new Date().toISOString();
119
+ // get template metadata from @metadata.json
120
+ const metadataContent = fs_1.default.readFileSync(constants_1.NEW_BLOCK_TEMPLATE_METADATA_PATH, 'utf-8');
121
+ metadata = Object.assign(Object.assign({}, metadata), (0, helper_1.safeParse)(metadataContent));
122
+ // Write metadata file
123
+ fs_1.default.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
124
+ // Copy template file to index.tsx
125
+ const templateContent = fs_1.default.readFileSync(constants_1.NEW_BLOCK_TEMPLATE_PATH, 'utf-8');
126
+ fs_1.default.writeFileSync(indexPath, templateContent);
127
+ return res.json({ success: true, metadata });
128
+ }
129
+ catch (error) {
130
+ console.error('Failed to create block:', error);
131
+ return res.status(500).json({ error: 'Failed to create block' });
132
+ }
133
+ }));
101
134
  exports.initBlockStudioRouter.get('/all', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
102
135
  const { withBlockletData = true } = req.query;
103
136
  const allBlocks = yield (0, helper_1.findComponentFiles)();
104
137
  // get code to metadata
105
138
  const allBlocksWithCode = allBlocks.map((block) => {
106
- const code = fs_1.default.readFileSync(block.fullPath, 'utf8');
139
+ const code = (0, helper_1.getBlockCode)(block.fullPath);
107
140
  if (code) {
108
- (0, lodash_3.set)(block.metadata, 'renderer.script', code);
109
- (0, lodash_3.set)(block.metadata, 'renderer.type', 'react-component');
141
+ (0, lodash_1.set)(block.metadata, 'renderer.script', code);
142
+ (0, lodash_1.set)(block.metadata, 'renderer.type', 'react-component');
110
143
  }
111
144
  return block;
112
145
  });
@@ -123,8 +156,8 @@ exports.initBlockStudioRouter.get('/all', (req, res) => __awaiter(void 0, void 0
123
156
  };
124
157
  return item;
125
158
  });
126
- return res.json((0, lodash_2.keyBy)(allBlocksWithBlockletData, 'data.id'));
159
+ return res.json((0, lodash_1.keyBy)(allBlocksWithBlockletData, 'data.id'));
127
160
  }
128
- res.json((0, lodash_2.keyBy)(allBlocksWithCode, 'id'));
161
+ return res.json((0, lodash_1.keyBy)(allBlocksWithCode, 'id'));
129
162
  }));
130
163
  exports.default = exports.initBlockStudioRouter;
@@ -140,7 +140,7 @@ exports.initResourceRouter.post('/', (req, res) => __awaiter(void 0, void 0, voi
140
140
  const buildProcess = (0, child_process_1.spawn)('pnpm', ['run', 'build-lib'], {
141
141
  stdio: 'inherit',
142
142
  shell: true,
143
- env: Object.assign(Object.assign({}, process.env), { FORCE_COLOR: '1', BLOCK_FILTER: componentIds.join(',') }),
143
+ env: Object.assign(Object.assign({}, process.env), { FORCE_COLOR: '1', BLOCK_FILTER: componentIds.join(','), NODE_OPTIONS: '--max_old_space_size=16384' }),
144
144
  });
145
145
  yield new Promise((resolve, reject) => {
146
146
  buildProcess.on('close', (code) => {
@@ -149,6 +149,10 @@ exports.initResourceRouter.post('/', (req, res) => __awaiter(void 0, void 0, voi
149
149
  else
150
150
  reject(new Error(`Build process exited with code ${code}`));
151
151
  });
152
+ buildProcess.on('error', (error) => {
153
+ console.error('Build process error:', error);
154
+ reject(error);
155
+ });
152
156
  });
153
157
  const dir = getExportDir(projectId, releaseId);
154
158
  fs_1.default.rmSync(dir, { recursive: true, force: true });
@@ -47,6 +47,7 @@ exports.initBlockStudioPlugins = initBlockStudioPlugins;
47
47
  // import typescript from '@rollup/plugin-typescript';
48
48
  const fs_1 = require("fs");
49
49
  const path = __importStar(require("path"));
50
+ const ufo_1 = require("ufo");
50
51
  const vite_plugin_react_pages_1 = __importStar(require("vite-plugin-react-pages"));
51
52
  const helper_1 = require("../utils/helper");
52
53
  const vite_plugin_html_transform_1 = require("./vite-plugin-html-transform");
@@ -108,18 +109,13 @@ function initBlockStudioPlugins(options) {
108
109
  formats: ['es', !multiMode ? 'umd' : 'cjs'],
109
110
  fileName: (format, entryName) => `${format}/${entryName}.js`,
110
111
  }, rollupOptions: {
111
- external: [
112
- 'react',
113
- 'react-router-dom',
114
- 'react-dom',
115
- 'react-is',
116
- 'react/jsx-runtime',
117
- 'crypto',
118
- // '@emotion/react',
119
- // '@emotion/styled',
120
- '@arcblock/ux',
121
- '@arcblock/did-connect',
122
- ],
112
+ external: (id) => {
113
+ const skip = ['react', 'crypto'];
114
+ if (skip.some((s) => id === s)) {
115
+ return true;
116
+ }
117
+ return false;
118
+ },
123
119
  output: {
124
120
  chunkFileNames: () => {
125
121
  return '[format]/_chunks/[name]-[hash].js';
@@ -127,22 +123,13 @@ function initBlockStudioPlugins(options) {
127
123
  // 为所有外部依赖提供全局变量
128
124
  globals: {
129
125
  react: 'React',
130
- 'react-dom': 'ReactDOM',
131
- 'react-is': 'ReactIs',
132
- 'react-router-dom': 'ReactRouterDOM',
133
- 'react/jsx-runtime': 'ReactJsxRuntime',
134
- // '@emotion/react': 'emotionReact',
135
- // '@emotion/styled': 'emotionStyled',
136
- '@mui/material': 'MUI',
137
- '@arcblock/ux': 'ArcBlockUX',
138
- '@arcblock/did-connect': 'ArcBlockDidConnect',
139
126
  },
140
127
  paths: {
141
- // Redirect 'react' imports to '@blocklet/pages-kit/builtin/react'
142
- // react: '@blocklet/pages-kit/builtin/react',
128
+ // Redirect 'react' imports to '@blocklet/pages-kit/builtin/react'
129
+ react: '@blocklet/pages-kit/builtin/react',
143
130
  },
144
131
  // 确保正确处理命名导出和默认导出
145
- // interop: 'auto',
132
+ interop: 'auto',
146
133
  },
147
134
  } }, _config === null || _config === void 0 ? void 0 : _config.build),
148
135
  };
@@ -162,20 +149,23 @@ function initBlockStudioPlugins(options) {
162
149
  const pageId = `/${blockName}`;
163
150
  const dirPath = path.dirname(filePath);
164
151
  const metadataPath = path.join(dirPath, '@metadata.json');
152
+ const dataPath = isHtml ? `${vite_plugin_html_transform_1.VIRTUAL_MODULE_ID}?dir=${dirPath}` : filePath;
165
153
  api.addPageData({
166
154
  pageId,
167
- dataPath: isHtml ? `${vite_plugin_html_transform_1.VIRTUAL_MODULE_ID}?dir=${dirPath}` : filePath,
155
+ dataPath,
168
156
  staticData: isHtml
169
157
  ? {
170
- isHtmlPreview: true,
171
- dataPath: filePath,
158
+ isHtml: true,
159
+ dataPath,
160
+ code: (0, vite_plugin_html_transform_1.generateComponent)((0, vite_plugin_html_transform_1.readHtmlFiles)(dirPath)),
172
161
  blockName,
173
162
  dirPath,
163
+ importPath: (0, ufo_1.joinURL)('@id', dataPath),
174
164
  metadataPath,
175
165
  }
176
- : Object.assign(Object.assign({}, (yield helpers.extractStaticData(file))), { code: (0, fs_1.readFileSync)(file.path, 'utf-8'), dataPath: filePath, blockName,
177
- dirPath,
178
- metadataPath }),
166
+ : Object.assign(Object.assign({}, (yield helpers.extractStaticData(file))), { code: (0, fs_1.readFileSync)(file.path, 'utf-8'), dataPath,
167
+ blockName,
168
+ dirPath, importPath: (0, ufo_1.joinURL)('@fs', dataPath), metadataPath }),
179
169
  });
180
170
  });
181
171
  });
@@ -196,6 +186,15 @@ function initBlockStudioPlugins(options) {
196
186
  // maxConcurrent: 5, // 可选,默认值
197
187
  // timeout: 30 * 1000, // 可选,默认值 30 秒
198
188
  // }),
189
+ {
190
+ name: 'build-force-exit',
191
+ apply: 'build',
192
+ enforce: 'post',
193
+ closeBundle() {
194
+ // ensure vite build exit
195
+ process.exit(0);
196
+ },
197
+ },
199
198
  ];
200
199
  }
201
200
  exports.default = initBlockStudioPlugins;
@@ -10,6 +10,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.RESOLVED_VIRTUAL_MODULE_ID = exports.VIRTUAL_MODULE_ID = void 0;
13
+ exports.readHtmlFiles = readHtmlFiles;
14
+ exports.generateComponent = generateComponent;
13
15
  exports.initHtmlPreviewTransformPlugin = initHtmlPreviewTransformPlugin;
14
16
  const fs_1 = require("fs");
15
17
  const path_1 = require("path");
@@ -19,6 +21,7 @@ exports.RESOLVED_VIRTUAL_MODULE_ID = `\0${exports.VIRTUAL_MODULE_ID}`;
19
21
  const isRelativePath = (path) => {
20
22
  return path.startsWith('./') || path.startsWith('../') || (!path.startsWith('http') && !path.startsWith('//'));
21
23
  };
24
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
22
25
  function extractExternalResources(html, _dirPath) {
23
26
  const external = {
24
27
  js: [],
@@ -168,10 +171,24 @@ ${content.trim()}`;
168
171
  <meta http-equiv="X-Content-Type-Options" content="nosniff">
169
172
  <meta http-equiv="Referrer-Policy" content="no-referrer">
170
173
  <meta http-equiv="Permissions-Policy" content="accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()">`;
174
+ const autoHeightScript = `<script>
175
+ (function() {
176
+ if ('ResizeObserver' in window) {
177
+ const resizeObserver = new ResizeObserver(() => {
178
+ const height = document.documentElement.scrollHeight;
179
+ window.parent.postMessage({ height }, '*');
180
+ });
181
+
182
+ resizeObserver.observe(document.documentElement);
183
+ }
184
+ })();
185
+ </script>`;
171
186
  // 将处理后的相对路径引入的 CSS 和 JS 注入到 HTML 中
172
187
  const htmlContent = htmlWithoutRelativeImport
173
188
  .replace('<head>', `<head>${securityHeaders}`)
174
189
  .replace('</head>', `${cssContents.map((css) => `<style>${css.trim()}</style>`).join('\n')}
190
+
191
+ ${autoHeightScript}
175
192
  </head>`)
176
193
  .replace('</body>', `
177
194
  ${jsContents.map((js) => `<script>${js}</script>`).join('\n')}
@@ -188,18 +205,41 @@ ${content.trim()}`;
188
205
  name: (0, path_1.basename)(dirPath),
189
206
  };
190
207
  }
208
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
191
209
  function generateComponent(content, _isDev = true) {
192
210
  const htmlContent = content.html;
193
211
  const { name } = content;
194
- return `import { createElement } from 'react';
212
+ return `import { createElement, useEffect, useRef } from 'react';
213
+
195
214
 
196
215
  export default function HtmlPreview() {
216
+ const iframeRef = useRef(null);
217
+
218
+ useEffect(() => {
219
+ const iframe = iframeRef.current;
220
+ if (!iframe) return;
221
+
222
+ const handleMessage = (event) => {
223
+ if (event.source === iframe.contentWindow) {
224
+ const height = event.data.height;
225
+ if (height) {
226
+ iframe.style.height = height + 'px';
227
+ }
228
+ }
229
+ };
230
+
231
+ window.addEventListener('message', handleMessage);
232
+ return () => window.removeEventListener('message', handleMessage);
233
+ }, []);
234
+
197
235
  return createElement('iframe', {
198
- style: { border: 'none', width: '100%', height: '100%' },
236
+ ref: iframeRef,
237
+ style: { border: 'none', width: '100%', height: '100%', maxHeight: '100vh' },
199
238
  sandbox: 'allow-scripts',
200
239
  title: 'Preview ${name}',
201
240
  srcDoc: ${htmlContent}
202
241
  });
242
+
203
243
  }`;
204
244
  }
205
245
  function initHtmlPreviewTransformPlugin() {