@blocklet/pages-kit-block-studio 0.6.13 → 0.6.15
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/middlewares/init-resource-router.js +7 -262
- package/lib/cjs/tsconfig.tsbuildinfo +1 -1
- package/lib/cjs/utils/build-lib.js +291 -42
- package/lib/cjs/utils/helper.js +38 -0
- package/lib/esm/middlewares/init-resource-router.js +8 -224
- package/lib/esm/tsconfig.tsbuildinfo +1 -1
- package/lib/esm/utils/build-lib.js +259 -43
- package/lib/esm/utils/helper.js +35 -0
- package/lib/types/middlewares/init-resource-router.d.ts +0 -3
- package/lib/types/tsconfig.tsbuildinfo +1 -1
- package/lib/types/utils/build-lib.d.ts +4 -2
- package/lib/types/utils/helper.d.ts +3 -0
- package/package.json +3 -3
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
/* eslint-disable no-await-in-loop */
|
|
2
2
|
/* eslint-disable no-console */
|
|
3
|
+
import { getMediaKitFileStream } from '@blocklet/uploader-server';
|
|
3
4
|
import chalk from 'chalk';
|
|
4
5
|
import { execSync, spawn } from 'child_process';
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import get from 'lodash/get';
|
|
8
|
+
import set from 'lodash/set';
|
|
9
|
+
import path, { join, basename } from 'path';
|
|
10
|
+
import ts from 'typescript';
|
|
11
|
+
import { findComponentFiles, libDir, getPreviewImageRelativePath, generateYaml, logger, getComponentScriptName, getEditComponentBlockName, getAigneOutputValueSchemaBlockName, getPropertiesSchemaBlockName, getGetServerSidePropsBlockName, copyRecursive, } from './helper';
|
|
12
|
+
async function performBuild(workingDir, componentIds) {
|
|
8
13
|
// Scan for all index files
|
|
9
14
|
const allBlocks = findComponentFiles({ cwd: workingDir }).map((entry) => {
|
|
10
15
|
return entry.blockName;
|
|
11
16
|
});
|
|
12
|
-
const filterModules = process.argv.includes('--filter')
|
|
13
|
-
? process.argv[process.argv.indexOf('--filter') + 1]?.split(',')
|
|
14
|
-
: process.env.BLOCK_FILTER?.split(',') || null;
|
|
15
17
|
const ignoreViteLog = process.argv.includes('--log') ? false : process.env.BLOCK_LOG !== 'true';
|
|
16
18
|
const multiMode = process.argv.includes('--multi') || process.env.BLOCK_MULTI === 'true';
|
|
17
|
-
const blocks = allBlocks.filter((name) => !
|
|
19
|
+
const blocks = allBlocks.filter((name) => !componentIds || componentIds.includes(name || ''));
|
|
18
20
|
if (!blocks.length) {
|
|
19
|
-
console.log(chalk.yellow('No components
|
|
20
|
-
throw new Error('No components
|
|
21
|
-
return;
|
|
21
|
+
console.log(chalk.yellow('No components found, please check has any component been selected'));
|
|
22
|
+
throw new Error('No components found, please check has any component been selected');
|
|
22
23
|
}
|
|
23
24
|
// Clean up the lib directory
|
|
24
25
|
await execSync(`rm -rf ${libDir}`, { cwd: workingDir });
|
|
@@ -26,51 +27,266 @@ export async function buildLib(options) {
|
|
|
26
27
|
// Start to build
|
|
27
28
|
console.log(chalk.cyan(`Start to build ${blocks.length} blocks in parallel\n`));
|
|
28
29
|
const canBuildBlocks = multiMode ? blocks : [blocks.join(',')];
|
|
29
|
-
const configFile = 'vite-lib.config';
|
|
30
|
-
const hasConfig = execSync(`ls ${configFile}
|
|
30
|
+
const configFile = 'vite-lib.config.ts';
|
|
31
|
+
const hasConfig = execSync(`ls ${configFile} 2>/dev/null || true`, {
|
|
31
32
|
cwd: workingDir,
|
|
32
33
|
encoding: 'utf-8',
|
|
33
34
|
}).trim() !== '';
|
|
35
|
+
await Promise.all(canBuildBlocks.map((blockName) => {
|
|
36
|
+
console.log(chalk.blue(`Building ${blockName} Block...`));
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const build = spawn('vite', [
|
|
39
|
+
'build',
|
|
40
|
+
'--filter',
|
|
41
|
+
`"${blockName}"`,
|
|
42
|
+
'--outDir',
|
|
43
|
+
libDir,
|
|
44
|
+
'--emptyOutDir=false',
|
|
45
|
+
hasConfig ? `--config ${configFile}.*` : '',
|
|
46
|
+
], {
|
|
47
|
+
stdio: ignoreViteLog ? ['inherit', 'ignore', 'ignore'] : 'inherit',
|
|
48
|
+
shell: true,
|
|
49
|
+
cwd: workingDir,
|
|
50
|
+
});
|
|
51
|
+
build.on('close', (code) => {
|
|
52
|
+
if (code === 0) {
|
|
53
|
+
console.log(chalk.green(`Build ${blockName} successfully`));
|
|
54
|
+
resolve();
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
reject(new Error(`Build failed with code ${code}`));
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
}));
|
|
62
|
+
console.log(chalk.green(`\nBuild ${blocks.length} blocks successfully`));
|
|
63
|
+
console.log(chalk.gray(`Generate the ${libDir} directory successfully`));
|
|
64
|
+
}
|
|
65
|
+
async function performPackaging({ exportDir, componentIds, workingDir }) {
|
|
66
|
+
if (exportDir) {
|
|
67
|
+
// Clear and create export directory
|
|
68
|
+
fs.rmSync(exportDir, { recursive: true, force: true });
|
|
69
|
+
fs.mkdirSync(exportDir, { recursive: true });
|
|
70
|
+
}
|
|
71
|
+
const distDir = join(workingDir, libDir);
|
|
72
|
+
const codeDir = join(distDir, 'es');
|
|
73
|
+
const tmpPackage = join(distDir, 'resource-blocklet');
|
|
74
|
+
fs.mkdirSync(tmpPackage, { recursive: true });
|
|
75
|
+
const pagesDir = join(tmpPackage, 'pages');
|
|
76
|
+
fs.mkdirSync(pagesDir, { recursive: true });
|
|
77
|
+
const componentsDir = join(tmpPackage, 'components');
|
|
78
|
+
fs.mkdirSync(componentsDir, { recursive: true });
|
|
79
|
+
const chunksDir = join(tmpPackage, 'chunks');
|
|
80
|
+
fs.mkdirSync(chunksDir, { recursive: true });
|
|
81
|
+
const chunksMapPath = join(codeDir, 'chunks-map.json');
|
|
82
|
+
const chunksMap = JSON.parse(fs.readFileSync(chunksMapPath, 'utf8'));
|
|
83
|
+
// Get components with metadata
|
|
84
|
+
const canUseComponents = findComponentFiles({
|
|
85
|
+
cwd: workingDir,
|
|
86
|
+
filter: componentIds,
|
|
87
|
+
strictExistMetadata: true,
|
|
88
|
+
});
|
|
89
|
+
// Process metadata files
|
|
90
|
+
const metadataList = await Promise.all(canUseComponents.map(async ({ fullPath, blockName, metadata: _metadata }) => {
|
|
91
|
+
const metadata = _metadata;
|
|
92
|
+
const jsName = `${blockName}.js`;
|
|
93
|
+
// Set version to 2
|
|
94
|
+
set(metadata, 'version', 2);
|
|
95
|
+
// Get main component code
|
|
96
|
+
const code = fs.readFileSync(join(codeDir, `${getComponentScriptName(blockName, 'esm')}.js`), 'utf8');
|
|
97
|
+
if (code) {
|
|
98
|
+
set(metadata, 'renderer.script', code);
|
|
99
|
+
set(metadata, 'renderer.type', 'react-component');
|
|
100
|
+
set(metadata, 'renderer.chunks', chunksMap[jsName] || []);
|
|
101
|
+
}
|
|
102
|
+
// Transpile to CJS
|
|
103
|
+
try {
|
|
104
|
+
const cjsCode = ts.transpileModule(code, {
|
|
105
|
+
compilerOptions: {
|
|
106
|
+
jsx: ts.JsxEmit.React,
|
|
107
|
+
target: ts.ScriptTarget.ES2016,
|
|
108
|
+
module: ts.ModuleKind.CommonJS,
|
|
109
|
+
moduleResolution: ts.ModuleResolutionKind.Node16,
|
|
110
|
+
},
|
|
111
|
+
}).outputText;
|
|
112
|
+
if (cjsCode) {
|
|
113
|
+
set(metadata, 'renderer.cjsScript', cjsCode);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
// ignore error
|
|
118
|
+
}
|
|
119
|
+
// Handle edit component code
|
|
120
|
+
try {
|
|
121
|
+
const editComponentJsName = `${getEditComponentBlockName(blockName)}.js`;
|
|
122
|
+
const editComponentCode = fs.readFileSync(join(codeDir, editComponentJsName), 'utf8');
|
|
123
|
+
if (editComponentCode) {
|
|
124
|
+
set(metadata, 'renderer.editComponent', editComponentCode);
|
|
125
|
+
set(metadata, 'renderer.chunks', Array.from(new Set([...get(metadata, 'renderer.chunks', []), ...(chunksMap[editComponentJsName] || [])])));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
// ignore error
|
|
130
|
+
}
|
|
131
|
+
// Handle aigne output value schema
|
|
132
|
+
try {
|
|
133
|
+
const aigneOutputValueSchemaJsName = `${getAigneOutputValueSchemaBlockName(blockName)}.js`;
|
|
134
|
+
const aigneOutputValueSchemaCode = fs.readFileSync(join(codeDir, aigneOutputValueSchemaJsName), 'utf8');
|
|
135
|
+
if (aigneOutputValueSchemaCode) {
|
|
136
|
+
set(metadata, 'renderer.aigneOutputValueSchema', aigneOutputValueSchemaCode);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
// ignore error
|
|
141
|
+
}
|
|
142
|
+
// Handle properties schema
|
|
143
|
+
try {
|
|
144
|
+
const propertiesSchemaJsName = `${getPropertiesSchemaBlockName(blockName)}.js`;
|
|
145
|
+
const propertiesSchemaCode = fs.readFileSync(join(codeDir, propertiesSchemaJsName), 'utf8');
|
|
146
|
+
if (propertiesSchemaCode) {
|
|
147
|
+
set(metadata, 'renderer.PROPERTIES_SCHEMA', propertiesSchemaCode);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
// ignore error
|
|
152
|
+
}
|
|
153
|
+
// Handle getServerSideProps
|
|
154
|
+
try {
|
|
155
|
+
const getServerSidePropsJsName = `${getGetServerSidePropsBlockName(blockName)}.js`;
|
|
156
|
+
const getServerSidePropsCode = fs.readFileSync(join(codeDir, getServerSidePropsJsName), 'utf8');
|
|
157
|
+
if (getServerSidePropsCode) {
|
|
158
|
+
set(metadata, 'renderer.getServerSideProps', getServerSidePropsCode);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
// ignore error
|
|
163
|
+
}
|
|
164
|
+
// Handle preview image
|
|
165
|
+
if (metadata.previewImage) {
|
|
166
|
+
const imagePath = path.join(path.dirname(fullPath), getPreviewImageRelativePath(metadata.previewImage));
|
|
167
|
+
const imageDestPath = path.join(componentsDir, metadata.previewImage);
|
|
168
|
+
if (fs.existsSync(imagePath)) {
|
|
169
|
+
fs.copyFileSync(imagePath, imageDestPath);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// Handle type:url properties
|
|
173
|
+
if (metadata.properties) {
|
|
174
|
+
const downloadPromises = [];
|
|
175
|
+
Object.keys(metadata.properties).forEach((key) => {
|
|
176
|
+
const property = metadata.properties[key].data;
|
|
177
|
+
if (property.type === 'url') {
|
|
178
|
+
Object.keys(property.locales).forEach((locale) => {
|
|
179
|
+
if (property.locales[locale].defaultValue?.mediaKitUrl?.startsWith('mediakit://')) {
|
|
180
|
+
const downloadPromise = (async () => {
|
|
181
|
+
try {
|
|
182
|
+
const fileName = basename(property.locales[locale].defaultValue.mediaKitUrl);
|
|
183
|
+
const targetPath = path.join(componentsDir, fileName);
|
|
184
|
+
if (fs.existsSync(targetPath)) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
// try to get image from preview image
|
|
188
|
+
const imagePathInPreview = path.join(path.dirname(fullPath), getPreviewImageRelativePath(fileName));
|
|
189
|
+
if (fs.existsSync(imagePathInPreview)) {
|
|
190
|
+
fs.copyFileSync(imagePathInPreview, targetPath);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const resWithStream = await getMediaKitFileStream(property.locales[locale].defaultValue.mediaKitUrl);
|
|
194
|
+
if (!resWithStream.data) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const writeStream = fs.createWriteStream(targetPath);
|
|
198
|
+
resWithStream.data.pipe(writeStream);
|
|
199
|
+
await new Promise((resolve, reject) => {
|
|
200
|
+
writeStream.on('finish', () => {
|
|
201
|
+
property.locales[locale].defaultValue.url = property.locales[locale].defaultValue.mediaKitUrl;
|
|
202
|
+
resolve();
|
|
203
|
+
});
|
|
204
|
+
writeStream.on('error', reject);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
console.error('Download media kit file failed:', error.message);
|
|
209
|
+
}
|
|
210
|
+
})();
|
|
211
|
+
downloadPromises.push(downloadPromise);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
if (downloadPromises.length > 0) {
|
|
217
|
+
await Promise.allSettled(downloadPromises);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// Write metadata file
|
|
221
|
+
const metadataYmlPath = path.join(componentsDir, `${metadata.name || 'unnamed'}.${metadata.id}.yml`);
|
|
222
|
+
fs.writeFileSync(metadataYmlPath, generateYaml(metadata));
|
|
223
|
+
return metadata;
|
|
224
|
+
}));
|
|
225
|
+
// Copy chunks directory
|
|
226
|
+
await copyRecursive(join(codeDir, 'chunks'), chunksDir);
|
|
227
|
+
// Generate pages.config.yml
|
|
228
|
+
const pagesConfigPath = path.join(tmpPackage, '.blocklet/pages/pages.config.yml');
|
|
229
|
+
fs.mkdirSync(path.dirname(pagesConfigPath), { recursive: true });
|
|
230
|
+
const pagesConfig = {
|
|
231
|
+
version: 2,
|
|
232
|
+
pages: [],
|
|
233
|
+
components: metadataList.map((metadata) => ({
|
|
234
|
+
id: metadata.id,
|
|
235
|
+
name: metadata.name,
|
|
236
|
+
})),
|
|
237
|
+
supportedLocales: [],
|
|
238
|
+
config: {},
|
|
239
|
+
};
|
|
240
|
+
fs.writeFileSync(pagesConfigPath, generateYaml(pagesConfig));
|
|
241
|
+
logger.info('generate resource blocklet block count:', metadataList.length);
|
|
242
|
+
if (exportDir) {
|
|
243
|
+
// Copy to target directory
|
|
244
|
+
await copyRecursive(tmpPackage, exportDir);
|
|
245
|
+
console.log(chalk.green(`Package exported to: ${exportDir}`));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
export async function buildLib(options = {}) {
|
|
249
|
+
const workingDir = options?.cwd || process.cwd();
|
|
250
|
+
const filterModules = process.argv.includes('--filter')
|
|
251
|
+
? process.argv[process.argv.indexOf('--filter') + 1]?.split(',')
|
|
252
|
+
: process.env.BLOCK_FILTER?.split(',');
|
|
253
|
+
// Get parameters from environment variables
|
|
254
|
+
const componentIds = filterModules ?? null;
|
|
255
|
+
const exportDir = process.argv.includes('--export-dir')
|
|
256
|
+
? process.argv[process.argv.indexOf('--export-dir') + 1]
|
|
257
|
+
: process.env.EXPORT_DIR;
|
|
34
258
|
try {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
'--emptyOutDir=false',
|
|
45
|
-
hasConfig ? `--config ${configFile}.*` : '',
|
|
46
|
-
], {
|
|
47
|
-
stdio: ignoreViteLog ? ['inherit', 'ignore', 'ignore'] : 'inherit',
|
|
48
|
-
shell: true,
|
|
49
|
-
cwd: workingDir,
|
|
50
|
-
});
|
|
51
|
-
build.on('close', (code) => {
|
|
52
|
-
if (code === 0) {
|
|
53
|
-
console.log(chalk.green(`Build ${blockName} successfully`));
|
|
54
|
-
resolve();
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
reject(new Error(`Build failed with code ${code}`));
|
|
58
|
-
}
|
|
59
|
-
});
|
|
259
|
+
// Phase 1: Build components
|
|
260
|
+
await performBuild(workingDir, componentIds);
|
|
261
|
+
console.log(chalk.green('Build completed successfully'));
|
|
262
|
+
// Phase 2: Package resources (if export directory is specified)
|
|
263
|
+
if (exportDir) {
|
|
264
|
+
await performPackaging({
|
|
265
|
+
exportDir,
|
|
266
|
+
componentIds,
|
|
267
|
+
workingDir,
|
|
60
268
|
});
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
console.log(chalk.gray(`Generate the ${libDir} directory successfully`));
|
|
64
|
-
process.exit(0);
|
|
269
|
+
console.log(chalk.green('Package completed successfully'));
|
|
270
|
+
}
|
|
65
271
|
}
|
|
66
272
|
catch (err) {
|
|
67
273
|
console.error(chalk.red('Build failed:'), err);
|
|
68
|
-
process.
|
|
274
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
275
|
+
process.exit(1);
|
|
276
|
+
}
|
|
277
|
+
throw err;
|
|
278
|
+
}
|
|
279
|
+
finally {
|
|
280
|
+
process.exit(0);
|
|
69
281
|
}
|
|
70
282
|
}
|
|
71
283
|
const cwdArg = process.argv.indexOf('--cwd');
|
|
72
284
|
const cwd = cwdArg !== -1 ? process.argv[cwdArg + 1] : undefined;
|
|
73
|
-
buildLib({ cwd })
|
|
285
|
+
buildLib({ cwd })
|
|
286
|
+
.catch((err) => {
|
|
74
287
|
console.error(chalk.red('Build failed:'), err);
|
|
75
288
|
process.exit(1);
|
|
289
|
+
})
|
|
290
|
+
.finally(() => {
|
|
291
|
+
process.exit(0);
|
|
76
292
|
});
|
package/lib/esm/utils/helper.js
CHANGED
|
@@ -202,3 +202,38 @@ export const GET_SERVER_SIDE_PROPS_NAME = 'getServerSideProps';
|
|
|
202
202
|
export const getGetServerSidePropsBlockName = (blockName) => {
|
|
203
203
|
return `${blockName}(${GET_SERVER_SIDE_PROPS_NAME})`;
|
|
204
204
|
};
|
|
205
|
+
export function copyFile(src, dest) {
|
|
206
|
+
return new Promise((resolve, reject) => {
|
|
207
|
+
const readStream = fs.createReadStream(src);
|
|
208
|
+
const writeStream = fs.createWriteStream(dest);
|
|
209
|
+
readStream.on('error', reject);
|
|
210
|
+
writeStream.on('error', reject);
|
|
211
|
+
writeStream.on('finish', resolve);
|
|
212
|
+
readStream.pipe(writeStream);
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
export async function copyDirectory(src, dest) {
|
|
216
|
+
await fs.promises.mkdir(dest, { recursive: true });
|
|
217
|
+
const entries = await fs.promises.readdir(src, { withFileTypes: true });
|
|
218
|
+
for (const entry of entries) {
|
|
219
|
+
const srcPath = path.join(src, entry.name);
|
|
220
|
+
const destPath = path.join(dest, entry.name);
|
|
221
|
+
if (entry.isDirectory()) {
|
|
222
|
+
// eslint-disable-next-line no-await-in-loop
|
|
223
|
+
await copyDirectory(srcPath, destPath);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
// eslint-disable-next-line no-await-in-loop
|
|
227
|
+
await copyFile(srcPath, destPath);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
export async function copyRecursive(src, dest) {
|
|
232
|
+
const srcStats = await fs.promises.stat(src);
|
|
233
|
+
if (srcStats.isDirectory()) {
|
|
234
|
+
await copyDirectory(src, dest);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
await copyFile(src, dest);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
export declare function copyFile(src: string, dest: string): Promise<void>;
|
|
2
|
-
export declare function copyDirectory(src: string, dest: string): Promise<void>;
|
|
3
|
-
export declare function copyRecursive(src: string, dest: string): Promise<void>;
|
|
4
1
|
export declare const initResourceRouter: import("express-ws").Router;
|
|
5
2
|
export default initResourceRouter;
|