一份關於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/

相關文章
相關標籤/搜索