Webpack 子编译器更改配置 [英] Webpack Child Compiler Change Configuration

查看:49
本文介绍了Webpack 子编译器更改配置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望在编译我的 Service Worker 时将我的 webpack 构建的输出定义为一个变量.

I would like the output of my webpack build, to be defined as a variable while compiling my service worker.

我想使用子编译功能来编译放入不同路径的服务工作者.我需要从 webpack 编译发出的输出来正确编译 service worker.

I would like to use the child compilation functionality to compile a service worker that is put into a different path. I need the output emitted from the webpack compilation to properly compile the service worker.

我最初的做法是使用与创建子编译器的离线插件相同的策略,但我需要能够更改服务工作者的输出路径.Service Worker 路径很​​重要,因为它定义了范围.

My initial play was to use the same strategy as offline-plugin where you create a child compiler, but I need to be able to change the output path for the service worker. Service workers path is important because it defines scope.

我想知道如何使用子编译器 API 完成下面的操作,以防止我的构建产生这种副作用(希望它能给我 webpack-dev-server 支持.

I am wondering how to accomplish what I have below using the child compiler API to prevent having this sort of side-effect of my build (and hopefully it would give me webpack-dev-server support.

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;

推荐答案

首先,你所描述的一切都在 offline-plugin 实现中,所以现在我要向你展示我是怎么做的

First of all, everything you have described is in offline-plugin implementation, so now I am going to show you how I do it.

当你需要在 webpack 中使用 子编译compilation.assets 时,一切都会变得有点棘手.问题是必须在 complier.plugin('make') 事件上创建 子编译,但是 compilation.assets 仅在 complier.plugin('make') 上可用code>compiler.plugin('emit') 几乎在编译结束时触发的事件.

Everything becomes a bit tricky in webpack when you need to use child compilation and compilation.assets in it. Problem is that child compilation has to be created on complier.plugin('make') event, but compilation.assets are available only on compiler.plugin('emit') event which is fired almost in the end of a compilation.

(注意:代码在 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 操作:

This will make your entry compile into separate file which you can name how you want. Next, you need to do some hacky manipulations with compilation.assets on 'emit' event:

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 将其替换为实际数据.

You probably can have some special place in the entry where you want to insert assets list. But be careful, if you will use regular template syntax, then JS loader won't be able to parse your file. So you may place something like this __INSERT_WEBPACK_ASSETS_DATA__ and then use String#replace to replace it with with the actual data.

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

This is basically it. Now you should be able to inject variable with compilation.assets into your child compilation output. Note that in the offline-plugin, I use fake compilation name when I create it and then rename it on 'emit' event to the real file name. I don't remember exact reasons why, but I remember that I had them. So, you probably will need to experiment with it by yourself.

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

Here is the full code of this boilerplate (with both 'make' and 'emit' events): https://gist.github.com/NekR/f85d297fe4f1ea3c168827b305c13844

这篇关于Webpack 子编译器更改配置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆