webpack5
简介
webpack 是代码编译工具,有入口、出口、loader 和插件。webpack 是一个用于现代JavaScript应用程序的静态模块打包工具。当 webpack 处理应用程序时,它会在内部构建一个依赖图(dependency graph),此依赖图对应映射到项目所需的每个模块,并生成一个或多个 bundle
参考资料
简介安装配置
简介
- webpack 是一个模块打包器(构建工具)。它的主要目标是将 JavaScript 文件打包在一起,打包后的文件用于在浏览器中使用,但它也能够胜任转换(transform)、打包(bundle)或包裹(package)任何资源(resource or asset)。
- 官网: https://webpack.js.org/
- 中文文档:https://webpack.docschina.org/
webpack原理和概念
- 树结构: 在一个入口文件中引入所有资源,形成所有依赖关系树状图
- 模块:模块就是模块可以是ES6模块也可以是commonJS或者AMD模块,对于webpack来说,所有的资源(css,img…)
- chunk:打包过程中被操作的模块文件叫做chunk,例如异步加载一个模块就是一个chunk
- bundel:bundle是最后打包后的文件,最终文件可以和chunk长的一模一样,但是大部分情况下他是多个chunk的集合
- 为了优化最后生产出的bundle数量可能不等于chunk的数量,因为有可能多个chunk被组合到了一个Bundle中。
1 | graph LR |
webpack环境安装
1 | 安装webpack、webpack-cli至开发环境 i=install -D=--save-dev 注意看看pack.json webpack版本5+ webpack-cli4+ |
webpack基础配置
- 项目根目录下,新建
webpack.config.js
文件(就用这个名字,换其它的名字需要在执行 webpack 命令的时候重新指定一遍,默认会读取这个名字的文件不需要指定) - 该文件为执行 webpack 命令默认读取的配置文件
- webpack默认打包js资源
1 | //node中的包,可获取当前项目的根路径 |
html资源打包配置
由于webpack默认只能打包js资源,我们想要打包html资源需要在开发环境安装html-webpack-plugin插件
插件安装
插件3大步骤:
1.下载 npm i html-webpack-plugin -D
2.引入 const htmlWebpackPlugin = require(‘html-webpack-plugin’);
3.使用 new htmlWebpackPlugin();
1 | 方式一:npm安装插件 |
配置webpack.config.js文件
- 打包 html 文件
1 | const {resolve} = require("path"); |
分开打包 html 文件
- 不同的 html 文件需要引入不同的 js 文件,因此需要对不同的 js 文件分别或组合打包成一个bundle,在不同的页面中引用
1 | //模拟真实打包 |
css资源打包
内联打包
- 实现原理:先用css-loader把 css 样式打包到 js 的一个bundle 然后用style-loader创建了一个>标签引入样式,属于内联式打包
- 开发环境安装插件:css-loader style-loader
- css-loader:把css资源打包捆绑到js文件中(作用是处理css中的 @import 和 url 这样的外部资源)
- style-loader:把css加载引入到html中(作用是把样式插入到 DOM中,方法是在head中插入一个style标签,并把样式写入到这个标签的 innerHTML里)
1 | #方式一:npm 安装插件 |
css资源打包到html
- webpack配置
module
标签
打包的 js 导入css文件(import/require)
1
2
3
4
5//打包index的时候会通过css-loder把css打到index.js中
require('./style.css')
require('./lessstyle.less')
require('./sassstyle.scss')
console.log("这是入口文件");
webpack.config.js配置
1 | //打包 css |
Less/Sass资源打包
- 因为css只是单纯的属性描述,它并不具有变量、条件语句等,css的特性导致了它难组织和维护。
- Sass和Less都属于CSS预处理器,定义了一种新的语言,其基本思想是用一种专门的编程语言,为
- CSS增加一些编程的特性,将CSS作为目标生成文件,然后开发者使用这种语言进行CSS编码工作.
- Less需要使用npm下载less包和less- loader
- Sass需要使用npm下载node-sass包和sass- loader
- 需要在打包的 js 文件中引如 less sass
插件安装
1 | #Less的插件(开发环境) |
webpack.config.js配置
1 | module: { |
less/sass 语法
1 | //less语法 |
1 | //sass语法 |
单独打包样式文件
把less,sass,css等资源打包成一个独立的资源文件
下载插件
插件3大步骤:
1.下载 npm i mini-css-extract-plugin -D
2.引入 const miniCssExtractPlugin = require(‘mini-css-extract-plugin’);
3.使用 new miniCssExtractPlugin()
1 | # npm 下载 |
webpack.config.js配置
1 | //将css less sass 资源 单独打包 成独立的文件 不嵌入在 js 中 |
css兼容性处理
- 通过插件确保所有的css样式中的属性在所有类型的浏览器大多数浏览器的大多数版本都支持,且显示效果一致
- 需要使用postcss处理,下载两个包postcss-loader和postcss-preset-env
- posters会找到 package json中的 browserslist里面的配置,通过配置加载css的兼容性
- 修改loader的配置, 新版需要写postcss.config.js, less和sass兼容性同理
插件安装
1 | npm 安装postcss-loader,postcss-preset-env 安装至开发环境 |
配置文件
- 需要新建
postcss.config.js
文件、package.json中新增browserslist
标签、webpack.config.js中使用postcss-loader
新建 postcss 配置文件
- 项目根路径新建
postcss.config.js
文件,该文件为 postcss 的默认配置文件
1 | // postcss 配置文件,该配置文件引入 postcss-preset-env 插件-->该插件会读取 package.json文件下的 browserslist |
package.json文件配置信息
1 | { |
webpack.config.js配置
- 执行 webpack 打包时如果 less scss 文件中有注释会出现如下截图报错,删除注释即可
1 | //解决css less sass 兼容问题 |
压缩 css
- 下载插件 optimize-css-assets-webpack-plugin
- 引入插件:const OptimizeCssAssetsWebpackPlugin = require(‘optimize-css-assets-webpack-plugin’);
- 使用插件: plugins: [ new OptimizeCssAssetsWebpackPlugin() ]
下载插件
1 | # npm 引入插件(开发环境) |
webpack.config.js 配置
- 引入:const OptimizeCssAssetsWebpackPlugin = require(‘optimize-css-assets-webpack-plugin’);
- 创建对象:new OptimizeCssAssetsWebpackPlugin()
1 | //压缩 css |
图片资源打包
css中引入图片
实现方式
- webpack4 需要用
file-loader
url-loader
这两个插件(需要下载) - webpack5 直接使用
assets-module
因为在v5
中url-loader
已经被废弃(该模块不需要下载)
webpack.config.js 配置
1 | //打包图片资源(css html中引入) |
html中引入图片
实现方式
- 使用 html-loader 插件实现
1 | # npm 安装(开发环境) |
webpack.config.js 配置
1 | //打包图片资源(css html中引入) |
打包其它资源
- 不需要优化和压缩处理,直接输出的资源,称为其他资源,如字体
字体icon资源打包
流程
- iconfont 图标库下载对应的资源后将【.css .ttf .woff .woff2】文件 copy 至项目下
- 入口 js 中引入 iconfont.css
require('../font/iconfont.css')
- webpack5 直接使用
asset/resource
模块(无需下载) - webpack 配置 asset/resource 规则
下载及 copy 字体文件
入口 js 中引入 iconfont
- 在入口 js 文件中引入 iconfont.css 文件
require('../font/iconfont.css')
webpack.config.js 配置
1 | //打包字体资源 |
eslint
简介
- eslint 是一个开源的
js 代码检查工具
,初衷是为了让程序员可以创建自己的检测规则。实际生产中,团队内往往会制订一套统一的标准,让整个团队的编码风格达到一致 - eslint 其实与 webpack 没有任何关系,两者并不互相依赖,甚至一般情况下我们并不会在 webpack 中进行 eslint 的配置,可以单独使用。
- 语法检查使用eslint-loader, 并基于eslint包,
只用来检查js语法
。(eslint-loader –> eslint-webpack-plugin ) - 注意只检查自己写的js源代码, 第三方库是不用检查的, 可以在npmjs.com中查看规则。
- 需要使用js来的规则库来检查代码 “airbnb”, 需要eslint-config-airbnb-base和eslint-plugin-import 两个包
- eslin进行检查需要依赖eslint-loader,同时告诉它用什么标准去检查 常用的就是
airbnb
airbnb 又依赖 eslint-config-airbnb-base和eslint-plugin-import 两个包
安装插件包
有很多视频在使用 eslint-loader 我在 webpack5.68.0 使用时会有如下报错,网上说 eslint-loader 已经弃用了 采用 eslint-webpack-plugin 插件
Module build failed (from ./node_modules/eslint-loader/dist/cjs.js):
TypeError: Cannot read properties of undefined (reading ‘getFormatter’)
1 | # npm 安装(开发环境) |
- 如果在安装的插件的时候有提示 Expected version “^12.22.0 || ^14.17.0 || >=16.0.0” ,需要更换 node 版本
- 我是在 node 官网下载最近的一个稳定版本重新安装的就可以了 v16.14.0
配置文件
- const ESLintPlugin = require(‘eslint-webpack-plugin’);
引入插件
- new ESLintPlugin({fix: true })
使用插件,自动修复不合理写法,规则会根据 package.json 中的 eslintConfig 下 extends 对应的属性去检查
1 | // eslint 语法规范检查 |
- “scripts”: { “eslint”: “eslint src” } 在控制台可通过执行
npm run eslint
或者yarn eslint
会去检查 src目录下的 js 规范 - “eslintConfig”: { “extends”: “airbnb-base” } 定义的检查规范为
airbnb-base
1 | { |
特殊配置
- 有的时候想针对某行代码跳过检查只需要在该行代码上添加
// eslint-disable-next-line
即可跳过对下一行的检查(只针对下一行有效)
热部署
简介
- 在前面的章节中,我们每次写完程序或者修改了内容后都需要通过 webpack 进行打包到 build 目录,这种情况一般是用在生产环境,开发完了打包测试上线,在实际的工作中我们更加希望我们每次修改完代码后就能够自动刷新对应的 html css js 等内容便于我们实时的查看调试,这也就本次记录的内容热部署
- devServer给我们提供了开发过程中的服务器,是一个使用了express的Http服务器,它的作用主要是为了监听资源文件的改变,该http服务器和client使用了websocket通信协议,只要资源文件发生改变,webpack-dev-server就会实时的进行编译。
- 只会在内存中编译,不会有任何输出,下载webpack-dev-server包
- webpack-dev-server并不能读取你的webpack.config.js的配置output
也就是说每次修改了配置文件需要手动重启一下,修改其它的 html css js 会自动刷新
- 启动devServer指令为: npx webpack serve 本目录执行
- webpack5无法自动刷新,解决:添加配置:target: ‘web’
流程
- 下载 webpack-dev-server 包
- webpackage.config.js 下新增
devServer
属性用于指定端口等信息 - package.json 中指定启动命令
示例
下载包
1 | # npm 安装(开发环境) |
webpack.config.js 配置
- 每次配置文件 webpack.config.js 发生了变化需要重启 devServer 服务器(因为配置文件是在启动时生效,发生改变不能修改启动时的参数设置这些)
- 注释了 eslint 检查(开发环境不方便)
- 去除了
mode: "development"
更改为在启动命令scripts
中指定 - 新增
target
devServer
- htmlWebpackPlugin filename 需要指定为 index.html 不然会报错 404(应该是热部署启动后默认去读取 index.html 文件)
- 如果自动刷新无效的话注意一般是开启了HMR(devServer中 hot:true) 看 entry属性下有没有配置需要监听的html(entry: [‘./src/demo/js/index.js’,’./src/demo/index.html’]) 这里的
./src/demo/index.html
就是需要自动刷新的页面
1 | // 热部署 htmlWebpackPlugin filename 需要指定为 index.html 不然会报错 404 |
- content-base //设定webpack-dev-server的director根目录。如果不进行设定的话,默认是在当前目录下。
- quiet: //控制台中不输出打包的信息,开发中一般设置为false,进行 打印,这样查看错误比较方面
- no-info: // 不显示任何信息
- colors: //对信息进行颜色输出
- no-colors: //对信息不进行颜色输出
- compress: //开启gzip压缩
- host <hostname/ip>: //设置ip
- port
: //设置端口号,默认是:8080 - inline: //webpack-dev-server会在你的webpack.config.js的入口配置文件中再添加一个入口,
- hot: //开发热替换
- open: //启动命令,自动打开浏览器
- history-api-fallback: //查看历史url
package.json
scripts
下新增dev
build
通过命令指定开发模式启动或者打包,并且携带参数指定 mode 这样就不需要在 webpack.config.js 中指定 mode- 命令行中的比配置文件中参数的优先级高
1 | { |
环境优化
- 开发环境的优化:打包构建速度(比如我们只更新了一个js文件重新编译的时候只编译这一个 js 文件,热加载)、优化代码调式
- 生产环境的优化:代码运行的性能(例如尽量减小代码文件的大小,只打包引用到了的 css js )
开发环境HMR(模块热替换)
热模块替换一般是针对开发环境的优化
- 模块热替换(Hot Module Replacement 即 HMR)是 webpack 提供的最有用的功能之一, 它允许在运行时更新各种模块, 而
无需进行完全刷新
。 - 启用这个功能,只需要修改一下 webpack.config.js 的配置, 使用 webpack 内置的 HMR 插件就可以了,
在devServer中使用hot参数(hot:true)
。 - 启用 webpack 内置的 HMR插件后, module.hot 接口就会暴露在 index.js 中, 接下来需要在 index.js 中配置告诉 webpack 接受HMR的模块。
样式文件
- 样式文件(css less sass)在使用HMR功能的时候,开发环境中使用
style-loader
(之前使用的MiniCssExtractPlugin.loader
把所有 css less sass 打包成一个单独的文件,这样 HMR 就没有意义了因为更新了这个所有打包一起的文件比较大,开发环境使用 style-loader 就不会打包成单独的文件,这样就能做到只更新这一个样式文件 ) - 这里我没去实践,一般是会根据配置什么的去设置比如开发环境用 style-loader 线上用 MiniCssExtractPlugin.loader 打包成一个 css 文件
html
- HTML 的HMR功能,默认也没有HMR功能(不用做HMR功能)需要在entry入口中引入html文件(entry:[‘./src/demo/js/index.js’,’./src/demo/index.html’])
js
- js的HMR功能,默认没有HMR功能,只能处理非入口文件的js文件
- 启用 webpack 内置的 HMR插件后, module.hot 接口就会暴露在 index.js 中, 接下来需要在 index.js 中配置告诉 webpack 接受HMR的模块(通过代码
module.hot.accept
)
- 如上图所示当一个 js 文件发生变化时,所有的 js 都会去执行,如果想要去实现只更新我们自己修改了的 js 文件需要在入口文件中通过代码指定文件示例如下
1 | if (module.hot) { |
修改 print.js 中将 【111】改为 【33333】 后并未执行 index.js 中的打印语句(打包 css样式的 js 文件这句话),只执行了module.hot.accept的回调函数
修改 print.js后并未再次打印这句话,也就证明热加载只加载了 print.js
HMR 中只监听了 print.js
服务器检测到了 print.js 的代码变化后需要执行的 module.hot.accept 的回调函数
线上环境(去除死代码)
该内容是针对线上环境
且指的是 js css 这类文件- html文件 不需要,因为如果不需要的 html 我们会注释掉,然后打包的时候会去压缩注释掉的内容,但是 js css 这些可能会留着暂时不注释,可能以后会用,那么我们就期望打包的时候 没有引用的 js css 这些东西不打包进去(比如去网上 copy 了一个一万行的js 但是我们只用了其中的一部分,但是又不敢乱删除,以前的方法就会把所有的一万行打包进去,优化了的话它自动就会去找到这一万行代码中我们使用到的 js 打包进去)
- 或者说引入的第三方的BootStrap jQuery 我们也期望只把我们项目使用到的js css 打包进去多余的就不要
js
- Webpack通过 tree-shaking 去掉了实际上并没有使用的js代码来减少包的大小
- tree-shaking 是 webpack 自带的功能不需要下载其它的包(tree-shaking:树摇,摇晃树子把黄了的叶子摇下来不要)
- 前提条件:
必须使用es6模块化
开启production环境(mode中指定)
css
下载插件
1 | # npm 安装(开发环境) |
webpack.config.js 配置
- plugins下新增以下内容 四个引入 const 一个 new
1 | //const {resolve, join} = require('path'); |