先来搞明白基础配置

目标

我们目标是配置一个使用Html、JavaScript、CSS来完成基础的开发,能够处理js文件、处理css和一些静态文件,我们一步步来~

基础配置实践

基础路径:

1
2
3
4
5
6
7
8
├── node_modules
├── package.json
├── src
│ ├── index.html
│ ├── index.js
│ ├── test.png
│ └── index.css
└── webpack.config.js

依赖版本:

1
2
3
4
5
6
7
8
9
10
11
12
{
"devDependencies": {
"css-loader": "^1.0.0",
"file-loader": "^1.1.11",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.4.1",
"style-loader": "^0.21.0",
"url-loader": "^1.0.1",
"webpack": "^4.16.1",
"webpack-cli": "^3.1.0"
}
}

初始化project

第一步是初始化project,创建一个文件夹webpack-study,键入npm init,一路enter,最终文件夹下生成了一个package.json文件.

安装依赖包

第二步是安装webpack与webpack-cli,为什么还要安装webpack-cli,因为webpack的指令需要webpack-cli来实现,两者目前来说是不可分离的,所以:

npm i webpack webpck-cli -D

编辑config文件

然后编辑webpack.config.js文件:

1
2
3
4
5
6
7
8
9
10
11
const path = require('path')

module.exports = (env, argv) => {
return {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/bundle.js'
},
}
}

这是最基础的配置,我们主要定义的是如何去处理js文件,它的入口文件在./src/index.js,打包后文件存储在dist目录下,js文件存储在dist文件夹中的js/中,命名为bundle.js.

编写代码

我们试试编辑index.htmlindex.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h2>this is a webpack test</h2>
</body>
<script src="./index.js"></script>
</html>
1
2
// index.js
document.write('xixixi')

然后,在package.json中的scripts添加npm指令:

1
2
3
4
5
6
7
8
{
...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --mode production"
}
...
}

运行打包

运行npm run build后,会得出一个dist文件夹,如下:

1
2
3
4
5
6
7
8
├── dist
│ └── js
│ └── bundle.js
├── package.json
├── src
│ ├── index.html
│ └── index.js
└── webpack.config.js

这样我们就得到了打包结果,我们写的index.js被打包到dist中,但是这并不是一个完整的结构,因为dist文件中并没有html文件,所以我们进一步优化:

添加html-webpack-plugin插件

npm i html-webpack-plugin -D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = (env, argv) => {
return {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/bundle.js'
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html'
})
]
}
}

html-webpack-plugin功能非常强大,template是我们指定的模版文件,filename是我们打包后的html文件名,最为神奇的是html-webpack-plugin会自动将打包后的文件导入到index.html中。

处理CSS

我们下一个问题是如何打包css文件,因为webpack只能处理js文件,那么就需要对应的loader来处理css文件:

npm i css-loader style-loader -D

  • css-loader: 解析.css文件
  • style-loader: 将解析完成的内容插入到js中,通过js将样式绑定到dom元素中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = (env, argv) => {
return {
...
module: {
rules: [
{
test: /\.css/,
use: [
'style-loader',
'css-loader'
]
}
]
}
}
}

这里注意是是loader的使用顺序是从右到左的,上面的配置即表示先使用css-loader解析css文件,在用style-loader将样式绑定到dom元素中.

新增index.css文件:

1
2
3
h2{
color: pink;
}

修改index.js,将css导入:

1
2
require('./index.css')
document.write('xixixi')

我们运行npm run build,发现html中有样式,但是css却是嵌入到js中的,这很不优雅,我们都希望各类文件排排坐,分离开来.

分离CSS

为了各司其职,我们决定将css分离开来,这次我们使用mini-css-extract-plugin这个插件来替代style-loader,为什么说他们两是替代关系呢?因为我们之前说style-loader是将css样式插入到dom元素中,那么如果要分离css,那么就不能使用style-loadermini-css-extract-plugin就是将css文件单独分开来:

npm i mini-css-extract-plugin -D

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
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = (env, argv) => {
return {
...
plugins: [
...
new MiniCssExtractPlugin({
filename: "css/[name].[hash].css",
chunkFilename: "css/[id].[hash].css",
})
],
module: {
rules: [
{
test: /\.css/,
use: [
// 'style-loader',
MiniCssExtractPlugin.loader,
'css-loader'
]
}
]
}
}
}

我们npm run build,就发现css已经分离出,并且在html-webpack-plugin的帮助下,也将css导入到html中:

1
2
3
4
5
6
├── dist
│ ├── index.html
│ ├── css
│ │ └── main.70c0912768e4fa3bf241.css
│ └── js
│ └── bundle.js

导入文件

我们开发中经常会使用某些静态文件,当然webpack是不支持这类文件的,比如png、svg这类文件,这个时候我们就需要使用file-loader来解析静态文件,配合url-loader可以将小文件转换成base64格式直接插入,减少请求次数.

  • file-loader 处理各类文件
  • url-loader 将指定大小的文件转换成base64

两者之间是什么关系呢,我们可以理解为url-loader是file-loader的拓展,但是url-loader必须要依靠file-loader的基础能力,所以我们需要将两个loader都下载:npm i file-loader url-loader -D

修改index.html:

1
2
3
4
<body>
<h2>this is a webpack test</h2>
<div class="pic"></div>
</body>

index.css中导入图片:

1
2
3
4
5
.pic {
height: 300px;
width: 400px;
background-image: url('./test.png')
}

配置webpack.config.js

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

module.exports = (env, argv) => {
return {
...
module: {
rules: [
...
{
test: /\.(png|jpg|gif|jpeg|svg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1024,
name: '[name].[hash:6].[ext]',
outputPath: 'images/',
publicPath: '../images'
}
}
]
}
]
}
}
}

我们这里设置了limit,表示当文件小于1024B,即转换成base64格式,name设置了文件的name和hash值,outputPath则是文件存储的位置,publicPath则是引入文件时,路径前自带的初始化路径,以正确的索引文件.

执行npm run build,得到打包结果:

1
2
3
4
5
6
7
8
├── dist
│ ├── index.html
│ ├── css
│ │ └── main.32e8e4a338b99c0f881f.css
│ ├── images
│ │ └── test.82e44a.png
│ └── js
│ └── bundle.js

最后

最后我们来看看整个webpack.config.js的配置:

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
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = (env, argv) => {
return {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/bundle.js'
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html'
}),
new MiniCssExtractPlugin({
filename: "css/[name].[hash].css",
chunkFilename: "css/[id].[hash].css",
})
],
module: {
rules: [
{
test: /\.css/,
use: [
// 'style-loader',
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test: /\.(png|jpg|gif|jpeg|svg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1024,
name: '[name].[hash:6].[ext]',
outputPath: 'images/',
publicPath: '../images'
}
}
]
}
]
}
}
}

当然,这仅仅只是完成了最基础的功能,距离真正能够方便我们开发的配置或许还有一些距离,但是一般来说,以上配置都是必须的,所以我们不必要着急,慢慢来,请关注我后续博客,将会在此基础上实现更加完善的功能。

本章节的代码已经上传到Github,传送门webpack-study,请自行切换到chapter-01分支。

He that thinks his business below him will always be above his business. :)