插件

我们已经看到一个内置的webpack插件的例子,在npm run build脚本中调用的webpack -p命令就是使用webpack附带的UglifyJsPlugin插件以生产模式压缩打包文件。

加载器可以对单个文件运行转换,插件可以运行在更大的代码块上。

公共代码

commons-chunk-plugin是webpack附带的另一个核心插件,用于创建一个单独的模块,为多个入口文件分享公共代码。到目前为止,我们一直在使用单个入口文件和单个输出打包文件。在许多实际场景中,你将受益于将其分解为多个输入和输出文件。

如果你的应用程序有两个不同的区域需要分享某个模块,例如:用于面向公共应用程序的app.js、用于管理区域的admin.js,你可以像这样为其创建单独的入口点:

// webpack.config.js
const webpack = require('webpack')
const path = require('path') const extractCommons = new webpack.optimize.CommonsChunkPlugin({
name: 'commons',
filename: 'commons.js'
}) const config = {
context: path.resolve(__dirname, 'src'),
entry: {
app: './app.js',
admin: './admin.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js'
},
module: {
// ...
},
plugins: [
extractCommons
]
} module.exports = config

注意output.filename的变化,现在包含了[name],它会被替换为块名称。因此我们可以从这个配置中得到两个输出文件、也是我们的两个入口文件:app.bundle.jsadmin.bundle.js

commonschunk插件生成第三个文件commons.js,其中包含的是我们入口文件需要的公共模块。

// src/app.js
import './style.scss'
import {groupBy} from 'lodash/collection'
import people from './people' const managerGroups = groupBy(people, 'manager') const root = document.querySelector('#root')
root.innerHTML = `<pre>${JSON.stringify(managerGroups, null, 2)}</pre>`
// src/admin.js
import people from './people' const root = document.querySelector('#root')
root.innerHTML = `<p>There are ${people.length} people.</p>`

这些入口文件将输出以下文件:

  • app.bundle.js包括stylelodash/collection模块
  • admin.bundle.js不包含额外的模块
  • commons.js包括我们的people模块

然后我们可以在两个区域中引入共享模块:

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Hello webpack</title>
</head>
<body>
<div id="root"></div>
<script src="dist/commons.js"></script>
<script src="dist/app.bundle.js"></script>
</body>
</html>
<!-- admin.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Hello webpack</title>
</head>
<body>
<div id="root"></div>
<script src="dist/commons.js"></script>
<script src="dist/admin.bundle.js"></script>
</body>
</html>

在浏览器中加载index.htmladmin.html可以看到它们自动的创建了通用模块。

提取CSS

另一个流行的插件是extract-text-webpack-plugin,可用于将模块提取到自己的输出文件中。

下面我们将修改.scss规则来编译Sass,加载CSS,然后将其提取到自己的CSS打包文件中,从而将其从JavaScript打包文件中删除。

npm install extract-text-webpack-plugin@2.0.0-beta.4 --save-dev

// webpack.config.js
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const extractCSS = new ExtractTextPlugin('[name].bundle.css') const config = {
// ...
module: {
rules: [{
test: /\.scss$/,
loader: extractCSS.extract(['css-loader','sass-loader'])
}, {
// ...
}]
},
plugins: [
extractCSS,
// ...
]
}

重新启动webpack,你应该看到一个新的包app.bundle.css,你可以像往常一样直接引用它。

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Hello webpack</title>
<link rel="stylesheet" href="dist/app.bundle.css">
</head>
<body>
<div id="root"></div>
<script src="dist/commons.js"></script>
<script src="dist/app.bundle.js"></script>
</body>
</html>

刷新页面以确认我们的CSS已经被编译并且从app.bundle.js移动到app.bundle.css中。成功!

代码分割

我们已经了解了分割代码几种方法:

  • 手动创建单独的入口文件
  • 将共享代码自动拆分成公共块
  • 使用extract-text-webpack-plugin从我们的编译包中提取出块文件

另一个分割代码的方法是使用System.import require.ensure。通过在这些函数中封装代码块,你可以在运行时创建一个按需加载的模块。这可以显著提高加载时间性能,因为在开始时不向客户端发送所有内容。System.import使用模块名称作为参数,并返回一个Promise。require.ensure需要一个依赖关系的列表,一个回调和一个可选的模块的名称。

如果你的应用中有一段依赖于应用其他部分不需要的依赖,那最好把它分离成单独的包。我们通过添加一个名为dashboard.js的新模块来演示一下,这个模块需要引入d3模块。

npm install d3 --save
// src/dashboard.js
import * as d3 from 'd3' console.log('Loaded!', d3) export const draw = () => {
console.log('Draw!')
}

app.js的底部导入dashboard.js

// ...

const routes = {
dashboard: () => {
System.import('./dashboard').then((dashboard) => {
dashboard.draw()
}).catch((err) => {
console.log("Chunk loading failed")
})
}
} // demo async loading with a timeout
setTimeout(routes.dashboard, 1000)

因为我们添加了异步加载模块,所以我们需要在配置文件中使用一个output.publicPath属性,以便让webpack知道在哪里获取它们。

// webpack.config.js

const config = {
// ...
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '/dist/',
filename: '[name].bundle.js'
},
// ...
}

重新启动构建,你会看到一个神秘的新打包文件0.bundle.js

webpack为了提醒你,使用[big]来突出显示较大的包,

这个0.bundle.js将根据需要使用JSONP请求获取,因此直接从文件系统加载文件不会再加载它。我们需要运行一个服务器,任何服务器都可以。

python -m SimpleHTTPServer 8001

打开http://localhost:8001/

加载后一秒钟,你应该看到一个指向我们动态生成的打包文件 /dist/0.bundle.js的GET请求和打印到控制台的“Loaded!”。成功!

Webpack Dev Server

实时重新加载可以通过在文件更改时自动刷新来真正改善开发人员体验。只需安装它,并使用webpack-dev-server启动它,你就可以进行体验了。

npm install webpack-dev-server@2.2.0-rc.0 --save-dev

修改package.json中的start脚本。

"start": "webpack-dev-server --inline",

运行npm start启动服务器并且在你的浏览器中打开http://localhost:8080/

尝试更改src目录下的任意文件,例如更改people.js中一个名称或者style.scss中的一个样式,你会切身感受到这一好处。

热模块替换

如果你对实时重新加载只是印象深刻,那么热模块替换(HMR)将会让你大吃一惊。现在是2017年,可能你在使用全局状态开发单页面应用程序。在开发过程中,你会对组件进行很多小的改动,然后希望在的浏览器中真实的看到这些变化。手动刷新页面或使用实时重新加载,你的全局状态将会消失,你不得不从头开始。热加载的出现从此改变了这种情况。

在开发人员理想的工作流程中,你可以对模块进行更改,并在运行时进行编译和交换,而无需刷新浏览器(丢弃本地状态)或接触其他模块。虽然有时候仍然需要手动刷新,但HMR仍然可以节省大量的时间,预计它在未来会很流行。

package.json中对start脚本进行最后一次编辑。

"start": "webpack-dev-server --inline --hot",

app.js的顶部告诉webpack接受该模块的热加载以及它的所有依赖。

if (module.hot) {
module.hot.accept()
} // ...

注意:因为仅在开发阶段使用,webpack-dev-server -hotmodule.hot设置为true, 当在生产模式下构建、module.hot设置为false时,这些将被从打包文件中分离出来。

NamedModulesPlugin添加到webpack.config.js中的插件列表中以改善控制台中的日志记录性能。

plugins: [
new webpack.NamedModulesPlugin(),
// ...
]

最后,在页面中添加一个元素,我们可以在输入框中添加一些文本,以证明在我们更改模块的时候不会发生全页刷新。

<body>
<input />
<div id="root"></div>
...

npm start重启服务器来看看热加载!

在输入框中输入“HMR规则”,然后在people.js中更改名称,你会发现在不刷新页面的情况下发生了内容更新并且输入框丢失输入聚焦状态。

这只是一个简单的示例,但是希望你能意识到这是非常有用的。对于像React这样基于组件的开发这更是十分有用的,你有很多“笨”组件需要与其状态分离,组件可以在不丢失状态的情况下被更新并重新呈现,因此你可以不断的获得即时反馈。

热加载CSS

更改style.scss中<pre>元素的背景颜色,你会发现它并没有被HMR更新。

pre {
background: red;
}

事实证明,当你使用style-loader时,CSS的HMR可以直接使用而不需要做任何操作。我们通过将CSS模块提取到外部的无法替代的CSS文件中来去除这个关联。

如果我们将Sass规则恢复到初始状态,并从插件列表中删除extractCSS,那么你也可以看到Sass的热加载。

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

HTTP/2

使用像webpack这样的模块打包工具的好处主要是你可以通过控制资源的构建方式来帮助你提高应用性能。多年来,将文件连接起来以减少客户端上需要的请求数量一直被认为是最佳实践。但HTTP / 2现在允许在单个请求中传送多个文件,因此连接文件不再是具有极端有效性的解决方法,但是它仍然很重要。你的应用程序实际上也可以从多个拥有单独缓存的小文件中受益,客户端可以获取单个更改的模块,而不必再次请求存在大部分相同内容的整个包。

送给你的结尾语

我希望这个关于webpack2的介绍对你有所帮助、能够开始使用它来产生很好的效果。围绕webpack的配置、加载器和插件的学习可能需要一些时间,但是了解这个工具的工作原理肯定是很有好处的。

原文地址:https://www.sitepoint.com/beginners-guide-to-webpack-2-and-module-bundling/

一份关于webpack2和模块打包的新手指南(二)的更多相关文章

  1. 一份关于webpack2和模块打包的新手指南

    webpack已成为现代Web开发中最重要的工具之一.它是一个用于JavaScript的模块打包工具,但是它也可以转换所有的前端资源,例如HTML和CSS,甚至是图片.它可以让你更好地控制应用程序所产 ...

  2. 一份关于webpack2和模块打包的新手指南(一)

    webpack已成为现代Web开发中最重要的工具之一.它是一个用于JavaScript的模块打包工具,但是它也可以转换所有的前端资源,例如HTML和CSS,甚至是图片.它可以让你更好地控制应用程序所产 ...

  3. js模块化/js模块加载器/js模块打包器

    之前对这几个概念一直记得很模糊,也无法用自己的语言表达出来,今天看了大神的文章,尝试根据自己的理解总结一下,算是一篇读后感. 大神的文章:http://www.css88.com/archives/7 ...

  4. Zepto自定义模块打包构建

    文章转自 http://www.chengxuyuans.com/web_technology/zeptojs-build.html zepto.js 是个好东西,遵循 jQuery API,但比 j ...

  5. 探索 模块打包 exports和require 与 export和import 的用法和区别

    菜单快捷导航: CommonJS 之 exports和require用法 ES6 Module 之 export 和 import 用法 CommonJS和ES6 Module的区别 循环依赖 和 解 ...

  6. 多模块打包后,扫描不到@controller和@service,实现 ADD DIRECTORY ENTRIES

    多模块打包后,扫描不到@controller和@service等Bean. 原因:打包时没有生成目录信息 解决办法: 1.在eclipse或者myeclipse 打包时 勾选 ADD DIRECTOR ...

  7. Webpack - CommonJs & AMD 模块打包器

    Webpack 是一个 CommonJs & AMD 模块打包器.可以把你的 JavaScript 代码分离为多个包,在需要的时候进行加载,支持预处理文件,例如 json, jade, cof ...

  8. Maven之多模块打包成一个jar包及assembly

    一.多模块打包 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="htt ...

  9. 【spring cloud】【IDEA】【Maven】spring cloud多模块打包,打包的jar包只有几k,jar包无法运行,运行报错:no main manifest attribute, in /ms-eureka.jar

    ======================================================================================== 引申:maven打包多 ...

随机推荐

  1. ubuntu下安装apcu扩展

    apcu前身是apc,apc分为系统缓存和用户缓存 1.系统缓存是指PHP执行时增加缓存,减少PHP文件的反复检查和编译,从而达到系统加速的目的. 2.用户缓存是指,PHP代码中将数据写入缓存,是用户 ...

  2. COGS 1361. 树

    ★   输入文件:treed.in   输出文件:treed.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] 在一个凉爽的夏夜,xth和rabbit来到花园里砍树.为啥 ...

  3. SDUT_2146:最小子序列和

    题目描述 给你一个长为n(10<=n<=10000)的数组,数组中的每一个数大于等于1小于等于1000000.请你找出一个长为k(1<=k<=1000)的子序列.找序列时,假如 ...

  4. 在Oracle用SQL处理以 System.currentTimeMillis

    有時為了系統的需求會紀錄到毫秒(Millisecond),我們會接將得到的值寫入db,但是如果要用SQL 做時間範圍的搜尋,有以下做法( systemdate欄位存放System.currentTim ...

  5. Android(java)学习笔记183:多媒体之图形颜色的变化

    1.相信大家都用过美图秀秀中如下的功能,调整颜色: 2. 下面通过案例说明Android中如何调色: 颜色矩阵 ColorMatrix cm = new ColorMatrix(); paint.se ...

  6. 面向对象的设计的SOLID原则

    S.O.L.I.D是面向对象设计和编程中5个重要编码规则的首字母的缩写. - SRP The Single Responsibility Principle 单一责任原则 当需要修改某个类的时候原因有 ...

  7. VINS-Fusion代码阅读(四)

    pts_i和pts_j:具体指什么含义?(分别为第l个路标点在第i, j个相机归一化相机坐标系中的观察到的坐标,P¯¯¯cil \bar{P}^{c_i}_l Pˉ lc i​ ​ 和 P¯¯¯cjl ...

  8. c++调用com口操作autocad

    #include "stdafx.h" #include <atlcomcli.h> #import "D:\\C++test\\FirstCom\\Rele ...

  9. 日常[系统]:Linux新人报到(吐槽%&%……&¥……%

    昨天换了系统,从win7换到了NOIP必须面对的Linux系统. 不得不说,真的很不适应.原本右上角的三个按钮变到了左上角. 可爱的DEVCPP被无情的抛弃了. 又用不惯guide,只好用文本编辑器写 ...

  10. PHP 安装完成后 增加 bcmath 模块

    1. cd /usr/local/src/php-5.6.38/ext/bcmath  目录2. /usr/local/php/bin/phpize  生成configure需要的配置文件3.  ./ ...