Write custom webpack resolver

戏子无情 提交于 2019-12-04 16:16:33

Update: Note that the plugin architecture changed significantly in webpack 4. The code below will no longer work on current webpack versions.

If you're interested in a webpack 4 compliant version, leave a comment and I'll add it to this answer.

I've found the solution, it was mainly triggered by reading the small doResolve() line in the docs.

The solution was a multiple-step process:

1. Running callback() is not sufficient to continue the waterfall.

To pass the resolving task back to webpack, I needed to replace

callback(null, modified)

with

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

(2. Fix the webpack documentation)

The docs were missing the third parameter (message) of the doResolve() method, resulting in an error when using the code as shown there. That's why I had given up on the doResolve() method when I found it before putting the question up on SO.

I've made a pull request, the docs should be fixed shortly.

3. Don't use Object.assign()

It seems that the original request object (named init in the question) must not be duplicated via Object.assign() to be passed on to the resolver.

Apparently it contains internal information that trick the resolver into looking up the wrong paths.

So this line

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

needs to be replaced by this:

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

That's it. To see it a bit clearer, here's the whole MyResolver plugin from above now working with the mentioned modifications:

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

}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!