Sing-Spa和qiankuan简单搭建

微前端

视频笔记:www.bilibili.com/video/BV1Dt…
参考链接: juejin.cn/post/695944…

为什么要使用微前端

  • 项目大打包慢
  • 多人协作冲突
  • 团队技术栈不同
  • 每个团队可以独立开发、独立部署
  • 项目中还需要老的应用代码,需要使用新的技术栈

将一个应用划分成若干个子应用,将子应用打包成一个个的lib。当路径切换时加载不同的子应用。这样每个子应用都是独立的,技术栈也不用做限制。从而解决了前端协同开发问题。

应用通信

  • 基于URL来进行数据传输,但是传输消息能力弱
  • 基于CustomEvent实现通信
  • 基于Props主子应用通信
  • 使用权限变量、redux进行通信

公共依赖

  • CDN – extends
  • webpack联邦模块

为什么不是iframe?

  • 如果不考虑体验问题,iframe几乎是最完美的微前端解决方案。
  • iframe最大的特性就是提供了浏览器原生的硬隔离方案,无论是样式隔离、JS隔离这些问题统统都能被完美解决。但他的最大问题也在于他的隔离性无法被突破,导致应用间上下文无法被共享,随之带来的开发体验、产品体验的问题。
  1. url不同步,浏览器刷新iframe url状态丢失,后退前进按钮无法使用。

single-SPA

  • 问题:父子应用,平级应用样式、js冲突
  • 实现了路由截止、路由加载
  • 接入协议:子应用必须提供bootstrap、mount、unmount方法

子应用

  1. 新建子应用

    vue create child-vue
    
    注意: 使用history路由
    复制代码
  2. 安装single-spa-vue

    npm install singe-spa-vue
    复制代码
  3. 修改src目录下的main.js文件

import Vue from 'vue'
import App from './App.vue'
import router from './router'
//  1. 首先引入single-spa-vue
import singleSpaVue from 'single-spa-vue'

Vue.config.productionTip = false

// 2. 新建一个对象,而不是实例化Vue
const appOptions = {
  el: '#vue', //挂载父应用中的id为vue的标签中
  router,
  render: h => h(App)
}

// 3. singleSpaVue包裹
const vueLifeCycle = singleSpaVue({
  Vue,
  appOptions
})

// 5. 父应用引用我, 不加这个,默认跳转父应用的理由
if(window.singleSpaNavigate){
  __webpack_public_path__ = 'http://localhost:10002/'
}

// 6. 子应用独立运行,当前不是作为子应用的情况
if(!window.singleSpaNavigate){
  delete appOptions.el
  new Vue(appOptions).$mount('#app')
}

//4. 协议接入,父应用会调用这些方法
export const bootstrap = vueLifeCycle.bootstrap
export const mount = vueLifeCycle.mount
export const unmount = vueLifeCycle.unmount

复制代码
  1. 将子应用打包成一个lib

    首先需要在根目录下创建一个vue.config.js文件

module.exports = {
    configureWebpack: {
        output: {
            library: 'singleVue',
            library: 'umd' // 最后将数学挂载到window上
        },
        devServer: {
            port: 10000
        }
    }
}
复制代码

父应用

  1. 创建父应用

    vue create parent-vue

    注意:使用history路由

  2. 安装single-spa

    npm install single-spa

  3. 修改src目录下的app.vue文件

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/vue">加载Vue应用</router-link> |
    </div>
    <!--子应用挂载的位置-->
    <div id="vue"></div>
  </div>
</template>
复制代码
  1. 修改src目录下的main.js文件
import Vue from 'vue'
import App from './App.vue'
import router from './router'
// 1. 引入注册子应用方法和启动方法
import { registerApplication, start} from 'single-spa'

Vue.config.productionTip = false


async function loadScript(url){
  return new Promise((resolve, reject)=>{
    let script = document.createElement('script')
    script.src = url
    script.onload = resolve;
    script.onerror = reject;
    document.head.appendChild(script)
  })
}

// 2.注册子应用
registerApplication('myVueApp',
  async ()=>{
      await loadScript('http://localhost:10002/js/chunk-vendors.js') 
      await loadScript('http://localhost:10002/js/app.js')
      return window.singleVue
  },
  location => location.pathname.startsWith('/vue'),
)

// 3. 启动
start();

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

复制代码

single-spa的缺点

  • 不能动态加载js
  • 样式不隔离
  • 全局变量没有js沙箱机制

子应用之间的样式隔离

主应用和子应用之间的样式隔离

JS的隔离

A应用给window加属性window.a, B应用也可以访问window
单应用切换,沙箱 创建一个干净的环境,切换时可以删除属性和恢复属性

js沙箱

  1. 快照沙箱 1年前拍一张,再拍一张,作对比,将区别保存起来
    blog.csdn.net/qq_33226029…
    多个子应用不能使用这种方式
  2. 代理沙箱 es6 proxy
  • 把不同的应用用不同的代理实现
  • qiankuan源码实现js隔离的方式

qiankun

官网:qiankun.umijs.org/zh/guide

  • 技术栈无关,任意技术栈的应用均可使用/接入,不论是React/Vue/Angular/Jquery还是其他框架;
  • HTML Entry接入方式,让你接入微应用像使用iframe一样简单;
  • 样式隔离, 确保微应用之间样式互相不干扰;
  • JS沙箱, 确保微应用之间[全局变量/事件]不冲突;
  • 资源预加载, 在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度;
  • umi插件, 提供了@umijs/plugin-qiankun供umi应用一键切换成微前端系统。

项目实施

新建基座qiankuan-base

  1. 安装qiankuan

npm install qiankuan
2. 修改src目录下的main.js文件

import Vue from 'vue'
import App from './App.vue'
import router from './router'

import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(ElementUI)

Vue.config.productionTip = false
// 1. 引入qiankun
import {registerMicroApps, start} from 'qiankun'
// 2. 创建路由数组
const apps = [
{
  name : 'vueApp', //应用的名字
  entry: 'http://localhost:20000', //子应用支持跨域
  container: '#vue', //挂载容器
  activeRule: '/vue', //激活的路径
  props: {a: 1}
},
{
  name : 'reactApp',
  entry: 'http://localhost:30000', //子应用支持跨域
  container: '#react',
  activeRule: '/react',
 
}
]
// 3. 注册子应用路由
registerMicroApps(apps) //注册应用
// 4. 启动
start({
prefetch: false //取消预加载
}) //启动

new Vue({
router,
render: h => h(App)
}).$mount('#app')

复制代码

新建子应用qiankuan-vue

新建子应用qiankuan-react

  1. 安装react-app-rewired

npm install react-app-rewired

  1. 修改根目录下的package.json文件
 "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-app-rewired eject"
  },
复制代码
  1. 在根目录新建config-overrides.js文件
module.exports = {
    webpack: (config) => {
        config.output.library = 'reactApp';
        config.output.libraryTarget = 'umd'
        config.output.publicPath = "http://localhost:30000"
        return config
    },
    devServer: (configFunction) => {
        return function(proxy, allowedHost){
            const config = configFunction(proxy, allowedHost);
            config.headers = {
                'Access-Control-Allow-Origin': '*'
            }
            return config;
        }
    }
}
复制代码
  1. 修改src目录下的index.js文件
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';


function render(){
  ReactDOM.render(
    <React.StrictMode>
      <App />
    </React.StrictMode>,
    document.getElementById('root')
  );
}

if(!window.__POWERED_BY_QIANKUN__){
  render()
}

export async function bootstrap(){}
export async function mount(){
  render()
}
export async function unmount(){
  ReactDOM.unmountComponentAtNode(document.getElementById('root'))
}
复制代码
  1. 启动qiankun-react子应用

npm run start

从零实现一个微前端框架

初始化开发环境

  1. 新建一个文件夹my-single-spa
  2. 初始化: 执行命令npm init -y
    会生成一个package.json文件
{
  "name": "my-single-spa",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

复制代码
  1. 安装打包工具rollup
  • npm install rollup
  • rollup相对于webpack的好处是:打包出来的代码比较简洁
  1. 安装rollup-plugin-serve
  • npm install rollup-plugin-serve
  • 该工具可以启动应用
  1. 根目录下新建配置文件rollup.config.js
import serve from 'rollup-plugin-serve'

//rollup可以帮我们打包 es6模块化语法
export default {
 input : './src/single-spa.js', //指定入口文件
 output: {
     file: './lib/umd/single-spa.js', //指定出口文件
     format: 'umd',  //指定挂载到window
     name: 'singleSpa',
     sourcemap: true
 },
 plugins: [
    serve({ //服务
        openPage: '/index.html', //默认打开的页面
        contentBase: '',
        port: 3000
    })
 ]
}
复制代码
  1. 根目录下新建入口文件夹src
  2. 根目录下新建index.html文件
  3. 修改根目录下的配置文件package.json
 "scripts": {
    "dev": "rollup -c -w"
  },
复制代码

以上完成rollup环境的搭建

应用加载状态-生命周期

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享