webpack构建工具的学习
什么是webpack
- 是一个模块打包工具
- webpack将前端的所有资源文件(js/json/css/img/less…)都看做模块,来进行处理
- 会根据模块的依赖关系进行分析,生成对应的资源
- 原生的webpack只可以完成
js/json
的打包编译,而转换什么的需要其他插件进行完成,比如说es6转es5,箭头函数转换,都需要依赖其他loader或者插件(plugins)
五个核心概念
- 入口(entry): 告诉webpack应该使用哪个模块,作为构建内部依赖图的开始,比如vue中我们经常在一个文件夹当中建立
index.js
或者main.js
作为入口文件 - 出口(output): 在哪里输出文件,以及如何命名这些文件
- 比如经常可以看到有些目录有
dist
build
等这些,里面只有js,css,img等一些文件,就是打包输出后的东西
- 比如经常可以看到有些目录有
- loader:
- 我们需要注意,原生webpack只支持解析
js
和json
,其他的需要安装对应的loader,比如处理less就需要less-loader
- 本身是一个函数,接收源文件作为参数,返回转换结果
- loader异步以
xxx-loader
方式命名,xxx
代表了这个loader要做的转换功能
- 我们需要注意,原生webpack只支持解析
- 插件(plugins):
- 执行访问更广的任务,从打包到优化都可以实现
- 完成一些loader不能完成的功能
- 模式(model)
- 有生产模式
production
, 开发模式development
,主要区别就是是否会将代码进行压缩
- 有生产模式
安装webpack
- 当然,离不开npm,所以npm初始化就不多说了,直接
npm init -y
- 安装webpack
npm install webpack webpack-cli -g
//全局安装npm install webpack webpack-cli -D
//局部安装- 查看版本
webpack --version
- 还有,除了全局安装,记得也在项目局部也安装下,不然后面可能有莫名其妙的问题引发
处理js和json文件
目录结构如下:
代码如下:
index.js
1 | /**index.js**/ |
module1.js
1 | /** module1.js **/ |
module2.js
1 | /** module2.js **/ |
user.json
1 | /** user.json **/ |
index.html
1 | /** index.html **/ |
运行命令打包后的文件:
运行:
1 | //生产模式打包 |
输出:
注意:
- es6情况下,如果引入的是一个json文件,那么引入这个json文件的时候,这个json文件是默认暴露
1 | 相当于你在user.json写的是 |
webpack 和webpack-cli的关系
vue中有vue-cli,webpack有webpack-cli , 有时候我就在想,这个没有cli和有cli有什么区别呢?不带
cli
的可以理解为一个工具,是死的,就如果程序一样,不双击运行永远不会运行,而cli
就可以帮助我们去使用这个工具,比如是帮助我们使用vue
,帮助我们去使用webpack
等cli说通俗点就是cli是一个让你在命令行中使用webpack/vue一些工具的辅助程序。
webpack的使用
基本输出操作
- webpack 要编译的文件 -o 输出的文件 –mode=development或者production
- 比如
webpack ./js/index.js -o ./dist/js --mode=development
就将 js目录下的index.js
文件打包输出到dist/js目录下(开发者模式)
运行后输出
- 但是原生的webpack只支持js/json,并且不支持es6转换es5,箭头函数转换等等,这些都需要依赖loader或者插件,所以我们后面就来看看怎么使用这些loader或者插件来帮助我们完成
配置文件的使用
前置了解
- src为程序员写的源码,建立配置文件的时候不要建立在src当中!
- 为什么需要,每一次输入这么一长段的代码很不方便,我们不可能每次都敲这个命令来完成打包吧?
webpack ./js/index.js -o ./dist/js
,所以我们可以使用配置文件来帮助我们完成 - 还有就是,webpack需要对文件进行操作,所以依赖于nodejs运行,所以肯定是CMJ模块化规范!,所以你会看到,一会儿在webpack配置文件中使用
require
引入模块,一会在src目录
下使用import
引入模块的操作,一个是CommonJs模块,一个是es6模块规范~ - 还有就是基本上要用const来接收引入的模块,是防止有人再次定义了被覆盖而导致的错误,这种错误很难找到!
- 开发依赖和生产依赖
- 开发依赖,帮助程序员加工处理代码的,比如说
less
- 生产依赖,帮助程序员完成某些功能的代码,比如说
lodash
,jQuery
之类的
- 开发依赖,帮助程序员加工处理代码的,比如说
建立配置文件并使用
在src外面建立一个文件名字叫 webpack.config.js 的文件,官网详细配置地址
webpack.config.js
配置代码
1 | /** |
- 这样子我们就不用输出很长的一段代码
- 只需要输入
webpack
就可,会自动寻找当前运行目录下的webpack.config.js
配置文件
解析css文件 css-loader和style-loader
- 由于webpack不能解析css文件,只能解析
js或者是json文件
,但是我们想解析css,那么我们需要安装解析css的插件 -css-loader
没有安装css-loader
之前,会提示You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
- 安装插件
npm install css-loader style-loader -D
1.首先在主入口当中添加引入css import "./css/index.css"
1 | import "../css/index.css";//引入css文件 |
2.然后配置webpack.config.js
use
当中的顺序是从右到左的!style-loader
作用: 将css-loader解析的内容处理,生成style
并挂载到head
上css-loader
作用: css-loader帮我们解析css文件里面的css代码比如这是在只使用了
css-loader
的情况下输出接收到的内容,可以看到,css-loader
帮我们读取了css的内容
1 | //loader的配置项 |
3.就可以直接使用了可以运行webpack命令来看看
解析less文件 less-loader
- 安装插件
npm install less-loader -D
1.首先在主入口当中添加引入less import "./css/index.css"
1 | import "../css/index.less";//引入less文件 |
2.然后修改下webpack.config.js
1 | module: { |
打包html文件 html-webpack-plugin(插件)
- 我们之前的打包,只将
js,less,css
打包到了dist
目录下,html
这个老大哥还留着在原来的地方,这次我们打包html文件 - 安装
npm install html-webpack-plugin -D
- 其他
1.首先配置下webpack.config.js
文件
- 注意这里是插件的使用,所以新增加了一个配置项
plugins
- 注意有模板和没有模板的区别!
1 | var HtmlWebpackPlugin = require('html-webpack-plugin'); |
html-loader和html-webpack-plugin冲突导致的报错
前置
之前学习的时候是webpack4为基本,现在到webpack5了,有些问题了,当我们即使用html-webpack-plugin
又使用html-loader
的时候,就会发生这个报错(至少在我现在的版本的情况下会报错!)
- “html-loader”: “^3.1.0”,
- “html-webpack-plugin”: “^5.5.0”
- “webpack”: “^5.72.1”,
- “webpack-cli”: “^4.9.2”
1 | ERROR in Error: Child compilation failed: |
冲突报错解决
- 原来的
index.html
改名为index.ejs
然后webpack.config.js修改下即可
1 | //loader的配置项 |
- 如果想在ejs引入图片文件并实现后期打包的话,就需要使用
<%= require('图片位置') %>
1 | <body> |
webpack5使用asset module
- 在webpack5之前,我们url-loader、file-loader、raw-loader来完成操作
- 现在webpack5自带的asset-module就可以实现以前的功能
- 之前通过
use
来使用这些loader,asset module
通过type
来完成 - 官网(英文)的介绍
功能替换
- asset/resource
- 将资源分割为单独的文件,并导出url,就是之前的 file-loader的功能
- 官网关于此的api
- asset/inline
- 将资源导出为dataURL(url(data:))的形式,之前的 url-loader的功能
- asset/source
- 将资源导出为源码(source code). 之前的 raw-loader 功能
- asset
- 自动选择导出为单独文件或者 dataURL形式(默认为8KB)
打包样式中的文件-方法1-asset/resource
类似于file-loader
相当于只是对文件进行了重命名,不具有转base64功能
设置type为asset/resource
1 | module: { |
打包样式中的文件-方法2-asste
类似于url-loader
,可以设置图片小于设定的大小后进行base64编码
设置type为asset
1 | module: { |
使用file-loader url-loader的时候会出现多出来一部分
- 将type设置为
javascript/auto
1 | { |
处理html文件的图片 html-loader
不处理html文件图片时候打包后的效果
发现并没有将html当中的图片进行打包
处理步骤和效果
1.首先安装loader: npm install html-loader -D
2.然后配置webpack.config.js
1 | //loader的配置项 |
3.然后就可以测试下是否正常了
打包其他资源(比如说字体图标,mp4等资源)
- 有时候我们使用了阿里图标字体库,就必须要使用到
ttf
字体资源,所以我们就要考虑这些资源的打包
webpack5的使用 asset/resource
1 | module: { |
注意
使用这个asset/resource的时候,不知道是不是版本问题还是我配置的问题,老是出现__webpack_public_path__ = __webpack_base_uri__ = htmlWebpackPluginPublicPath;
这个没有用的文件和文件内容,很奇怪,,,,,,
之前用webpack4的时候就没有,可能是因为是我写这个的时候使用的都是asset
或者asset/resource
来处理,而没有使用file-loader
或 url-loader
来处理的原因吧
webpack使用webpack-dev-server
- 安装,最好是全局和局部都安装!!!! (带指令集的最好全局安装)
npm install webpack-dev-server -D
npm install webpack-dev-server -g
1.首先 在配置对象当中添加 devServer
配置选项
- 热更新(热模替换): 当内容发生变化的时候,只重新编译变化了的部分,而不会引发整体的编译更新
- 不开启热更新的话,当内容发生变化的时候,就会全部重新编译全部更新
webpack.config.js
1 | module.exports = { |
2.使用
后面就可以了,要使用这个webpack-dev-server
,就只需要把webpack
改为webpack-dev-server
即可
使用webpack-dev-server命名
生产环境
- 之前如果已经配置完成了,那么开发环境就可以用了,开发我们不讲究什么兼容性啊,什么压缩啊,而生产环境就需要
- 所以我们可以准备二套webpack的配置文件,一套用于生产,一套用于开发
- 将之前写的配置文件配置为生产环境
准备二套配置文件
- 建立config文件夹,里面包括二个文件
webpack.dev.js
文件 用于开发环境webpack.prod.js
文件 用于生产环境
wepack.dev.js文件
webpack4的时候(参考下)
1 | const path = require("path"); |
webpack5的时候(这里以这套为例)
1 | /** |
使用package.json当中运行脚本 这样子就不用每次都输入很长一段代码了
在webpack中,当运行webpack的时候,可以指明配置文件在哪里,使用
--config
就可以指明,否者的话就去当前运行目录下寻找是否有webpack.config.js
文件!- 比如
webpack --config ./config/webpack.dev.js
就指明webpack的配置文件在哪里
- 比如
在package.json当中添加
script
配置项
1 | "scripts": { |
后期即可通过npm run start
来进行start当中的命令,通过npm run build
来运行build命令!
提醒下:~如果script当中是以start
的key值,那么可以简写就可以运行命令,直接npm start
就可以,而其他的不可以!
提取css为单独的文件 mini-css-extract-plugin
webpack4测试可以css可以结合less使用,webpack5莫名其妙less无法和css结合…我这有问题!!!!!!!!!!!!
webpack4测试可以css可以结合less使用,webpack5莫名其妙less无法和css结合…我这有问题!!!!!!!!!!!!
webpack4测试可以css可以结合less使用,webpack5莫名其妙less无法和css结合…我这有问题!!!!!!!!!!!!
- 之前的css,都是包含在js了,通过style-loader css-loader来进行解析使用,但是我们后期打包想分离,css就是css,js就是js
- 就需要使用插件
mini-css-extract-plugin
- 复习下 style-loader的用处, 就是将js当中的css创建生成标签 ,然后插入到
head
中 - 关于此插件的api
1.安装
1 | npm install --save-dev mini-css-extract-plugin |
2.配置loader
1 | //引入mini-css-extract-plugin,用于提取css为单独文件 |
3.配置插件
1 | module.exports = { |
3.使用 在配置了package.json的情况下,直接npm run build
即可
css兼容性处理
- 注意,修改下打包的配置项目为开发模式 mode = production ,否者不会处理兼容性问题(因为开发模式要什么兼容性,生产环境才要兼容性)
1.安装loader
1 | npm install postcss postcss-loader postcss-preset-env -D |
**2.定义通用配置 **因为css和less样式文件都要进行兼容性处理,所以我们定义好一个通用的配置:~ (相当于告诉这个工具,要兼容到哪些浏览器) ~!!!
1 | // 配置一个styleLoader,处理less和css时都会使用 |
3.修改css-loader和less-loader配置
1 | { |
4.配置package.json,在其中追加browserslist配置,通过配置加载指定的css兼容性样式
browserslist 是一套描述产品目标运行环境的工具,它被广泛用在各种涉及浏览器/移动端的兼容性支持工具中
若出现版本不兼容,或配置不正确的错误,那么需更换依赖包版本: npm i less-loader@5 postcss-loader@3
代码: vue脚手架用的就是这一套~
1 | //注意,package.json不可以有注释,记得删除! |
如图配置完成在package.json中
5.然后重新运行 npm run build 即可
可以看到,这里的display:flex
自动添加了前置,就是做了下兼容性处理
js语法转换
- 概述:将浏览器不能识别的新语法转换成原来识别的旧语法,做浏览器兼容性处理,比如说箭头函数
1.安装loader
1 | npm install babel-loader @babel/core @babel/preset-env -D |
2.配置loader
1 | module: { |
3.就可以啦,然后直接 npm run build就可以了
如图示例转换了箭头函数
js兼容性处理
处理babel无法处理的~,比如说js语法转换无法处理 promise,而如果做了js语法兼容性处理是可以处理promise的,(注:ie11不使用兼容性处理的无法使用promise的!)
注意从 7.4 开始,就不推荐使用 @babel/polyfill 了,但是这里依旧记录下这个库的使用教程和官方推荐
babel7.4+版本的js兼容性处理
1.安装
1 | npm install babel-loader @babel/core @babel/preset-env core-js -D |
2.使用
代码:
1 | module.exports = { |
3.注意
如果出现提示To be a valid preset, its name and options should be wrapped in a pair of brackets
或者RROR in ./src/app.ts Module build failed (from ./node_modules/babel-loader/lib/index.js):Error: [BABEL] D:\develop\phpstudy_pro\WWW\tpyescriptStudy\05_snake\src\app.ts: Unknown option: .useBuiltIns. Check out https://babeljs.io/docs/en/babel-core/#options for more information about options.
可能是因为少了括号,这位老哥一语道破
我的ts结合babel
4.效果
打包后相比@babel/poplyfill库明显减少
promise语法也正常输出在ie浏览器
babel7.4以下 js兼容性处理-@babel/polyfill库的使用
**缺点:!**这个插件会将所有的兼容性代码全部引入,会导致打包后文件体积变大!!!!
1.安装
1 | npm install @babel/polyfill -D |
安装的时候会提示这些,表示@babel/polyfill
不推荐使用
1 | npm WARN deprecated @babel/polyfill@7.12.1: 🚨 This package has been deprecated in favor of separate inclusion of a polyfill and regenerator-runtime (when needed). See the @babel/polyfill docs (https://babeljs.io/docs/en/babel-polyfill) for more information. |
官网对于此的介绍: 从 7.4 开始,就不推荐使用 @babel/polyfill 了,但是这里依旧记录下这个库的使用教程
2.webpack入口文件处引入
- 比如我webpack的入口是
src\js\index.js
,那么我就在这文件夹添加import '@babel/polyfill';
// 包含ES6的高级语法的转换 就可以
3.使用
没有js兼容性处理前IE11的输出(promise测试)
使用js兼容性处理后IE11的输出(promise测试)
4.效果
测试代码
1 | setTimeout(() => { |
不过体积有点大
js语法检查
1.安装loader
1 | npm install eslint-loader eslint -D |
2.安装检查规则库
备注:eslint-config-airbnb-base定制了一套标准的、常用的js语法检查规则,推荐使用
1 | npm install eslint-config-airbnb-base eslint-plugin-import -D |
3.配置webpack
1 | module.exports = { |
4.配置package.json
注意安装语法规则库
1 | "eslintConfig": { |
5.使用
打包的时候自动运行
如图,我这里检测到的不符合语法规范的问题
压缩css(对于html,js,webpack4都已经默认压缩了)
1.安装
webpack4的时候使用这个 官网api
1 | npm install optimize-css-assets-webpack-plugin -D |
webpack5的时候使用这个 官网api
1 | npm install css-minimizer-webpack-plugin --save-dev |
2.引入插件
webpack4的时候使用这个
1 | const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); |
webpack5的时候使用这个
1 | const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); |
3.配置插件
webpack4的optimize-css-assets-webpack-plugin
配置
1 | module.exports = { |
webpack5的css-minimizer-webpack-plugin
配置
1 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); |
注意!注意!注意!注意!注意!
在webpack5中,不需要手动引入uglify插件,只需配置mode
为production
就可以压缩js代码。但是,如果用了css-minimizer-webpack-plugin
插件去压缩css文件,js的压缩就会失效,所以使用terser-webpack-plugin
插件去压缩js代码
(我这边反正就是二个一起使用是报错``,这里记录下)
我使用的时候报错记录,可能是提取css的时候遗留下来的问题吧,
1 | ERROR in main.css |
打包和运行进度条功能
1.安装
1 | npm install webpackbar -D |
2.引入插件
1 | const WebpackBar = require('webpackbar'); |
3.配置添加到webpack配置文件
1 | module.exports = { |
4.然后就有效果了
webpack当中use的几种形式
use为一个数组
里面可以为一个个的字符串,比如
use:["style-loader","css-loader"]
也可以对象掺杂着字符串,比如
use:[{...},"css-loader"]
也可以全部为对象,比如
use:[{...},{...},{...}]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17module.exports = {
module:{
rules:[
//分割下 use全部为对象
{
test: /\.less$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "less-loader"
}]
},
]
}
}
use为一个对象,代表使用这一个loader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18module: {
rules: [
//use为一个对象的情况
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env', { targets: "defaults" }]
]
}
}
},
//其他loader
]
}
webpack配置对象当中的resolve
resolve.extensions
使用 import 引入其他模块时,如果不加上后缀扩展名(extension)且找不到对应的文件时,webpack 就会尝试根据 extensions 数组,依次加上扩展名看看能不能匹配到一个文件,直到找到为止。如果找不到则会报错。
默认值为:
['.js','.json','wasm']
功能就是,不加后缀名的情况下,依次匹配,直到匹配所有的还匹配不到就报错
所以你经常可以看到一些人导入模块不添加后缀名,直接 import xxx from “./abc/a”,就是resolve.extensions起到的作用!
如图,当导入模块import * as all from "./food"
的时候,发现模块不存在,会依次去寻找,然后后缀都匹配完了还是找不到就报错
推荐几款好用的npm
rimraf —- 快速删除node_modules文件夹
1.安装
1 | npm install rimraf -g |
2.使用
在所属文件夹下使用cmd指令下,进入所需删除的node_modules文件夹的位置,再输入指令
1 | rimraf node_modules |
clena-webpack-plugin — 每次打包删除dist目录
1.安装
1 | npm install --save-dev clean-webpack-plugin |
2.使用
1 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); |
webpack箭头函数导致第一行xx位置报错
- 解决 : 添加 environment:{ arrowFunction:false }
示例:
1 | module.exports = { |
设置前编译
设置后编译
loader和plugin作用和区别
loader
: 是文件加载器,可以加载资源文件,并对这些文件进行一些处理,比如:编译,压缩等,plugin
:webpack在运行的生命周期会广播出许多事件,plugin可以监听这些事件,在合适的时机中通过webpack提供的api改变输出结果
区别:
- loader是将A文件进行编译形成B文件,这里操作的是文件,A.less => A.css
- plugin是用于在webpack打包编译过程里,在对应的事件节点里执行自定义操作,比如资源管理、bundle文件优化等操作