# 前端架构(10)

SPA MPA 常驻进程服务 同构 MPA + SPA

node 做接口聚合 接口的数量 接口的二次封装

node 最大优点 轻 便宜

进到html目录
cd /workspace/docker/nginx/data/html

查看目录下文件
ll

将zhihuigongdi-web目录改名
sudo  mv 原文件名 新文件名

将上传的文件放到html目录下
sudo mv /tmp/zhihuigongdi-web  /workspace/docker/nginx/data/html

查看docker容器
docker ps -a

停掉nginx容器 
sudo docker stop c0202a0ea868(容器ID)

替换文件
sudo cp /workspace/docker/nginx/data/html/zhihuigongdi-web
 c0202a0ea868:/usr/share/nginx/html/zhihuigongdi-web

重启nginx容器
sudo docker start c0202a0ea868

ts-node app.ts 

# pm2 核心原理

  1. 核心功能和原理
  • 进程守护:PM2 会在后台守护 Node.js 应用,如果应用崩溃或意外退出,PM2 会自动重启,以保证服务的持续性。它通过监控进程的状态,当检测到进程异常退出时,立即触发重新启动。
  • 负载均衡(Cluster 模式):PM2 通过 Node.js 原生的 Cluster 模块实现负载均衡,在多核 CPU 上开启多个进程(worker),并自动分配请求到不同进程,提升性能和并发处理能力。
  • 日志管理:PM2 会记录应用的 stdout 和 stderr 日志,帮助开发者进行问题排查。同时,PM2 还支持通过 logrotate 插件进行日志分割,防止日志文件过大。
  • 监控和管理:PM2 提供监控命令,可以查看每个进程的状态(如 CPU 使用率、内存占用等),并可以通过 web 界面或 PM2 Plus(付费服务)进行远程监控。
  • 进程持久化:PM2 可以将进程列表保存到一个配置文件中,系统重启后可以自动恢复之前的进程状态。

“PM2 是一个常用的 Node.js 进程管理工具,它通过守护进程和自动重启机制保证应用的高可用性。它使用 Cluster 模式在多核 CPU 上实现负载均衡,并通过日志管理和监控命令帮助开发者排查问题。PM2 的主进程会定期检查和管理各个子进程,确保其正常运行并及时重启异常退出的进程,从而保持服务的稳定性。”

# 项目搭建

├── Dockerfile
├── app.ts
├── assets
├── config
├── docker-compose.yml
├── ecosystem.config.js
├── index.todo
├── interface
├── logs
├── middlewares
├── node_modules
├── package.json
├── routers
├── services
├── tsconfig.json
├── typings
├── views
└── yarn.lock


# koa-swig

const Koa = require('koa');
const Router = require('koa-router');
const render = require('koa-swig');
const path = require('path');
const co = require('co');

const app = new Koa();
const router = new Router();

// 配置模板引擎
app.context.render = co.wrap(
  render({
    root: path.join(__dirname, 'views'), // 模板文件所在的目录
    autoescape: true,
    cache: false, // 生产环境中建议设置为 'memory' 以启用缓存
    ext: 'html', // 模板文件的扩展名
  })
);

// 配置路由
router.get('/', async (ctx) => {
  await ctx.render('index', {
    title: '首页',
    content: '欢迎使用 Koa 和 koa-swig!',
  });
});

app.use(router.routes()).use(router.allowedMethods());

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});

# ioc di aop 在面试时

  1. IoC(Inversion of Control,控制反转)

概念:IoC 是一种设计原则,用于将对象的创建和管理交给容器或框架,而不是由对象自身控制。IoC 通过将控制权交给外部,增强了系统的灵活性和可扩展性。

通过 IoC 容器来管理服务和组件的实例,使得代码更加模块化、可测试。在 React 中,我们也可以使用 Context API 或者 Redux 来实现类似的控制反转效果,让组件的状态和依赖更加集中和便于管理。”

  1. DI(Dependency Injection,依赖注入)

概念:DI 是实现 IoC 的一种具体方式,通过将对象的依赖关系注入到对象内部,而不是在对象内部创建依赖。依赖注入使得对象之间的耦合度降低,提高了代码的可维护性和可测试性。

“依赖注入是控制反转的一种实现方式。在前端开发中,Angular 利用 DI 系统来注入服务和依赖,这使得组件代码更简洁、更易测试。在 Vue 中,我们可以通过插件模式为应用注入全局依赖;在 React 中,可以通过 Context API 或第三方库来实现依赖注入。”

  1. AOP(Aspect-Oriented Programming,面向切面编程)

概念:AOP 是一种编程范式,用于将横切关注点(如日志记录、性能监控、权限验证)从业务逻辑中分离出来,从而实现代码的解耦和重用。

“AOP 是一种将通用功能与业务逻辑分离的编程方式。在前端中,我们可以使用拦截器来实现 AOP,比如在 Vue 或 Angular 中使用 HTTP 拦截器来统一处理请求的日志记录或异常。在 React 中,可以通过高阶组件或 Hooks 抽离横切关注点,实现类似的效果,比如在组件加载时执行特定的逻辑或进行错误边界处理。”

  • 安装 awilix 和 awilix-koa
npm install awilix awilix-koa

创建服务和控制器

// services/UserService.js: 定义一个用户服务,用于处理用户相关的业务逻辑。

class UserService {
  getUserById(id) {
    // 模拟从数据库获取用户
    return { id, name: 'John Doe' };
  }
}

module.exports = UserService;

controllers/UserController.js: 定义一个控制器,将服务注入到控制器中。


const { route, GET } = require('awilix-koa');

@route('/user')
class UserController {
  constructor({ userService }) {
    this.userService = userService; // 依赖注入 UserService
  }

  @route('/:id')
  @GET()
  async getUser(ctx) {
    const user = this.userService.getUserById(ctx.params.id);
    ctx.body = user;
  }
}

module.exports = UserController;

配置依赖注入容器


// app.js: 配置 awilix 容器,并将服务注册到容器中。

const Koa = require('koa');
const Router = require('koa-router');
const { scopePerRequest, loadControllers } = require('awilix-koa');
const { createContainer, asClass } = require('awilix');

const app = new Koa();
const router = new Router();

// 创建 DI 容器
const container = createContainer();

// 注册服务
container.register({
  userService: asClass(require('./services/UserService')).scoped(),
});

// 使用 awilix-koa 中间件
app.use(scopePerRequest(container));
app.use(loadControllers('./controllers/*.js', { cwd: __dirname }));

app.use(router.routes()).use(router.allowedMethods());

app.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});

在此示例中,我们实现了依赖注入(DI)和控制反转(IoC):

  • DI:在 UserController 中,我们通过构造函数注入 UserService,实现了服务的依赖注入,这样控制器和服务被解耦,可以更方便地进行单元测试。
  • IoC:我们使用 awilix 容器来管理依赖,这种方式将对象的创建和依赖管理控制权交给了容器,从而实现了控制反转。

# 静态资源

koa-static

import serve from "koa-static";


app.use(serve(staticDir));

# log4

import { configure, getLogger } from "log4js";

configure({
  appenders: { cheese: { type: "file", filename: `${__dirname}/logs/yd.log` } },
  categories: { default: { appenders: ["cheese"], level: "error" } },
});

const logger = getLogger("cheese");

ErrorHandler.error(app, logger);

import Koa from 'koa';
import { Context } from '@interfaces/IKoa';
import { Logger } from 'log4js';

class ErrorHandler {
  static error(app: Koa, logger: Logger) {
    app.use(async (ctx: Context, next: () => Promise<unknown>) => {
      try {
        await next();
      } catch (e) {
        logger.error(e);
        ctx.body = '500请求啦~恢复中.';
      }
    });

    // MPA和SPA的结合的话 这个中间件就没有用了
    app.use(async (ctx: Context, next: () => Promise<unknown>) => {
      await next();
      if (ctx.status !== 404) {
        return;
      }
      ctx.body =
        '<script type="text/javascript" src="//qzonestyle.gtimg.cn/qzone/hybrid/app/404/search_children.js" charset="utf-8"></script>';
    });
  }
}
export default ErrorHandler;

# koa-swig

import render from "koa-swig";
import serve from "koa-static";
import co from "co";

app.context.render = co.wrap(
  render({
    root: viewDir,
    autoescape: true,
    cache: <"memory" | false>memoryFlag,
    writeBody: false,
    ext: "html",
  })
);
app.use(serve(staticDir));

SSR MPA(纯) 同构

SPA loading 过程长 bigpipe nest next nuxt

# next

alt text

alt text

# 架构13

# Fork TS checker webpack 插件

Fork TS Checker Webpack Plugin 的作用是将 TypeScript 类型检查和 ESLint 检查从 Webpack 的主编译进程中分离出来,在一个单独的工作进程中运行,从而提升编译的速度。

# 优化性能

# Million

给我一些实际的代码 解决生产问题

# 实现ioc

# ts-node-env

 "scripts": {
    "dev": "ts-node-dev --respawn --transpile-only ./index.ts"
  },

# AST

静态语法分析树

# haskey

function haskey<O extends Object>(obj: O, key: PropertyKey): key is keyof O {
  return obj.hasOwnProperty(key);
}

# 私仓

# 创建用户

curl -XPUT \
     -H "Content-type: application/json" \
     -d '{"name": "mywebdream", "password": "123456"}' \
     'http://localhost:4873/-/user/org.couchdb.user:mywebdream'

# multi-repo

# mono-repo

把multi-repo 升级为mono-repo

# Verslon lens

# pnpm workspace

1.工作区间的文件的相互引入 pnpm workspace lerna 2.发包 rush nx.dev lerna pnpm publish(没有办法自动更新版本号) changeset 3.ts 编译到指定的模板 turbo rollup vite webpack(禁忌) esbuild tsc --build --template ts-node-esm bun

pnpm + changeset + bun
yarn workspaces + changeset + turbo
lerna + rollup


feat - 新功能 feature

fix - 修复 bug docs - 文档注释 style - 代码格式(不影响代码运行的变动) refactor - 重构、优化(既不增加新功能,也不是修复bug) perf - 性能优化 test - 增加测试 chore - 构建过程或辅助工具的变动 revert - 回退 build - 打包

Muti-Repo升级至Mono-Repo,实现代码管理统一化与协作效率提升

1.选择一个面试的时候 比较适合你的 整体的方案 2.部署一个tsx的.storybook项目 然后把组件和 对应storybook拆开 3.对应storybook放到apps 私仓中 4.本地搭建私仓、npm用免费的账户发布一个像样的代码 (刷一点star)

# storybook项目

pnpm dlx storybook@latest init

# changeset

 pnpm changeset
pnpm changeset publish

bnb rtc

先公链 在合约

pm2开负载均衡

加机器横向扩容 16g+32核 600台

容器自动扩容 serverLess