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

插件

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

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

公共代码

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

若是你的应用程序有两个不一样的区域须要分享某个模块,例如:用于面向公共应用程序的app.js、用于管理区域的admin.js,你能够像这样为其建立单独的入口点:webpack

// 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.jsweb

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

// 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>`

这些入口文件将输出如下文件:json

  • 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,可用于将模块提取到本身的输出文件中。sass

下面咱们将修改.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.importrequire.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/

相关文章
相关标签/搜索