@next-core/brick-container 2.78.0 → 2.78.2

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.
@@ -15,6 +15,7 @@ const {
15
15
  tryFiles,
16
16
  removeCacheHeaders,
17
17
  } = require("./utils");
18
+ const { getIndexHtml } = require("./getIndexHtml");
18
19
 
19
20
  module.exports = (env) => {
20
21
  const {
@@ -35,13 +36,13 @@ module.exports = (env) => {
35
36
  brickPackagesDir,
36
37
  alternativeBrickPackagesDir,
37
38
  useLegacyBootstrap,
38
- hasStandaloneApps,
39
- standaloneAppsConfig,
40
- allAppsConfig,
39
+ legacyStandaloneAppsConfig,
40
+ legacyAllAppsConfig,
41
+ useLocalContainer,
41
42
  } = env;
42
43
 
43
44
  const pathRewriteFactory = (seg) =>
44
- useSubdir
45
+ useSubdir || seg.includes("/sa-static/")
45
46
  ? undefined
46
47
  : {
47
48
  [`^/${seg}`]: `/next/${seg}`,
@@ -56,25 +57,23 @@ module.exports = (env) => {
56
57
  },
57
58
  };
58
59
  if (useRemote) {
59
- for (const standaloneConfig of allAppsConfig) {
60
- const assetRoot = standaloneConfig
61
- ? standaloneConfig.standaloneVersion === 2
62
- ? standaloneConfig.publicPrefix
63
- : `${standaloneConfig.appRoot}-/`
64
- : "";
60
+ for (const standaloneConfig of legacyAllAppsConfig) {
61
+ const assetRoot = standaloneConfig ? `${standaloneConfig.appRoot}-/` : "";
65
62
  if (standaloneConfig) {
66
63
  // 在「独立应用」模式中,静态资源路径在 `your-app/-/` 目录下。
67
64
  proxyPaths.push(assetRoot);
68
65
  proxyPaths.push(`${standaloneConfig.appRoot}conf.yaml`);
69
- if (standaloneConfig.standaloneVersion === 2) {
70
- proxyPaths.push(`${standaloneConfig.appRoot}-/`);
71
- }
72
66
  } else {
73
67
  const assetPaths = ["bricks", "micro-apps", "templates"];
74
68
  proxyPaths.push(...assetPaths.map((p) => `${assetRoot}${p}`));
75
69
  }
76
70
  }
77
71
 
72
+ proxyPaths.push(
73
+ "(/next)?/sa-static/:appId/versions/:appVersion/webroot/-/",
74
+ "/sa-static/"
75
+ );
76
+
78
77
  apiProxyOptions.onProxyRes = (proxyRes, req, res) => {
79
78
  if (env.asCdn) {
80
79
  return;
@@ -84,23 +83,33 @@ module.exports = (env) => {
84
83
  let reqIsBootstrap =
85
84
  req.path === "/next/api/auth/bootstrap" ||
86
85
  req.path === "/next/api/auth/v2/bootstrap";
87
- let matchedStandaloneConfig;
88
- if (!reqIsBootstrap && hasStandaloneApps) {
89
- for (const standaloneConfig of standaloneAppsConfig) {
90
- const regex = new RegExp(
91
- `^${escapeRegExp(
92
- standaloneConfig.appRoot
93
- )}-/bootstrap\\.[^.]+\\.json$`
94
- );
95
- if (regex.test(req.path)) {
96
- reqIsBootstrap = true;
97
- matchedStandaloneConfig = standaloneConfig;
86
+ let isStandalone = false;
87
+ let publicRootWithVersion = false;
88
+ if (!reqIsBootstrap) {
89
+ const regex =
90
+ /^(?:\/next)?\/sa-static\/[^/]+\/versions\/[^/]+\/webroot\/-\/bootstrap\.[^.]+\.json$/;
91
+ if (regex.test(req.path)) {
92
+ reqIsBootstrap = true;
93
+ isStandalone = true;
94
+ publicRootWithVersion = true;
95
+ }
96
+ if (!reqIsBootstrap) {
97
+ for (const standaloneConfig of legacyStandaloneAppsConfig) {
98
+ const regex = new RegExp(
99
+ `^${escapeRegExp(
100
+ standaloneConfig.appRoot
101
+ )}-/bootstrap\\.[^.]+\\.json$`
102
+ );
103
+ if (regex.test(req.path)) {
104
+ reqIsBootstrap = true;
105
+ isStandalone = true;
106
+ }
98
107
  }
99
108
  }
100
109
  }
101
110
 
102
111
  if (reqIsBootstrap) {
103
- if (matchedStandaloneConfig && res.statusCode === 200) {
112
+ if (res.statusCode === 200) {
104
113
  // Disable cache for standalone bootstrap for development.
105
114
  removeCacheHeaders(proxyRes);
106
115
  }
@@ -109,7 +118,7 @@ module.exports = (env) => {
109
118
  return raw;
110
119
  }
111
120
  const result = JSON.parse(raw);
112
- const data = matchedStandaloneConfig ? result : result.data;
121
+ const data = isStandalone ? result : result.data;
113
122
  if (localMicroApps.length > 0 || mockedMicroApps.length > 0) {
114
123
  data.storyboards = mockedMicroApps
115
124
  .map((id) =>
@@ -156,7 +165,7 @@ module.exports = (env) => {
156
165
  env,
157
166
  id,
158
167
  data.brickPackages,
159
- matchedStandaloneConfig
168
+ publicRootWithVersion
160
169
  )
161
170
  )
162
171
  .filter(Boolean)
@@ -362,23 +371,106 @@ module.exports = (env) => {
362
371
  }
363
372
 
364
373
  const rootProxyOptions = {};
365
- if (!env.useLocalContainer && !env.asCdn) {
374
+ if (useRemote && !env.asCdn) {
366
375
  proxyPaths.push("");
367
376
  rootProxyOptions.onProxyRes = (proxyRes, req, res) => {
368
377
  if (
369
378
  req.method === "GET" &&
370
379
  (req.get("accept") || "").includes("text/html")
371
380
  ) {
381
+ if (res.statusCode === 200) {
382
+ // Disable cache for standalone runtime for development.
383
+ removeCacheHeaders(proxyRes);
384
+ }
372
385
  modifyResponse(res, proxyRes, (raw) => {
373
386
  if (
374
387
  !(
375
388
  res.statusCode === 200 &&
376
- res.get("content-type") === "text/html" &&
377
- raw.includes(`/next/browse-happy.html`)
389
+ (res.get("content-type") || "").includes("text/html") &&
390
+ raw.includes(`/browse-happy.html`)
378
391
  )
379
392
  ) {
380
393
  return raw;
381
394
  }
395
+ if (useLocalContainer) {
396
+ const pathname = useSubdir
397
+ ? req.path.replace(/^\/next\//, "/")
398
+ : req.path;
399
+ const standalone = /\bSTANDALONE_MICRO_APPS\s*=\s*(?:!0|true)/.test(
400
+ raw
401
+ );
402
+ if (standalone) {
403
+ const appDir = pathname
404
+ .split("/")
405
+ .slice(1, pathname.startsWith("/legacy/") ? 3 : 2)
406
+ .concat("")
407
+ .join("/");
408
+
409
+ const appRootMatches = raw.match(/\bAPP_ROOT\s*=\s*("[^"]+")/);
410
+ if (!appRootMatches) {
411
+ const message = "Unexpected: APP_ROOT is not found";
412
+ console.log(message, raw);
413
+ throw new Error(message);
414
+ }
415
+ const appRoot = JSON.parse(appRootMatches[1]);
416
+
417
+ const bootstrapHashMatches = raw.match(
418
+ /\bbootstrap\.([^."]+)\.json\b/
419
+ );
420
+ if (!bootstrapHashMatches) {
421
+ const message = "Unexpected: bootstrapHash is not found";
422
+ console.log(message, raw);
423
+ throw new Error(message);
424
+ }
425
+ const bootstrapHash = bootstrapHashMatches[1];
426
+
427
+ const noAuthGuard = /\bNO_AUTH_GUARD\s*=\s*(?:!0|true)/.test(raw);
428
+
429
+ const publicRootWithVersion =
430
+ /\bPUBLIC_ROOT_WITH_VERSION\s*=\s*(?:!0|true)/.test(raw);
431
+
432
+ if (publicRootWithVersion) {
433
+ const publicPrefixMatches = raw.match(
434
+ /\bvar\s+d\s*=\s*("[^"]+")/
435
+ );
436
+ if (!publicPrefixMatches) {
437
+ const message =
438
+ "Unexpected: PUBLIC_ROOT_WITH_VERSION is true while public-prefix is not found";
439
+ console.log(message, raw);
440
+ throw new Error(message);
441
+ }
442
+ const publicPrefix = JSON.parse(publicPrefixMatches[1]);
443
+
444
+ // const coreVersionMatches = raw.match(/"core\/(?:[^/]+)\/"/);
445
+ // const coreVersion = JSON.parse(coreVersionMatches[0]).split("/")[1];
446
+ const coreVersion = "0.0.0";
447
+
448
+ return getIndexHtml(
449
+ {
450
+ appDir,
451
+ appRoot,
452
+ publicPrefix,
453
+ bootstrapHash,
454
+ coreVersion,
455
+ noAuthGuard,
456
+ standaloneVersion: 2,
457
+ },
458
+ env
459
+ );
460
+ }
461
+ return getIndexHtml(
462
+ {
463
+ appDir,
464
+ appRoot,
465
+ bootstrapHash,
466
+ noAuthGuard,
467
+ standaloneVersion: 1,
468
+ },
469
+ env
470
+ );
471
+ }
472
+ return getIndexHtml(null, env);
473
+ }
382
474
  const content = useSubdir ? raw : raw.replace(/\/next\//g, "/");
383
475
  return env.liveReload
384
476
  ? appendLiveReloadScript(content, env)
@@ -426,7 +518,11 @@ module.exports = (env) => {
426
518
  }
427
519
  : {}),
428
520
  ...proxyPaths.reduce((acc, seg) => {
429
- acc[seg.startsWith("/") ? seg : `${baseHref}${seg}`] = {
521
+ acc[
522
+ seg.startsWith("/") || seg.startsWith("(/")
523
+ ? seg
524
+ : `${baseHref}${seg}`
525
+ ] = {
430
526
  target: server,
431
527
  secure: false,
432
528
  changeOrigin: true,
package/serve/serve.js CHANGED
@@ -11,101 +11,23 @@ const yaml = require("js-yaml");
11
11
  const getEnv = require("./getEnv");
12
12
  const serveLocal = require("./serveLocal");
13
13
  const getProxies = require("./getProxies");
14
- const { getPatternsToWatch, appendLiveReloadScript } = require("./utils");
14
+ const { getPatternsToWatch } = require("./utils");
15
+ const { getIndexHtml, distDir } = require("./getIndexHtml");
15
16
 
16
17
  module.exports = function serve(runtimeFlags) {
17
18
  const env = getEnv(runtimeFlags);
18
19
 
19
20
  const app = express();
20
21
 
21
- const distDir = path.dirname(
22
- require.resolve("@next-core/brick-container/dist/index.html")
23
- );
24
-
25
22
  serveLocal(env, app);
26
23
 
27
24
  const serveIndexHtmlFactory = (standaloneConfig) => (_req, res) => {
28
- const indexHtml = path.join(distDir, "index.html");
29
- let content = fs.readFileSync(indexHtml, "utf8");
30
-
31
- if (env.liveReload) {
32
- content = appendLiveReloadScript(content, env);
33
- }
34
-
35
- // Replace nginx ssi placeholders.
36
- content = content
37
- .replace(
38
- new RegExp(
39
- escapeRegExp("<!--# echo var='base_href' default='/' -->"),
40
- "g"
41
- ),
42
- env.baseHref
43
- )
44
- .replace(
45
- new RegExp(
46
- escapeRegExp("<!--# echo var='core_root' default='' -->"),
47
- "g"
48
- ),
49
- `${env.publicCdn ?? ""}${
50
- standaloneConfig
51
- ? standaloneConfig.standaloneVersion === 2
52
- ? `${standaloneConfig.publicPrefix}core/${standaloneConfig.coreVersion}/`
53
- : `${standaloneConfig.appRoot}-/core/`
54
- : ""
55
- }`
56
- )
57
- .replace(
58
- new RegExp(
59
- escapeRegExp("<!--# echo var='mock_date' default='' -->"),
60
- "g"
61
- ),
62
- env.mockDate ?? ""
63
- )
64
- .replace(
65
- new RegExp(
66
- escapeRegExp("<!--# echo var='public_cdn' default='' -->"),
67
- "g"
68
- ),
69
- env.publicCdn ?? ""
70
- );
71
-
72
- if (standaloneConfig) {
73
- content = content.replace(
74
- "</head>",
75
- [
76
- "<script>",
77
- "((w)=>{",
78
- "w.STANDALONE_MICRO_APPS=!0;",
79
- `var a=w.APP_ROOT=${JSON.stringify(standaloneConfig.appRoot)};`,
80
- (standaloneConfig.standaloneVersion === 2
81
- ? [
82
- "w.PUBLIC_ROOT_WITH_VERSION=!0",
83
- `var d=${JSON.stringify(standaloneConfig.publicPrefix)}`,
84
- 'var p=w.PUBLIC_ROOT=(w.PUBLIC_CDN||"")+d',
85
- `w.CORE_ROOT=p+"core/${standaloneConfig.coreVersion}/"`,
86
- `w.BOOTSTRAP_FILE=a+"-/bootstrap.${standaloneConfig.bootstrapHash}.json"`,
87
- ]
88
- : [
89
- 'var d=a+"-/"',
90
- 'var p=w.PUBLIC_ROOT=(w.PUBLIC_CDN||"")+d',
91
- 'w.CORE_ROOT=p+"core/"',
92
- `w.BOOTSTRAP_FILE=d+"bootstrap.${standaloneConfig.bootstrapHash}.json"`,
93
- ]
94
- )
95
- .filter(Boolean)
96
- .join(";"),
97
- "})(window)",
98
- "</script></head>",
99
- ].join("")
100
- );
101
- }
102
-
103
- res.send(content);
25
+ res.send(getIndexHtml(standaloneConfig, env));
104
26
  };
105
27
 
106
28
  if (!env.useRemote) {
107
29
  let fakeAuthHandled = false;
108
- for (const standaloneConfig of env.standaloneAppsConfig) {
30
+ for (const standaloneConfig of env.legacyStandaloneAppsConfig) {
109
31
  // Return a fake `conf.yaml` for standalone micro-apps.
110
32
  app.get(`${standaloneConfig.appRoot}conf.yaml`, (req, res) => {
111
33
  res.setHeader("content-type", "text/plain");
@@ -132,7 +54,7 @@ module.exports = function serve(runtimeFlags) {
132
54
 
133
55
  if (env.useLocalContainer) {
134
56
  const browseHappyHtml = "browse-happy.html";
135
- for (const standaloneConfig of env.allAppsConfig) {
57
+ for (const standaloneConfig of env.legacyAllAppsConfig) {
136
58
  const serveRoot = `${env.baseHref}${
137
59
  standaloneConfig ? standaloneConfig.appDir : ""
138
60
  }`;
@@ -145,7 +67,7 @@ module.exports = function serve(runtimeFlags) {
145
67
  });
146
68
  } else {
147
69
  // Serve index.html.
148
- app.get(serveRoot, serveIndexHtmlFactory(standaloneConfig));
70
+ app.get(serveRoot, serveIndexHtmlFactory(standaloneConfig, env));
149
71
 
150
72
  // Serve browse-happy.html.
151
73
  app.get(`${env.baseHref}${browseHappyHtml}`, (req, res) => {
@@ -155,12 +77,15 @@ module.exports = function serve(runtimeFlags) {
155
77
 
156
78
  // Serve static files.
157
79
  const staticRoot = standaloneConfig
158
- ? standaloneConfig.standaloneVersion === 2
159
- ? `${standaloneConfig.publicPrefix}core/${standaloneConfig.coreVersion}/`
160
- : `${standaloneConfig.appRoot || serveRoot}-/core/`
80
+ ? `${standaloneConfig.appRoot || serveRoot}-/core/`
161
81
  : serveRoot;
162
82
  app.use(staticRoot, express.static(distDir));
163
83
  }
84
+
85
+ // Serve static files in next-core for new standalone apps.
86
+ app.use("(/next)?/sa-static/-/core/:coreVersion/", express.static(distDir));
87
+ // For legacy standalone apps.
88
+ app.use(`${env.baseHref}:appId/-/core/`, express.static(distDir));
164
89
  }
165
90
 
166
91
  // Using proxies.
@@ -221,11 +146,11 @@ module.exports = function serve(runtimeFlags) {
221
146
  }
222
147
 
223
148
  if (env.useLocalContainer && !env.asCdn) {
224
- for (const standaloneConfig of env.allAppsConfig) {
149
+ for (const standaloneConfig of env.legacyAllAppsConfig) {
225
150
  const serveRoot = `${env.baseHref}${
226
151
  standaloneConfig ? standaloneConfig.appDir : ""
227
152
  }`;
228
- app.use(serveRoot, serveIndexHtmlFactory(standaloneConfig));
153
+ app.use(serveRoot, serveIndexHtmlFactory(standaloneConfig, env));
229
154
  }
230
155
 
231
156
  // Return a fake 404 page for not-existed apps.
@@ -8,7 +8,6 @@ const {
8
8
  getSettings,
9
9
  getTemplatePackages,
10
10
  getSingleStoryboard,
11
- tryFiles,
12
11
  tryServeFiles,
13
12
  } = require("./utils");
14
13
 
@@ -31,18 +30,34 @@ module.exports = (env, app) => {
31
30
  mocked,
32
31
  mockedMicroAppsDir,
33
32
  mockedMicroApps,
34
- allAppsConfig,
35
33
  asCdn,
34
+ legacyStandaloneAppsConfig,
36
35
  } = env;
37
36
  let username;
38
37
 
39
- for (const standaloneConfig of allAppsConfig) {
40
- const publicRoot = standaloneConfig
41
- ? standaloneConfig.standaloneVersion === 2
42
- ? standaloneConfig.publicPrefix
43
- : `${standaloneConfig.appRoot}-/`
44
- : baseHref;
38
+ const serveLocalConfigs = legacyStandaloneAppsConfig
39
+ .map((standaloneConfig) => ({
40
+ publicRoot: `${standaloneConfig.appRoot}-/`,
41
+ isStandalone: true,
42
+ }))
43
+ .concat(
44
+ {
45
+ publicRoot: "(/next)?/sa-static/-/",
46
+ publicRootAsRegExpRaw: "(?:/next)?/sa-static/-/",
47
+ isStandalone: true,
48
+ publicRootWithVersion: true,
49
+ },
50
+ {
51
+ publicRoot: baseHref,
52
+ }
53
+ );
45
54
 
55
+ for (const {
56
+ publicRoot,
57
+ publicRootAsRegExpRaw,
58
+ isStandalone,
59
+ publicRootWithVersion,
60
+ } of serveLocalConfigs) {
46
61
  // 开发时默认拦截 bootstrap 请求。
47
62
  // 如果设定 `REMOTE=true`,则透传远端请求。
48
63
  if (useRemote) {
@@ -89,8 +104,10 @@ module.exports = (env, app) => {
89
104
  // 直接返回本地构件库相关文件(但排除编辑器相关文件)。
90
105
  app.get(
91
106
  new RegExp(
92
- `^${escapeRegExp(
93
- `${publicRoot}bricks/${pkgId}/`
107
+ `^${
108
+ publicRootAsRegExpRaw || escapeRegExp(publicRoot)
109
+ }${escapeRegExp(
110
+ `bricks/${pkgId}/`
94
111
  )}(?:\\d+(?:\\.\\d+)*/)?(?!dist/editors/)(.+)`
95
112
  ),
96
113
  (req, res) => {
@@ -107,7 +124,7 @@ module.exports = (env, app) => {
107
124
  );
108
125
  });
109
126
 
110
- standaloneConfig ||
127
+ isStandalone ||
111
128
  localMicroApps.forEach((appId) => {
112
129
  // 直接返回本地小产品相关文件。
113
130
  app.get(`${baseHref}micro-apps/${appId}/*`, (req, res) => {
@@ -135,7 +152,7 @@ module.exports = (env, app) => {
135
152
  });
136
153
  });
137
154
 
138
- standaloneConfig ||
155
+ isStandalone ||
139
156
  mockedMicroApps.forEach((appId) => {
140
157
  // 直接返回本地小产品相关文件。
141
158
  app.get(`${baseHref}micro-apps/${appId}/*`, (req, res) => {
@@ -159,7 +176,7 @@ module.exports = (env, app) => {
159
176
  });
160
177
  // API to fulfil the active storyboard.
161
178
  asCdn ||
162
- standaloneConfig ||
179
+ isStandalone ||
163
180
  localMicroApps.concat(mockedMicroApps).forEach((appId) => {
164
181
  app.get(
165
182
  `${baseHref}api/auth(/v2)?/bootstrap/${appId}`,
@@ -176,7 +193,7 @@ module.exports = (env, app) => {
176
193
  );
177
194
  });
178
195
  } else {
179
- if (standaloneConfig) {
196
+ if (isStandalone) {
180
197
  app.get(`${publicRoot}bootstrap.hash.json`, (req, res) => {
181
198
  res.json({
182
199
  navbar: getNavbar(env),
@@ -190,7 +207,7 @@ module.exports = (env, app) => {
190
207
  brief: req.query.brief === "true",
191
208
  })
192
209
  ),
193
- brickPackages: getBrickPackages(env, standaloneConfig),
210
+ brickPackages: getBrickPackages(env, publicRootWithVersion),
194
211
  templatePackages: getTemplatePackages(env),
195
212
  });
196
213
  });
package/serve/utils.js CHANGED
@@ -9,6 +9,7 @@ function getNavbar(env) {
9
9
  }
10
10
 
11
11
  function getStoryboardsByMicroApps(env, mocked, options = {}) {
12
+ // Used only in non-remote mode.
12
13
  return getNamesOfMicroApps(env, mocked)
13
14
  .map((name) => getSingleStoryboard(env, name, mocked, options))
14
15
  .filter(Boolean);
@@ -30,7 +31,9 @@ function getNamesOfMicroApps(env, mocked) {
30
31
  .map((dirent) => dirent.name);
31
32
  // Ignore `auth` for fully standalone micro-apps.
32
33
  return mocked &&
33
- env.standaloneAppsConfig.some((standaloneConfig) => standaloneConfig.appDir)
34
+ env.legacyStandaloneAppsConfig.some(
35
+ (standaloneConfig) => standaloneConfig.appDir
36
+ )
34
37
  ? apps.filter((name) => name !== "auth")
35
38
  : apps;
36
39
  }
@@ -83,10 +86,10 @@ function getSingleStoryboard(env, microAppName, mocked, options = {}) {
83
86
  return storyboard;
84
87
  }
85
88
 
86
- function getBrickPackages(env, standaloneConfig) {
89
+ function getBrickPackages(env, publicRootWithVersion) {
87
90
  return getNamesOfBrickPackages(env)
88
91
  .map((name) =>
89
- getSingleBrickPackage(env, name, undefined, standaloneConfig)
92
+ getSingleBrickPackage(env, name, undefined, publicRootWithVersion)
90
93
  )
91
94
  .filter(Boolean);
92
95
  }
@@ -110,7 +113,7 @@ function getSingleBrickPackage(
110
113
  env,
111
114
  brickPackageName,
112
115
  remoteBrickPackages,
113
- standaloneConfig
116
+ publicRootWithVersion
114
117
  ) {
115
118
  const {
116
119
  brickPackagesDir,
@@ -144,7 +147,7 @@ function getSingleBrickPackage(
144
147
  if (fs.existsSync(distDir)) {
145
148
  if (!remoteBrickPackages || localBrickPackages.includes(brickPackageName)) {
146
149
  let versionPart = "";
147
- if (standaloneConfig && standaloneConfig.standaloneVersion === 2) {
150
+ if (publicRootWithVersion) {
148
151
  const packageJson = JSON.parse(
149
152
  fs.readFileSync(path.resolve(distDir, "../package.json"))
150
153
  );