@next-core/brick-container 2.78.0 → 2.78.1

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,9 +36,10 @@ module.exports = (env) => {
35
36
  brickPackagesDir,
36
37
  alternativeBrickPackagesDir,
37
38
  useLegacyBootstrap,
38
- hasStandaloneApps,
39
- standaloneAppsConfig,
40
- allAppsConfig,
39
+ legacyStandaloneAppsConfig,
40
+ legacyAllAppsConfig,
41
+ saStaticRoot,
42
+ useLocalContainer,
41
43
  } = env;
42
44
 
43
45
  const pathRewriteFactory = (seg) =>
@@ -56,25 +58,24 @@ module.exports = (env) => {
56
58
  },
57
59
  };
58
60
  if (useRemote) {
59
- for (const standaloneConfig of allAppsConfig) {
60
- const assetRoot = standaloneConfig
61
- ? standaloneConfig.standaloneVersion === 2
62
- ? standaloneConfig.publicPrefix
63
- : `${standaloneConfig.appRoot}-/`
64
- : "";
61
+ for (const standaloneConfig of legacyAllAppsConfig) {
62
+ const assetRoot = standaloneConfig ? `${standaloneConfig.appRoot}-/` : "";
65
63
  if (standaloneConfig) {
66
64
  // 在「独立应用」模式中,静态资源路径在 `your-app/-/` 目录下。
67
65
  proxyPaths.push(assetRoot);
68
66
  proxyPaths.push(`${standaloneConfig.appRoot}conf.yaml`);
69
- if (standaloneConfig.standaloneVersion === 2) {
70
- proxyPaths.push(`${standaloneConfig.appRoot}-/`);
71
- }
72
67
  } else {
73
68
  const assetPaths = ["bricks", "micro-apps", "templates"];
74
69
  proxyPaths.push(...assetPaths.map((p) => `${assetRoot}${p}`));
75
70
  }
76
71
  }
77
72
 
73
+ proxyPaths.push(
74
+ `${saStaticRoot}-/`,
75
+ `${saStaticRoot}:appId/versions/:appVersion/conf.yaml`,
76
+ `${saStaticRoot}:appId/versions/:appVersion/webroot/-/`
77
+ );
78
+
78
79
  apiProxyOptions.onProxyRes = (proxyRes, req, res) => {
79
80
  if (env.asCdn) {
80
81
  return;
@@ -84,23 +85,33 @@ module.exports = (env) => {
84
85
  let reqIsBootstrap =
85
86
  req.path === "/next/api/auth/bootstrap" ||
86
87
  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;
88
+ let isStandalone = false;
89
+ let publicRootWithVersion = false;
90
+ if (!reqIsBootstrap) {
91
+ const regex =
92
+ /^(?:\/next)?\/sa-static\/[^/]+\/versions\/[^/]+\/webroot\/-\/bootstrap\.[^.]+\.json$/;
93
+ if (regex.test(req.path)) {
94
+ reqIsBootstrap = true;
95
+ isStandalone = true;
96
+ publicRootWithVersion = true;
97
+ }
98
+ if (!reqIsBootstrap) {
99
+ for (const standaloneConfig of legacyStandaloneAppsConfig) {
100
+ const regex = new RegExp(
101
+ `^${escapeRegExp(
102
+ standaloneConfig.appRoot
103
+ )}-/bootstrap\\.[^.]+\\.json$`
104
+ );
105
+ if (regex.test(req.path)) {
106
+ reqIsBootstrap = true;
107
+ isStandalone = true;
108
+ }
98
109
  }
99
110
  }
100
111
  }
101
112
 
102
113
  if (reqIsBootstrap) {
103
- if (matchedStandaloneConfig && res.statusCode === 200) {
114
+ if (res.statusCode === 200) {
104
115
  // Disable cache for standalone bootstrap for development.
105
116
  removeCacheHeaders(proxyRes);
106
117
  }
@@ -109,7 +120,7 @@ module.exports = (env) => {
109
120
  return raw;
110
121
  }
111
122
  const result = JSON.parse(raw);
112
- const data = matchedStandaloneConfig ? result : result.data;
123
+ const data = isStandalone ? result : result.data;
113
124
  if (localMicroApps.length > 0 || mockedMicroApps.length > 0) {
114
125
  data.storyboards = mockedMicroApps
115
126
  .map((id) =>
@@ -156,7 +167,7 @@ module.exports = (env) => {
156
167
  env,
157
168
  id,
158
169
  data.brickPackages,
159
- matchedStandaloneConfig
170
+ publicRootWithVersion
160
171
  )
161
172
  )
162
173
  .filter(Boolean)
@@ -362,23 +373,106 @@ module.exports = (env) => {
362
373
  }
363
374
 
364
375
  const rootProxyOptions = {};
365
- if (!env.useLocalContainer && !env.asCdn) {
376
+ if (useRemote && !env.asCdn) {
366
377
  proxyPaths.push("");
367
378
  rootProxyOptions.onProxyRes = (proxyRes, req, res) => {
368
379
  if (
369
380
  req.method === "GET" &&
370
381
  (req.get("accept") || "").includes("text/html")
371
382
  ) {
383
+ if (res.statusCode === 200) {
384
+ // Disable cache for standalone runtime for development.
385
+ removeCacheHeaders(proxyRes);
386
+ }
372
387
  modifyResponse(res, proxyRes, (raw) => {
373
388
  if (
374
389
  !(
375
390
  res.statusCode === 200 &&
376
- res.get("content-type") === "text/html" &&
377
- raw.includes(`/next/browse-happy.html`)
391
+ (res.get("content-type") || "").includes("text/html") &&
392
+ raw.includes(`/browse-happy.html`)
378
393
  )
379
394
  ) {
380
395
  return raw;
381
396
  }
397
+ if (useLocalContainer) {
398
+ const pathname = useSubdir
399
+ ? req.path.replace(/^\/next\//, "/")
400
+ : req.path;
401
+ const standalone = /\bSTANDALONE_MICRO_APPS\s*=\s*(?:!0|true)/.test(
402
+ raw
403
+ );
404
+ if (standalone) {
405
+ const appDir = pathname
406
+ .split("/")
407
+ .slice(1, pathname.startsWith("/legacy/") ? 3 : 2)
408
+ .concat("")
409
+ .join("/");
410
+
411
+ const appRootMatches = raw.match(/\bAPP_ROOT\s*=\s*("[^"]+")/);
412
+ if (!appRootMatches) {
413
+ const message = "Unexpected: APP_ROOT is not found";
414
+ console.log(message, raw);
415
+ throw new Error(message);
416
+ }
417
+ const appRoot = JSON.parse(appRootMatches[1]);
418
+
419
+ const bootstrapHashMatches = raw.match(
420
+ /\bbootstrap\.([^."]+)\.json\b/
421
+ );
422
+ if (!bootstrapHashMatches) {
423
+ const message = "Unexpected: bootstrapHash is not found";
424
+ console.log(message, raw);
425
+ throw new Error(message);
426
+ }
427
+ const bootstrapHash = bootstrapHashMatches[1];
428
+
429
+ const noAuthGuard = /\bNO_AUTH_GUARD\s*=\s*(?:!0|true)/.test(raw);
430
+
431
+ const publicRootWithVersion =
432
+ /\bPUBLIC_ROOT_WITH_VERSION\s*=\s*(?:!0|true)/.test(raw);
433
+
434
+ if (publicRootWithVersion) {
435
+ const publicPrefixMatches = raw.match(
436
+ /\bvar\s+d\s*=\s*("[^"]+")/
437
+ );
438
+ if (!publicPrefixMatches) {
439
+ const message =
440
+ "Unexpected: PUBLIC_ROOT_WITH_VERSION is true while public-prefix is not found";
441
+ console.log(message, raw);
442
+ throw new Error(message);
443
+ }
444
+ const publicPrefix = JSON.parse(publicPrefixMatches[1]);
445
+
446
+ // const coreVersionMatches = raw.match(/"core\/(?:[^/]+)\/"/);
447
+ // const coreVersion = JSON.parse(coreVersionMatches[0]).split("/")[1];
448
+ const coreVersion = "0.0.0";
449
+
450
+ return getIndexHtml(
451
+ {
452
+ appDir,
453
+ appRoot,
454
+ publicPrefix,
455
+ bootstrapHash,
456
+ coreVersion,
457
+ noAuthGuard,
458
+ standaloneVersion: 2,
459
+ },
460
+ env
461
+ );
462
+ }
463
+ return getIndexHtml(
464
+ {
465
+ appDir,
466
+ appRoot,
467
+ bootstrapHash,
468
+ noAuthGuard,
469
+ standaloneVersion: 1,
470
+ },
471
+ env
472
+ );
473
+ }
474
+ return getIndexHtml(null, env);
475
+ }
382
476
  const content = useSubdir ? raw : raw.replace(/\/next\//g, "/");
383
477
  return env.liveReload
384
478
  ? appendLiveReloadScript(content, env)
@@ -426,7 +520,11 @@ module.exports = (env) => {
426
520
  }
427
521
  : {}),
428
522
  ...proxyPaths.reduce((acc, seg) => {
429
- acc[seg.startsWith("/") ? seg : `${baseHref}${seg}`] = {
523
+ acc[
524
+ seg.startsWith("/") || seg.startsWith("(/")
525
+ ? seg
526
+ : `${baseHref}${seg}`
527
+ ] = {
430
528
  target: server,
431
529
  secure: false,
432
530
  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,13 @@ 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(`${env.saStaticRoot}-/core/:coreVersion/`, express.static(distDir));
164
87
  }
165
88
 
166
89
  // Using proxies.
@@ -221,11 +144,11 @@ module.exports = function serve(runtimeFlags) {
221
144
  }
222
145
 
223
146
  if (env.useLocalContainer && !env.asCdn) {
224
- for (const standaloneConfig of env.allAppsConfig) {
147
+ for (const standaloneConfig of env.legacyAllAppsConfig) {
225
148
  const serveRoot = `${env.baseHref}${
226
149
  standaloneConfig ? standaloneConfig.appDir : ""
227
150
  }`;
228
- app.use(serveRoot, serveIndexHtmlFactory(standaloneConfig));
151
+ app.use(serveRoot, serveIndexHtmlFactory(standaloneConfig, env));
229
152
  }
230
153
 
231
154
  // 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,33 @@ module.exports = (env, app) => {
31
30
  mocked,
32
31
  mockedMicroAppsDir,
33
32
  mockedMicroApps,
34
- allAppsConfig,
35
33
  asCdn,
34
+ legacyStandaloneAppsConfig,
35
+ saStaticRoot,
36
36
  } = env;
37
37
  let username;
38
38
 
39
- for (const standaloneConfig of allAppsConfig) {
40
- const publicRoot = standaloneConfig
41
- ? standaloneConfig.standaloneVersion === 2
42
- ? standaloneConfig.publicPrefix
43
- : `${standaloneConfig.appRoot}-/`
44
- : baseHref;
39
+ const serveLocalConfigs = legacyStandaloneAppsConfig
40
+ .map((standaloneConfig) => ({
41
+ publicRoot: `${standaloneConfig.appRoot}-/`,
42
+ isStandalone: true,
43
+ }))
44
+ .concat(
45
+ {
46
+ publicRoot: `${saStaticRoot}-/`,
47
+ isStandalone: true,
48
+ publicRootWithVersion: true,
49
+ },
50
+ {
51
+ publicRoot: baseHref,
52
+ }
53
+ );
45
54
 
55
+ for (const {
56
+ publicRoot,
57
+ isStandalone,
58
+ publicRootWithVersion,
59
+ } of serveLocalConfigs) {
46
60
  // 开发时默认拦截 bootstrap 请求。
47
61
  // 如果设定 `REMOTE=true`,则透传远端请求。
48
62
  if (useRemote) {
@@ -107,7 +121,7 @@ module.exports = (env, app) => {
107
121
  );
108
122
  });
109
123
 
110
- standaloneConfig ||
124
+ isStandalone ||
111
125
  localMicroApps.forEach((appId) => {
112
126
  // 直接返回本地小产品相关文件。
113
127
  app.get(`${baseHref}micro-apps/${appId}/*`, (req, res) => {
@@ -135,7 +149,7 @@ module.exports = (env, app) => {
135
149
  });
136
150
  });
137
151
 
138
- standaloneConfig ||
152
+ isStandalone ||
139
153
  mockedMicroApps.forEach((appId) => {
140
154
  // 直接返回本地小产品相关文件。
141
155
  app.get(`${baseHref}micro-apps/${appId}/*`, (req, res) => {
@@ -159,7 +173,7 @@ module.exports = (env, app) => {
159
173
  });
160
174
  // API to fulfil the active storyboard.
161
175
  asCdn ||
162
- standaloneConfig ||
176
+ isStandalone ||
163
177
  localMicroApps.concat(mockedMicroApps).forEach((appId) => {
164
178
  app.get(
165
179
  `${baseHref}api/auth(/v2)?/bootstrap/${appId}`,
@@ -176,7 +190,7 @@ module.exports = (env, app) => {
176
190
  );
177
191
  });
178
192
  } else {
179
- if (standaloneConfig) {
193
+ if (isStandalone) {
180
194
  app.get(`${publicRoot}bootstrap.hash.json`, (req, res) => {
181
195
  res.json({
182
196
  navbar: getNavbar(env),
@@ -190,7 +204,7 @@ module.exports = (env, app) => {
190
204
  brief: req.query.brief === "true",
191
205
  })
192
206
  ),
193
- brickPackages: getBrickPackages(env, standaloneConfig),
207
+ brickPackages: getBrickPackages(env, publicRootWithVersion),
194
208
  templatePackages: getTemplatePackages(env),
195
209
  });
196
210
  });
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
  );