【问题标题】:Run command after webpack buildwebpack 构建后运行命令
【发布时间】:2015-07-30 12:27:34
【问题描述】:

我想以--watch 模式运行 webpack,并在每次构建后运行一个 shell 命令,将一个文件夹同步到另一个文件夹。

我发现this plugin 在每次构建后都会触发一个事件。这行得通,但最后一个难题是从 Javascript 触发 shell 命令(用于同步)。非常感谢任何有关如何实现这一点的指针。

【问题讨论】:

    标签: javascript webpack


    【解决方案1】:

    Webpack 4

    截至今天(2018 年 4 月 11 日),我尝试过的大多数插件都使用了已弃用的 API,导致出现以下警告:

    DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead
    

    很高兴发现您可以轻松编写一个 ad-hoc webpack 插件 (docs)。

    在您的webpack.config.js 文件中:

    const exec = require('child_process').exec;
    
    module.exports = {
    
      // ... other config here ...
    
      plugins: [
    
        // ... other plugins here ...
    
        {
          apply: (compiler) => {
            compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
              exec('<path to your post-build script here>', (err, stdout, stderr) => {
                if (stdout) process.stdout.write(stdout);
                if (stderr) process.stderr.write(stderr);
              });
            });
          }
        }
      ]
    };
    

    如果您更愿意使用spawn 从脚本中获取实时或“实时”数据,这说明了基本用法:

    const spawn = require('child_process').spawn;
    
    const child = spawn('<your script here>');
    child.stdout.on('data', function (data) {
        process.stdout.write(data);
    });
    child.stderr.on('data', function (data) {
        process.stderr.write(data);
    });
    

    【讨论】:

    • 很好,也适用于手表版本,但 Yair Tavor 的解决方案似乎并非如此。
    • 请注意,如果您正在寻找钩子的 before 等效项,您可以尝试beforeCompile。可以找到有关可用挂钩的文档here
    • 您确定“”吗?文档说它应该是“运行的命令”:nodejs.org/api/…。当我在那里有一条路径时,它会抱怨权限:“/bin/sh:tasks/postbuild.sh: Permission denied”
    • @Andrey 您可以提供要运行的命令,或具有执行权限集的脚本文件的路径。要解决您的问题,请尝试chmod +x /path/to/script
    • 可以,但是如果webpack有子编译,就不行了
    【解决方案2】:

    我也需要这样的东西,所以我编译了一个超级简单的插件来在每次构建之前和之后执行shell命令。

    'use strict';
    
    var exec = require('child_process').exec;
    
    function puts(error, stdout, stderr) {
        console.log(stdout);
    }
    
    function WebpackShellPlugin(options) {
      var defaultOptions = {
        onBuildStart: [],
        onBuildEnd: []
      };
    
      this.options = Object.assign(defaultOptions, options);
    }
    
    WebpackShellPlugin.prototype.apply = function(compiler) {
      const options = this.options;
    
      compiler.plugin("compilation", compilation => {
        if(options.onBuildStart.length){
            console.log("Executing pre-build scripts");
            options.onBuildStart.forEach(script => exec(script, puts));
        }
      });
    
      compiler.plugin("emit", (compilation, callback) => {
        if(options.onBuildEnd.length){
            console.log("Executing post-build scripts");
            options.onBuildEnd.forEach(script => exec(script, puts));
        }
        callback();
      });
    };
    
    module.exports = WebpackShellPlugin;
    

    然后在你的 webpack 配置中:

    plugins: [
        new WebpackShellPlugin({ 
             onBuildStart: ['echo "hello world"'], 
             onBuildEnd: ['echo "goodbye world"'] 
        })
    ]
    

    这是超级基本的,不正确支持异步脚本。但它有效。随意修改你认为合适的。

    在 MIT 许可下考虑此代码。

    需要节点 4.x 及更高版本才能运行,因为我在这里使用了一些 es6 功能。

    【讨论】:

    • 如果你需要访问捆绑文件,最好使用after-emit,因为emit会在Webpack开始发送文件时触发。
    • 你可以创建一个非 e6 版本吗?
    • 我将其归结为简单地将单个 js 函数而不是字符串命令传递给 exec。效果很好。
    【解决方案3】:

    基本上,您可以在整个编译的各个阶段连接到编译器,以发射资源阶段等,并根据需要运行您自己的脚本或代码。

    我喜欢这样做——

    class CustomPlugin {
      constructor(name, command, stage = 'afterEmit') {
        this.name = name;
        this.command = command;
        this.stage = stage;
      }
    
      static execHandler(err, stdout, stderr) {
        if (stdout) process.stdout.write(stdout);
        if (stderr) process.stderr.write(stderr);
      }
    
      apply(compiler) {
        compiler.hooks[this.stage].tap(this.name, () => {
          exec(this.command, CustomPlugin.execHandler);
        });
      }
    }
    

    然后像这样使用它

    new CustomPlugin('RunTest', 'jest', 'beforeRun'),
    

    【讨论】:

    • 我可以看到自己经常使用这种模式。
    【解决方案4】:

    使用webpack-shell-plugin

    如何使用:

    const WebpackShellPlugin = require('webpack-shell-plugin');
    
    
        module.exports = {
          ...
          ...
          plugins: [
            new WebpackShellPlugin({onBuildStart:['echo "Webpack Start"'], onBuildEnd:['echo "Webpack End"']})
          ],
          ...
        }
    

    【讨论】:

    • 注意:这实际上是@Yair Tavor 在他的anwser 中建议的插件。
    • @Olga 将解决方案减少到绝对必要的程度是一种实际的贡献,值得称赞。克里希纳,您可以通过解释与 Yair Tavor 答案的差异来增强您的答案。据我了解,Yair Tavor 的解决方案已打包在 webpack-shell-plugin 中,您提出的是如何使用它。值得一提的是帮助其他人了解情况。
    【解决方案5】:

    您可以轻松运行任何带有内置child_process 模块的shell 命令。你也可以尝试一些 node.js 的 shell 库,比如Shell.js。它封装了大部分默认 shell,使用起来更方便

    【讨论】:

    • 谢谢,那是缺少的链接。我不知何故在兜圈子,完全错过了这个选项。
    • 对于那些仅仅是 webpack 用户的人来说,一个例子是受欢迎的。
    【解决方案6】:

    如果您想在特定文件发生更改时这样做,您可以使用我构建的这个小插件:https://www.npmjs.com/package/webpack-noodle-plugin

    希望对你有帮助

    【讨论】:

      【解决方案7】:

      webpack-shell-plugin-next插件

      webpack-shell-plugin-next插件:

      使用插件

      onAfterDoneplugin API:

      onAfterDone:完成后执行的脚本的配置对象。

      可用于实现所需的手表相关行为(此外,请参阅下面的重要说明):

      我想在--watch 模式下运行 webpack,并在每次构建后运行一个 shell 命令,将一个文件夹同步到另一个文件夹。

      重要提示onAfterDone 插件 API 也适用于(影响)正常构建模式(即没有 --watch 选项的 webpack 命令)。

      这里是相关 GitHub 问题的附加参考:onDoneWatch scripts executing before bundle written · Issue #16 · s00d/webpack-shell-plugin-next

      示例

      刚刚尝试使用该插件:效果很好。

      devDependencies(来自package.json

      "devDependencies": {
        "webpack": "5.3.2",
        "webpack-cli": "4.1.0",
        "webpack-shell-plugin-next": "2.0.4"
      }
      

      watch npm 运行脚本(来自package.json

      "scripts": {
        "watch": "webpack --config webpack.config.js --watch"
      }
      

      Webpack 配置文件 (webpack.config.js)

      const WebpackShellPluginNext = require('webpack-shell-plugin-next');
      
      module.exports = {
          plugins: [
              new WebpackShellPluginNext({
                  onAfterDone: {
                      scripts: ['echo "It works!"'],
                      blocking: true,
                      parallel: false
                  }
              })
          ]
      };
      

      在 watch 模式下运行 Webpack 的命令行

      npm run watch
      

      【讨论】:

        【解决方案8】:

        我在使用 webpack-shell-pluginwebpack-shell-plugin-next 时遇到了一些问题:尽管我使用的是 onDoneWatch,但脚本在发出新文件之前执行。

        那时我找到了hook-shell-script-webpack-plugin。 像魅力一样工作。

        【讨论】:

        • 已经有很多答案可以解决这个问题,请添加一些额外信息,说明您的答案有何不同。
        • 其他答案指向webpack-shell-plugin 或使用 webpack 挂钩的自定义实现。我无法让 shell 插件工作,并且制作自定义插件似乎有点过头了。我发现没有其他人指出的另一种解决方案。希望它可能会有所帮助
        猜你喜欢
        • 2019-01-22
        • 2019-09-26
        • 2023-03-24
        • 2013-04-06
        • 1970-01-01
        • 2018-09-20
        • 1970-01-01
        • 2019-01-08
        • 1970-01-01
        相关资源
        最近更新 更多