Skip to content

Commit e232b9a

Browse files
authored
Merge pull request #4610 from easyops-cn/steve/v3-perf
Steve/v3 perf
2 parents d647a7e + 226a728 commit e232b9a

File tree

8 files changed

+100
-41
lines changed

8 files changed

+100
-41
lines changed

packages/brick-container/build.config.js

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -118,27 +118,12 @@ export default {
118118
mockdate: {
119119
test: /[\\/]node_modules[\\/]mockdate[\\/]/,
120120
priority: -5,
121-
reuseExistingChunk: true,
122121
name: "mockdate",
123122
minSize: 100,
124123
},
125-
defaultVendors: {
126-
test: /[\\/]node_modules[\\/]/,
124+
all: {
127125
priority: -10,
128-
reuseExistingChunk: true,
129-
name: "vendors",
130-
},
131-
core: {
132-
// Make it compatible with EasyOps CI.
133-
test: /[\\/](?:next-core|data[\\/]easyops)[\\/](?:packages|sdk)[\\/](?!theme[\\/])/,
134-
priority: -10,
135-
reuseExistingChunk: true,
136-
name: "core",
137-
},
138-
default: {
139-
minChunks: 2,
140-
priority: -20,
141-
reuseExistingChunk: true,
126+
name: "all",
142127
},
143128
},
144129
},

packages/brick-container/serve/middlewares/getMiddlewares.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import express from "express";
21
import jsYaml from "js-yaml";
32
import bootstrapJson from "./bootstrapJson.js";
43
import mockAuth from "./mockAuth.js";
54
import singleAppBootstrapJson from "./singleAppBootstrapJson.js";
65
import standaloneBootstrapJson from "./standaloneBootstrapJson.js";
76
import serveBricksWithVersions from "./serveBricksWithVersions.js";
7+
import { serveBricks } from "@next-core/serve-helpers";
88

99
const { safeDump, JSON_SCHEMA } = jsYaml;
1010

@@ -34,7 +34,7 @@ export function getMiddlewares(env) {
3434
});
3535
middlewares.push({
3636
path: `${baseHref}api/v1/runtime_standalone`,
37-
middleware(req, res) {
37+
middleware(_req, res) {
3838
res.send({
3939
code: 0,
4040
data: {
@@ -45,7 +45,7 @@ export function getMiddlewares(env) {
4545
});
4646
middlewares.push({
4747
path: `${baseHref}api/gateway/micro_app_standalone.runtime.RuntimeMicroAppStandalone/api/v1/micro_app_standalone/runtime/:appId`,
48-
middleware(req, res) {
48+
middleware(_req, res) {
4949
res.send({
5050
code: 0,
5151
data: null,
@@ -54,7 +54,7 @@ export function getMiddlewares(env) {
5454
});
5555
middlewares.push({
5656
path: `${baseHref}api/gateway/data_exchange.store.ClickHouseInsertData/api/v1/data_exchange/frontend_stat`,
57-
middleware(req, res) {
57+
middleware(_req, res) {
5858
res.send({
5959
code: 0,
6060
data: null,
@@ -67,7 +67,7 @@ export function getMiddlewares(env) {
6767
}
6868

6969
export function getPreMiddlewares(env) {
70-
const { baseHref, localMicroApps, localBrickFolders, userConfigByApps } = env;
70+
const { baseHref, localMicroApps, userConfigByApps } = env;
7171

7272
/**
7373
* @type {import("webpack-dev-server").Middleware[]}
@@ -81,7 +81,7 @@ export function getPreMiddlewares(env) {
8181
});
8282
middlewares.push({
8383
path: `${baseHref}sa-static/${appId}/versions/0.0.0/webroot/conf.yaml`,
84-
middleware(req, res) {
84+
middleware(_req, res) {
8585
if (userConfigByApps) {
8686
const conf = {
8787
user_config_by_apps: userConfigByApps,
@@ -108,12 +108,10 @@ export function getPreMiddlewares(env) {
108108
middleware: serveBricksWithVersions(env),
109109
});
110110

111-
for (const dir of localBrickFolders) {
112-
middlewares.push({
113-
path: `${baseHref}bricks/`,
114-
middleware: express.static(dir),
115-
});
116-
}
111+
middlewares.push({
112+
path: `${baseHref}bricks/`,
113+
middleware: serveBricks(env),
114+
});
117115

118116
return middlewares;
119117
}

packages/brick-playground/scripts/start.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import path from "node:path";
22
import { existsSync } from "node:fs";
33
import WebpackDevServer from "webpack-dev-server";
4-
import express from "express";
54
import glob from "glob";
65
import { build } from "@next-core/build-next-bricks";
6+
import { serveBricks } from "@next-core/serve-helpers";
77
import config from "../build.config.js";
88
import bootstrapJson from "../serve/bootstrapJson.js";
99
import examplesJson from "../serve/examplesJson.js";
@@ -52,12 +52,10 @@ const server = new WebpackDevServer(
5252
open: true,
5353
port: 8082,
5454
setupMiddlewares(middlewares) {
55-
for (const folder of localBrickFolders) {
56-
middlewares.push({
57-
path: "/preview/bricks/",
58-
middleware: express.static(folder),
59-
});
60-
}
55+
middlewares.push({
56+
path: "/preview/bricks/",
57+
middleware: serveBricks({ localBrickFolders }),
58+
});
6159

6260
middlewares.push({
6361
path: "/preview/",

packages/brick-playground/serve/index.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { existsSync } from "node:fs";
44
import express from "express";
55
import compression from "compression";
66
import glob from "glob";
7+
import { serveBricks } from "@next-core/serve-helpers";
78
import bootstrapJson from "./bootstrapJson.js";
89
import examplesJson from "./examplesJson.js";
910

@@ -46,9 +47,7 @@ const localBrickFolders = (
4647
)
4748
).flat();
4849

49-
for (const folder of localBrickFolders) {
50-
app.use("/preview/bricks/", express.static(folder));
51-
}
50+
app.use("/preview/bricks/", serveBricks({ localBrickFolders }));
5251

5352
app.use("/preview/", bootstrapJson(localBrickFolders));
5453
app.use(examplesJson(rootDir));

packages/serve-helpers/index.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Request, Response } from "express";
1+
import type { Request, Response, NextFunction } from "express";
22

33
export function getBrickPackages(
44
localBrickFolders: string[],
@@ -19,3 +19,6 @@ export function tryServeFiles(
1919
req: Request,
2020
res: Response
2121
): string | undefined;
22+
export function serveBricks(options: {
23+
localBrickFolders: string[];
24+
}): (req: Request, res: Response, next: NextFunction) => void;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from "./getBrickPackages.js";
22
export * from "./tryFiles.js";
3+
export * from "./serveBricks.js";
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// @ts-check
2+
import path from "node:path";
3+
import { tryServeFiles } from "./tryFiles.js";
4+
5+
/**
6+
* @typedef {import("express").Request} Request
7+
* @typedef {import("express").Response} Response
8+
* @typedef {import("express").NextFunction} NextFunction
9+
*/
10+
11+
/**
12+
* @param {{ localBrickFolders: string[] }} options
13+
* @returns {(req: Request, res: Response, next: NextFunction ) => void}
14+
*/
15+
export function serveBricks({ localBrickFolders }) {
16+
/**
17+
* @param {Request} req
18+
* @param {Response} res
19+
* @param {NextFunction} next
20+
*/
21+
return function (req, res, next) {
22+
const files = localBrickFolders.map((dir) =>
23+
path.join(dir, req.path.split("/").join(path.sep))
24+
);
25+
tryServeFiles(files, req, res, next);
26+
};
27+
}

packages/serve-helpers/src/tryFiles.js

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { existsSync } from "node:fs";
1+
import { randomUUID } from "node:crypto";
2+
import { createReadStream, existsSync, statSync } from "node:fs";
23

34
/**
45
* @param files {string|string[]}
@@ -21,8 +22,55 @@ export function tryFiles(files) {
2122
export function tryServeFiles(files, req, res, next) {
2223
const filePath = tryFiles(files);
2324
if (filePath) {
25+
// Express.js doesn't support multiple ranges out of the box.
26+
const range = req.get("range");
27+
if (range) {
28+
const matches = range.match(/bytes=([\d-]+(?:,\s*[\d-]+)+)/);
29+
if (matches) {
30+
const ranges = matches[1].split(/,\s*/g);
31+
if (ranges.length > 1) {
32+
return sendMultiRanges(filePath, ranges, res);
33+
}
34+
}
35+
}
2436
res.sendFile(filePath);
2537
return;
2638
}
2739
next();
2840
}
41+
42+
function sendMultiRanges(filePath, _ranges, res) {
43+
const stat = statSync(filePath);
44+
const fileSize = stat.size;
45+
46+
const ranges = _ranges.map((range) => {
47+
const [start, end] = range.split("-").map(Number);
48+
return {
49+
start: isNaN(start) ? fileSize - end : start,
50+
end: isNaN(end) ? fileSize - 1 : end,
51+
};
52+
});
53+
54+
const boundary = randomUUID().replaceAll("-", "");
55+
res.writeHead(206, {
56+
"Content-Type": `multipart/byteranges; boundary=${boundary}`,
57+
"Last-Modified": stat.mtime.toUTCString(),
58+
"Cache-Control": "max-age=31536000",
59+
// "Expires": "Thu, 12 Feb 2026 09:39:38 GMT",
60+
});
61+
62+
(async () => {
63+
for (const { start, end } of ranges) {
64+
await new Promise((resolve) => {
65+
const stream = createReadStream(filePath, { start, end });
66+
let chunk = `\r\n--${boundary}\r\n`;
67+
chunk += `Content-Range: bytes ${start}-${end}/${fileSize}\r\n\r\n`;
68+
res.write(chunk);
69+
stream.pipe(res, { end: false });
70+
stream.on("end", resolve);
71+
});
72+
}
73+
})().then(() => {
74+
res.end(`\r\n--${boundary}--\r\n`);
75+
});
76+
}

0 commit comments

Comments
 (0)