Coder Social home page Coder Social logo

run-script-webpack-plugin's Introduction

atassis

run-script-webpack-plugin's People

Contributors

alexgeb avatar atassis avatar bkniffler avatar dependabot[bot] avatar gtstogy avatar hungtcs avatar shahmirn avatar tarik02 avatar treylon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

run-script-webpack-plugin's Issues

thanks

thanks for your great work ❤️

Wait till process stopped

These features would be really nice to have:

  • Wait till process stopped during restart
  • Kill process with SIGKILL if it didn't stop during timeout

Example:

import {ChildProcess, fork} from 'child_process';
import {Compilation, Compiler, WebpackPluginInstance} from 'webpack';

const killProcess = async ({pid, signal = 'SIGTERM', timeout}) => {
  process.kill(pid, signal);
  let count = 0;
  do {
    try {
      process.kill(pid, 0);
    } catch (e) {
      return;
    }
    if ((count += 100) > timeout) {
      break;
    }

    await new Promise(cb => setTimeout(cb, 100));
  } while (true);

  try {
    process.kill(pid, 'SIGKILL');
  } catch (e) {
    return;
  }

  count = 0;
  do {
    try {
      process.kill(pid, 0);
    } catch (e) {
      return;
    }
    if ((count += 100) > timeout) {
      throw new Error('Timeout process kill');
    }

    await new Promise(cb => setTimeout(cb, 100));
  } while (true);

};

export type RunScriptWebpackPluginOptions = {
  autoRestart?: boolean;
  args: string[];
  cwd?: string;
  keyboard: boolean;
  name?: string;
  nodeArgs: string[];
  restartable?: boolean;
  signal: boolean | string;
  killTimeoutMs?: number;
};

function getSignal(signal: string | boolean) {
  // allow users to disable sending a signal by setting to `false`...
  if (signal === false) return;
  if (signal === true) return 'SIGUSR2';
  return signal;
}

export class RunScriptWebpackPlugin implements WebpackPluginInstance {
  private readonly options: RunScriptWebpackPluginOptions;

  private worker?: ChildProcess;

  private _entrypoint?: string;

  constructor(options: Partial<RunScriptWebpackPluginOptions> = {}) {
    this.options = {
      autoRestart: true,
      signal: false,
      killTimeoutMs: 5000,
      // Only listen on keyboard in development, so the server doesn't hang forever
      keyboard: process.env.NODE_ENV === 'development',
      ...options,
      args: [...(options.args || [])],
      nodeArgs: options.nodeArgs || process.execArgv,
    };

    if (this.options.restartable) {
      this._enableRestarting();
    }
  }

  private _enableRestarting(): void {
    if (this.options.keyboard) {
      process.stdin.setEncoding('utf8');
      process.stdin.on('data', (data: string) => {
        if (data.trim() === 'rs') {
          this._restartServer();
        }
      });
    }
  }

  private async _restartServer(): Promise<void> {
    console.log('Restarting app...');
    if (this.worker?.pid) {
      const signal = getSignal(this.options.signal);
      await killProcess({
        pid: this.worker.pid,
        signal,
        timeout: this.options.killTimeoutMs,
      });
    }
    this._startServer((worker) => {
      this.worker = worker;
    });
  }

  private afterEmit = (compilation: Compilation, cb: (err?: any) => void): void => {
    if (this.worker && this.worker.connected && this.worker?.pid) {
      if (this.options.autoRestart) {
        this._restartServer().then(() => cb()).catch(err => cb(err));
        return;
      }
      const signal = getSignal(this.options.signal);
      if (signal) {
        killProcess({
          pid: this.worker.pid,
          signal,
          timeout: this.options.killTimeoutMs,
        }).then(() => cb()).catch(err => cb(err));
      }
      cb();
      return;
    }

    this.startServer(compilation, cb);
  };

  apply = (compiler: Compiler): void => {
    compiler.hooks.afterEmit.tapAsync(
      {name: 'RunScriptPlugin'},
      this.afterEmit,
    );
  };

  private startServer = (compilation: Compilation, cb: () => void): void => {
    const {assets, compiler} = compilation;
    const {options} = this;
    let name;
    const names = Object.keys(assets);
    if (options.name) {
      name = options.name;
      if (!assets[name]) {
        console.error(
          `Entry ${name} not found. Try one of: ${names.join(' ')}`,
        );
      }
    } else {
      name = names[0];
      if (names.length > 1) {
        console.log(
          `More than one entry built, selected ${name}. All names: ${names.join(
            ' ',
          )}`,
        );
      }
    }
    if (!compiler.options.output || !compiler.options.output.path) {
      throw new Error('output.path should be defined in webpack config!');
    }

    this._entrypoint = `${compiler.options.output.path}/${name}`;
    this._startServer((worker) => {
      this.worker = worker;
      cb();
    });
  };

  private _startServer(cb: (arg0: ChildProcess) => void): void {
    const {args, nodeArgs, cwd} = this.options;
    if (!this._entrypoint) throw new Error('run-script-webpack-plugin requires an entrypoint.');

    const child = fork(this._entrypoint, args, {
      execArgv: nodeArgs,
      stdio: 'inherit',
      cwd,
    });
    setTimeout(() => cb(child), 0);
  }
}

Error: No such label 'emitAssets' for WebpackLogger.timeEnd()

When following nest.js doc for hot reloading,
Hot reloading docs

Error: No such label 'emitAssets' for WebpackLogger.timeEnd()
\Desktop\projects\github_visualization\backend\node_modules\webpack\lib\logging\Logger.js:123
                        throw new Error(`No such label '${label}' for WebpackLogger.timeEnd()`);

this error happens.
It works well with @0.0.11 but @0.0.12 causes this error.

When looking for the commit which has changes between @0.0.11 and @0.0.12, I could only find this.worker.pid, but I'm not sure this causes the error.

Add some tests

Add some tests for a package for easier bug fixes.
Usecases, ways to test, etc

Error on Windows when using signal

Config:

module.exports = {
    name: 'dev',
    watch: true,
    cache: { type: 'filesystem' },
    target: 'node',
    profile: false,
    mode: 'development',
    devtool: 'inline-source-map',
    entry: [path.resolve('./src/index.ts')],
    experiments: {
        topLevelAwait: true,
    },
    hot: true,
    output: {
        path: path.resolve('./dist'),
        filename: 'server.js',
        chunkFilename: '[name].js',
        libraryTarget: 'commonjs2',
        compareBeforeEmit: true,
    },
    resolve: {
        extensions: ['.ts', '.js', '.json'],
        modules: ['node_modules', 'src'],
        alias: {},
    },
    externals: [
        nodeExternals({
            allowlist: ['webpack/hot/poll?1000'],
        }),
    ],
    plugins: [
            new RunScriptWebpackPlugin({
            name: 'server.js',
            signal: true,
        }),
    ],
};

Error:

node:internal/process/per_thread:215
        throw new ERR_UNKNOWN_SIGNAL(sig);
        ^

TypeError [ERR_UNKNOWN_SIGNAL]: Unknown signal: SIGUSR2
    at new NodeError (node:internal/errors:372:5)
    at process.kill (node:internal/process/per_thread:215:15)
    at RunScriptWebpackPlugin.afterEmit (D:\Projects\raketa\node_modules\run-script-webpack-plugin\dist\index.js:19:29)
    at Hook.eval [as callAsync] (eval at create (D:\Projects\raketa\node_modules\webpack\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:17:1)
    at D:\Projects\raketa\node_modules\webpack\lib\Compiler.js:882:27
    at D:\Projects\raketa\node_modules\neo-async\async.js:2818:7
    at done (D:\Projects\raketa\node_modules\neo-async\async.js:3522:9)
    at writeOut (D:\Projects\raketa\rnode_modules\webpack\lib\Compiler.js:834:17)
    at D:\Projects\raketa\node_modules\webpack\lib\Compiler.js:869:7
    at arrayIterator (D:\Projects\raketa\node_modules\neo-async\async.js:3467:9) {
  code: 'ERR_UNKNOWN_SIGNAL'
}

Windows: 10
Node.js v18.0.0
Webpack: 5

Keyboard option also does not work (

the server does not always restart after reassembly on MacOs

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.