Me gustaría ejecutar webpack en modo --watch
y ejecutar un comando de shell después de cada compilación que sincronice una carpeta con otra.
Encontré este complemento que activa un evento después de cada compilación. Eso funciona, pero la última pieza del rompecabezas es activar un comando de shell (para sincronizar) desde Javascript. Cualquier sugerencia sobre cómo lograr esto es muy apreciada.
A partir de hoy (11 de abril de 2018), la mayoría de los complementos que probé usan la API obsoleta, lo que genera esta advertencia:
DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead
Me complació descubrir que puede escribir fácilmente un complemento de paquete web ad-hoc ( docs ).
En su archivo 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); }); }); } } ] };
Si prefiere usar spawn
para obtener datos en tiempo real o "en vivo" de su secuencia de comandos, esto ilustra el uso básico:
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); });
También necesitaba tal cosa, así que compilé un complemento súper simple para ejecutar comandos de shell antes y después de cada compilación.
'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;
luego en la configuración de su paquete web:
plugins: [ new WebpackShellPlugin({ onBuildStart: ['echo "hello world"'], onBuildEnd: ['echo "goodbye world"'] }) ]
Esto es súper básico y no admite scripts asíncronos correctamente. pero funciona. siéntase libre de modificar como mejor le parezca.
Considere este código bajo licencia MIT.
Necesita el nodo 4.x y superior para ejecutarse, ya que aquí uso algunas características de es6.
Básicamente, puede conectarse al compilador en varias etapas de la compilación completa para emitir recursos, etc. y ejecutar su propio script o código como desee.
Me gusta hacerlo de esta manera -
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); }); } }
y luego usarlo así
new CustomPlugin('RunTest', 'jest', 'beforeRun'),