場景
我們有個(gè)使用場景 秦陋,程序啟動(dòng)時(shí)惠呼,把文件路徑傳入导俘,再去加載這個(gè)文件。項(xiàng)目整體是采用webpack打包剔蹋,本以為會順利旅薄,直到…
問題
編譯時(shí)的警告 和 運(yùn)行時(shí)的報(bào)錯(cuò),
編譯時(shí)警告 warning: Critical dependency: the request of a dependency is an expression
運(yùn)行時(shí)報(bào)錯(cuò) error : Cannot find module ‘XXX’.
分析
查了些資料泣崩,webpack打包本身不支持動(dòng)態(tài)加載少梁。打包時(shí),webpack會進(jìn)行打包分析 矫付,無論是import 還是 require的路徑內(nèi)容凯沪,都必須要在編譯時(shí)就找到,否則打包后 路徑就有問題技即,但是有些場景著洼,只有在運(yùn)行時(shí)才能確定文件的加載路徑。
劃重點(diǎn)而叼, 無論import / require 身笤,也不管你啥場景,webpack編譯時(shí) 就必須要知道你引入的文件路徑葵陵。這樣想運(yùn)行時(shí)動(dòng)態(tài)引入就做不了啊液荸,但是有時(shí)就是需要運(yùn)行時(shí)才能確認(rèn)文件路徑,webpack這里真是狗拿耗子脱篙,煩人娇钱。
解決方案
網(wǎng)上回答五花八門,大體思路都是繞開webpack在編譯時(shí)進(jìn)行加載绊困。這里總結(jié)了2種最簡單直接方式文搂,
方式1 : non_webpack_require
declare const __non_webpack_require__: NodeRequire;
const root = __non_webpack_require__(path);
但是這種和webpack強(qiáng)綁定,也就是必須要用webpack編譯打包秤朗。
- 如果用其它的打包工具打包煤蹭,會不識別這個(gè)關(guān)鍵字 non_webpack_require
- 如果是typescript語法,還要像上面一樣提前聲明下,否則編譯過不了
方式2: eval
const myCustomModule = eval('require')(myCustomPath)
簡單硝皂,粗暴常挚,管用!就巧妙繞過了webpack的限制稽物,且兼容其它編譯打包工具奄毡。
原理淺析
這里簡單解釋下 ,為什么webpack里用require 不行贝或,直接上一個(gè)例子吼过,
這個(gè)是編譯前源碼,
const processedByWebpack = require("./module");
const notProcessed = __non_webpack_require__("./non-webpack");
console.log(processedByWebpack);
console.log(notProcessed);
編譯后結(jié)果傀缩,
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
const processedByWebpack = __webpack_require__(1);
const notProcessed = require("./non-webpack");
console.log(processedByWebpack);
console.log(notProcessed);
/***/ }),
/* 1 */
/***/ (function(module, exports) {
module.exports = "This module is bundled with webpack"
/***/ })
/******/ ]);
可以看到webpack把require語句直接轉(zhuǎn)換為 webpack_require(1) 那先,然后1是對應(yīng)的代碼农猬。所以如果你寫的是一個(gè)動(dòng)態(tài)路徑赡艰,webpack就不知道去哪里找,也不能把對應(yīng)代碼打包進(jìn)來斤葱。
此時(shí)如果你巧用 non_webpack_require慷垮,webpack也便不再為難你,不再解析成webpack_require揍堕,而是直接轉(zhuǎn)為require料身,則可以動(dòng)態(tài) 運(yùn)行時(shí)解析路徑。
思考 誰對誰錯(cuò)
文末照例思考 對與錯(cuò) 衩茸,能看到這里芹血,相信不少研發(fā)同學(xué)都踩到了這個(gè)問題,
找這個(gè)問題楞慈,我也花了好久幔烛。所以是require 錯(cuò)了,還是 webpack 錯(cuò)了囊蓝,為什么找到這個(gè)答案這么費(fèi)勁饿悬。
- require本身就是動(dòng)態(tài)加載,require本身沒有錯(cuò)聚霜。
- webpack 本身做的 就是打包狡恬,打包就涉及到 文件依賴分析,然后都匯總到一個(gè)文件蝎宇,肯定是不傾向于動(dòng)態(tài)加載弟劲,但是動(dòng)態(tài)加載對于很多場景也是強(qiáng)需求啊,有些只有在運(yùn)行時(shí)姥芥,才能確定依賴文件的具體路徑兔乞。 當(dāng)然webpack也給留個(gè)口子,
但是文檔你寫成這樣誰能找到, 本身參數(shù)內(nèi)容就多报嵌,一句 to do cool stuff 完事虱咧,咋就不給個(gè)示例? 不稍微解釋下。
所以锚国, require沒錯(cuò)腕巡,webpack本身沒錯(cuò) , webpack文檔不太行 ??血筑。
Refs:
https://stackoverflow.com/questions/46185302/non-webpack-require-is-not-defined
https://stackoverflow.com/questions/42797313/webpack-dynamic-module-loader-by-require
https://webpack.js.org/api/module-methods/#import