@nocobase/app 2.1.31 → 2.2.0-alpha.10

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 (23) hide show
  1. package/client/public/browser-checker.js +58 -0
  2. package/client/rsbuild.config.ts +21 -0
  3. package/client-v2/rsbuild.config.ts +66 -0
  4. package/dist/client/assets/{index-6426e795.js → index-baf26099.js} +507 -378
  5. package/dist/client/assets/{vendor-antd-a0dccf46.js → vendor-antd-f421fb70.js} +8 -8
  6. package/dist/client/assets/{vendor-diagram-686f3f07.js → vendor-diagram-c90b5083.js} +2 -2
  7. package/dist/client/assets/{vendor-lodash-97b39f5f.js → vendor-lodash-c512d103.js} +2 -2
  8. package/dist/client/assets/{vendor-misc-c30c528b.js → vendor-misc-47bbd442.js} +3 -3
  9. package/dist/client/browser-checker.js +58 -0
  10. package/dist/client/index.html +3 -1
  11. package/dist/client/index.html.tpl +3 -1
  12. package/dist/client/v/assets/{8384-4b58de2e.js → 8384-1634db4d.js} +2 -2
  13. package/dist/client/v/assets/index-372e693c.js +1843 -0
  14. package/dist/client/v/assets/{vendor-antd-f8c3ace1.js → vendor-antd-155a4c9b.js} +8 -8
  15. package/dist/client/v/index.html +1 -1
  16. package/package.json +7 -7
  17. package/dist/client/v/assets/index-17b108fa.js +0 -1714
  18. /package/dist/client/assets/{index-6426e795.js.LICENSE.txt → index-baf26099.js.LICENSE.txt} +0 -0
  19. /package/dist/client/assets/{vendor-diagram-686f3f07.js.LICENSE.txt → vendor-diagram-c90b5083.js.LICENSE.txt} +0 -0
  20. /package/dist/client/assets/{vendor-lodash-97b39f5f.js.LICENSE.txt → vendor-lodash-c512d103.js.LICENSE.txt} +0 -0
  21. /package/dist/client/assets/{vendor-misc-c30c528b.js.LICENSE.txt → vendor-misc-47bbd442.js.LICENSE.txt} +0 -0
  22. /package/dist/client/v/assets/{8384-4b58de2e.js.LICENSE.txt → 8384-1634db4d.js.LICENSE.txt} +0 -0
  23. /package/dist/client/v/assets/{index-17b108fa.js.LICENSE.txt → index-372e693c.js.LICENSE.txt} +0 -0
@@ -17,9 +17,31 @@ function normalizePublicPath(value) {
17
17
  return ensureTrailingSlash(normalized);
18
18
  }
19
19
 
20
+ function trimTrailingSlash(value) {
21
+ return value === '/' ? value : value.replace(/\/+$/g, '');
22
+ }
23
+
24
+ function normalizePathname(value) {
25
+ const normalized = ensureLeadingSlash(String(value || '/').trim() || '/').replace(/\/{2,}/g, '/');
26
+ if (normalized !== '/' && normalized.endsWith('/')) {
27
+ return normalized.replace(/\/+$/g, '');
28
+ }
29
+ return normalized;
30
+ }
31
+
32
+ function isClientDocumentEntryPath(pathname) {
33
+ const normalized = normalizePathname(pathname);
34
+ return normalized === '/' || normalized === '/index.html' || !/\.[^/]+$/.test(normalized);
35
+ }
36
+
20
37
  const basename = normalizePublicPath(window['__nocobase_public_path__'] || '/');
21
38
  const currentPath = ensureLeadingSlash(String(window.location.pathname || '/').trim() || '/').replace(/\/{2,}/g, '/');
22
39
  const basenameWithoutTrailingSlash = basename === '/' ? '/' : basename.replace(/\/+$/, '');
40
+ const modernClientPrefix =
41
+ String(window['__nocobase_modern_client_prefix__'] || 'v')
42
+ .trim()
43
+ .replace(/^\/+|\/+$/g, '') || 'v';
44
+ const appClientEntryMode = window['__nocobase_app_client_entry_mode__'];
23
45
 
24
46
  if (basename !== '/' && currentPath === basenameWithoutTrailingSlash) {
25
47
  const newUrl = `${window.location.origin}${basename}${window.location.search}${window.location.hash}`;
@@ -28,6 +50,42 @@ if (basename !== '/' && currentPath === basenameWithoutTrailingSlash) {
28
50
  const newPath = currentPath === '/' ? basename : `${basenameWithoutTrailingSlash}${currentPath}`;
29
51
  let newUrl = window.location.origin + newPath + window.location.search + window.location.hash;
30
52
  window.location.replace(newUrl);
53
+ } else {
54
+ // This client-side redirect is still needed because legacy `index.html` is
55
+ // not always served through the node gateway. In nginx/static delivery paths
56
+ // the browser may already be running the legacy shell by the time entry-mode
57
+ // logic is evaluated, so the last hop into the modern entry has to be
58
+ // recoverable in the browser as well.
59
+ const normalizedPath = normalizePathname(currentPath);
60
+ const relativePath =
61
+ basename === '/'
62
+ ? normalizedPath
63
+ : normalizedPath === basenameWithoutTrailingSlash
64
+ ? '/'
65
+ : normalizedPath.startsWith(basename)
66
+ ? normalizePathname(normalizedPath.slice(basename.length - 1))
67
+ : null;
68
+ const modernBase = `${trimTrailingSlash(basename)}/${modernClientPrefix}/`.replace(/\/{2,}/g, '/');
69
+ const isModernDefault = appClientEntryMode === 'modern-default';
70
+ const isModernOnly = appClientEntryMode === 'modern-only';
71
+ if (
72
+ relativePath &&
73
+ isClientDocumentEntryPath(relativePath) &&
74
+ (isModernDefault || isModernOnly) &&
75
+ !normalizedPath.startsWith(modernBase)
76
+ ) {
77
+ const targetPath = isModernDefault
78
+ ? relativePath === '/' || relativePath === '/index.html'
79
+ ? relativePath === '/index.html'
80
+ ? `${modernBase}index.html`
81
+ : modernBase
82
+ : null
83
+ : `${trimTrailingSlash(modernBase)}${relativePath}`;
84
+ if (targetPath && targetPath !== currentPath) {
85
+ const newUrl = window.location.origin + targetPath + window.location.search + window.location.hash;
86
+ window.location.replace(newUrl);
87
+ }
88
+ }
31
89
  }
32
90
  let showLog = true;
33
91
  function log(m) {
@@ -47,9 +47,16 @@ function toDefineLiteral(value: string | undefined) {
47
47
  }
48
48
 
49
49
  function createRuntimeHeadScript(appPublicPath: string, isBuild: boolean) {
50
+ const modernClientPrefix =
51
+ String(process.env.APP_MODERN_CLIENT_PREFIX || 'v')
52
+ .trim()
53
+ .replace(/^\/+|\/+$/g, '') || 'v';
54
+ const appClientEntryMode = process.env.APP_CLIENT_ENTRY_MODE;
50
55
  if (!isBuild) {
51
56
  return [
52
57
  `window['__nocobase_public_path__'] = ${JSON.stringify(appPublicPath)};`,
58
+ `window['__nocobase_modern_client_prefix__'] = ${JSON.stringify(modernClientPrefix)};`,
59
+ `window['__nocobase_app_client_entry_mode__'] = ${JSON.stringify(appClientEntryMode)};`,
53
60
  `window['__nocobase_dev_public_path__'] = "/";`,
54
61
  `window['__nocobase_app_dev__'] = ${JSON.stringify(process.env.NOCOBASE_APP_DEV === 'true')};`,
55
62
  `window['__esm_cdn_base_url__'] = ${JSON.stringify(process.env.ESM_CDN_BASE_URL || '')};`,
@@ -60,6 +67,8 @@ function createRuntimeHeadScript(appPublicPath: string, isBuild: boolean) {
60
67
  return [
61
68
  `window['__webpack_public_path__'] = '{{env.CDN_BASE_URL}}';`,
62
69
  `window['__nocobase_public_path__'] = '${appPublicPath}';`,
70
+ `window['__nocobase_modern_client_prefix__'] = '{{env.APP_MODERN_CLIENT_PREFIX}}';`,
71
+ `window['__nocobase_app_client_entry_mode__'] = '{{env.APP_CLIENT_ENTRY_MODE}}';`,
63
72
  `window['__nocobase_api_base_url__'] = '{{env.API_BASE_URL}}';`,
64
73
  `window['__nocobase_api_client_storage_prefix__'] = '{{env.API_CLIENT_STORAGE_PREFIX}}';`,
65
74
  `window['__nocobase_api_client_storage_type__'] = '{{env.API_CLIENT_STORAGE_TYPE}}';`,
@@ -96,6 +105,7 @@ export default defineConfig(({ command }) => {
96
105
  const appPublicPath = isBuild ? APP_PUBLIC_PATH_TEMPLATE : resolvedAppPublicPath;
97
106
  const htmlPublicPath = isDev ? '/' : appPublicPath;
98
107
  const apiBasePath = ensurePublicPath(process.env.API_BASE_PATH, '/api/');
108
+ const fileBasePath = ensurePublicPath(`${resolvedAppPublicPath}files/`, '/files/');
99
109
  const localStorageBasePath = ensurePublicPath(`${resolvedAppPublicPath}storage/uploads/`, '/storage/uploads/');
100
110
  const staticBasePath = ensurePublicPath(`${resolvedAppPublicPath}static/`, '/static/');
101
111
  const wsBasePath = ensurePublicPath(process.env.WS_PATH, '/ws/');
@@ -107,6 +117,7 @@ export default defineConfig(({ command }) => {
107
117
  `${resolvedAppPublicPath.replace(/\/$/, '')}/${modernClientPrefix}/`,
108
118
  `/${modernClientPrefix}/`,
109
119
  );
120
+ const portalBasePath = ensurePublicPath(`${resolvedAppPublicPath.replace(/\/$/, '')}/x/`, '/x/');
110
121
  const clientPort = toNumber(process.env.APP_PORT, 13001);
111
122
  const v2Port = toNumber(process.env.APP_V2_PORT, clientPort + 2);
112
123
  const hmrPath = `${resolvedAppPublicPath.replace(/\/$/, '')}/__rspack_hmr`;
@@ -220,6 +231,10 @@ export default defineConfig(({ command }) => {
220
231
  target: proxyTargetUrl,
221
232
  changeOrigin: true,
222
233
  },
234
+ [fileBasePath]: {
235
+ target: proxyTargetUrl,
236
+ changeOrigin: true,
237
+ },
223
238
  [staticBasePath]: {
224
239
  target: proxyTargetUrl,
225
240
  changeOrigin: true,
@@ -239,6 +254,12 @@ export default defineConfig(({ command }) => {
239
254
  },
240
255
  xfwd: true,
241
256
  },
257
+ [portalBasePath]: {
258
+ target: proxyTargetUrl,
259
+ changeOrigin: true,
260
+ ws: true,
261
+ xfwd: true,
262
+ },
242
263
  },
243
264
  historyApiFallback: {
244
265
  disableDotRule: true,
@@ -52,6 +52,27 @@ function toNumber(value: string | undefined, fallback: number) {
52
52
  return Number.isFinite(parsed) ? parsed : fallback;
53
53
  }
54
54
 
55
+ function normalizePathname(value: string | undefined) {
56
+ let normalized = value || '/';
57
+ if (!normalized.startsWith('/')) {
58
+ normalized = `/${normalized}`;
59
+ }
60
+ normalized = normalized.replace(/\/{2,}/g, '/');
61
+ if (normalized !== '/' && normalized.endsWith('/')) {
62
+ return normalized.replace(/\/+$/g, '');
63
+ }
64
+ return normalized || '/';
65
+ }
66
+
67
+ function isClientDocumentEntryPath(pathname: string) {
68
+ return pathname === '/' || pathname === '/index.html' || !/\.[^/]+$/.test(pathname);
69
+ }
70
+
71
+ function isWithinBasePath(pathname: string, basePath: string) {
72
+ const normalizedBasePath = normalizePathname(basePath);
73
+ return pathname === normalizedBasePath || pathname.startsWith(`${normalizedBasePath}/`);
74
+ }
75
+
55
76
  function createRuntimeHeadScript(v2PublicPath: string, isBuild: boolean, modernClientPrefix: string) {
56
77
  if (!isBuild) {
57
78
  return [
@@ -123,8 +144,10 @@ export default defineConfig(({ command }) => {
123
144
  const isBuild = command === 'build';
124
145
  const appPublicPath = ensurePublicPath(process.env.APP_PUBLIC_PATH || '/');
125
146
  const apiBasePath = ensurePublicPath(process.env.API_BASE_PATH || '/api/');
147
+ const fileBasePath = ensurePublicPath(`${appPublicPath.replace(/\/$/, '')}/files/`);
126
148
  const localStorageBasePath = ensurePublicPath(`${appPublicPath.replace(/\/$/, '')}/storage/uploads/`);
127
149
  const staticBasePath = ensurePublicPath(`${appPublicPath.replace(/\/$/, '')}/static/`);
150
+ const portalBasePath = ensurePublicPath(`${appPublicPath.replace(/\/$/, '')}/x/`);
128
151
  const modernClientPrefix = normalizeModernClientPrefix(process.env.APP_MODERN_CLIENT_PREFIX);
129
152
  // Build bakes the FIXED dist-dir segment (`/v/`) as a sentinel that the
130
153
  // server rewrites to the runtime prefix per request. Dev serves under the
@@ -132,6 +155,7 @@ export default defineConfig(({ command }) => {
132
155
  const modernClientDistPath = ensurePublicPath(`${appPublicPath.replace(/\/$/, '')}/${MODERN_CLIENT_DIST_DIR}/`);
133
156
  const modernClientPublicPath = ensurePublicPath(`${appPublicPath.replace(/\/$/, '')}/${modernClientPrefix}/`);
134
157
  const v2PublicPath = isBuild ? modernClientDistPath : modernClientPublicPath;
158
+ const appClientEntryMode = process.env.APP_CLIENT_ENTRY_MODE;
135
159
  const wsBasePath = ensurePublicPath(process.env.WS_PATH || '/ws/');
136
160
  const hmrPath = `${v2PublicPath.replace(/\/$/, '')}/__rspack_hmr`;
137
161
  const v2Port = toNumber(process.env.APP_V2_PORT, 13002);
@@ -256,10 +280,20 @@ export default defineConfig(({ command }) => {
256
280
  target: proxyTargetUrl,
257
281
  changeOrigin: true,
258
282
  },
283
+ [fileBasePath]: {
284
+ target: proxyTargetUrl,
285
+ changeOrigin: true,
286
+ },
259
287
  [staticBasePath]: {
260
288
  target: proxyTargetUrl,
261
289
  changeOrigin: true,
262
290
  },
291
+ [portalBasePath]: {
292
+ target: proxyTargetUrl,
293
+ changeOrigin: true,
294
+ ws: true,
295
+ xfwd: true,
296
+ },
263
297
  [wsBasePath]: {
264
298
  target: proxyTargetUrl,
265
299
  changeOrigin: true,
@@ -275,6 +309,38 @@ export default defineConfig(({ command }) => {
275
309
  dev: {
276
310
  assetPrefix: v2PublicPath,
277
311
  lazyCompilation: false,
312
+ setupMiddlewares: [
313
+ (middlewares) => {
314
+ if (appClientEntryMode !== 'modern-only') {
315
+ return;
316
+ }
317
+
318
+ middlewares.unshift((req, res, next) => {
319
+ const [rawPathname = '/', query = ''] = String(req.url || '/').split('?');
320
+ const pathname = normalizePathname(rawPathname);
321
+ if (
322
+ !isClientDocumentEntryPath(pathname) ||
323
+ pathname.startsWith('/.well-known/') ||
324
+ pathname.startsWith(apiBasePath) ||
325
+ pathname.startsWith(wsBasePath) ||
326
+ pathname.startsWith(localStorageBasePath) ||
327
+ pathname.startsWith(portalBasePath) ||
328
+ pathname.startsWith(staticBasePath)
329
+ ) {
330
+ next();
331
+ return;
332
+ }
333
+ if (!isWithinBasePath(pathname, v2PublicPath)) {
334
+ const target = pathname === '/' ? v2PublicPath : `${v2PublicPath.replace(/\/$/, '')}${pathname}`;
335
+ res.statusCode = 302;
336
+ res.setHeader('Location', `${target}${query ? `?${query}` : ''}`);
337
+ res.end();
338
+ return;
339
+ }
340
+ next();
341
+ });
342
+ },
343
+ ],
278
344
  client: {
279
345
  overlay: false,
280
346
  protocol: 'ws',