简体   繁体   中英

Webpack: Infinite watch loop and auto-generated files

I have a script which generates a file, call it auto.js . This file contains some dynamically generated imports and is being used within a VueJS project.

// auto.js

import { apple, strawberry, orange } from 'delicious-fruits';
import { carrot, cucumber, celery  } from 'delicious-vegetables';

While using Webpacks dev server , should any project file change, my goal is to have this script re-generate my auto.js file, and then have that included in the re-compiled project.

I have turned this script into a Webpack plugin, whereby I'm listening for the watchRun compiler hook . This seems like the ideal hook, per its description:

Executes a plugin during watch mode after a new compilation is triggered but before the compilation is actually started.

class AutoGenerate {
  constructor(options) {
    this.options = options;
  }
  apply(compiler) {
    compiler.hooks.watchRun.tap('AutoGenerate', () => {
      generateFile()
    })
  }
}

function generateFile () {
  // generate auto.js and write to disk
}

I always wind up with an infinite loop situation. I have tried approaching the problem by using various life cycles events (hooks), as well ignoring the auto-generated file. Of course, by ignoring it, those changes are not included in the re-compiled project.

const webpack = require('webpack');
const AutoGenerate = require("./auto.plugin");

module.exports = {
  configureWebpack: {
    plugins: [
      new webpack.WatchIgnorePlugin([/.*auto\.js/]),
      new AutoGenerate()
    ]
  }
}

I've also tried tapping into the compilation, and adding a new asset to the compilation. While the process does not error out, the generated asset is not a part of the final compilation.

// auto.plugin.js

class AutoGenerate {

  static defaultOptions = {
    outputFile: 'auto.js',
  };

  constructor(options = {}) {
    this.options = { ...AutoGenerate.defaultOptions, ...options };
  }

  apply(compiler) {

    compiler.hooks.thisCompilation.tap('AutoGenerate', (compilation) => {

      const path = require("path")
      const filePath = path.resolve(__dirname, `src/plugins/${this.options.outputFile}`)
      const { RawSource } = require('webpack-sources')
      const fileContent = new RawSource(generateFile())

      compilation.emitAsset(
        filePath,
        fileContent
      )

    });

  }
}

function generateFile() {
  // generate file content & return as string
}

module.exports = { AutoGenerate };
// vue.config.js

const AutoGenerate = require("./auto.plugin");

module.exports = {
  configureWebpack: {
    plugins: [
      new AutoGenerate()
    ]
  }
}

How can I trigger my logic for auto-generating this file, while having this file be included as part of any re-compilation, while at the same time avoiding an infinite loop?

I have not been able to identify a direct solution to the problem posed above. However, for anyone reading, I've come to discover that this can be accomplished by utilizing a package called before-build-webpack , notably by including the watch-run trigger.

// vue.config.js

const WebpackBeforeBuildPlugin = require('before-build-webpack')

module.exports = {
  configureWebpack: {
    plugins: [
      new WebpackBeforeBuildPlugin(function(stats, callback) {
        // ...
      }, ['run', 'watch-run'])
    ]
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM