一. 认识webpack
工具
1. 内置模块path
path
模块用于对路径和文件进行处理,提供了很多好用的方法- 我们知道在
Mac OS
、Linux
和`window上的路径时不一样的window
上会使用\
或者\\
来作为文件路径的分隔符,当然目前也支持/
- 在
Mac OS
、Linux
的Unix
操作系统上使用/
来作为文件路径的分隔符
- 那么如果我们在
window
上使用\
来作为分隔符开发了一个应用程序,要部署到Linux
上面应该怎么办呢?- 显示路径会出现一些问题
- 所以为了屏蔽他们之间的差异,在开发中对于路径的操作我们可以使用
path
模块,node
会根据操作系统自动处理对应的路径
- 可移植操作系统接口(英语:
Portable Operating System Interface
,缩写为POSIX
)Linux
和Mac OS
都实现了POSIX
接口Window
部分电脑实现了POSIX
接口
2. path常见的API
从路径中获取信息
path.dirname(filepath)
:获取文件的父文件夹__dirname
: 当前模块的所在目录名,全局可使用,但实际并不是全局对象
path.basename(filepath)
:获取文件名path.extname(filepath)
:获取文件扩展名__filename
: 当前模块的文件名
jsconst path = require('path') const filepath = 'C://abc/cba/nba.txt' console.log(path.dirname(filepath)) // C://abc/cba console.log(path.basename(filepath)) // nba.txt console.log(path.extname(filepath)) // .txt
路径的拼接:
path.join(...paths)
- 如果我们希望将多个路径进行拼接,但是不同的操作系统可能使用的是不同的分隔符
- 这个时候我们可以使用
path.join
函数
jsconst path = require('path') const path1 = "/abc/cba" const path2 = "../aaa/bbb/ccc.txt" const path3 = "./ddd/eee.js" console.log(path.join(path1, path2)) // \abc\aaa\bbb\ccc.txt console.log(path.join(path1, path3)) // \abc\cba\ddd\eee.js console.log(path.join(path2, path3)) // ..\aaa\bbb\ccc.txt\ddd\eee.js console.log(path.join(path3, path2)) // ddd\aaa\bbb\ccc.txt
拼接绝对路径:
path.resolve()
path.resolve
方法会把一个路径或路径片段的序列解析为一个绝对路径- 给定的路径的序列是从右往左被处理的,后面每个
path
被依次解析,直到构造完成一个绝对路径,\
绝对路径,指当前文件所作的根目录 - 如果在处理完所有给定
path
的段之后,还没有生成绝对路径,则使用当前工作目录 - 生成的路径被规范化并删除尾部斜杠,零长度
path
段被忽略 - 如果没有
path
传递段,path.resolve()
将返回当前工作目录的绝对路径(当前模块所在的目录名)
jsconst path = require('path') const path1 = "/abc/cba" const path2 = "../aaa/bbb/ccc.txt" const path3 = "./ddd/eee.js" // 注意:当前文件所在目录:C:\Users\23634\Desktop\learn\ console.log(path.resolve(path1, path2, path3)) // C:\abc\aaa\bbb\ccc.txt\ddd\eee.js console.log(path.resolve(path3)) // C:\Users\23634\Desktop\learn\ddd\eee.js console.log(path.resolve('./hello/', '')) // C:\Users\23634\Desktop\learn\hello console.log(path.resolve()) // C:\Users\23634\Desktop\learn
3.在webpack
中的使用
在
webpack
中获取路径或者起别名的地方也可以使用
4.认识webpack
- 事实上随着前端的快速发展,目前前端的开发已经变的越来越复杂了:
- 比如开发过程中我们需要通过模块化的方式来开发
- 比如也会使用一些高级的特性来加快我们的开发效率或者安全性,比如通过
ES6+
、TypeScript
开发脚本逻辑,通过sass
、less
等方式来编写css
样式代码 - 比如开发过程中,我们还希望实时的监听文件的变化来并且反映到浏览器上,提高开发的效率
- 比如开发完成后我们还需要将代码进行压缩、合并以及其他相关的优化等…
- 但是对于很多的前端开发者来说,并不需要思考这些问题,日常的开发中根本就没有面临这些问题:
- 这是因为目前前端开发我们通常都会直接使用三大框架来开发:
Vue
、React
、Angular
- 但是事实上,这三大框架的创建过程我们都是借助于脚手架(
CLI
)的 - 事实上
Vue-CLI
、create-react-app
、Angular-CLI
都是基于webpack
来帮助我们支持模块化、less
、TypeScript
、打包优化等的
- 这是因为目前前端开发我们通常都会直接使用三大框架来开发:
5.脚手架依赖webpack
- 事实上我们上面提到的所有脚手架都是依赖于
webpack
的:

6.Webpack
到底是什么呢?
我们先来看一下官方的解释:
webpack
是一个静态的模块化打包工具,为现代的JavaScript
应用程序我们来对上面的解释进行拆解:
- 打包
bundler
:webpack
可以将帮助我们进行打包,所以它是一个打包工具 - 静态的
static
:这样表述的原因是我们最终可以将代码打包成最终的静态资源(部署到静态服务器) - 模块化
module
:webpack
默认支持各种模块化开发,ES Module
、CommonJS
、AMD
等 - 现代的
modern
:我们前端说过,正是因为现代前端开发面临各种各样的问题,才催生了webpack
的出现和发展
- 打包
7.Vue
项目加载的文件有哪些呢?
JavaScript
的打包:- 将
ES6
转换成ES5
的语法 TypeScript
的处理,将其转换成JavaScript
- 将
CSS
的处理:CSS
文件模块的加载、提取Less
、Sass
等预处理器的处理
- 资源文件
img
、font
:- 图片
img
文件的加载 - 字体
font
文件的加载
- 图片
HTML
资源的处理:- 打包
HTML
资源文件
- 打包
- 处理
vue
项目的SFC
文件.vue
文件
8.Webpack
的使用前提
webpack
的官方文档是https://webpack.js.org/
webpack
的中文官方文档是https://webpack.docschina.org/
DOCUMENTATION
:文档详情,也是我们最关注的
Webpack
的运行是依赖Node
环境的,所以我们电脑上必须有Node
环境- 所以我们需要先安装
Node.js
,并且同时会安装npm
,也可以使用nvm
或者n
来管理Node
版本
- 所以我们需要先安装
9.Webpack
的安装
webpack
的安装目前分为两个:webpack
、webpack-cli
(webpack4
开始,安装webpack
需要同时安装webpack-cli
,此工具用于在命令行中运行webpack
)那么它们是什么关系呢?
- 执行
webpack
命令,会执行node_modules
下的.bin
目录下的webpack
webpack
在执行时是依赖webpack-cli
的,如果没有安装就会报错webpack-cli
是在命令行里使用webpack
必须要用的东西,因为其作用是能识别命令行- 而
webpack-cli
中代码执行时,才是真正利用webpack
进行编译和打包的过程 - 所以在安装
webpack
时,我们需要同时安装webpack-cli
(第三方的脚手架事实上是没有使用webpack-cli
的,而是类似于自己的vue-service-cli
的东西)
- 执行
二.webpack
基本打包
1. Webpack的默认打包(重点)
我们可以通过
webpack
进行打包,之后运行打包之后的代码在目录下直接执行
webpack
命令bashnpx webpack # 或 webpack
生成一个
dist
文件夹,里面存放一个main.js
的文件,就是我们打包之后的文件:- 这个文件中的代码被压缩和丑化了
- 另外我们发现代码中依然存在
ES6
的语法,比如箭头函数、const
等,这是因为默认情况下webpack
并不清楚我们打包后的文件是否需要转成ES5
之前的语法,后续我们需要通过babel
来进行转换和设置
我们发现是可以正常进行打包的,但是有一个问题,
webpack
是如何确定我们的入口的呢?事实上,当我们运行
webpack
时,webpack
默认会查找当前目录下的src/index.js
作为入口所以,如果当前项目中没有存在
src/index.js
文件,那么会报错导入时如果省略后缀名,
webpack
本身也会帮我们添加文件后缀名当然,我们也可以通过
cli
参数中来指定入口和出口bash# --entry 入口地址 # --output-path 打包文件所在文件夹路径 # --output-filename 打包文件名称 npx webpack --entry ./src/main.js --output-path ./build --output-filename aaa.js
--output-path
:配置打包后的文件夹路径--output-filename
:配置打包后的文件夹下面的源文件名称
也可以选择在
webpack
配置文件中配置jsconst path = require('path') // const curDir = path.resolve() // console.log(curDir + '\\bundle') module.exports = { entry: './src/main.js', output: { filename: 'aaa.js', // path: curDir + '\\bundle' // path: path.resolve('./bundle') path: path.resolve(__dirname, './bundle') // 必须是绝对路径 } }
webpack
的配置文件webpack.config.js
文件名是固定的,而webpack
是基于node
运行的,跑在node
的环境下,所以这个模块文件只能使用node
的CommonJS
的模块化,不能使用别的模块化执行
npx webpack
,默认会去当前目录下寻找配置文件webpack.config.js
如果需要修改指定配置文件名,使用
npx webpack --config wk.config.js
,或者package.json
文件中配置scripts
命令
2.创建局部的webpack
前面我们直接执行
webpack
命令使用的是全局的webpack
,如果希望使用局部的可以按照下面的步骤来操作第一步:创建
package.json
文件,用于管理项目的信息、库依赖等jsnpm init -y // 自动生成默认配置信息 npm init // 手动设置配置信息
第二步:安装局部的
webpack
(webpack4.x开始,这两个都需要安装)bashnpm i webpack webpack-cli -D // webpack属于开发依赖
第三步:使用局部的
webpack
bash# 一般包都是需要使用 npx + 包 命令来搭配使用的,正常是不会去当前目录中的子目录中查找node_modules文件中对应的包 npx webpack # webpack比较特殊,可以省略npx,会去当前目录的子目录中查找node_modules文件中对应的包 webpack
第四步:在
package.json
中创建scripts
脚本,执行脚本打包即可js"scirpt": { "build": "webpack" // npm run build }
三. webpack
配置文件
1.webpack.config.js配置文件
- 在通常情况下,
webpack
需要打包的项目是非常复杂的,并且我们需要一系列的配置来满足要求,默认配置必然是不可以的 - 我们可以在根目录下创建一个
webpack.config.js
文件,来作为webpack
的配置文件:

2.指定配置文件
- 但是如果我们的配置文件并不是
webpack.config.js
的名字,而是其他的名字呢?- 比如我们将
webpack.config.js
修改成了wk.config.js
- 这个时候我们可以通过
--config
来指定对应的配置文件
- 比如我们将
- 但是每次这样执行命令来对源码进行编译,会非常繁琐,所以我们可以在
package.json
中增加一个新的脚本:

四. 编写和打包CSS
文件
1.Webpack
的依赖图
webpack
到底是如何对我们的项目进行打包的呢?- 事实上
webpack
在处理应用程序时,它会根据命令或者配置文件找到入口文件 - 从入口开始,会生成一个 依赖关系图,这个依赖关系图会包含应用程序中所需的所有模块(比如
js
文件、css
文件、图片、字体等) - 然后遍历图结构,打包一个个模块(根据文件的不同使用不同的
loader
来解析,webpack
默认只会对js
文件进行打包,内置功能)
- 事实上
2.编写案例代码
我们创建一个
component.js
- 通过
JavaScript
创建了一个元素,并且希望给它设置一些样式
- 通过
3.css-loader的使用
上面的错误信息告诉我们需要一个合适的
loader
来处理这个css
文件,但是loader
是什么呢?loader
可以用于对模块的源代码进行转换- 我们可以将
css
文件也看成是一个模块,我们是通过import
来加载这个模块的- 如果有一个模块只是为了引入,而没有导出任何的东西,这样就表示该模块加入到依赖图中了,这里是可以不写
from
的
- 如果有一个模块只是为了引入,而没有导出任何的东西,这样就表示该模块加入到依赖图中了,这里是可以不写
- 在加载这个模块时,
webpack
其实并不知道如何对其进行加载,我们必须制定对应的loader
来完成这个功能
那么我们需要一个什么样的
loader
呢?- 对于加载
css
文件来说,我们需要一个可以读取css
文件的loader
- 这个
loader
最常用的是css-loader
- 对于加载
css-loader
的安装:jsnpm i css-loader -D // loader打包时(开发阶段)依赖
4.css-loader的使用方案
如何使用这个
loader
来加载css
文件呢?有三种方式:- 内联方式
CLI
方式(webpack5
中不再使用)- 配置方式
内联方式:内联方式使用较少,因为不方便管理
在引入的样式前加上使用的
loader
,并且使用!分割jsimport "css-loader!./css/style.css"
CLI
方式- 在
webpack5
的文档中已经没有了--module-bind
- 实际应用中也比较少使用,因为不方便管理
- 在
5.loader
配置方式
- 配置方式表示的意思是在我们的
webpack.config.js
文件中写明配置信息:module.rules
中允许我们配置多个loader
(因为我们也会继续使用其他的loader
,来完成其他文件的加载)- 这种方式可以更好的表示
loader
的配置,也方便后期的维护,同时也让你对各个Loader
有一个全局的概览
module.rules
的配置如下:rules
属性对应的值是一个数组:[Rule]
- 数组中存放的是一个个的
Rule
,Rule
是一个对象,对象中可以设置多个属性:test
属性:用于对resource
(资源/文件)进行匹配的,通常会设置成正则表达式use
属性:对应的值时一个数组:[UseEntry]
UseEntry
是一个对象,可以通过对象的属性来设置一些其他属性loader
:必须有一个loader
属性,对应的值是一个字符串options
:可选的属性,值是一个字符串或者对象,值会被传入到loader
中query
:目前已经使用options
来替代
- 传递字符串(如:
use: [ 'style-loader' ]
)是loader
属性的简写方式(如:use: [ { loader: 'style-loader'} ])
loader
属性:Rule.use: [ { loader } ]
的简写
6.Loader
的配置代码
const path = require('path')
module.exports = {
entry: './src/main.js',
output: {
filename: 'aaa.js',
path: path.resolve(__dirname, './bundle')
},
module: {
rules: [
{
test: /\.css$/, // 告诉webpack匹配什么文件
use: [ // use多个loader使用顺序:从下往上 从右往左的
{ loader: 'style-loader' },
{ loader: 'css-loader' }
],
// 简写一: 如果loader只有一个,可以省略use,直接写在外面
loader: "css-loader",
// 简写二: 多个loader不需要其他属性时, 可以直接写loader字符串形式
use: [
"style-loader",
"css-loader"
]
}
]
}
}
7.认识style-loader
我们已经可以通过
css-loader
来加载css
文件了- 但是你会发现这个css在我们的代码中并没有生效(页面没有效果)
这是为什么呢?
- 因为**
css-loader
只是负责将.css
文件进行解析,并不会将解析之后的css
插入到页面中** - 如果我们希望再完成插入
style
的操作,那么我们还需要另外一个loader
,就是style-loader
- 因为**
安装
style-loader
:jsnpm i style-loader -D // loader打包时(开发阶段)依赖
8.配置style-loader
那么我们应该如何使用
style-loader
:- 在配置文件中,添加
style-loader
- 注意:因为**
loader
的执行顺序是从右向左(或者说从下到上,或者说从后到前的)**,所以我们需要将style-loader
写到css-loader
的前面
jsuse: [ // use多个loader使用顺序:从下往上 从右往左的 从后往前 { loader: 'style-loader' }, { loader: 'css-loader' } ]
- 在配置文件中,添加
重新执行编译
npm run build
,可以发现打包后的css
已经生效了:- 当前目前我们的
css
是通过页内样式的方式添加进来的 - 后续我们也会讲如何将
css
抽取到单独的文件中,并且进行压缩等操作
- 当前目前我们的
五. 编写和打包less
文件
1.如何处理less
文件?
在我们开发中,我们可能会使用
less
、sass
、stylus
等预处理器来编写cs
样式,效率会更高那么,如何可以让我们的环境支持这些预处理器呢?
- 首先我们需要确定,
less
、sass
等编写的css
需要通过工具转换成普通的css
- 首先我们需要确定,
比如我们编写如下的
less
样式:less@fontSize: 30px; @fontWeight: 700; .content { font-size: @fontSize; font-weight: @fontWeight; }
2.Less
工具处理
我们可以使用
less
工具来完成它的编译转换:jsnpm i less -D
执行如下命令:
jsnpx lessc ./src/css/title.less title css
3.less-loader
处理
但是在项目中我们会编写大量的
css
,它们如何可以自动转换呢?这个时候我们就可以使用
less-loader
,来自动使用less
工具转换less
到css
less-loader
依赖less
,所以less
的包也会被安装
jsnpm i less-loader -D
配置
webpack.config.js
js{ test: /\.less$/, use: [ "style-loader", "css-loader", "less-loader" ] // less-loader先转换成css,然后css-loader处理... }
六.postcss
工具处理CSS
1.认识PostCSS
工具
use-select:none;
让用户无法选中该元素,但是这个属性有一定兼容性问题,所以需要用到postcss
来帮助我们判断属性是否需要添加浏览器前缀来做兼容- 什么是
PostCSS
呢?PostCSS
是一个通过JavaScript
来转换样式的工具- 这个工具可以帮助我们进行一些
CSS
的转换和适配,比如自动添加浏览器前缀、css
样式的重置 - 但是实现这些功能,我们需要借助于
PostCSS
对应的插件
- 如何使用
PostCSS
呢?主要就是两个步骤:- 第一步:查找
PostCSS
在构建工具中的扩展,比如webpack
中的postcss-loader
- 第二步:选择可以添加你需要的
PostCSS
相关的插件
- 第一步:查找
2.postcss-loader
我们可以借助于构建工具:
在
webpack
中使用postcss
就是使用postcss-loader
来处理的我们来安装
postcss-loader
:jsnpm i postcss-loader -D // 开发打包时依赖
我们修改加载
css
的loader
:(配置文件已经过多,给出一部分了)- 注意:因为**
postcss
需要有对应的插件才会起效果**,所以我们需要配置它的plugin
- 注意:因为**
3.单独的postcss
配置文件
因为我们需要添加前缀,所以要安装
autoprefixer
:jsnpm i autoprefixer -D
我们可以将这些配置信息放到一个单独的文件中进行管理:
在项目的根目录下创建
postcss.config.js
jsmodule.exports = { plugins: [ 'autoprefixer' // 在使用某些postcss插件时,也可以直接传入字符串 // require('autoprefixer') ] }
4.postcss-preset-env
事实上,在配置
postcss-loader
时,我们配置插件并不需要使用autoprefixer
我们可以使用另外一个插件:
postcss-preset-env
postcss-preset-env
也是一个postcss
的插件- 它可以帮助我们将一些现代的
CSS
特性,转成大多数浏览器认识的CSS
,并且会根据目标浏览器或者运行时环境添加所需的polyfill
- 也包括会自动帮助我们添加
autoprefixer
(所以相当于已经内置了autoprefixer
)
首先,我们需要安装
postcss-preset-env
jsnpm i postcss-preset-env -D
之后,我们直接修改掉之前的
autoprefixer
即可:jsmodule.exports = { plugins: [ // 'autoprefixer' // 在使用某些postcss插件时,也可以直接传入字符串 'postcss-preset-env' // 可以帮助十六进制颜色转换为rgba ] }
postcss-loader
和less-loader
没有前后顺序要求