vue-cli 3.0+

简  介

vue-cli 3.0相对2.x进行了断裂式的升级,配置方式有了巨大的改变,同时性能也有了很大的提升。最新的4.x延续了3.x,没有断裂式升级,只是增加部分新特性和局部优化。

  • vue-cli 3.0+ 内置了webpack4,针对vue项目做了调整和优化,带有合理的默认配置最佳实践。
  • vue-cli 3.0+ 新增了插件系统,集成了前端生态中最好的工具,并可使用vue add ...命令轻松新增插件。
  • vue-cli 3.0+ 新增了可视化管理界面,可以可视化查看和修改配置,用vue ui命令启动。

目录结构中明显的改变就是去掉了2.x中的build/, config/构建配置的文件夹,改为在vue.config.js文件中修改配置。由于内置了webpack,对webpack配置更细颗粒的修改由webpack-chain的方式实现。

01

打包性能痛点

随着项目的复杂和功能的增加,依赖的第三方包越来越多,打包的性能问题逐渐变得无法忽视。总体来说,主要体现在两个方面:

  • 构建过程时间太长
  • 打包结果体积太大

针对这两个问题,就需要定制vue-cli的webpack配置,寻找打包优化策略。

针对时间太长的问题,可采用预编译策略;针对体积太大的问题,可采用分包拆包的策略。

现阶段较优的方案是通过webpack的splitChunks优化配置和DllPlugin插件配合相关插件来实现的。

  • splitChunks主要是通过拆包减小单个包的体积
  • DllPlugin是对依赖的第三方包通过预编译的方式提前构建,同时也支持分包构建

针对不同的需求和场景,大体的建议是:

如果打包速度尚可,只想拆包减小单个包的体积,只使用splitChunks即可;如果个别依赖库打包速度太慢,可以配合使用DllPlugin对其进行预编译;如果依赖库较多,同时还想将预编译的多个库也分包,那就无需使用splitChunks,全部交给DllPlugin处理。

02

splitChunks拆包

vue-cli 3.0+默认拆分配置会将node_modules中的依赖和src中的代码分开打成两个包:js/chunk-vendors[hash].js和js/app[hash].js。如果想颗粒度更细的拆包,就需要修改splitChunks配置了。

// vue.config.js const cacheGroups = require('./build/splitChunks') // 配置拆出单独文件方便管理 module.exports = {   /* 链式配置:语法参考文档   webpack-chain API: https://github.com/Yatoo2018/webpack-chain/tree/zh-cmn-Hans */   chainWebpack: config => {     if (process.env.NODE_ENV === 'production') {        // 拆包优化      config.optimization.splitChunks({        chunks: 'all', // async表示抽取异步模块,all表示对所有模块生效,initial表示对同步模块生效        ...cacheGroups      })    }  }}
// build/splitChunks.jsmodule.exports = {  cacheGroups: {    common: {      name: "chunk-common",      chunks: "initial",      minChunks: 2,      maxInitialRequests: 5,      minSize: 0,      priority: 1,      reuseExistingChunk: true,      enforce: true    },    vendors: {      name: "chunk-vendors",      test: /[\\/]node_modules[\\/]/,      chunks: "initial",      priority: 2,      reuseExistingChunk: true,      enforce: true    },    polyfill: {      name: "chunk-corejs",      test: /[\\/]node_modules[\\/]core-js[\\/]/,      chunks: "all",      priority: 3,      reuseExistingChunk: true,      enforce: true    }  }}

cacheGroups(缓存组)是 Webpack splitChunks 最核心的配置,splitChunks的配置项都是作用于cacheGroup上的。其他参数说明如下:

  • chunks: 'async' 三选一:"initial" | "all" | "async" (默认)
  • minSize: 30000 最小尺寸,30K
  • maxSize: 0 文件的最大尺寸,0为不限制
  • minChunks: 1 默认1,被提取的一个模块至少需要在几个 chunk 中被引用,值越大抽取出来的文件就越小
  • maxInitialRequests: 3 针对一个 entry 做初始化模块分隔的时候的最大文件数
  • priority: 0 优先级,数字越大优先级越高
  • reuseExistingChunk: true 是否使用已有的 chunk:如果该chunk包含的modules已经在另一个被分割的chunk中存在,那么直接引用已存在的chunk,不会再重新产生一个
  • enforce: true 提升本组配置项的优先级,不会被splitChunks全局配置覆盖

需要拆分的包,在cacheGroups对象中依次添加即可。

修改配置后,要查看打包的效果,可以使用webpack-bundle-analyzer可视化工具插件,配置后,打包完成时会自动打开浏览器显示打包报告,可以可视化地查看打包情况。

vue 2 打包ios vue3.0打包_html

// vue.config.jsconst BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPluginmodule.exports = {  chainWebpack: config => {    if (process.env.NODE_ENV === 'production') {      // 配置webpack-bundle-analyzer打包分析插件      config.plugin('webpack-report').use(BundleAnalyzerPlugin, [        {          analyzerMode: 'static'        }      ])    }  }}

03

DllPlugin预编译

DllPlugin 是基于 Windows 动态链接库(dll)的思想被创作出来的,是webpack的内置插件。可以实现将第三方库提前编译打包到一个(不分包)或多个(分包)文件,打包一次后不需再随业务代码一起被重新打包(只有当依赖自身发生版本变化时才需要重新打包)。这种提前将第三方依赖库预编译抽离出来的办法,可以大幅提升打包速度。

DllPlugin需要配合另外两个插件一起使用,组成一个三件套,分三步走:

  • 配置 dll 专属的配置文件,打包 dll 库,会打包出js和manifest.json描述文件
  • 使用DllReferencePlugin插件,配置manifest.json描述文件,告诉webpack关联关系
  • 使用add-asset-html-webpack-plugin插件将dll文件自动注入到打包后的index.html中

配置 dll 专属的配置文件,打包 dll 库

// build/webpack.dll.config.jsconst webpack = require('webpack')const path = require('path')const { CleanWebpackPlugin } = require('clean-webpack-plugin')const dllEntry = require('./dllEntry')module.exports = {  mode: 'production',  entry: {    ...dllEntry // 多个入口拆出为单独文件,方便管理和复用  },  output: {    path: path.join(__dirname, '../dll'),    filename: '[name]_[hash:6].dll.js',    library: '[name]_[hash]'  },  plugins: [    new CleanWebpackPlugin(), // 每次打包时先清除已有文件    new webpack.DllPlugin({      context: path.resolve(__dirname, '../'),      name: '[name]_[hash]',      path: path.join(__dirname, '../dll', '[name].manifest.json')    })  ]}
// build/dllEntry.js/* 要拆分预编译的包 */module.exports = {  vue: [    'vue/dist/vue.esm.js', // 可以指定vue为带 Compiler模式,默认为 runtime-only 模式    'vue-router',    'vuex',    'vue-i18n'  ],  polyfill: ['core-js'],  element: ['element-ui'],}

dll专属配置文件配好后,在项目正式打包部署前需要先打包dll。可以配置一个npm script命令:

// package.json"scripts": {    "dll": "webpack --progress --config ./build/webpack.dll.config.js",    "build": "vue-cli-service build"}

记得安装相关依赖:

npm i -D webpack webpack-cli clean-webpack-plugin add-asset-html-webpack-plugin

运行npm run build之前,先运行npm run dll。这样就会生成抽离出来的对应库的js文件和manifest.json描述文件。

第一步完成。

使用DllReferencePlugin插件

第二步,在vue.config.js中配置DllReferencePlugin。

// vue.config.jsconst getDllManifest = require('./build/dllReference') // 关联插件拆分出单独文件便于管理module.exports = {  configureWebpack: config => {    let plugins = []    if (process.env.NODE_ENV === 'production') { // 为生产环境修改配置...      // webpack.DllReferencePlugin      plugins = [...getDllManifest()]      config.plugins = [...config.plugins, ...plugins]    }  }}
// build/dllReference.jsconst path = require('path')const webpack = require('webpack')const dllEntry = require('./dllEntry') // 复用第一步中build/dllEntry.js文件暴露出的dllEntry/** 获取 dll文件的 manifest * @param {*} config */function getDllManifest () {  const plugins = []  // 遍历dllEntry,有多个则添加多个manifest.json  Object.keys(dllEntry).forEach((name) => {    plugins.push(      new webpack.DllReferencePlugin({        context: path.resolve(__dirname, '../'), // context必须与DllPlugin中的context一致        manifest: path.resolve(__dirname, '../dll/[name].manifest.json').replace(/\[name\]/gi, name)      })    )  })  return plugins}module.exports = getDllManifest

第二步完成。

使用add-asset-html-webpack-plugin插件

最后一步,在vue.config.js中配置add-asset-html-webpack-plugin插件将dll文件自动注入到打包后的index.html中。

// vue.config.jsconst getDllManifest = require('./build/dllReference')module.exports = {  configureWebpack: config => {    let plugins = []    if (process.env.NODE_ENV === 'production') { // 为生产环境修改配置...      // webpack.DllReferencePlugin      plugins = [...getDllManifest()]            // 插入dll到html      plugins.push(new AddAssetHtmlPlugin({        // context: __dirname,        filepath: path.resolve(__dirname, './dll/*.dll.js'),        outputPath: '/dll',        publicPath: '/dll'      }))      config.plugins = [...config.plugins, ...plugins]    }  }}

至此,DllPlugin全部配置完成。

验收成果

都配置好了,我们来验收下成果。

除了splitChunks拆包小节使用的webpack-bundle-analyzer可视化工具插件外,这里推荐使用vue-cli 3.0+提供的可视化管理工具。在终端运行vue ui命令,会启动一个监听8000端口的GUI服务,并自动打开浏览器,显示可视化操作界面。

vue 2 打包ios vue3.0打包_webpack最新版本_02

导入我们的项目,点击左侧菜单任务,我们在package.json中配置的npm script命令会显示在任务列表中。

vue 2 打包ios vue3.0打包_html_03

  • 先选择dll,点击运行按钮,就可以看到我们打包的dll的情况。
  • 再选择build,点击运行按钮,可以查看打包的情况、资源和速度统计。
  • 最后我们检查下打包好的dist文件夹,看看js和dll文件夹,以及index.html中js和dll文件是否自动注入成功。

彩 蛋

由于vue-cli 3.0+内置了webpack,基于vue项目的最佳实践做了默认配置。对我们来说就成了一个黑盒子,不像vue-cli 2.x那样,可以直观的看到webpack的具体配置。

如果你不确定自己修改的webpack是否正确,是否生效,有两种方式可以检验。

  • 可以使用vue-cli 3.0+可视化管理工具提供的inspect任务,点击运行,即可看到修改后webpack配置的最终结果。
  • 可以使用终端命令vue inspect --mode production > webpack.ouput.js,运行后会生成一个js文件,在文件中可以自由搜索查找自己修改的配置。

vue 2 打包ios vue3.0打包_vue 2 打包ios_04

这两种方式生成的文件,就是之前vue-cli 2.x中webpack的具体配置。