首頁  >  文章  >  web前端  >  webpack模組實例教程

webpack模組實例教程

零下一度
零下一度原創
2017-06-26 10:13:101427瀏覽

前面的话

  在web存在多种支持JavaScript模块化的工具(如requirejs和r.js),这些工具各有优势和限制。webpack基于从这些系统获得的经验教训,并将模块的概念应用于项目中的任何文件。本文将详细介绍webpack的模块解析

 

模块

  在模块化编程中,开发者将程序分解成离散功能块(discrete chunks of functionality),并称之为模块

  每个模块具有比完整程序更小的接触面,使得校验、调试、测试轻而易举。 精心编写的模块提供了可靠的抽象和封装界限,使得应用程序中每个模块都具有条理清楚的设计和明确的目的

  Node.js从最一开始就支持模块化编程。对比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可以开箱即用

【支持类型】

  webpack通过loader可以支持各种语言和预处理器编写模块。loader描述了webpack如何处理非JavaScript(non-JavaScript) 模块,并且在bundle中引入这些依赖。 webpack 社区已经为各种流行语言和语言处理器构建了loader,包括:

CoffeeScript
TypeScript
ESNext (Babel)
Sass
Less
Stylus

  总的来说,webpack提供了可定制的、强大和丰富的API,允许任何技术栈使用webpack,保持了在开发、测试和生成流程中无侵入性(non-opinionated)

 

模块解析

  resolver是一个库(library),用于帮助找到模块的绝对路径。一个模块可以作为另一个模块的依赖模块,然后被后者引用,如下:

import foo from 'path/to/module'// 或者require('path/to/module')

  所依赖的模块可以是来自应用程序代码或第三方的库(library)。resolver帮助webpack找到bundle中需要引入的模块代码,这些代码在包含在每个require/import语句中。当打包模块时,webpack使用enhanced-resolve来解析文件路径

【解析规则】

  使用enhanced-resolve,webpack能够解析三种文件路径:

  1、绝对路径

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

  由于已经取得文件的绝对路径,因此不需要进一步再做解析

  2、相对路径

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

  在这种情况下,使用import或require的资源文件(resource file)所在的目录被认为是上下文目录(context directory)。在import/require中给定的相对路径,会添加此上下文路径(context path),以产生模块的绝对路径(absolute path)

  3、模块路径

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

  模块将在resolve.modules中指定的所有目录内搜索。 可以替换初始模块路径,此替换路径通过使用resolve.alias配置选项来创建一个别名

  一旦根据上述规则解析路径后,解析器(resolver)将检查路径是否指向文件或目录

  如果路径指向一个文件:

    a、如果路径具有文件扩展名,则被直接将文件打包

    b、否则,将使用 [resolve.extensions] 选项作为文件扩展名来解析,此选项告诉解析器在解析中能够接受哪些扩展名(例如 .js, .jsx)

  如果路径指向一个文件夹,则采取以下步骤找到具有正确扩展名的正确文件:

    a、如果文件夹中包含 package.json 文件,则按照顺序查找 resolve.mainFields 配置选项中指定的字段。并且 package.json 中的第一个这样的字段确定文件路径

    b、如果package.json文件不存在或者package.json文件中的main字段没有返回一个有效路径,则按照顺序查找 esolve.mainFiles配置选项中指定的文件名,看是否能在import/require目录下匹配到一个存在的文件名

    c、文件扩展名通过 resolve.extensions 选项采用类似的方法进行解析

  webpack 根据构建目标(build target)为这些选项提供了合理的默认配置

【解析与缓存】

  Loader解析遵循与文件解析器指定的规则相同的规则。resolveLoader 配置选项可以用来为 Loader 提供独立的解析规则。

  每个文件系统访问都被缓存,以便更快触发对同一文件的多个并行或穿行请求。在观察模式下,只有修改过的文件会从缓存中摘出。如果关闭观察模式,在每次编译前清理缓存

 

依赖图表

  任何时候,一个文件依赖于另一个文件,webpack就把此视为文件之间有依赖关系。这使得 webpack 可以接收非代码资源(non-code asset)(例如图像或 web 字体),并且可以把它们作为依赖提供给应用程序

  webpack从命令行或配置文件中定义的一个模块列表开始,处理应用程序。 从这些入口起点开始,webpack 递归地构建一个依赖图表,这个依赖图表包含着应用程序所需的每个模块,然后将所有这些模块打包为少量的bundle(通常只有一个 )可由浏览器加载

 

构建目标

  因为服务器和浏览器代码都可以用JavaScript编写,所以webpack提供了多种构建目标(target),可以在webpack配置中设置

【用法】

  要设置target属性,只需要在webpack配置中设置target的值

//webpack.config.jsmodule.exports = {
  target: 'node'};

  在上面例子中,使用node webpack会编译为用于「类Node.js」环境(使用Node.js的require,而不是使用任意内置模块(如fs或path)来加载chunk)。

  每个target都有各种部署(deployment)/环境(environment)特定的附加项,以支持满足其需求

【多个Target】

  尽管webpack不支持向target传入多个字符串,可以通过打包两份分离的配置来创建同构的库

//webpack.config.jsvar 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檔案

 

模組熱替換

  模組熱替換HMR( 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 是選用功能,只會影響包含HMR 程式碼的模組。舉個例子,透過 style-loader 為 style 樣式追加補丁。 為了運行追加補丁,style-loader 實現了 HMR 介面;當它透過 HMR 接收到更新,它會使用新的樣式取代舊的樣式。

  類似的,當在一個模組中實現了 HMR 接口,可以描述出當模組被更新後發生了什麼。然而在多數情況下,不需要強制在每個模組中寫入 HMR 程式碼。如果一個模組沒有 HMR 處理函數,更新就會冒泡。這意味著一個簡單的處理函數能夠對整個模組樹(complete module tree)進行處理。如果在這個模組樹中,一個單獨的模組被更新,那麼整個模組樹都會被重新加載(只會重新加載,不會遷移)。

【站在HMR Runtime的角度】

  對於模組系統的 runtime,附加的程式碼被傳送到 parents 和 children 追蹤模組。

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

  1、check 發送 HTTP 請求來更新 manifest。如果請求失敗,表示沒有可用更新。如果請求成功,待更新 chunk 會和目前載入過的 chunk 進行比較。對每個載入過的 chunk,會下載相對應的待更新 chunk。當所有待更新 chunk 完成下載,就會準備切換到 ready 狀態。

  2、apply 方法將所有被更新模組標記為無效。對於每個無效模組,都需要在模組中有一個更新處理函數,或在它的父級模組們中有更新處理函數。否則,無效標記冒泡,並將父級也標記為無效。每個冒泡繼續直到到達應用程式入口起點,或到達帶有更新處理函數的模組(以最先到達為準)。如果它從入口起點開始冒泡,則此過程失敗。

  之後,所有無效模組都被(透過 dispose 處理函數)處理和解除載入。然後更新目前 hash,並且呼叫所有 "accept" 處理函數。 runtime 切換回閒置狀態,一切照常繼續

  可以在開發過程中將 HMR 作為 LiveReload 的替代。 webpack-dev-server 支援熱模式,在試圖重新載入整個頁面之前,熱模式會嘗試使用 HMR 來更新

  一些 loader 已經產生可熱更新的模組。例如,style-loader 能夠置換出頁面的樣式表。對於這樣的模組,不需要做任何特殊處理

以上是webpack模組實例教程的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn