新聞中心
- 1、webpack的概念
- 1.1、入口(entry)
- 1.2、輸出(output)
- 1.3、loader
- 1.4、插件(plugin)
- 1.5、模式(mode)
- 1.6、瀏覽器兼容性(browser compatibility)
- 1.7、環(huán)境(environment)
- 2、入口起點(entry points)
- 2.1、單個入口(簡寫)語法
- 2.2、對象語法
- 2.2.1、描述入口的對象
- 2.3、常見場景
- 2.3.1、分離app和vendor(第三方庫)入口
- 2.3.2、多頁面應(yīng)用程序
- 3、輸出(output)
- 3.1、用法
- 3.2、多個入口起點
- 3.3、高級進階
- 4、loader
- 4.1、示例
- 4.2、使用loader
- 4.3、Configuration
- 4.4、內(nèi)聯(lián)方式
- 4.5、loader特性
- 4.6、解析loader
- 5、plugin
- 5.1、剖析
- 5.2 用法
- 5.3 配置方式
- 5.4、Node API方式
- 6、配置(Configuration)
- 6.1、基本配置
- 6.2、多個target
- 6.3、使用其他配置語言
- 7、模塊(Modules)
- 7.1、何為webpack模塊
- 7.2、支持的模塊類型
- 8、模塊解析(Module Resolution)
- 8.1、webpack中的解析規(guī)則
- 8.2、解析loader
- 8.3、緩存
- 9、Module Fedration
- 9.1、動機
- 9.2、底層概念
- 9.3、高級概念
- 9.4、構(gòu)建塊(Building blocks)
- 9.5、概念目標
- 9.6、用例
- 9.7、基于Promise的動態(tài)Remote
- 9.8、動態(tài)Public Path
- 10、更多

本質(zhì)上,webpack是一個用于現(xiàn)代JavaScript應(yīng)用程序的靜態(tài)模塊打包工具。當webpack處理應(yīng)用程序時,它會在內(nèi)部從一個或多個入口點構(gòu)建一個依賴圖,然后將你項目中所需的每一個模塊組合成一個或多個bundles,它們均為靜態(tài)資源,用于展示你的內(nèi)容。
從v4.0.0開始,webpack 可以不用再引入一個配置文件來打包項目,然而,它仍然有著高度可配置性,可以很好滿足你的需求。
在開始前需要先了解一些核心概念:
- 入口(entry)
- 輸出(output)
- loader
- 插件(plugin)
- 模式(mode)
- 瀏覽器兼容性(browser compatibility)
- 環(huán)境(environment)
入口起點(entry point)指示webpack應(yīng)該使用哪個模塊,來作為構(gòu)建其內(nèi)部依賴圖(dependency graph)的開始。進入入口起點后,webpack會找到有哪些模塊和庫是入口起點(直接和間接)的依賴。
默認值是./src/index.js,但你可以通過在webpack configuration中配置entry屬性,來指定一個(或多個)不同的入口起點。例如:
webpack.config.js
module.exports = {entry: './path/to/my/entry/file.js',
};1.2、輸出(output)output屬性告訴webpack在哪里輸出它所創(chuàng)建的bundle。以及如何命名這些文件。主要輸出文件的默認值是"./dist/main.js",其他生成文件默認放置在"./dist.js"文件夾中。
你可以通過在配置中指定一個output字段,來配置這些處理過程:
webpack.config.js
const path = require('path')
module.exports = {entry: './path/to/my/entry/file.js',
output: {path: path.resolve(__dirname, 'dist'), // bundle生成(emit)到哪里
filename: 'my-first-webpack.bundle.js', // 告訴webpack bundle的名稱
……
}
}1.3、loaderwebpack只能理解JavaScript和JSON文件,這是webpack開箱可用的自帶能力。loader讓webpack能夠去處理其他類型的文件,并將它們轉(zhuǎn)化為有效的模板,以供應(yīng)用程序使用,以及被添加到依賴圖中。
Warnig
webpack的其中一個強大的特性就是能通過import導入任何類型的模板(例如.css文件),其他打包程序或執(zhí)行器的可能不支持。我們認為這種語言擴展是很有必要的,因為這可以使開發(fā)人員創(chuàng)建出更準確地依賴關(guān)系圖。
在更高層面,在webpack的配置中,loader有兩個屬性:
- test屬性,識別出哪些文件會被轉(zhuǎn)換。
- use屬性,定義出在進行轉(zhuǎn)換時,應(yīng)該使用哪個loader。
webpack.config.js
moudle.exports = {output: {filename: 'my-first-webpack.bundle.js'
},
module: {rules: [{test:/\.txt$/, use: 'raw-loader'}]
}
}在以上配置中,對一個單獨的module對象定義了rules屬性,里面包含兩個必須屬性:test和use。告訴webpack編譯器(compiler)如下信息:
在require()/import語句中被解析為.txt的路徑時,在你對它打包之前,先用use(使用)raw-loader轉(zhuǎn)換一下。
Warning
重要的是:在webpack配置中定義rules時,要定義在module.rules而不是rules中。為了使你便于理解,如果沒有按照正確的方式去做,webpack會給出警告。
1.4、插件(plugin)Warning
在使用正則表達式匹配文件時,不要為它添加引號。也就是說,/.txt / 與 ′ / t ˙ x t /與 '/\.txt /與′/t˙xt/’ 或者 “/.txt$/” 不一樣。前者指示webpack匹配任何以.txt結(jié)尾的文件,后者指示webpack匹配具有絕對路徑‘.txt’的單個文件;這可能不符合你的意圖。
loader用于轉(zhuǎn)換某些類型的模塊,而插件則可以用于執(zhí)行范圍更廣的任務(wù)。包括:打包優(yōu)化,資源管理,注入環(huán)境變量等。
想要使用一個插件,你只需要require()它,然后把它添加到plugins數(shù)組中。多數(shù)插件可以通過選項(option)自定義。你也可以在一個配置文件中因為不同目的而多次使用同一個插件,這時需要通過使用new操作符來創(chuàng)建一個插件實例。
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack') // 用于訪問內(nèi)直插件
module.exports = {module: [{test: /\.txt$/, use: 'raw-loader'}],
plugins: [new HtmlWebpackPlugin({template: './src/index.html'})]
}在上面的示例中,html-webpack-plugin為應(yīng)用程序生成一個HTML文件,并自動將生成的所有bundle注入到此文件中。
1.5、模式(mode)通過選擇developmemt,production或none之中的一個,來設(shè)置mode參數(shù),你可以啟用webpack內(nèi)置在相應(yīng)環(huán)境下的優(yōu)化。其默認值為production。
module.exports = {mode: 'production',
}1.6、瀏覽器兼容性(browser compatibility)Webpack支持所有符合ES5標準的瀏覽器(不支持IE8及以下版本)。
webpack的import()和require.ensure()需要Promise。如果你想要支持舊版本瀏覽器,在使用這些表達式之前,還要提前加載polyfill。
Webpack5運行于Node.js v10.13.0+的版本
2、入口起點(entry points) 2.1、單個入口(簡寫)語法用法:entry: string | [string]
webpack.config.js
module.exports = {entry: './path/to/my/entry/file.js'
}entry屬性的單個入口語法,是以下形式的簡寫:
module.exports = {entry: {main: './path/to/my/entry/file.js'
}
}也可以將一個文件路徑數(shù)組傳遞給entry屬性,這將創(chuàng)建一個所謂的‘multi-main entry’。在你想要一次注入多個依賴文件,并將它們的依賴關(guān)系繪制在一個‘chunk’中時,這種方式就很有用。
module.exports = {entry: ['./src/file_1.js', './src/file_2.js'],
output: {filename: 'bundle.js',
},
};2.2、對象語法用法:
entry: {string | [string] } | {}
module.exports = {entry: {app: './src/app.js',
adminApp: './src/adminApp.js'
}
} 對象語法會比較繁瑣。然而,這是應(yīng)用程序中定義入口的最可擴展的方式。
Tip
“webpack配置的可擴展”是指,這些配置可以重復使用,并且可以與其他配置組合使用。這是一種流行的技術(shù),用于將關(guān)注點從環(huán)境(environment)、構(gòu)建目標(build target)、運行時(runtime)中分離。然后使用專門的工具(如webpack-merge)將它們合并起來。
2.2.1、描述入口的對象“Tip”
當你通過插件生成入口時,你可以傳遞空對象{}給entry。
用于描述入口的對象。你可以使用如下屬性:
- dependOn: 當前入口所依賴的入口。它們必須在該入口被加載前被加載。
- import:啟動時需要加載的模塊。
- library:指定library選項,為當前entry構(gòu)建一個library。
- runtime:運行時chunk的名字。如果設(shè)置了,就會創(chuàng)建一個新的運行時chunk。在webpack5.43.0之后可將其設(shè)置為false以避免一個新的運行時chunk。
- publicPath:當該入口的輸出文件在瀏覽器中被引用時,為它們指定一個公共URL地址??刹榭磑utput.publicPath.
runtime和dependOn不應(yīng)該在同一個入口上同時使用,所以如下配置無效,并會拋出錯誤:module.exports = {entry: {a2: 'dependingfile.js', b2: { dependOn: 'a2', import: './src/app.js' } } }
確保runtime不能指向已存在的入口名稱,例如下面配置會拋出一個錯誤:module.exports = {entry: {a2: './a', b2: { runtime: 'x2', dependOn: 'a2', import: './b', }, }, };
另外dependOn不能是循環(huán)引用的,下面的例子也會出現(xiàn)錯誤:module.exports = {entry: {a1: './a', b1: { runtime: 'a1', import: './b' } } }module.exports = {entry: {a3: { import: './a', dependOn: 'b3', }, b3: { import: './b', dependOn: 'a3' } } }
以下列出一些入口配置和他們的實際用例:
2.3.1、分離app和vendor(第三方庫)入口// webpack.config.js
module.exports = {module.exports = {entry: { main: './src/app.js',
vendor: './src/vendor.js',
}
}
}
// webpack.prod.js
module.exports = {output: {filename: '[name].[contenthash].bundle.js,
}
}
// webpack.dev.js
module.exports = {module.exports = {filename: '[name].bundle.js'
}
}這是告訴webpack我們想要配置2個單獨的入口點(例如上面的示例)。
這樣就可以在vendor.js中存入未做修改的必要library或文件(例如Bootstrap,JQuery,圖片等),然后將它們打包在一起成為單獨的chunk。內(nèi)容哈希保持不變,這使瀏覽器可以獨立地緩存它們,從而減少了加載時間。
2.3.2、多頁面應(yīng)用程序Tip
在webpack< 4中不鼓勵這樣做,通常將vendor作為一個單獨的入口起點添加到entry選項中,以將其編譯為一個單獨的文件(與CommonsChunkPlugin結(jié)合使用)。
而在webpack4中不鼓勵這樣做,而是使用optimization.splitChunks選項,將vendor和app模塊分開,并為其創(chuàng)建一個單獨的文件。不要為vendor或其他不是執(zhí)行起點創(chuàng)建entry。
module.exports = {entry: {pageOne: './src/pageone/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
}告訴webpack需要三個獨立分離的依賴圖(如上面的示例)。
原因:在多頁面應(yīng)用程序中,server會拉取一個新的HTML文檔給你的客戶端。頁面重新加載此新文檔,并且資源被重新下載。然而,這給了我們特殊的機會去做很多事情,例如使用optimization.splitChunks為頁面間共享的應(yīng)用程序代碼創(chuàng)建bundle。由于入口起點數(shù)量的增多,多頁應(yīng)用能夠復用多個入口起點之間的大量代碼/模塊,從而可以極大地從這些技術(shù)中受益。
3、輸出(output)根據(jù)經(jīng)驗:每個HTML文檔只使用一個入口起點。
可以通過配置output選項,告知webpack如何向硬盤寫入編譯文件。注意,即使可以存在多個entry起點,但只能指定一個output配置。
3.1、用法在webpack配置中,output屬性的最低要求是,將它的值設(shè)置為一個對象,然后為將輸出文件名配置為一個output.filename:
module.exports = {output: {filename: 'bundle.js'
}
}此配置將一個單獨的bundle.js文件輸出到dist目錄中。
3.2、多個入口起點如果配置中創(chuàng)建出多余一個“chunk”(例如,使用多個入口起點或使用像CommonsChunkPlugin這樣的插件),則應(yīng)該使用占位符(substitutions)來確保每個文件具有唯一的名稱。
module.exports = {entry: {app: './src/app.js',
search: './src/search.js'
},
output: {filename: '[name].js',
path: __dirname + '/dist'
}
}
// 寫入到硬盤:./dist/app.js, ./dist/search.js3.3、高級進階以下是對資源使用CDN和hash的復雜示例:
config.js
module.exports = {output: {path: '/home/proj/cdn/assets/[fullhash]',
publicPath: 'https://cdn.example.com/assets/[fullhash]'
}
}如果在編譯時,不知道最終輸出文件的publicPath是什么地址,則可以將其留空,并且在運行時通過入口起點文件中的__webpack_public_path__ 動態(tài)設(shè)置
__webpack_public_path__ = myRuntimePublicPath4、loaderloader用于對模塊的源碼進行轉(zhuǎn)換。loader可以使你在import或“l(fā)oad(加載)”模塊時預處理文件。因此,loader類似于其他構(gòu)建工具中“任務(wù)(task)”,并提供了處理前端構(gòu)建步驟的得力方式。loader可以將文件從不同的語言(如TypeScript)轉(zhuǎn)換為JavaScript或?qū)?nèi)聯(lián)圖像轉(zhuǎn)換為data URL。loader甚至允許你直接在JavaScript模板中import CSS文件!
4.1、示例例如,你可以使用loader告訴webpack加載css文件,或者將TypeScript轉(zhuǎn)換為JavaScript。為此,首先安裝相對應(yīng)的loader:
npm install --save-dev css-loader ts-loader然后指示webpack對每個.css使用css-loader,以及對所有.ts文件使用ts-loader:
webpack.config.js
module.exports = {module: {rules: [
{test: /\.css$/, use: 'css-loader'},
{test: /\.ts$/, use: 'ts-loader'}
]
}
}4.2、使用loader在你的應(yīng)用程序中,有兩種使用loader的方式:
- 配置方式(推薦):在webpack.config.js文件中指定loader。
- 內(nèi)聯(lián)方式:在每個import語句中顯示指定loader。
注意在webpack v4版本可以通過CLI使用loader,但在webpack v5中被棄用。
module.rules允許你在webpack配置中指定多個loader。這種方式是展示loader的一種簡明的方式,并且有助于使代碼變得簡潔和易于維護。同時讓你對各個loader有個全局概覽:
loader從右到左,從sass-loader開始執(zhí)行,然后繼續(xù)執(zhí)行css-loader,最后以style-loader為結(jié)束。
module.exports = {module: {rules: [{ test: /\.css$/,
use: [
{loader: 'style-loader'},
{ loader: 'css-loader',
options: {modules: true,
}
},
{loader: 'sass-loader' }
]
}]
}
}4.4、內(nèi)聯(lián)方式可以在import語句或任何與import方法同等的引用方式中指定loader。使用!將資源中的loader分開。每部分都會相當于當前的目錄解析。
import Styles from 'style-loader!css-loader?modules!./styles.css';通過為內(nèi)聯(lián)import語句添加前綴,可以覆蓋配置中的所有l(wèi)oader,preLoader和postLoader:
- 使用!前綴,將禁用所有已配置的normal loader(普通loader)
import Styles from '!style-loader!css-loader?modules!./styles.css'- 使用?。∏熬Y,將禁用所有已配置的loader(preLoader, loader, postLoader)
import Styles from '!!style-loader!css-loader?modules!./styles.css'- 使用-!前綴,將禁用所有已配置的preLoader和loader,但是不禁用postLoaders
import Styles from '-!style-loader!css-loader?modules!./styles.css'選項可以傳遞查詢參數(shù),例如?key=value&foo=bar,或者一個JSON對象,例如?{‘key’:‘value’,‘foo’:‘bar’}
4.5、loader特性Tip
盡可能使用module.rules,因為這樣可以減少源碼中樣板文件的代碼量,并且可以在出錯時,更快地調(diào)試和定位loader中的問題。
- loader支持鏈式調(diào)用。鏈中的每個loader會將轉(zhuǎn)換應(yīng)用在已處理過的資源上。一組鏈式的loader將按照相反的順序執(zhí)行。鏈中的第一個loader將其結(jié)果(也就是應(yīng)用過轉(zhuǎn)換后的資源)傳遞給下一個loader,依次類推。最后,鏈中的最后一個loader,返回webpack所期望的Javascript。
- loader可以是同步的,也可以是異步的。
- loader運行在Node.js中,并能夠執(zhí)行任何操作。
- loader可以通過options對象配置(仍然支持使用query參數(shù)來設(shè)置選項,但是這種方式已被廢棄)。
- 除了常見的package.json的main來將npm模塊導出為loader,還可以在module.rules中使用loader字段直接引用一個模塊。
- 插件(plugin)可以為loader帶來更多特性。
- loader能夠產(chǎn)生額外的任意文件。
可以通過loader的預處理函數(shù),為JavaScript生態(tài)系統(tǒng)提供更多能力。用戶現(xiàn)在可以更加靈活地引入細粒度邏輯,例如:壓縮、打包、語言轉(zhuǎn)譯(或編譯)和更多其他特性。
4.6、解析loaderloader遵循標準模塊解析規(guī)則。多數(shù)情況下,loader將從模塊路徑加載(通常是從npm install,node_modules進行加載)。
我們預期loader模塊導出為一個函數(shù),并且編寫為Node.js兼容的Javascript。通常使用npm進行管理loader,但是也可以將應(yīng)用程序中的文件作為自定義loader。按照規(guī)定,loader通常被命名為xxx-loader(例如json-loader)。
插件是webpack的支柱功能。Webpack自身也是構(gòu)建于你在webpack配置中用到的相同的插件系統(tǒng)之上。
插件目的在于解決loader無法實現(xiàn)的其他事。webpack提供很多開箱即用的插件。
5.1、剖析Tip
如果在插件中使用了webpack-sources的package,請使用require(‘webpack’).source替代require(‘webpack-source’),以避免持久緩存的版本沖突。
webpack 插件是一個具有apply方法的Javascript對象。apply方法會被webpack compiler調(diào)用,并且在整個編譯生命周期都可以訪問compiler對象。
ConsoleLogOnBuildWebpackPlugin.js
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin { apply(compiler) {compiler.hooks.run.tap(pluginName, (compilation) =>{ console.log('webpack 構(gòu)建正在啟動');
})
}
}
module.exports = ConsoleLogOnBuildwebpackPlugin;compiler hook的tap方法的第一個參數(shù),應(yīng)該是駝峰式命名的插件名稱。建議為此使用一個常量,以便它可以在所有的hook中重復使用。
5.2 用法由于插件可以攜帶參數(shù)/選項,你必須在webpack配置中,向plugins屬性傳入一個new實例。
取決于你的webpack用法,對應(yīng)有多種使用插件的方式。
5.3 配置方式webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack'); // 訪問內(nèi)置的插件
const path = require('path');
module.exports = {entry: './path/to/my/entry/file.js',
output: {filename: 'my-first-webpack.bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {rule: [
{test: /\.(js|jsx)$/,
use: 'bable-loader',
}
]
},
plugins: [
new webpack.ProgressPlugin(),
new HtmlWebpackPlugin({tempalte: './src/index.html'})
]
}ProgressPlugin用于自定義編譯過程中的進度報告,HtmlWebpackPlugin將生成一個HTML文件,并在其中使用script引入一個名為my-first-webpack.bundle.js的JS文件。
5.4、Node API方式在使用Node API 時,還可以通過配置中的plugins屬性傳入插件。
some-node-script.js
const webpack = require('webpack'); // 訪問webpack運行時(runtime)
const configuration = require('./webpack.config.js')
let compiler = webpack('configuration');
new webpack.ProgressPlugin().apply(compiler)
compiler.run(function(err, stats) {// ...
})6、配置(Configuration)在線配置示例:https://createapp.dev/webpack/no-library–html-webpack-plugin
你可能已經(jīng)注意到,很少有webpack配置看起來完全相同。這是因為webpack的配置文件是Javascript文件,文件內(nèi)導出了一個webpack配置對象。webpack會根據(jù)該配置定義的屬性進行處理。
由于webpack遵循Commonjs模板規(guī)范,因此,你可以在配置中使用:
- 通過require(…)引入其他文件
- 通過require(…)使用npm下載的工具函數(shù)
- 使用Javascript控制流表達式,例如?:操作符
- 對value使用常量或變量賦值
- 編寫并執(zhí)行函數(shù),生成部分配置
請在合適的場景,使用這些功能。
雖然技術(shù)上可行,但還是應(yīng)避免如下操作:
- 當使用webpack CLI工具時,訪問CLI參數(shù)(應(yīng)編寫自己的CLI工具替代,或者使用 --dev)
- 導出不確定的結(jié)果(兩次調(diào)用webpack應(yīng)產(chǎn)生相同的輸出文件)
- 編寫超長的配置(應(yīng)將配置文件拆分成多個)
Tip
此文檔中得出最重要的結(jié)論是,webpack的配置可以有許多不同的樣式和風格。關(guān)鍵在于,為了易于維護和理解這些配置,需要在團隊內(nèi)部保證一致。
接下來的示例中,展示了webpack配置如何實現(xiàn)即可表達,又可靈活配置,這主要得益于 配置即為代碼:
6.1、基本配置webpack.config.js
const path = require('path');
module.exports = {mode: 'development',
entry: './foo.js',
output: {path: path.resolve(__dirname, 'dist'),
filename: 'foo.bundle.js',
}
}6.2、多個target除了可以將單個配置導出為object、function或Promise以外,還可以將其導出為多個配置。
6.3、使用其他配置語言Webpack支持有多種編程和數(shù)據(jù)語言編寫的配置文件。
7、模塊(Modules)在模塊化編程中,開發(fā)者將程序分解為功能離散的chunk,并稱之為模塊。
每個模塊都擁有小于完整程序的體積,使得驗證、調(diào)試及測試變得輕而易舉。精心編寫的模塊提供了可靠的抽象和封裝界限,使得應(yīng)用程序中每個模塊都具備了條理清晰的設(shè)計和明確的目的。
Node.js從一開始就支持模塊化編程。然而,web的模塊化正在緩慢支持中。在web界存在多種支持Javascript模塊化工具,這些工具各有優(yōu)勢和限制。Webpack從這些系統(tǒng)中汲取經(jīng)驗和教訓,并將模塊的概念應(yīng)用到項目的任何文件中。
7.1、何為webpack模塊與Node.js模塊相比,webpack模塊能以各種方式表達它們的依賴關(guān)系。下面是一些示例:
- ES2015 import語句
- CommonJS require()語句
- AMD define和require語句
- css/sass/less文件中的@import語句
- stylesheet url(…)或者HTML的img src=…文件中的圖片鏈接。
Webpack天生支持如下模塊類型:
- ECMAScript模塊
- CommonJS模塊
- AMD模塊
- Assets
- WebAssembly模塊
通過loader可以使webpack支持多種語言和預處理器語法編寫的模塊。loader向webpack描述了如何處理非原生模塊,并將相關(guān)依賴引入到你的bundles中。webpack社區(qū)已經(jīng)為各種流行的語言和預處理器創(chuàng)建了loader,其中包括:
- CoffeeScript
- TypeScript
- ESNext(Bable)
- Sass
- Less
- Stylus
- Elm
- …
總的來說,webpack提供了可定制,強大且豐富的API,允許在任何技術(shù)棧中使用,同時支持在開發(fā)、測試和生產(chǎn)環(huán)境的工作流中做到無入侵性。
8、模塊解析(Module Resolution)resolver是一個幫助尋找模塊絕對路徑的庫。一個模塊可以作為另一個模塊的依賴模塊,然后被后者引用,如下:
import foo from 'path/to/module';
// 或者
require('path/to/module')所依賴的模塊可以是來自應(yīng)用程序的代碼或第三方庫。resolver幫助webpack從每個require/import語句中,找到需要引入到bundle中的模塊代碼。當打包模塊時,webpack使用enhanced-resolve來解析文件路徑。
8.1、webpack中的解析規(guī)則使用enhanced-resolve,webpack能解析三種文件路徑:
絕對路徑
import '/home/me/file';
import 'c:\\Users\\me\\file';由于已經(jīng)獲得文件的絕對路徑,因此不需要再做進一步解析。
相對路徑
import '../src/file1';
import './file2';在這種情況下,使用import或require的源文件所在的目錄,被認為是上下文目錄,在import/require中給定的相對路徑,會拼接此上下文路徑,來生成模塊的絕對路徑。
模塊路徑
import 'module';
import 'module/lib/file';在resolve.modules中指定的所有目錄中檢索模塊。你可以通過配置別名的方式來替換初始模塊路徑,具體請參照resolve.alias配置選項。
- 如果package中包含package.json文件,那么在resolve.exportsFields配置選項中指定的字段會被依次查找,package.json中的第一個字段會根據(jù)package導出指定確認package中可用的export。
一旦根據(jù)上述規(guī)則解析路徑后,resolver將會檢查路徑是指向文件還是文件夾。如果路徑指向文件:
- 如果文件具有擴展名,則直接將文件打包。
- 否則,將使用resolve.extensions選項作為文件擴展名來解析,此選項會告訴解析器中能夠接受那些擴展名(例如 .js,.jsx)。
如果路徑指向一個文件夾,則進行如下步驟尋找具有正確擴展名的文件:
- 如果文件夾中包含package.json文件,則會根據(jù)resolve.mainFields配置中的字段順序
查找,并根據(jù)package.json中符合配置要求的第一個字段來確定文件路徑。 - 如果不存在package.json文件或resolve.mainFields沒有返回有效路徑,則會根據(jù)resolve.mainFiles配置選項中指定的文件名順序查找,看是否能在import/require的目錄下匹配到一個存在的文件名。
- 然后使用resolve.extensions選項,以類似的方式解析文件擴展名。
Webpack會根據(jù)構(gòu)建目標,為這些選項提供合理的默認配置。
8.2、解析loaderloader的解析規(guī)則也遵循特定的規(guī)范。但是resolveLoader配置項可以為loader設(shè)置獨立的解析規(guī)則。
8.3、緩存每次文件系統(tǒng)訪問文件都會被緩存,以便更快觸發(fā)對同一文件的多個并行或串行請求。在watch模式下,只有修改過的文件會被從緩存中移出。如果關(guān)閉watch模式,則會在每次編譯前清理緩存。
9、Module Fedration 9.1、動機多個獨立的構(gòu)建可以組成一個應(yīng)用程序,這些獨立的構(gòu)建之間不應(yīng)該存在依賴關(guān)系,因此可以單獨開發(fā)和部署他它們。
9.2、底層概念我們區(qū)分本地模塊和遠程模塊。本地模塊即為普通模塊,是當前構(gòu)建的一部分。遠程模塊不屬于當前構(gòu)建,并在運行時從所謂的容器加載。
加載遠程模塊被認為是異步操作。當使用遠程模塊時,這些異步操作將被放置在遠程模塊和入口之間的下一個chunk的加載操作中。如果沒有chunk加載操作,就不能使用遠程模塊。
chunk的加載操作通常是通過調(diào)用import()實現(xiàn)的,但也支持像require.ensure或require([…])子類的舊語法。
容器是由容器入口創(chuàng)建的,該入口暴露了對特定模塊的異步訪問。暴露的訪問分為兩個步驟:
- 加載模塊(異步的)
- 執(zhí)行模塊(同步的)
步驟1將在chunk加載期間完成。步驟2將在與其他(本地和遠程)的模塊交錯執(zhí)行期間完成。這樣一來,執(zhí)行順序不受模塊從本地轉(zhuǎn)換為遠程或遠程轉(zhuǎn)換為本地的影響。
容器可以嵌套使用,容器可以使用來自其他容器的模塊。容器之間也可以循環(huán)依賴。
9.3、高級概念每個構(gòu)建都充當一個容器,也可以將其他構(gòu)建作為容器。通過這種方式,每個構(gòu)建都能夠通過從對應(yīng)容器中加載模塊來訪問其他容器暴露出來的模塊。
共享模塊是指即可重寫的又可作為向嵌套容器提供重寫的模塊。它們通常指向每個構(gòu)建中的相同模塊,例如相同的庫。
packageName選項允許通過設(shè)置包名來查找所需要的版本。默認情況下,它會自動推斷模塊請求,當想禁用自動推斷時,請將requiredVersion設(shè)置為false。
9.4、構(gòu)建塊(Building blocks)ContainerPlugin(low level)
該插件使用指定的公開模塊來創(chuàng)建一個額外的容器入口。
ContainerReferencePlugin(low level)
該插件將特定的引用添加到作為外部資源(externals)的容器中,并允許從這些容器中導入遠程模塊。它還會調(diào)用這些容器的override API來為它們提供重載(當構(gòu)建也是一個容器時,通過__webpack__override__或override API)和指定的重載被提供給所有引用的容器。
ModuleFederationPlugin(high level)
ModuleFederation組合了ContainerPlugin和ContainerReferencePlugin。
- 它既可以暴露,又可以使用webpack支持的任何模塊類型。
- 代碼塊加載應(yīng)該并行加載所需的所有的內(nèi)容(web:到服務(wù)器的單次往返)
- 從使用者到容器的控制
- 重寫模塊是一種單向操作
- 同級容器不能重寫彼此的模塊
- 概念適用于獨立于環(huán)境
- 可用于web、Node.js等
- 共享中的相對和絕對請求
- 會一直提供,即使不使用
- 會將相對路徑解析到config.context
- 默認不會使用requiredVersion
- 共享中的模塊請求
- 只在使用時提供
- 會匹配構(gòu)建中所有使用的相等模塊請求
- 將提供所有匹配模塊
- 將從圖中這個位置的 package.json 提取 requiredVersion
- 當你有嵌套的 node_modules 時,可以提供和使用多個不同的版本
- 共享中尾部帶有 / 的模塊請求將匹配所有具有這個前綴的模塊請求
每個頁面單獨構(gòu)建
單頁應(yīng)用的每個頁面都是在單獨的構(gòu)建中從容器暴露出來的。主體應(yīng)用程序(application shell)也是獨立構(gòu)建,會將所有頁面作為遠程模塊來引用。通過這種方式,可以單獨部署每個頁面。在更新路由或添加新路由時部署主體應(yīng)用程序。主體應(yīng)用程序?qū)⒊S脦於x為共享模塊,以避免在頁面構(gòu)建中出現(xiàn)重復。
將組件庫作為容器
許多應(yīng)用程序共享一個通用的組件庫,可以將其構(gòu)建成暴露所有組件的容器。每個應(yīng)用程序使用來自組件庫容器的組件??梢詥为毑渴饘M件庫的更改,而不需要重新部署所有應(yīng)用程序。應(yīng)用程序自動使用組件庫的最新版本。
動態(tài)遠程容器
該容器接口支持 get 和 init 方法。 init 是一個兼容 async 的方法,調(diào)用時,只含有一個參數(shù):共享作用域?qū)ο?shared scope object)。此對象在遠程容器中用作共享作用域,并由 host 提供的模塊填充。 可以利用它在運行時動態(tài)地將遠程容器連接到 host 容器。
(async () =>{// 初始化共享作用域(shared scope)用提供的已知此構(gòu)建和所有遠程的模塊填充它
await __webpack_init_sharing__('default');
const container = window.someContainer; // 或從其他地方獲取容器
// 初始化容器 它可能提供共享模塊
await container.init(__webpack_share_scopes__.default);
const module = await container.get('./module');
})();容器嘗試提供共享模塊,但是如果共享模塊已經(jīng)被使用,則會發(fā)出警告,并忽略所提供的共享模塊。容器仍能將其作為降級模塊。
你可以通過動態(tài)加載的方式,提供一個共享模塊的不同版本,從而實現(xiàn) A/B 測試。
Tip
在嘗試動態(tài)連接遠程容器之前,確保已加載容器。
例子:
init.js
function loadComponent(scope, module) {return async () =>{// 初始化共享作用域(shared scope)用提供的已知此構(gòu)建和所有遠程的模塊填充它
await __webpack_init_sharing__('default');
const container = window[scope]; // 或從其他地方獲取容器
// 初始化容器 它可能提供共享模塊
await container.init(__webpack_share_scopes__.default);
const factory = await window[scope].get(module);
const Module = factory();
return Module;
};
}
loadComponent('abtests', 'test123');9.7、基于Promise的動態(tài)Remote一般來說,remote是使用URL配置的,示例如下:
module.exports = {plugins: [
new ModuleFederationPlugin({ name: 'host',
remotes: {app1: ''
}
})
]
}但是你也可以向remote傳遞一個promise,其會在運行時被調(diào)用。你應(yīng)該用符合上面描述的get/init接口的模板來調(diào)用這個promise。例如,如果你想傳遞你應(yīng)該使用哪個版本的聯(lián)邦模塊,你可以通過一個查詢參數(shù)做一些事情。
9.8、動態(tài)Public Path提供一個host api以設(shè)置publicPath
可以允許host在運行時通過公開遠程模塊的方法來設(shè)置遠程模塊的publicPath。
當你在host域的子路徑上掛載獨立部署的子應(yīng)用程序時,這種方法特別有用。
場景:
你在 https://my-host.com/app/* 上有一個 host 應(yīng)用,并且在 https://foo-app.com 上有一個子應(yīng)用。子應(yīng)用程序也掛載在 host 域上, 因此, https://foo-app.com 可以通過 https://my-host.com/app/foo-app 訪問,并且 https://my-host.com/app/foo-app/* 可以通過代理重定向到 https://foo-app.com/*。
示例:
webpack.config.js (remote)
module.exports = {entry: {remote: './public-path',
},
plugins: [
new ModuleFederationPlugin({ name: 'remote', // 該名稱必須與入口名稱相匹配
exposes: ['./public-path'],
// ...
}),
],
};public-path.js (remote)
export function set(value) {__webpack_public_path__ = value;
}src/index.js (host)
const publicPath = await import('remote/public-path');
publicPath.set('/your-public-path');
//bootstrap app e.g. import('./bootstrap.js')10、更多https://webpack.docschina.org/
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
新聞名稱:Webpack摘抄-創(chuàng)新互聯(lián)
文章路徑:http://www.dlmjj.cn/article/jgops.html


咨詢
建站咨詢
