微前端之子应用的启动与改造

本文假设你已经创建好了所有子应用。

启动

微前端中往往有多个子应用。

如果要同时启动所有的子应用,你当然可以一个一个的去启动。

如果你嫌这样麻烦的话,接着往下看。

你可以创建这样一个启动脚本文件,命名为 run.js。这个脚本会通过 child_process 创建多个 shell 命令,每个命令负责一个应用,具体代码如下:

js 复制代码
const childProocess = require('child_process')
const path = require('path')

const filePath = {
  vue2: path.join(__dirname, '../vue2'),
  vue3: path.join(__dirname, '../vue3'),
  react15: path.join(__dirname, '../react15'),
  react16: path.join(__dirname, '../react16'),
  main: path.join(__dirname, '../main'),
}
// 进入子目录 npm start 启动项目
function runChild () {
  Object.values(filePath).forEach(item => {
    childProocess.spawn(`cd ${item} && npm start`, {
      stdio: "inherit",
      shell: true
    })
  })
}
runChild()

修改最外层 package.json

json 复制代码
{
  "scripts": {
    "start": "node run.js"
  }
}

执行 npm start,所有应用都会被启动。

注意:每个子应用的启动脚本要统一为 npm start

改造

子应用要想接入微前端,肯定得需要改造,主要调整是在入口文件。

这里分别拿 Vue3 和 React16 举例。

Vue3

改造前:

js 复制代码
import { createApp } from 'vue'
import App from './App.vue'

import router from './router'
createApp(App).use(router).mount('#app')

改造后:

js 复制代码
import { createApp } from 'vue'
import App from './App.vue'

import router from './router'

let instance = null

const render = () => {
  instance = createApp(App)
  instance.use(router).mount('#app')
}

// 不在微前端环境
if(!window.__MICRO_WEB__) {
  render()
}

export const bootstrap = () => {
  console.log('开始加载');
}

export const mount = () => {
  render()
  console.log('渲染成功')
}

export const unmount = () => {
  console.log('卸载', instance)
}

React16

改造前:

js 复制代码
import React from 'react'
import "./index.scss"
import ReactDOM from 'react-dom'
import BasicMap from './src/router';

ReactDOM.render((
    <BasicMap />
  ), document.getElementById('app-react'))

改造后:

js 复制代码
import React from 'react'
import "./index.scss"
import ReactDOM from 'react-dom'
import BasicMap from './src/router';

const render = () => {
  ReactDOM.render((
    <BasicMap />
  ), document.getElementById('app-react'))
}

// 不在微前端环境
if (!window.__MICRO_WEB__) {
  render()
}

export const bootstrap = () => {
  console.log('开始加载');
}

export const mount = () => {
  render()
}

export const unmount = () => {
  console.log('卸载')
}

改造完成后,在 window.vue3 或 window.react16 中都会多出 bootstrapmountunmount 这三个方法。(vue3 和 react16 是在 vue.config.jswebpack.config.js 中分别定义的 library 名字)。

原理分析

webpack 默认打包成立即执行函数:

js 复制代码
(function(){
    ...
})()

如果设置了 library,webpack 将会把打包的结果赋于 library 定义的变量:

js 复制代码
var react16 = (function(){
    ...
})()
相关推荐
kyriewen1 天前
我手写了一个 EventEmitter,面试官追问了 6 个问题——第 4 个我没答上来
前端·javascript·面试
IT_陈寒1 天前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
小林攻城狮1 天前
使用 Transport 节流解决 Vercel AI SDK 流式渲染卡死问题
前端·react.js
前端缘梦1 天前
告别 TS 运行时类型漏洞!Zod 完整入门实战教程(前端 / 全栈必备)
前端·react.js·全栈
the_answer1 天前
Webpack vs Vite 深度对比分析
前端·webpack
转转技术团队1 天前
验证码识别实战:前端不写页面,改训模型了?
前端
MomentYY1 天前
Temperature:AI 的“脑洞旋钮”
前端·llm·ai编程
杉氧1 天前
深入理解 Compose 重组机制:快照系统如何驱动 UI 精准刷新?
android·架构·android jetpack
远航_1 天前
OpenSpec 完整详细介绍
前端·后端
召钱熏1 天前
状态枚举正确≠渲染正确:一个语音按钮的状态机边界修复实录
android·前端