18. 构建开发和生产环境-分离配置文件
最后更新于:2022-04-02 01:40:32
## 1. 前言
以前本系列教程的其中一篇文章 [13. 生产环境 vs 开发环境](https://www.rails365.net/articles/webpack-3-ling-ji-chu-ru-men-jiao-cheng-13-sheng-chan-huan-jing-vs-kai-fa-huan-jing) 有写过如何处理开发和线上环境的配置的差异性问题,之前我们是用一个环境变量 `NODE_ENV=production`,这个环境变量是放在命令行中,作为命令行的一部分,比如 `NODE_ENV=production webpack -p`,传入到配置文件`webpack.config.js` 中,由它通过 `process.env.NODE_ENV` 这样来引用,从而来判断是开发环境或生产环境。
我们始终使用的是同一个配置文件,即 `webpack.config.js`,区别不同的环境是通过变量,这节我们来讲下比较普遍使用的作法,也是官方推荐的作法,来实现配置文件的分离。
首先要明白的一点是,为什么要分离成不同的环境配置文件呢?主要是开发和生产环境的差异性比较大,比如我们开发环境需要一个 `webpack-dev-server` 而生产环境不需要,生产环境只需要保证编译出来的文件体积足够小,性能足够好就可以,开发环境也不需要压缩文件,不压缩反而能看得清楚编译后的源码,而生产环境就要保证体积小,所以要压缩编译后的文件。
之前我们也写了不少配置,现在我们就把它们整理一遍,主要是参照官方的这一篇文档: [生产环境构建](https://doc.webpack-china.org/guides/production/),我也把这次的提交放到 [github](https://github.com/hfpp2012/hello-webpack/commit/f437da8069fed37bc934ee42e598e0e5ccaa2a5d) 上了,有兴趣的可以直接来看。
我们根据文档把这个操作实践一遍,这边主要是贴代码加一些简单的讲解。
## 2. 操作
首先把 `webpack.config.js` 一分为二,开发环境的配置文件叫 `webpack.dev.js`,而生产环境的叫 `webpack.prod.js`,除此之外,还要多加一个文件,就是把他们共同的部分抽出来,单独成一个文件,叫 `webpack.common.js`,这样 `webpack.dev.js` 和 `webpack.prod.js` 就不会有太多相同或重复的内容,只要写出他们不同的部分就好了,这样也好维护啊。
```
├── webpack.common.js
├── webpack.dev.js
└── webpack.prod.js
```
抽出来相同的内容为 `webpack.common.js` 再加上差异化的部分 `webpack.dev.js` 和 `webpack.prod.js`,那总要把它们合起来才是可读取的真正的配置文件,如何合起来呢,官方提供了一个工具:webpack-merge。
首先来安装这个工具。
``` bash
$ npm install --save-dev webpack-merge
```
接下来我就要来贴代码啦,贴代码之前,先列一下这次的一些改动:
1. 去掉了 HMR,之前临时为了 HMR 而改的 [name].[hash].js 也改回来了 [name].[chunkhash].js,可以查看回这篇文章 [12. 如何使用模块热替换 HMR 来处理 CSS](https://www.rails365.net/articles/webpack-3-ling-ji-chu-ru-men-jiao-cheng-12-ru-he-shi-yong-mo-kuai-re-ti-huan-hmr-lai-chu-li-css)
2. 用了 DefinePlugin 这个插件 来定义全局变量,参见下面的 webpack.prod.js 文件,关于它的用法可以看这篇文章 [webpack.DefinePlugin使用介绍](https://juejin.im/post/5868985461ff4b0057794959)。
3. 其他一些细微的调整,比如 sass-loader 那部分,还有 svg 文件的处理等。
4. 开发环境使用了 `devtool: 'inline-source-map'`,编译出来的 `bundle` 文件较大。
5. css 使用 contenthash 而不是 chunkhash,文件内容一改变,文件名才改变。
开始贴代码。
**webpack.common.js**
``` javascript
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[chunkhash].js'
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}),
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
minify: false,
hash: process.env.NODE_ENV === 'production',
excludeChunks: ['contact']
}),
new HtmlWebpackPlugin({
template: './src/contact.html',
filename: 'contact.html',
minify: false,
hash: process.env.NODE_ENV === 'production',
chunks: ['contact']
}),
new ExtractTextPlugin({
filename: '[name].[contenthash].css',
disable: false,
}),
],
module: {
rules: [
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader?sourceMap', 'sass-loader?sourceMap']
})
},
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
{ test: /\.jsx$/, loader: 'babel-loader', exclude: /node_modules/ },
{ test: /\.pug$/, loader: ['raw-loader', 'pug-html-loader'] },
{
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',
}]
},
{ test: /\.woff2?$/, loader: 'url-loader?limit=10000&name=[name].[ext]&outputPath=fonts/' },
{ test: /\.(ttf|eot)$/, loader: 'file-loader?name=[name].[ext]&outputPath=fonts/' },
{ test:/bootstrap-sass[\/\\]assets[\/\\]javascripts[\/\\]/, loader: 'imports-loader?jQuery=jquery' },
]
}
};
```
**webpack.dev.js**
``` javascript
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const bootstrapEntryPoints = require('./webpack.bootstrap.config')
module.exports = merge(common, {
entry: {
"app.bundle": './src/app.js',
"contact": './src/contact.js',
"bootstrap": bootstrapEntryPoints.dev
},
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
inline: true,
port: 9000,
open: true,
}
});
```
**webpack.prod.js**
``` javascript
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const bootstrapEntryPoints = require('./webpack.bootstrap.config')
const webpack = require('webpack');
module.exports = merge(common, {
entry: {
"app.bundle": './src/app.js',
"contact": './src/contact.js',
"bootstrap": bootstrapEntryPoints.prod
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
})
]
});
```
最后记得修改一下 `package.json` 文件。
``` json
{
"scripts": {
"dev": "webpack-dev-server --config webpack.dev.js",
"prod": "webpack -p --config webpack.prod.js"
}
}
```
`npm run dev` 的运行结果如下:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/517/2017/37a03ee75fae7866b9ba93e4a56dbdde.png)
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/518/2017/df2d3fed591be6ca779c55d814b44796.png)
`npm run prod` 的运行结果如下:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/519/2017/4dea0f0a230fcce905230b1dca4235a5.png)
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/520/2017/bcbba6af37c7746c7471a682b2063f48.png)
先说这么多吧。
';
17. 轻松通过两个实例来理解 devtool: \’source-map\’ 是什么意思
最后更新于:2022-04-02 01:40:30
# 17. 轻松通过两个实例来理解 devtool: 'source-map' 是什么意思
正如标题所说,有时候,你在看别人的 `webpack.config.js` 文件的配置的时候,你会发现他们可能加了这么一行:
```
devtool: 'source-map'
```
从字面上来想象,`devtool` 好像跟开发有关,`source-map` 好像跟 `源码` 或 `地图` 有关,与其去猜,我们不如通过实例来感受下它真正的意思。
我们这节只是入门教程的其中一篇,不从太深入地角度来理解 `source-map` 的含义,因为它太复杂了,引用一位大牛的话是这么说的,看下面的图片:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/507/2017/303a9cea24c6bcde5002a39300f65d34.png)
下面我们开始来感受下 `source-map` 的魔力。
## 1. 先不使用 `source-map` 的情况
我们先在 js 里随便写一些错误的代码,也就是说你可以乱写一些不存在的方法。
比如下面这样:
**src/app.js**
``` javascript
import css from './app.scss';
...
// 这个 sss 方法不存在,是我随便写的
sss
import $ from 'jquery';
import './jquery.changeStyle';
...
```
**写错代码很正常啊,关键是要懂得如何调试,就是要先找到哪出错,把它改过来就好。**
我们来找一下哪里出错了。
打开浏览器的开发者工具,如下:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/508/2017/07b211e7996c98dc7367c4553b7683a4.png)
接着打开上图中的那个链接,然后:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/510/2017/2c7cbb0eac16842d831c0238643ce1e4.png)
这样会一脸懵懂的,因为仅仅定位到编译后的 `app.bundle.js` 文件是没用的,因为还是找不到源文件,那也就无法改正错误的代码。
## 2. 使用 devtool: 'source-map'
那怎么办呢?很简单。
在 **webpack.config.js** 文件中添加 `devtool: 'source-map'`,如下所示:
``` javascript
module.exports = {
entry: {
...
},
devtool: 'source-map'
}
```
这样再来试一下刚才的调试操作。
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/511/2017/4ac075cc584509a7eecfe82805db09ef.png)
接着看下面的图片:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/512/2017/94aab7811a89dba9302d679da95748f5.png)
我们已经解决了问题,这样就能够查看哪里报错并找到报错的源文件。
刚才我们处理的是 javascript 文件,那 css 文件呢?
我们来看下。
## 3. 处理 css 文件
首先,我们还是先来写一些错的 css 代码。
**src/app.scss**
``` css
body {
background: pink;
p {
/* xxxx 是故意写错的。 */
color: xxxx;
}
}
```
我的 `html` 页面是有 `p` 标签的,我们用开发者工具定位到 `p` 标签的样式中,如下图所示:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/514/2017/33a8e3520d6c69fc10a004964a803459.png)
**从图中可以看出,我们无法调试 css 代码,即使用了 `devtool: 'source-map'` 也没用。**
那怎么办呢?
之前我们是使用下面一些 `loader` 来处理 css 的。(不懂的,可以查看以前的章节)
``` javascript
var cssDev = ['style-loader', 'css-loader', 'sass-loader'];
```
这几个 `loader` 刚好都有个选项叫 `sourceMap`。(这个可以分别查看他们的官网得知)
我们把它设为 true 即可。
我们把上面的代码改成下面这样:
``` javascript
var cssDev = ['style-loader', 'css-loader?sourceMap', 'sass-loader?sourceMap'];
```
我们再来试试效果。
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/515/2017/bfd57fb46a9ff89dfdc2b96755ce15f4.png)
接着,我们点进去之后,得到类似下图所示的情况。
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/516/2017/2355a09b777e3dc2a39004822ffa9266.png)
那这样,我们就可以方便地调试 javascript 和 css 代码了。
至于 devtool 更深层次的内容请参考它的官方文档[Devtool](https://webpack.js.org/configuration/devtool/)
以下是一些参考链接:
* [webpack sourcemap 选项多种模式的一些解释](https://segmentfault.com/a/1190000004280859)
* [[webpack] devtool里的7种SourceMap模式是什么鬼?](https://juejin.im/post/58293502a0bb9f005767ba2f)
先说这么多。
';
16. 使用 ProvidePlugin 插件来处理像 jQuery 这样的第三方包
最后更新于:2022-04-02 01:40:28
# 16. 使用 ProvidePlugin 插件来处理像 jQuery 这样的第三方包
怎么在项目中引用 jQuery 这样的库呢?
想一想,只要在 js 文件里,像 `import React from 'react'` 这样来处理应该就可以,我们来试一下。
首先,安装 jquery。
```
# 注意这里是 --save 而不是 --save-dev,因为要在线上环境上用 jquery
$ npm install --save jquery
```
接下来来使用 jquery。
**src/app.js**
``` javascript
import 'jquery';
// 在 html 中应该有 id 为 "hello" 的元素吧,这点相信大家都懂的。
// 这一行作用是把元素的内容改成 "change to other text"
$("#hello").text('change to other text');
```
遗憾地告诉你,报错了!
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/502/2017/2d6058decc685f3716f64767ca32dace.png)
虽然 `import` 了,但是编译的时候,找不到 `$` 这个标识符。
我们来改进一下:
**src/app.js**
``` javascript
import $ from 'jquery';
$("#hello").text('change to other text');
```
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/503/2017/db7b1be4bf94c700145c72a16a334756.png)
效果出来。
没啥问题,但这不是我们这篇文章要讲的主要内容。
我们考虑一种情况,跟上面的不太一样,你可能会使用各种 jquery 插件。
我们来试试吧,通过实例来体验。
我们来随便写一个简单的 jquery 插件。
**src/jquery.changeStyle.js**
``` javascript
$.fn.changeStyle = function(colorStr){
this.css("color", colorStr);
}
```
这个插件很简单,只是改变元素的颜色。
怎么来引用和使用呢?
跟之前类似。
**src/app.js**
``` javascript
import $ from 'jquery';
import './jquery.changeStyle';
$("#hello").text('change to other text');
// 把元素改成紫色
$("#hello").changeStyle('pink');
```
报错了,跟之前报的错一样。
```
Uncaught ReferenceError: $ is not defined
```
说是 `$` 没定义,可是我们 `import` 了呀。
那把 `import './jquery.changeStyle';` 改成 `import changeStyle from './jquery.changeStyle';` 试一下。
还是没什么卵用。
`src/jquery.changeStyle.js` 文件引用了 jquery 这个插件,可是外面 `src/app.js` 却不知道。
我们来改一下 `src/jquery.changeStyle.js` 文件的内容。
**src/jquery.changeStyle.js**
``` javascript
import $ from 'jquery';
$.fn.changeStyle = function(colorStr){
this.css("color", colorStr);
}
```
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/506/2017/8c539a81f57819ab1da753384ff354c8.png)
效果出来了,这样是可以的。
但是有一个问题啊,上面的 jquery 插件是我们自己随意写的,我们想怎么改都可以,如果是第三方的呢,就是说你有可能从网上下载一个别人写好的。
这个时候,你总不能下载后,再来改吧。
我们怎么做呢?
这个时候要引入 webpack 的一个插件:[ProvidePlugin](https://webpack.js.org/plugins/provide-plugin/)。
这个插件可以有这样的效果。
**不必通过 import/require 使用模块**
把刚才的 **src/jquery.changeStyle.js** 还原一下。
**src/jquery.changeStyle.js**
``` javascript
$.fn.changeStyle = function(colorStr){
this.css("color", colorStr);
}
```
接下来:
**webpack.config.js**
``` javascript
module.exports = {
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}),
...
]
}
```
什么意思呢?很容易理解,以后要遇到或处理 `jQuery` 或 `$` 都会去自动加载 jquery 这个库。
现在我们运行一下 `npm run dev`,效果出来了。
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/506/2017/8c539a81f57819ab1da753384ff354c8.png)
这个插件不止可以处理 jquery,还可以处理别的库,等你慢慢用它吧。
就先到这。
';
15. 加载和打包 Twitter Bootstrap 框架
最后更新于:2022-04-02 01:40:25
# 15. 加载和打包 Twitter Bootstrap 框架
这节主要来实践如何加载和打包 Twitter Bootstrap 框架。
## 1. 准备工作
先来复制一些 bootstrap 的代码片断。
**src/index.html**
``` html
```
**注意,本节使用的是 bootstrap 3,因为目前写这篇文章时,bootstrap 4 还没出正式版,所以我们用 bootstrap 3。**
效果如下:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/497/2017/14dc4e8e5193414ef58441cc332d3600.png)
图标没显示出来,css 也没加载到,js 更是不可用。
## 2. 安装 bootstrap-loader
要加载 bootstrap 框架,主要是使用这个这个 loader:[bootstrap-loader](https://github.com/shakacode/bootstrap-loader)。
现在主要通过查看它的官方文档,来了解如何安装和使用它。
安装。
```
$ npm install bootstrap-loader --save-dev
$ npm install resolve-url-loader url-loader --save-dev
```
## 3. 使用
接下来,我们来看如何使用 [bootstrap-loader](https://github.com/shakacode/bootstrap-loader) 这个 loader。
### 3.1 创建 .bootstraprc 文件
在项目根目录下,创建 `.bootstraprc` 文件,其内容拷贝于下面这个链接的内容。
[.bootstraprc-3-default](https://raw.githubusercontent.com/shakacode/bootstrap-loader/master/.bootstraprc-3-default)
这个内容是官方提供的,主要存放的是 bootstrap 的配置选项,就是通过它来控制一些 bootstrap 的功能。
### 3.2 创建 webpack.bootstrap.config.js 文件
然后在项目根目录下,创建 `webpack.bootstrap.config.js` 文件,其内容拷贝于下面这个链接的内容。
[webpack.bootstrap.config.js](https://raw.githubusercontent.com/shakacode/bootstrap-loader/master/examples/basic/webpack.bootstrap.config.js)
这个内容是官方提供的,主要存放的是关于 `bootstrap` 的 webpack 配置的内容,它包含生产环境和开发环境的配置。
### 3.3 引用 boostrap 的 webpack 配置
现在我们把刚才下载的 `webpack.bootstrap.config.js` 文件利用起来。
**webpack.config.js**
``` javascript
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`,发现报了个错。
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/498/2017/6f263c601614d72a397cdbc5cfda0df0.png)
字体文件没处理好。
通过查看 `bootstrap-loader` 官方的 readme 文档,加上下面几行 loader 的配置,可解决问题。
```
module: {
loaders: [
{ test: /\.(woff2?|svg)$/, loader: 'url-loader?limit=10000' },
{ test: /\.(ttf|eot)$/, loader: 'file-loader' },
],
},
```
再次运行 `npm run dev`,发现下面的页面效果。
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/499/2017/0bcf44017f5e6b20d8993cddb6a1b3c7.png)
字体图标和 css 都没问题了,但是 js 没加载好,点击按钮没有弹出模态框。
查看报错:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/500/2017/d565d3066ee05488fd44a77b566876c3.png)
原来是 jquery 没加载到。
在 `webpack.config.js` 配置文件的 loader 部分加上下面这行:
```
{ test:/bootstrap-sass[\/\\]assets[\/\\]javascripts[\/\\]/, loader: 'imports-loader?jQuery=jquery' },
```
然后在终端上执行下面的命令:
``` bash
$ npm install --save-dev imports-loader jquery
```
即可解决问题。
效果:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/501/2017/c20dee58e49ba92c9574306daa770aaa.png)
点击按钮后,模态框弹出来了,good!
## 4. 优化目录结构
我们运行一下 `npm run prod` 命令,没啥问题,目录结构是下面这样的:
```
dist
├── 448c34a56d699c29117adc64c43affeb.woff2
├── 89889688147bd7575d6327160d64e760.svg
├── app.bundle.f3ffd242134090bbd4b7.js
├── b86262bb1045a2b16a4d9fcf64afc1b1.svg
├── bootstrap.f3ffd242134090bbd4b7.js
├── contact.f3ffd242134090bbd4b7.js
├── contact.html
├── e18bbf611f2a2e43afc071aa2f4e1512.ttf
├── f4769f9bdb7466be65088239c12046d1.eot
├── fa2772327f55d8198301fdb8bcfc8158.woff
├── images
│ ├── glyphicons-halflings-regular.svg
│ └── money-bag.svg
├── index.html
└── style.css
```
比较乱,如果能把 css,js,字体文件分开成各个目录就蛮好的。
我们来改一下配置:
**webpack.config.js**
``` javascript
// css 文件放到 css 目录中
new ExtractTextPlugin({
filename: '[name].css',
disable: !isProd,
publicPath: 'css/'
}),
// 字体文件都放到 fonts 目录中
{ test: /\.(woff2?|svg)$/, loader: 'url-loader?limit=10000&name=[name].[ext]&outputPath=fonts/' },
{ test: /\.(ttf|eot)$/, loader: 'file-loader?name=[name].[ext]&outputPath=fonts/' },
```
运行 `npm run prod` 之后,dist 的目录结构如下:
```
dist
├── app.bundle.0cc9d9267f555d83ccb0.js
├── bootstrap.0cc9d9267f555d83ccb0.js
├── contact.0cc9d9267f555d83ccb0.js
├── contact.html
├── css
│ ├── app.bundle.css
│ └── bootstrap.css
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ ├── glyphicons-halflings-regular.woff2
│ └── money-bag.svg
├── images
│ ├── glyphicons-halflings-regular.svg
│ └── money-bag.svg
└── index.html
```
这样目录结构就比刚才清晰多了。
先说这么多吧。
';
14. 如何打包图片
最后更新于:2022-04-02 01:40:23
# 14. 如何打包图片
这节我们来讲一个比较重要的内容,就是如何打包图片,这也是很多人问的一个问题。
我们首先在网站上加个图片,就在 css 里加,加个背景图。
``` bash
# 在 src 目录下新建 images 目录
$ mkdir src/images
```
**src/app.scss**
``` css
body {
background: url('./images/logo.png') 0 0 no-repeat;
...
}
```
你要确保 `src/images` 下有 `logo.png` 这张图片(随便在网络上找一张)。
然后 `npm run dev`,你会发现类似下面的错误:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/492/2017/a2317c77ab383c319db92f4d878fef0c.png)
只要找到适合的 `loader` 来处理扩展名为 `png` 的图片文件即可。
## 1. file-loader
我找到了一个:[file-loader](https://github.com/webpack-contrib/file-loader)。
官方对这个 `loader` 的定义是这样的:
> Instructs webpack to emit the required object as file and to return its public URL
大概意思是:对一些对象作为文件来处理,然后可以返回它的URL。
还是看下面操作一遍就会知道的。
先准备一些数据。
之前我们是用 `pug`(查看[如何使用 pug (jade) 作为 HTML 的模板](https://www.rails365.net/articles/webpack-3-ling-ji-chu-ru-men-jiao-cheng-11-ru-he-shi-yong-pug-jade-zuo-wei-html-mu-ban)) 来作为 HTML的模板的,我们还原回来,重新使用 html 作为模板。
**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']
}),
...
```
关键时刻来了。
安装。
``` bash
$ npm install --save-dev file-loader
```
**webpack.config**
``` javascript
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.png$/,
use: [
{
loader: 'file-loader',
},
]
},
]
}
};
```
效果如下:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/493/2017/a0eab9a72ee2ce81ff5a8e3b807f9866.png)
这里文件名带着 hash ,我们要如何让 `file-loader` 输出图片的原文件名呢?
## 2. file-loader 的参数
其实,`file-loader` 是可以带参数的,例如下面这样:
```
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` 是输出的路径。
试试效果:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/494/2017/62430b926fd9f062e533619c40e54d9a.png)
good!
## 3. 解析 html 代码里面 img 的标签
忘了一个重要的地方,之前我们是在 CSS 里引用图片作为背景的,但是,我们经常是在 html 直接使用 `src` 标签来引用图片的。
例如下面这样:
``` html
```
点击下载:[money-bag.svg](https://rails365.oss-cn-shenzhen.aliyuncs.com/money-bag.svg)
然而结果是这样的:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/495/2017/c3e63b381628fa7161c24bc381d351ce.png)
**404了,文件找不到,没有成功。**
其实缺少了一个在 html 代码里处理 `img` 标签的 `loader`。
这个 `loader` 是 [html-loader](https://github.com/webpack-contrib/html-loader)
官方对它的定义是这样的:
> Exports HTML as string. HTML is minimized when the compiler demands.
大概意思是说,把 html 变成导出成字符串的过程中,还能进行压缩处理(minimized)。
现在我们来加上这个 `loader`。
先安装。
``` bash
$ npm install --save-dev html-loader
```
``` javascript
...
{
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
}
}],
}
...
```
再试试发现就可以了。
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/496/2017/0bdf3722bf59d61bd19c9173fc0b3dbc.png)
## 4. 压缩图片
有时候图片太大,我们输出到生产环境的时候,希望可以让图片文件的体积小点,webpack 也可以轻易办到,就是自动压缩图片,然后生产环境拿到的图片就会很小。
还是用一个插件,这个插件叫 [image-webpack-loader](https://github.com/tcoopman/image-webpack-loader)。
这个插件主要是来压缩图片文件的。
安装。
``` bash
$ npm install image-webpack-loader --save-dev
```
**webpack.config.js**
``` javascript
{
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
}
}],
}
```
源文件的图片大小情况是这样的:
``` bash
$ 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`):
``` bash
$ 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 文档吧。
先说这么多。
';
13. 生产环境 vs 开发环境
最后更新于:2022-04-02 01:40:21
# 13. 生产环境 vs 开发环境
接着[上一节](https://www.rails365.net/articles/webpack-3-ling-ji-chu-ru-men-jiao-cheng-12-ru-he-shi-yong-mo-kuai-re-ti-huan-hmr-lai-chu-li-css)来,我们要解决上一节所遇到的一个问题。
上一节提到,要让生产环境使用 `extract-text-webpack-plugin` 这个插件,而开发环境不使用,如何做到呢?
其实原理很简单,只要能区分出哪个是开发环境,哪个是生产环境就可以,只要判断是生产环境的时候就用,不是的话,就不用,就可以了。
我们来试一下。
## 1. 增加环境变量
首先来看一下之前的开发环境和生产环境分别使用的编译命令:
**webpack.config.js**
```
"scripts": {
"dev": "webpack-dev-server",
"prod": "webpack -p"
},
```
分别是开发环境使用的 `npm run dev` 命令和生产环境使用的 `npm run prod` 命令。
我们把它改成下面这样:
```
"scripts": {
"dev": "webpack-dev-server",
"prod": "NODE_ENV=production webpack -p"
},
```
开发环境的部分不变,生产环境的加了一个环境变量:
```
NODE_ENV=production
```
很简单,`NODE_ENV` 是变量名,而 `production` 是 `NODE_ENV` 是这个变量的值,这些都不是固定的,你可以改成你想要的任意内容,只要能引用到就行了。
那么我们如何来使用这个变量呢?
## 2. 使用环境变量
要引用我们之前创建的环境变量,也蛮简单的。
在 `webpack.config.js` 文件中:
``` javascript
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` 这个插件的代码。
```
new ExtractTextPlugin({
filename: 'style.css',
disable: false
}),
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
```
我们把 `webpack.config.js` 中的代码更改如下:
``` javascript
...
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` 命令了,再也不用临时关掉一些插件了。
这节就说这么多。
';
12. 如何使用模块热替换 HMR 来处理 CSS
最后更新于:2022-04-02 01:40:19
# 12. 如何使用模块热替换 HMR 来处理 CSS
`模块热替换` 是什么意思?
以前我们使用的 `webpack --watch` 或 `webpack-dev-server` 的功能是监听文件改变,就自动刷新浏览器,而这个 `模块热替换` 不用刷新浏览器,它是只让修改到的模块,才会在浏览器上发生相应的变化,就是生效,而不是重新刷新浏览器。
为什么要这么做呢?有时候模块越多,改得频繁,刷新起来还是很慢的,效率低呀。
所以有了 `模块热替换` 的功能,我们来试一下,让我们一改 CSS 然后浏览器不用刷新就会让页面生效改变。
## 1. 启用 HMR
**webpack.config.js**
``` javascript
devServer: {
port: 9000,
open: true,
}
```
改成下面这样:
```
devServer: {
port: 9000,
open: true,
hot: true
}
```
**webpack.config.js**
``` javascript
...
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()
],
...
};
```
可惜,报错了个错:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/489/2017/e81ccc7779f83e2d02e23466c6c3499b.png)
文件名还不能用 `chunkhash` 了,它说要用 `hash` 来代替 `chunkhash`。
我们来改一下:
```
filename: '[name].[chunkhash].js'
```
变成
```
filename: '[name].[hash].js'
```
## 2. 处理 extract-text-webpack-plugin
现在你试一下改变 `src/app.scss` 的内容,你会发现页面不动了,你无论怎么改,页面都不会改变,也不会刷新。
之前我们是用 `extract-text-webpack-plugin` 这个插件来处理 CSS 的,在用 HMR 的时候要先把它关闭一下。
用一个参数 `disable: true` 就可以关闭掉。
**webpack.config.js**
```
new ExtractTextPlugin("style.css")
```
变成
```
new ExtractTextPlugin({
filename: 'style.css',
disable: true
}),
```
然后把处理 `scss` 文件的 `loader` 部分变成类似下面这样:
```
...
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
//resolve-url-loader may be chained before sass-loader if necessary
use: ['css-loader', 'sass-loader']
})
...
```
变成
```
...
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
...
```
再试试,能够生效。
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/490/2017/1ecfdc2a0205e6fa06a638b8f88f6f30.png)
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/491/2017/80c0f1e3adffb25151134a4584e07c8c.png)
为什么要关闭呢这个插件呢?
其实想想也能知道,在开发环境下,用不用 `extract-text-webpack-plugin` 这个插件,意义不大,你把 css 变不变成一个文件,关系不大,开发环境只要能调效,效果能够看到就可以,但是生产环境需要这个插件,我们总不能开发环境不使用这个插件,也导致生产环境也不使用吧?
那如何解决这个问题呢?也就是说让生产环境使用这个插件,而开发环境不使用,我们下节来讨论这个问题。
先这么多吧。
';
11. 如何使用 pug (jade) 作为 HTML 的模板
最后更新于:2022-04-02 01:40:17
# 11. 如何使用 pug (jade) 作为 HTML 的模板
首先肯定会问什么是 [pug](https://github.com/pugjs/pug),如果是 nodejs 程序员的话,肯定听过 `jade` 吧,`pug` 就是 从 `jade` 改名过来的。
说白了,它就是可以让你以更好的语法来写 html 。
下面看看例子就会清楚的。
现在我们就要代替之前的 `src/index.html` 改用 pug 语法来写。
首先把 `src/index.html` 改名叫 `src/index.pug`
```
$ rename src/index.html src/index.pug
```
**src/index.pug**
```
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.
```
上面的内容是从 `pug` 官方的示例中抄的,然后稍微改了一下。
**webpack.config.js**
```
...
module.exports = {
...
plugins: [
...
new HtmlWebpackPlugin({
template: './src/index.pug',
...
}),
...
],
module: {
rules: [
...
{ test: /\.pug$/, loader: ['raw-loader', 'pug-html-loader'] }
]
}
};
```
```
$ npm install --save-dev pug pug-html-loader raw-loader
```
这样基本没啥问题,来看下结果:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/0e55b27f89ab9bc6f21d03bd04fa594f_961x324.png)
我们来试试 `pug` 的 `include` 功能,就是可以包含子模板。
**src/index.pug**
```
...
body
include includes/header.pug
...
```
**src/includes/header.png**
```
h1 from header pug file
```
目录结构是这样的:
```
src
├── Root.js
├── app.js
├── app.scss
├── contact.html
├── contact.js
├── includes
│ └── header.pug
└── index.pug
```
结果:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/a6133bf0697019fdfba3fbae28203701_1089x364.png)
先这样吧。
';
10. 配置多个 HTML 文件
最后更新于:2022-04-02 01:40:14
# 10. 配置多个 HTML 文件
之前我们只写了一个 html 文件,就是 `src/index.html`,但是有时候我们是需要多个的,这个时候,怎么办呢?
之前我们是这么做的,用了 html-webpack-plugin 这个插件来输出 html 文件。
**webpack.config.js**
```
...
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
minify: {
collapseWhitespace: true,
},
hash: true,
})
...
```
之前怎么做,现在还是怎么做,我们复制一下,改个名字不就好吗?
**webpack.config.js**
```
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
minify: {
collapseWhitespace: true,
},
hash: true,
}),
new HtmlWebpackPlugin({
template: './src/contact.html',
filename: 'contact.html',
minify: {
collapseWhitespace: true,
},
hash: true,
})
```
**src/contact.html**
```
Contact
';
Contact page
``` ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/a76f30a8cf5d49ababc1fb482cacd03d_798x222.png) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/322f3c15e648c159c70d09ffba245aad_1356x163.png) 有个问题,**`contact.html` 使用的 js 和 css 跟 `index.html` 是一模一样的** 如果我要让 `contact.html` 使用跟 `index.html` 不同的 js,如何做呢?(只要保证 js 不同,css 也会不同的,因为 css 也是由 js 里 import 的嘛) 那我们来改造一下: ``` ... 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` 代表的是包含。 **src/contact.js** ``` console.log('hi from contact js') ``` 结果: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/f08a8937c6815f9c3abc262230cb461f_922x254.png) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/385f09e043513de451266f411b329ff6_1188x172.png) 这样就 OK 了。 先说这么多。9. 用 clean-webpack-plugin 来清除文件
最后更新于:2022-04-02 01:40:12
# 9. 用 clean-webpack-plugin 来清除文件
其实 [clean-webpack-plugin](https://github.com/johnagan/clean-webpack-plugin) 很容易知道它的作用,就是来清除文件的。
一般这个插件是配合 `webpack -p` 这条命令来使用,就是说在为生产环境编译文件的时候,先把 `build或dist` (就是放生产环境用的文件) 目录里的文件先清除干净,再生成新的。
## 1. 为什么要用 clean-webpack-plugin
如果还不理解为什么要用它,就看看下面的例子就可以知道的。
**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
```
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/6282ca80966b7974ef9db9f573f2c065_930x280.png)
看看 `dist` 目录:
```
dist
├── app.bundle.e56abf8d6e5742c78c4b.js
├── index.html
└── style.css
```
你再把 `src/app.js` 改改内容,然后再执行 `npm run prod`。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/d57a42692f44dc00e72f54c70a3a5c4b_954x217.png)
再多运行几次,生成的带 hash 的 `app.bundle.js` 文件就会很多。
```
dist
├── app.bundle.0e380cea371d050137cd.js
├── app.bundle.259c34c1603489ef3572.js
├── app.bundle.e56abf8d6e5742c78c4b.js
├── index.html
└── style.css
```
这些带 hash 的 `app.bundle.js` 只有最新的才有用,其他的都没用,我们要在 build 之前把它们全清空,这真是 clean-webpack-plugin 发挥的作用。
## 2. 使用 clean-webpack-plugin
首先来安装。
```
$ npm i clean-webpack-plugin --save-dev
```
**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),
...
new ExtractTextPlugin('style.css')
],
...
};
```
现在运行 `npm run prod` 试试,只有下面的文件:
```
dist
├── app.bundle.0e380cea371d050137cd.js
├── index.html
└── style.css
```
先到这里。
';
8. 用 webpack 和 babel 配置 react 开发环境
最后更新于:2022-04-02 01:40:10
# 8. 用 webpack 和 babel 配置 react 开发环境
相信这个话题很多人都感兴趣,这里就用几个简单的命令就可以搭建出 react 的开发环境。
## 1. 安装 react
要使用 react,就必须装下面两个包的。
``` bash
$ npm install --save react react-dom
```
## 2. 建立 babel
可能你不懂 `babel` 是什么,你可以把它理解为编译器,它能把 `react` 代码转成一般浏览器可读可执行的代码,通常可以用它来转化 `react` 或 `vue` 这样的前端代码,或者把 `es6` 代码转成普通的 javascript 代码等等。
如果还不理解的话,可以看我这篇文章 [babel 入门指南](https://www.rails365.net/articles/babel-ru-men-zhi-nan)。
要让 `babel` 很好的转化 `react` 代码,首先要安装好 `babel`,再装 `babel` 转化 `react` 的包。
运行下面的命令。
``` bash
$ npm install --save-dev babel-core babel-preset-react babel-preset-env
```
创建 `.babelrc` 文件。
```
{
"presets": ["env", "react"]
}
```
为什么我知道要这么做呢?
因为我是分别结合 `babel` 和 `react` 的官网给的最新官方指南。
可以参考下面两个链接:
- [React preset](https://babeljs.io/docs/plugins/preset-react/)
- [React Installation](https://reactjs.org/docs/installation.html)
## 3. 在 webpack 使用 babel-loader
最后我们需要在 webpack 中使用一个 loader 来转化 react 的代码。
首先,安装。
``` bash
$ npm install --save-dev babel-loader
```
**webpack.config.js**
``` javascript
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 组件
接着我们来准备一些 react 的代码,要来测试一下。
**src/index.html**
``` html
Hello World
```
**src/app.js**
``` javascript
import css from './app.scss';
import React from 'react';
import ReactDOM from 'react-dom';
import Root from './Root';
ReactDOM.render(
,
document.getElementById('root')
);
```
**src/Root.js**
``` javascript
import React from 'react';
export default class Root extends React.Component {
render() {
return (
);
}
}
```
效果如下:
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/480/2017/10c0036dbb58d4e7f45fd5fae5cc09ef.png)
参考链接:
- [Setting up Webpack, Babel and React from scratch, revisited](https://stanko.github.io/webpack-babel-react-revisited/)
- [Setup a React Environment Using webpack and Babel](https://scotch.io/tutorials/setup-a-react-environment-using-webpack-and-babel)
- [Setting up React with Webpack 3.0, Yarn and Babel](https://www.codementor.io/goodnesskay/setting-up-react-with-webpack-3-0-yarn-and-babel-9ftd5phqz)
先说这么多吧。
';
Hello World
7. 初识 webpack-dev-server
最后更新于:2022-04-02 01:40:07
现在我们来学习一个最常用的插件 `webpack-dev-server`,一般来说,这个插件,大家都会用,特别是开发环境下。
我们之前使用 `webpack -d --watch` 来在开发环境下编译静态文件,但是这个功能,完全可以用 `webpack-dev-server` 来代替。
除此之外, `webpack-dev-server` 还有其他的功能,比如在本地上开启服务,打开浏览器等。
这节我们主要来简单体验一下 `webpack-dev-server` 的功能。
``` bash
# 先全局安装
$ npm install -g webpack-dev-server
$ npm install --save-dev webpack-dev-server
```
然后运行命令:
``` bash
$ webpack-dev-server
```
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/462/2017/e6c1ff7d21b2a497df4b414a7a2ee546.png)
现在我们用浏览器打开 `localhost:8080` 也可以看到以前的效果。
下面是编译后的源码。
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/463/2017/8694f46c943095e6526eefd5890b1288.png)
默认是运行在 `8080` 端口,这个我们可以改。
**webpack.config.js**
```
var HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: './src/app.js',
...
devServer: {
port: 9000
},
...
};
```
我们还可以配置一运行 `webpack-dev-server` 的时候就自动打开浏览器。
**webpack.config.js**
```
var HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: './src/app.js',
...
devServer: {
port: 9000,
open: true
},
...
};
```
以后都会一直用 `webpack-dev-server` 的啦。
先这样吧。
';
6. 使用 loader 处理 CSS 和 Sass
最后更新于:2022-04-02 01:40:05
# 6. 使用 loader 处理 CSS 和 Sass
## 1. 什么是 loader
官方的解释是这样的:
> loader 用于对模块的源代码进行转换。loader 可以使你在 import 或"加载"模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件!
可能会一脸懵懂吧。
说白了,就是 `loader` 类似于 task,能够处理文件,比如把 Scss 转成 CSS,TypeScript 转成 JavaScript 等。
再不明白的话,还是用实例来说明吧。(其实它的概念并不重要,你会用就行)
## 2. 用 [css-loader](https://github.com/webpack-contrib/css-loader) 和 [style-loader](https://github.com/webpack-contrib/style-loader) 处理 CSS
现在我们来演示一下如何用 `loader` 来处理 CSS 文件。
先准备好内容。
**src/app.css**
```
body {
background: pink;
}
```
**src/app.js**
```
import css from './app.css';
console.log("hello world");
```
如果你现在运行 `npm run dev` 或 `webpack` 命令,就会出现类似下面的提示错误。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/dfdf436f72b9e1af14ac095c1e2283c7_1066x392.png)
意思就是说,默认情况下,`webpack` 处理不了 CSS 的东西。
我们来处理这个问题。
```
$ npm install --save-dev css-loader style-loader
```
**webpack.config.js**
```
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,
})],
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
]
}
};
```
我们来看下效果:
**dist/index.html**
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/fe0bba903a190b1265f4885249649fb2_1160x99.png)
编译出的内容跟之前的差不多。
我们用浏览器打开 `dist/index.html` 文件。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/3ca72a1bfbe2d853ed6d0cf0650c4513_1062x642.png)
编译出的 `app.bundle.js` 文件是有包含 CSS 的内容的。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/8425eca0134233b09639638d0d74f2a9_1057x641.png)
## 3. 用 [sass-loader](https://github.com/webpack-contrib/sass-loader) 把 SASS 编译成 CSS
应该都知道 SASS 是什么吧,不懂的话可以查一下。
说白了,就是可以用更好的语法来写 CSS,比如用嵌套。看下面的例子应该就会理解的。
把 `src/app.css` 改名为 `src/app.scss`
**src/app.scss**
```
body {
background: pink;
p {
color: red;
}
}
```
**src/index.html**
```
Hello World
';
hello world
``` **src/app.js** ``` import css from './app.scss'; console.log("hello world"); ``` 安装(中间可能要下载二进制包,要耐心等待) ``` $ npm install sass-loader node-sass --save-dev ``` **webpack.config.js** ``` 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, })], module: { rules: [ { test: /\.scss$/, use: [ 'style-loader', 'css-loader', 'sass-loader' ] } ] } }; ``` 效果如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/0afd61616a015744096cb4914d0bfe26_982x662.png) ## 4. 用 [extract-text-webpack-plugin](https://github.com/webpack-contrib/extract-text-webpack-plugin) 把 CSS 分离成文件 有时候我们要把 SASS 或 CSS 处理好后,放到一个 CSS 文件中,用这个插件就可以实现。 ``` $ npm install --save-dev extract-text-webpack-plugin ``` **webpack.config.js** ``` var HtmlWebpackPlugin = require('html-webpack-plugin'); const ExtractTextPlugin = require('extract-text-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, }), new ExtractTextPlugin('style.css') ], 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'] }) } ] } }; ``` 在 `dist` 目录下生成了 `style.css` 文件。 **dist/style.css** ``` body { background: pink; } body p { color: red; } ``` **dist/index.html** ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/921287859e50295f312fe82af197722a_1152x96.png) 先说这么多吧。5. 使用第一个 webpack 插件 html-webpack-plugin
最后更新于:2022-04-02 01:40:03
# 5. 使用第一个 webpack 插件 html-webpack-plugin
之前我们已经可以转化 js 文件了,但是一般来说,我们放在网页上的是 html 页面。
现在我们就把 html 和 js 还有 webpack 结合来玩玩。
很简单,只要把 js 文件引入到 html 中就好。
## 1. 创建 index.html
首先在 `dist` 目录下创建 `index.html` 文件,其内容如下:
```
Project
```
这样,你在服务器上把这个 `index.html` 和 `app.bundle.js` 放到网站根目录中,用 nginx 托管起来,就可以用了。
前端的项目不就是这样处理的吗?
但是,我一般不会这么做,我会用更好的方式来处理这个问题。
为什么呢?
因为 `index.html` 文件太死了,连 js 文件都写死了,有时候引用的 js 文件是动态变化的呢?
打个比方,类似下面这种例子:
```
```
而且还不确定有多少个。
还有一种情况,有时候为了更好的 cache 处理,文件名还带着 hash,例如下面这样:
`main.9046fe2bf8166cbe16d7.js`
这个 hash 是文件的 md5 值,随着文件的内容而变化,你总不能每变化一次,就改一下 `index.html` 文件吧?
效率太低!
下面我们要使用一个 `webpack` 的插件 [html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin) 来更好的处理这个问题。
## 2. html-webpack-plugin
webpack 吸引人的地方就是因为它有太多的插件,有时候一些需求,一个插件就搞定。
**这么多插件,我们不可能全都学,全都用,要用也是找最好的,最常用的来玩,而且学了一个,其他的也差不多,掌握方法就好。**
**学习插件的第一步,是进入其主页,先把它的 `readme` 文档看看,至少知道它是干什么的,能解决什么问题,最后知道如何用就行了。**
### 2.1 安装
先来安装,一条命令就好。
```
$ npm install html-webpack-plugin --save-dev
```
安装成功后,`package.json` 这个文件会多出一行 `"html-webpack-plugin": "^2.30.1",`,如下所示:
```
{
"name": "hello-wepback",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack -d --watch",
"prod": "webpack -p"
},
"author": "",
"license": "ISC",
"devDependencies": {
"html-webpack-plugin": "^2.30.1",
"webpack": "^3.8.1"
}
}
```
### 2.2 使用
现在我们把之前的 `dist/index.html` 先删除掉,我们要用 `html-webpack-plugin` 这个插件来自动生成它。
把 `webpack.config.js` 文件改一下,如下所示:
```
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/app.js',
output: {
path: __dirname + '/dist',
filename: 'app.bundle.js'
},
plugins: [new HtmlWebpackPlugin()]
};
```
最后,运行一下上文所说的 `npm run dev` 命令,你会发现在 `dist` 目录生成了 `index.html` 文件,打开来看下。
```
Webpack App
```
连标题 `Webpack App ` 都自动生成了,如果这是固定的话,就不太灵活,但是 `html-webpack-plugin` 有选项来处理这个问题。
## 3. 更好的使用 html-webpack-plugin
要改变 `title` 很简单,上文提到 `HtmlWebpackPlugin` 这个方法可以传入很多参数的,下面这样就可以解决这个问题。
```
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/app.js',
output: {
path: __dirname + '/dist',
filename: 'app.bundle.js'
},
plugins: [new HtmlWebpackPlugin({
title: "hello world"
})]
};
```
再去看看新生成的 `index.html` 文件,是不是变化了。
```
hello world
```
只是改变了一点点东西,其实也没多大用处,有时候我们要让 `index.html` 根据我们的意愿来生成。就是说它的内容是我们自己定的。
这个就不得不提到 `html-webpack-plugin` 的 `template` 功能。
把 `webpack.config.js` 更改如下:
```
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',
})]
};
```
接着新建 `src/index.html` 文件,内容如下:
```
Hello World
```
我们再来看看新生成的 `dist/index.html` 文件,内容如下:
```
Hello World
```
下面我再来介绍几个参数,以及它的结果。
`filename: 'index.html'` 默认情况下生成的 html 文件叫 `index.html`,但有时候你不想叫这个名字,可以改。
```
minify: {
collapseWhitespace: true,
},
```
这个可以把生成的 `index.html` 文件的内容的没用空格去掉,减少空间。
效果如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/b555f89863776bc2d608312b3c06dbc0_2336x184.png)
`hash: true` 为了更好的 cache,可以在文件名后加个 hash。(这点不明白的先跳过)
效果如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/b4065ca28d8bd25352c43722bb4476d3_915x110.png)
最后的 `webpack.config.js` 内容大约是下面这样的:
```
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,
})]
};
```
`html-webpack-plugin` 肯定还有更多的用法和选项,这个只能根据需要慢慢探究了。
先说这么多。
';
4. webpack 的配置文件 webpack.config.js
最后更新于:2022-04-02 01:40:01
# 4. webpack 的配置文件 webpack.config.js
在命令行中运行 `webpack` 命令确实可以实现 `webpack` 的功能,但是我们一般不这么做,我们要用配置文件来处理。
我们把之前学到的知识用 `webpack` 的配置文件来实现,配置文件的名字叫 `webpack.config.js` 位于项目根目录下。
## 1. 创建配置文件 webpack.config.js
它的内容如下:
```
module.exports = {
entry: './src/app.js',
output: {
filename: './dist/app.bundle.js'
}
};
```
简单解释一下: `entry` 表示源文件,`output` 这边表示的是输出的目标文件。
很简单吧!
那怎么用呢?
直接在终端上输入 `webpack` 就可以了。`webpack` 命令会去找 `webpack.config.js` 文件,并读取它的内容(源文件和目标文件),最后进行相应的处理。
如下所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/c72cb1ed918cf9e8b7a565bbe62cc788_921x419.png)
当然,`webpack.config.js` 的内容不止这么简单,可以更复杂些,我们以后再来介绍。
## 2. 改造 package.json 的 scripts 部分
还记得上次说过的 `package.json` 这个文件吗?它主要放了一些项目的介绍信息,除此之外,它还要一个重要的功能。
就是可以放一些常用的命令行脚本,比如我们可以把我们经常要用的 `webpack` 命令放到这里来。
我把它改了一下,变成类似下面这样:
```
{
"name": "hello-wepback",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "webpack -d --watch",
"prod": "webpack -p"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^3.8.1"
}
}
```
改动的内容主要是增加了下面几行:
```
"scripts": {
"dev": "webpack -d --watch",
"prod": "webpack -p"
},
```
怎么用呢?
很简单,分别是
```
$ npm run dev
```
和
```
$ npm run prod
```
你会发现 `npm run dev` 和 `webpack -d --watch` 的效果是一样的。
`-d` 这个参数之前没介绍过,它的意思就是说包含 source maps,这个有什么用呢,就是让你在用浏览器调试的时候,可以很方便地定位到源文件,知道这个意思就好了,不用深究太多。
你会想,为什么要用 `package.json` 的 `scripts` 功能呢?
我觉得主要有两个原因吧:
第一:简单维护,所有的命令都放一起了,也能方便地查看
第二:别人下载了你的源码,一查看 `package.json` 就能知道怎么运行这个项目。
先说这么多。
';
3. 实现 hello world
最后更新于:2022-04-02 01:39:58
# 3. 实现 hello world
现在我们要先把 webpack 用起来。
为了方便,我们先用 npm 创建一个空项目。
## 1. 用 npm init 初始化项目
打开终端,运行如下命令:
```
# 随便进一个目录
$ cd ~/codes
# 创建一个存放 webpack 项目的目录,名为 hello-webpack
$ mkdir hello-webpack
$ npm init
```
之后你会看到会提示你输入一些内容,你不用管,直接全部回车:
```
name: (hello-wepback)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
```
最后,你会发现 `hello-webpack` 目录下多出了一个名为 `package.json` 的文件。
它的内容如下:
```
{
"name": "hello-wepback",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
```
整个 json 文件的内容很简单,主要是显示这个项目的名称、版本、作者、协议等信息,一看就能很清晰。
具体的信息这里我们先按下不表,以后我们会跟这个文件经常打交道的。
## 2. 集成 webpack
现在项目是空的,没有任何东西,我们现在需要把 webpack 集成进来,让这个项目可以用这个 webpack。
我们在终端上输入如下命令:
```
$ npm install --save-dev webpack
```
你会看到正在安装 webpack 的进度,稍等片刻,成功之后,我们再来看看 `package.json` 这个文件的内容。
```
{
"name": "hello-wepback",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^3.8.1"
}
}
```
多了下面这几行:
```
"devDependencies": {
"webpack": "^3.8.1"
}
```
什么意思呢?就是说,我现在这个项目依赖于 webpack 这个工具,就算以后别人得到这个 `package.json` 文件,就会知道要安装这个 webpack 了。
同时你也会发现,多了一个目录,叫 `node_modules`,这个就是放刚才安装的 webpack 这个库的所有要用到的源码文件。
这点先了解这么多,其实知道大概的意思就行。
## 3. 创建 javascript 文件
现在项目创建了,webpack 也集成到项目中了,该是要把 webpack 玩起来的时候了。
首先创建一个目录叫 `src`,然后在该目录下创建 javascript 文件,叫 `app.js`。
这个文件的内容最简单,就输出 `hello world`,如下所示:
```
console.log('hello world');
```
## 4. 把 webpack 用起来
现在要把刚才的 js 文件用 webpack 编译一下。
编译后输出的文件,我们放到一个目录中,就叫 `dist` 好了。
先把这个目录创建好。
现在的目录结构是这样的:
```
.
├── dist
├── node_modules
├── package.json
└── src
└── app.js
```
OK,现在开始转化,在终端上输入如下命令:
```
$ webpack ./src/app.js ./dist/app.bundle.js
```
意思就是说,把 `./src/app.js` 作为源文件,把转化后的结果放到 `./dist/app.bundle.js` 文件中。
下面是输出的结果:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/62496eb94262b6cbb1bf28532d2c93e7_848x256.png)
成功了!
果然,在 `dist` 目录下生成了 `app.bundle.js` 文件。
它的内容如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/7e7439d02b1e99b5fe27d5915483ed7e_986x543.png)
大约总共有 74 行,大小约是2.5 kb,可以看出多出了不少东西,但至少 `hello world` 那一行源码被包含进来了。
具体的内容,你打开转化后的文件看看就知道了。
## 5 webpack 的其他用法
上面介绍的只是 webpack 一个最简单的功能,它可不止有这个用法,还有其他的,我们来介绍一下。
### 5.1 --watch
首先,在开发环境中,总是要一边改,一边看转化效果吧,webpack 也能办到,多加一个参数就好。
```
$ webpack --watch ./src/app.js ./dist/app.bundle.js
```
输出效果:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/63680006fb2bac6be465f0520d6fe751_489x174.png)
现在去改改 `src/app.js` 文件的内容,试试效果,看看 `dist/app.bundle.js` 是否实时变化了。
### 5.2 -p
之前转化的 `app.bundle.js` 文件大约有 74 行代码,差不多 2k 多的大小,好大啊,毕竟我们的代码只有一行而已。
在生产环境,或线上,我们肯定不希望这么大的体积,毕竟体积越大,带宽浪费就越多呀,下载也越慢。
如果要发布到线上环境,我们要把它压缩一下的。
而 webpack 本来就有这样的功能,也只是一个参数 `-p`
```
$ webpack -p ./src/app.js ./dist/app.bundle.js
```
输出如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/bbb7ddd0947e1076d1a5cf683fae9c22_443x131.png)
可以看到,输出的文件相比以前的 2.5 kb 小了一些,大约 505 个字节。
我们打开来看下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/6e4aa43b7a65bfc2ad48ff66c420eb7c_2180x298.png)
好了,先说这么多吧。
';
2. 安装
最后更新于:2022-04-02 01:39:56
# 2. 安装
## 1. 安装 nodejs
要使用 webpack,必须确保电脑上存在着 nodejs 这个运行环境,所以,如果没有 nodejs,要先安装它。
在浏览器输入下面的网址:
界面如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/88e47d784286b1f60e635e8f81637b33_1632x788.png)
下载安装包后,点击可执行文件,不断地按下一步,就可以安装成功。
最后打开命令行终端,输入以下命令。
```
$ node -v
```
应该会显示所安装的 nodejs 的版本,比如我的:
```
v7.8.0
```
这样就表示电脑上有 nodejs 的环境了。
## 2. 安装 webpack
下一步,就可以安装 webpack 了。
在命令行终端上输入以下命令:
```
$ npm install -g webpack
```
> npm 是 nodejs 管理插件用的工具,install 表示安装,-g 表示全局安装,这样会把可执行文件 webpack 放到 bin 目录下,以后就可以直接运行 webpack 目录了。
我们来检测一下是否把 webpack 安装成功了。
在终端上输入以下命令:
```
webpack -v
```
输出 webpack 的版本如下:
```
3.6.0
```
> 值得一提的是,如果用国内的网络安装 npm 包会很慢的话,可以考虑用一下淘宝的源,具体可以看 或
';
1. 介绍
最后更新于:2022-04-02 01:39:54
## 1. [webpack](https://github.com/webpack/webpack) 是什么?
![](https://rails365.oss-cn-shenzhen.aliyuncs.com/uploads/photo/image/320/2017/5734645b60521d83d889a7716ff5a542.svg)
先来说一下 `webpack` 是什么。
`webpack` 的官方对它是这样定义的:
> `webpack` is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.
中文的大概意思是说:
> `webpack` 可以看做是模块打包机:它做的事情是,分析你的项目结构,找到 `JavaScript` 模块以及其它的一些浏览器不能直接运行的拓展语言(`Scss`,`TypeScript` 等),并将其转换和打包为合适的格式供浏览器使用。
用大白话可以这样说:
> `webpack`是一个前端模块化方案,更侧重模块打包,我们可以把开发中的所有资源(图片、js 文件、css 文件等)都看成模块,通过 `loader`(加载器)和 `plugins`(插件)对资源进行处理,打包成符合生产环境部署的前端资源。
如果这样还不明白的话,我们来说下前因后果。
在当今的社会,作为 web 开发,会越来越意识到前端的重要性,随着 `HTML5`、 `CSS3`、 `ES6` 各种技术的发展,前端的开发越来越宠大。甚至有些应用就是单页面应用(SPA),纯 `JavaScript` 开发,`JavaScript` 文件的管理也是一个问题。`JavaScript` 模块化编程,已经成为一个迫切的需求,这就出现了 `JavaScript` 的模块解决方案,以前是用 `requirejs` 或 `seajs`,而现在则是用 `webpack`。
举个例子,很多人开发了各种优秀的 `JavaScript` 模块或组件,我们不想重复发明轮子,而是想直接利用别人的模块,就是类似 `require` 或 `include` 这样的机制,把别人的模块引入进来,但是 `JavaScript` 又没有 `类`或`包` 这样的概念,那应该如何做呢?
如何去引入别人的模块?引入之后保证各种依赖关系不出错?这就是 `webpack` 要解决的问题。
模块化的概念我们理解了,那如何理解 `打包` 这个词呢?
其实,模块化的问题解决之后,`webpack` 就能把各种资源模块打包合并成一个文件输出给浏览器。在打包的过程中还能对这些资源进行处理,比如压缩减少体积,把 `sass` 编译成 `css`, `coffee` 编译成 `js`。所以它在某些程度上,跟 `grunt/gulp` 的功能有些相同。至于与 `grunt/gulp` 的不同之处,我们下面会讲到。
## 2. 与 `grunt/gulp` 的区别
`grunt/gulp` 的定义是 `Task Runner`。它有点像 `ruby` 的 `Rake`或 `Thor`,如果你不懂 `ruby`,那 `c/cpp`语言的 `make`,这应该总知道吧。它是一种写任务的工具,只是 `grunt/gulp` 是用 `JavaScript` 来写 task 而已。
`grunt/gulp` 强调的是前端开发的工作流程,我们可以通过配置一系列的 task,定义 task 处理的事务(例如文件压缩合并、雪碧图、启动 server、版本控制等),然后定义执行顺序,来让 `grunt/gulp` 执行这些 task,从而构建项目的整个前端开发流程。
``` javascript
const gulp = require('gulp');
const babel = require('gulp-babel');
// gulp.src 会指定源文件,然后通过 pipe 函数把内容传给下个处理方法,最后 gulp.dest 是输出处理后的文件内容。
gulp.task('default', () =>
gulp.src('src/app.js')
.pipe(babel({
presets: ['es2015']
}))
.pipe(gulp.dest('dist'))
);
```
打个比方,如果你的工程模块依赖很简单,不需要把 js 或各种资源打包,只需要简单的合并、压缩,那就不需要 webpack。grunt/gulp 就够用了。反过来,如果你的工程庞大,页面中使用了很多库(SPA很容易出现这种情况),那就可以选择使用 `webpack`,因为这样既能做到模块化管理,也能做到 `grunt/gulp` 的一些功能,比如压缩,转化 `coffeescript` 为 `js` 等。
> `gulp` 也能和 `webpack` 结合起来用,`gulp` 里面有个 [webpack-stream](https://github.com/shama/webpack-stream) 插件。就是让 `webpack` 专门去做 module dependency 的事情, 生成一个 `bundle.js` 文件,然后再用 `gulp` 去做一些其他杂七杂八 minify, uglify 的事情。 后来人们发现 `webpack` 有个 `plugins` 的选项, 可以用来进一步处理经过 `loader` 生成的 `bundle.js`,于是有人写了对应的插件, 所以 minify/uglify, 生成 hash 的工作也可以转移到 `webpack` 本身了,挤掉了 `gulp` 这部分的市场份额。 再后来大家有发现 `npm/package.json` 里面的 scripts 原来好好用啊,调用任务的时候就直接写一个简单的命令,因为 `gulp` 也不就是各种插件命令的组合呀,大部分情况下越来越不需要 `gulp/grunt` 之类的了。 所以你现在看到的很多新项目都是`package.json` 里面 scripts 写了一堆,外部只需要一个 `webpack` 就够了。(摘自网络 https://segmentfault.com/q/1010000008058766)
最后总结一下:
虽然都是前端自动化构建工具,但看他们的定位就知道不是对等的。
`grunt/gulp` 严格上讲,模块化不是他强调的东西,他旨在规范前端开发流程。
`webpack` 更是明显强调模块化开发,而那些文件压缩合并、预处理等功能,不过是他附带的功能。
## 3. 跟 Browserify 相比
`webpack` 与其和 `grunt/gulp` 相比较,还不如跟 `Browserify` 比较,因为它们两者更相近,不过好像 `Browserify` 应该被 `webpack` 代替了吧,我对 `Browserify` 了解也不多,在此就不细说了。
## 4. 优势
1. `webpack` 不仅仅能处理 js, 也能处理 css, 也能处理 html,甚至是图片等各种前端资源。
2. 它开发便捷,仅仅使用一个配置文件,就能替代部分 `grunt/gulp` 的工作,比如打包、压缩混淆、图片转 base64等。
3. 扩展性强,插件机制完善。
## 5. 为什么要学习 `webpack`
现在最流行的 `react`、`vue`、`angular` 等技术,你要学习和使用它们,难免会碰到 `webpack`,因为一般都会用 `webpack` 来构建前端的开发环境,这样,我们还有什么理由不学习呢?
';
0. 开始
最后更新于:2022-04-02 01:39:52
# webpack 3 零基础入门教程
最详细,最简单的零基础 webpack 3 入门教程,人人都能学会。
原文发布于我的个人博客:https://www.rails365.net
源码位于:https://github.com/hfpp2012/webpack-tutorial
项目源代码位于:https://github.com/hfpp2012/hello-webpack
### 联系我:
email: hfpp2012@gmail.com
qq: 903279182
';