一.了解什么是Webpack?Webpack的作用是什么?

Webpack是一种端资源构建工具,一个静态模块打包器
Webpack的作用就是将在node中写好的代码(后端)解析为在浏览器(前端)可以运行的代码,提高了项目效率和可维护性

二.Webpack的5个核心概念

1. entry入口

入口指示Webpack以哪个入口文件开始打包,分析构建内部依赖图

2. output输出

输出指示Webpack打包后的资源bundlex输出到哪里,以及如何命名

3. loader(翻译官的作用)

loader可以让webpack能够处理哪些非js文件(webpack自身只理解js,json,线wenpack5可以处理图片资源)

4. plugins

插件plugins可以用于执行范围更广的任务。插件的范围包括:从打包优化和压缩,一直到重新定义环境中的变量。

5. mode

模块知识Webpack使用相应模式的配置。
image.png

1
2
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/*
webpack.config.js是webpack的配置文件
作用:告诉webpack干哪些活(运行webpack指令时,会加载里面的配置)
所有的构建工具都是基于nodejs平台运行的,模块化默认采用commonjs
*/

// resolve用来拼接绝对路径的方法
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
// webpack配置
// 入口文件
entry: './src/index.js',
// 输出
output: {
// 输出文件名
filename: 'built.js',
// 输出路径 __dirname是nodejs的变量,代表当前文件webpack.js目录的绝对路径02打包样式资源
// 输出到build目录下去
path: resolve(__dirname, 'build')
},
// loader的配置(1.下载2.使用)
module: {
rules: [
{
// test:使用正则匹配文件
test: /\.css$/,
// use:使用哪些loader进行处理,执行顺序是倒序依次执行,比如会先使用css-loader再使用style-loader
use: [
// style-loader会创建style标签,将js中的样式资源插入进行,添加到head中生效
'style-loader',
// css-loader会将css文件变成commonjs模块加载js中,里面内容是样式字符串
'css-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
// 将less文件编译成css文件,需要安装less和less-loader
'less-loader'
]
},
// 处理图片资源【webpack5会自动处理图片资源 !!加上以下配置反而图片显示不出来,webpack4可以用以下配置】
// {
// test: /\.(jpg|png|gif)$/,
// // 使用多个loader时可以用use:[],如果只使用一个loader可以直接写loader:‘xxx’
// // url-loader依赖file-loader,所以需要下载两个包
// loader: 'url-loader',
// // 图片配置信息
// options: {
// // 一般会对小图片进行base64处理,这里是当图片小于8kb时,就会被base64处理成字符串
// // 优点:减少请求数量(减轻服务器压力)
// // 缺点:图片体积会变大导致问价请求速度变慢
// limit: 10 * 1024, //根据项目情况来定,假如项目中小图片是9kb,难么这里可以设置10*1024
// // 在webpack4中ulr-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
// // 解析时会出现问题:src内容会变为[object module]
// // 解决办法:关闭url-loader的es6模块化,使用commonjs解析
// esModule: false,
// // 打包后的图片的名称是hash值,字符比较长,可以自定义命名
// // 意思为:取hash值的前10位,[ext]是指取文件原来扩展名
// name: '[hash:10].[ext]'
// }
// },
// html-loader处理html中的img图片资源(负责引入img标签,然后交由url-loader进行解析处理)
{
test: /\.html$/,
loader: 'html-loader'
},
// 打包其他资源(除了html/css/js以外的资源)
{
// exclude:排除html,css,js资源的其他资源都适用file-loader(比如字体图标iconfont)
exclude: /\.(html|css|js)$/,
loader: 'file-loader'
}
]
},
// 插件(1.下载2.引入3.使用)
plugins: [
// html-webpack-plugin插件会打包html文件
// 功能:会默认创建一个空的html,自动引入打包后输出的所有资源(js/css)
new HtmlWebpackPlugin({
// template模版:意味复制./src/index.html文件,并自动引入打包后输出的所有资源
template: './src/index.html'
})
],
// 模式
mode: 'development'
}

三.搭建webpack的基础配置

  1. 安装依赖:———– npm init
  2. 安装webpack
    1. 自从有了webpack4之后如果想要使用webpack必须要安装webpack-cli,-D代表实在开发环境中
    2. 安装npm install webpack webpack-cli -D
  3. 创建src文件夹,里面创建入口文件main.js编辑需要的内容
  4. 利用webpack对内容进行打包
    1. 在最外层(src的同级目录)创建webpack.config.js文件(文件名称不可更改)
    2. webpack.config.js文件内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//引入path 导入node.js 中专门操作路径模块
const path = require("path");

//使用node.js 中的导出语法,向外导出 一个 webpack配置对象
module.export = {
//入口文件
entry: "./src/main.js",
//出口文件
output: {
//__dirname:当前目录
path: path.resolve(__dirname, "./build"),
//打包生成的文件名
filename: "bundle.js",
},
};il
  3. 因为初始配置的时候已经安装了webpack,这时你可以在node-modules/.bin文件夹中发现webpack文件夹所以这个时候再次利用webpack只需要在控制台输入`npx webpack`指令就会去bin文件中寻找webpack.
  4. 注意上方代码可能会报错:Module not found: Error: Can't resolve './src' in 'D:\Study\Webpack\01-source-map'这是因为新版的webpack比旧版的更加严格,他一般认为index.html或index.js是入口文件,把main改成index即可。

四.source-map(编译后源文件的映射即编译后的代码)

认识source-map
     a.代码通常运行在浏览器上时,是通过**打包压缩**的:
  • 这也就表明了真实跑在浏览器上的代码和我们编写的代码是有差异的;
  • 比如ES6的代码可能被转化成ES5
  • 比如对应的代码行号,列号在经过编译后肯定不会一致
  • 比如代码进行丑化压缩时,会将编码名称等修改
  • 比如我们使用了TypeScript等方式编写的代码,最终回转换成JS

b.但是,当代码报错需要调试时,调试转换后的代码时很困难的。
c.那么如何可以调试这种转换后不一致的代码呢?答案是source-map

  • source-map是从已转换的代码映射到原始的源文件
  • 使浏览器可以重构原始源并在调试器中显示重建的原始源
如何使用source-map?

可以分为以下两个步骤;

  • 第一步:根据源文件,生成source-map文件,webpack在打包的时候,可以配置生成source-map(即在配置文件中加入;devtool: ‘选定的值’)。配置代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
const path = require("path"); //引入path

module.exports = {
devtool: 'source-map',
//项目入口文件配置
entry: "./src/index.js",
//项目出口文件配置
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "build")
},
mode: "development",
};
  • 第二步:在转换后的代码,最后添加一个注释,它指向sourcemap; 一般在转换后的代码中会自动生成:如下代码:
1
2
//即上方提到的注释bundle.js文件名字
//# sourceMappingURL=common.bundle.js.map

source-map的好处:
浏览器会根据我们的注释查找相应的source-map,并且根据source-map还原我们的代码,方便调试。
在Chrome中打开控制台,选择设置,按照如下方式打开source-map:
image.png

生成source-map文件
  • 如何在使用webpack打包的时候,生成对应的source-map?
    • webpack为我们提供了非常多的选项(目前是26个),来处理source-map
    • 官方文档:https://www.webpackjs.com/configuration/devtool/
    • 选择不同的值,生成的source-map会稍微有差异,打包过程也会有差异,可能根据不同的情况进行选择;
  • 下面几个值不会生成source-map
    • false:不适用source-map,也就是没有任何和source-map相关的内容
    • none:production模式下的默认值(什么值都不写),不生成source-map。
    • eval:development模式下的默认值,不生成source-map
      • 但是它会在eval执行的代码中,添加//#sourceURL=
      • 它会被浏览器在执行时解析,并且调试面板中生成对应的一些文件目录,方便我们调试
  • 生成source-map
    • source-map:生成一个独立的source-map文件,并在bundle文件中有一个注释指向source-map文件

其他类型的值了解即可

五.深入解析Babel-polyfill

什么是Babel?

  • Babel是一个工具链,主要用于旧浏览器或者环境中将ECMAScript 2015+代码转换为向后兼容版本的js
  • 包括:语法转换,源代码转换,Polyfil实现目标环境缺少的功能等。
Babel命令执行
  • babel本身可以作为一个独立的工具(和postcss一样),不和webpack等构建工具配置单独使用。
  • 如果希望在命令行尝试使用babel,需要安装如下库:
    • @babel/core:babel的核心代码,必须安装
    • @babel/cli:可以让我们在命令行中使用babel;

安装指令:npm install @babel/cli @babel/core

  • 使用babel处理所写的源代码:
    • src:源文件的目录
    • –out-dir:指定要输出的文件夹dist;

处理指令:npx babel src --out-dir dist

  • 插件安装:
    • 如果需要转换箭头函数,则要安装使用箭头函数转换相关的插件:
1
安装插件指令:npm install @babel/plugin-transform-arrow-functions -D

转换源代码(并转换里面的箭头函数):

1
npx babel ./src --out-dir ./build --plugins=@babel/plugin-transform-arrow-functions
  • 如果需要转换块级作用域(即将const,let转换成var),则要安装转换块级作用域相关的插件:

安装插件指令:

1
npm install @babel/plugin-transform-block-scoping -D

转换源代码(并转换里面的箭头函数和块级作用域):

1
npx babel ./src --out-dir ./build --plugins=@babel/plugin-transform-block-scoping,@babel/plugin-transform-arrow-functions

Babel的预设preset

  • 当转换的内容过多的时候,一个个设置比较麻烦,因此可以使用预设(preset)减少步骤
  • 安装@babel/preset-env预设:
1
npm install @babel/preset-env -D
  • 执行下方命令生成对应文件:
1
npx babel ./src --out-dir ./bulid --presets=@babel/preset-env
Babel的底层原理(较为重要)

Babel拥有编译器的工作流程:

  • 解析阶段(Parsing)
  • 转换阶段(Transfromation)
  • 生成阶段(Code Generation)

image.png

浏览器兼容性配置

要想实现浏览器的兼容性需要借助Browserslist
Browserslist是什么?Browserslist是一个在不同的前端工具之间,共享目标浏览器和Node.js版本的配置

  • Autoprefixer
  • Babel
  • postcss-preset-env
  • eslint-plugin-compat
  • stylelint-no-unsupported-broewr-features
  • postcss-normailze
  • obsolete-webpack-plugin

image.png
image.png
配置browserlist

  • 如何配置browerlist?
    • 方案一:在package.json中配置
    • 方案二:单独的一个配置文件.browserslistrc
  • 方案一:package.json配置:
1
2
3
4
5
"browerslist":[
"last 2 version",
"not dead",
">0.2%"
]
  • 方案二:.browerslistrc文件:
1
2
3
> 0.5%
last 2 version
not dead

image.png
根据上方条件找到符合情况的所有浏览器,根据浏览器的特性对需要转换打包的代码进行适当的调整。
设置目标浏览器的browserlist
最终打包的js文件需要跑在目标浏览器上,那么如何告知babel目标浏览器是什么?

  • 方式一:借助browserslist工具
  • 方式二:target属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module: {
rules: [
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
presets: [
["@babel/preset-env",{
//在开发中针对babel的浏览器兼容查询使用browerslist工具,而不是设置target
//因为browserslist工具,可以在多个前端工具之间进行浏览器兼容性(postcss/babel)
// targets: ">5%"
}]
],
},
},
},
],
},
};

如果两个同时配置产生的效果:

  • 配置的targets属性会覆盖browerslist;
  • 但是在 开发过程中,更推荐通过browerslist来配置,因为类似于postcss工具,也会使用broesersliat,进行统一浏览器的适配。
babel的配置文件
  • 与大多数配置文件一样,babel的配置信息也可以单独的放在一个独立的文件中。因此,babel给我们提供了两种配置文件的编号:
    • babel.config.json(后缀.json也可以 改成.js,.cjs,.mjs)文件;
    • .babelrc.json(后缀.json也可以改成.js,.cjs,.mjs,作者直接写成.babelrc)文件
    • 例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
//相当于以前的webpack.config.js中的options里的内容,将其babel配置单独拿出,比较好管理
module.exports = {
presets: [
[
"@babel/preset-env",
{
//在开发中针对babel的浏览器兼容查询使用browerslist工具,而不是设置target
//因为browserslist工具,可以在多个前端工具之间进行浏览器兼容性(postcss/babel)
// targets: ">5%"
},
],
],
};
  • 上方两种方式的区别?目前很多项目都采用了多包管理的方式(babel本身,element-plus,umi等);
    • babel.config.json(babel17):可以直接作用域Monorepos项目的子包,更加推荐;
    • .babelrc.json:早期使用较多的配置方式,但是对配置Monorepros项目是比较麻烦的;
babel和polyfill

polyfill
image.png

  1. 安装可以使用polyfill插件
1
npm install core-js regenerator-runtime
  1. 在babel.config.js中进行相关配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//相当于以前的webpack.config.js中的options里的内容,将其babel配置单独拿出,比较好管理
module.exports = {
presets: [
[
"@babel/preset-env",
{
//在开发中针对babel的浏览器兼容查询使用browerslist工具,而不是设置target
//因为browserslist工具,可以在多个前端工具之间进行浏览器兼容性(postcss/babel)
// targets: ">5%"
// corejs: 3,
//false表示不使用polyfill进行填充
useBuiltIns: false
},
],
],
};

注意:当useBuiltIns为false时,corejs需要注释,否则会在控制台提出如下警告:
image.png
image.png
image.png
虽然它有三个值可以设置但是尽量使用usage

React和TS解析

image.png
一.如何对React进行打包?

  1. 首先在src下创建存放react组件的文件夹,在里面写react的jsx形式的组件文件
  2. 在入口的index.js中引入react组件并进行编写:
1
2
3
4
5
6
7
8
9
10
//引入react组件
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './react/App.jsx'

//编写react代码
//在src的同级目录创建一个index.html文件,并创建一个标签作为存放react组件的容器
const root=ReactDOM.createRoot(document.querySelector("#root"))
root.render(<App/>)

创建react文件前需要先安装react插件

1
npm install react react-dom       

因为以前的配置只是关于js的,React作用的html文件并未对其进行打包,所以要进行html打包的配置

  1. react所需的html打包的配置
  • 安装html打包的库
1
npm install html-webpack-plugin -D
  • 在webpack.config.js文件中配置html打包所需代码,这样以后只需要用npm run build也可以生成html的打包文件
1
2
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
//html打包所引入的库
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path"); //引入path

module.exports = {
mode: "development",
devtool: "source-map",
//项目入口文件配置
entry: "./src/index.js",
//项目出口文件配置
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "build"),
// 重新打包时,先将之前打包得文件夹删除掉
clean: true,
},
module: {
rules: [
{
test: /\.jsx?$/, //x?:表示0个或者一个x
use: {
loader: "babel-loader",
// options: {
// presets: [
// ["@babel/preset-env",{
// //在开发中针对babel的浏览器兼容查询使用browerslist工具,而不是设置target
// //因为browserslist工具,可以在多个前端工具之间进行浏览器兼容性(postcss/babel)
// // targets: ">5%"
// }]
// ],
// },
},
},
],
},
//打包html文件-----------新增的html打包配置
plugins: [
new HtmlWebpackPlugin({
template: "./index.html",
}),
],
};

  1. 因为要转换react代码所以需要安装react的预设:
1
npm install @babel/preset-react -D

相关配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//相当于以前的webpack.config.js中的options里的内容,将其babel配置单独拿出,比较好管理
module.exports = {
presets: [
[
"@babel/preset-env",
{
//在开发中针对babel的浏览器兼容查询使用browerslist工具,而不是设置target
//因为browserslist工具,可以在多个前端工具之间进行浏览器兼容性(postcss/babel)
// targets: ">5%"
// corejs: 3,
// useBuiltIns: "usage"
},
],
//react转换的预设
["@babel/preset-react"]
],
};

二.ts编译打包
方式一:

  1. 首先在src下创建存放ts文件的文件夹,在里面写.ts形式的文件
  2. 在入口的index.js中引入ts文件并进行编写:

例如:

1
2
3
import {sum}  from './ts/math.ts'
//使用ts代码
console.log(sum(20,30));

3.转换ts:
首先安装ts相关的转换库让其代码在打包时可以转换成js代码:

1
npm install ts-loader -D

其次配置ts-loader:

1
2
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
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path"); //引入path

module.exports = {
mode: "development",
devtool: "source-map",
//项目入口文件配置
entry: "./src/index.js",
//项目出口文件配置
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "build"),
// 重新打包时,先将之前打包得文件夹删除掉
clean: true,
},
resolve: {
//可以是引入文件的时候不加文件的后缀名
extensions: [".js", ".json", ".wasm", ".jsx", ".vue",'.ts'],
},
module: {
rules: [
{
test: /\.jsx?$/, //x?:表示0个或者一个x
use: {
loader: "babel-loader",
},
},
//解析ts
{
test: /\.ts$/,
use: "ts-loader" //安装ts-loader:npm install ts-loader -D 下一步创建tsconfig文件:tsc --init
}
],
},
//打包html文件
plugins: [
new HtmlWebpackPlugin({
template: "./index.html",
}),
],
};

最后进行打包

1
npm run build

image.png
在下方中安装ts-loader时就会自动安装上方的ts
image.png
除了可以用上方的方式编译ts文件之外也可以用下面的方式。它主要是借用babel。
方式二:
1.因为在ts文件中可能含有es语言之类的新语法,浏览器可能不认识,所以需要对其进行补丁。如果单纯的借助上方方式并不能实现,需要在babel对ts进行预设,并且转换。

1
2
3
4
5
6
7
8
9
10
11
export function sum(num1: number, num2: number) {
return num1 + num2;
}
export function formatPrice(priceString: string) {
//因为下方的ts中使用了es新推出的includes()方法,为了进行正常的使用所以会对其进行补丁和预设
if (priceString.includes("$")) {
return "xxxx";
} else {
return "yyy";
}
}

2.将webpack.config中的use的值设置为”babel-loader”

1
2
3
4
5
6
7
//解析ts
{
test: /\.ts$/,
// use: "ts-loader" //安装ts-loader:npm install ts-loader -D 下一步创建tsconfig文件:tsc --init
//为了方便以后的运行配置,或者如果ts文件中出现了es新出的方法进行补丁建议使用babel-loader
use: 'babel-loader'
}

3.安装ts的预设

1
npm install @babel/preset-typescript -D

4.在babel.config.js中配置ts的预设和补丁,进行方法填充

1
2
3
4
5
6
7
8
//ts转换的预设
[
("@babel/preset-typescript",
{
corejs: 3,
useBuiltIns: "usage",
})
],

image.png
ts-loader与babel-loader的区别:
image.png
如何在使用Babel的时候也对ts进行实时监听:
image.png
package.json中的script的代码:

1
2
3
4
5
6
7
8
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
//检测ts文件的语法是否正确
"ts-check": "tsc --noEmit",
//相比于上面这个只要在控制台运行npm run ts-check-watch就会进行实时监听,完全正确之后再ctrl+c进行打包操作
"ts-check-watch": "tsc --noEmit --watch"
},