3

We have a bunch of video files that were deployed with the webpack code (stored in LFS)

We've moved them out to CDN and want to use the webpack file-loader with publicPath to convert them to absolute urls during build.

Webpack barfs because the file doesn't exist. This is my attempt at writing a resolve plugin to skip them, but i still get file not found errors.... What am i missing?

var VideoResolver = {
  apply: function(resolver) {
    const target = resolver.ensureHook("resolved");

    resolver.getHook("module").tapAsync("VideoResolver", (request, resolveContext, callback) => {
      if (request.request.startsWith("assets/videos") || request.request.endsWith(".mp4")) {

        const resolved =  {
          path: request.request,
          request: request.request,
          query: request.query,
          resolveToContext:{},
          directory: !request.request.endsWith(".mp4")
        };
        console.log(resolved)
        resolver.doResolve(
          target,
          resolved,
          `skipping video resolve for ${request.request}`,
          resolveContext,
          callback
        );
      } else {
        callback();
      }
    });
  },
};

Edit: Looks like the NormalModule and LoaderRunner read the content of files and pass it to the loaders (which seem badly named :) ). I can't see an easy way to override this behaviour

Adam Mills
  • 7,719
  • 3
  • 31
  • 47

1 Answers1

1

you are not supposed to ignore them in the resolved hook. It's too late. you need to use a previous step, in this case I think it should be in the first step - the resolve step.

see this GitHub comment for the order of the available hooks:

resolve
parsed-resolve
described-resolve
after-described-resolve
relative
described-relative
raw-file
file
existing-file
resolved

see this excellent SO answer for an example of how to create a plugin with webpack 4.

Pay attention that doResolve will rerun the plugin stack again so that your plugin will run again so you need to put in some condition so that you will not resolve again. e.g. check if the request is not an absolute path.

so your plugin could be something like that:

class MyResolverPlugin {
    constructor(source, target) {
        this.source = source || 'resolve';
        this.target = target || 'resolve';
    }

    apply(resolver) {
        var target = resolver.ensureHook(this.target);
        resolver.getHook(this.source).tapAsync('MyResolverPlugin', (request, resolveContext, callback) => {
            const req = request.request;
            const ext = req && path.extname(req);
            const issuer = request.context && request.context.issuer;
            if (ext && ext == ".mp4" && req.startsWith("assets/videos")
                && issuer && !issuer.includes("node_modules")) {
                const file = path.join("/absolute/path/to/new/video/folder", req);
                const obj = { ...request, request: file };
                return resolver.doResolve(target, obj, null, resolveContext, callback);
            }
            callback();
        });
    }
}
ziv
  • 3,641
  • 3
  • 21
  • 26