chore: 优化前后端一体部署策略,将前端代码的代理方式交给gateway并对gateway增加spa支持

pull/49/head
moonrailgun 3 years ago
parent 23e690c5ae
commit 3b4321c27f

@ -72,7 +72,7 @@ export async function fetchRegistryPlugins(): Promise<PluginManifest[]> {
*
*/
export async function fetchServiceRegistryPlugins(): Promise<PluginManifest[]> {
const { data } = await request.get('/registry.json');
const { data } = await request.get('/registry-be.json');
return data;
}

@ -1,21 +1,6 @@
version: "3.3"
services:
# 应用网关
web:
build:
context: .
image: tailchat
restart: unless-stopped
env_file: docker-compose.env
labels:
- "traefik.enable=true"
- "traefik.http.routers.web.rule=Method(`GET`) || (Path(`/`) || PathPrefix(`/main`) || PathPrefix(`/entry`))"
- "traefik.http.services.web.loadbalancer.server.port=11011"
command: npx http-server-spa ./client/web/dist index.html 11011
networks:
- internal
# 应用网关
service-gateway:
build:

@ -8,7 +8,7 @@
"dev:web": "cd client/web && pnpm run dev",
"dev:server": "cd server && pnpm run dev",
"start:service": "cd server && pnpm run start:service",
"build": "concurrently npm:build:web npm:build:server && cp -r client/web/dist/* server/dist/public",
"build": "concurrently npm:build:web npm:build:server && cp -r client/web/dist/* server/dist/public && cp -r client/web/dist/* server/dist/public",
"build:web": "cd client/web && pnpm run build",
"build:server": "cd server && pnpm run build && echo \"Install server side plugin:\" && pnpm run plugin:install com.msgbyte.tasks com.msgbyte.linkmeta com.msgbyte.github com.msgbyte.simplenotify && mkdir -p ./dist/public && cp -r ./public/plugins ./dist/public && cp ./public/registry.json ./dist/public",
"check:type": "concurrently npm:check:type:client npm:check:type:server",

@ -479,6 +479,7 @@ importers:
'@moonrailgun/socket.io-admin-ui': ^0.2.1
'@socket.io/redis-adapter': ^7.0.0
'@typegoose/typegoose': 9.3.1
'@types/accepts': ^1.3.5
'@types/bcryptjs': ^2.4.2
'@types/blessed': ^0.1.19
'@types/bluebird': ^3.5.36
@ -498,6 +499,9 @@ importers:
'@types/node': 16.11.7
'@types/nodemailer': ^6.4.4
'@types/oidc-provider': ^7.8.1
'@types/send': ^0.17.1
'@types/serve-static': ^1.15.0
accepts: ^1.3.8
bcryptjs: ^2.4.3
bluebird: ^3.7.2
crc: ^3.8.0
@ -535,6 +539,8 @@ importers:
prettier: ^2.3.2
qs: ^6.10.3
redlock: ^4.2.0
send: ^0.18.0
serve-static: ^1.15.0
socket.io: ^4.2.0
socket.io-client: ^4.1.3
tailchat-server-sdk: workspace:*
@ -548,6 +554,7 @@ importers:
'@typegoose/typegoose': 9.3.1_mongoose@6.1.1
'@types/blessed': 0.1.19
'@types/bluebird': 3.5.36
accepts: 1.3.8
bcryptjs: 2.4.3
bluebird: 3.7.2
crc: 3.8.0
@ -574,12 +581,15 @@ importers:
oidc-provider: 7.11.5
qs: 6.11.0
redlock: 4.2.0
send: 0.18.0
serve-static: 1.15.0
socket.io: 4.5.1
tailchat-server-sdk: link:packages/sdk
ts-node: 10.9.1_t4lrjbt3sxauai4t5o275zsepa
typescript: 4.7.4
devDependencies:
'@babel/helper-compilation-targets': 7.18.9
'@types/accepts': 1.3.5
'@types/bcryptjs': 2.4.2
'@types/crc': 3.8.0
'@types/ejs': 3.1.1
@ -597,6 +607,8 @@ importers:
'@types/node': 16.11.7
'@types/nodemailer': 6.4.5
'@types/oidc-provider': 7.11.1
'@types/send': 0.17.1
'@types/serve-static': 1.15.0
fs-extra: 10.1.0
gulp-sort: 2.0.0
i18next-scanner: 3.3.0
@ -6238,6 +6250,10 @@ packages:
dependencies:
'@types/unist': 2.0.6
/@types/mime/1.3.2:
resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==}
dev: true
/@types/mime/2.0.3:
resolution: {integrity: sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==}
dev: true
@ -6476,6 +6492,13 @@ packages:
/@types/scheduler/0.16.2:
resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
/@types/send/0.17.1:
resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==}
dependencies:
'@types/mime': 1.3.2
'@types/node': 18.7.11
dev: true
/@types/serve-index/1.9.1:
resolution: {integrity: sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==}
dependencies:
@ -14694,7 +14717,7 @@ packages:
pretty-format: 27.5.1
slash: 3.0.0
strip-json-comments: 3.1.1
ts-node: 10.9.1_bqee57coj3oib6dw4m24wknwqe
ts-node: 10.9.1_t4lrjbt3sxauai4t5o275zsepa
transitivePeerDependencies:
- bufferutil
- canvas
@ -22838,7 +22861,6 @@ packages:
typescript: 4.7.4
v8-compile-cache-lib: 3.0.1
yn: 3.1.1
dev: false
/ts-pnp/1.2.0_typescript@4.7.4:
resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==}

@ -37,6 +37,7 @@
"@typegoose/typegoose": "9.3.1",
"@types/blessed": "^0.1.19",
"@types/bluebird": "^3.5.36",
"accepts": "^1.3.8",
"bcryptjs": "^2.4.3",
"bluebird": "^3.7.2",
"crc": "^3.8.0",
@ -63,6 +64,8 @@
"oidc-provider": "^7.10.6",
"qs": "^6.10.3",
"redlock": "^4.2.0",
"send": "^0.18.0",
"serve-static": "^1.15.0",
"socket.io": "^4.2.0",
"tailchat-server-sdk": "workspace:*",
"ts-node": "^10.0.0",
@ -70,6 +73,7 @@
},
"devDependencies": {
"@babel/helper-compilation-targets": "^7.18.2",
"@types/accepts": "^1.3.5",
"@types/bcryptjs": "^2.4.2",
"@types/crc": "^3.4.0",
"@types/ejs": "^3.1.0",
@ -87,6 +91,8 @@
"@types/node": "16.11.7",
"@types/nodemailer": "^6.4.4",
"@types/oidc-provider": "^7.8.1",
"@types/send": "^0.17.1",
"@types/serve-static": "^1.15.0",
"fs-extra": "^10.0.0",
"gulp-sort": "^2.0.0",
"i18next-scanner": "^3.0.0",

@ -11,6 +11,7 @@ const _ = require('lodash');
const containerPath = path.resolve(__dirname, '../plugins');
const publicPath = path.resolve(__dirname, '../public');
const registryPath = path.resolve(publicPath, './registry-be.json');
const list = fs.readdirSync(containerPath);
const dirs = list.filter((item) =>
@ -57,14 +58,9 @@ async function start() {
// 追加前端配置到registry
const originRegistry =
(await fs
.readJSON(path.resolve(publicPath, './registry.json'))
.catch(() => [])) ?? [];
(await fs.readJSON(registryPath).catch(() => [])) ?? [];
const newRegistry = _.uniqBy([manifest, ...originRegistry], (m) => m.name);
await fs.writeJSON(
path.resolve(publicPath, './registry.json'),
newRegistry
);
await fs.writeJSON(registryPath, newRegistry);
console.log('└ 安装完毕:', p);
}

@ -14,6 +14,9 @@ import {
import { TcHealth } from '../../mixins/health.mixin';
import type { Readable } from 'stream';
import { checkPathMatch } from '../../lib/utils';
import serve from 'serve-static';
import accepts from 'accepts';
import send from 'send';
export default class ApiService extends TcService {
authWhitelist = [];
@ -50,11 +53,11 @@ export default class ApiService extends TcService {
// Logging the response data. Set to any log level to enable it. E.g. "info"
this.registerSetting('logResponseData', null);
// Serve assets from "public" folder
this.registerSetting('assets', {
folder: 'public',
// Options to `server-static` module
options: {},
});
// this.registerSetting('assets', {
// folder: 'public',
// // Options to `server-static` module
// options: {},
// });
this.registerSetting('cors', {
// Configures the Access-Control-Allow-Origin CORS header.
origin: '*',
@ -69,6 +72,27 @@ export default class ApiService extends TcService {
// Configures the Access-Control-Max-Age CORS header.
maxAge: 3600,
});
// this.registerSetting('rateLimit', {
// // How long to keep record of requests in memory (in milliseconds).
// // Defaults to 60000 (1 min)
// window: 60 * 1000,
// // Max number of requests during window. Defaults to 30
// limit: 30,
// // Set rate limit headers to response. Defaults to false
// headers: true,
// // Function used to generate keys. Defaults to:
// key: (req) => {
// return (
// req.headers['x-forwarded-for'] ||
// req.connection.remoteAddress ||
// req.socket.remoteAddress ||
// req.connection.socket.remoteAddress
// );
// },
// });
this.registerMethod('authorize', this.authorize);
@ -83,6 +107,7 @@ export default class ApiService extends TcService {
getRoutes() {
return [
// /api
{
path: '/api',
whitelist: [
@ -166,6 +191,7 @@ export default class ApiService extends TcService {
// Enable/disable logging
logging: true,
},
// /upload
{
// Reference: https://github.com/moleculerjs/moleculer-web/blob/master/examples/file/index.js
path: '/upload',
@ -217,6 +243,7 @@ export default class ApiService extends TcService {
mappingPolicy: 'restrict',
},
// /health
{
path: '/health',
aliases: {
@ -224,6 +251,7 @@ export default class ApiService extends TcService {
},
mappingPolicy: 'restrict',
},
// /static 对象存储文件代理
{
path: '/static',
authentication: false,
@ -257,6 +285,25 @@ export default class ApiService extends TcService {
},
mappingPolicy: 'restrict',
},
// 静态文件代理
{
path: '/',
authentication: false,
authorization: false,
use: [serve('public', {})],
onError(req: IncomingMessage, res: ServerResponse, err) {
if (
String(req.method).toLowerCase() === 'get' && // get请求
accepts(req).types(['html']) && // 且请求html页面
err.code === 404
) {
// 如果没有找到, 则返回index.html(for spa)
console.log('fallback to fe entry file');
send(req, './public/index.html', { root: process.cwd() }).pipe(res);
}
},
autoAliases: false,
},
];
}

Loading…
Cancel
Save