万字长文解密webpack-基本使用/高级用法/性能优化 你想要的全都有!!!

创作不易 拒绝白嫖 点个赞呗

本质上,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。
主要概念

1.1 拆分配置和merge

npm init -y

yarn add -D webpack webpack-cli

yarn add -D webpack-merge

  • build\webpack.common.js
  • build\webpack.dev.js
  • build\webpack.prod.js

公共配置

const path = require('path') module.exports ={ entry:path.join(__dirname, '..', 'src/index') } 

开发时

const webpackCommon = require('./webpack.common.js') const { merge } = require('webpack-merge') module.exports = merge(webpackCommon, { mode: 'development' }) 

打包时

const path = require('path') const webpack = require('webpack') const webpackCommon = require('./webpack.common.js') const { merge } = require('webpack-merge') const { CleanWebpackPlugin } = require('clean-webpack-plugin') module.exports = merge(webpackCommon, { mode: 'production', output: { filename: '[name].[contenthash:8].js', path: path.join(__dirname, '..', 'dist'), }, plugins: [new CleanWebpackPlugin()] }) 
 "scripts": {  "dev": "webpack-dev-server --config build/webpack.dev.js", "build": "webpack --config build/webpack.prod.js" }, 

新建src/index
执行 yarn build

1.2 启动本地服务

yarn add -D webpack-dev-server

webpack.dev.js

 devServer: { port: 8080, progress: true,  contentBase:path.join(__dirname, '..', 'dist'),  open: true,  compress: true,   proxy: { } } 

yarn dev

yarn add -D html-webpack-plugin

webpack.common.js

 plugins:[ new HtmlWebpackPlugin({ template: path.join(__dirname, '..', 'src/index.html'), filename: 'index.html' }) ] 

开发环境,会在内存中生成一个html文件
打包环境,会在dist下生成一个html文件
html文件会自动引入main.js

1.3 处理es6(配置babel)

yarn add -D babel-loader

yarn add -D @babel/core

yarn add -D @babel/preset-env

 module: { rules: [ { test: /\.js$/,  use: [ 'babel-loader', ], include: path.join(__dirname, '..', 'src'), exclude: /node_modules/ } ] }, 

1.4 处理css

css插入到页面的style标签

yarn add -D style-loader

yarn add -D css-loader

自动添加前缀

yarn add -D postcss-loader autoprefixer

build\webpack.common.js

{ test: /\.css$/,  use: ['style-loader', 'css-loader', 'postcss-loader'] }, 

postcss.config.js

module.exports = { plugins: [require('autoprefixer')] } 

1.5 处理图片

js文件中通过 import imgSrc from ‘./photo’; img.src = imgSrc引入
在css文件中作为背景图引入
在html文件中直接引入

yarn add -D file-loader

yarn add -D url-loader

build-base-conf\webpack.dev.js

  { test: /\.(png|jpg|jpeg|gif)$/, use: 'file-loader' } 

build-base-conf\webpack.prod.js

  { test: /\.(png|jpg|jpeg|gif)$/, use: { loader: 'url-loader', options: {   limit: 5 * 1024,  outputPath: '/img1/',   } } }, 

2.1 配置多入口

entry: { index: path.join(srcPath, 'index.js'), other: path.join(srcPath, 'other.js') }, 

这里的index与other就是chunk名称

build-base-conf\webpack.prod.js

 output: { filename: 'bundle.[contentHash:8].js',  path: distPath,  }, 

注意这里只需要在prod里面加入配置,
dev不需要

new HtmlWebpackPlugin({ template: path.join(__dirname, '..', 'src/index.html'), filename: 'index.html',  chunks: ['index']  }),  new HtmlWebpackPlugin({ template: path.join(__dirname, '..', 'src/other.html'), filename: 'other.html', chunks: ['other']  }) 

2.2 抽离css(打包)

yarn add -D mini-css-extract-plugin

build\webpack.prod.js

 { test: /\.css$/, use: [ MiniCssExtractPlugin.loader,  'css-loader', 'postcss-loader' ] }, 

2.3 压缩css(打包)

yarn add optimize-css-assets-webpack-plugin

build-min-extract-css\webpack.prod.js

 optimization: {  minimizer: [ new OptimizeCSSAssetsPlugin({})], } 

2.4 抽离公共代码

抽离公共代码
我们在开发多个页面的项目的时候,有时候会在几个页面中引用某些公共的模块,这些公共模块多次被下载会造成资源浪费,如果把这些公共模块抽离出来只需下载一次之后便缓存起来了,这样就可以避免因重复下载而浪费资源,那么怎么在webpack中抽离出公共部分呢?方法如下:

举例:

项目中分别有a.js, b.js, page1.js, page2.js这四个JS文件,
page1.js 和 page2.js中同时都引用了a.js, b.js,
这时候想把a.js, b.js抽离出来合并成一个公共的js,然后在page1, page2中自动引入这个公共的js,

 splitChunks: { cacheGroups: {  common: { chunks: 'initial', minSize: 0,  minChunks: 2  } } } 

页面中有时会引入第三方模块,比如import $ from ‘jquery’; page1中需要引用,page2中也需要引用,这时候就可以用vendor把jquery抽离出来,方法如下:

 optimization: {  splitChunks: { chunks: 'all',   cacheGroups: {  vendor: { name: 'vendor',  priority: 1,  test: /node_modules/, minSize: 0,  minChunks: 1  },  common: { name: 'common',  priority: 0,  minSize: 0,  minChunks: 2  } } } } 

注意:这里需要配置权重 priority,因为抽离的时候会执行第一个common配置,入口处看到jquery也被公用了就一起抽离了,不会再执行wendor的配置了,所以加了权重之后会先抽离第三方模块,然后再抽离公共common的,这样就实现了第三方和公用的都被抽离了。

3.1 优化babal-loader(缩小构建目标)

Loader处理文件的转换操作是很耗时的,所以需要让尽可能少的文件被Loader处理

{ test: /\.js$/, use: [ 'babel-loader?cacheDirectory', ], include: path.resolve(__dirname, 'src'), exclude: path.resolve(__dirname,' ./node_modules'), }, 

3.2 happyPack 多进程打包

yarn add -D happypack

Plugins

new HappyPack({  id: "babel", loaders: ["babel-loader?cacheDirectory"],  threads: 5,  }), new HappyPack({ id: 'styles', loaders: ['css-loader', 'postcss-loader'], threads: 5,  verbose: true  }), 

rules

 { test: /\.(js|jsx)$/, use: [MiniCssExtractPlugin.loader, "HappyPack/loader?id=babel"], exclude: path.resolve(__dirname, " ./node_modules"), }, { test: /\.css$/, use: 'happypack/loader?id=styles', include: path.join(__dirname, '..', 'src') }, 

3.3 ParallelUglifyPlugin优化压缩

webpack默认提供了UglifyJS插件来压缩JS代码,但是它使用的是单线程压缩代码,也就是说多个js文件需要被压缩,它需要一个个文件进行压缩。
所以说在正式环境打包压缩代码速度非常慢(因为压缩JS代码需要先把代码解析成用Object抽象表示的AST语法树,再去应用各种规则分析和处理AST,导致这个过程耗时非常大)。

yarn add -D webpack-parallel-uglify-plugin

 new ParallelUglifyPlugin({  uglifyJS: { output: {  beautify: false,  comments: false }, compress: {  drop_console: true,  collapse_vars: true,  reduce_vars: true } } } ) 

3.4 自动刷新

 借助自动化的手段,在监听到本地源码文件发生变化时,自动重新构建出可运行的代码后再控制浏览器刷新。Webpack将这些功能都内置了,并且提供了多种方案供我们选择。 
module.export = { watch: true, watchOptions: {  ignored: /node_modules/,  aggregateTimeout: 300,  poll: 1000 } } 
  • 在 Webpack 中监听一个文件发生变化的原理是定时可在watchOptions.poll中设置)的去获取这个文件的最后编辑时间,每次都存下最新的最后编辑时间,如果发现当前获取的和最后一次保存的最后编辑时间不一致,就认为该文件发生了变化
  • 当发现某个文件发生了变化时,并不会立刻告诉监听者,而是先缓存起来,收集一段时间(可在watchOptions.aggregateTimeout中设置)的变化后,再一次性告诉监听者。防止在编辑代码的过程中可能会高频的输入文字导致文件变化的事件高频的发生

3.5 模块热更新

_ _DevServer 还支持一种叫做模块热替换( Hot Module Replacement )的技术可在不刷新整个网页的情况下做到超灵敏实时预览。原理是在一个源码发生变化时,只需重新编译发生变化的模块,再用新输出的模块替换掉浏览器中对应的老模块 。模块热替换技术在很大程度上提升了开发效率和体验 。
项目中模块热替换的配置:

 const HotModuleReplacementPlugin = require('webpack/lib/HotModuleReplacementPlugin'); devServer:{ host:'localhost', port:'8080', open:true//自动拉起浏览器 // 只设置hot只有cssHMR生效 hot:true,//热加载 //hotOnly:true }, plugins:[ //热更新插件 new webpack.HotModuleReplacementPlugin() ] HotModuleReplacementPlugin生成一个mainifest(一个json结构描述了发生变化的modules列表) 和update file(一个js文件包含修改后的代码内容) 

JS文件中

if (module.hot) { module.hot.accept('./print.js', function() { //告诉 webpack 接受热替换的模块 console.log('Accepting the updated printMe module!'); printMe(); }) } // 对Js生效 

3.6 性能分析

 const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); const commonConfig = {  plugins: [ new BundleAnalyzerPlugin({ analyzerPort: 8889,  openAnalyzer: false, }), ]  } 
 const SpeedMeasurePlugin = require("speed-measure-webpack-plugin"); const smp = new SpeedMeasurePlugin();  module.exports = (production) => { if (production) { const endProdConfig = merge(commonConfig, prodConfig); return smp.wrap(endProdConfig); } else { const endDevConfig = merge(commonConfig, devConfig); return smp.wrap(endDevConfig); } }; 

2020-10-10 webpack 5.0.0 发布了,但这并不意味着它已经完成了,没有 bug,甚至功能完整。 就像 webpack 4
一样,我们通过修复问题以及增加新特性来延续开发。 在接下来的日子里,可能会有很多 bug 修复。新特性可能也会出现。

尝试用持久性缓存来提高构建性能。 尝试用更好的算法和默认值来改进长期缓存。 尝试用更好的 Tree Shaking 和代码生成来改善包大小。
尝试改善与网络平台的兼容性。 尝试在不引入任何破坏性变化的情况下,清理那些在实现 v4 功能时处于奇怪状态的内部结构。
试图通过现在引入突破性的变化来为未来的功能做准备,使其能够尽可能长时间地保持在 v5 版本上。 迁移指南

本网页由快兔兔AI采集器生成,目的为演示采集效果,若侵权请及时联系删除。

原文链接:https://blog.csdn.net/shangyanaf/article/details/119948539

更多内容