本文已参与「新人创作礼」活动,一起开启掘金创作之路
该专栏会带你从零学习webpack,一步步由浅入深地了解webpack的原理以及如何使用,还会教你如何自定义loader、plugin,以及webpack性能优化,如Tree Shaking、gzip压缩等
希望在读完本专栏后,能够让你灵活使用webpack,从而更好地解决工作中项目构建时遇到的问题,以及知道该如何对项目的构建进行性能优化
本篇文章是该专栏的第一章,会带你体验一下webpack,让你大体上了解一下webpack是干什么用的
本专栏对应的
github仓库:github.com/Plasticine-…
1. Webpack是什么?
webpack is a static module bundler for modern JavaScript applications.
这是官网对webpack的概念解释
bundler说明它是一个打包工具static说明能够处理各种静态资源module说明支持模块化开发,比如各种模块化方案ES Module、Common JS、AMD等
综上,可以大概了解到,webpack是一个能够将项目中用到的各种静态资源、模块化js代码打包成最终可以部署在服务器上直接使用,能够直接被浏览器解析运行的构建工具
2. 安装webpack
pnpm i webpack webpack-cli -D
3. webpack和webpack-cli的关系
一般来说需要安装webpack和webpack-cli,webpack-cli是在命令行中使用webpack时必须安装的依赖,安装了之后就能在命令行使用webpack命令了
但是它不是必须的,比如一些第三方脚手架工具,如vue-cli,其内部就只装了webpack而没有装webpack-cli,它有自己的vue-service-cli能够实现类似的功能
4. 体验webpack
首先在项目目录下创建一个src目录,并在其中创建index.js文件,然后写入一些代码
// src/index.js
console.log('hello webpack!');
然后执行npx webpack后会发现,项目目录下多出了dist目录,并且有一个main.js文件,其内容和我们的index.js一模一样
由此可以发现,webpack在没有配置的时候,默认是以src/index.js作为入口文件,dist/main.js作为打包的结果
5. webpack配置文件
可以在项目目录下创建webpack.config.js对webpack进行一些个性化配置,比如上面的入口文件默认是src/index.js,出口是dist/main.js,我们可以对其作出修改
// webpack.config.js
const path = require('path');
module.exports = {
entry: path.resolve(__dirname, 'src/main.js'),
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
},
};
path是Node.js的内置模块,用于处理路径相关的操作,path.resolve()就是用于拼接路径,第一个参数传入了__dirname表示当前文件webpack.config.js所在目录,然后拼接上src/main.js,最终就会得到D:/webpack_learning/01_webpack_start/src/main.js这样的绝对路径了
5.1 vscode编写webpack配置时提供自动补全
如果直接像上面那样去写webpack.config.js的时候是没有自动补全的,webpack的配置项那么多,一直去官网查对应配置项还是挺麻烦的,只需要添加上注释,并且用@type注解声明导出的对象的类型,就可以获得自动补全提示了!
/**
* @type { import('webpack').Configuration }
*/
module.exports = {
entry: path.resolve(__dirname, 'src/main.js'),
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
},
};
写相应配置项的时候还能够看到对应的配置项的作用(和官网的一致),省去了不少查文档的时间
5.2 指定配置文件名字
默认的配置文件名是webpack.config.js,如果想要使用别的名字,可以在执行webpack命令的时候加上--config参数,然后带上配置文件的路径即可
比如我希望使用webpack.test.config.js作为配置文件,那么应当这样执行命令
npx webpack --config ./webpack.test.config.js
5.3 将webpack命令作为package.json的脚本
如果我们指定了默认配置文件名以外的配置文件时,每次都要输入npx webpack --config ./webpack.test.config.js这样一长串太麻烦了,可以直接将其写在package.json的scripts配置项中
"scripts": {
"build": "webpack --config ./webpack.test.config.js"
},
注意:写在**scripts**中的命令不需要再加上**npx**
6. webpack初体验案例
6.1 案例场景和环境搭建
在这个案例中,我们会在js中直接用import导入css文件,看看导入的css文件能否生效
首先准备一下环境,在项目根目录下创建index.html,并在其中引入打包后的js文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>webpack start</title>
</head>
<body>
<script src="../dist/bundle.js"></script>
</body>
</html>
然后在src/css中创建index.css,并写好一些样式
* {
padding: 0;
margin: 0;
}
html,
body {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
background-color: #1d3557;
}
.box {
height: 500px;
width: 500px;
background-color: #457b9d;
}
然后再在入口文件中导入该css文件,并使用js创建一个class为box的div元素
// src/index.js
import './css/index.css';
(() => {
const boxEl = createEl('div', 'box');
document.body.appendChild(boxEl);
})();
/**
* 创建指定标签和类名的 DOM 元素
* @param {string} elTag 标签名
* @param {string} className 类名
* @returns HTMLElement DOM 元素
*/
function createEl(elTag, className) {
const el = document.createElement(elTag);
el.className = className;
return el;
}
6.2 初探loader
执行npx webpack,却遇到了如下报错
提示我们缺少了处理这种类型文件的
loader,loader是webpack的一个重要概念,在依赖图中遇到的各种类型文件时,要有相应的loader去处理才能正常打包,之后的文章中会详细介绍loader,这里先简要介绍一下loader是干什么的:
- 可以用于对模块的源代码进行转化
- 由于我们是通过
import导入css文件的,因此index.css可以被看成是一个模块 - 加载该模块的时候,
webpack并不知道要如何处理css这种类型的模块,因此需要有一个特定的loader去处理,让它能够顺利被webpack加载
那么什么loader能够处理css类型的模块呢?答案就是css-loader
6.3 安装并配置css-loader
首先需要安装css-loader
pnpm i css-loader -D
配置css-loader有三种方式:
- 内联方式
- CLI方式(webpack5中不再使用)
- 在配置文件中配置
下面逐一介绍这三种模式
6.3.1 内联方式
直接在导入相应模块的时候指明使用的loader,因而被称为内联方式
import 'css-loader!./css/index.css';
这种方式很少用,因为不方便管理,并且每次导入css都要手动声明一下,不太方便使用
6.3.2 CLI方式
该方式在webpack5中已经被取消,下面是webpack4文档中关于该方式的介绍
根据官方文档,我们使用这种方式打包的命令如下
npx webpack --module-bind 'css=css-loader'
但是由于我们安装的是webpack5,已经不支持该参数了,所以会报错,但是没关系,这种方式了解即可,实际开发中并不会这样去使用loader
6.3.3 配置文件中配置
这种方式是最常用的,意思是在webpack.config.js中的module.rules下配置loader
这种方式方便后期维护,能够一目了然,知道项目中用到了哪些loader,以我们的css-loader为例,看一下要怎么配置吧!
const path = require('path');
/**
* @type { import('webpack').Configuration }
*/
module.exports = {
entry: path.resolve(__dirname, 'src/index.js'),
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
// 也可以直接用 test 简写
resource: {
test: /\.css/,
},
// rules.use 中的 loader 还可以直接简写为 rules.loader
use: [
// 需要给 loader 提供配置项的时候使用对象形式
// 不需要提供配置时直接用字符串即可
// 即 use: ['css-loader']
{
loader: 'css-loader',
options: {
xxx: 'options item',
},
},
],
},
],
},
};
webpack的配置有很多都可以简写,这一点可以在写的时候注意一下自动补全中的文档提示
由于我们暂时不需要用到
css-loader的配置项,因此直接在rules.use中写上字符串就好了
const path = require('path');
/**
* @type { import('webpack').Configuration }
*/
module.exports = {
entry: path.resolve(__dirname, 'src/index.js'),
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css/,
use: ['css-loader'],
},
],
},
};
6.4 使用style-loader
现在我们配置完了,并且打包也正常了,可是通过live-server运行一个服务器,然后访问index.html的时候却发现样式并没有生效
这是为什么呢?
因为
css-loader只是负责解析.css文件类型的模块,但是并不会将解析后的结果插入到html中
如果希望将解析后的css样式插入到html中,还需要另外一个loader -- style-loader
安装style-loader
pnpm i style-loader -D
然后将style-loader配置到webpack.config.js中
const path = require('path');
/**
* @type { import('webpack').Configuration }
*/
module.exports = {
entry: path.resolve(__dirname, 'src/index.js'),
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css/,
// 一定要将 style-loader 写在 css-loader 前面,因为 webpack 是逆序使用 loader 的
use: ['style-loader', 'css-loader'],
},
],
},
};
执行pnpm run build后就能够看到效果了
查看打包后的结果可以发现,会在
html中的head标签中创建一个style标签,并将样式放在这里面
后续我会讲解如何将
css抽取到单独的文件中,并进行压缩等操作