如何写好简历中的项目经历 —— 以微前端项目为例

137 阅读5分钟

前言

最近面试找工作,写项目经历的时候真的很煎熬,主要是翻来翻去觉得没啥可写的,想必很多人和我一样,当时整天忙于具体业务,无暇顾及其他,当时会议上也听 leader 讲解框架层面的东西,但都是一知半解,云里雾里。那个时候精力都用在理解工作目标、完成工作任务上了。

随着工作经验的增加,回头看过去的项目经历,我们或多或少已经有了一些新的知识储备和上下文信息,收集整理并验证这些信息,然后代入当时的处境里,站在全局的视角看待当时所处的位置和所做的事情,还是有很多可以深挖的点。

以下,以我过去工作参与过的一个微前端改造项目举例,希望给同样需要的你一点启发。

好几年前,在毕业刚进前司的时候,我们的项目迎来了一次微前端的改造,我有幸参与其中,具体的工作是将子项目改造后接入基座应用。

当时情况: YS大佬和GH老大选择的是 qiankun 框架,我主要负责子应用接入,有什么搞不定的地方都是直接请教大佬。

需要重新思考的是:

  1. 子应用具体是怎么接入主应用的?子应用加载、初始化的时机?
  2. 当时微前端架构方案有哪些?为什么是qiankun?要解决的问题是什么?
  3. 时至今日,是否有其他更好的方案?如果现在你遇到同样的问题,你会怎么做?
  4. qiankun的原理是什么?怎么做样式隔离和JS隔离的?子应用和子应用间,子应用和主应用间是如何通信的?
  5. 你当时在接入的时候有没有遇到什么问题?怎么解决的?

1. 子应用接入和初始化时机

接入方式优点缺点适用场景
HTML Entry天然支持CSS隔离需子应用提供完整HTML旧项目改造、多技术栈共存
JS Entry构建产物更轻量需手动处理CSS隔离新项目、技术栈统一

初始化时机

  • 路由匹配:主应用监听路由变化,当路径匹配子应用激活规则时加载。
  • 手动触发:通过loadMicroApp API主动加载。

2. 微前端方案对比与选型

方案优点缺点适用场景
iframe天然隔离,简单易用通信困难,SEO不友好第三方页面嵌入
npm包版本控制严格技术栈耦合,更新需主应用发布内部组件库复用
single-spa框架无关,灵活度高需手动处理沙箱隔离技术栈混合项目
qiankun开箱即用的沙箱隔离,HTML Entry子应用改造成本较高大型复杂应用拆分
  • 选择qiankun的原因

    • 沙箱隔离:JS/CSS隔离避免污染。
    • 技术栈无关:支持不同框架子应用共存。
    • 独立部署:子应用可单独发布。

3. webpack 的模块联邦

需要升级到 webpack 5+,

4. qiankun 的核心原理

qiankun的沙箱机制类似于‘虚拟机’,为每个子应用创建独立的运行环境,卸载时自动‘快照恢复’。 基于single-spa 进行的二次封装,核心原理是运行时的沙箱隔离和通信机制:

  • 沙箱隔离

    • JS隔离:通过Proxy代理全局对象(如window),记录/恢复子应用运行时环境。

    • CSS隔离

      • Shadow DOM:严格隔离(qiankun可选配置)。
      • Scoped CSS:动态添加/移除样式表。
      • 动态样式表隔离存在局限性(如@font-face污染)
  • 通信机制: 主应用和子应用通信:

    • 全局状态:通过initGlobalState实现父子应用通信。
    • 自定义事件:利用window.dispatchEvent跨应用通信。
// 主应用初始化状态
const actions = initGlobalState({ user: null });

// 子应用监听状态变化
actions.onGlobalStateChange((state) => {
  console.log('用户信息变更:', state.user);
});

子应用间通信:

// 子应用A发布事件
window.dispatchEvent(new CustomEvent('app-event', { 
  detail: { type: 'data-update' } 
}));

// 子应用B监听
window.addEventListener('app-event', (e) => {
  console.log(e.detail); // 避免直接传递函数引用
});

5、遇到的问题

  1. 子应用修改 window 全局对象导致状态污染。针对这个问题,可以从 隔离机制代码改造 两个方面解决:
  • 注册子应用时,可以开启配置严格的沙箱模式,并限制子应用对特定全局变量的访问。
  • 尽量使用局部变量,不修改全局变量,如果要共享数据,可以在主应用维护一套eventBus,通过监听变化和回调来。
  • 必须使用全局变量时,使用 qiankun 提供的生命周期钩子,在子应用的 mount 和 unmount 周期中管理全局状态:
// 子应用 entry.js
export async function mount(props) {
  // 挂载时临时设置全局变量
  window.__TEMP_VAR__ = 'value';
}

export async function unmount() {
  // 卸载时清理全局变量
  delete window.__TEMP_VAR__;
}
  • 也可以直接设置 ESLint 规则,禁止直接修改 window。
  1. 子应用公用的第三方库和依赖版本不一致会导致冲突,需要将公共依赖库的版本调至一致,一般来说就是升级旧版本的依赖包到新版本。如果实在无法升级例如需要vue2 和 vue3 共存,可以使用webpack external进行版本隔离。
  • 依赖冲突
    Webpack externals 的配置示例需补充:
  // webpack.config.js
  externals: {
    vue: 'Vue', // 通过CDN引入,避免打包
    react: 'React'
  }
  1. 子应用资源跨域的问题, 需要Nginx配置跨域问题。