我的webpack学习记录(四):高级概念

192 阅读5分钟

高级概念

第一点 :Tree Shaking:打包的时候去除掉没使用的多余代码,但是只支持es6 的module形式的引入,因为只支持静态引入 import { a } from './fn.js' 可以,因为静态引入 require('./fn.js') 不可以,因为动态引入

如何配置,production默认开启,development模式需要配置 vue.config.js: optimization:{ usedExports:true } 还有package.json配置sideEffects:false, false代表没有例外,全部需要treeshaking,如果需要特殊处理不进行traashaking则进行下面的配置

package.json里面还需要配置sideEffects:['@babel/poly-fill'],如果不配置的话,像是babel-polyfill这种包他没有导出任何东西,他是把东西绑定到windows上,此时tree shaking会把它处理掉,为了避免这种情况,需要配置sideEffects:['@babel/poly-fill']

import './a.css' 当引入css文件时也不会导出东西,这样也会被处理掉,所以package.json应该写成 sideEffects:['*.css']

实际上development模式,即使tree shaking也不会直接删除多余代码,而是会标识没有使用,但是production会删除

第二点:关于模式development和production

production模式下代码一般会压缩,source-map一般可以生成map文件 为了避免两种模式频繁切换的麻烦,原来webpack.config.js文件可以一份为二,webpack.dev.js和webpack.prod.js,然后package.json里面 ‘dev’:'webpack-dev-server --config webpack.dev.js',

'build':'webpack --config webpack.prod.js'

第三点:关于模式code spliting 使用的是splitChunksPlugin splitChunks:{}那么代表使用默认配置,默认配置如下 splitChunks: {

  chunks: 'async',//chunks要和cacheGroups配合使用
  
  minSize: 20000,//大小超过20000b才分割
  
  minRemainingSize: 0,
  
  maxSize: 0,
  
  minChunks: 1,
  
  maxAsyncRequests: 30,
  
  maxInitialRequests: 30,
  
  enforceSizeThreshold: 50000,
  
  cacheGroups: {
  
    defaultVendors: {
    
      test: /[\\/]node_modules[\\/]/,
      
      priority: -10,
      
      reuseExistingChunk: true
      
    },
    
    default: {
    
      minChunks: 2,
      
      priority: -20,
      
      reuseExistingChunk: true
      
    }
    
  }
  
}

同步代码配置:optimization:{ splitChunks:{ chunks:'all',

}

} all代表同步异步都分割,async代表异步的文件分割,initial代表同步带吗分割

实际上异步会自动被打包到单独文件 function a() {

return import(/* webpackChunkName="lodash" */ 'lodash').then((default:'_')=>{

_.join(['1','2'])

})

}

a()

/webpackChunkName="lodash"/代表奖励啊异步分割的lodash代表起个名字叫lodash,但是这个起作用的前提是babel动态引入功能使用的是官方的插件plugin @babel/plugin-syntax-dynamic-import ,这个需要babelrc文件里面plugins值也要相应配置

第四点:关于懒加载和chunk 懒加载和webpack不是必然绑定,他是es6里import的相关概念,所以使用懒加载,一定要使用babel-polyfill

关于chunk,其实每一个js文件就是一个可以看做一个chunk,上面的代码分割配置中minChunks: 3,意思就是引用的这个chunk至少被引用3次才会被当做公共js提取分割

第五点:打包分析,preload prefetch

打包分析:webpack --profile --json > a.json --config common.config.js意思就是打包过程的相关数据会被放到这个json文件中,然后这个webpack.github.com/analyse 网站上有工具可以分析这个文件,工具有很多,除了这个官方的,还有,在webpack官网的guides下面的code splitting 下面有一个bundle analysis点开,有好多,选择自己适用的

关于preload,其实想想webpack的splitchunks里面配置chunks:默认是async,不是all,为什么,因为对于同步代码,分割以后,效果只是第二次使用别加载,但是webpack想第一次就有效果,我们可以分析页面,在控制台使用ctrl+shift+p命令,输入show coverage,点击刷新,可以看到页面一开始加载的文件性能分析

要想实现文件预加载 document.addEventListener("click",()=> {

import(/* webpackPrefetch:true */, './a.js').then(({default:f}) => { f() })

}) 这样的话,首页加载完后,空闲时间就会加载a.js,webpack认为真正提升性能的是异步加载文件,同步利用缓存不是根本,配合prefetch和preload最好,但是prefetch和preload有什么区别,prefetch是等主线程文件加载完了,空闲了才去加载,但是preload是和主线程同事加载,所以使用prefetch最好,

!!!!!就是要记住,缓存提升性能不是最重要的点,重点在于要提升代码的利用率!!!!!

第六点:css文件的代码分割 可以使用MiniCssExtractPlugin插件,该插件目前还不支持HMR热更新,所以最好在生产环境使用,还有压缩css的配套插件

第七点:webpack与浏览器缓存

文件名不变的话,用户普通刷新(不是强制刷新时),还是会去浏览器的缓存文件,不会找服务器那最新的,为此,output里面的production环境要name:[name].[contenthash].js 最新的webpack5里面内容不变。contenthash就不会变,但是之前的4321等版本内容不变,contenthash还是会变,所以要在optimization里面配置一下runtimeChunk:{name:runtime}才行

第八点:shimming webpac打包的代码在有的低版本的浏览器不能用,他会帮我们做兼容

index.js: import $ from 'jquery' import { b } from 'a.js' s('body')......

a.js: export function b(){ $('#ee').... }

此时a这个第三方库没有引入jquery,你在index.js里直接使用会报错,但是我们不能直接改a的代码,所以webpack帮我们在a内部引入plugins:[new Webpack.ProvidePlugin({:'jquery'})] 意思你的代码里面用了,我就帮你引入jquery,避免报错

另外任何一个模块里面的this指向模块自己,不指向window,如果你想让this指向window,可以借助imports-loader

第九点:环境变量的使用 webpack.config.js:

module.exports=(env)=>{

if(env&&env.production){

return{}

}else{

reutrn {}

}

}

那么在package.json: scripts:{

build: webpack --env.production --config './webpack.common.js' }

或者build: webpack --env.production=abc --config './webpack.common.js' 那么if(env&&env.production===‘abc’)

第十点:关于loader和plugins

loader其实就是一个函数,接受字符串和buffer,设置module.exports.raw=true则可以接受buffer类型数据,loader的执行分为pitch和normal,pitch是从前往后然后在从后往前执行normal,pitch的第三个参数data在normal阶段可以获取,如果pitch阶段有return数据,则会直接跳过后面的loader直接往前一个loader执行,loader内部可以同步一可以异步,具体的要看官网的api

plugin是一个class类,webpack会执行这个class里面的apply方法,默认compiler参数compiler.hooks.emit.tap('插件名字',(compilation)=>{ compilation可以去到目前执行阶段的打包内容 })

compiler的hooks类似于vue的生命周期,可以在自己想要的阶段执行指定的事情,具体hooks看官网api 常用的htmlWebpackPlugin ,cleanWebpackPlugin, miniCssExtractPlugin,DllPlugin,