qiankun(乾坤)微前端入门到放弃

349 阅读4分钟

qiankun(乾坤)微前端入门到放弃

1. 什么是qiankun

qiankun 是一个基于 single-spa微前端实现库,旨在帮助大家能更简单、无痛的构建一个生产可用微前端架构系统。

qiankun 孵化自蚂蚁金融科技基于微前端架构的云产品统一接入平台,在经过一批线上应用的充分检验及打磨后,我们将其微前端内核抽取出来并开源,希望能同时帮助社区有类似需求的系统更方便的构建自己的微前端系统,同时也希望通过社区的帮助将 qiankun 打磨的更加成熟完善。

2. 什么是微前端

微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。

微前端架构具备以下几个核心价值:

  • 技术栈无关

主框架不限制接入应用的技术栈,微应用具备完全自主权

  • 独立开发、独立部署

微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新

  • 增量升级

在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略

  • 独立运行时

每个微应用之间状态隔离,运行时状态不共享

3. 创建项目配置运行

3.1 我们以React18为例,创建一个基座(micro-base)、应用1(micro-app1)、应用2(micro-app2)

  • 创建基座

     cnpm create react-app micro-base --template typescript
    
  • 创建应用1

     cnpm create react-app micro-app1 --template typescript
    
  • 创建应用2

     cnpm create react-app micro-app2 --template typescript
    
  • 这里还需要指定一下每个应用的端口号,在3个应用中分别创建.env的文件;micro-base中对应的PORT=3000micro-app1中对应的PORT=3001micro-app2中对应的PORT=3002

     PORT=3000
    

3.2 分别在三个项目中安装qiankun

 npm i qiankun -S # 或者 yarn add qiankun

3.3 接下来的步骤很重要了

3.3.1 首先在micro-base中进行操作

  1. 修改src/index.jsx文件,引入qiankun并注册应用,注意看注释,也可以直接将所有代码拷贝过去

     import React from 'react'
     import ReactDOM from 'react-dom/client'
     import './index.css'
     import App from './App'
     // 1. 引入 qiankun 的 start 和 registerMicroApps 两个方法
     import { start, registerMicroApps } from 'qiankun'
     ​
     // 2. 注册所需要的应用
     registerMicroApps([
       {
         name: 'micro-app1', // 这个是应用的名称
         entry: '//localhost:3001', // 这个对应的应用的访问地址,注意这个端口号,在 3.1 中有配置
         container: '#micro-app1', // 这个是把应用放在哪个容器中,请看第二步中说明
         activeRule: '/micro-app1' // 当前访问的地址中如果匹配到该陆游,激活当前微应用
       },
       {
         name: 'micro-app2', // app name registered
         entry: '//localhost:3002',
         container: '#micro-app2',
         activeRule: '/micro-app2'
       }
     ])
     // 启动监听微应用
     start()
     ​
     const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
     root.render(
       <React.StrictMode>
         <App />
       </React.StrictMode>
     )
     ​
    
  1. 修改App.tsx文件,主要是创建刚刚注册微应用中容器对应的节点,如下

     import React from 'react'
     import logo from './logo.svg'
     import './App.css'
     ​
     function App() {
       return (
         <div className='App'>
           <nav>
             <ul>
               <li>
                 <a href='/micro-app1'>micro-app1</a>
               </li>
               <li>
                 <a href='/micro-app2'>micro-app2</a>
               </li>
             </ul>
           </nav>
           {/* 这里是第一步中 container 对应的容器名称 */}
           <div id='micro-app1'></div>
           <div id='micro-app2'></div>
         </div>
       )
     }
     ​
     export default App
     ​
    

3.3.2 在微应用中的操作

  1. src目录下新建一个文件名为public-path.js运行时publicPath的文件,写入以下内容

     /* eslint-disable */
     if (window.__POWERED_BY_QIANKUN__) {
       __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
     }
    
  1. src/index.jsx文件中引入刚刚创建的文件

     import './public-path'
    
  1. 改写render函数,修改并导出qiankun的生命周期,适配qiankun访问应用,修改后的src/idnex.jsx文件如下;注意看注释

     import React from 'react'
     import ReactDOM from 'react-dom/client'
     import './index.css'
     import App from './App'
     // 引入第一步中创建的文件
     import './public-path'
     ​
     let root: ReactDOM.Root
     function render(props: any) {
       const { container } = props
       // 这里用的 React18 ,要用 createRoot 创建节点,然后渲染。
       // #root 是 public/index.html id 为 root 的 dom 节点
       root = ReactDOM.createRoot(container ? container.querySelector('#root') : document.querySelector('#root'))
       root.render(
         <React.StrictMode>
           <App />
         </React.StrictMode>
       )
     }
     ​
     // @ts-ignore
     if (!window.__POWERED_BY_QIANKUN__) {
       render({})
     }
     ​
     // 乾坤启动触发
     export async function bootstrap() {
       console.log('[react16] react app bootstraped')
     }
     ​
     // 钱快
     export async function mount(props: any) {
       console.log('[react16] props from main framework', props)
       render(props)
     }
     ​
     export async function unmount(props: any) {
       root.unmount()
     }
     ​
    
  1. 修改webpack配置

这里我们安装@rescripts/cli这个插件来修改webpack配置

 npm i -D @rescripts/cli

在根目录新增一个名为.rescriptsrc.js的文件

 const { name } = require('./package')
 ​
 module.exports = {
   webpack: (config) => {
     config.output.library = `${name}-[name]`
     config.output.libraryTarget = 'umd'
     config.output.jsonpFunction = `webpackJsonp_${name}`
     config.output.globalObject = 'window'
 ​
     return config
   },
 ​
   devServer: (_) => {
     const config = _
 ​
     config.headers = {
       'Access-Control-Allow-Origin': '*'
     }
     config.historyApiFallback = true
     config.hot = false
     // config.watchContentBase = false
     config.liveReload = false
 ​
     return config
   }
 }
 ​
  1. 修改package.json中的scripts

     -   "start": "react-scripts start",
     +   "start": "rescripts start",
     -   "build": "react-scripts build",
     +   "build": "rescripts build",
     -   "test": "react-scripts test",
     +   "test": "rescripts test",
     -   "eject": "react-scripts eject"
    

3.3.3 经过上面的步骤已经把micro-app1配置弄好了,micro-app2的配置同micro-app1

  1. 将应用跑起来,在3个目录中分别运行:npm run start
  1. 浏览器访问:http://localhost:3000/micro-app1看是不是出来了micro-app1中输出的内容,如果是说明你成功了。

micro-app2.jpg