webpack4学习(2)-优化

393 阅读2分钟

HMR热更新

一个模块发生变化只打包这个模块。
样式文件:配合style-loader内部实现HMR
js文件: 默认不实现HMR
html文件:默认不实现HRM

  • css HMR
module.exports={
  module:{
    rules:[
      {
        test:/\.css$/,
        use:[
          'style-loader',  //配套host实现css热更新
          'cass-loader'
        ]
      }
    ]
  },
  devServer:{
    hot:true
  }
}
  • HTML HMR
// 入口引入,html文件。html就一个文件无需实现HMR
module.exports={
  entry:['./index.js','./index.html'],
  devServer:{
    host:true
  }
}
  • js HMR

只处理非入口文件

// index.js 文件嵌入代码
if(module.hot){
 //说明开启了HMR
 module.hot.accept('./modulePath',function(){
   //监听模块的变化,一旦发生变化,其他模块不会重新打包。
   // 本回调将被执行
 })
}

source-map

提供源代码到构建后代码映射技术

[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map

  • inline:map.js内联,在代码最未。增加文件体积
  • eval: map.js内联,在每个文件代码后嵌入。增加文件体积
  • cheap:定位到行
  • module: 会将loader的souce map加入
devtool构建速度重新构建速度生产环境调试位置
(none)++++++yes无映射代码,打包后的代码
eval++++++no生成后的代码
cheap-eval-source-map+++no转换过的代码(仅限行)
cheap-module-eval-source-mapo++no原始源代码(仅限行)
eval-source-map--+no原始源代码
cheap-source-map+oyes转换过的代码(仅限行)
cheap-module-source-mapo-yes原始源代码(仅限行)
inline-cheap-source-map+ono转换过的代码(仅限行)
inline-cheap-module-source-mapo-no原始源代码(仅限行)
source-map----yes原始源代码,代码的错误位置
inline-source-map----no原始源代码,的错误位置
hidden-source-map----yes原始源代码
nosources-source-map----yes无源代码内容

oneof

oneof中的laoder只会使用一个

module.exports={
  module:{
    rules:[
      {
      //一下loader只会匹配一个
        oneOf:[
          {
            test:/\.css$/,
            use:[
              'style-loader',
              'css-loader'
            ]
          }
        ]
      }
    ]
  }
}

多进程打包

进程启动时间600ms,进程通信也需耗时。所以消耗时间长的loader,才需多进程打包

// npm i thread-loader
module.exports={
  module:{
    rules:[
      {
        test:/\.js$/,
        use:[
          {
            loader:'thread-loader',
            // 可设置cup核数,默认进程为cpu核数-1
            options:{
             workers:2 //进程2
            }
          }
        'babel-loader'
        ]
      }
    ]
  }
}

缓存

  • babel缓存
module.exports={
  module:{
    rules:[
      {
        test:/\.js$/,
        loader:'babel-loader',
        options:{
          cacheDirectory:true
        }
      }
    ]
  }
}
  • 文件资源缓存
    • [hash]每次webpack构建会生成一个唯一的hash,每次重新打包hash都会变。缓存无效
    • [chunkhash]:根据chunk生成hash,如果所打的包来源于同一个chunkhash是一样的,cssjs中被引入属于同一个chunk
    • [contenthash]:根据内容生成hash

生产使用contenthash文件打包+服务器缓存配合使用

tree shaking

去除无用的代码

  • 条件:使用es6模块化、mode='production'
  • 有的版本可能会把需要的代码删了
//package.json
{
  "sideEffects":false //所有代码都可以tree shaking
  // 会删除.css @babel/polyfill等引入未直接调用的文件
}
//package.json
{
  "sideEffects":["*.css","*.less"] //不删除的文件
}

code split

  • 多入口,多出口
import { resolve } from 'path';
module.exports={
  entry:{
    mian:'./src/main.js',
    index:'./src/index.js'
  },
  output:{
    filename:'js/[name].[contenthash:10].js',
    path:resolve(__dirname,'dist')
  }
}
  • optimization 第三方模块单独打成一个包
module.exports={
  entry:'./src/index.js',
  output:{
    filename:'js/[name].[contenthash:10].js',
    path:resolve(__dirname,'dist')
  },
  optimization:{
    splitChunks:{
      chunks:'all'
    }
  },
  /*
    将当前模块的记录其他模块的hash单独打包成一个文件,
    解决当文件内容发生变化时contenthash发生变化,导致应用此模块的js文件内容变化
    (js文件引用文件引用的是打包后的文件名)
  */
  runtimeChunk:{
    name:entrypoint=>`runtime-${entrypoint.name}`
  }
}
  • js实现代码分隔 webpack.config.js
module.exports={
  entry:'./src/index.js',
  output:{
    filename:'js/[name].[contenthash:10].js',
    path:resolve(__dirname,'dist')
  },
}

index.js

import(/webpackChunkName:'test'/'./test.js');
console.log('index')
// 会成两个js文件

懒加载 预加载

  • 懒加载:需要使用的时候加载
document.querySelector('.btn').onClick=function(){
  import(/*webpackChunkName:'test'*/'./test.js')
}
  • 预加载:其他资源加载完毕,空闲时在加载文件(兼容性差)
document.querySelector('.btn').onClick=function(){
  import(/*webpackChunkName:'test',webpackRrefetch:true*/'./test.js')
}

dll

对第三方库单独打包

// webpack.dll.config.js
const { resolve } = require('path');
const  webpack = require('webpack');
module.exports={
  entry:{
    /*
      vendor最终生成的名字,要打的包['moment']
    */
    vendor:['moment'],
    }
    output:{
      filename:'[name].js',
      path:resolve(__dirname,'dll'),
      library:'[name]_[hash]' //向外暴露内容的名字
    },
    plugins:[
      //作用生成一个manifest.json --> 提供与包的映射关系
      new webpack.DllPlugin({
        name:'[name]_[hash].js',
        path:resolve(__dirname,'dll/mainfest.json')
      })
    ],
    mode:'production'
}
// package.json
webpack --config webpack.dll.config.js

webpack排除已打包的第三方库及html自动引入

const webpack = require('webpack');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
module.exports={
  plugins:[
    new webpack.DllReferencePlugin({
      manifest: resolve(__dirname,'dll/manifest.json')
    }),
    //在html中自动引入资源
    new AddAssetHtmlWebpackPlugin({
      filePath:resolve(__dirname,'dll/vendor.js')
    })
  ]
}

externals

module.exports={
   // 拒绝包打入
  externals:{
    // 包名:npm下载的包名
    jquery:'jQuery'
  }
}