Webpack4从配置到优化

核心:

  • entry(打包入口)
  • output(打包后的文件处理)
  • loader(对各类资源的处理)
  • plugin(利用插件对webpack进行扩展和加强)
  • mode(针对开发环境和生产环境的区分处理)

其余常用:

  • devServer(热更新)
  • resolve(模块解析)
  • optimization(优化)
  • devtool(源码调试)

优化手段:

  • stats分析
  • 速度分析
  • 体积分析
  • tree-shaking
  • scope-hoisting
  • 多进程构建
  • 并行压缩
  • 预编译资源模块
  • 提高二次构建速度
  • css的tree-shaking
  • webpack图片压缩
  • 动态polufil
  1. entry打包入口
    定义打包的入口
module.exports = {
  entry: './src/index.js'
}

// 多入口
module.exports = {
  entry: {
    index: './src/index.js',
    list: './src/index.js'
  }
}
  1. output输出

编译后文件输出到磁盘的相关配置

module.exports = {
  output: {
    filename: '[name]_[chunkhash:8].js', // 单个文件可以直接,多入口利用占位符保证文件统一
    path: path.join(__dirname, '../dist'), // 写入文件磁盘路径
    publicPath: 'https://cdn.example.com/assets/' // 使用CDN,给全部文件引入模板文件时加上路径前缀
  }
}
  1. loader(资源解析转换)

webpack原生只支持js和json,利用loader,对不一样的文件类型支持,转换成有效的模块

// 1、解析es6和jsx
module.exports = {
  module: {
    rules: [
      {
        test: /\.(j|t)sx?$/,
        use: 'babel-loader',
        exclude: /node_modules/
      }
    ]
  }
}

// 2、解析css文件

// style-loader 将样式经过style标签插入模板文件的head中
// css-loader 用于加载css文件,转换成commonJs对象
{
  test: /.css$/,
  use: ['style-loader', 'css-loader']
}

// 3、解析less

// less-loader
{
  test: /.css$/,
  use: [
    'style-loader',
    'css-loader',
    {
      loader: 'less-loader',
      options: { // 可配置属性,修改变量的值,通常利用来修改UI库的主题样式,如下是antd主题样式配置
        modifyVars: {
          '@primary-color': '#ec7259',
        },
        javascriptEnabled: true, // 支持内联的js
      }
    }
  ]
}

// 4、图片和字体解析

/* file-loader:解析图片, 字体等
url-loader:也可处理图片和字体,并可设置较小资源自动base64,url-loader比file-loader功能强大 */

{
  test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
  use: [
    {
      loader: 'url-loader',
      options: {
        limit: 8192,
        name: 'static/img/[name].[hash:8].[ext]', // [ext]代表文件后缀名
      }
    }
  ]
},
{
  test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
  loader: 'url-loader',
  options: {
    limit: 8192,
    name: 'static/fonts/[name].[hash:8].[ext]'
  }
}

// 5、移动端适配

/* px2rem-loader: 把px转换成rem,配合lib-flexible使用 */

{
  loader: 'px2rem-loader',
  options: {
    remUnit: 75, // 1rem=多少像素
    remPrecision: 8, // rem的小数点后位数
  }
}

// 6、css前缀补齐

/* postcss-loader:用于浏览器适配,某些css3属性浏览器不支持须要加前缀,它会自动针对不一样浏览器加不一样的属性前缀 */

{
  loader: 'postcss-loader',
  options: {
    plugin: ()=> [autoprefixer()] // 安装autoprefixer
  }
}
  1. plugin(利用插件对webpack进行扩展和加强)
  • 解决loader没法完成的事
  • 由于插件能够携带参数/选项,因此要向 plugins属性传入new实例 简单示例
const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin") // 自动生成index.html
const { CleanWebpackPlugin } = require("clean-webpack-plugin") // 每次打包清空文件夹
const MiniCssExtractPlugin = require("mini-css-extract-plugin") // css分离
const TerserWebpackPlugin = require("terser-webpack-plugin") // 压缩js(在optimization中配置)
const OptimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin") // 压缩css

// 1、 页面打包

new HtmlWebpackPlugin({ // 产出html文件,编译时会读取模板文件
  filename: '../dist/index.html', // 指定生成的模板文件名及路径
  template: path.join(__dirname, '../index.html'), // 指定要使用的模板文件
  inject: true, // 指定的chunk会自动注入html文件中
  chunks: ['index'], // 为了避免缓存,可以在指定产出的资源后面添加hash值
  minify: { // 代码的最小输出
    collapseWhitespace: true, // 删除空格,但不会删除script、style和textarea中的空格
    preserveLineBreaks: false, // 是否保留换行符
    minifyCss: true, // css压缩
    minifyJs: true, // js压缩
    removeComments: true // 删除注释,可是会保留script和style中的注释 
  }
}),

// 2、文件清理

/* 
每次打包文件到dist,首先要清理dist内部文件,或直接删除dist文件夹,防止文件重复 咱们可利用rimraf dist
但此方式不太优雅,咱们可使用clean-webpack-plugin,清理dist内部文件 */

new CleanWebpackPlugin(),

// 3、css剥离

/* 
css代码默认打包在js文件中,但有时候css变了,js没变,或者相反,这是不利于缓存的,
咱们能够把css剥离出来单独生成文件,去作缓存处理 */

new MiniCssExtractPlugin({
  filename: '[name]_[contenthash:8].css', // 代码块名字
  chunkFilename: "[id].css" // 异步加载用
}),

// 4、css压缩

/* 既然css单独剥离出来,就要作压缩 */

new OptimizeCssAssetsPlugin({
  assetNameRegExp: /\.css$/g,
  // cssProcessor: require("cssnao") // cssnano 压缩和优化的css插件 
})

// 5、基础库分离

/* 
咱们常把一些不太变化的静态资源放在cdn上,而后在模版文件里引入
在webpack也提供了插件支持,可直接配置插入
假如咱们分离react和react-dom 
*/

const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
plugins: [
  new HtmlWebpackExternalsPlugin({
    externals: [
      {
        module: 'react',
        entry: 'https://cdn.cn/16.8.0/react.min.js',
        global: 'React',
      },
      {
        module: 'react-dom',
        entry: 'https://cdn.cn/16.8.0/react-dom.min.js',
        global: 'ReactDOM',
      }
    ]
  })
]
  1. mode(针对开发环境和生产环境的区分处理)

对应三个属性:

  • development 开发模式
  • production 生产模式
  • none 无

webpack会针对不一样环境直接作一些优化工做,例如production模式下会进行,tree-shaking和scope-hosting

  1. devServer(热更新)
devServer: {
  historyApiFallback: true, // 单页面程序 刷新浏览器会出现404,缘由是它经过这个路径(好比: /search/list)来访问后台,因此会出现404,而把historyApiFallback设置为true那么全部的路径都执行index.html
  host: '192.168.1.1', // 域名
  open: true, // 支持自动打开浏览器
  hot: true, // 模块热替换,在前端代码变更的时候无需整个刷新页面,只把变化的部分替换掉
  inline: false, // inline选项会为入口页面添加“热加载”功能,即代码改变后从新加载页面
  port: 8080, // 端口
  proxy: proxyConfig._proxy, // 代理后端服务
  before(app) { // 其余中间件以前, 提供执行自定义中间件
    apiMocker(app, path.resolve('./mocks/mock.js'), // 举例:可用来作mock数据
      proxyConfig._proxy);
  }
}
  1. resolve(模块解析)

设置模块如何被解析

常用属性:

  • alias 建立 import 或 require 的别名,来确保模块引入变得更简单
  • extensions 自动解析肯定的扩展
  • mainFileds 当从 npm 包中导入模块时,决定在 package.json 中使用哪一个字段导入模块
  • moudles 告诉 webpack 解析模块时应该搜索的目录
resolve: {
  alias: {
    '@': path.resolve('src'),
    '@nm': path.resolve('node_modules')
  },
  extensions: ['.js', '.jsx', '.json'],
  moudles: [path.resolve(__dirname, 'node_modules')]
}
  1. optimization(优化)

1、提取公共资源

  • 项目多页面的时候,大多数页面使用的基础库或依赖都是同样的,这时每一个页面都单独打包一份,对资源是一种浪费,打包后体积较大,页面加载时间长,
  • 因此咱们能够把公共资源提取出来单独打包,访问多页面时利用缓存机制,只加载一次,达到优化目的
  • splitChunks,代替以前的CommonsChunkPlugin,公共资源分离vendors

2、公共文件分离

  • 一些公共的工具函数类文件,咱们能够经过限制被调用的次数来决定是否把它分离出来
  • 利用splitChunks 公共文件分离commons

3、提取webpack的模块化信息清单

  • 模块信息清单在每次有模块变动(hash 变动)时都会变动, 因此把这部分代码单独打包出来, 配合后端缓存策略,
  • 避免某个模块的变化致使包含在模块化信息中的模块缓存失效
  • 具体使用runtimeChunk
optimization: {
    runtimeChunk: {
      name: 'manifest',
    },
    splitChunks: {
      minSize: 50000 // 分离的包的体积大小
      cacheGroups: {
        vendors: {
          test:  /(react|react-dom)/, //正则匹配要分离的文件
          name: 'vendors',
          chunks: 'all', // 肯定对何种引入方式的文件进行分离
          minChunks: 1, // 最小使用的次数
          priority: 10, // 多个缓存组时,须要有优先级排列,优先使用哪一个进行分离
        },
        commons: { // 分离公共文件
          name: 'commons',
          chunks: 'all',
          minChunks: 2,
          priority: 5,
        },
      },
    },
    minimizer: [ // 放优化的插件
      new TerserWebpackPlugin({ // 压缩js
        parallel: true, // 开启多进程压缩
        cache: true // 开启缓存(压缩过的不压缩)
      }),
      new OptimizeCssAssetsWebpackPlugin({ // 压缩css
        assetNameRegExp: /\.css$/g,
        // cssProcessor: require("cssnao")
      })
    ]
  },
  1. devtool(源码调试)
  • 控制是否生成,以及如何生成 source map
  • 咱们要进行一个配置以方便咱们在测试环境进行问题定位,源码调试的加强

关键字定义:

  • eval 模块都使用 eval() 包裹执行,而且都有 //@ sourceURL(指向的是原文件index.js,调试的时候,根据sourceUrl找到的index.js文件的)
  • source map 产生.map文件(这个map文件会和原始文件作一个映射,调试的时候,就是经过这个.map文件去定位原来的代码位置的 )
  • cheap 不包含列的信息,(假如代码运行出现了错误,控制台报出了,error,咱们点击定位到具体源码的时候,就只能定位到行,而不能定位到具体的列)
  • inline .map文件做为dataUrl嵌入到打包文件,而不单独生成
  • moudle 包含loader的sourcemap(调试的代码不会被转换,会保留原始代码语法)

几种关键字进行组合就造成了具体的用法,不一样用法对构建速度是有影响的,基本状况你越清晰容易的看到原始的代码,构建速度就越慢,调试的方便性和构建速度上你们能够本身权衡一下

// 开发环境
devtool: 'cheap-module-eval-source-map' // 原始源代码(仅限行)

// 生产环境,通常不进行设置

优化手段

  1. 优化分析 stats
// 构建完成后会生成json文件,显示构建的一些信息,时间,各模块的体积等
scripts: {
  'build: stats': 'webpack --config build/webpack.prod.config.js --json > stats.json',
}
  1. 速度分析

分析每一个插件和loader的耗时状况 使用举例

const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin')
const smp = new SpeedMeasureWebpackPlugin();
module.exports = smp.wrap(merge(webpackConfigBase, webpackConfigProd));

可以看到每一个插件和loader的耗时状况, 若是耗时较长,会以红字提示,咱们就能够具体分析那个地方为何时间长,能够用别的插件替换之类的去作构建速度优化

  1. 体积分析

以图形大小的形式,更加直观的看到各个模块插件所占用的体积

const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
plugins: [ 
  new BundleAnalyzerPlugin({ 
    analyzerPort: 8919 //打包构建后体积分析图展现的窗口
    }),
],
  1. tree-shaking
  • 字面意思是摇晃树,就是把树上坏掉的叶子摇下来,就是死码清除(即没有被用到的代码)
  • 某个模块或文件,的某个方法被用到了,整个模块都会被打包都bundle文件中去,tree-shaking会把没有用到的方法去除,在uglify阶段清除
  • 仅支持es6语法 webpack 4 中设置 production 默认开启了此项优化
  1. 多进程构建
  • webpack构建是一个涉及文件的读写的过程,若是项目很是复杂,构建时间就会加长
  • 而webpack运行在nodejs上是单线程模型,同一时间只能处理一个任务
  • 咱们是否可让webpack同时进行多任务处理呢 happypack和thread loader给咱们提供了方案
  • thread loader由官方提供
  • thread loader放在最上面,就会在最后执行,以前的loader会在一个单独的worker池中运行
  • 每一个 worker 都是一个单独的有 600ms 限制的 node.js 进程,从而实现了多进程的构建,下降构建时间 举例
rules: [
  {
    test: /.js$/,
    use: [
      {
        loader: 'thread-loader',
        options: {
          workers: 3, // 产生的 worker 的数量,默认是 cpu 的核心数
        }
      }
    ]
  },
]
  1. 构建异常,中断处理

构建过程当中,有时会出现构建异常报错的状况,咱们能够经过某些方法捕获,以及自定义一些逻辑

plugins: [
  // 主动捕获构建错误
  function () {
    this.hooks.done.tap('done', (stats) => {
      if (stats.compilation.errors
        && process.argv.indexOf('--watch' == -1)) {
        console.log('error', stats.compilation.errors);
        // 能够作一个构建系统的日志,在此处上报错误缘由
        process.exit(12); // 自定义错误code码
      }
    });
  },
],
  1. 并行压缩
  • webpack4 推荐使用 terser-webpack-plugin 开启 parallel
  • uglify-webpack-plugin也支持并行压缩,但不支持es6,不作具体介绍,有兴趣的同窗自行查询
optimization: {
  minimizer: [
      new TerserPluginWebpack({
          parallel: 4, // 开启 不主动指定的话,默认数值是当前电脑cpu数量的2倍减1
      })
  ],
}
  1. 分包,预编译资源模块

问题 以前的分包存在问题

  • externals 分包会打出太多的script标签
  • splitchunk 分包须要一个分析的时间

解决

  • 预编译资源模块
  • 将react,react-dom redux 等基础包和业务基础包打包成一个文件

方法

  • dll-plugin进行分包,
  • dllreferenceplugin 对mainfest.json(对分离包的描述)引用,将预编译的模块加载进来
  • 利用add-asset-html-webpack-plugin把生成文件插入模版
// package.json
"scripts": {
  "dll": "webpack --config build/webpack.dll.js" // 打包前只需执行一次,只要基础包不变则不须要执行
},
// webpack.dll.js
const path = require('path');
const webpack = require('webpack');
module.exports = {
  entry: { // 指定要分离的包
      library: [ // 基础包
          'react',
          'react-dom',
      ],
  },
  output: {
      filename: "[name]_[hash].dll.js",
      path: path.resolve(__dirname, './library'),
      library: "[name]_[hash]", //包名称 注意此名需和下面的DllPlugin,name名一致
  },
  plugins: [
      new webpack.DllPlugin({
          name: "[name]_[hash]",
          path: path.resolve(__dirname, './library/[name].json')
      })
  ]
}
// webpack.prod.js
plugins: [
...
// 将给定的 JS文件添加到 webpack 配置的文件中,并插入到模版文件中
new AddAssetHtmlPlugin({
    filepath: path.resolve(__dirname, '../build/library/*.dll.js'),
  }),
// 
new webpack.DllReferencePlugin({
    manifest: require('../build/library/library.json')
  }),
]
  1. 提高二次构建后的速度

缓存插件 hard-source-webpack-plugin

const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
  plugins: [
    ...
    new HardSourceWebpackPlugin() 
  ]
]}
  1. css的tree-shaking(Remove unused CSS)
  • 清除css无用代码
  • 早期PurifyCSSPlugin,它主要的做用是能够去除没有用到的CSS代码,相似JS的Tree Shaking,现已再也不维护
  • 如今使用purgecss-webpack-plugin,配合mini-css-extract-plugin使用
const PATHS = {
  src: path.join(__dirname, '../src')
}
plugin: [
  new PurgecssPlugin({
    paths: glob.sync(`${PATHS.src}/**/*`,  { nodir: true }), // 注意是绝对路径匹配
  }),
]
  1. webpack 图片压缩
  • 使图片压缩更加自动化
  • 基于node库的imagemin
/* 支持定制选项,
可引入第三方插件
支持多个图片格式 */

{
  test: /.(png|jpg|gif|jpeg)$/,
  use: [
    {
        loader: 'url-loader',
        options: {
            limit: 8192,
            name:'[name]_[hash:8].[ext]'
        }
      },
      {
        loader: 'image-webpack-loader',
        options: {
          mozjpeg: {
            progressive: true,
            quality: 65
          },
          optipng: {
            enabled: false,
          },
          pngquant: {
            quality: [0.65, 0.90],
            speed: 4
          },
          gifsicle: {
            interlaced: false,
          },
          webp: {
            quality: 75
          }
        }
      },
  ],
},
  1. 动态polyfill服务
    polyfill-service
  • 获取浏览器的useragent判断支持状况,
  • 动态的返回浏览器不支持的新特性
  • 官方提供了cdnhttps://polyfill.io/v3/polyfill.min.js
  • 也能够基于官方自建polyfill服务,更加自由的配置属性(好比,指定只判断promise的支持程度) 例如 https://polyfill.alicdn.com/polyfill.min.js?features=Promise
  1. 基础配置
    解析js
    解析css
    解析less
    解析图片
    解析字体
    前缀补齐
    移动端适配
    目录清理
    页面打包
    css抽离
    异常主动捕获

  2. 提升构建速度
    resolve缩小文件的搜索范围
    使用DllPlugin减小基础模块编译次数
    thread loader 多进程构建
    terser并行压缩
    hard-source-webpack-plugin提高二次构建速度
    dll分包,预编译资源模块

  3. 减少构建体积
    公共资源分离
    Tree Shaking
    scope-hoisting
    js,css,字体,图片压缩
    动态polyfill
    css的tree-shaking
    代码分割,按需引入,import动态加载

  4. 提高开发体验
    sourcemap源码调试
    devserver热更新
    友好错误提示

  5. 保证稳定安全
    代码压缩混淆

你可能感兴趣的:(Webpack4从配置到优化)