文章目录
  1. 1. 入门命令
    1. 1.1. 其他
  2. 2. html-webpack-plugin
  3. 3. css-loader
  4. 4. webpack-dev-server
  5. 5. webpack 和 babel 配置 react 开发环境
    1. 5.1. 3.在 webpack 使用 babel-loader
    2. 5.2. 4. 写 react 组件
  6. 6. 用 clean-webpack-plugin 来清除文件
  7. 7. 配置多个 HTML 文件
  8. 8. 使用 pug (jade) 作为 HTML 的模板
  9. 9. 如何使用模块热替换 HMR 来处理 CSS
    1. 9.1. 1.启用 HMR
    2. 9.2. 2.处理 extract-text-webpack-plugin
  10. 10. 生产环境 vs 开发环境
    1. 10.1. 1. 增加环境变量
    2. 10.2. 2.使用环境变量
    3. 10.3. 3.window 平台使用
  11. 11. 如何打包图片
    1. 11.1. 1.file-loader
    2. 11.2. 2. file-loader 的参数
    3. 11.3. 3.解析 html 代码里面 img 的标签
    4. 11.4. 4. 压缩图片
      1. 11.4.1. 参考
      2. 11.4.2. 补充

webpack 3

入门命令

随后会用 webpack-dev-server 替代
基本构建

1
webpack src/app.js dist/app.bundle.js

开发环境实时构建

1
webpack --watch

生产环境中构建

1
webpack -p

其他

  • webpack -d – 包含资源地图
  • webpack –colors - 让编译的输出内容带有颜色

html-webpack-plugin

自动生成 html 文件,指定模板,添加 hash,mini

1
$ npm install html-webpack-plugin --save-dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
entry: "./src/app.js",
output: {
path: __dirname + "/dist",
filename: "app.bundle.js"
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
filename: "index.html",
minify: {
collapseWhitespace: true
},
hash: true
})
]
};

css-loader

1
$ npm install --save-dev css-loader style-loader
1
2
3
4
5
6
7
8
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
];
}
  • sass-loader
1
2
$ npm install sass-loader node-sass --save-dev
# 安装(中间可能要下载二进制包,要耐心等待)
1
import css from "./app.scss";
1
2
3
4
5
rules: [
{
test: /\.scss$/,
use: [ 'style-loader', 'css-loader', 'sass-loader' ]
}
  • extract-text-webpack-plugin

    用 extract-text-webpack-plugin 把 CSS 分离成文件

有时候我们要把 SASS 或 CSS 处理好后,放到一个 CSS 文件中,用这个插件就可以实现。

1
$ npm install --save-dev extract-text-webpack-plugin

webpack-dev-server

1
2
3
4
# 先全局安装
$ npm install -g webpack-dev-server@2.9.1
$ npm install webpack-dev-server@2.9.1 --save-dev
$ npm install webpack-cli -D

自动打开,切换端口号

1
2
3
4
5
6
7
8
9
module.exports = {
entry: './src/app.js',
...
devServer: {
port: 9000,
open: true
},
...
};

然后运行命令:

1
$ webpack-dev-server

webpack 和 babel 配置 react 开发环境

3.在 webpack 使用 babel-loader

最后我们需要在 webpack 中使用一个 loader 来转化 react 的代码。
首先,安装。

1
$ npm install --save-dev babel-loader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
entry: './src/app.js',
...
module: {
rules: [
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
//resolve-url-loader may be chained before sass-loader if necessary
use: ['css-loader', 'sass-loader']
})
},
// 这两行是处理 react 相关的内容
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
{ test: /\.jsx$/, loader: 'babel-loader', exclude: /node_modules/ }
]
}
};

4. 写 react 组件

src/index.html

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
</head>
<body>
<div id="root"></div>
</body>
</html>

src/app.js

1
2
3
4
5
6
7
import css from "./app.scss";

import React from "react";
import ReactDOM from "react-dom";
import Root from "./Root";

ReactDOM.render(<Root />, document.getElementById("root"));

src/Root.js

1
2
3
4
5
6
7
8
9
10
11
import React from "react";

export default class Root extends React.Component {
render() {
return (
<div style={{ textAlign: "center" }}>
<h1>Hello World</h1>
</div>
);
}
}

用 clean-webpack-plugin 来清除文件

生产环境每次执行npm run build都会在 dist 文件目录生成新的app.bundle.d01ae8858971a17f8ed2.js,再多运行几次,生成的带 hash 的 app.bundle.js 文件就会很多。

这些带 hash 的 app.bundle.js 只有最新的才有用,其他的都没用,我们要在 build 之前把它们全清空:

1
$ npm i clean-webpack-plugin --save-dev

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
const path = require('path')
...
const CleanWebpackPlugin = require('clean-webpack-plugin');

let pathsToClean = [
'dist',
]

module.exports = {
entry: {
"app.bundle": './src/app.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[chunkhash].js'
},
...
plugins: [
new CleanWebpackPlugin(pathsToClean),
...
new ExtractTextPlugin('style.css')
],
...
};

现在运行 npm run build 试试,只有下面的文件:

1
2
3
4
dist
├── app.bundle.0e380cea371d050137cd.js
├── index.html
└── style.css

配置多个 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
module.exports = {
entry: {
"app.bundle": './src/app.js',
// 这行是新增的。
"contact": './src/contact.js'
},
...
plugins: [
new CleanWebpackPlugin(pathsToClean),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
minify: {
collapseWhitespace: true,
},
hash: true,
// 这行是新增的。
excludeChunks: ['contact']
}),
new HtmlWebpackPlugin({
template: './src/contact.html',
filename: 'contact.html',
minify: {
collapseWhitespace: true,
},
hash: true,
// 这行是新增的。
chunks: ['contact']
}),
new ExtractTextPlugin('style.css')
],
...
};

上面的 excludeChunks 指的是不包含, chunks 代表的是包含。

使用 pug (jade) 作为 HTML 的模板

pug,nodejs 的 html 模板

1
npm install --save-dev pug pug-html-loader raw-loader

src/index.pug

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
doctype html
html(lang="en")
head
title= pageTitle
script(type='text/javascript').
if (foo) bar(1 + 5)
body
h1 Pug - node template engine
#root
#container.col
if youAreUsingPug
p You are amazing
else
p Get on it!
p.
Pug is a terse and simple templating language with a
strong focus on performance and powerful features.

webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

module.exports = {
...
plugins: [
...
new HtmlWebpackPlugin({
template: './src/index.pug',
...
}),
...
],
module: {
rules: [
...
{ test: /\.pug$/, loader: ['raw-loader', 'pug-html-loader'] }
]
}
};

我们来试试 pug 的 include 功能,就是可以包含子模板。

1
2
3
4
...
body
include includes/header.pug
...

src/includes/header.pug

1
h1 from header pug file

目录结构是这样的:

1
2
3
4
5
6
7
8
9
src
├── Root.js
├── app.js
├── app.scss
├── contact.html
├── contact.js
├── includes
│ └── header.pug
└── index.pug

如何使用模块热替换 HMR 来处理 CSS

1.启用 HMR

webpack.config.js

1
2
3
4
devServer: {
port: 9000,
open: true,
}

改成下面这样:

1
2
3
4
5
devServer: {
port: 9000,
open: true,
hot: true
}

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
...
const webpack = require('webpack');

...

module.exports = {
entry: {
"app.bundle": './src/app.js',
"contact": './src/contact.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[chunkhash].js'
},
devServer: {
port: 9000,
open: true,
hot: true
},
plugins: [
new CleanWebpackPlugin(pathsToClean),
...
// 这两行是新增的
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
],
...
};

报错!!!文件名还不能用 chunkhash 了,它说要用 hash 来代替 chunkhash。

chunkhash 是每个文件都使用不同的 hash 值

1
filename: "[name].[chunkhash].js";

hash 指每个文件使用相同的 hash 值

1
filename: "[name].[hash].js";

2.处理 extract-text-webpack-plugin

现在你试一下改变 src/app.scss 的内容,你会发现页面不动了,你无论怎么改,页面都不会改变,也不会刷新。

之前我们是用 extract-text-webpack-plugin 这个插件来处理 CSS 的,在用 HMR 的时候要先把它关闭一下。

用一个参数 disable: true 就可以关闭掉。

webpack.config.js

1
new ExtractTextPlugin("style.css");

变成

1
2
3
4
new ExtractTextPlugin({
filename: 'style.css',
disable: true
}),

然后把处理 scss 文件的 loader 部分变成类似下面这样:

1
2
3
4
5
6
7
8
...
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
//resolve-url-loader may be chained before sass-loader if necessary
use: ['css-loader', 'sass-loader']
})
...

变成

1
2
3
4
...
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
...

再试试,能够生效。

为什么要关闭呢这个插件呢?

其实想想也能知道,在开发环境下,用不用 extract-text-webpack-plugin 这个插件,意义不大,你把 css 变不变成一个文件,关系不大,开发环境只要能调效,效果能够看到就可以,但是生产环境需要这个插件,我们总不能开发环境不使用这个插件,也导致生产环境也不使用吧?

那如何解决这个问题呢?也就是说让生产环境使用这个插件,而开发环境不使用.

生产环境 vs 开发环境

要让生产环境使用 extract-text-webpack-plugin 这个插件,而开发环境不使用,如何做到呢?

其实原理很简单,只要能区分出哪个是开发环境,哪个是生产环境就可以,只要判断是生产环境的时候就用,不是的话…

1. 增加环境变量

首先来看一下之前的开发环境和生产环境分别使用的编译命令:

webpack.config.js

1
2
3
4
"scripts": {
"dev": "webpack-dev-server",
"prod": "webpack -p"
},

分别是开发环境使用的 npm run dev 命令和生产环境使用的 npm run prod 命令。

我们把它改成下面这样:

1
2
3
4
"scripts": {
"dev": "webpack-dev-server",
"prod": "NODE_ENV=production webpack -p"
},

开发环境的部分不变,生产环境的加了一个环境变量:

1
NODE_ENV = production;

很简单,NODE_ENV 是变量名,而 production 是 NODE_ENV 是这个变量的值,这些都不是固定的,你可以改成你想要的任意内容,只要能引用到就行了。

那么我们如何来使用这个变量呢?

2.使用环境变量

要引用我们之前创建的环境变量,也蛮简单的。

在 webpack.config.js 文件中:

1
var isProd = process.env.NODE_ENV === "production"; // true or false

process.env.NODE_ENV 就能得到之前设置的变量,如果运行的是 npm run prod,那么 process.env.NODE_ENV 为 true

上一节,我们有类似下面这样的两段关于 extract-text-webpack-plugin 这个插件的代码。

1
2
3
4
5
6
7
new ExtractTextPlugin({
filename: 'style.css',
disable: false
}),

test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']

我们把 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
...
// 线上线下切换 css-loder
var isProd = process.env.NODE_ENV === 'production'; // true or false
var cssDev = ['style-loader', 'css-loader', 'sass-loader'];
var cssProd = ExtractTextPlugin.extract({
fallback: 'style-loader',
//resolve-url-loader may be chained before sass-loader if necessary
use: ['css-loader', 'sass-loader']
})

var cssConfig = isProd ? cssProd : cssDev;

module.exports = {
...
plugins: [
...
new ExtractTextPlugin({
filename: 'style.css',
disable: !isProd
}),
...
],
module: {
rules: [
{
test: /\.scss$/,
use: cssConfig
},
...
]
}
};

只要能区别出不同的环境,使用不同的配置内容就可以了。

现在就可以放心地使用 npm run dev 和 npm run prod 命令了,再也不用临时关掉一些插件了。

3.window 平台使用

windows 平台:不能直接使用 NODE_ENV, 步骤如下:

1.npm install cross-env –save-dev

2.命令改为
“prod”: “cross-env NODE_ENV=production webpack -p”

如何打包图片

src/app.scss

1
2
3
4
body {
background: url('./images/logo.png') 0 0 no-repeat;
...
}

然后 npm run dev,你会发现类似下面的错误:
只要找到适合的 loader 来处理扩展名为 png 的图片文件即可。

1.file-loader

file-loader

安装

1
$ npm install --save-dev file-loader

2. file-loader 的参数

其实,file-loader 是可以带参数的,例如下面这样:

1
2
3
4
5
6
7
8
9
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'images/'
}
},

/\.(gif|png|jpe?g|svg)$/i 表示可以处理好多图片的格式,毕竟不只是 png 才是图片,别的扩展名的文件也可能是图片嘛。

[name] 代表文件名,[ext] 代表文件扩展名,outputPath 是输出的路径。

3.解析 html 代码里面 img 的标签

忘了一个重要的地方,之前我们是在 CSS 里引用图片作为背景的,但是,我们经常是在 html 直接使用 src 标签

例如下面这样:

1
<img src="./images/money-bag.svg" alt="" height=50>

src/index.html

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title></title>
</head>
<body>
<img src="./images/money-bag.svg" alt="" height="50" />
</body>
</html>

然而结果是这样的:404 了,文件找不到,没有成功。

其实缺少了一个在 html 代码里处理 img 标签的 loader。

这个 loader 是 html-loader

官方对它的定义是这样的:

Exports HTML as string. HTML is minimized when the compiler demands.

大概意思是说,把 html 变成导出成字符串的过程中,还能进行压缩处理(minimized)。

现在我们来加上这个 loader。

先安装。

1
$ npm install --save-dev html-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
...
{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'images/'
}
},
]
},
// 下面几行才是 html-loader 的配置内容
{
test: /\.html$/,
use: [ {
loader: 'html-loader',
options: {
minimize: true
}
}],
}
...

再试试发现就可以了。

4. 压缩图片

有时候图片太大,我们输出到生产环境的时候,希望可以让图片文件的体积小点,webpack 也可以轻易办到,就是自动压缩图片,然后生产环境拿到的图片就会很小。

还是用一个插件,这个插件叫 image-webpack-loader

这个插件主要是来压缩图片文件的。

安装。

1
$  npm install image-webpack-loader --save-dev

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
{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'images/'
}
},
{
loader: 'image-webpack-loader',
options: {
bypassOnDebug: true,
}
}
]
},
{
test: /\.html$/,
use: [ {
loader: 'html-loader',
options: {
minimize: true
}
}],
}

源文件的图片大小情况是这样的:

1
2
3
4
$ ls -lh src/images
total 256
-rw-r--r--@ 1 hfpp2012 staff 112K Nov 3 23:10 logo.png
-rw-r--r--@ 1 hfpp2012 staff 11K Dec 4 16:32 money-bag.svg

而压缩后(npm run prod):

1
2
3
4
$ ls -lh dist/images
total 96
-rw-r--r-- 1 hfpp2012 staff 33K Dec 4 21:34 logo.png
-rw-r--r-- 1 hfpp2012 staff 8.5K Dec 4 21:34 money-bag.svg

由上面的对比可知,压缩后体积减少了一些。

当然这个插件,肯定还有更多的用法,具体查看 readme 文档吧。

参考

补充

文章目录
  1. 1. 入门命令
    1. 1.1. 其他
  2. 2. html-webpack-plugin
  3. 3. css-loader
  4. 4. webpack-dev-server
  5. 5. webpack 和 babel 配置 react 开发环境
    1. 5.1. 3.在 webpack 使用 babel-loader
    2. 5.2. 4. 写 react 组件
  6. 6. 用 clean-webpack-plugin 来清除文件
  7. 7. 配置多个 HTML 文件
  8. 8. 使用 pug (jade) 作为 HTML 的模板
  9. 9. 如何使用模块热替换 HMR 来处理 CSS
    1. 9.1. 1.启用 HMR
    2. 9.2. 2.处理 extract-text-webpack-plugin
  10. 10. 生产环境 vs 开发环境
    1. 10.1. 1. 增加环境变量
    2. 10.2. 2.使用环境变量
    3. 10.3. 3.window 平台使用
  11. 11. 如何打包图片
    1. 11.1. 1.file-loader
    2. 11.2. 2. file-loader 的参数
    3. 11.3. 3.解析 html 代码里面 img 的标签
    4. 11.4. 4. 压缩图片
      1. 11.4.1. 参考
      2. 11.4.2. 补充