脚手架优化

本章节主要介绍idm-module-vue脚手架优化方式。最新版脚手架已经修改点此进入在新窗口打开

优化涉及相关文件

package.json

"scripts": {
    "serve": "npm run serve:dynamic",
    "serve:static": "cross-env FILE_MODE=static  vue-cli-service serve",
    "serve:dynamic": "cross-env FILE_MODE=dynamic  vue-cli-service serve",
    "build": "npm run build:all",
    "build:static": "cross-env FILE_MODE=static vue-cli-service build",
    "build:dynamic": "cross-env FILE_MODE=dynamic vue-cli-service build",
    "build:static:no-clean": "cross-env FILE_MODE=static vue-cli-service build --no-clean",
    "build:dynamic:no-clean": "cross-env FILE_MODE=dynamic vue-cli-service build --no-clean",
    "build:all": "npm run clean && npm run build:dynamic:no-clean && npm run build:static:no-clean && npm run zip",
    "lint": "vue-cli-service lint",
    "zip": "idm zip",
    "clean": "node ./webpack/clean.js",
    "gen": "idm-generate vue"
},
"devDependencies": {
    "cross-env": "^7.0.3",
    "chalk": "^4.1.2"
}

vue.config.js

const path = require('path')
const chalk = require('chalk')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const webpack = require('webpack');
const isDev = process.env.NODE_ENV === 'development'
function resolve(dir) {
    return path.join(__dirname, dir)
}
const fileMode = process.env.FILE_MODE || 'dynamic'
let indexName = 'index';
if(fileMode== 'static') {
  indexName = 'index2'
}
console.log(`${chalk.blue('Current file mode')}   ------ >  ${chalk.yellow(fileMode)}`)
console.log(`${chalk.blue('Current file index')}  ------ >  ${chalk.yellow(indexName)}`)
console.log(`${chalk.green('Start building .....')}`)
const entryFileMap = {
  dynamic: 'src/main.js',
  static: 'src/mainStatic.js'
}
let assetsDir = "./static";
let getAssetsDir = function(filename) {
  return path.posix.join(assetsDir, filename);
};
let uuidCharts = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split("");
let getGUID = function(len, radix) {
  var chars = uuidCharts,
      uuid = [],
      i;
  radix = radix || chars.length;
  len = len || 16;
  if (len) {
      for (i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)];
  } else {
      var r;
      uuid[8] = uuid[13] = uuid[18] = uuid[23] = "";
      uuid[14] = "4";
      for (i = 0; i < 36; i++) {
          if (!uuid[i]) {
              r = 0 | (Math.random() * 16);
              uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r];
          }
      }
  }

  return uuid.join("");
}
const splitChunks = {
  chunks: 'async',
  minSize: 2000000,
  minChunks: 1,
  maxAsyncRequests: 30,
  maxInitialRequests: 30,
  enforceSizeThreshold: 50000,
  cacheGroups: {
    vendors: {
      name: 'chunk-vendors2',
      test: /[\\/]node_modules[\\/]/,
      enforce: true,
      reuseExistingChunk: true,
      priority: 0
    }
  },
}
const externals = {
  vue: 'Vue',
  'vue-router': 'VueRouter',
  vuex: 'Vuex',
  // axios: 'axios',
  jquery: '$'
}
module.exports = {
    publicPath:"./",
    assetsDir:assetsDir,
    productionSourceMap: false,
    pages:{
      [indexName]: {
        entry: entryFileMap[fileMode],
        template: 'public/index.html',
        filename: 'index.html',
        title: '',
        includeScripts: [
           "./lib/vue.min.js",
           "./lib/jquery.min.js",
            "./lib/axios.min.js",
            "./lib/qs.js",
            "./lib/lodash.min.js",
            "./lib/idm.core.js"
        ],
        includeCss:[
          "./lib/idm.base.css"
        ]
      },
    },
    chainWebpack(config) {
      config.externals(externals)
      config
      .plugin('define')
      .tap(args => { 
          args[0]['process.env.CodeVar'] = JSON.stringify("CodeVar_"+getGUID()+"_"+new Date().getTime());
          return args
      })
      config.module
        .rule('svg')
        .exclude.add(resolve('src/icons'))
        .end()
      config.module
        .rule('icons')
        .test(/\.svg$/)
        .include.add(resolve('src/icons'))
        .end()
        .use('svg-sprite-loader')
        .loader('svg-sprite-loader')
        .options({
          symbolId: 'icon-[name]'
        })
        .end()
    },
    configureWebpack: {
      optimization: fileMode == 'dynamic' ?  undefined : { splitChunks },
      plugins: [
        new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn/)
      ],
      output: {
        filename: `${assetsDir}/js/[name].js`,
        chunkFilename: `${assetsDir}/js/[name].js`,
        jsonpFunction:JSON.stringify("webpackJsonp_"+getGUID()+"_"+new Date().getTime())
      },
      resolve:{
        extensions: ['.js', '.vue', '.json'],
        alias: {
          '@ant-design/icons/lib/dist$': resolve('src/plugins/antdicons.js')
        }
      }
    },
    css: {
        extract: isDev ? false : {
          filename: `${assetsDir}/css/[name].css`,
          chunkFilename: `${assetsDir}/css/[name].css`
        },
        sourceMap: isDev,
        requireModuleExtension: true,
        loaderOptions: {
          sass: {
          }
        }
    },
    devServer: {
        proxy: {
            '^/DreamWeb/*': {
                target: "http://localhost:8080",
                changeOrigin: true,
                secure: false
            }
        }
    }

}

webpack/clean.js

const fs = require('fs');
const chalk = require('chalk')
function removeDirectory(path) {
  if (fs.existsSync(path)) {
    fs.readdirSync(path).forEach((file) => {
      const curPath = path + '/' + file;
      if (fs.lstatSync(curPath).isDirectory()) {
        removeDirectory(curPath)
      } else {
        fs.unlinkSync(curPath)
      }
    });
    fs.rmdirSync(path)
  }
}
removeDirectory('dist')
console.log(chalk.green('Clean dist success!'))

src/mainStatic.js

import Vue from 'vue'
import './core/regModule';
import config from '../public/static/config.json';
import '@/icons' // icon
import "@/plugins/ant-design-vue"

config && config.module.forEach(item => {
  const _cp = () => import(/* webpackChunkName: "[request]" */ `./components/${item.className}.vue`)
  Vue.component(item.className+"@"+config.className+"-" +config.version, _cp)
})

Vue.config.productionTip = false
Vue.config.devtools = true

src/Main.vue

<template>
    <component :is="`${componentName}`" @hook:mounted="handleComponentMounted" :ref="`${componentName}`"/>
</template>

<script>

export default {
  name: 'Main',
  data(){
    return {
      componentName: this.$root.componentName
    }
  },
  methods: {
    handleComponentMounted(){
      const that = this;
      this.$refs[this.componentName].$nextTick(()=>{
        that.$root.moduleObject.mountComplete && that.$root.moduleObject.mountComplete(that.$root.moduleObject);
      })
    }
  }
}
</script>

src/regModule.js

mounted() {
    //加载完成回调
    // this.$nextTick(function () {
    //     moduleObject.mountComplete && moduleObject.mountComplete(moduleObject);
    // })
}