webpack3 入门
安装
安装 nodejs
打开命令行终端, 输入一下命令, 如果出现安装版本号 ( 如: v8.11.2 ), 说明安装成功
$ node -v
安装 webpack
在命令行终端上输入以下命令, 全局安装 webpack:
$ npm install webpack@3.6.0 -g
npm 是 nodejs 管理插件的工具, install 表示安装, @3.6.0 表示安装指定的 webpack 版本, 如果不加@xxx, 则会默认安装最新版本; -g 表示全局安装, 这样就会把可执行文件 webpack 放到 bin 目录下, 以后就可以直接运行 webpack 目录了.
在 终端上输入以下命令, 如果输出 webpack 的版本号 ( 如 3.6.0 ), 说明安装成功.
webpack -v
实现 hello world
使用 npm init 初始化项目
新建一个 hello-webpack 文件夹, 在该文件目录下打开终端, 输入下面的命令:
$ npm init
之后会看到一些提示信息, 不用管, 直接全部回车, 最后, 会发现 hello-webpack 目录下多了一个名为 package.json 的文件, 内容如下:
1
2
3
4
5
6
7
8
9
10
11{
"name": "hello-webpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}整个 json 文件的内容很简单, 主要显示了这个项目的名称、版本、作者、协议等信息。
集成 webpack
目前项目是空的, 没有任何东西, 现在需要把 webpack 集成进来, 让这个项目可以用这个 webpack. 在终端上输入如下命令:
$ npm install –save-dev webpack@3.8.1
安装成功之后会发现 package.json 文件中多了下面这几行代码:
1
2
3"devDependencies": {
"webpack": "^3.8.1"
}创建 JavaScript 文件
创建一个 src 目录, 然后在该目录下创建 app.js 文件, 内容如下:
console.log(“Hello World”);
把 webpack 用起来
现在要把刚才的 js 文件用 weback 编译一下
新建一个 dist 目录, 编译后的文件就报错在 dist 文件中
在终端中输入下面的命令:
$ webpack ./src/app.js ./dist/app.bundle.js
这个命令的意思就是把 ./src/app.js 作为源文件, 把编译后的结果放到 ./dist/app.bundle.js 文件中.
编译成功后, 我们可以在 dist 目录下看到 app.bundle.js 文件.
webpack 的其他用法
上面介绍的只是 webpack 一个最简单的功能, 下面介绍一些其他的用法:
–watch
首先, 在开发环境中, 如果要一边改, 一遍看转换效果, 可以使用 -watch 功能实现, 命令如下:
$ webpack –watch ./src/app.js ./dist/app.bundle.js
现在改动 src/app.js 文件的内容, 就可以看到 dist/app.bundle.js 实时发生变化啦!
-p
之前编译的 app.bundle.js 文件大约有 74 行代码, 差不多 2k 多的大小.
在生产环境, 或线上, 我们不希望这么大的体积, 如果要发布到线上环境, 我们要把它压缩一下.
可以使用 -p 功能来实现: 命令如下
$ webpack -p ./src/app.js ./dist/app.bundle.js
编译成功后, 可以看到 app.bundle.js 文件的体积比之前小了一些, 只有 506 个字节.
webpack 配置文件 webpack.config.js
虽然在命令行中使用 webpack 命令可以实现 webpack 的功能, 但我们一般是不这么做的, 我们使用配置文件来处理
创建配置文件 webpack.config.js
在 package.json 同级目录下新建 webpack.config.js 文件, 内容如下:
1
2
3
4
5
6module.exports = {
entry: './src/app.js',
output: {
filename: './dist/app.bundle.js'
}
}entry 表示输入文件, output 表示输出的目标文件.
直接在终端上输入 webpack 就可以编译文件了. webpack 命令会去找 webpack.config.js 文件, 并读取它的内容, 最后进行相应的处理.
改造 package.json 的 script 部分
我们可以把一些常用的命令脚本, 比如经常要用到的 webpack 命令放到 package.json 中
修改 package.json 文件的 scripts 部分, 代码如下:
1
2
3
4
5
6
7"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack -d --watch",
"prod": "webpack -p"
},
// -d 这个参数的意思是说包含 source maps, 就是让你在用浏览器调试的时候, 可以很方便地定位到源文件分别在命令行运行如下命令:
$ npm run dev
$ npm run prod
你会发现 npm run dev 和 webpack -d –watch 的效果是一样的. 这样做有如下好处:
- 简单维护, 所有的命令都放在一起了, 也能方便查看
- 别人下载了你的源码, 一查看 package.json 就能知道怎么运行这个项目
使用第一个 webpack 插件 html-webpack-plugin
创建 index.html 文件
首先, 在 dist 目录下创建 index.html 文件, 内容如下:
1
2
3
4
5
6
7
8
9
10
11<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Project</title>
</head>
<body>
<script src="app.bundle.js"></script>
</body>
</html>这样的 index.html 文件太死了, 连 js 文件都写死了, 有时候引用的 js 文件是动态变化的, 比如这样的:
1
2
3
4<script src="app.bundle1.js"></script>
<script src="app.bundle2.js"></script>
<script src="app.bundle3.js"></script>
... ...还有一种情况, 有时候为了更好的 cache 处理, 文件名还带着 hash, 例如这样的:
main.9046fe2bf8166cbe16d7.js
这个 hash 是文件的 md5 值, 随着文件的内容而变化, 总不能每变化一次就改一下 index.html 文件吧, 效率太低了.
下面我们使用 webpack 的 html-webpack-plugin 来处理这个问题.
html-webpack-plugin
安装
npm install html-webpack-plugin –save-dev
安装成功后, package.json 文件的 “devDependencies” 选项会多出来一行 “html-webpack-plugin”: “^2.30.1”
使用
现在把之前的 dist/index.html 文件先删除掉, 使用 html-webpack-plugin 插件来自动生成它.
修改 webpack.config.js 文件, 如下:
1
2
3
4
5
6
7
8
9
10
11
12const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/app.js',
output: {
path: __dirname + '/dist',
filename: './dist/app.bundle.js'
},
plugins: [
new HtmlWebpackPlugin(),
]
};最后, 运行一下 npm run dev 命令, 会发现在 dist 目录下生成了 index.html 文件.
更好的使用 html-webpack-plugin
打开 index.html 文件可以看到, 连标题
Webpack App 都自动生成了. 如果不想要这样默认的标题怎么办呢?要改变 title 很简单, HtmlWebpackPlugin 这个方法可以传入很多参数, 下面这样就可以解决这个问题
1
2
3
4
5
6... ...
plugins: [
new HtmlWebpackPlugin({
title: "hello world"
}),
]重新生成 index.html 文件, 可以看到标题已经改变了.
有时候我们要让 index.html 根据我们的意愿来生成. 就是说它的内容是我们自己定的. 可以使用 html-webpack-plugin 的 template 功能来实现, 修改 webpack.config.js 如下:
1
2
3
4
5
6
7... ...
plugins: [
new HtmlWebpackPlugin({
title: "hello world",
template: './src/index.html',
}),
]接着新建 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>
</body>
</html>运行 npm run dev 生成的 dist/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>
<script type="text/javascript" src="./dist/app.bundle.js"></script></body>
</html>下面在看看其他几个参数及结果
filename: “index.html” 默认情况下生成的 html 文件叫 index.html, 如果不想叫这个名字, 可以修改
minify: {
collapseWhitespace: true,
}
// 这个可以把生成的 index.html 文件的内容的没用的空格去掉, 减少空间.
hash: true 为了更好的 cache, 可以在文件名后加个 hash. 如: src=”./dist/app.bundle.js?0b5552db1f811f9c43e0”
1
2
3
4
5
6
7
8
9
10
11
12// 最后的 webpack.config.js 内容如下所示
... ...
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
minify: {
collapseWhitespace: true,
},
hash: true,
}),
]html-webpack-plugin 还有很多其他用法和选项, 参考官方文档.
使用 loader 处理 CSS 和 Sass
什么是 loader
官方的解释是这样的:
loader 用于对模块的源代码进行转换。loader 可以使你在 import 或”加载”模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件!
其实就是处理文件的, 比如把 Scss 转化成 CSS, TypeScript 转化成 JavaScript 等.
用 css-loader 和 style-loader 处理 CSS
新建 app.css 文件并在 app.js 文件中引入
1
2
3
4
5
6
7
8// src/app.css
body {
background: pink;
}
// src/app.js
import css from './app.css';
console.log("hello world");如果现在运行 npm run dev 或者 webpack 命令, 会出现 You may need an appropriate loader to handle this file type. 这样的报错信息.
意思是说, 默认情况下, webpack 处理不了 CSS 的东西, 你需要一个 loader 来处理这个类型的文件.
安装 css-loader 和 style-loader
$ npm install css-loader style-loader –save-dev
在 webpack.config.js 文件中进行配置
1
2
3
4
5
6
7
8
9
10
11
12module.exports = {
... ...
module: {
rules: [
{
// 意思是说, 当检测到 .css 结尾的文件时, 使用 style-loader 和 css-loader 来处理
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
}现在再使用 npm run dev 编译一下, 打开 dist/index.html 可以看到背景色已经变成了粉色了.
编译出来的 app.bundle.js 是包含 CSS 内容的.
用 sass-loader 把 SASS 编译成 CSS
修改文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// src/app.scss 将 src/app.css 改名为 src/app.scss
body {
background: pink;
p {
color: red;
}
}
// src/index.html
<body>
<p>Hello world</p>
</body>
// src/app.js
import css from './app.scss';安装 sass-loader 和node-sass
$ npm install sass-loader node-sass –save-dev
1
2
3
4
5
6
7
8
9
10
11// webpack.config.js
... ...
module: {
rules: [
... ...
{
test: /\.scss$/,
use: [ 'style-loader', 'css-loader', 'sass-loader' ]
}
]
}打包完成后可以看到 p 标签内的文本变成了红色的
使用 extract-text-webpack-plugin 把 CSS 分离成文件
有时候我们要把 SASS 或者 CSS 处理好后, 放到一个 CSS 文件中, 可以使用这个插件来实现
$ npm install extract-text-webpack-plugin –save-dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// webpack.config.js
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
... ...
plugins: [
... ...
new ExtractTextPlugin('style.css')
],
module: {
rules: [
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [ 'css-loader', 'sass-loader' ]
})
}
]
}
}这样编译后就在 dist 目录下生成了 style.css 文件.
并且可以在 index.html 文件中看到 style.css 是通过 link 的方式引入进来的.
初识 webpack-dev-server
一般来说, webpack-dev-server 这个插件在开发环境都会使用到.
我们之前使用 webpack -d –watch 来在开发环境下编译静态文件, 这个功能完全可以使用 webpack-dev-server 来代替.
除此之外, webpack-dev-derver 还有其他功能, 比如在本地开启服务、打开浏览器等.
安装
1
2
3
4// 首先全局安装
$ npm install webpack-dev-server -g
// 然后项目本地安装
$ npm install webpack-dev-server --save-dev运行命令
$ webpack-dev-server
如果看到 The CLI moved into a separate package: webpack-cli 这个报错信息, 根据提示下载 webpack-cli
$ npm install webpack-cli -D
再次运行 webpack-dev-server 命令, 如果看到 throw new Error(‘invalid “instanceof” keyword value ‘ + c); 这个报错信息, 可能是 webpack 版本与 webpack-dev-server 版本不兼容 ( 这里的 webpack 是 ^3.8.1 版本的, webpack-dev-server 是 ^3.1.10 版本的 );
重新下载一个版本的 webpack-dev-server, 例如 ( ^2.11.3 )
$ npm install webpack-dev-server@2.11.3 –save-dev
再次运行 webpack-dev-server 命令, 可以看到 Project is running at http://localhost:8080/ 提示信息
打开浏览器, 输入 localhost:8080, 可以看到和以前一样的效果.
修改默认端口
项目默认是运行在 8080 端口上的, 这个我们可以修改
1
2
3
4
5
6
7
8
9
10
11// webpack.config.js
module.exports = {
... ...
devServer: {
// 修改端口
port: 9000,
// 还可以配置一运行 webpack-dev-server 的时候就会自动打开浏览器
open: true
},
... ...
}
使用 webpack 和 babel 配置 react 开发环境
安装 react
要使用 react, 就必须安装下面两个包
$ npm install react react-dom –save
建立 babel
你可以把 babel 理解为编译器, 它能把 react 代码转成一般浏览器可读可执行的代码, 通常可以用来转化 react 或 vue 这样的前端代码, 或者把 ES6 代码转化成普通的 JavaScript 代码
要让 babel 很好的转化 react 代码, 首先要安装好 babel, 再安装 babel 转化 react 的包
$ npm install babel-core babel-preset-react babel-preset-env –save-dev
创建 .babelrc 文件
1
2
3{
"presets": ["env", "react"]
}
在 webpack 使用 babel-loader
最后我们需要在 webpack 中使用一个 loader 来转化 react 的代码
首先,安装
$ npm install babel-loader –save-dev
然后进行配置
1
2
3
4
5
6
7
8
9// webpack.config.js
module: {
rules: [
... ...
// 这两行是处理 react 相关的内容
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
{ test: /\.jsx$/, loader: 'babel-loader', exclude: /node_modules/ }
]
}
写 react 组件
准备一些 react 的代码, 来测试一下
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// src/index.html
<!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
... ...
import React from 'react';
import ReactDOM from 'react-dom';
import Root from './Root';
ReactDOM.render(
<Root></Root>,
document.getElementById('root')
);
// src/Root.js
import React from 'react';
export default class Root extends React.Component {
render () {
return (
<div style={{textAlign: 'center'}}>
<h1>Hello World</h1>
</div>
);
}
}修改版本问题
由于安装的 babel-core^6.26.3 版本与 babel-loader^8.0.4 版本不匹配, 所以运行 webpack-dev-server 出现了如下错误: babel-loader@8 requires Babel 7.x (the package ‘@babel/core’). If you’d like to use Babel 6.x (‘babel-core’), you should install ‘babel-loader@7’.
根据提示重新安装 babel-loader
$ npm install babel-loader@7.1.5 –save-dev
重新运行 webpack-dev-server 命令, 可以看到浏览器自动打开并展示出了期望的页面样式.
使用 clean-webpack-plugin 来清除文件
一般这个插件是配合 webpack -p 这条命令来清除文件使用的, 就是说在为生产环境编译文件的时候, 先把 build 或 dist ( 就是放生产环境用的文件 ) 目录里的文件先清除干净, 在生成新的.
为什么要使用 clean-webpack-plugin 插件
我们来通过一个例子了解一下
1
2
3
4
5
6
7
8
9
10
11
12
13// webpack.config.js
const path = require('path')
... ...
module.exports = {
entry: {
"app.bundle": './src/app.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[chunkhash].js'
},
... ...
}在终端上运行:
$ npm run prod
1
2
3
4
5// 可以看到 dist 目录下生成了 app.bundle.14fe4a2f90cf9a717bbd.js 文件
dist
├── app.bundle.14fe4a2f90cf9a717bbd.js
├── index.html
└── style.css再把 src/app.js 的内容改改, 然后再执行 npm run prod, 多运行几次可以发现, 生成的带 hash 的 app.bundle.js 文件很多
1
2
3
4
5
6dist
├── app.bundle.0e380cea371d050137cd.js
├── app.bundle.259c34c1603489ef3572.js
├── app.bundle.14fe4a2f90cf9a717bbd.js
├── index.html
└── style.css这些带 hash 的 app.bundle.js 只有最新的才有用, 其他的都没用, 我们要在 build 之前把他们全都清空, clean-webpack-plugin 插件就是用来干这个的.
使用 clean-webpack-plugin
首先安装
$ npm install clean-webpack-plugin –save-dev
然后配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// webpack.config.js
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),
... ...
]
}在运行 npm run dev 可以发现, dist 目录下新生成的 文件只有一个了
1
2
3
4dist
├── app.bundle.3ccf5544bcda830c4ec5.js
├── index.html
└── style.css
配置多个 HTML 文件
之前我们只写了一个 html 文件, 就是 src/index.html, 但是有时候我们是需要多个的, 这个时候该怎么办呢?
之前我们是这样做的, 用了 html-webpack-plugin 这个插件来输出 html 文件.
1 | // webpack.config.js |
我们现在还这么做, 只需要改个名字就好了.
1 | // webpack.config.js |
有个问题, contact.html 使用的 js 和 css 跟 index.html 是一模一样的. 如果我们要让 contact.html 使用跟 index.html 不同的 js, 可以这样来改造一下: ( 只要保证 js 不同, css 也会不同的, 因为 css 是由 js 里 import 的 )
1 | ... ... |
上面的 excludeChunks 指的是不包含, chunks 代表的是包含.
// src/contact.js
console.log( ‘hi from contact.js’ )
结果可以看到, contact 页面里面引用的就只有 contact.js 了.
如何使用 pug (jade) 作为 HTML 的模板
什么是 pug? 如果是 nodejs 程序员的话, 肯定听过 jade 吧, pug 就是从 jade 改名过来的. 说白了, 它就是可以让你以更好的语法来写 html.
我们来看看下面的例子
现在我们要代替之前的 src/index.html 改用 pug 语法来写.
首先把 src/index.html 改名叫 src/index.pug
// 使用命令行重命名
$ rename src/index.html src/index.pug
1 | // src/index.pug |
上面的内容是从 pug 官方的示例中抄的
1 | // webpack.config.js |
安装 pug
$ npm install –save-dev pug pug-html-loader raw-loader
现在可以启动服务, 打开页面看看效果.
现在来试试 pug 的 include 功能, 就是可以包含子模板.
1 | // src/index.pug |
现在再来启动服务来看看效果.
如何使用模块热替换 HMR 来处理 CSS
模块热替换 是什么意思?
以前我们使用的 webpack –watch 或 webpack-dev-server 的功能是监听文件改变, 就自动刷新浏览器, 而这个 模块热替换 不用刷新浏览器, 它是只让修改到的模块, 才会在浏览器上发生相应的变化, 就是生效, 而不是重新刷新浏览器.
所以有了 模块热替换 的功能, 我们来试一下, 改动 CSS 然后浏览器不用刷新就会让页面生效改变.
启用 HMR
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// webpack.config.js
... ...
const webpack = require('webpack');
... ...
modele.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,
// 启用 HMR
hot: true
},
plugins: [
new CleanWebpackPlugin(pathsToClean),
... ...
// 下面这两行是新增加的
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
],
... ...
}启动服务, 可以发现报了一个错误: Cannot use [chunkhash] for chunk in ‘[name].[chunkhash].js’ (use [hash] instead)
文件名不能使用 chunkhash 了, 要使用 hash 来代替 chunkhash.
我们来修改一下:
将: filename: ‘[name].[chunkhash].js’
改成: filename: ‘[name].[hash].js’
处理 extract-text-webpack-plugin
现在试一下改变 src/app.scss 的内容, 会发现页面不动了, 无论怎么改, 页面都不会改变, 也不会刷新.
之前我们是用 extract-text-webpack-plugin 这个插件来处理 CSS 的, 在用 HMR 的时候要先把它关闭一下.
用参数 disable: true 就可以关闭掉.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// webpack.config.js
将: new ExtractTextPlugin("style.css")
改成: new ExtractTextPlugin({
filename: 'style.css',
disable: true
}),
// 然后把处理 scss 文件的 loader 部分变成类似下面这样:
... ...
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'sass-loader']
})
... ...
修改为:
... ...
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
... ...再试试, 能够生效.
为什么要关闭这个插件呢? 其实想想也能知道, 在开发环境下, 用不用 extract-text-webpack-plugin 这个插件意义不大, 把 css 变不变成一个文件, 关系不大, 开发环境只要能调校, 效果能够看到就可以, 但是生产环境需要这个插件, 我们总不能开发环境不使用这个插件, 也导致生产环境也不适用吧.
那么怎么来解决这个问题呢? 也就是说让生产环境使用这个插件, 而开发环境不使用,
生产环境 VS 开发环境
要让生产环境使用 extract-text-webpack-plugin 这个插件, 而开发环境不使用.
其实原理很简单, 只要能区分出那个事开发环境, 那个是生产环境就可以; 只要判断是生产环境的时候就用, 不是的话, 就不用.
增加环境变量
首先来看一下之前的开发环境和生产环境分别使用的编译命令:
1
2
3
4
5// package.json
"scripts": {
"dev": "webpack-dev-server",
"prod": "webpack -p"
},开发环境使用的是 npm run dev 命令; 生产环境使用的是 npm run prod 命令.
我们把它改成下面这样:
1
2
3
4
5"scripts": {
"dev": "webpack-dev-server",
"prod": "NODE_ENV=production webpack -p"
},
// 开发环境的部分不变, 生产环境的加了一个环境变量: NODE_ENV=production很简单, NODE_ENV 是变量名, 而 production 是 NODE_ENV 这个变量的值, 这些都不是固定的, 可以改成你想要的任意内容, 只要能引用到就行.
使用环境变量
要引用我们之前创建的环境变量, 也非常简单
// webpack.config.js
var isProd = process.env.NODE_ENV === ‘production’; // true or false
process.env.NODE_ENV 就能得到之前设置的变量, 如果运行的是 npm run prod, 那么 process.env.NODE_ENV 的值就是 production, 那么 isProd 就是 true; 如果运行的是 npm run dev, isProd 就是 false, 因为 npm run dev 没有设置这个 NODE_ENV 这个环境变量.
前面我们有类似下面这样的两段关于 extract-text-webpack-plugin 这个插件的代码
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
36new ExtractTextPlugin({
filename: 'style.css',
disable: false
}),
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
// 我们把 webpack.config.js 中的代码改成下面这样
... ...
var isProd = process.env.NODE_ENV === 'production';
var cssDev = ['style-loader', 'css-loader', 'sass-loader'];
var cssProd = ExtractTextPlugin.extract({
fallback: 'style-loader',
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 命令了, 再也不用临时关掉一些插件了.
1
2
3
4// 运行 npm run prod 提示 'NODE_ENV' 不是内部或外部命令,也不是可运行的程序 问题
解决方法: 安装 cross-env, 再在 NODE_ENV=xxx 前面添加 cross-env 如
$ npm install cross-env --save-dev
"prod": "cross-env NODE_ENV=production webpack -p"
如何打包图片
我们首先在 src 目录下新建一个 images 文件夹, 然后使用 css 在网站上添加一个背景图片.
1 | // src/app.scss |
然后运行 npm run dev, 你会发现类似这样的报错信息: You may need an appropriate loader to handle this file type.
你需要找到一个适合的 loader 来处理扩展名为 png 类型的文件.
file-loader
官方对这个 loader 是这样定义的:
Instructs webpack to emit the required object as file and to return its public URL
大概意思是: 对一些对象作为文件来处理, 然后可以返回它的URL.
下面我们来使用一下:
先准备一些数据. 之前我们是用 pug 来作为 HTML 的模板的, 现在还原回来, 重新使用 html 作为模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// src/index.html
// webpack.config.js
plugins: [
new CleanWebpackPlugin(pathsToClean),
new HtmlWebpackPlugin({
// 这里不再使用 pug 模板, 重新使用之前的 index.html
template: './src/index.html',
filename: 'index.html',
minify: {
collapseWhitespace: true,
},
hash: true,
excludeChunks: ['contact']
}),
... ...
]安装 file-loader:
$ npm install file-loader –save-dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// webpack.config.js
... ...
module.exports = {
... ...
module: {
rules: [
... ...
{
test: /\.png$/,
use: [
{
loader: 'file-loader',
}
]
}
]
}
}打开控制台可以看到图片的文件名是带着 hash 的, 怎么才能让 file-loader 输出图片的源文件名呢?
file-loader 的参数
file-loader 是可以带参数的, 例如下面这样:
1
2
3
4
5
6
7
8
9
10test: /\.(gif|png|jpe?g|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'images/'
}
}
]/.(gif|png|jpe?g|svg)$/i 表示也可以处理其他格式的图片; [name] 代表文件名; [ext] 代表文件扩展名; outputPath 是输出的路径
现在再看看控制台, 文件名可以显示出来了, 是不带 hash 的.
解析 html 代码里面 img 的标签
前面我们是在 css 里引用图片作为背景的, 但是, 我们经常是在 html 直接使用 src 标签来引用图片的. 例如下面这样:
可以在看到控制台中报了 money-bag.svg 404(Not Found) 的错误. 但是 images 目录下确实是有这个文件的.
其实这是因为缺少一个在 html 代码里处理 img 标签的 html-loader.
官方对 html-loader 的定义是这样的:
Exports HTML as string. HTML is minimized when the compiler demands.
大概意思是说, 把 html 变成导出成字符串的过程中, 还能进行压缩处理 (minimized).
现在来添加这个 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// 首先下载
$ npm install html-loader --save-dev
... ...
{
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
}
}]
}
... ...现在再来试试看, 这张 svg 格式的图片可以显示出来啦.
压缩图片
有时候图片太大了, 我们输出到生产环境的时候, 希望可以让图片文件的体积小点, 我们可以使用 image-webpack-loader 来处理. 这个插件主要是用来压缩图片文件的.
安装:
$ npm install image-webpack-loader –save-dev
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// webpack.config.js
{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'images/'
}
},
{
loader: 'image-webpack-loader',
options: {
bypssOnDebug: true,
}
}
]
},
{
test: /\.html$/,
use: [{
loader: 'html-loader',
options: {
minimize: true
}
}],
}运行命令 npm run prod, 对图片进行压缩处理.
在 dist/images 目录下查看压缩后的文件体积大小. 可以看到压缩后的文件相比之前明显减少.
加载和打包 Twitter Bootstrap 框架
准备工作
先来复制一些 bootstrap 的代码片段.
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// src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button type="button" class="btn btn-default" aria-label="Left Align">
<span class="glyphicon glyphicon-align-left" aria-hidden="true"></span>
</button>
<button type="button" class="btn btn-default btn-lg">
<span class="glyphicon glyphicon-star" aria-hidden="true"></span> Star
</button>
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
Launch demo modal
</button>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Modal title</h4>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</body>
</html>这里使用的是 bootstrap 3.
启动服务, 打开页面可以看到 图标没有显示出来, css 也没有加载到, js 更是不可用.
安装 bootstrap-loader
要加载 bootstrap 框架, 主要是使用这个 bootstrap-loader 这个 loader.
可以查看它的官方文档, 来了解如何安装和使用它.
$ npm install bootstrap-loader@2.2.0 bootstrap-sass –save-dev
$ npm install resolve-url-loader url-loader –save-dev
使用
通过官方文档, 我们来了解一下 bootstrap-loader 这个 loader 如何使用
创建 .bootstraprc 文件
在项目根目录下, 创建 .bootstraprc 文件, 内容复制下面这个链接的内容.
这个内容是官方提供的, 主要存放的是 bootstrap 的配置选项, 就是通过它来控制一些 bootstrap 的功能.
创建 webpack.bootstrap.config.js 文件
在项目跟目录下创建 webpack.bootstrap.config.js 文件, 内容复制下面这个链接的内容.
这个内容是官方提供的, 主要存放的是关于 bootstrap 的 webpack 配置的内容, 它包含生产环境和开发环境的配置.
引用 bootstrap 的 webpack 配置
现在把刚才下载的 webpack.bootstrap.config.js 文件利用起来
1
2
3
4
5
6
7
8
9
10
11// webpack.config.js
const bootstrapEntryPoints = require('./webpack.bootstrap.config')
var bootstrapConfig = isProd ? bootstrapEntryPoints.prod : bootstrapEntryPoints.dev
module.exports = {
entry: {
"app.bundle": './src/app.js',
"contact": './src/contact.js',
"bootstrap": bootstrapConfig
},
... ...
}运行一下 npm run dev, 发现报了一个错误.