atassis / run-script-webpack-plugin Goto Github PK
View Code? Open in Web Editor NEWAutomatically run your script once Webpack's build completes.
License: MIT License
Automatically run your script once Webpack's build completes.
License: MIT License
thanks for your great work ❤️
Srtipt not rerunned after rebuild by watch mode
server/index.ts
import express from 'express'
const port = 3000
const app = express()
app.listen(port, () => {
console.log(`> Express server started on ${port}`)
})
console.log('text')
Need to create a changelog file or description on the release tag, so it easier to track what the changes happen so far
These features would be really nice to have:
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);
}
}
#20 related
Ideally, the code would be smart enough to detect that HMR is in use, but at the minimum, there should be documentation present regarding the autoRestart flag.
run-script-webpack-plugin/src/index.ts
Line 59 in 477b739
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 for a package for easier bug fixes.
Usecases, ways to test, etc
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
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.