@nocobase/cli 2.0.0-beta.2 → 2.0.0-beta.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/cli",
3
- "version": "2.0.0-beta.2",
3
+ "version": "2.0.0-beta.21",
4
4
  "description": "",
5
5
  "license": "AGPL-3.0",
6
6
  "main": "./src/index.js",
@@ -8,8 +8,8 @@
8
8
  "nocobase": "./bin/index.js"
9
9
  },
10
10
  "dependencies": {
11
- "@nocobase/app": "2.0.0-beta.2",
12
- "@nocobase/license-kit": "^0.3.5",
11
+ "@nocobase/app": "2.0.0-beta.21",
12
+ "@nocobase/license-kit": "^0.3.7",
13
13
  "@types/fs-extra": "^11.0.1",
14
14
  "@umijs/utils": "3.5.20",
15
15
  "chalk": "^4.1.1",
@@ -27,12 +27,12 @@
27
27
  "tsx": "^4.19.0"
28
28
  },
29
29
  "devDependencies": {
30
- "@nocobase/devtools": "2.0.0-beta.2"
30
+ "@nocobase/devtools": "2.0.0-beta.21"
31
31
  },
32
32
  "repository": {
33
33
  "type": "git",
34
34
  "url": "git+https://github.com/nocobase/nocobase.git",
35
35
  "directory": "packages/core/cli"
36
36
  },
37
- "gitHead": "b77a33ee933ae6e09d2d5dce017ca15d8552d57b"
37
+ "gitHead": "3ea30685d9592934ec578c0b5e8def60a7fcc3c2"
38
38
  }
@@ -0,0 +1,166 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ const chalk = require('chalk');
11
+ const { Command } = require('commander');
12
+ const fs = require('fs-extra');
13
+ const { resolve } = require('path');
14
+
15
+ /**
16
+ * 复制主应用客户端文件
17
+ * @param {string} source - 源目录路径
18
+ * @param {string} target - 目标目录路径
19
+ */
20
+ async function copyMainClient(source, target) {
21
+ if (!(await fs.exists(source))) {
22
+ console.log(chalk.yellow(`Source directory does not exist: ${source}`));
23
+ return;
24
+ }
25
+ // 确保目标目录存在且为空
26
+ await fs.ensureDir(target);
27
+ await fs.emptyDir(target);
28
+ await fs.copy(source, target, { recursive: true });
29
+ console.log(chalk.green(`Copied main client files from ${source} to ${target}`));
30
+ }
31
+
32
+ /**
33
+ * 复制插件客户端文件
34
+ * @param {string} pluginsBaseDir - 插件基础目录路径
35
+ * @param {string} namespace - 命名空间(如 '@nocobase' 或 '@nocobase-example')
36
+ * @param {string} target - 目标目录
37
+ */
38
+ async function copyPluginClients(pluginsBaseDir, namespace, target) {
39
+ const pluginsDir = resolve(process.cwd(), pluginsBaseDir, namespace);
40
+ if (await fs.exists(pluginsDir)) {
41
+ const pluginNames = await fs.readdir(pluginsDir);
42
+ for (const pluginName of pluginNames) {
43
+ const pluginPath = resolve(pluginsDir, pluginName);
44
+ const pluginDistClient = resolve(pluginPath, 'dist/client');
45
+ if (await fs.exists(pluginDistClient)) {
46
+ const pluginTarget = resolve(target, 'static/plugins', namespace, pluginName, 'dist/client');
47
+ await fs.mkdir(resolve(pluginTarget, '..'), { recursive: true });
48
+ await fs.copy(pluginDistClient, pluginTarget, { recursive: true });
49
+ console.log(chalk.green(`Copied ${namespace}/${pluginName} client files`));
50
+ }
51
+ }
52
+ }
53
+ }
54
+
55
+ /**
56
+ * 递归上传目录到 OSS
57
+ * @param {Client} client - OSS 客户端实例
58
+ * @param {string} localDir - 本地目录路径
59
+ * @param {string} ossPrefix - OSS 对象前缀(目录路径)
60
+ */
61
+ async function uploadDirectoryToOSS(client, localDir, ossPrefix = '') {
62
+ if (!(await fs.exists(localDir))) {
63
+ console.log(chalk.yellow(`Directory does not exist: ${localDir}`));
64
+ return;
65
+ }
66
+
67
+ const stats = await fs.stat(localDir);
68
+ if (!stats.isDirectory()) {
69
+ throw new Error(`${localDir} is not a directory`);
70
+ }
71
+
72
+ const files = await fs.readdir(localDir);
73
+ let uploadedCount = 0;
74
+
75
+ for (const file of files) {
76
+ const filePath = resolve(localDir, file);
77
+ const fileStats = await fs.stat(filePath);
78
+
79
+ if (fileStats.isDirectory()) {
80
+ // 递归处理子目录
81
+ const subOssPrefix = ossPrefix ? `${ossPrefix}/${file}` : file;
82
+ const subCount = await uploadDirectoryToOSS(client, filePath, subOssPrefix);
83
+ uploadedCount += subCount;
84
+ } else {
85
+ // 上传文件
86
+ const ossKey = ossPrefix ? `${ossPrefix}/${file}` : file;
87
+ try {
88
+ await client.put(ossKey, filePath);
89
+ // console.log(chalk.green(`Uploaded: ${ossKey}`));
90
+ uploadedCount++;
91
+ } catch (error) {
92
+ console.error(chalk.red(`Failed to upload ${ossKey}:`), error.message);
93
+ throw error;
94
+ }
95
+ }
96
+ }
97
+
98
+ return uploadedCount;
99
+ }
100
+
101
+ /**
102
+ *
103
+ * @param {Command} cli
104
+ */
105
+ module.exports = (cli) => {
106
+ cli
107
+ .command('client:extract')
108
+ .allowUnknownOption()
109
+ .action(async () => {
110
+ const version = require('../../package.json').version;
111
+ const target = resolve(process.cwd(), 'storage/dist-client', version);
112
+ const mainClientSource = resolve(process.cwd(), 'node_modules/@nocobase/app/dist/client');
113
+ await copyMainClient(mainClientSource, target);
114
+ await copyPluginClients('packages/plugins', '@nocobase', target);
115
+ await copyPluginClients('packages/plugins', '@nocobase-example', target);
116
+ await copyPluginClients('packages/pro-plugins', '@nocobase', target);
117
+ });
118
+
119
+ cli
120
+ .command('client:upload')
121
+ .allowUnknownOption()
122
+ .action(async () => {
123
+ const version = require('../../package.json').version;
124
+ const target = resolve(process.cwd(), 'storage/dist-client', version);
125
+
126
+ // 检查必要的环境变量
127
+ if (
128
+ !process.env.CDN_ALI_OSS_ACCESS_KEY_ID ||
129
+ !process.env.CDN_ALI_OSS_ACCESS_KEY_SECRET ||
130
+ !process.env.CDN_ALI_OSS_BUCKET ||
131
+ !process.env.CDN_ALI_OSS_REGION
132
+ ) {
133
+ console.error(
134
+ chalk.red(
135
+ 'Missing required environment variables: CDN_ALI_OSS_ACCESS_KEY_ID, CDN_ALI_OSS_ACCESS_KEY_SECRET, CDN_ALI_OSS_BUCKET, CDN_ALI_OSS_REGION',
136
+ ),
137
+ );
138
+ process.exit(1);
139
+ }
140
+
141
+ const Client = require('ali-oss');
142
+
143
+ const client = new Client({
144
+ accessKeyId: process.env.CDN_ALI_OSS_ACCESS_KEY_ID,
145
+ accessKeySecret: process.env.CDN_ALI_OSS_ACCESS_KEY_SECRET,
146
+ bucket: process.env.CDN_ALI_OSS_BUCKET,
147
+ region: process.env.CDN_ALI_OSS_REGION,
148
+ });
149
+
150
+ if (!(await fs.exists(target))) {
151
+ console.error(chalk.red(`Target directory does not exist: ${target}`));
152
+ console.log(chalk.yellow('Please run "client:extract" first to generate the client files.'));
153
+ process.exit(1);
154
+ }
155
+
156
+ console.log(chalk.blue(`Uploading directory ${target} to OSS...`));
157
+ const ossPrefix = `${version}`;
158
+ try {
159
+ const uploadedCount = await uploadDirectoryToOSS(client, target, ossPrefix);
160
+ console.log(chalk.green(`Successfully uploaded ${uploadedCount} files to OSS`));
161
+ } catch (error) {
162
+ console.error(chalk.red('Upload failed:'), error);
163
+ process.exit(1);
164
+ }
165
+ });
166
+ };
@@ -38,6 +38,7 @@ module.exports = (cli) => {
38
38
  require('./pkg')(cli);
39
39
  require('./instance-id')(cli);
40
40
  require('./view-license-key')(cli);
41
+ require('./client')(cli);
41
42
  if (isPackageValid('@umijs/utils')) {
42
43
  require('./create-plugin')(cli);
43
44
  }
@@ -208,7 +208,7 @@ class PackageManager {
208
208
  showLicenseInfo(LicenseKeyError.notValid);
209
209
  }
210
210
  logger.error(`Login failed: ${this.baseURL}`);
211
- logger.error(error?.message || error);
211
+ logger.error(error?.message, { error });
212
212
  }
213
213
  }
214
214
 
@@ -283,7 +283,12 @@ module.exports = (cli) => {
283
283
  NOCOBASE_PKG_URL = 'https://pkg.nocobase.com/',
284
284
  NOCOBASE_PKG_USERNAME,
285
285
  NOCOBASE_PKG_PASSWORD,
286
+ DISABLE_PKG_DOWNLOAD,
286
287
  } = process.env;
288
+ if (DISABLE_PKG_DOWNLOAD === 'true') {
289
+ logger.info('Package download is disabled.');
290
+ return;
291
+ }
287
292
  let accessKeyId;
288
293
  let accessKeySecret;
289
294
  try {
@@ -32,6 +32,6 @@ module.exports = (cli) => {
32
32
  .command('pm2-stop')
33
33
  .allowUnknownOption()
34
34
  .action(() => {
35
- run('pm2', ['stop', 'all']);
35
+ run('pm2', ['kill']);
36
36
  });
37
37
  };
@@ -62,6 +62,7 @@ module.exports = (cli) => {
62
62
  if (descJson['devDependencies']?.['@nocobase/devtools']) {
63
63
  descJson['devDependencies']['@nocobase/devtools'] = stdout;
64
64
  }
65
+ descJson['resolutions'] = sourceJson['resolutions'];
65
66
  const json = deepmerge(descJson, sourceJson);
66
67
  await writeJSON(descPath, json, { spaces: 2, encoding: 'utf8' });
67
68
  await run('yarn', ['install']);
package/src/util.js CHANGED
@@ -295,14 +295,26 @@ function buildIndexHtml(force = false) {
295
295
  fs.copyFileSync(file, tpl);
296
296
  }
297
297
  const data = fs.readFileSync(tpl, 'utf-8');
298
- const replacedData = data
298
+ let replacedData = data
299
+ .replace(/\{\{env.CDN_BASE_URL\}\}/g, process.env.CDN_BASE_URL)
299
300
  .replace(/\{\{env.APP_PUBLIC_PATH\}\}/g, process.env.APP_PUBLIC_PATH)
301
+ .replace(/\{\{env.API_CLIENT_SHARE_TOKEN\}\}/g, process.env.API_CLIENT_SHARE_TOKEN || 'false')
300
302
  .replace(/\{\{env.API_CLIENT_STORAGE_TYPE\}\}/g, process.env.API_CLIENT_STORAGE_TYPE)
301
303
  .replace(/\{\{env.API_CLIENT_STORAGE_PREFIX\}\}/g, process.env.API_CLIENT_STORAGE_PREFIX)
302
304
  .replace(/\{\{env.API_BASE_URL\}\}/g, process.env.API_BASE_URL || process.env.API_BASE_PATH)
303
305
  .replace(/\{\{env.WS_URL\}\}/g, process.env.WEBSOCKET_URL || '')
304
306
  .replace(/\{\{env.WS_PATH\}\}/g, process.env.WS_PATH)
307
+ .replace(/\{\{env.ESM_CDN_BASE_URL\}\}/g, process.env.ESM_CDN_BASE_URL || '')
308
+ .replace(/\{\{env.ESM_CDN_SUFFIX\}\}/g, process.env.ESM_CDN_SUFFIX || '')
305
309
  .replace('src="/umi.', `src="${process.env.APP_PUBLIC_PATH}umi.`);
310
+
311
+ if (process.env.CDN_BASE_URL) {
312
+ const appBaseUrl = process.env.CDN_BASE_URL.replace(/\/+$/, '');
313
+ const appPublicPath = process.env.APP_PUBLIC_PATH.replace(/\/+$/, '');
314
+ const re1 = new RegExp(`src="${appPublicPath}/`, 'g');
315
+ const re2 = new RegExp(`href="${appPublicPath}/`, 'g');
316
+ replacedData = replacedData.replace(re1, `src="${appBaseUrl}/`).replace(re2, `href="${appBaseUrl}/`);
317
+ }
306
318
  fs.writeFileSync(file, replacedData, 'utf-8');
307
319
  }
308
320
 
@@ -360,6 +372,7 @@ exports.initEnv = function initEnv() {
360
372
  APP_PORT: 13000,
361
373
  API_BASE_PATH: '/api/',
362
374
  API_CLIENT_STORAGE_PREFIX: 'NOCOBASE_',
375
+ API_CLIENT_SHARE_TOKEN: 'false',
363
376
  API_CLIENT_STORAGE_TYPE: 'localStorage',
364
377
  // DB_DIALECT: 'sqlite',
365
378
  DB_STORAGE: 'storage/db/nocobase.sqlite',
@@ -383,8 +396,12 @@ exports.initEnv = function initEnv() {
383
396
  PLUGIN_STATICS_PATH: '/static/plugins/',
384
397
  LOGGER_BASE_PATH: 'storage/logs',
385
398
  APP_SERVER_BASE_URL: '',
399
+ APP_BASE_URL: '',
400
+ CDN_BASE_URL: '',
386
401
  APP_PUBLIC_PATH: '/',
387
402
  WATCH_FILE: resolve(process.cwd(), 'storage/app.watch.ts'),
403
+ ESM_CDN_BASE_URL: 'https://esm.sh',
404
+ ESM_CDN_SUFFIX: '',
388
405
  };
389
406
 
390
407
  if (
@@ -438,6 +455,16 @@ exports.initEnv = function initEnv() {
438
455
  process.env.__env_modified__ = true;
439
456
  }
440
457
 
458
+ if (!process.env.CDN_BASE_URL && process.env.APP_PUBLIC_PATH !== '/') {
459
+ process.env.CDN_BASE_URL = process.env.APP_PUBLIC_PATH;
460
+ }
461
+
462
+ if (process.env.CDN_BASE_URL.includes('http') && process.env.CDN_VERSION === 'auto') {
463
+ const version = require('../package.json').version;
464
+ process.env.CDN_BASE_URL = process.env.CDN_BASE_URL.replace(/\/+$/, '') + '/' + version + '/';
465
+ process.env.CDN_VERSION = '';
466
+ }
467
+
441
468
  if (!process.env.TZ) {
442
469
  const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
443
470
  process.env.TZ = getTimezonesByOffset(process.env.DB_TIMEZONE || timeZone);
@@ -24,8 +24,8 @@
24
24
  "@types/react-dom": "^18.0.0",
25
25
  "react-router-dom": "^6.30.1",
26
26
  "react-router": "^6.30.1",
27
+ "antd": "5.24.2",
27
28
  "async": "^3.2.6",
28
- "antd": "5.12.8",
29
29
  "rollup": "4.24.0",
30
30
  "semver": "^7.7.1"
31
31
  },