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 (

Hello World

); } } ``` 效果如下: ![](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) 先说这么多吧。
';

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
';