javascript - Webpack-plugin: Hvordan legge til en loader dynamisk til en modul?


Jeg skriver en Webpack-plugin. Under moduloppløsning bør denne pluginen dynamisk legge til en bestemt loader for noen moduler, men ikke for alle.

Min idé akkurat nå er å utnytte normal-module-factory's after-resolve-hendelse. Der kunne jeg endre arrayet data.loaders. Noe feilsøking viste meg at dette arrayet inneholder objekter av formen { loader: string, options: object | undefined }.

Jeg kunne ikke finne noen dokumentasjon på å endre per-modul-lastere på farten. Så jeg lurer på:

  • Er dette den riktige tilnærmingen?
  • Noen (men ikke alle) eksisterende loaders-oppføringer inneholder en ekstra egenskap ident, som ser slik ut: 'ref--0-0'. Når bør jeg sette denne egenskapen, og med hvilken verdi?

Svar #1

Jeg er ikke sikker på om det er den beste løsningen, men denne koden ser ut til å fungere:

class MyPlugin {
  apply(compiler) {
    compiler.plugin('normal-module-factory', normalModuleFactory => {
      normalModuleFactory.plugin('after-resolve', (data, callback) => {
        data.loaders.push({
          loader: ..., // Path to loader
          options: {}
        });
        callback(null, data);
      });
    });
  }
}

module.exports = MyPlugin;

Når det gjelder den ekstra ident-egenskapen: Webpack må kunne sammenligne loader-alternativer. Som standard gjør den dette ved å kalle JSON.stringify() på alternativobjektet, og deretter sammenligne de resulterende strengene. Ved å legge til en ident-egenskap kan du eksplisitt spesifisere en strengrepresentasjon av alternativobjektet. For detaljer, se https://stackoverflow.com/a/49006233/52041.

Svar #2

Jeg prøvde å løse et lignende problem, og ønsket å legge til en loader bare for bestemte filer identifisert andre steder i en plugin. Min løsning er som følger:

loader.js

module.exports = function loader(content) {
  return mySpecialTransformation(content);
};

plugin.js

const path = require('path');

class MyPluginName {
  apply(compiler) {
    compiler.hooks.compilation.tap('MyPluginName', compilation => {
      compilation.hooks.normalModuleLoader.tap('MyPluginName', (loaderContext, module) => {
        if (myModuleCondition(module)) {
          module.loaders.unshift({
            loader: path.resolve(__dirname, 'loader.js'), // Path to loader
            options: {}
          });
        }
      });
    });
  }
}

Merk at jeg har brukt unshift i stedet for push for å legge til loaderen - jeg er fortsatt i utviklingsstadiet, så jeg kan ta feil, men min nåværende forståelse er at jeg vil at loaderen min skal kjøre etter alle 'standard' loadere som muligens transkriberer TypeScript, osv. Jeg tror at loadere deretter brukes fra høyre mot venstre. Avhengig av hva du gjør, kan dette være uvesentlig.