vue-cli项目优化笔记

一、背景

  1. 项目采用vue-cli搭建,起初为单模板页面,后面为了将功能划分细致一些,采用了多模板的方式。
  2. 随着项目越来庞大,引入的第三方插件也越来越多。开发模式下热更新慢,编译速度慢,编译后的单文件也越来越大。

为了解决以上问题,参照网上已有解决方案,主要从以下几个方面入手进行项目结构的优化。

二、多模板页面的自动化

  1. 在未引入自动化之前多模板的目录结构如下:

src目录中卫主要的入口文件

修改相关配置文件 在build目录下:

webpack.base.conf.js

module.exports = {
  entry: {
    app: "./src/main.js",
    login:'./src/login.js',
    admin:'./src/admin.js',
  },
}

  
复制代码

webpack.dev.conf.js

plugins: [
    new HtmlWebpackPlugin({
      filename: 'login.html',
      template: 'login.html',
      inject: true,
      excludeChunks: ['app','admin']
    }),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html',
      inject: true,
      excludeChunks: ['login','admin']
    }),
    new HtmlWebpackPlugin({
      filename: 'admin.html',
      template: 'admin.html',
      inject: true,
      excludeChunks: ['login','app']
    }),
  ]

复制代码

webpack.prod.conf.js

plugins: [
    new HtmlWebpackPlugin({
      filename: config.build.index,
      template: 'index.html',
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      },
      excludeChunks: ['login','admin'],
      chunksSortMode: 'dependency'
    }),
    new HtmlWebpackPlugin({
      filename: config.build.login,
      template: 'login.html',
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      },
      excludeChunks: ['app','admin'],
      chunksSortMode: 'dependency'
    }),
    new HtmlWebpackPlugin({
      filename: config.build.admin,
      template: 'admin.html',
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      },
      excludeChunks: ['app','login'],
      chunksSortMode: 'dependency'
    }),
]
复制代码

相关字段的解释请查看 webpack 简介

配置完以上后能保证项目可以正常访问,能够正常使用,但是如果需要再增加模板文件后,就需要更改以上所有的地方,这样非常不方便项目的扩展。因此就优化了项目目录结构,将上述用到的地方都通过方法返回。

  1. 优化后的目录结构

在项目目录下新建template,各个模板文件如上图所示。

在build目录中的utils中增加函数entrieshtmlPlugin


// glob是webpack安装时依赖的一个第三方模块,还模块允许你使用 *等符号, 例如lib/*.js就是获取lib文件夹下的所有js后缀名的文件
var glob = require('glob');


//多入口配置
// 通过glob模块读取pages文件夹下的所有对应文件夹下的js后缀文件,如果该文件存在
// 那么就作为入口处理
exports.entries = function () {
  var entryFiles = glob.sync(PAGE_PATH + '/*/*.js')
  var map = {}
  entryFiles.forEach((filePath) => {
    var files=filePath.split('/');
    var filename = files[files.length-2];
    map[filename] = filePath;
  })
  return map
}

//多页面输出配置
// 与上面的多页面入口配置相同,读取pages文件夹下的对应的html后缀文件,然后放入数组中
exports.htmlPlugin = function () {
  let entryHtml = glob.sync(PAGE_PATH + '/*/*.html')
  let arr = []
  var fileNames=[];
  entryHtml.forEach((filePath)=>{
    var files=filePath.split('/');
    var filename = files[files.length-2];
    let obj={
      path:filePath,
      name:filename
    }
    fileNames.push(obj);
  })

  fileNames.forEach((obj) => {
    let conf = {
      // 模板来源
      template: obj.path,
      // 文件名称
      filename: obj.name +'.html',
      // 页面模板需要加对应的js脚本,如果不加这行则每个页面都会引入所有的js脚本
      inject: true,
      excludeChunks: (function(){
        let arr=[];
        fileNames.forEach(item=>{
          if(item.name!=obj.name){
            arr.push(item.name);
          }
        })
        return arr;
      })()
    }
    if (process.env.NODE_ENV === 'production') {
      conf = merge(conf, {
        minify: {
          removeComments: true,
          collapseWhitespace: true,
          removeAttributeQuotes: true
        },
        chunksSortMode: 'dependency'
      })
    }
    arr.push(new HtmlWebpackPlugin(conf))
  })
  return arr
}

复制代码

webpack.base.conf.js

const utils = require('./utils');
module.exports = {
    entry:utils.entries(),
}

复制代码

webpack.dev.conf.js

const utils = require('./utils');

plugins: [
    new webpack.DefinePlugin({
      'process.env': merge(require('../config/dev.env'),
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
    new webpack.NoEmitOnErrorsPlugin(),
    // copy custom static assets
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../static'),
        to: config.dev.assetsSubDirectory,
        ignore: ['.*']
      }
    ])
  ].concat(utils.htmlPlugin())
复制代码

webpack.prod.conf.js

plugins:[].concat(utils.htmlPlugin())
复制代码

三、打包速度的优化

  1. 将webpack3升级为webpack4,传说速度能优化不少,但是没有试过。
  2. 引入happypack HappyPack 允许 Webpack 使用 Node多线程进行构建来提升构建的速度。参考请见webpack优化之HappyPack 实战
  3. 采用DllPlugin也能提升打包速度
  4. 将资源按需引入,
  5. 在html中引入压缩资源

四、优化编译后的单文件大小

在优化打包的单文件之前,可以先引入插件 webpack-bundle-analyzer这个插件可以可视化分析打包文件的相关情况 使用方式

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
  plugins: [
     new BundleAnalyzerPlugin(),
    ]
复制代码

运行截图,此截图为优化之后的结果

  1. 引入DllReferencePlugin
  • 在build目录下新建vendor-manifest.jsonwebpack.dll.config.js文件,

webpack.dll.config.js

const path = require('path');
const webpack = require('webpack');
const glob = require('glob');
const fs = require('fs');
const {JSDOM} = require('jsdom');

// 取得相应的页面路径,因为之前的配置,所以是src文件夹下的pages文件夹
var PAGE_PATH = path.resolve(__dirname, '../template');

//动态的生成文件名,为了解决浏览器缓存问题,同文件名会因为浏览器缓存问题
const file_name = 'vendor.' + (new Date()).getTime() + '.dll.js';

/****
* 遍历template目录下的html文件,引入生成好的dll.js文件
***/
function set_html_vendor() {

  //删除已有的vendor文件
  var vendor_file = glob.sync(path.resolve(__dirname, '../static/js/') + '*/*.dll.js');
  vendor_file.map(file => [
    fs.unlink(file, function (err) {
      if (err) {
        throw err;
      }
    })
  ])

  //找到所有的html模板
  var entryFiles = glob.sync(PAGE_PATH + '/*/*.html');
  entryFiles.map(item_path => {
    fs.readFile(item_path, function (err, data) {
      if (err) {
        throw err;
      }
      var data_string = data.toString();
      //转成dom对象方便读取
      var {
        document
      } = (new JSDOM(data_string)).window;
      //更改路径
      document.querySelector('#vendor_script').src = '/static/js/' + file_name;
      //将修改完成的写入到文件中
      fs.writeFile(item_path, '\n\n' + document.querySelector('html').innerHTML + '\n', function (err) {
        if (err) {
          throw err;
        }
      })
    })
  })
}

set_html_vendor();

module.exports = {
  entry: {
    vendor: [
      // 'element-ui',
      'babel-polyfill',
      'vue-awesome-swiper',
      'vue-i18n',
      'echarts',
      'vue-amap',
      'vue',
      'vue-router',
      'vuex',
      'jspdf',
      'html2canvas',
      'js-md5',
      'awe-dnd'
    ]
  },
  output: {
    path: path.join(__dirname, '../static/js'),    //生成dll.js的目录
    filename: file_name,
    library: '[name]_library' // vendor.dll.js中暴露出的全局变量名
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.join(__dirname, '.', '[name]-manifest.json'),
      name: '[name]_library'
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ]
};

复制代码

webpack.base.conf.js

  
  plugins: [
    // new webpack.optimize.CommonsChunkPlugin('common.js'),  这行需要注释掉
    new webpack.DllReferencePlugin({
      manifest: require('./vendor-manifest.json')
    }),
  ],
复制代码

在template中的html文件中引入dll.js文件,此处为script定义了一个id,方便动态更改引入文件地址。

在package.json文件中加入命令

"build:dll": "webpack --config build/webpack.dll.config.js"
复制代码

执行npm run build:dll

执行结果:

在引入之前 vendor文件为5.45M

在引入dll文件之后wendor文件为4.77M

  1. jQuery的引入

在vue-cli的项目中引入jQuery修改webpack.base.conf.js文件,打包出来jQuery约200k

 plugins: [
    new webpack.ProvidePlugin({
      jQuery: "jquery",
      $: "jquery"
    }),
  ],
复制代码

通过这种方式引入jQuery会增大文件的打包大小,所以直接在html文件中引入jQuery,本文件大小约80k

 <script src="/static/js/jquery-3.3.1.min.js">script>
复制代码

  1. 路由懒加载

参考官方链接: 路由懒加载

五、参考资料

使用 webpack 定制前端开发环境

vue-cli之webpack3构建全面提速优化 webpack进阶——DllPlugin优化打包性能(基于vue-cli)

结合vue-cli来谈webpack打包优化

记一次vue+element+echarts项目的优化(如何轻松将项目性能提升70%)

使用 HappyPack 和 DllPlugin 来提升你的 Webpack 构建速度

转载于:https://juejin.im/post/5c629075f265da2d90581933

你可能感兴趣的:(vue-cli项目优化笔记)