最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • vue cli项目构建打包优化初探

    正文概述 掘金(小子王)   2021-05-02   701

    背景

    因为公司的前端项目在打包构建方面时间属实长得离谱,冷启动大约5min,本地构建打包也大约5min,到线上腾讯云docker构建打包全过程需要16~20min。因此不仅极大影响开发效率,也大大延迟了给测试交付的时间。

    优化思路

    • 了解项目当前webpack配置
    • 构建相关优化
    • 打包体积相关优化
    • docker相关优化

    量化工具

    speed-measure-webpack-plugin

    介绍:

    speed-measure-webpack-plugin npm

    通过smp输出的分析可以清楚的了解到webpack构建过程中,每一阶段的loader以及plugin的工作花费的时间。

    使用方式:

    # Yarn
    yarn add -D speed-measure-webpack-plugin
    
    const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
    module.exports = {
      chainWebpack: config => {
        config
          .plugin('speed-measure-webpack-plugin')
          .use(SpeedMeasurePlugin)
          .end()
      }
    }
    

    在本项目中使用其他的使用都会报error,但是以上的用法似乎不会区分plugin与loader的使用,甚至没有其他plugin的使用情况信息,迷惑~。

    webpack-bundle-analyzer

    介绍:

    webpack-bundle-analyzer npm 用来分析webapck构建打包后的文件,如分包情况,占用体积等参数的分析。

    使用方式:

    # Yarn
    yarn add -D webpack-bundle-analyzer
    
    const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
    module.exports = {
      plugins: [
        new BundleAnalyzerPlugin()
      ]
    }
    

    但是在vue-cli中有report命令可以直接调用,然后去dist打包目录打开report.html。

    vue-cli-service build --report
    or
    vue-cli-service build --report-json
    

    查看vue-cli当前webpack配置

    介绍

    vue-cli脚手架会有webpack的很多默认行为,因此我们得知道基于vue-cli的项目,当前的webpack都配置了啥,然后才能做针对性的分析与优化。

    使用方式:

    #根据mode,分别生成开发环境、生产环境的配置
    vue inspect --mode production > output.js
    #输入命令后,在根目录会生产一个output.js文件
    

    如果vue command not found的错可以全局安装注册一下vue命令npm install -g vue-cli

    构建相关优化

    hard-source-webpack-plugin

    介绍

    hard-source-webpack-plugin npm

    在启动项目时会针对项目生成缓存,若是项目无package或其他变化,下次就不用花费时间重新构建,直接复用缓存。

    使用方式:

    #yarn
    yarn add -D hard-source-webpack-plugin
    
    const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
    module.exports = {
    	configureWebpack: config => {
      	config.plugin.push(
        	// 为模块提供中间缓存,缓存路径是:node_modules/.cache/hard-source
          // solve Configuration changes are not being detected
          new HardSourceWebpackPlugin({
            root: process.cwd(),
            directories: [],
            environmentHash: {
              root: process.cwd(),
              directories: [],
              files: ['package.json', 'yarn.lock', 'vue.config.js']
            }
          })
          // 配置了files的主要原因是解决配置更新,cache不生效了的问题,配置后有包的变化,plugin会重新构建一部分cache
        )
      }
    }
    

    注意:

    Could not freeze : Cannot read property 'hash' of undefined 删除node_modules/.cache后,重新启动项目,产生这个问题的原因可能是异步加载模块时编译产生的错误,可参考:

    缩小文件检索解析范围

    为避免无用的检索与递归遍历,可以使用alias指定引用时候的模块,noParse,对不依赖本地代码的第三方依赖不进行解析。

    // 定义getAliasPath方法,把相对路径转换成绝对路径
    const getAliasPath = dir => join(__dirname, dir)
    module.exports = {
    	configureWebpack: config => {
        config.module.noParse = /^(vu|vue-router|vuex|vuex-router-sync|lodash|echarts|axios|element-ui)$/
      }
      chainWebpack: config => {
        // 添加别名
        config.resolve.alias
          .set('@', getAliasPath('src'))
          .set('assets', getAliasPath('src/assets'))
          .set('utils', getAliasPath('src/utils'))
          .set('views', getAliasPath('src/views'))
          .set('components', getAliasPath('src/components'))
    	}
      // 生产环境禁用eslint
      lintOnSave: !process.env.NODE_ENV !== 'production',
    }
    

    减少打包体积

    image-webpack-plugin 图片压缩

    对图片像素要求没很极致的,这个压缩还是可以使用的,压缩率肉眼看起来感觉是没太大区别。 这里注意一下,我没有对svg进行压缩,原因是压缩的svg,再通过构建时被打包成base64时,生成的base64会有问题,无法访问。

    module.exports = {
      chainWebpack: config => {
       // 对图片进行压缩
        config.module
          .rule('images')
          .test(/\.(png|jpe?g|gif)(\?.*)?$/)
          .use('image-webpack-loader')
          .loader('image-webpack-loader')
          .options({ bypassOnDebug: true })
          .end()
    	}
    }
    

    UglifyJsPlugin删除console 注释

    uglifyJsPlugin 用来对js文件进行压缩,减小js文件的大小。其会拖慢webpack的编译速度,建议开发环境时关闭,生产环境再将其打开。 更建议规范团队成员的代码上去解决。

    #yarn
    yarn add -D uglifyjs-webpack-plugin
    
    const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
    
    module.exports = {
    	configureWebpack: config => {
      	config.plugin.push(
        	new UglifyJsPlugin({
            uglifyOptions: {
              // 删除注释
              output: {
                comments: false
              },
              // 删除console debugger 删除警告
              compress: {
                warnings: false,
                drop_console: true, //console
                drop_debugger: false,
                pure_funcs: ['console.log'] //移除console
              }
            },
            sourceMap: false,
            parallel: true //使用多进程并行运行来提高构建速度。默认并发运行数:os.cpus().length - 1。
          })
        )
      }
    }
    

    DLL动态链接库

    这个插件是在一个额外的独立的 webpack 设置中创建一个只有 dll 的 bundle(dll-only-bundle)。 这个插件会生成一个名为 manifest.json 的文件,这个文件是用来让 DLLReferencePlugin 映射到相关的依赖上去的。

    配置DllPlugin,可以分为下面几个步骤:

    1. 新建webpack.dll.config.js文件(其他命名都可以),配置需要拆分的插件;
    2. 在package.json文件中新建一条命令来专门打包,"build:dll":"webpack --config webpack.dll.config.js"; 运行该命令;
    3. 在vue.config.js 文件中配置DllReferencePlugin,主要把dll引用到需要预编译的依赖;
    4. 在index.html手动引入拆分的bundle包(放到cdn的话会更好)

    安装:

    #yarn 
    yarn add webpack-cli@^3.2.3 add-asset-html-webpack-plugin@^3.1.3 clean-webpack-plugin@^1.0.1 --dev
    
    // webpack.dll.config.js
    /* eslint-disable @typescript-eslint/no-var-requires */
    const path = require('path')
    const webpack = require('webpack')
    const CleanWebpackPlugin = require('clean-webpack-plugin')
    // dll文件存放的目录
    const dllPath = 'public/vendor'
    
    module.exports = {
      entry: {
        // 需要提取的库文件
        vendor: ['vue', 'vue-router', 'vuex'],
        utils: ['axios', 'lodash']
      },
      output: {
        path: path.join(__dirname, dllPath),
        filename: '[name].dll.js',
        // vendor.dll.js中暴露出的全局变量名
        // 保持与 webpack.DllPlugin 中名称一致
        library: '[name]_[hash]'
      },
      plugins: [
        // 清除之前的dll文件
        new CleanWebpackPlugin(['*.*'], {
          root: path.join(__dirname, dllPath)
        }),
        // manifest.json 描述动态链接库包含了哪些内容
        new webpack.DllPlugin({
          path: path.join(__dirname, dllPath, '[name]-manifest.json'),
          // 保持与 output.library 中名称一致
          name: '[name]_[hash]',
          context: process.cwd()
        })
      ]
    12
    
    

    vue.config.js plugin中使用

    config.plugin.push(
      new DllReferencePlugin({
        context: process.cwd(),
        manifest: require('./public/vendor/vendor-manifest.json')
      }),
        new DllReferencePlugin({
        context: process.cwd(),
        manifest: require('./public/vendor/utils-manifest.json')
      }),
        // 将 dll 注入到 生成的 html 模板中
        new AddAssetHtmlPlugin({
        // dll文件位置
        filepath: getPath('./public/vendor/*.js'),
        // dll 引用路径
        publicPath: './vendor',
        // dll最终输出的目录
        outputPath: './vendor'
      })
    )
    

    splitChunks 分割代码

    split-chunks-plugin webpack

    • chunks: 表示哪些代码需要优化,有三个可选值:initial(初始块)、async(按需加载块)、all(全部块),默认为async
    • minSize: 表示在压缩前的最小模块大小,默认为30000
    • minChunks: 表示被引用次数,默认为1
    • maxAsyncRequests: 按需加载时候最大的并行请求数,默认为5
    • maxInitialRequests: 一个入口最大的并行请求数,默认为3
    • automaticNameDelimiter: 命名连接符
    • name: 拆分出来块的名字,默认由块名和hash值自动生成
    • cacheGroups: 缓存组。缓存组的属性除上面所有属性外,还有test, priority, reuseExistingChunk
      • test: 用于控制哪些模块被这个缓存组匹配到
      • priority: 缓存组打包的先后优先级
      • reuseExistingChunk: 如果当前代码块包含的模块已经有了,就不在产生一个新的代码块
    config.optimization = {
      runtimeChunk: 'single',
      splitChunks: {
        chunks: 'all', // 表示哪些代码需要优化,有三个可选值:initial(初始块)、async(按需加载块)、all(全部块),默认为async
        maxInitialRequests: Infinity, // 按需加载时候最大的并行请求数,默认为5
        minSize: 30000, // 依赖包超过300000bit将被单独打包
        // 缓存组
        // priority: 缓存组打包的先后优先级
        // minChunks: 表示被引用次数,默认为1
        cacheGroups: {
          //公共模块
          commons: {
            name: 'chunk-commons',
            test: resolve('src'), // can customize your rules
            minSize: 100, //大小超过100个字节
            minChunks: 3, //  minimum common number
            priority: 5,
            reuseExistingChunk: true
          },
          // 第三方库
          libs: {
            name: 'chunk-libs',
            test: /[\\/]node_modules[\\/]/,
            priority: 10,
            chunks: 'initial', // only package third parties that are initially dependent
            reuseExistingChunk: true,
            enforce: true
          },
          echarts: {
            name: 'chunk-echarts',
            test: /[\\/]node_modules[\\/]echarts[\\/]/,
            chunks: 'all',
            priority: 12,
            reuseExistingChunk: true,
            enforce: true
          }
        }
      }
    }
    

    总结

    以上是我在公司项目做的一些小优化,对其他项目不一定适用,甚至使用上也不是最优,但目前对本项目很大程度上还是有帮助的。更多webpack优化的思路,我附上个思维导图吧。(仅供学习,记录?) vue cli项目构建打包优化初探

    其他

    Vue CLI

    vue-cli中的configureWebpack设置

    如何使用 docker 部署前端项目


    起源地下载网 » vue cli项目构建打包优化初探

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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