【webpack4系列】设计可维护的webpack4.x+vue构建配置(终极篇)

文章目录

构建配置包设计

构建配置管理的可选方案:

  • 通过多个配置文件管理不同环境的构建,webpack --config 参数进行控制
  • 将构建配置设计成一个库,比如:xxx-webpack
  • 抽成一个工具进行管理,比如:create-vue-app
  • 将所有的配置放在一个文件,通过 --env 参数控制分支选择

通过多个配置文件管理不同环境的 webpack 配置

  • 动态配置项:config.js
  • 通用功能:utils.js
  • 基础配置:webpack.base.js
  • 开发环境:webpack.dev.js
  • 生产环境:webpack.prod.js
  • 预编译配置:webpack.dll.js

抽离成一个 npm 包统一管理(省略)

  • 规范:Git commit日志、README、ESLint 规范、Semver 规范
  • 质量:冒烟测试、单元测试、测试覆盖率和 CI

什么是semver 规范?

概念:语义化的版本控制(Semantic Versioning),简称语义化版本,英文缩写为 SemVer

优势:

  • 避免出现循环依赖
  • 依赖冲突减少

语义化版本(Semantic Versioning)规范格式

  • 主版本号: 做了不兼容的 API 修改(进行不向下兼容的修改)
  • 次版本号: 做了向下兼容的功能性增加(API 保持向下兼容的新增及修改)
  • 修订号: 做了向下兼容的问题修正(修复问题但不影响 API)

通过 webpack-merge 组合配置

const merge = require("webpack-merge")
// 省略其他代码
module.exports = merge(baseConfig, devConfig);

功能模块设计

  • 基础配置:webpack.base.js
    • 资源解析
      • 解析ES6
      • 解析vue
      • 解析css
      • 解析less
      • 解析scss
      • 解析图片
      • 解析字体
      • 解析媒体
    • 样式增强
      • CSS前缀补齐
      • CSS px转成rem等
    • 目录清理
    • 忽略打包内容
    • 命令行信息显示优化
    • 错误捕获和处理
    • CSS提取成一个单独的文件
  • 开发配置:webpack.dev.js
    • 代码热更新
      • css热更新
      • js热更新
    • devServer配置
    • sourcemap
    • 样式压缩(可略)
    • 资源拷贝(可略)
  • 生产配置:webpack.prod.js
    • 代码压缩
    • 文件指纹
    • Tree Shaking(webpack4自带)
    • Scope Hositing(webpack4自带)
    • 速度优化(基础包CDN等)
    • 体积优化(代码分割)
    • 资源拷贝(可略)
    • 构建报告(可略)
    • 构建速度(可略)
  • 预编译配置:webpack.dll.js
    • 基础库:vue、element-ui等
    • 其它库:axios、vue-router等
  • 通用功能:utils.js
    • CSS加载器
    • 资源路径
    • 环境变量
    • eslint检测配置
  • 动态配置项:config.js
    • dev: 开发动态配置项
    • build:生产动态配置项

目录结构设计

  • app-build 放置配置文件
  • app-dll 放预编译后的文件
  • src(或者lib)放置源代码
  • test 放置测试代码(可省略)

结构如下:

+ |- /app-build
    + |- config.js
    + |- utils.js
    + |- webpack.dev.js
    + |- webpack.prod.js
    + |- webpack.base.js
    + |- webpack.dll.js
+ |- /app-dll
    + |- dll.library.min.js
    + |- dll.vendors.min.js
    + |- manifest.library.json
    + |- manifest.vendors.json
+ |- /test
+ |- /src
+ |- .env.development
+ |- .env.production
+ |- .eslintignore
+ |- .eslinrc.js
+ |- .prettierrc
+ |- package.json
+ |- README.md

构建配置插件

安装webpack、webpack-cli

npm i webpack@4 webpack-cli@4.10.0 -D

关联HTML插件html-webpack-plugin

webpack4.x对应的html-webpack-plugin@4

npm install html-webpack-plugin@4 -D 

webpack示例配置:

const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
  ]
}

解析ES6

webpack4.x安装@babel/core,@babel/preset-env,babel-loader@8

npm i babel-loader@8 @babel/core @babel/preset-env core-js@3 -D

在根路径下新建一个.babelrc文件,增加ES6的babel preset配置,代码如下:

{
  "preset": ["@babel/preset-env"]
}

webpack示例配置:

module: {
    rules: [
      {
        test: /\.js$/,
        use: 'babel-loader'
      } 
    ]
}

解析vue、JSX

安装插件:

npm i @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props vue-loader@15 vue-style-loader@3 vue-template-compiler -D
npm i vue@2 -S

在.babelrc文件中添加JSX相关配置:

{
  "presets": [["@babel/preset-env"], "@vue/babel-preset-jsx"]
}

解析CSS、Less和Sass

解析CSS

解析css,需要安装style-loader和css-loader。

其中webpack4.x安装style-loader1.x、css-loader4.x:

npm i css-loader@4 style-loader@1 -D

rules配置:

{
    test: /.css$/,
    use: ['style-loader', 'css-loader']
}
解析Less

解析less,需要安装less、less-loader。

其中webpack4.x建议安装less-loader@6(less-loader@7.0.1也支持webpack4.x)

npm i less less-loader@6 -D

版本参考:https://github.com/webpack-contrib/less-loader/blob/v6.2.0/package.json

rules配置如下:

{
    test: /.less$/,
    use: ['style-loader', 'css-loader', 'less-loader']
}
解析sass

安装sass、sass-loader、sass-resources-loader(剔除掉node-sass,深度依赖node版本):

npm i sass@1.32.13 sass-loader@7.3.1 sass-resources-loader@2.2.4 -D

注意:node-sass可以解析/deep/、::v-deep,sass只能解析::v-deep,如果剔除掉node-sass,需要把相关语法升级。像/deep/、::v-deep、:deep()这些是Vue.js框架中用于穿透样式作用域的特定选择器。

以下是对/deep/::v-deep:deep() 的对比说明:

选择器 说明 应用示例
/deep/ 是一个用于穿透组件样式作用域的旧版选择器。在某些Vue版本中被移除,不建议使用。 在Vue 2.x中,用于穿透样式作用域,如:.parent /deep/ .child { ... }
::v-deep 是Vue中的一个内置伪选择器,用于访问子组件的样式。它只适用于scoped样式中,并将样式深入到子组件作用域中。 在Vue组件的<style scoped>标签中使用,如:.parent ::v-deep .child { ... }
:deep() 是/deep/的替代品,也是一个伪类选择器。适用于全局样式和嵌套组件中的样式,用于穿透样式作用域。 可用于Vue组件的<style>标签中,无论是否带有scoped属性,如:.parent :deep(.child) { ... }
提取CSS

如果需要单独把 CSS 文件分离出来,我们需要使用 mini-css-extract-plugin 插件。

注:v4 版本之后才开始使用 mini-css-extract-plugin,之前的版本是使用 extract-text-webpack-plugin。

安装mini-css-extract-plugin插件:

npm i mini-css-extract-plugin -D

解析图片和字体

资源解析:解析图片

解析图片,可以安装file-loader,其中file-loader最新版本为6.2.0,支持webpack4.x。

npm i file-loader -D

版本参考:https://github.com/webpack-contrib/file-loader/blob/v6.2.0/package.json

rules配置如下:

{
    test: /.(png|jpe?g|gif)$/,
    use: 'file-loader'
}
资源解析:解析字体

rules配置如下:

{
    test: /.(woff|woff2|eot|otf|ttf)$/,
    use: 'file-loader'
},

css参考样式:

@font-face {
  font-family: 'SourceHeavy';
  src: url('./images/SourceHeavy.otf') format('truetype');
}

.search-text {
  font-size: 20px;
  color: #f00;
  font-family: 'SourceHeavy';
}
资源解析:使用url-loader

url-loader 也可以处理图⽚和字体,可以设置较⼩资源⾃动 base64,其中url-loader内部实现也是使用的file-loader。

目前url-loader最新版本为4.1.1,支持webpack4.x.

npm i url-loader -D

版本参考:https://github.com/webpack-contrib/url-loader/blob/master/package.json

rules配置(把之前关于图片的file-loader配置替换):

 {
    test: /.(png|jpe?g|gif)$/,
    use: [{ loader: 'url-loader', options: { limit: 10240 } }],
 }

热更新:webpack-dev-server

  • webpack-dev-server不刷新浏览器
  • webpack-dev-server不输出⽂件,⽽是放在内存中
  • 使⽤ HotModuleReplacementPlugin插件
npm i webpack-dev-server@3 -D

package.json示例配置:

"scripts": {
    "dev": "webpack-dev-server --open"
}

其中open是构建完成之后,自动开启浏览器。

文件指纹策略:chunkhash、contenthash和hash

注:文件指纹只能用于生产环境。

文件指纹如何生成
  • Hash:和整个项⽬的构建相关,只要项⽬⽂件有修改,整个项⽬构建的hash值就会更改
  • Chunkhash:和webpack 打包的chunk 有关,不同的entry 会⽣成不同的chunkhash值
  • Contenthash:根据⽂件内容来定义hash ,⽂件内容不变,则contenthash不变
文件指纹设置
  • JS文件:设置output的filename,使⽤[chunkhash]。
output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name]_[chunkhash:8].js'
  }
  • CSS文件:设置MiniCssExtractPlugin的filename,使⽤[contenthash]
new MiniCssExtractPlugin({
  filename: "[name]_[contenthash:8].css"
}),

HTML 、CSS和JavaScript代码压缩

JS压缩

webpack4及以后使用内置optimization,配合自定义压缩插件terser-webpack-plugin使用

npm i terser-webpack-plugin@4 -D

配置示例:

optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        // 过滤掉以".min.js"结尾的文件.
        exclude: /\.min\.js$/i,
        // Enable multi-process parallel running and set number of concurrent runs.
        parallel: true,
        // Enable file caching. Default path to cache directory: node_modules/.cache/terser-webpack-plugin.
        cache: true,
        terserOptions: {
          // 开启变量名混淆
          mangle: true,
          compress: {
            unused: true,
            // 移除所有debugger
            drop_debugger: true,
            // 移除所有console
            drop_console: true,
            pure_funcs: [
              // 移除指定的指令,如console, alert等
              "console.log",
              "console.error",
              "console.dir"
            ]
          },
          format: {
            // 删除注释
            comments: true
          }
        },
        // 是否将注释剥离到单独的文件中
        extractComments: false
      })
    ]
  }
CSS压缩

需要安装optimize-css-assets-webpack-plugin,同时使⽤cssnano

说明:optimize-css-assets-webpack-plugin插件目前官网最新版本5.0.8,使用的webpack为^4.44.1。

npm i optimize-css-assets-webpack-plugin@5 cssnano@4 -D

插件配置地址:https://github.com/NMFR/optimize-css-assets-webpack-plugin/blob/master/package.json

const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')

module.exports = {
  // 其他省略
  mode: 'production',
  plugins: [
    new OptimizeCssAssetsPlugin({
      assetNameRegExp: /\.css$/g,
      cssProcessor: require('cssnano'),
    }),
  ],
}

另外官网推荐了另外一个CSS样式插件:css-minimizer-webpack-plugin。如果在开发环境提取的CSS需要压缩,建议使用css-minimizer-webpack-plugin插件,测试压缩速度比optimize-css-assets-webpack-plugin快。

安装:

npm i css-minimizer-webpack-plugin@1.3.0 -D

示例配置:

const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

module.exports = {
    optimization: {
        minimize: true,
        minimizer: [
          new CssMinimizerPlugin({
            test: /\.css$/i
          })
        ]
      }
}
HTML压缩

安装html-webpack-plugin,并设置压缩参数。

其中webpack4.x对应的html-webpack-plugin@4。

npm i html-webpack-plugin@4 -D

webpack示例配置:

const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, 'src/index.html'),
      filename: 'index.html',
      chunks: ['index'],
      inject: true,
      minify: {
        html5: true,
        collapseWhitespace: true,
        preserveLineBreaks: false,
        minifyCSS: true,
        minifyJS: true,
        removeComments: false,
      },
    }),

    new HtmlWebpackPlugin({
      template: path.join(__dirname, 'src/search.html'),
      filename: 'search.html',
      chunks: ['search'],
      inject: true,
      minify: {
        html5: true,
        collapseWhitespace: true,
        preserveLineBreaks: false,
        minifyCSS: true,
        minifyJS: true,
        removeComments: false,
      },
    })
  ]
}

自动清理构建目录产物

webpack4.x使用clean-webpack-plugin@3版本:

npm i clean-webpack-plugin@3 -D

webpack配置:

const { CleanWebpackPlugin }  = require('clean-webpack-plugin')

plugins: [
    new CleanWebpackPlugin(),
 ]

PostCSS插件autoprefixer自动补齐CSS3前缀

需要安装postcss-loader、postcss、autoprefixer插件。

其中webpack4.x需要安装postcss-loader@4。

npm i postcss-loader@4 postcss@8 autoprefixer -D

示例配置如下:

module.exports = {
  module: {
    rules: [
      {
        test: /.css$/,
        use: [
          'css-loader',
          'less-loader',
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  [
                    'autoprefixer',
                    {
                      overrideBrowserslist: ['last 2 version', '>1%', 'ios 7']
                    }
                  ]
                ]
              }
            }
          }
        ]
      }
    ]
  }
}

静态资源内联

资源内联的意义:

  • 代码层⾯:
    • ⻚⾯框架的初始化脚本
    • 上报相关打点
    • css 内联避免⻚⾯闪动
  • 请求层⾯:减少 HTTP ⽹络请求数
    • ⼩图⽚或者字体内联 (url-loader)

安装raw-loader@0.5.1版本

npm i raw-loader@0.5.1 -D
  • raw-loader 内联 html
<%= require('raw-loader!./meta.html') %>
  • raw-loader 内联 JS
<%= require('raw-loader!babel-loader!../../node_modules/lib-flexible/flexible.js') %>

示例,例如我们抽离meta通用的代码为一个meta.html,以及flexible.js插件都内联带html页面中。
meta.html示例代码:

<meta charset="UTF-8">
<meta name="viewport" content="viewport-fit=cover,width=device-width,initial-scale=1,user-scalable=no">
<meta name="format-detection" content="telephone=no">
<meta name="keywords" content="keywords content">
<meta name="name" itemprop="name" content="name content">
<meta name="apple-mobile-web-app-capable" content="no">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">

使用sourcemap

作⽤:通过source map定位到源代码

sourcemap参考文章:http://www.ruanyifeng.com/blog/2013/01/javascript_source_map.html

source map 关键字:

  • eval: 使⽤eval包裹模块代码
  • source map: 产⽣.map⽂件
  • cheap: 不包含列信息
  • inline: 将.map作为DataURI嵌⼊,不单独⽣成.map⽂件
  • module:包含loader的sourcemap

source map 类型:
在这里插入图片描述

一般开发环境配置:

module.exports = {
  // 其他代码省略
  devtool: "source-map"
};
<
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值