Webpack子编译器更改配置

6
我希望在编译服务工作者时,能将webpack构建的输出定义为一个变量。
我想使用child compilation功能编译服务工作者,并将其放入不同的路径中。我需要从webpack编译发出的输出来正确编译服务工作者。
我的初始尝试是使用offline-plugin相同的策略创建子编译器,但我需要能够更改服务工作者的输出路径。服务工作者的路径很重要,因为它定义了范围。
我想知道如何使用子编译器API完成下面的操作,以防止我的构建产生这种副作用(并希望它能给我提供webpack-dev-server支持)。
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;
1个回答

16
首先,你所描述的一切都是在 offline-plugin 实现中,现在我将展示如何实现它。
当你需要在 webpack 中使用子编译和 compilation.assets 时,一切变得有点棘手。问题在于,子编译必须在 complier.plugin('make') 事件上创建,但 compilation.assets 仅在几乎在编译结束时触发的 compiler.plugin('emit') 事件上可用。
以下是子编译实现的样板:
(注意:代码采用 ES2015 版本)
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);
      });
    });
  }
}

这将使您的条目编译成单独的文件,您可以按照自己的意愿命名。接下来,在'emit'事件上,您需要对compilation.assets进行一些hacky操作:

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

编辑:在输入文件的某个特殊位置,您可能希望插入资产列表。但是要注意,如果您使用常规的模板语法,则JS加载器将无法解析您的文件。因此,您可以放置类似于__INSERT_WEBPACK_ASSETS_DATA__的内容,然后使用String#replace将其替换为实际数据。

基本上就是这样。现在您应该能够将compilation.assets变量注入到您的子编译输出中。请注意,在offline-plugin中,我在创建它时使用虚假编译名称,然后在'emit'事件上将其重命名为真实文件名。我不记得确切的原因,但我记得我有它们。因此,您可能需要自己进行实验。

这是这个样板代码的完整代码(包括'make''emit'事件):https://gist.github.com/NekR/f85d297fe4f1ea3c168827b305c13844


如果有另一个针对WebWorker目标场景的webpack.config.js文件,那该怎么办呢?子编译器是否可以加载并使用webworker目标webpack.config.js文件进行编译?childCompiler.options = new WebpackOptionsApply().process(self.options, childCompiler); - ATNASGDWNGTH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接