Webpack「v5.0」
概念 | webpack 中文文档 (docschina.org)
webpack是一个现代JavaScript应用程序的静态模块打包工具。当webpack处理应用程序时,它会在内部构建一个依赖图(dependency [/dɪˈpendənsi/] graph [/ɡræf/]),此依赖图会映射项目所需的每个模块,并生成一个或多个bundle /ˈbʌndl/ 包!
0. 预备知识
0.1 为啥要学webpack?
0.1.1 性能优化
见性能优化
之前我们在讲前端的时候,我们可以从以下几个方面,去提高页面第一次渲染的速度,以及运行时的性能:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 
 | /* 第一类:明显改善页面第一次加载的速度,减少白屏等待的时间
 @1 使用骨架屏技术
 + 服务器骨架屏:页面首屏内容是基于服务器渲染的
 + 前端骨架屏:在真实内容渲染出来之前,我们给予相关位置用“色框”占位!(知乎?)
 @2 减少HTTP请求的次数和大小
 + CSS/JS都要做合并压缩「尽可能合并为一个CSS和一个JS」
 + 图片的合并压缩,例如:雪碧图(CSS Sprit)
 + 使用图片BASE64来加快图片的渲染!
 + 图片一定要做延迟加载
 + 使用字体图片和矢量图,来代替位图!!
 + 音视频资源也要设置延迟加载「preload='none'」
 + 数据的异步加载
 + 开启服务器端的GZIP压缩,可以让访问的资源压缩60%+
 @3 渲染页面中的优化
 + 因为<script>会阻碍GUI渲染,所以:把其放在页面末尾,或者设置async/defer!
 + 因为<link>是异步加载CSS资源,所以建议放在页面开始,尽快获取样式资源!!
 + 不要使用import导入CSS,因为其会阻碍GUI的渲染!
 + 样式代码较少的情况下,使用<style>内嵌式,尤其是移动端开发!
 @4 在网络传输中的优化
 + 减少cookie的内容大小「因为只要向服务器发送请求,不论服务器是否需要,总会在请求头中把cookie传递给服务器,如果cookie比较大,会让所有的请求都变慢」
 + 资源分服务器部署「例如:web服务器、图片服务器、数据服务器」,这样可以降低服务器压力,提高服务器的并发,让资源能更加合理的被利用;但是也会导致DNS解析次数增加,此时可以基于DNS Prefetch来优化DNS解析!!
 + 基于HTTP/2.0来代替HTTP/1.1
 + 基于新的二进制格式,让传输的内容更加丰富健壮
 + header压缩,让传输速度更快(没改就不传)
 + 服务端自动推送,可以减少HTTP请求次数
 + 多路复用,让传输速度更快,避免线头阻塞(UDP)
 + 基于Connection:keep-alive保持TCP通道长链接「HTTP/1.1版本会自动开启」
 + 开启CDN「地域分布式服务器部署」
 + 对于静态资源文件采取“强缓存和协商缓存”,对于不经常更新的数据请求,设置数据缓存!
 
 第二类:提高页面运行时候的性能
 @1 减少循环嵌套,降低时间复杂度;避免出现死循环/死递归;
 @2 使用事件委托来优化事件绑定,性能可以提高40%+
 @3 减少DOM的回流(重排)和重绘
 + 样式分离读写「渲染队列机制」
 + 批量新增元素「字符串拼接、文档碎片」
 + 基于transform/opacity等方式操作样式
 + 把需要频繁修改样式的元素(例如:JS实现动画)脱离文档流
 + ...
 @4 使用函数的防抖和节流处理高频触发操作
 @5 合理使用闭包,避免内存泄漏,以及手动释放无用的内存!
 @6 减少页面冗余代码,提高代码的重复使用率「也就是尽可能的做封装处理」
 @7 尽可能不要使用for/in循环,因为其消耗性能
 @8 避免使用eval/with等消耗性能的代码
 @9 能用CSS3处理的动画坚决不用JS「JS动画尽可能基于requestAnimationFrame来代替定时器」
 @10 避免使用CSS表达式,因为其非常消耗性能
 @11 CSS选择器的前缀不要过长「因为CSS选择器渲染是从右到左」
 @12 减少table布局「table的渲染是比较消耗性能的」
 ......
 */
 
 | 
我们
0.1.2为了兼容、预编译、开发预览
- 平时开发的时候,一般会使用less/sass/stylus等CSS预编译器「需要基于vscode插件把其编译为CSS」; 
- 会直接使用ES6的语法「需要基于babel把其转换为ES5,以此兼容IE」; 
- 会给CSS3样式加很多的前缀,以此来处理兼容问题……   
- 我们还会基于vscode中的liveserver插件,创建一个本地web服务器,来预览我们的项目…..
 我们还要基于各种方案,来解决跨域访问的问题……
 
0.2 webpack可以帮我们干的事情
-   代码转换:TypeScript编译成JavaScript、LESS/SCSS编译成CSS、ES6/7编译为ES5、虚拟DOM编译为真实的DOM等等…
-   文件优化:压缩JS、CSS、HTML代码,压缩合并图片,图片BASE64等
-   代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码等
-   模块合并:把模块分类合并成一个文件
-   自动刷新:创建本地Web服务器,监听本地源代码的变化,自动重新构建,刷新浏览器
-   代码校验:Eslint代码规范校验和检测、单元测试等
-   自动发布:自动构建出线上发布代码并传输给发布系统
-   跨域处理
- ……
除了webpack外的其他:
-   grunt(淘汰)
-   gulp(少了、老了)
-   Parcel
-   vite(底层原理是rollup,比webpack快,但兼容不好)
-   rollup
-   Turbopack(据说比webpack快700倍,比vite快10倍)
-   ……
webpack问题
1.webpack打包原理
2.webpack的基础操作
安装
为防止全局安装webpack导致版本冲突,真实项目中以本地安装为主
弊端:本地安装就需要配置webpack命令
npm比较慢建议使用yarn、pnmp
| 12
 3
 4
 
 | $ npm init -y$ npm install webpack webpack-cli --save-dev
 OR
 $ yarn add webpack webpack-cli -D
 
 | 
零配置使用
| 12
 3
 4
 5
 6
 
 | /** 默认会打包SRC目录中的JS文件(入口默认index.js)
 * 打包完成的目录默认是DIST/MAIN.JS
 * webpack默认支持CommonJS和ES6 Module的模块规范,依此进行依赖打包
 */
 $ npx webpack
 
 | 
自定义基础配置
webpack.config.js
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | const path = require('path');
 
 
 module.exports = {
 
 mode: 'production',
 
 entry: './src/index.js',
 
 output: {
 
 filename: 'bundle.[hash].js',
 
 path: path.resolve(__dirname, 'dist')
 }
 };
 
 | 
html-webpack-plugin
https://www.webpackjs.com/plugins/html-webpack-plugin/
$ yarn add html-webpack-plugin -D
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {
 ...
 plugins: [
 new HtmlWebpackPlugin({
 
 template: './public/index.html',
 
 filename: 'index.html',
 
 minify: true
 })
 ]
 }
 
 | 
多入口 & 多出口
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 
 | const HtmlWebpackPlugin = require('html-webpack-plugin');
 const htmlPlugins = ['index', 'login'].map(chunk => {
 return new HtmlWebpackPlugin({
 template: `./public/${chunk}.html`,
 filename: `${chunk}.html`,
 
 chunks: [chunk],
 minify: true
 });
 });
 module.exports = {
 mode: 'production',
 
 entry: {
 index: "./src/index.js",
 login: "./src/login.js",
 },
 
 output: {
 filename: "[name].[hash].js",
 path: path.resolve(__dirname, "dist")
 },
 plugins: [
 ...htmlPlugins
 ]
 };
 
 | 
clean-webpack-plugin
$ yarn add clean-webpack-plugin -D
| 12
 3
 4
 5
 6
 7
 
 | const { CleanWebpackPlugin } = require('clean-webpack-plugin');module.exports = {
 ...
 plugins: [
 new CleanWebpackPlugin()
 ]
 };
 
 | 
webpack-dev-server
https://webpack.js.org/configuration/dev-server/
$ yarn add webpack-dev-server -D
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 
 | "scripts": {
 "start": "webpack server",
 "build": "webpack"
 }
 
 
 module.exports = {
 ...
 devServer: {
 
 host: '127.0.0.1',
 
 port: 3000,
 
 compress: true,
 
 open: true,
 
 hot: true,
 
 proxy: {
 "/jian": {
 target: "https://www.jianshu.com/asimov",
 changeOrigin: true,
 ws: true,
 pathRewrite: { "^/jian": "" }
 },
 "/zhi": {
 target: "https://news-at.zhihu.com/api/4",
 changeOrigin: true,
 ws: true,
 pathRewrite: { "^/zhi": "" }
 }
 }
 }
 };
 
 
 
 
 
 
 
 
 | 
处理样式的loader「加载器」
$ yarn add css-loader style-loader less less-loader autoprefixer postcss-loader -D
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | module.exports = {...
 
 module: {
 rules: [{
 test: /\.(css|less)$/,
 use: [
 "style-loader",
 "css-loader",
 "postcss-loader",
 "less-loader"
 ]
 }]
 }
 };
 
 | 
postcss.config.js
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | module.exports = {plugins: [
 require('autoprefixer')
 ]
 };
 
 
 {
 loader: "postcss-loader",
 options: {
 postcssOptions: {
 plugins: [
 require('autoprefixer')
 ]
 }
 }
 },
 
 | 
package.json OR .browserslistrc
| 12
 3
 4
 5
 6
 
 | "browserslist": [
 "> 1%",
 "last 2 versions",
 "not dead"
 ]
 
 | 
https://www.npmjs.com/package/mini-css-extract-plugin
$ yarn add mini-css-extract-plugin -D
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | const MiniCssExtractPlugin = require('mini-css-extract-plugin');module.exports = {
 ...
 plugins: [
 ...
 new MiniCssExtractPlugin({
 
 filename: 'main.[hash].css'
 })
 ],
 ...
 module: {
 rules: [{
 test: /\.(css|less)$/,
 use: [
 
 MiniCssExtractPlugin.loader,
 ...
 ]
 }]
 }
 };
 
 | 
基于babel实现ES6的转换
$ yarn add babel babel-loader @babel/preset-env @babel/core -D
$ yarn add @babel/polyfill
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | module.exports = {...
 module: {
 rules: [{
 test: /\.js$/,
 use: ['babel-loader'],
 
 include: path.resolve(__dirname, 'src'),
 exclude: /node_modules/
 }]
 }
 };
 
 | 
babel.config.js
| 12
 3
 4
 5
 
 | module.exports = {presets: [
 "@babel/preset-env"
 ]
 };
 
 | 
index.js
| 1
 | import '@babel/polyfill';
 | 
设置优化项:压缩CSS/JS
$ yarn add css-minimizer-webpack-plugin terser-webpack-plugin -D
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | const TerserPlugin = require('terser-webpack-plugin');const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin');
 module.exports = {
 optimization: {
 
 minimizer: [
 new CssMinimizerWebpackPlugin(),
 new TerserPlugin()
 ]
 }
 };
 
 | 
设置解析器:配置别名
| 12
 3
 4
 5
 6
 7
 
 | module.exports = {resolve: {
 alias: {
 '@': path.resolve(__dirname, './src')
 }
 }
 };
 
 | 
图片的处理
$ yarn add file-loader url-loader -D
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | module.exports = {...
 module: {
 rules: [
 ...
 {
 test: /\.(png|jpe?g|gif)$/i,
 type: 'javascript/auto',
 use: [{
 
 loader: 'url-loader',
 options: {
 limit: 200 * 1024,
 esModule: false,
 name: 'images/[name].[hash].[ext]'
 }
 }]
 }]
 },
 
 performance: {
 maxAssetSize: 100 * 1024 * 1024 * 1024,
 maxEntrypointSize: 100 * 1024 * 1024 * 1024
 }
 };
 
 |