@nocobase/cli-v1 3.0.0-alpha.1 → 3.0.0-alpha.11
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/nocobase.conf.tpl +22 -8
- package/package.json +4 -4
- package/src/__tests__/build-index-html.test.js +14 -0
- package/src/__tests__/create-nginx-conf.test.js +20 -1
- package/src/__tests__/dev-command.test.js +10 -0
- package/src/commands/create-nginx-conf.js +3 -0
- package/src/commands/docs.js +7 -1
- package/src/util.js +1 -1
package/nocobase.conf.tpl
CHANGED
|
@@ -214,14 +214,28 @@ server {
|
|
|
214
214
|
|
|
215
215
|
|
|
216
216
|
|
|
217
|
-
location
|
|
217
|
+
location = {{publicPath}}{{portalClientPrefix}} {
|
|
218
218
|
absolute_redirect off;
|
|
219
|
+
return 302 {{v2PublicPath}}$is_args$args;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
location = {{publicPath}}{{portalClientPrefix}}/ {
|
|
223
|
+
absolute_redirect off;
|
|
224
|
+
return 302 {{v2PublicPath}}$is_args$args;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
location ^~ {{publicPath}}{{portalClientPrefix}}/apps/ {
|
|
228
|
+
absolute_redirect off;
|
|
229
|
+
|
|
230
|
+
if ($uri ~ ^{{publicPath}}{{portalClientPrefix}}/apps/(?<subapp>[A-Za-z0-9_-]+)/?$) {
|
|
231
|
+
return 302 {{v2PublicPath}}apps/$subapp/$is_args$args;
|
|
232
|
+
}
|
|
219
233
|
|
|
220
|
-
if ($uri ~ ^{{publicPath}}
|
|
221
|
-
return 308 {{publicPath}}
|
|
234
|
+
if ($uri ~ ^{{publicPath}}{{portalClientPrefix}}/apps/(?<subapp>[A-Za-z0-9_-]+)/(?<portal>[A-Za-z0-9_-]+)$) {
|
|
235
|
+
return 308 {{publicPath}}{{portalClientPrefix}}/apps/$subapp/$portal/$is_args$args;
|
|
222
236
|
}
|
|
223
237
|
|
|
224
|
-
if ($uri !~ ^{{publicPath}}
|
|
238
|
+
if ($uri !~ ^{{publicPath}}{{portalClientPrefix}}/apps/(?<subapp>[A-Za-z0-9_-]+)/(?<portal>[A-Za-z0-9_-]+)/(?<portal_path>.*)$) {
|
|
225
239
|
return 404;
|
|
226
240
|
}
|
|
227
241
|
|
|
@@ -238,14 +252,14 @@ server {
|
|
|
238
252
|
=404;
|
|
239
253
|
}
|
|
240
254
|
|
|
241
|
-
location ^~ {{publicPath}}
|
|
255
|
+
location ^~ {{publicPath}}{{portalClientPrefix}}/ {
|
|
242
256
|
absolute_redirect off;
|
|
243
257
|
|
|
244
|
-
if ($uri ~ ^{{publicPath}}
|
|
245
|
-
return 308 {{publicPath}}
|
|
258
|
+
if ($uri ~ ^{{publicPath}}{{portalClientPrefix}}/(?<portal>[A-Za-z0-9_-]+)$) {
|
|
259
|
+
return 308 {{publicPath}}{{portalClientPrefix}}/$portal/$is_args$args;
|
|
246
260
|
}
|
|
247
261
|
|
|
248
|
-
if ($uri !~ ^{{publicPath}}
|
|
262
|
+
if ($uri !~ ^{{publicPath}}{{portalClientPrefix}}/(?<portal>[A-Za-z0-9_-]+)/(?<portal_path>.*)$) {
|
|
249
263
|
return 404;
|
|
250
264
|
}
|
|
251
265
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/cli-v1",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.11",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"nocobase-v1": "./bin/index.js"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@nocobase/cli": "3.0.0-alpha.
|
|
12
|
+
"@nocobase/cli": "3.0.0-alpha.11",
|
|
13
13
|
"@nocobase/license-kit": "^0.3.8",
|
|
14
|
-
"@nocobase/utils": "3.0.0-alpha.
|
|
14
|
+
"@nocobase/utils": "3.0.0-alpha.11",
|
|
15
15
|
"chalk": "^4.1.1",
|
|
16
16
|
"commander": "^9.2.0",
|
|
17
17
|
"deepmerge": "^4.3.1",
|
|
@@ -33,5 +33,5 @@
|
|
|
33
33
|
"url": "git+https://github.com/nocobase/nocobase.git",
|
|
34
34
|
"directory": "packages/core/cli"
|
|
35
35
|
},
|
|
36
|
-
"gitHead": "
|
|
36
|
+
"gitHead": "03574f3a2d10b1ed8469dc7405aa0c4696d6d1d1"
|
|
37
37
|
}
|
|
@@ -87,6 +87,20 @@ describe('cli-v1 buildIndexHtml', () => {
|
|
|
87
87
|
fs.removeSync(appRoot);
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
+
test('injects settings-default as a valid client entry mode', () => {
|
|
91
|
+
const appRoot = createAppPackageRoot();
|
|
92
|
+
process.argv = ['node', 'nocobase-v1', 'start'];
|
|
93
|
+
process.env.APP_PACKAGE_ROOT = appRoot;
|
|
94
|
+
process.env.APP_PUBLIC_PATH = '/';
|
|
95
|
+
process.env.APP_CLIENT_ENTRY_MODE = 'settings-default';
|
|
96
|
+
|
|
97
|
+
buildIndexHtml();
|
|
98
|
+
|
|
99
|
+
const html = fs.readFileSync(path.join(appRoot, 'dist/client/index.html'), 'utf-8');
|
|
100
|
+
expect(html).toContain("window['__nocobase_app_client_entry_mode__'] = 'settings-default';");
|
|
101
|
+
fs.removeSync(appRoot);
|
|
102
|
+
});
|
|
103
|
+
|
|
90
104
|
test('refreshes cached tpl when new runtime placeholders are missing', () => {
|
|
91
105
|
const appRoot = createAppPackageRoot();
|
|
92
106
|
const tplPath = path.join(appRoot, 'dist/client/index.html.tpl');
|
|
@@ -15,7 +15,7 @@ const path = require('path');
|
|
|
15
15
|
|
|
16
16
|
const registerCreateNginxConf = require('../commands/create-nginx-conf');
|
|
17
17
|
|
|
18
|
-
describe('create-nginx-conf
|
|
18
|
+
describe('create-nginx-conf routing', () => {
|
|
19
19
|
const originalEnv = { ...process.env };
|
|
20
20
|
let storagePath;
|
|
21
21
|
|
|
@@ -65,4 +65,23 @@ describe('create-nginx-conf Settings SPA routing', () => {
|
|
|
65
65
|
expect(config).toContain('try_files $uri $uri/ /index.html;');
|
|
66
66
|
},
|
|
67
67
|
);
|
|
68
|
+
|
|
69
|
+
test.each([
|
|
70
|
+
['root mount', '/', '/x', '/v/'],
|
|
71
|
+
['custom public path', '/nocobase/', '/nocobase/x', '/nocobase/v/'],
|
|
72
|
+
])('redirects Portal roots to the Modern Client for %s', async (_label, publicPath, portalRoot, modernRoot) => {
|
|
73
|
+
const config = await renderConfig(publicPath);
|
|
74
|
+
|
|
75
|
+
expect(config).toContain(`location = ${portalRoot} {
|
|
76
|
+
absolute_redirect off;
|
|
77
|
+
return 302 ${modernRoot}$is_args$args;
|
|
78
|
+
}`);
|
|
79
|
+
expect(config).toContain(`location = ${portalRoot}/ {
|
|
80
|
+
absolute_redirect off;
|
|
81
|
+
return 302 ${modernRoot}$is_args$args;
|
|
82
|
+
}`);
|
|
83
|
+
expect(config).toContain(`return 302 ${modernRoot}$is_args$args;`);
|
|
84
|
+
expect(config).toContain(`if ($uri ~ ^${portalRoot}/apps/(?<subapp>[A-Za-z0-9_-]+)/?$) {`);
|
|
85
|
+
expect(config).toContain(`return 302 ${modernRoot}apps/$subapp/$is_args$args;`);
|
|
86
|
+
});
|
|
68
87
|
});
|
|
@@ -67,6 +67,16 @@ describe('cli-v1 dev command', () => {
|
|
|
67
67
|
});
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
+
test('resolveDevRuntimeMode keeps all clients in settings-default', () => {
|
|
71
|
+
expect(resolveDevRuntimeMode({ appClientEntryMode: 'settings-default' })).toMatchObject({
|
|
72
|
+
useModernOnlyEntryMode: false,
|
|
73
|
+
shouldRunClient: true,
|
|
74
|
+
shouldRunClientV2: true,
|
|
75
|
+
shouldRunSettings: true,
|
|
76
|
+
shouldRunServer: true,
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
70
80
|
test('resolveDevRuntimeMode preserves explicit client-v2-only flag behavior', () => {
|
|
71
81
|
expect(resolveDevRuntimeMode({ clientV2Only: true, appClientEntryMode: 'legacy-default' })).toMatchObject({
|
|
72
82
|
useModernOnlyEntryMode: false,
|
|
@@ -11,6 +11,8 @@ const { resolve, posix } = require('path');
|
|
|
11
11
|
const { storagePathJoin, resolvePublicPath, resolveV2PublicPath, normalizeModernClientPrefix } = require('../util');
|
|
12
12
|
const { readFileSync, writeFileSync } = require('fs');
|
|
13
13
|
|
|
14
|
+
const PORTAL_CLIENT_PREFIX = 'x';
|
|
15
|
+
|
|
14
16
|
function escapeRegExp(value) {
|
|
15
17
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
16
18
|
}
|
|
@@ -70,6 +72,7 @@ module.exports = (cli) => {
|
|
|
70
72
|
.replace(/\{\{distPath\}\}/g, distPath)
|
|
71
73
|
.replace(/\{\{v2PublicPath\}\}/g, v2PublicPath)
|
|
72
74
|
.replace(/\{\{v2PublicPathNoTrailingSlash\}\}/g, v2PublicPathWithoutTrailingSlash)
|
|
75
|
+
.replace(/\{\{portalClientPrefix\}\}/g, PORTAL_CLIENT_PREFIX)
|
|
73
76
|
.replace(/\{\{settingsAssetsPath\}\}/g, settingsAssetsPath)
|
|
74
77
|
.replace(/\{\{settingsDocumentPattern\}\}/g, settingsDocumentPattern)
|
|
75
78
|
.replace(/\{\{apiPort\}\}/g, process.env.APP_PORT)
|
package/src/commands/docs.js
CHANGED
|
@@ -57,6 +57,8 @@ function createCdnClient() {
|
|
|
57
57
|
* @param {string} timestampDir
|
|
58
58
|
*/
|
|
59
59
|
const REWRITE_RULES = [
|
|
60
|
+
// AI API 请求保持原路径,避免被后续规则补上文档版本的时间戳前缀
|
|
61
|
+
{ sourceUrl: '^/api/ai/(.*)$', targetTemplate: () => '/api/ai/$1', flag: 'break' },
|
|
60
62
|
// /en/ 下无后缀的页面路由,去掉 /en/ 前缀并改写到目录式 index.html
|
|
61
63
|
{ sourceUrl: '^/en/([^.]*[^/.])$', targetTemplate: (ts) => `/${ts}/$1/index.html`, flag: 'break' },
|
|
62
64
|
// 其他语言和默认语言的无后缀页面路由,统一改写到目录式 index.html
|
|
@@ -147,7 +149,11 @@ async function waitForRewriteRule(cdnClient, domain, timestampDir) {
|
|
|
147
149
|
if (!config) return false;
|
|
148
150
|
const args = config.functionArgs?.functionArg || [];
|
|
149
151
|
const targetArg = args.find((a) => a.argName === 'target_url');
|
|
150
|
-
|
|
152
|
+
const expectedTarget = rule.targetTemplate(timestampDir);
|
|
153
|
+
const targetMatches = expectedTarget.startsWith(expectedPrefix)
|
|
154
|
+
? (targetArg?.argValue || '').startsWith(expectedPrefix)
|
|
155
|
+
: targetArg?.argValue === expectedTarget;
|
|
156
|
+
return config.status === 'success' && targetMatches;
|
|
151
157
|
});
|
|
152
158
|
|
|
153
159
|
if (allEffective) {
|
package/src/util.js
CHANGED
|
@@ -433,7 +433,7 @@ const DEFAULT_MODERN_CLIENT_PREFIX = 'v';
|
|
|
433
433
|
exports.DEFAULT_MODERN_CLIENT_PREFIX = DEFAULT_MODERN_CLIENT_PREFIX;
|
|
434
434
|
|
|
435
435
|
const DEFAULT_APP_CLIENT_ENTRY_MODE = 'legacy-default';
|
|
436
|
-
const APP_CLIENT_ENTRY_MODES = new Set(['legacy-default', 'modern-default', 'modern-only']);
|
|
436
|
+
const APP_CLIENT_ENTRY_MODES = new Set(['legacy-default', 'modern-default', 'modern-only', 'settings-default']);
|
|
437
437
|
|
|
438
438
|
exports.DEFAULT_APP_CLIENT_ENTRY_MODE = DEFAULT_APP_CLIENT_ENTRY_MODE;
|
|
439
439
|
|