2017-05-14 144 views
1

我打算使用一套稍微複雜的約定來導入我的webpack項目中的資產。所以我試圖編寫一個插件,它應該重寫部分請求的模塊定位器,然後將其傳遞給解析器waterfall編寫自定義webpack解析器


假設我們只想

  • 檢查,如果被請求的模塊與#字符開始和
  • 如果是這樣,請更換與./lib/。現在應該由默認解析器查找新的模塊定位器。

這意味着當一個文件/var/www/source.jsrequire("#example"),它應該那麼實際上得到/var/www/lib/example.js


到目前爲止,我已經想通了,我顯然應該使用the module event hook用於此目的。這也是選擇by other answers,不幸的是我沒有太多的幫助。

所以這是我對自定義解決插件,這是非常簡單的:

function MyResolver() {} 
MyResolver.prototype.apply = function (compiler) { 

    compiler.plugin('module', function (init, callback) { 
    // Check if rewrite is necessary 
    if (init.request.startsWith('#')) { 

     // Create a new payload 
     const modified = Object.assign({}, init, { 
     request: './lib/' + init.request.slice(1) 
     }) 

     // Continue the waterfall with modified payload 
     callback(null, modified) 
    } else { 

     // Continue the waterfall with original payload 
     callback(null, init) 
    } 
    }) 

} 

然而,使用這種(以resolve.plugins)不起作用。運行webpack,出現以下錯誤:

ERROR in . 
Module build failed: Error: EISDIR: illegal operation on a directory, read 
@ ./source.js 1:0-30 

顯然,這不是做事情的方式。但是由於我在這件事上找不到太多的實例資料,所以我有些想法。


爲了更容易重現,我把這個確切的配置放到了GitHub倉庫中。所以,如果你有興趣幫助,你可能只是把它拿來:

git clone https://github.com/Loilo/webpack-custom-resolver.git 

然後只需運行npm installnpm run webpack看到錯誤。

回答

2

我找到了解決方案,主要是通過閱讀小doResolve()in the docs觸發。

該溶液是多步驟的過程:

1.運行callback()不足以繼續瀑布。

要通過解決任務返回的WebPack,我需要用

this.doResolve(
    'resolve', 
    modified, 
    `Looking up ${modified.request}`, 
    callback 
) 

(2更換

callback(null, modified) 

。修復webpack文檔)

該文檔缺少doResolve()方法的第三個參數(message),導致在使用此處顯示的代碼時出現錯誤。這就是爲什麼當我在將問題放在SO之前發現它時,我放棄了doResolve()方法。

我已經提出了拉取請求,文檔應該很快修復。

3.不要使用Object.assign()

看來,原來的請求對象(在這個問題命名init)不得複製通過Object.assign()對旋轉變壓器進行傳遞。

顯然它包含內部信息,欺騙解析器查找錯誤的路徑。

所以這條線

const modified = Object.assign({}, init, { 
    request: './lib/' + init.request.slice(1) 
}) 

需要通過這個來代替:

const modified = { 
    path: init.path, 
    request: './lib/' + init.request.slice(1), 
    query: init.query, 
    directory: init.directory 
} 

就是這樣。爲了更清楚地看到,下面是從上面的所有MyResolver插件現在使用上述修改:

function MyResolver() {} 
MyResolver.prototype.apply = function (compiler) { 

    compiler.plugin('module', function (init, callback) { 
    // Check if rewrite is necessary 
    if (init.request.startsWith('#')) { 

     // Create a new payload 
     const modified = { 
     path: init.path, 
     request: './lib/' + init.request.slice(1), 
     query: init.query, 
     directory: init.directory 
     } 

     // Continue the waterfall with modified payload 
     this.doResolve(
     // "resolve" just re-runs the whole resolving of this module, 
     // but this time with our modified request. 
     'resolve', 
     modified, 
     `Looking up ${modified.request}`, 
     callback 
    ) 
    } else { 
     this.doResolve(
     // Using "resolve" here would cause an infinite recursion, 
     // use an array of the possibilities instead. 
     [ 'module', 'file', 'directory' ], 
     modified, 
     `Looking up ${init.request}`, 
     callback 
    ) 
    } 
    }) 

}