在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) 機能は、アプリケーションの実行中にモジュールを追加または削除します。ページをリロードせずにモジュールを削除します。これにより、独立したモジュールが変更された後にページ全体を更新することなくモジュールを更新できるため、開発時間が大幅に短縮されます
【アプリの観点から】
1. アプリのコードは更新を確認するために HMR ランタイムを必要とします
2. HMR ランタイム (非同期) が更新をダウンロードし、更新が利用可能であることをアプリ コードに通知します
3. アプリ コードは更新を適用するために HMR ランタイムを必要とします
4. HMR ランタイム (非同期) が更新を適用します
このプロセスが自動的に更新をトリガーするように HMR を設定することも、ユーザー操作後に更新を要求することも選択できます
【コンパイラー (webpack) の観点から】
通常のリソースに加えて、コンパイラー (コンパイラー) ) は、以前のバージョンを新しいバージョンに更新できるように「アップデート」を発行する必要があります。 「update」は 2 つの部分で構成されます: 1. 更新されるマニフェスト (JSON); 2. 更新される 1 つ以上のチャンク (JavaScript)
マニフェストには、更新されるすべてのチャンク ディレクトリが含まれます。
更新される各チャンクには、更新されるすべてのモジュールに対応するチャンクのコード (またはモジュールが削除されることを示すフラグ) が含まれます。
コンパイラは、モジュール ID とチャンク ID がこれらのビルド間で一貫していることを保証します。通常、これらの ID はメモリに保存されます (たとえば、webpack-dev-server を使用する場合) が、JSON ファイルに保存することも可能です
【モジュールの観点から】
HMR はオプションの機能であり、影響するもののみですHMR コードを含むモジュール。たとえば、style-loader を通じてスタイル style にパッチを追加します。 追加のパッチを実行するために、スタイル ローダーは HMR インターフェイスを実装します。HMR 経由で更新を受け取ると、古いスタイルを新しいスタイルに置き換えます。
同様に、HMRインターフェースがモジュールに実装されている場合、モジュールが更新されたときに何が起こるかを記述することができます。ただし、ほとんどの場合、すべてのモジュールに HMR コードを強制する必要はありません。モジュールに HMR ハンドラーがない場合、更新がバブルアップします。これは、単純な処理関数で完全なモジュール ツリーを処理できることを意味します。このモジュール ツリー内の 1 つのモジュールが更新されると、モジュール ツリー全体が再ロードされます (再ロードのみであり、移行はされません)。
【HMRランタイムの観点から】
モジュールシステムのランタイムでは、追加のコードが親と子の追跡モジュールに送信されます。
管理の面では、ランタイムはcheckとapplyの2つのメソッドをサポートしています。
1. Check はマニフェストを更新するための HTTP リクエストを送信します。リクエストが失敗した場合、利用可能なアップデートはありません。リクエストが成功すると、更新されるチャンクが現在ロードされているチャンクと比較されます。ロードされたチャンクごとに、更新される対応するチャンクがダウンロードされます。更新するすべてのチャンクがダウンロードされると、準備完了状態に切り替える準備が整います。
2. apply メソッドは、更新されたすべてのモジュールを無効としてマークします。無効なモジュールごとに、モジュールまたはその親モジュールに更新ハンドラーが必要です。それ以外の場合、無効なタグがバブルアップし、親も無効であるとマークされます。各バブリングは、アプリケーションのエントリ ポイント、または更新ハンドラーを備えたモジュールのどちらか先に到達するまで継続します。エントリ ポイントからバブリングが始まると、プロセスは失敗します。
その後、無効なモジュールはすべて(破棄ハンドラー関数を介して)処理され、アンロードされます。次に、現在のハッシュが更新され、すべての「accept」ハンドラーが呼び出されます。ランタイムはアイドル状態に戻り、すべてが通常どおり続行されます
HMR は、開発中に LiveReload の代わりとして使用できます。 webpack-dev-server はホット モードをサポートしており、ページ全体をリロードする前に HMR を使用して更新を試行します
一部のローダーは、ホット アップデートできるモジュールを生成しています。たとえば、style-loader はページのスタイル シートを交換できます。このようなモジュールの場合、特別な処理は必要ありません
以上がwebpack モジュールのサンプル チュートリアルの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。