基于vue-element-admin公共库建设

1,331 阅读2分钟

背景

公司有几个后台管理项目基于vue-element-admin,公共的组件、公共样式、公共js库及公共页面组件都各写一套。那么就存在以下问题:

  1. 公共部分没有权限控制,团队成员都可以修改。
  2. 公共部分难以维护,修改一个工程要考虑其他工程的代码同步。
  3. 技术得不到沉淀,难以输出团队技术影响力

所以考虑把后管公共部分抽取出一个js文件

分析

  1. public/index.html先引入公共的js,如paview.js

    <!DOCTYPE html>
    <html>
      <head>
        <script src="./paview.js"></script>
      </head>
      <body>
        <div id="app"></div>
        <!-- built files will be auto injected -->
      </body>
    </html>
    
    
  2. 但是公共库依赖于vue.js和element-ui,所以vue.js和element-ui必须在paview.js引入之前引入。

  3. 另外对element-ui的定制,比如主题色样式,也应该属于公共部分

  4. 打包生成公共js的格式应该是umd。参考: segmentfault.com/a/119000001…

    1. 原生webpack需要写一些配置
    2. 使用vue-cli构建库的功能可以更快速生成umd文件,umd会暴露全局变量 cli.vuejs.org/zh/guide/bu…

所以公共库需要打包生成两部分:vue+element--ui和公共库,并在引入时保证顺序。

研究

  1. 在入口文件main.js导出公共的部分

    import Vue from "vue";
    
    import "normalize.css/normalize.css"; // A modern alternative to CSS resets
    
    import ElementUI from "element-ui";
    import "element-ui/lib/theme-chalk/index.css";
    import "@/styles/index.scss"; // global css
    import request from "@/utils/request";
    import Demo from "@/components/demo";
    
    // set ElementUI lang to EN
    Vue.use(ElementUI);
    
    export default {
      version: "1.0.0",
      utils: {
        request,
        Demo,
      },
    };
    
  2. package.json中增加构建命令

    // paview即是公共js暴露的全局变量
    "scripts": {
      "lib": "vue-cli-service build --target lib --name paview src/main.js"
    },
    
  3. 执行npm run lib命令,在dist目录得到输出

     dist/paview.umd.min.js    733.44 KiB               188.17 KiB
     dist/paview.umd.js        1820.97 KiB              349.87 KiB
     dist/paview.common.js     1820.50 KiB              349.72 KiB
     dist/paview.css           235.68 KiB               36.40 KiB
    
  4. 考虑到了公共js访问, 去掉default属性,增加vue.config.js文件, 增加配置

     configureWebpack: {
        output: {
          libraryExport: "default",
        },
        resolve: {
          alias: {
            "@": resolve("src"),
          },
        },
      },
    
  5. 考虑到单独导出element-ui, vue.config.js如下。 打包结果会生成vendors和common

  6. "use strict";
    const path = require("path");
    
    function resolve(dir) {
      return path.join(__dirname, dir);
    }
    
    // All configuration item explanations can be find in https://cli.vuejs.org/config/
    module.exports = {
      publicPath: "/",
      outputDir: "dist",
      productionSourceMap: false,
      lintOnSave: false,
      configureWebpack: {
        output: {
          libraryExport: "default",
        },
        resolve: {
          alias: {
            "@": resolve("src"),
          },
        },
      },
      chainWebpack(config) {
        config.optimization.splitChunks({
          chunks: "all",
          cacheGroups: {
            elementUI: {
              name: "element-ui", // split elementUI into a single package
              priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
              test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
            },
          },
        });
      },
    };
    
    
  7. 要去掉vue-cli默认的vendors和common split chunks,增加配置

  8. cacheGroups: {
            vendors: false,
            common: false,
            elementUI: {
              name: "element-ui", // split elementUI into a single package
              priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
              test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
            },
          },
    
  9. demo.html使用打包后的js和css

    <meta charset="utf-8" />
    <title>paview demo</title>
    
    <link rel="stylesheet" href="./dist/css/element-ui.cf6f4420.css" />
    <link rel="stylesheet" href="./dist/paview.css" />
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="./dist/paview.umd.element-ui.js"></script>
    <script src="./dist/paview.umd.min.js"></script>
    
    <body>
      <div id="app">
        <el-button>按钮</el-button>
        <demo />
      </div>
    </body>
    <script>
      const { request, Demo } = paview.utils;
    
      new Vue({
        el: "#app",
        components: {
          Demo,
        },
      });
      console.log(request);
    </script>
    
    
  10. 效果如下

    ![image-20211031223534946](/Users/wangqiaowen/Library/Application Support/typora-user-images/image-20211031223534946.png)

项目地址:gitee.com/jovenwang/p…