编写自定义webpackparsing器

我打算使用一些更复杂的约定来导入我的webpack项目中的资产。 所以我想写一个插件,应该重写所需的模块定位器的一部分,然后将其传递给parsing器瀑布 。


我们假设我们只是想

  • 检查一个请求的模块是否以#字符开始
  • 如果是这样,用./lib/replace。 现在应该由默认的parsing器查找新的模块定位器。

这意味着当一个文件/var/www/source.js确实require("#example") /var/www/source.js require("#example") ,它实际上应该得到/var/www/lib/example.js


到目前为止,我已经想通了,我显然应该使用module事件钩为此目的。 这也是其他答案所select的方式,但不幸的是我没有太多的帮助。

所以这是我的自定义解决插件,这是非常简单的:

 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 

显然,这不是做事情的方式。 但是因为在这个问题上我找不到太多的实例资料,所以我有些不了解。


为了使这更容易重现,我把这个确切的configuration到一个GitHub仓库。 所以如果你对帮助感兴趣,你可以取它:

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

然后运行npm installnpm run webpack来查看错误。

我find了解决scheme,主要是通过阅读文档中的小doResolve()行触发的。

解决scheme是一个多步骤的过程:

1.运行callback()不足以继续瀑布。

为了将parsing任务返回到webpack,我需要更换

 callback(null, modified) 

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

(2.修复webpack文档)

该文档缺lessdoResolve()方法的第三个参数( message ),导致使用代码时出现错误,如图所示。 这就是为什么我在把问题放在SO上之前就放弃了doResolve()方法。

我已经提出了要求,文件应该很快修复。

3.不要使用Object.assign()

似乎原来的请求对象(在问题中命名为init )不能通过Object.assign()被复制到parsing器。

显然它包含内部信息,欺骗parsing器查找错误的path。

所以这一行

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

需要被这个replace:

 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 ) } }) }