最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 从0搭建一个微前端项目(Single-spa)

    正文概述 掘金(G_king)   2021-03-10   826

    背景

    微前端架构模式早就在2016年由ThoughtWorks年提出,微前端是模仿服务端微服务的理念而应用于浏览器端,即将多个单一的单体应用组合起来拼凑成唯一应用,各个单体应用还可以独立开发、独立运行、独立部署,这也是微前端比较重要的特点。

    我司要开发一个中后台项目,本身toB的中后台项目因为周期时间长会形成项目难以维护和项目过大的缺点,我是体验过要完成一个小需求,本来只需要半天的时间就可以完成,结果代码查找和打包部署直接教育了我的天真想法,而且最重要的原因我们是多个团队共同开发,为了让不同的团队之间可以独立开发和部署,互相不影响,必须选择微前端。

    技术选型

    微前端是指一种架构模式,他有很多种实现方式,具体有哪些我就不一一介绍了,建议大家参考前端架构从入门到微前端这本书。

    我们选择的是前端微服务化的实现模式,前端微服务化是指每个前端应用完全独立,通过模块化的方式组合应用。

    技术栈:single-spa + vue

    准备工作

    1. 项目地址
    2. systemjs、相关模块化的知识
    3. single-spa框架
    4. vue相关技术栈

    我司基本流程图:

    从0搭建一个微前端项目(Single-spa)

    主项目

    1.安装依赖:
    • Single-spa
    • Systemjs
    2.子项目注册(microfrontend.js):
    import { registerApplication, start } from 'single-spa';
    
    ///// 文件的相关路径需要替换成自己项目实际路径
    /**
     *
     * 获取子项目app.js文件
     */
    function getApplication(path) {
      return window.System.import(`${path}?time=${new Date().getTime()}`).then((res) => {
        if (res.default) {
          return window.System.import(res.default['app.js']).then((ret) => ret.default);
        }
      });
    }
    /**
     * name: 第一个参数表示应用名称,name必须是string类型
     *
     * app:  加载函数  可以是一个Promise类型的 加载函数,返回的Promise resolve之后的结果必须是一个可以被解析的应用,
     * 这个应用其实是一个包含single-spa各个生命周期函数 的对象(e.g: vue打包 引入后的app.js)。
     *
     * activeWhen: 激活函数 一个纯函数  window.loaction作为第一个参数被调用,只有函数返回的值为true时,应用才会被激活。
     * 通常情况下,activity function会根据 window.location 的path来决定是否需要被激活(我就是这样玩的)
     *
     * single-spa根据顶级路由查找应用,而每个应用会处理自身的子路由。以下场景,single-spa会调用应用的activity funtion
     * 1.hashchange or popstate 事件触发时(vue-router hash或history路由模式都会触发)
     * 2.pushState or replaceState被调用时
     * 3.在single-spa 手动调用 triggerAppChange 方法
     * 4.checkActivityFunctions 方法被调用时
     *
     * customProps
     * 对象 可以表示自定义字段,子应用生命周期函数可以获取
     * 函数 两个参数 应用的名称和window.location
     */
    const development = process.env.NODE_ENV === 'development';
    /// web 部署根域名
    const baseUrl = process.env.VUE_APP_WEB_URL;
    
    const configProject = [
      {
        name: 'app1',
        app: window.System.import('app-demo1').then((res) => res.default), /// 子项目通过插件完成配置的引入方式
        activeWhen: (location) => location.pathname.startsWith('/app1'),
        customProps: {
          // 对象
          everything: 'just do it'
        }
        //   customProps: (name, location) => {
        //     // 函数
        //     return {everything: 'just do it'};
        //   }
      },
      {
        name: 'app2',
        app: getApplication(development ? 'http://localhost:8993/manifest.json' : `${baseUrl}/app2/manifest.json`),
        activeWhen: (location) => location.pathname.startsWith('/app2'),
        customProps: {
          // 对象
          everything: 'just do it'
        }
      }
    ];
    
    /// 注册子应用
    configProject.forEach((element) => {
      registerApplication(element);
    });
    // 暴露single-spa启动方法 可以控制子应用的激活时机
    export function appStart() {
      return start();
    }
    
    
    3.修改入口文件(main.js):
    相关逻辑代码,全部代码可以查看项目。
    // 引入启动方法
    import { appStart } from './microfrontend';
    
    // Single-spa启动方法在此处调用,是因为我们项目一般需要前置条件才会容许项目挂载 挂载应用
    
    /// e.g 比如登录
    // async function login() {
    //   await 相关接口请求
    //   appStart();
    // }
    appStart();
    
    4.修改router.js文件:
    5.import maps:
    <!--  配置导入映射的,模块必须符合以下三种规范之一:
          1. System.register - https://github.com/systemjs/systemjs/blob/master/docs/system-register.md
          2. UMD ( 推荐 )
          3. Global variable
    -->
    e.g: 
    <script type="systemjs-importmap">
          {
            "imports": {
              "vue": "https://cdn.jsdelivr.net/npm/vue@2.6.11",
              "vue-router": "https://unpkg.com/vue-router@3.2.0/dist/vue-router.js",
              "vuex": "https://unpkg.com/vuex@3.4.0",
              "lodash": "https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js",
              "dayjs": "https://unpkg.com/dayjs@1.8.21/dayjs.min.js",
              "app-demo1": "http://localhost:8992/js/app.js?time=<%=version%>"
            }
          }
    </script>
    

    子项目

    子项目(vue)的改造有两种方法,第一个是通过插件去修改相关配置(不推荐),第二个是自己动手修改相关配置,两种方式都在项目中使用了,分别代表的项目是app-demo1和app-demo2。

    手动配置

    1.安装相关依赖:
    • single-spa-vue
    • webpack-manifest-plugin
    2.修改入口文件(main.js):
    import Vue from 'vue';
    import App from './App.vue';
    import router from './router';
    import store from './store';
    // 新增
    import singleSpaVue from 'single-spa-vue';
    
    Vue.config.productionTip = false;
    
    const appOptions = {
      render: (h) => h(App),
      router, // 路由
      store // vuex
    };
    // 判断是微前端加载还是独立运行
    if (!window.singleSpaNavigate) {
      new Vue(appOptions).$mount('#app');
    }
    const vueLifecycles = singleSpaVue({
      Vue, //(必传项) 主Vue对象
      appOptions
    });
    
    // single-spa 生命周期函数 三个生命周期函数必须都有
    export const bootstrap = vueLifecycles.bootstrap;
    export const mount = vueLifecycles.mount;
    export const unmount = vueLifecycles.unmount;
    
    3.修改vue.config.js文件(修改webpack配置):
    const packageName = require('./package.json').name;
    const { WebpackManifestPlugin } = require('webpack-manifest-plugin'); // 资源清单 协助主应用加载资源
    
    module.exports = {
      // 设定好publicPath, 端口最好是一个固定值
      publicPath: process.env.NODE_ENV === 'production' ? '/app-demo2' : 'http://localhost:8993',
      configureWebpack: (config) => {
        config.output.libraryTarget = 'umd'; // 打包格式为umd 配合模块加载工具加载项目
        config.output.library = packageName;
        config.output.jsonpFunction = `webpackJsonp_${packageName}`;// 防止全局变量webpackJsonp冲突
        // 删除chunk-vendors.js文件,公共三方模块打包进app.js文件
        config.optimization.splitChunks.cacheGroups = {};
        //config.optimization.delete('splitChunks');
    
        // 打包时移除这些通用库,配合systemjs从root加载  
        //  注意⚠️ 和上文importmap相关联
        config.externals = ['vue', 'vue-router', 'vuex', 'lodash', 'dayjs'];
    
        /// 主项目加载的xxx.mainifest.json文件
        config.plugins.push(
          new WebpackManifestPlugin({
            fileName: 'manifest.json'
            // filter: function(option) {
            //   return option.isInitial;
            // }
          })
        );
      },
      devServer: {
        headers: {
          // 开发模式下解决微前端加载时跨域的问题
          'Access-Control-Allow-Origin': '*'
        }
      },
      css: {
        // css不单独打包成一个文件,和js打包进一个文件 这个也会造成css污染问题,通过其他方式避免。
        extract: false
      }
    };
    

    插件

    前提是通过vuecli创建的项目;通过插件修改的前提是子项目最好是新项目,因为插件会修改main.js文件,会造成代码丢失。
    

    终端执行:

    Vue add single-spa
    

    这个插件帮助我们做了哪些事情呢???

    注意事项

    1.css样式隔离:
    2.js隔离:
    3.应用之间通信:

    参考

    • 每日优鲜微前端实践
    • 字节跳动微前端实践
    • 爱奇艺微前端实践
    • 美团微前端实践

    起源地下载网 » 从0搭建一个微前端项目(Single-spa)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元