詳解Webpack loader 之 file-loader
簡介
安裝
npm install --save-dev file-loader
用法
默認情況下,生成的文件的文件名就是文件內(nèi)容的 MD5 哈希值并會保留所引用資源的原始擴展名。
import img from './webpack-logo.png'
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {}
}
]
}
]
}
}
生成文件 bd62c377ad80f89061ea5ad8829df35b.png (默認的文件名為 [hash].[ext]),輸出到輸出目錄并返回 public URL。
"/public/path/bd62c377ad80f89061ea5ad8829df35b.png"
當然如果不想使用默認的文件名,我們也可以通過配置 options.name 選項來設(shè)置輸出的文件名命名規(guī)則,需要注意的是 name 選項支持的類型為: {String|Function} :
String 類型
webpack.config.js
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]'
}
}
Function 類型
webpack.config.js
{
loader: 'file-loader',
options: {
name (file) {
if (env === 'development') {
return '[path][name].[ext]'
}
return '[hash].[ext]'
}
}
}
以上的示例中,我們使用了 [path] , [name] , [hash] 和 [ext] 占位符,它們對應(yīng)的含義是:
- [ext]:String,默認值為 file.extname,表示資源擴展名;
- [name]:String,默認值為 file.basename,表示資源的基本名稱;
- [path]:String,默認值為 file.dirname,表示資源相對于 context 的路徑;
- [hash]:String,默認值為 md5,內(nèi)容的哈希值,支持靈活的 hashes 配置,配置規(guī)則為:[<hashType>:hash:<digestType>:<length>],對應(yīng)的說明如下:

其實除了以上常用的四個占位符之外,還有支持 [N] ,N 是數(shù)值類型,表示當前文件名按照查詢參數(shù) regExp 匹配后獲得到第 N 個匹配結(jié)果。介紹完 name 配置項,接下來我們來繼續(xù)介紹幾個常用的配置。
常用配置項 outputPath
outputPath 用于配置自定義 output 輸出目錄,支持 String|Function 類型,默認值為 ‘undefined',用法如下:
webpack.config.js
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
outputPath: 'images/'
}
}
需要注意的是,outputPath 所設(shè)置的路徑,是相對于 webpack 的輸出目錄。
publicPath
publicPath 用于配置自定義 public 發(fā)布目錄,支持 String|Function 類型,默認值為 __webpack_public__path__ ,用法如下:
webpack.config.js
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
publicPath: 'assets/'
}
}
emitFile
emitFile 用于設(shè)置是否生成文件,類型是 Boolean,默認值為 true。但我們可以通過將 emitFile 設(shè)置為 false 來禁用該默認行為。
webpack.config.js
{
loader: 'file-loader',
options: {
emitFile: false
}
}
outputPath vs publicPath
outputPath 僅僅告訴 webpack 結(jié)果存儲在哪里,然而 publicPath 選項則被許多 webpack 的插件用于在生產(chǎn)模式下更新內(nèi)嵌到 css、html 文件內(nèi)的 url 值。例如:
// Development: Both Server and the image are on localhost
.image {
background-image: url('./test.png');
}
// Production: Server is on Heroku but the image is on a CDN
.image {
background-image: url('https://some-cdn/test.png');
}
loader 準則
編寫 loader 時應(yīng)該遵循以下準則:
- 簡單易用。
- 使用鏈式傳遞。
- 模塊化的輸出。
- 確保無狀態(tài)。
- 使用 loader utilities。
- 記錄 loader 的依賴。
- 解析模塊依賴關(guān)系。
- 提取通用代碼。
- 避免絕對路徑。
- 使用 peer dependencies。
以上的準則按重要程度排序,但某些僅適用于某些場景。若想進一步了解自定義 loader,可以閱讀 編寫一個 loader 這個文檔。接下來,我們來基于上述的準則分析一下 file-loader 的源碼。
file-loader 源碼簡析
所謂 loader 只是一個導(dǎo)出為函數(shù)對象的 JavaScript 模塊。 loader runner 會調(diào)用這個函數(shù),然后把上一個 loader 產(chǎn)生的結(jié)果或者資源文件傳入進去。 函數(shù)的 this 上下文將由 webpack 填充,并且 loader runner 具有一些有用方法,可以使 loader 改變?yōu)楫惒秸{(diào)用方式,或者獲取 query 參數(shù) 。
其實本文介紹的 file-loader 并不會對文件的內(nèi)容進行任何轉(zhuǎn)換,只是復(fù)制一份文件內(nèi)容,并根據(jù)相關(guān)的配置生成對應(yīng)的文件名,所生成的文件名一般會帶上 hash 值,從而避免文件重名導(dǎo)致沖突。接下來我們來簡單分析一下 file-loader 的部分源碼。
導(dǎo)入依賴模塊
import path from 'path'; import loaderUtils from 'loader-utils'; import validateOptions from 'schema-utils'; import schema from './options.json';
獲取配置對象及驗證
export default function loader(content) {
if (!this.emitFile)
throw new Error('File Loader\n\nemitFile is required from module system');
const options = loaderUtils.getOptions(this) || {};
validateOptions(schema, options, 'File Loader');
}
以上代碼中,emitFile 是由 loader 上下文提供的方法,用于輸出一個文件,對應(yīng)的函數(shù)簽名如下:
emitFile(name: string, content: Buffer|string, sourceMap: {...})
在調(diào)用 file-loader 時,如果發(fā)現(xiàn) this.emitFile 無效,則會拋出異常。接著 file-loader 會先調(diào)用 loaderUtils.getOptions() 方法,獲取當前 loader 對應(yīng)的配置對象,然后基于已定義的 Schema,驗證配置對象的有效性。對應(yīng)的 Schema 定義如下(不包含異常提示信息):
{
"type": "object",
"properties": {
"name": {},
"regExp": {},
"context": {
"type": "string"
},
"publicPath": {},
"outputPath": {},
"useRelativePath": {
"type": "boolean"
},
"emitFile": {
"type": "boolean"
}
},
"additionalProperties": true
}
獲取 context 及生成文件名稱
const context =
options.context //自定義文件context
// 從webpack 4開始,原先的this.options.context
// 被改進為this.rootContext
|| this.rootContext ||
(this.options && this.options.context);
const url = loaderUtils.interpolateName(
this,
options.name, // 默認為"[hash].[ext]"
{
context,
content,
regExp: options.regExp,
});
loaderUtils 中的 interpolateName 方法,用于生成對應(yīng)的文件名,該方法的簽名如下:
interpolateName(loaderContext, name, options);
其中 loaderContext 為 loader 的上下文對象,name 為文件名稱模板,options 為配置對象,支持 context,content 和 regExp 屬性。該方法的使用示例如下:
示例一:
// loaderContext.resourcePath = "/app/js/javascript.js";
let interpolatedName = loaderUtils.interpolateName(
loaderContext,
"js/[hash].script.[ext]",
{
content: "console.log('loaderUtils')"
});
// => js/e353f4da4c3e380646d2b4d75c8a13ab.script.js
以上示例核心的處理流程如下:

示例二:
// loaderContext.resourcePath = "/app/js/page-home.js"
loaderUtils.interpolateName(
loaderContext,
"script-[1].[ext]",
{
regExp: "page-(.*)\\.js",
content: "console.log('loaderUtils')"
});
// => script-home.js
處理 outputPath
let outputPath = url;
if (options.outputPath) {
if (typeof options.outputPath === 'function') {
outputPath = options.outputPath(url);
} else {
outputPath = path.posix.join(options.outputPath, url);
}
}
處理 publicPath
// __webpack_require__.p = "";
let publicPath = `__webpack_public_path__ + ${JSON.stringify(outputPath)}`;
if (options.publicPath) {
if (typeof options.publicPath === 'function') {
publicPath = options.publicPath(url);
} else if (options.publicPath.endsWith('/')) {
publicPath = options.publicPath + url;
} else {
publicPath = `${options.publicPath}/${url}`;
}
publicPath = JSON.stringify(publicPath);
}
處理 emitFile
if (options.emitFile === undefined || options.emitFile) {
// 把文件輸出到指定的outputPath路徑
this.emitFile(outputPath, content);
}
導(dǎo)出最終路徑
return `module.exports = ${publicPath};`;
參考資源
loader API
webpack-the-confusing-parts
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
javascript DOM設(shè)置樣式詳細說明和示例代碼
JavaScript也可以用來修改DOM元素的樣式,我們可以使用style屬性來訪問和修改元素的樣式屬性,這篇文章主要給大家介紹了關(guān)于javascript DOM設(shè)置樣式詳細說明和示例代碼的相關(guān)資料,需要的朋友可以參考下2024-06-06
詳解基于javascript實現(xiàn)的蘋果系統(tǒng)底部菜單
本篇文章主要對基于javascript實現(xiàn)的蘋果系統(tǒng)底部菜單進行了詳細的分析說明,有助于理解和學習編寫蘋果系統(tǒng)底部菜單,相信會對大家有所幫助,下面就跟小編一起來看看吧2016-12-12
JavaScript創(chuàng)建對象_動力節(jié)點Java學院整理
這篇文章主要為大家詳細介紹了JavaScript創(chuàng)建對象的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06
JavaScript里四舍五入函數(shù)round用法實例
這篇文章主要介紹了JavaScript里四舍五入函數(shù)round用法,實例分析了round函數(shù)的使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-04-04
Websocket通信協(xié)議在數(shù)字孿生中的應(yīng)用
這篇文章主要為大家介紹了Websocket通信協(xié)議在數(shù)字孿生中的應(yīng)用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-07-07

