目录
引入
随着前端的快速发展,目前前端的开发已经变的越来越复杂了:
-
比如开发过程中我们需要通过模块化的方式来开发
-
比如通过
ES6+、TypeScript
开发脚本逻辑,通过sass、 less
等方式来编写css
样式代码 -
比如开发完成后我们还需要将代码进行压缩、合并以及其他相关的优化
但是对于很多的前端开发者来说,并不需要思考这些问题,日常的开发中没有面临这些问题
-
是因为目前前端开发我们通常都会直接使用三大框架来开发:
Vue、React、Angular
-
但是事实上,这三大框架的创建过程我们都是借助于脚手架(
CLI
)的 -
Vue-CLI、create-react-app、Angular-CLI
都是基于webpack
来帮助我们支持模块化、less
、TypeScript
、打包优化的 -
但
Webpack
作为前端资源构建工具+静态模块打包器,是面试中的重中之重,我们有学习的必要
定义
webpack
的官方文档是 https://webpack.js.org/ , webpack
的中文官方文档是https://webpack.docschina.org/ , DOCUMENTATION
:文档详情是有助于理解的
webpack
是一个静态的模块化打包工具,为现代的JavaScript
应用程序
-
打包
bundler
:webpack
可以将帮助我们进行打包,所以它是一个打包工具 -
静态的
static
:最终可以将代码打包成最终的静态资源(部署到静态服务器) -
模块化
module
:webpack
默认支持各种模块化开发,ES Module、CommonJS、AMD
等 -
现代的
modern
:正是因为现代前端开发面临各种各样的问题,才催生了webpack
的出现和发展
安装和使用
Webpack
的运行是依赖Node
环境的 ,所以电脑上必须有Node
环境,再安装webpack
-
先安装
Node.js
,同时会安装npm
,Node
官方网站:https://nodejs.org/ -
webpack
的安装目前分为两个:webpack、webpack-cli
:-
npm install webpack webpack-cli --g
: 全局安装 -
npm install webpack webpack-cli --D
: 局部安装 -
webpack
和webpack-cli
什么关系呐?
-
执行
webpack
命令,会执行node_modules
下的.bin
目录下的webpack
-
webpack
在执行时是依赖webpack-cli
的,如果没有安装就会报错 -
因为Webpack-cli是Webpack的命令行接口 ,它提供了许多有用的命令来帮助开发者管理
Webpack
项目 -
Webpack-cli
可以理解成Webpack
的'管家',它负责接收并解析命令行参数 -
webpack-cli
解析完命令行时,它调用相应的Webpack
插件或功能来执行任务 ,才是真正利用webpack
进行编译和打包的过程 -
所以在安装
webpack
时,需要同时安装webpack-cli
-
第三方的脚手架事实上是没有使用
webpack-cli
的 ,而是类似于自己的vue-service-cli
的东西
-
-
-
前面安装完就可以在项目使用
webpack
了:-
使用
npm init
创建package.json
文件,用于管理项目的信息、库依赖等 -
使用
npm install webpack webpack-cli -D
安装局部的webpack
-
若全局也安装了
webpack
要使用npx webpack
命令打包 ,全局没安装使用webpack
命令 -
也可以在
package.json
中创建"scripts": {"build": "webpack"}
脚本 ,使用npm run build
执行脚本打包
-
-
打包会发生什么?
-
当运行
webpack
命令时,webpack
会查找当前目录下的src/index.js
作为入口,如果没有此文件就报错 -
从入口开始,会生成一个依赖关系图 ,包含应用程序中所需的所有模块(比如
.js
文件、css
文件、图片、字体等) -
然后遍历图结构,打包一个个模块(根据文件的不同使用不同的loader来解析)
-
打包完会在目录下会生成一个
dist
文件夹,里面存放一个main.js
的文件,就是打包之后的文件 -
main.js
中的代码会被压缩和丑化 ,代码仍存在ES6
语法,比如箭头函数、const
等,webpack
不会自动转化需要我们后面配置
-
配置文件
在通常情况下,webpack
需要打包的项目是非常复杂的 ,并且我们需要一系列的配置来满足要求,默认配置必然是不可以的
命令配置
webpack
打包命令改变配置:
-
配置
webpack
打包入口文件(默认src/index.js
) :webpack --entry ./src/main.js
,会打包./src/main.js
,只有这一次打包生效 -
配置
webpack
打包出口文件(默认dist/main.js
) :webpack --output-path ./build
,会打包代码,生成bulid
文件夹 -
配置
webpack
打包后的文件名(默认dist
) :webpack --output-filename bundle.js
,打包代码并生成bundle.js
文件 -
三者可以随意混合使用 :比如
webpack --entry ./src/main.js --output-filename bundle.js
-
想要每次打包生效需要在
package.json
配置"scripts": {"build": "写想要的webpack命令"}
,然后打包执行npm run build
就可以了
单独文件
也可以在根目录下创建一个webpack.config.js
文件,来作为webpack
的配置文件:
js
// package.json
{
"name": "webpack-study",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.95.0",
"webpack-cli": "^5.1.4"
}
}
// webpack.config.js
module.exports = {
entry: "./src/index.js",
output: {
filename: "index.js",
path: "/build", // 必须是绝对路径
},
};
这时 npm run build
执行完发现,在项目目录下根本没有打包成功的文件夹,但我们在C
盘看到了打包的文件,可想而知肯定是输出path
配错了
那么我们就需要结合Node
知识进行修改path
了,修改后打包就能看到在当前根目录已经有了build
文件夹,Node
具体学习这篇文章:https://blog.csdn.net/qq_45730399/article/details/142339453?spm=1001.2014.3001.5501
js
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "index.js",
/*
__dirname: 绝对路径,获取当前⽂件所在的路径,不包括后⾯的⽂件名
path.resolve(): 将参数解析为绝对路径
下面两行代码都可以
*/
// path: path.resolve(__dirname, "./build"),
path: path.resolve(__dirname, "build"),
},
};
指定文件
如果配置文件并不是webpack.config.js
的名字 ,这个时候可以通过 webpack --config 你的配置文件名字
来打包并指定对应的配置文件
-
如果还是使用
webpack
命令打包不会报错,只是会使用默认的打包配置,配置文件无效 -
每次执行命令对源码编译非常繁琐,可以在
package.json
中配置"scripts": {"build": "webpack --config wk.config.js"}
处理样式
js
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<!-- 引入我们打包后的js文件 -->
<script src="../build/bundle.js"></script>
</body>
</html>
// index.js
import "./style.css";
const divEl = document.createElement("div");
divEl.innerHTML = "hello world";
divEl.className = "box";
document.body.appendChild(divEl);
// style.css
.box {
color: coral;
font-size: 20px;
font-weight: bold;
}
我们写了上面代码执行打包命令,然后发现报错了,读错误说也许需要一个loader
处理css
文件 ,这就是下面要学习的loader
了
css-loader
上面的错误信息告诉我们需要一个loader
来加载这个css
文件,但是loader
是什么呢?
-
loader
可以用于对模块的源代码进行转换 -
可以将
css
文件也看成是一个模块 ,我们是通过import
来加载这个模块的 -
加载这个模块时,
webpack
不知道如何对其进行加载 ,必须制定对应的loader
来完成这个功能 -
对于加载
css
文件来说,需要一个可以读取css
文件的loader
,最常用的是css-loader
-
npm install css-loader -D
:安装css-loader
使用
使用这个loader
来加载css
文件呢?有三种方式:
-
内联方式 :
import "css-loader!./style.css"
内联方式使用较少,因为不方便管理 -
CLI
方式(webpack5
中不再使用) :在webpack5
的文档中已经没有了--module-bind
,实际应用中也比较少使用 -
配置方式 :在
webpack.config.js
文件中写明配置信息
配置信息解释如下:
-
module.rules
中允许配置多个loader
(因为会使用其他的loader
,完成其他文件的加载) -
这种方式可以更好的表示
loader
的配置,也方便后期的维护,同时也让你对各个Loader
有一个全局的概览 -
module.rules
的配置如下:rules
属性对应的值是一个数组:[Rule]
Rule
是一个对象,对象中可以设置多个属性:-
test
属性: 用于对resource
(资源)进行匹配的,会设置成正则表达式 -
use属性: 对应的值是一个数组:[UseEntry],
UseEntry
是一个对象,可以通过对象的属性来设置一些其他属性loader
:必须有一个loader
属性,对应的值是一个字符串options
:可选的属性,值是一个字符串或者对象 ,值会被传入到loader
中 -
loader
属性 : 字符串,单个规则只能有一个loader
属性 ,如果需要使用多个loader
,loader
属性只能指定一个loader
,应该使用use
数组
-
js// wk.config.js const path = require("path"); module.exports = { entry: "./src/index.js", output: { filename: "index.js", path: path.resolve(__dirname, "build"), }, module: { rules: [ { test: /\.css$/, // use: ["css-loader"], // 写法一 // use: [ // 写法二 // { // loader: "css-loader", // options: {}, // }, // ], loader: "css-loader", // 写法三 }, ], }, };
配置并打包完之后在打包文件中能看到css
代码,但发现页面样式无效 ,因为还需要借另一个loader
将style
插入页面
style-loader
-
css-loader
只负责将.css
文件进行解析 ,不会将解析之后的css
插入到页面中 -
如果希望完成插入
style
的操作,需要另外一个loader
,就是style-loader
-
npm install style-loader -D
:安装style-loader
-
在配置文件中添加
style-loader
,loader
的执行顺序是倒着的 ,需要将style-loader
写到css-loader
的前面
js
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "index.js",
path: path.resolve(__dirname, "build"),
},
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"], // 写法一
// use: [ // 写法二
// {
// loader: "style-loader",
// options: {},
// },
// {
// loader: "css-loader",
// options: {},
// },
// ],
},
],
},
};
less-loader
在开发中,可能会使用less、sass、stylus
的预处理器来编写css
样式,效率会更高,想让环境支持这些预处理器,需要把less、sass
等编写的css
需要通过工具转换成普通的css
-
npm install less -D
:下载less
-
编写
style.less
代码js// style.less @fontSize: 20px; @fontWeight: bold; .box { color: red; font-size: @fontSize; font-weight: @fontWeight; }
-
在
index.js
文件中引入import "./style.less"
-
尝试打包会报下图错误
-
npm install less-loader -D
:下载less-loader
-
配置
wk.config.js
,less-loader
应该放在最后 ,因为需要让less-loader
先把less
转成css
,在用css-loader
解析css
jsconst path = require("path"); module.exports = { entry: "./src/index.js", output: { filename: "index.js", path: path.resolve(__dirname, "build"), }, module: { rules: [ { test: /\.css$/, use: ["style-loader", "css-loader"], }, { test: /\.less$/, use: [ { loader: "style-loader", }, { loader: "css-loader", }, { loader: "less-loader", }, ], }, ], }, };
PostCSS
PostCSS
是一个通过JavaScript
来转换样式的工具 ,可以帮助进行一些CSS
的转换和适配,比如自动添加浏览器前缀、css样式的重置,postcss
需要有对应的插件才会起效果,只要包括:
-
自动前缀 :使用插件如
autoprefixer
自动添加浏览器前缀。 -
CSS 变量 :允许使用
CSS
变量和自定义属性。 -
未来的 CSS 语法 :通过
postcss-preset-env
等插件使用未来CSS
特性。 -
模块化 :与
CSS Modules
等结合使用,实现更好的模块化支持。
postcss-loader
在webpack
中使用postcss
就是使用postcss-loader
来处理的
-
npm install postcss-loader -D
:安装postcss-loader
-
npm install autoprefixer -D
:需要添加前缀,就安装autoprefixer
-
这时就可以增加配置了,样式
user-select
就会被加上前缀来适配浏览器-webkit-user-select: none; -moz-user-select: none; user-select: none
js
// style.less
@fontSize: 20px;
@fontWeight: bold;
.box-less {
height: 60px;
color: red;
font-size: @fontSize;
font-weight: @fontWeight;
user-select: none;
background-color: #f0a4a466;
}
// wk.config.js
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "index.js",
path: path.resolve(__dirname, "build"),
},
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader", "postcss-loader"],
},
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
"less-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
// plugins: ["autoprefixer"], // 也可以直接传入字符串
plugins: [require("autoprefixer")],
},
},
},
],
},
],
},
};
- 单独的
postcss
配置文件:在根目录下创建postcss.config.js
,wk.config.js
中还是要写postcss-loader
的,只是它插件的配置放单独文件
js
// wk.config.js
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "index.js",
path: path.resolve(__dirname, "build"),
},
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader", "postcss-loader"],
},
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
"less-loader",
{
loader: "postcss-loader",
// options: {
// postcssOptions: {
// plugins: [require("autoprefixer")],
// },
// },
},
],
},
],
},
};
// postcss.config.js
module.exports = {
plugins: [require("autoprefixer")],
};
postcss-preset-env
事实上,在配置postcss-loader
时,配置插件并通常不使用autoprefixer
,而使用另外一个插件:postcss-preset-env
,因为它更强大
-
postcss-preset-env
也是一个postcss
的插件,会自动帮助我们添加autoprefixer
(已经内置了autoprefixer
) -
也可以将一些现代的
CSS
特性,转成大多数浏览器认识的CSS
,会根据目标浏览器或者运行时环境添加所需的polyfills
(Polyfills
是一些代码(通常是JavaScript
)用来实现不被某些浏览器原生支持的特性) -
npm install postcss-preset-env -D
:安装postcss-preset-env
-
直接把之前的
autoprefixer
改为postcss-preset-env
,查看打包后打码可以发现它不仅加了前缀,还把less
文件中的背景颜色转成浏览器能识别的background-color: rgba(240, 164, 164, 0.4)
js
// wk.config.js
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "index.js",
path: path.resolve(__dirname, "build"),
},
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader", "postcss-loader"],
},
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
"less-loader",
{
loader: "postcss-loader",
// options: {
// postcssOptions: {
// plugins: [require("postcss-preset-env")],
// },
// },
},
],
},
],
},
};
// postcss.config.js
module.exports = {
plugins: [require("postcss-preset-env")],
};