Frage Webpack Child Compiler Konfigurationsänderung


Ich möchte, dass die Ausgabe meines Webpack-Builds beim Kompilieren meines Service-Mitarbeiters als Variable definiert wird.

Ich möchte die untergeordnete Kompilierungsfunktion verwenden, um einen Service-Worker zu kompilieren, der in einem anderen Pfad abgelegt wird. Ich brauche die Ausgabe, die von der Webpack-Kompilierung ausgegeben wird, um den Service-Arbeiter korrekt zu kompilieren.

Mein erstes Spiel war die gleiche Strategie wie beim Offline-Plugin, wo Sie einen Child-Compiler erstellen, aber ich muss den Ausgabepfad für den Service-Mitarbeiter ändern können. Service-Mitarbeiter-Pfad ist wichtig, weil es den Umfang definiert.

Ich frage mich, wie ich mit der Child-Compiler-API das erreichen kann, was ich unten habe, um zu verhindern, dass diese Art von Nebeneffekt meines Builds (und hoffentlich würde es mir Webpack-Dev-Server-Unterstützung geben).

var webpack = require('webpack');

function ServiceWorkerPlugin(options) {
    this.options = options;
}

ServiceWorkerPlugin.prototype.apply = function(compiler) {
    compiler.plugin('emit', (compilation, callback) => {
    const stats = compilation.getStats().toJson();
    const child = webpack(this.options);

    child.apply(
    new webpack.DefinePlugin({
    assets: stats.assets
  })
);

child.run((err, swStats) => {
     if (err) {
         callback(err);
     }
     const swStatsJson = swStats.toJson();

     if(swStatsJson.errors.length > 0) {
         console.log(swStatsJson.errors);
     }

     if(swStatsJson.warnings.length > 0) {
         console.log(swStatsJson.warnings);
     }

     callback();
});

module.exports = ServiceWorkerPlugin;

5
2017-07-08 22:06


Ursprung


Antworten:


Zuallererst ist alles, was du beschrieben hast, drin offline-plugin Implementierung, so werde ich Ihnen jetzt zeigen, wie ich es mache.

Im Webpack wird alles ein wenig schwierig, wenn Sie es brauchen Kinderzusammenstellung und compilation.assets drin. Problem ist das Kinderzusammenstellung muss am erstellt werden complier.plugin('make') Ereignis, aber compilation.assets sind nur verfügbar am compiler.plugin('emit') Ereignis, das fast am Ende einer Kompilation ausgelöst wird.

Hier ist eine Art Vorwand für Kinderzusammenstellung Implementierung:

(Hinweis: Der Code ist in der ES2015-Version)

import SingleEntryPlugin from 'webpack/lib/SingleEntryPlugin';

export default class AwesomePlugin {
  constructor() {
    // Define compilation name and output name
    this.childCompilerName = 'awesome-plugin-compilation';
    this.outputFileName = 'custom-file.js';
    // To make child compiler work, you have to have a entry in the file system
    this.compilationEntry = 'entry-file.js';
  }

  apply(compiler) {
    // Listen to `make` event
    compiler.plugin('make', (compilation, callback) => {
      // Creating child compiler with params
      const childCompiler = compilation.createChildCompiler(this.childCompilerName, {
        filename: this.outputFileName
      });

      // Everyone plugin does this, I don't know why
      childCompiler.context = compiler.context;

      // Add SingleEntryPlugin to make all this work
      childCompiler.apply(new SingleEntryPlugin(compiler.context, this.compilationEntry, this.outputFileName));

      // Needed for HMR. Even if your plugin don't support HMR,
      // this code seems to be always needed just in case to prevent possible errors
      childCompiler.plugin('compilation', (compilation) => {
        if (compilation.cache) {
          if (!compilation.cache[name]) {
            compilation.cache[name] = {};
          }

          compilation.cache = compilation.cache[name];
        }
      });

      // Run child compilation
      childCompiler.runAsChild((err, entries, childCompilation) => {
        callback(err);
      });
    });
  }
}

Dadurch wird Ihr Eintrag in eine separate Datei kompiliert, die Sie wie gewünscht benennen können. Als nächstes müssen Sie einige hacky Manipulationen mit machen compilation.assets auf 'emit' Veranstaltung:

compiler.plugin('emit', function(compilation, callback) {
  // Get our output asset
  const asset = compilation.assets[this.outputFileName];

  // Delete delete our asset from output
  delete compilation.assets[this.outputFileName];

  // Collect all output assets
  const assets = Object.keys(compilation.assets);

  // Combine collected assets and child compilation output into new source.
  // Note: `globalAssets` is global variable
  let source = `
    var globalAssets = ${ JSON.stringify(assets) }

    ${ asset.source() }
  `;

  // Add out asset back to the output
  compilation.assets[this.outputFileName] = {
    source() {
      return source;
    },
    size() {
      return Buffer.byteLength(source, 'utf8');
    }
  };
});

BEARBEITEN: Sie können wahrscheinlich einen besonderen Platz in dem Eintrag haben, in den Sie die Liste der Assets einfügen möchten. Aber seien Sie vorsichtig, wenn Sie reguläre Vorlagensyntax verwenden, dann wird JS Loader nicht in der Lage sein, Ihre Datei zu parsen. Also kannst du so etwas platzieren __INSERT_WEBPACK_ASSETS_DATA__ und dann benutzen String#replace um es mit den tatsächlichen Daten zu ersetzen.

Das ist es im Grunde. Jetzt sollten Sie Variable mit injizieren können compilation.assets in dein Kinderzusammenstellung Ausgabe. Beachten Sie, dass in der offline-plugin, Ich benutze Fälschung Kompilierungsname, wenn ich es erstelle und es dann umbenenne 'emit' Ereignis zum echten Dateinamen. Ich erinnere mich nicht an genaue Gründe, aber ich erinnere mich, dass ich sie hatte. Also müssen Sie wahrscheinlich selbst damit experimentieren.

Hier ist der vollständige Code dieses Boilerplate (mit beiden 'make' und 'emit' Veranstaltungen): https://gist.github.com/NekR/f85d297fe4f1ea3c168827b305c13844


8
2017-07-09 17:09