|
|
11 месяцев назад | |
|---|---|---|
| .. | ||
| Image | 11 месяцев назад | |
| src | 11 месяцев назад | |
| README.md | 11 месяцев назад | |
webpack 是一个为现代的 JavaScript 应用程序进行模块化打包的工具
webpack 是一个打包工具webpack 可以将打包打包成最终的静态资源,来部署到静态服务器webpack 默认支持各种模块化开发, ESModule、CommonJS、AMD等Webpack 的运行依赖 Node 环境,需要先安装 Node.js
Webpack 的安装从 4 版本之后,需要安装两个: Webpack(核心功能) 和 Webpack-cli (脚手架)
执行 webpack 命令会执行 node_modules 下的 bin 目录下的 webpack。 webpack 再执行时是依赖 webpack-cli 的,webpack-cli 在执行时,会利用 webpack 进行编译和打包过程
也就是说,
webpack是必须的。如果不使用webpack命令,而是自己写命令的话是可以不用webpack-cli的
使用命令行 npm install webpack webpack-cli -g 直接进行全局安装即可
使用命令行 npm install webpack webpack-cli -D 直接进行局部安装即可
正如当前 src 目录中的 01 项目所示,项目结构简单,一个 html 和三个 js 文件
│ index.html
│
└─src
│ index.js
│
└─util
add.js
data.js
在 index.html 根据引入 js 的方式不同,会出现不同的情况
| 引入代码 | 出现错误 | 错误原因 |
|---|---|---|
<script src="./src/index.js"></script> |
Cannot use import statement outside a module (at index.js:1:1) | 这是因为浏览器不支持 import 语句,需要修改引入代码为 <script src="./src/index.js" type="module"></script> |
<script src="./src/index.js" type="module"></script> |
01/src/util/add net::ERR_ABORTED 404 | 这是因为浏览器不会自动查找指定文件夹下同名的 js 文件,也就是说找不到 ./util/add 这个文件,需要修改为 ./util/add.js, 对 ./util/data 找不到也是同理 |
通过给 script 标签添加 type 属性和修改模块引入路径,成功让代码运行起来了
为了解决上面的问题,直接使用 webpack 命令来打包项目试试
直接使用 webpack 打包的时候,会检索当前目录下的 src/index.js 文件,并在同级目录下生成 dist/main.js
<script src="./dist/main.js" ></script>
成功运行,因为 main.js 是一个单独的文件,没有引入其他模块,所以不需要指定 type="module",也不需要修改 import 模块的路径
注意: 直接运行
webpack会搜索当前目录下的src/index.js所以要注意执行命令时所在的文件路径,如果没有会报错Module not found: Error: Can't resolve './src'
一般会使用 npm init -y 来创建 package.json, 进而通过局部安装的方式来安装所需的模块
可以通过 npx webpack 来运行局部安装的 webpack
npx会执行当前项目的node_modules/bin中的模块
可以通过向 package.json 的 script 中添加命令的方式来运行 webpack,使用 npm run build 来执行 build 命令
"scripts": {
"build": "webpack"
},
package.json 在执行命令的时候会优先查找当前目录中的 node_modules/bin
正如前面所讲,直接使用 webpack 命令会以 src/index.js 为入口(entry),查找依赖图结构
不是所有的项目的入口都是 src/index.js,打包之后的路径也不都是 dist 文件夹,所以 webpack 提供指定入口文件和输出路径的 option
npx webpack --entry ./src/main.js --output-path ./build
以 02 文件夹中的项目为例运行上述命令,会以
src/main.js为入口,并将输出的main.js打包到build文件夹中
在 官方文档 中也有详细说明
当然,如果全部使用命令进行 flag 配置,会非常麻烦,尤其是配置项目多了之后,会导致配置项难以查找,所以一般都是创建一个 webpack 的配置文件 webpack.config.js
webpack 是通过 commonjs 的方式来读取 webpack.config.js,所以使用 module.export = {} 方式来导出配置
毕竟最终
webpack也是依赖node来运行的,所以会使用node的模块导入机制
官网中也有对 config 的解释说明
const path = require("path")
module.exports = {
entry: "./src/main.js",
output: {
filename: "./bundle.js",
path: path.resolve(__dirname, "./build")
}
}
将上述代码写入 webpack.config.js 文件中,效果等同于 --entry ./src/main.js --output-path ./build
为什么 output.path 需要指定为 path.resolve(__dirname, "./build") ?
因为 webpack.config.js 的 output.path 需要指定为绝对路径,这个是 webpack 要求的,所以可以用到 node 内置的 path 模块,来获取当前文件(webpack.config.js) 的绝对路径
然后直接执行 npx webpack,自动读取当前项目目录中的 webpack.config.js 文件来进行操作,从而会生成 build/bundle.js 文件
如果当前目录中不存在 webpack.config.js 文件,而是 wp.config.js,这个时候需要指定配置文件的名称
npx webpack --config ./wp.config.js
如果有一个 js 文件名为 test.js,这个文件没有被其他任何模块 import,那么这个文件就不会打包到 webpack 的最终产物中去
webpack 在处理应用程序时,会根据命令或配置文件找到入口文件(比如 main.js),从入口开始,会生成一个依赖关系图,这个依赖关系图会包含应用程序所需的所有模块,然后遍历图结构,打包一个个模块(根据文件的不同使用不同的 loader 来解析)
webpack提供tree-shaking消除无用代码
也就是说,有一个 test.js 文件
console.log(`hello world`);
export function foo()
{
console.log(`test.js foo`);
}
在 main.js 中
如果使用如下代码,则不会引入 test.js
console.log(`main.js`);
如果使用如下代码,则会引入 test.js 但开启 tree-shaking 之后会消除 foo 函数,因为 foo 并没有被使用
import "./test"
console.log(`main.js`)
如果使用如下代码,则会将 foo 函数打包到最终文件中,因为 foo 被使用了
import * as test from "./test"
test.foo();
console.log(`main.js`)
前面提到过,不同类型文件需要不同的 loader 进行处理,比如 js、html、css 等
如果不对 webpack 做任何处理,运行 03 项目
官方案例
https://webpack.docschina.org/guides/asset-management/#loading-css
在 component.js 中通过 import ../css/index.css 会出现以下错误
ERROR in ./src/css/index.css 1:0
Module parse failed: Unexpected token (1:0)
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
> .content {
| color: red;
| }
@ ./src/util/component.js 1:0-25
@ ./src/index.js 1:0-25
根据 You may need an appropriate loader 你需要一个合适的 loader 来处理这个 css 文件
loader 可以用于对模块的源代码进行转换,这里将 index.css 看作是一个模块,通过 import ../css/index.css 来加载这个模块,但是 webpack 并不知道如何对这个模块进行加载,所以报错
为了让 webpack 知道如何加载,需要指定对应的 loader 来完成加载功能
直接使用 npm 局部安装 css-loader 和 style-loader 即可安装所需 loader
npm install css-loader style-loder -D
安装了 loader 只是表示你有这工具,但是如何使用这个工具需要通过配置来告诉 webpack
官网对 loader 的配置也有说明
loaderimport "style-loader!css-loader!../css/index.css"
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'css-loader',
},
],
},
],
},
module 属性可以配置 rules 规则数组
rules 是一个包含多个 rule 的数组
{
test: /\.css$/,
use: [
{
loader: 'css-loader',
},
],
},
test 用于正则匹配,对匹配上的资源,使用该规则中配置的 loader
/\.css$/由于.在正则中是特殊符号,需要用\转译;$表示匹配末尾
官网中对 loader 也有详细说明
| 写法一 | 写法二 | 写法三 |
|---|---|---|
use: [ { loader: "css-loader" } ] |
loader: "css-loader" |
use: [ "css-loader" ] |
上述三种写法等价
通过上述修改, 终于能够让 webpack 命令正常运行, 得到最后的 bundle.js 文件
但是实际运行的时候, .content 样式并没有正确显示在页面中, 这是因为 css-loader 只是负责解析 css 文件,并不负责插入 css, 所以还需要使用 style-loader 插入 style
常见的样式引入有三种方法
style 标签进行设置.css 文件进入引入{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
],
},
注意: webpack 加载 loader 的顺序是数组序号从大到小执行的
也就是根据上述配置, webpack 会先执行 css-loader 再执行 style-loader. 这个顺序就是正确的, 如果反向的话会执行 style-loader 再执行 css-loader, 但是没有 css-loader 解析 style-loader 怎么插入呢?
通过观察生成的 bundle.js 可以看到 webpack 是如何处理 css 的. 它通过创建一个 style 的方式将内容通过页内样式插入到 html 中
e.exports = function(e) {
var t = document.createElement("style");
return e.setAttributes(t, e.attributes), e.insert(t, e.options), t
}
可能会用 less、sass、stylus 的预处理器来编写 css 样式,效率更高,那么如何支持呢?
以 less 为例,想要将 less 转为 css,需要使用 less 这个库。想要解析 less 需要使用使用 less-loader 库
less-loader的执行需要less, 所以两个库都要安装
所以需要执行以下代码
npm install less less-loader -D
那么根据流水线操作,针对 .less 结尾的文件,需要首先使用 less-loader 将其转为 css,然后使用 css-loader 解析,最后使用 style-loader 插入到界面中
所以最终得到 less 的 rule 内容如下
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
"less-loader"
]
}
记得
rule不同的等效写法吗
针对不同的浏览器支持的特性,比如 css 特性、js 语法等,会导致各种兼容性问题
那么某个功能如果存在兼容性问题,是否需要针对这个功能对不同的浏览器做特殊处理呢?很多情况都是根据浏览器的市场占有率来决定的
caniuse 是一个判断某些功能能否使用的网站,其在 usage-table 界面中提供了市场占有率
很多项目存在 .browserslistrc 文件,内容可能如下
> 1%
last 2 versions
not dead
这里的 > 1% 就是指市场占有率大于 1%,根据当前运行的浏览器的版本,查找 caniuse 网站中的占有率,进而判断是否需要支持
通过 Browserslist 工具来共享兼容性配置给其他工具(babel、autoprefixer等)使用
Browserslist 是一个在不同的前端工具之间,共项目标浏览器和Node.js版本的配置
上述例子有一个叫 not dead 的配置,译为没有死亡的。 Browserslist 对 dead 的定义是 24 个月内没有官方支持或更新的浏览器
上述例子有一个叫 last 2 versions 的配置,表示每个浏览器的最后 2 个版本。比如 last 2 Chrome versions 就是 Chrome 浏览器最近的两个版本
除此之外,还有针对 node 的版本规则、针对指定平台浏览器的规则、支持特定功能浏览器的规则 等
首先通过 npm 安装 browserslist
npm install browserslist -D
然后就可以使用 browserslist 查询支持的浏览器了
cmd: npx browserslist ">1%, last 2 versions, not dead"
and_chr 132
and_ff 132
and_qq 14.9
and_uc 15.5
android 132
chrome 132
chrome 131
chrome 109
edge 132
edge 131
firefox 134
firefox 133
ios_saf 18.3
ios_saf 18.2
ios_saf 18.1
ios_saf 17.6-17.7
kaios 3.0-3.1
kaios 2.5
op_mini all
op_mob 80
opera 114
opera 113
safari 18.3
safari 18.2
samsung 27
samsung 26
在命令中
,等价于or也就是只要满足其中一个条件即可
cmd: npx browserslist ">1% and last 2 versions and not dead"
and_chr 132
chrome 132
chrome 131
edge 132
edge 131
firefox 134
ios_saf 18.2
op_mob 80
samsung 27
在命令中 and 表示所有条件必须全部满足才行
那么如何在项目中进行配置呢?
package.json 中新增 browserslist 属性进行配置,其他工具会根据该配置自动适配{
"name": "01",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
// ..
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
// ..
},
"browserslist": [
">1%",
"last 2 version",
"not dead",
]
}
通过新增 .browserslistrc 文件,进行配置
>1%"
last 2 version"
not dead"