likes
comments
collection
share

【前端工程化】webpack5+vue3+ts+代码规范构建企业级前端项目(三)

作者站长头像
站长
· 阅读数 32

目录

  1. 前言
  2. 构建耗时分析
  3. 开启持久化存储缓存
  4. 开启多线程loader
  5. 配置alias别名
  6. 缩小loader作用范围
  7. 精确使用loader
  8. 缩小模块搜索范围
  9. devtool模式配
  10. 其他优化配置
  11. 总结

1. 前言

20201010日,webpack 升级至 5 版本到现在已经快三年,webpack5版本优化了很多原有的功能比如tree-shakin优化,也新增了很多新特性,具体变动可以看这篇文章阔别两年,webpack 5 正式发布了!

本文是专栏【前端工程化】webpack5+vue3+ts+代码规范构建企业级前端项目系列第三篇,会详细讲解优化构建速度:构建耗时分析,持久化缓存,多线程loaderdevtoolloader作用范围等优化配置。

本系列文章将使用最新的webpack5一步一步从零搭建一个完整的vue3+ts开发和打包环境,配置完善构建速度构建结果的优化配置,以及配置完善的代码规范和git提交规范。完整代码已上传到webpack5-vue3-ts

全系列概览

【前端工程化】webpack5+vue3+ts+代码规范构建企业级前端项目(三)

全系列文章:

  1. 《基础功能配置:webpack5配置vue3+ts基础环境,实现dev开发和打包构建》
  2. 《进阶功能配置:环境变量,支持cssless,图片和媒体资源,css3前缀babel兼容》
  3. 《优化构建速度:构建耗时分析,持久化缓存,多线程loaderdevtoolloader作用范围》
  4. 优化化构建结果:构建结果分析,抽离css文件,压缩cssjs文件,hash合理配置,代码分割,tree-shaking清理cssjs,打包生成gzip
  5. 代码格式规范:editorconfig统一编辑器配置,prettier自动格式化代码,stylelint规范样式和保存自动修复,代码提交自动格式化cssjs代码等。
  6. 代码语法规范:eslint检测js代码语法,style-lint检测样式代码语法,使用tsc检测类型报错,lint-staged按需检测代码等。
  7. git提交规范:代码提交时husky检测代码语法规范,代码提交时husky检测commit备注规范,commitizen配置commit辅助信息等。

2. 构建耗时分析

当进行优化的时候,肯定要先知道时间都花费在哪些步骤上了,而speed-measure-webpack-plugin插件可以帮我们做到,安装依赖:

npm i speed-measure-webpack-plugin -D

使用的时候为了不影响到正常的开发/打包模式,我们选择新建一个配置文件,新增webpack构建分析配置文件build/webpack.analy.js

// build/webpack.analy.js
const prodConfig = require('./webpack.prod.js') // 引入打包配置
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin'); // 引入webpack打包速度分析插件
const smp = new SpeedMeasurePlugin(); // 实例化分析插件
const { merge } = require('webpack-merge') // 引入合并webpack配置方法

// 使用smp.wrap方法,把生产环境配置传进去,由于后面可能会加分析配置,所以先留出合并空位
module.exports = smp.wrap(merge(prodConfig, {

}))

修改package.json添加启动webpack打包分析脚本命令,在scripts新增:

{
  // ...
  "scripts": {
    // ...
    "build:analy": "cross-env NODE_ENV=production BASE_ENV=production webpack -c build/webpack.analy.js"
  }
  // ...
}

执行npm run build:analy命令

【前端工程化】webpack5+vue3+ts+代码规范构建企业级前端项目(三)

可以在图中看到各pluginloader的耗时时间,现在因为项目内容比较少,所以耗时都比较少,在真正的项目中可以通过这个来分析打包时间花费在什么地方,然后来针对性的优化。

speed-measure-webpack-plugin插件在webpack5+vue3中使用会报错,相关issues,但不影响看实际效果。

3. 开启持久化存储缓存

webpack5之前做缓存是使用babel-loader缓存解决js的解析结果,cache-loader缓存css等资源的解析结果,还有模块缓存插件hard-source-webpack-plugin,配置好缓存后第二次打包,通过对文件做哈希对比来验证文件前后是否一致,如果一致则采用上一次的缓存,可以极大地节省时间。

webpack5 较于 webpack4,新增了持久化缓存、改进缓存算法等优化,通过配置 webpack 持久化缓存,来缓存生成的 webpack 模块和 chunk,改善下一次打包的构建速度,可提速 90% 左右,配置也简单,修改build/webpack.base.js

// build/webpack.base.js
// ...
module.exports = {
  // ...
  cache: {
    type: 'filesystem', // 使用文件缓存
  },
}

当前文章代码的测试结果

模式第一次耗时第二次耗时
启动开发模式2869毫秒687毫秒
启动打包模式5455毫秒552毫秒

通过开启webpack5持久化存储缓存,再次打包的时间提升了90%

【前端工程化】webpack5+vue3+ts+代码规范构建企业级前端项目(三)

缓存的存储位置在node_modules/.cache/webpack,里面又区分了developmentproduction缓存:

【前端工程化】webpack5+vue3+ts+代码规范构建企业级前端项目(三)

4. 开启多线程loader

webpackloader默认在单线程执行,现代电脑一般都有多核cpu,可以借助多核cpu开启多线程loader解析,可以极大地提升loader解析的速度,thread-loader就是用来开启多进程解析loader的,安装依赖

npm i thread-loader -D

使用时,需将此 loader 放置在其他 loader 之前。放置在此 loader 之后的 loader 会在一个独立的 worker 池中运行。

修改build/webpack.base.js

// build/webpack.base.js
module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.vue/,
        use: ['thread-loader', 'vue-loader']
      },
      {
        test: /\.ts$/,
        use: ['thread-loader', 'babel-loader']
      }
    ]
  }
}

由于thread-loader不支持抽离css插件MiniCssExtractPlugin.loader(下面会讲),所以这里只配置了多进程解析js,开启多线程也是需要启动时间,大约500ms左右,所以适合规模比较大的项目。

5. 配置alias别名

webpack支持设置别名alias,设置别名可以让后续引用的地方减少路径的复杂度。

修改build/webpack.base.js

module.export = {
  // ...
   resolve: {
    // ...
    alias: {
      '@': path.join(__dirname, '../src')
    }
  }
}

修改tsconfig.json,添加baseUrlpaths

{
  "compilerOptions": {
    // ...
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "src/*"
      ]
    }
  }
}

配置修改完成后,在项目中使用 @/xxx.xx,就会指向项目中src/xxx.xx,js/ts文件和vue文件中都可以用。

src/App.vue可以修改为

<template>
  <img :src="smallImg" alt="小于10kb的图片" />
  <img :src="bigImg" alt="大于于10kb的图片" />
  <!-- 小图片背景容器 -->
  <div className='smallImg'></div>
  <!-- 大图片背景容器 -->
  <div className='bigImg'></div>
</template>

<script setup lang="ts">
  import smallImg from '@/assets/imgs/5kb.png'
  import bigImg from '@/assets/imgs/22kb.png'
  import '@/app.css'
  import '@/app.less'
</script>

<style scoped>
</style>

src/app.less可以修改为

// app.less
#root {
  .smallImg {
    width: 69px;
    height: 75px;
    background: url('@/assets/imgs/5kb.png') no-repeat;
  }
  .bigImg {
    width: 232px;
    height: 154px;
    background: url('@/assets/imgs/22kb.png') no-repeat;
  }
}

6. 缩小loader作用范围

一般第三库都是已经处理好的,不需要再次使用loader去解析,可以按照实际情况合理配置loader的作用范围,来减少不必要的loader解析,节省时间,通过使用 includeexclude 两个配置项,可以实现这个功能,常见的例如:

  • include:只解析该选项配置的模块
  • exclude:不解该选项配置的模块,优先级更高

修改build/webpack.base.js

// build/webpack.base.js
const path = require('path')
module.exports = {
  // ...
  module: {
    rules: [
      {
        include: [path.resolve(__dirname, '../src')], 只对项目src文件的vue进行loader解析
        test: /\.vue$/,
        use: ['thread-loader', 'vue-loader']
      },
      {
        include: [path.resolve(__dirname, '../src')], 只对项目src文件的ts进行loader解析
        test: /\.ts/,
        use: ['thread-loader', 'babel-loader']
      },
    ]
  }
}

其他loader也是相同的配置方式,如果除src文件外也还有需要解析的,就把对应的目录地址加上就可以了,比如需要引入antdcss,可以把antd的文件目录路径添加解析css规则到include里面。

7. 精确使用loader

loaderwebpack构建过程中使用的位置是在webpack构建模块依赖关系引入新文件时,会根据文件后缀来倒序遍历rules数组,如果文件后缀和test正则匹配到了,就会使用该rule中配置的loader依次对文件源代码进行处理,最终拿到处理后的sourceCode结果,可以通过避免使用无用的loader解析来提升构建速度,比如使用less-loader解析css文件。

可以拆分上面配置的lesscss, 避免让less-loader再去解析css文件

// build/webpack.base.js
// ...
module.exports = {
  module: {
    // ...
    rules: [
      // ...
      {
        test: /\.css$/, //匹配所有的 css 文件
        include: [path.resolve(__dirname, '../src')],
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/, //匹配所有的 less 文件
        include: [path.resolve(__dirname, '../src')],
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
    ]
  }
}

8. 缩小模块搜索范围

node里面模块有三种

  • node核心模块
  • node_modules模块
  • 自定义文件模块

使用requireimport引入模块时如果有准确的相对或者绝对路径,就会去按路径查询,如果引入的模块没有路径,会优先查询node核心模块,如果没有找到会去当前目录下node_modules中寻找,如果没有找到会查从父级文件夹查找node_modules,一直查到系统node全局模块。

这样会有两个问题,一个是当前项目没有安装某个依赖,但是上一级目录下node_modules或者全局模块有安装,就也会引入成功,但是部署到服务器时可能就会找不到造成报错,另一个问题就是一级一级查询比较消耗时间。可以告诉webpack搜索目录范围,来规避这两个问题。

修改build/webpack.base.js

// build/webpack.base.js
const path = require('path')
module.exports = {
  // ...
  resolve: {
     // ...
     // 如果用的是pnpm 就暂时不要配置这个,会有幽灵依赖的问题,访问不到很多模块。
     // 查找第三方模块只在本项目的node_modules中查找
     modules: [path.resolve(__dirname, '../node_modules')], 
  },
}

9. devtool配置

开发过程中或者打包后的代码都是webpack处理后的代码,如果进行调试肯定希望看到源代码,而不是编译后的代码, source map就是用来做源码映射的,不同的映射模式会明显影响到构建和重新构建的速度, devtool选项就是webpack提供的选择源码映射方式的配置。

devtool的命名规则为 ^(inline-|hidden-|eval-)?(nosources-)?(cheap-(module-)?)?source-map$

关键字描述
inline代码内通过 dataUrl 形式引入 SourceMap
hidden生成 SourceMap 文件,但不使用
evaleval(...) 形式执行代码,通过 dataUrl 形式引入 SourceMap
nosources不生成 SourceMap
cheap只需要定位到行信息,不需要列信息
module展示源代码中的错误位置

开发环境推荐:eval-cheap-module-source-map

  • 本地开发首次打包慢点没关系,因为 eval 缓存的原因, 热更新会很快
  • 开发中,我们每行代码不会写的太长,只需要定位到行就行,所以加上 cheap
  • 我们希望能够找到源代码的错误,而不是打包后的,所以需要加上 module

修改build/webpack.dev.js

// build/webpack.dev.js
module.exports = {
  // ...
  devtool: 'eval-cheap-module-source-map'
}

打包环境推荐:none(就是不配置devtool选项了,不是配置devtool: 'none')

// build/webpack.prod.js
module.exports = {
  // ...
  // devtool: '', // 不用配置devtool此项
}
  • none话调试只能看到编译后的代码,也不会泄露源代码,打包速度也会比较快。
  • 只是不方便线上排查问题, 但一般都可以根据报错信息在本地环境很快找出问题所在。
  • 如果想排查线上问题时可以映射源码,推荐用cheap-module-source-map,只展示行信息,单独存在map文件,可以在编译速度和排查问题上做一个很好的均衡。

10. 其他优化配置

除了上面的配置外,webpack还提供了其他的一些优化方式,本次搭建没有使用到,所以只简单罗列下:

  • externals: 外包拓展,打包时会忽略配置的依赖,会从上下文中寻找对应变量。
  • module.noParse: 匹配到设置的模块,将不进行依赖解析,适合jquery,boostrap这类不依赖外部模块的包
  • ignorePlugin: 可以使用正则忽略一部分文件,常在使用多语言的包时可以把非中文语言包过滤掉

总结

到这里一些项目优化构建速度就已经配置好了,下一篇会讲解优化构建结果的配置,通过一系列配置来优化项目构建结果,通过配置来减少体积大小,提升代码质量,提高整体的项目体验。

文章系列:

  1. 《基础功能配置:webpack5配置vue3+ts基础环境,实现dev开发和打包构建》
  2. 《进阶功能配置:环境变量,支持cssless,图片和媒体资源,css3前缀babel兼容》
  3. 《优化构建速度:构建耗时分析,持久化缓存,多线程loaderdevtoolloader作用范围》
  4. 优化化构建结果:构建结果分析,抽离css文件,压缩cssjs文件,hash合理配置,代码分割,tree-shaking清理cssjs,打包生成gzip
  5. 代码格式规范:editorconfig统一编辑器配置,prettier自动格式化代码,stylelint规范样式和保存自动修复,代码提交自动格式化cssjs代码等。
  6. 代码语法规范:eslint检测js代码语法,style-lint检测样式代码语法,使用tsc检测类型报错,lint-staged按需检测代码等。
  7. git提交规范:代码提交时husky检测代码语法规范,代码提交时husky检测commit备注规范,commitizen配置commit辅助信息等。

参考

  1. webpack官网
  2. babel官网
  3. 【万字】透过分析 webpack 面试题,构建 webpack5.x 知识体系
  4. Babel 那些事儿
  5. 阔别两年,webpack 5 正式发布了!