隨便記錄一些東西,如有錯(cuò)誤歡迎指出
require.context是什么
一個(gè)webpack的api,通過執(zhí)行require.context函數(shù)獲取一個(gè)特定的上下文,主要用來實(shí)現(xiàn)自動(dòng)化導(dǎo)入模塊,在前端工程中,如果遇到從一個(gè)文件夾引入很多模塊的情況,可以使用這個(gè)api,它會遍歷文件夾中的指定文件,然后自動(dòng)導(dǎo)入,使得不需要每次顯式的調(diào)用import導(dǎo)入模塊
什么時(shí)候需要用到require.context
如果有以下情況,可以考慮使用require.context替換
在Vue寫的項(xiàng)目中,我把路由通過不同的功能劃分成不同的模塊,在index.js中一個(gè)個(gè)導(dǎo)入(原諒ide的警告-.-),但是如果項(xiàng)目變大了之后,每次手動(dòng)import會顯得有些力不從心,這里可以使用require.context函數(shù)遍歷modules文件夾的所有文件一次性導(dǎo)入到index.js中
分析require.context
require.context函數(shù)接受三個(gè)參數(shù)
directory {String} -讀取文件的路徑
useSubdirectories {Boolean} -是否遍歷文件的子目錄
regExp {RegExp} -匹配文件的正則
語法: require.context(directory, useSubdirectories = false, regExp = /^.//);
借用webpakc官網(wǎng)的例子
require.context('./test', false, /.test.js$/);
上面的代碼遍歷當(dāng)前目錄下的test文件夾的所有.test.js結(jié)尾的文件,不遍歷子目錄
大概用圖片來表示的話就是這樣子的
在index.js中調(diào)用 require.context('./test', false, /.test.js$/);會得到test文件下3個(gè)文件的執(zhí)行環(huán)境
值得注意的是require.context函數(shù)執(zhí)行后返回的是一個(gè)函數(shù),并且這個(gè)函數(shù)有3個(gè)屬性
resolve {Function} -接受一個(gè)參數(shù)request,request為test文件夾下面匹配文件的相對路徑,返回這個(gè)匹配文件相對于整個(gè)工程的相對路徑
keys {Function} -返回匹配成功模塊的名字組成的數(shù)組
id {String} -執(zhí)行環(huán)境的id,返回的是一個(gè)字符串,主要用在module.hot.accept,應(yīng)該是熱加載?
這三個(gè)都是作為函數(shù)的屬性(注意是作為函數(shù)的屬性,函數(shù)也是對象,有對應(yīng)的屬性)
talk is cheap ,show me the code
結(jié)合工程看一下這3個(gè)屬性返回了什么
我們在里層的modules文件夾新建一個(gè)index.js,用來收集所有的模塊然后一次性導(dǎo)出給外層的index.js
這里我們先上代碼,代碼是寫在里層的index.js中的(代碼借鑒于加快Vue項(xiàng)目的開發(fā)速度)
這里我把require.context函數(shù)執(zhí)行后的代碼賦值給了files變量,files中保存了圖一的以.js結(jié)尾的文件,files是個(gè)函數(shù),我們分別調(diào)用者3個(gè)屬性看看會返回什么
可以看到
執(zhí)行了keys方法返回了一個(gè)由匹配文件的文件名組成的數(shù)組
id屬性返回了匹配的文件夾的相對于工程的相對路徑,是否遍歷子目錄,匹配正則組成的字符串
對于resolve方法可以看到它是一個(gè)函數(shù)接受req參數(shù),經(jīng)過實(shí)踐我發(fā)現(xiàn)這個(gè)req參數(shù)的值是keys方法返回的數(shù)組的元素,接著我們傳入其中一個(gè)元素執(zhí)行resolve函數(shù)
resolve方法返回了一個(gè)字符串代表著傳入?yún)?shù)的文件相對于整個(gè)工程的相對路徑
同時(shí)files作為一個(gè)函數(shù),也接受一個(gè)req參數(shù),這個(gè)和resolve方法的req參數(shù)是一樣的,即匹配的文件名的相對路徑,而files函數(shù)返回的是一個(gè)模塊,這個(gè)模塊才是真正我們需要的
這個(gè)Module模塊和使用import導(dǎo)入的模塊是一樣的
回到工程
首先調(diào)用require.context導(dǎo)入某個(gè)文件夾的所有匹配文件,返回執(zhí)行上下文的環(huán)境賦值給files變量
聲明一個(gè)configRouters用來暴露給外層index.js作為vue-router的數(shù)組
調(diào)用files函數(shù)的keys方法返回modules文件夾下所有以.js結(jié)尾的文件的文件名,返回文件名組成的數(shù)組
遍歷數(shù)組每一項(xiàng),如果是index.js就跳過(index.js并不是路由模塊),調(diào)用files函數(shù)傳入遍歷的元素返回一個(gè)Modules模塊
因?yàn)槲业穆窂绞怯胑xport default導(dǎo)出的,所以在Module模塊的default屬性中獲取到我導(dǎo)出的內(nèi)容(即路由的結(jié)構(gòu)),類似這種樣子
- 將上一步返回的所有路由結(jié)構(gòu)添加到configRouters數(shù)組然后暴露給外層的index.js
- 外層引入后導(dǎo)入到vue-router中就可以使用了
寫在后面
在使用require.context自動(dòng)導(dǎo)入路由文件時(shí)發(fā)現(xiàn)一個(gè)問題,路由的順序不是你期望的樣子,因?yàn)閣ebpack是根據(jù)你文件夾中文件的位置排序的,這個(gè)時(shí)候需要定義一個(gè)標(biāo)識符來給路由數(shù)組排序,這里我們給每個(gè)文件夾最上層的路由添加一個(gè)sort屬性用于排序

隨后在讀取模塊后,給外層index傳入路由配置前,給路由的模塊排序

require.context另外一個(gè)常用的地方是svg圖標(biāo),可以不用每次導(dǎo)入圖標(biāo)文件,相對于以前的iconfont,svg有很多好處強(qiáng)烈推薦,詳情可以看這個(gè)