webpack概念

官網:http://www.css88.com/doc/webpack2/concepts/css

webpack是js的模塊打包器(module bundler)。html

入口(Entry)

webpack將建立全部應用程序的依賴關係圖標(dependency graph)。node

入口起點(entry point):圖表的起點。根上下文(contextual root)  app第一個啓動文件webpack

入口起點告訴webpack從哪裏開始,遵循依賴圖表打包文件。git

webpack中使用webpack配置對象的entry屬性定義入口。github

單個入口(簡寫)語法

 

用法: entry: string | Array<string>web

 webpack.config.jsnpm

1 module.exports = {
2   entry: './path/to/my/entry/file.js'
3 };
4 module.exports = config;

entry屬性的單個入口語法,是下面的簡寫:編程

1 module.exports = {
2   entry: {
3       main: './path/to/my/entry/file.js'
4   }
5 };

向entry傳入一個數組會發生什麼?將建立多個入口。json

對象語法

用法:entry: {[entryChunkName: string]: string | Array<string>} 

const config = {
  entry: {
    app: './src/app.js',   // 應用程序(app)
    vendors: './src/vendors.js'  // 公共庫(vendor)
  }
};

 對象語法是應用程序中定義入口的最可擴展的方式。

可擴展的webpack配置:可重用並可與其餘配置組合使用。用於將關注點從環境、構建目標、運行時中分離,而後用專門的工具(如 webpack-merge)將它們合併。

 

輸出(Output)

全部的資源(assets)歸攏在一塊兒後,須要告訴webpack在哪裏打包應用程序。

output屬性,描述了如何處理歸攏在一塊兒的代碼(bundled code)。

webpack.config.js

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  }
};

用法(Usage)

 將output設置爲一個對象,包括如下兩點:

1.編譯文件的文件名(filename),推薦:main.js   ||   bundle.js   ||  index.js

2.output.path對應一個絕對路徑(一次性打包的目錄)。

webpack.config.js

const config = {
    output: {
      filename: 'bundle.js',
      path: '/home/proj/public/assets'
    }
};
exports.module = config;

選項(Options)

能夠向output屬性傳入的值。

output.chuckFilename

非入口的 chunk(non-entry chunk) 的文件名,路徑相對於 output.path 目錄。

[id] 被 chunk 的 id 替換。

[name] 被 chunk 的 name 替換(或者,在 chunk 沒有 name 時使用 id 替換)。

[hash] 被 compilation 生命週期的 hash 替換。

[chunkhash] 被 chunk 的 hash 替換。

output.crossOriginLoading

此選項啓用跨域加載(cross-origin loading) chunk。

可選的值有:

false - 禁用跨域加載

"anonymous" - 啓用跨域加載。當使用 anonymous 時,發送不帶憑據(credential)的請求。

"use-credentials" - 啓用跨域加載。發送帶憑據(credential)的請求。

output.devtoolLineToLine

全部/指定模塊啓用行到行映射(line-to-line mapped)模式。

行到行映射模式使用一個簡單的 SourceMap,即生成資源(generated source)的每一行都映射到原始資源(original source)的同一行。這是一個可作性能優化之處。

true 在全部模塊啓用(不推薦)

{test, include, exclude} 對象,對特定文件啓用(相似於 module.loaders)。

默認值:false

output.filename

 指定硬盤每一個輸出文件的名稱。

單個入口

{
  entry: './src/app.js',
  output: {
    filename: 'bundle.js'
    path: __dirname + 'build',
  }
}
// 寫入到硬盤: ./build/bundle.js

 

多個入口

如配置建立多個「chunk」(例如使用多個入口起點或使用相似CommonsChunkPlugin(提取公共代碼)的插件),爲確保每一個文件名都不重複,應使用如下替換方式:

[name] 被 chunk 的 name 替換。

[hash] 被 compilation 生命週期的 hash 替換。

[chunkhash] 被 chunk 的 hash 替換。

{
  entry: {
    app: './src/app.js',
    search: './src/search.js'
  },
  output: {
    filename: '[name].js',
    path: __dirname + '/build'
  }
}
// 寫入到硬盤:./build/app.js, ./build/search.js

 

output.hotUpdateChunkFilename

熱更新 chunk(Hot Update Chunk) 的文件名。在 output.path 目錄中。

[id] 被 chunk 的 id 替換。

[hash] 被 compilation 生命週期的 hash 替換。(最後一個 hash 存儲在記錄中)

默認值:"[id].[hash].hot-update.js"

output.hotUpdateFunction

webpack 中用於異步加載(async load)熱更新(hot update) chunk 的 JSONP 函數。

默認值:"webpackHotUpdate"

output.hotUpdateMainFilename

熱更新主文件(hot update main file)的文件名。

[hash] 被 compilation 生命週期的 hash 替換。(最後一個 hash 存儲在記錄中)

默認值:"[hash].hot-update.json"

output.jsonpFunction

webpack 中用於異步加載(async loading) chunk 的 JSONP 函數。

較短的函數可能會減小文件大小。當單頁有多個 webpack 實例時,請使用不一樣的標識符(identifier)。

默認值:"webpackJsonp"

output.library

若是設置此選項,會將 bundle 導出爲 library。output.library 是 library 的名稱。

若是你正在編寫 library,而且須要將其發佈爲單獨的文件,請使用此選項。

output.libraryTarget

library 的導出格式

"var" - 導出爲一個變量:var Library = xxx(默認)

"this" - 導出爲 this 的一個屬性:this["Library"] = xxx

"commonjs" - 導出爲 exports 的一個屬性:exports["Library"] = xxx

"commonjs2" - 經過 module.exportsmodule.exports = xxx 導出

"amd" - 導出爲 AMD(可選命名 - 經過 library 選項設置名稱)

"umd" - 導出爲 AMD,CommonJS2 或者導出爲 root 的屬性

默認值:"var"

若是 output.library 未設置,可是 output.libraryTarget 被設置爲 var 之外的值,則「所導出對象」的每一個屬性都被複制到「對應的被導出對象」上(除了 amdcommonjs2 和 umd)。

output.path

導出目錄爲絕對路徑(必選項)。

[hash] 被 compilation 生命週期的 hash 替換。

config.js

output: {
  path: "/home/proj/public/assets",
  publicPath: "/assets/"
}

 

index.html

<head>
  <link href="/assets/spinner.gif" />
</head> 

 

接下來是一個更復雜的例子,來講明對資源使用 CDN 和 hash。

config.js

output: {
  path: "/home/proj/cdn/assets/[hash]",
  publicPath: "http://cdn.example.com/assets/[hash]/"
}

 

注意:在編譯時不知道最終輸出文件的 publicPath 的狀況下,publicPath 能夠留空,而且在入口起點文件運行時動態設置。若是你在編譯時不知道 publicPath,你能夠先忽略它,而且在入口起點設置 __webpack_public_path__

 __webpack_public_path__ = myRuntimePublicPath
// 其餘的應用程序入口

 

output.sourceMapFilename

JavaScript 文件的 SourceMap 的文件名。它們在 output.path 目錄中。

[file] 被 JavaScript 文件的文件名替換。

[id] 被 chunk 的 id 替換。

[hash] 被 compilation 生命週期的 hash 替換。

默認值:"[file].map"

 

加載器(Loader)

webpack的目標是讓webpack聚焦於項目中的全部資源(asset),而瀏覽器不須要關注這些(並非資源都必須打包在一塊兒)。webpack把每一個文件(.css, .html, .scss, .jpg, etc.) 都做爲模塊處理。並且webpack只理解js

loader是對應用程序中資源文件進行轉換。它們是(運行在Node.js中的)函數,能夠將資源文件做爲參數的來源,而後返回到新的資源文件。

webpack配置的目標:

1.識別(identity)被對應loader轉換(transform)的文件

2. 進行過文件轉換,能夠將被轉換的文件添加到依賴圖表(最終添加到bundle中)(use屬性)

webpack.config.js

const config = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  },
  module: {
    rules: [
      // 當遇到【在require() / import語句中被解析爲'.js'或'.jsx'的路徑】時,把它們添加並打包前,要先使用babel-loader轉換
   {test: /\.(js | jsx)$/, use: 'babel-loader'}    
    ]
  }
};

module.exports = config;

 

在webpack配置中定義loader時,要定義在module.rules中,而不是rules。定義錯時webpack會提出嚴重警告。

示例

可以使用 loader 告訴 webpack 加載 CSS 文件,或者將 TypeScript 轉爲 JavaScript。

首先,安裝相對應的 loader:

npm install --save-dev css-loader
npm install --save-dev ts-loader

 

其次,配置 webpack.config.js,對每一個 .css 文件使用 css-loader,對每一個 .ts 文件使用 ts-loader

webpack.config.js

module.exports = {
  module: {
    rules: [
      {test: /\.css$/, use: ['css-loader'](loaders/css-loader)},
      {test: /\.ts$/, use: ['ts-loader']((https://github.com/TypeStrong/ts-loader))}
    ]
  }
};

注意,根據配置選項,下面的規範定義了同等的 loader 用法:

{test: /\.css$/, [loader](/configuration/module#rule-loader): 'css-loader'}
// or equivalently
{test: /\.css$/, [use](/configuration/module#rule-use): 'css-loader'}
// or equivalently
{test: /\.css$/, [use](/configuration/module#rule-use): {
  loader: 'css-loader',
  options: {}
}}

配置

在你的應用程序中,有三種方式使用 loader:

  • 經過配置
  • 在 require 語句中顯示使用
  • 經過 CLI

經過 webpack.config.js

module.rules 容許在 webpack 配置中指定幾個 loader。

這是展現 loader 的一種簡明的方式,而且有助於簡潔代碼,以及對每一個相應的 loader 有一個完整的概述。

module: {
  rules: [
    {
      test: /\.css$/,
      use: [
        {loader: 'style-loader'},
        {
          loader: 'css-loader',
          options: {
            module: true
          }
        }
      ]
    }
  ]
}

經過 require

能夠在 require 語句(或 definerequire.ensure, 等語句)中指定 loader。使用 ! 將資源中的 loader 分開。分開的每一個部分都相對於當前目錄解析。

require('style-loader!css-loader?modules!./styles.css');

 

經過前置全部規則及使用 !,能夠對應覆蓋到配置中的任意 loader。

選項能夠傳遞查詢參數,就像在 web 中那樣(?key=value&foo=bar)。也可使用 JSON 對象(?{"key":"value","foo":"bar"})。

儘量使用 module.rules,由於能夠在源碼中減小引用,而且更快調試和定位 loader,避免代碼愈來愈糟。

經過 CLI

可選項,經過 CLI 使用 loader:

webpack --module-bind jade --module-bind 'css=style!css'

對 .jade 文件使用 jade-loader,對 .css 文件使用 style-loader 和 css-loader

Loader 特性

  • loader 支持鏈式傳遞。可對資源使用流水線(pipeline)。loader 鏈式地按照前後順序進行編譯。loader 鏈中的第一個 loader 返回值給下一個 loader。在最後一個 loader,返回 webpack 所預期的 JavaScript。
  • loader 能夠是同步或異步函數。
  • loader 運行在 Node.js 中,可執行任何可能的操做。
  • loader 接收查詢參數。用於 loader 間傳遞配置。
  • loader 也可以使用 options 對象進行配置。
  • 除了使用 package.json 常見的 main 屬性,還能夠將普通的 npm 模塊導出爲 loader,作法是在 package.json 裏定義一個 loader 字段。
  • 插件(plugin)能夠爲 loader 帶來更多特性。
  • loader 可以產生額外的任意文件。

loader 經過(loader)預處理函數,爲 JavaScript 生態系統提供了更多有力功能。用戶如今能夠更加靈活的引入細粒度邏輯,例如壓縮(compression)、打包(package)、語言翻譯(language translation)和其餘更多。

解析 Loader

loader 遵循標準的模塊解析。多數狀況下,loader 將從模塊路徑(一般是 npm installnode_modules)解析。

如何編寫模塊?

loader 模塊須要導出爲一個函數,而且使用 Node.js 兼容的 JavaScript 編寫。一般使用 npm 管理 loader,也能夠將 loader 模塊做爲應用程序中的文件。

按照約定,loader 一般被命名爲 XXX-loader,其中 XXX 是上下文的名稱,例如 json-loader

loader 的名稱約定和優先搜索順序,由 webpack 配置 API 中的 resolveLoader.moduleTemplates 定義。

 

插件(Plugins)

loader僅在每一個文件的基礎上執行轉換,插件目的在於解決loader沒法實現的事情。

插件(plugins)最經常使用(但不限)於在打包模塊的「compilation」和「chunk」生命週期執行操做和自定義功能。

webpack的插件系統強大且可定製化。

在一個配置中,屢次使用一個插件,用於不一樣的目的。

1.想使用一個插件,只需require()它,而後把它添加到plugins數組中。多數插件能夠經過選項(option)自定義。

2.須要使用new來建立插件的實例,而且經過實例來調用插件。 

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');  // installed via npm(經過npm安裝)
const webpack = require('webpack'); //to access built-in plugins(訪問內置插件)
const path = require('path');

const config = {
  entry: './path/to/my/entry/file.js';
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  },
  module: {
    rules: [
      {test: /\.(js | jsx)$/, use: 'babel-loader'}
    ]
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin(),   // 優化js組件
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};
module.exports = config;

剖析

webpack 插件是一個具備 apply 屬性的 JavaScript 對象。 apply 屬性會被 webpack compiler 調用,而且 compiler 對象可在整個 compilation 生命週期訪問。

ConsoleLogOnBuildWebpackPlugin.js

function ConsoleLogOnBuildWebpackPlugin() {

};

ConsoleLogOnBuildWebpackPlugin.prototype.apply = function(compiler) {
  compiler.plugin('run', function(compiler, callback) {
    console.log("webpack 構建過程開始!!!");
    callback();
  });
};

 

 經過Function.prototype.apply方法能夠把任意函數做爲插件傳遞(this 將指向 compiler)。在配置中使用這樣的方式來內聯自定義插件。

用法

plugin 能夠攜帶參數/選項,在 wepback 配置中,需向 plugins 屬性傳入 new 實例。

配置

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');  // installed via npm(經過npm安裝)
const webpack = require('webpack'); //to access built-in plugins(訪問內置插件)
const path = require('path');

const config = {
  entry: './path/to/my/entry/file.js';
  output: {
    filename: 'my-first-webpack.bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    loaders: [
      {
        test: /\.(js | jsx)$/, 
        loader: 'babel-loader'
       }
    ]
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin(),   // 優化js組件
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};
module.exports = config;            

 

配置(Configuration)

webpack 的配置文件是 JavaScript 文件導出的一個對象。此對象,由 webpack 根據對象定義的屬性進行解析。

由於 webpack 配置是標準的 Node.js CommonJS 模塊,能夠以下:

  • 經過 require(...) 導入其餘文件
  • 經過 require(...) 使用 npm 的工具函數
  • 使用 JavaScript 控制流表達式,例如 ?: 操做符
  • 對經常使用值使用常量或變量
  • 編寫並執行函數來生成部分配置

不該該使用如下。從技術上講能夠這麼作,可是並不推薦:

  • 在使用 webpack 命令行接口(CLI)(應該編寫本身的命令行接口(CLI),或使用 --env)時,訪問命令行接口(CLI)參數
  • 導出不肯定的值(調用 webpack 兩次應該產生一樣的輸出文件)
  • 編寫很長的配置(應該將配置拆分爲多個文件)

最簡單的配置

webpack.config.js

var path = require('path');

module.exports = {
  entry: './foo.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'foo.bundle.js'
  }
};

多個 Target

webpack.config.js

var path = require('path');
var webpack = require('webpack');
var webpackMerge = require('webpack-merge');

var baseConfig = {
  target: 'async-node',
  entry: {
    entry: './entry.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js'
  },
  plugin: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'inline',
      filename: 'inline.js',
      minChunks: Infinity
    }),
    new webpack.optimize.AggressiveSplittingPlugin({
      minSize: 5000,
      maxSize: 10000
    }),
  ]
};

let targets = ['web', 'webworker', 'node', 'async-node', 'node-webkit', 'electron-main'].map((target) => {
  let base = webpackMerge(baseConfig, {
    target: target,
    output: {
      path: path.resolve(__dirname, 'diat/' + target),
      filename: '[name].' + target + '.js'
    }
  });
  return base;
});

module.exports = targets;

 

模塊(Modules)

在模塊化編程,開發者將程序分解成稱爲模塊的離散功能塊。

什麼是 webpack 模塊

對比 Node.js 模塊,webpack 模塊可以以各類方式表達它們的依賴關係,幾個例子以下:

  • ES2015 import 語句
  • CommonJS require() 語句
  • AMD define 和 require 語句
  • css/sass/less 文件中的 @import 語句。
  • 樣式(url(...))或 HTML 文件(<img src=...>)中的圖片連接(image url)

 webpack 1 須要特定的 loader 來轉換 ES 2015 import,然而經過 webpack 2 能夠開箱即用。

 

模塊解析(Module Resolution)

解析器是一個經過絕對路徑來幫助定位模塊的庫(library)。 一個模塊能夠做爲另外一個模塊的依賴模塊,而後被後者引用,以下:

import foo from 'path/to/module'
// or
require('path/to/module')

依賴模塊能夠來自應用程序代碼或第三方庫。解析器幫助 webpack 找到 bundle 中須要引入的模塊代碼,這些代碼包含在 require/import 語句中。 當打包模塊時,webpack 使用加強解析來解析文件路徑

webpack 中的解析規則

使用 enhanced-resolve,webpack 可以解析三種文件路徑:

絕對路徑

import "/home/me/file";
import "C:\\Users\\me\\file";

 

已經有了文件的絕對路徑,不須要進一步解析。

相對路徑

import "../src/file1";
import "./file2";

 

出現 import 或 require 的資源文件的目錄被認爲是上下文目錄(context directory)(當前處理文件的目錄)。在 import/require 中給定的相對路徑被追加到此上下文路徑(context path),以生成模塊的絕對路徑(absolute path)。

模塊路徑

import "module";
import "module/lib/file";

 

模塊將在 resolve.modules 中指定的全部目錄內搜索。 能夠替換初始模塊路徑,此替換路徑經過使用 resolve.alias 配置選項來建立一個別名。

一旦根據上述規則解析路徑後,解析器(resolver)將檢查路徑是否指向文件或目錄。若是路徑指向一個文件:

  • 若是路徑具備文件擴展名,則被直接將文件打包。
  • 不然,將使用 [resolve.extensions] 選項做爲文件擴展名來解析,此選項告訴解析器在解析中可以接受哪些擴展名(例如 .js.jsx)。

若是路徑指向一個文件夾,則採起如下步驟找到具備正確擴展名的正確文件。

  • 若是文件夾中包含 package.json 文件,則按照順序查找 resolve.mainFields 配置選項中指定的字段。而且 package.json 中的第一個這樣的字段肯定文件路徑。

webpack 根據構建目標(build target)爲這些選項提供了合理的默認配置。

解析加載器(Resolving Loaders)

Loader 解析遵循與文件解析器指定的規則相同的規則。可是 resolveLoader 配置選項能夠用來爲 Loader 提供獨立的解析規則。

緩存

每一個文件系統訪問都被緩存,以便更快觸發對同一文件的多個並行或穿行請求。在觀察模式下,只有修改過的文件會從緩存中摘出。若是關閉觀察模式,在每次編譯前清理緩存。

 

依賴圖表(Dependency Graph)

任什麼時候候一個文件依賴於另外一個文件,webpack 把這個文件看成依賴處理。這使得 webpack 能夠接收非代碼資源(non-code asset)(例如圖像或 web 字體),而且也能把它們做爲依賴提供給應用。

webpack 從命令行或配置文件定義的一個模塊列表,開始處理應用。 從這些入口點開始,webpack 遞歸地構建一個依賴圖表,這個依賴圖表包括應用所需的每一個模塊,而後將全部模塊打包爲少許的包(bundle) - 一般只有一個包 - 可由瀏覽器加載。

 對於 HTTP/1.1 客戶端,打包應用會尤爲強大,由於當瀏覽器發起一個新請求時,它可以最大限度地減小應用的等待次數。對於 HTTP/2,能夠經過 webpack 使用代碼拆分(Code Splitting)和打包實現最佳優化。

 

構建目標(Targets)

由於服務器和瀏覽器代碼均可以用 JavaScript 編寫,因此 webpack 提供了多種構建目標(target),你能夠在webpack 配置中設置。

用法

要設置 target 屬性,只須要在你的 webpack 配置中設置 target 的值。

webpack.config.js

module.exports = {
    target: 'node'
};

在上面例子中,使用 node webpack 會編譯爲用於「類 Node.js」環境(使用 Node.js 的 require ,而不是使用任意內置模塊(如 fs 或 path)來加載 chunk)。

每一個target都有各類部署(deployment)/環境(environment)特定的附加項,以支持知足其需求。查看target 的可用值。

多個 Target

儘管 webpack 不支持向 target 傳入多個字符串,你能夠經過打包兩份分離的配置來建立同構的庫:

webpack.config.js

var path = require('path');
var serverConfig = {
  target: 'node',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'lib.node.js'
  }
  // ...
};

var clientConfig = {
  target: 'web',  // <=== 默認是'web',可省略
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'lib.js'
  }
  //...
};

module.exports = [serverConfig, clientConfig];

 

 上面的例子將在dist 文件夾下建立 lib.js 和 lib.node.js 文件。

 

模塊熱替換(Hot Module Replacement)

模塊熱替換功能會在應用程序運行過程當中替換、添加或刪除模塊,而無需從新加載頁面。在獨立模塊變動後,無需刷新整個頁面,就能夠更新這些模塊,極大地加速了開發時間。

這一切是如何運行的?

站在 App 的角度

  1. app 代碼要求 HMR runtime 檢查更新。
  2. HMR runtime (異步)下載更新,而後通知 app 代碼更新可用。
  3. app 代碼要求 HMR runtime 應用更新。
  4. HMR runtime (異步)應用更新。

能夠設置 HMR,使此進程自動觸發更新,或者選擇要求在用戶交互後進行更新。

站在編譯器(webpack) 的角度

除了普通資源,編譯器(compiler)須要發出 "update",以容許更新以前的版本到新的版本。"update" 由兩部分組成:

  1. 待更新 manifest (JSON)
  2. 一個或多個待更新 chunk (JavaScript)

manifest 包括新的編譯 hash 和全部的待更新 chunk 目錄。

每一個待更新 chunk 包括用於與全部被更新模塊相對應 chunk 的代碼(或一個 flag 用於代表模塊要被移除)。

編譯器確保模塊 ID 和 chunk ID 在這些構建之間保持一致。一般將這些 ID 存儲在內存中(例如,當使用 webpack-dev-server 時),可是也可能將它們存儲在一個 JSON 文件中。

站在模塊的角度

HMR 是可選功能,只會影響包含 HRM 代碼的模塊。舉個例子,經過 style-loader 爲 style 樣式追加補丁。 爲了運行追加補丁,style-loader 實現了 HMR 接口;當它經過 HRM 接收到更新,它會使用新的樣式替換舊的樣式。

相似的,當在一個模塊中實現了 HMR 接口,你能夠描述出當模塊被更新後發生了什麼。然而在多數狀況下,不須要強制在每一個模塊中寫入 HMR 代碼。若是一個模塊沒有 HMR 處理函數,更新就會冒泡。這意味着一個簡單的處理函數可以對整個模塊樹(complete module tree)進行處理。若是在這個模塊樹中,一個單獨的模塊被更新,那麼整個模塊樹都會被從新加載(只會從新加載,不會遷移)。

站在 HMR Runtime 的角度 (Technical)

對於模塊系統的 runtime,附加的代碼被髮送到 parents 和 children 跟蹤模塊。

在管理方面,runtime 支持兩個方法 check 和 apply

check 發送 HTTP 請求來更新 manifest。若是請求失敗,說明沒有可用更新。若是請求成功,待更新 chunk 會和當前加載過的 chunk 進行比較。對每一個加載過的 chunk,會下載相對應的待更新 chunk。當全部待更新 chunk 完成下載,就會準備切換到 ready 狀態。

apply 方法將全部被更新模塊標記爲無效。對於每一個無效模塊,都須要在模塊中有一個更新處理函數,或者在它的父級模塊們中有更新處理函數。不然,無效標記冒泡,並將父級也標記爲無效。每一個冒泡繼續直到到達應用程序入口起點,或者到達帶有更新處理函數的模塊(以最早到達爲準)。若是它從入口起點開始冒泡,則此過程失敗。

以後,全部無效模塊都被(經過 dispose 處理函數)處理和解除加載。而後更新當前 hash,而且調用全部 "accept" 處理函數。runtime 切換回閒置狀態,一切照常繼續。

能使用 HMR 作什麼?

能夠在開發過程當中將 HMR 做爲 LiveReload 的替代。webpack-dev-server 支持熱模式,在試圖從新加載整個頁面以前,熱模式會嘗試使用 HMR 來更新。查看如何實如今 React 項目中使用 HRM 爲例。

一些 loader 已經生成可熱更新的模塊。例如,style-loader 可以置換出頁面的樣式表。對於這樣的模塊,不須要作任何特殊處理。

相關文章
相關標籤/搜索