Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: pass a callback to webpack from webpack-cli #1977

Merged
merged 12 commits into from
Oct 26, 2020
51 changes: 51 additions & 0 deletions packages/webpack-cli/lib/plugins/WebpackCLIPlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const { packageExists } = require('../utils/package-exists');
const webpack = packageExists('webpack') ? require('webpack') : undefined;
const logger = require('../utils/logger');

const PluginName = 'webpack-cli';

class WebpackCLIPlugin {
constructor(options) {
this.options = options;
}
async apply(compiler) {
const compilers = compiler.compilers ? compiler.compilers : [compiler];
piecyk marked this conversation as resolved.
Show resolved Hide resolved

for (const compiler of compilers) {
if (this.options.progress) {
const { ProgressPlugin } = compiler.webpack || webpack;

let progressPluginExists;

if (compiler.options.plugins) {
progressPluginExists = Boolean(compiler.options.plugins.find((e) => e instanceof ProgressPlugin));
}

if (!progressPluginExists) {
new ProgressPlugin().apply(compiler);
}
}
}

compiler.hooks.watchRun.tap(PluginName, (compilation) => {
const { bail, watch } = compilation.options;
if (bail && watch) {
logger.warn('You are using "bail" with "watch". "bail" will still exit webpack when the first error is found.');
}

logger.success(`Compilation${compilation.name ? `${compilation.name}` : ''} starting...`);
});

compiler.hooks.done.tap(PluginName, (compilation) => {
logger.success(`Compilation${compilation.name ? `${compilation.name}` : ''} finished`);

process.nextTick(() => {
if (compiler.watchMode) {
logger.success('watching files for updates...');
}
});
});
}
}

module.exports = WebpackCLIPlugin;
132 changes: 45 additions & 87 deletions packages/webpack-cli/lib/webpack-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const { toKebabCase } = require('./utils/helpers');
const assignFlagDefaults = require('./utils/flag-defaults');
const { writeFileSync } = require('fs');
const { options: coloretteOptions } = require('colorette');
const WebpackCLIPlugin = require('./plugins/WebpackCLIPlugin');

// CLI arg resolvers
const handleConfigResolution = require('./groups/ConfigGroup');
Expand Down Expand Up @@ -212,24 +213,27 @@ class WebpackCLI extends GroupHelper {
return this.runOptionGroups(args);
}

createCompiler(options) {
handleError(error) {
// https://github.com/webpack/webpack/blob/master/lib/index.js#L267
// https://github.com/webpack/webpack/blob/v4.44.2/lib/webpack.js#L90
const ValidationError = webpack.ValidationError ? webpack.ValidationError : webpack.WebpackOptionsValidationError;
piecyk marked this conversation as resolved.
Show resolved Hide resolved

// In case of schema errors print and exit process
// For webpack@4 and webpack@5
if (error instanceof ValidationError) {
logger.error(error.message);
} else {
logger.error(error);
}
}

createCompiler(options, callback) {
let compiler;

try {
compiler = webpack(options);
compiler = webpack(options, callback);
} catch (error) {
// https://github.com/webpack/webpack/blob/master/lib/index.js#L267
// https://github.com/webpack/webpack/blob/v4.44.2/lib/webpack.js#L90
const ValidationError = webpack.ValidationError ? webpack.ValidationError : webpack.WebpackOptionsValidationError;

// In case of schema errors print and exit process
// For webpack@4 and webpack@5
if (error instanceof ValidationError) {
logger.error(error.message);
} else {
logger.error(error);
}

this.handleError(error);
process.exit(2);
}

Expand All @@ -245,54 +249,35 @@ class WebpackCLI extends GroupHelper {
async run(args, cliOptions) {
await this.processArgs(args, cliOptions);

const compiler = this.createCompiler(this.compilerConfiguration);

const options = this.compilerConfiguration;
const outputOptions = this.outputConfiguration;

if (outputOptions.interactive) {
const interactive = require('./utils/interactive');
let compiler;

return interactive(compiler, options, outputOptions);
}
let options = this.compilerConfiguration;
let outputOptions = this.outputConfiguration;

const compilers = compiler.compilers ? compiler.compilers : [compiler];
const isWatchMode = Boolean(compilers.find((compiler) => compiler.options.watch));
const isRawOutput = typeof outputOptions.json === 'undefined';

if (isRawOutput) {
for (const compiler of compilers) {
if (outputOptions.progress) {
const { ProgressPlugin } = webpack;

let progressPluginExists;

if (compiler.options.plugins) {
progressPluginExists = Boolean(compiler.options.plugins.find((e) => e instanceof ProgressPlugin));
}
const webpackCLIPlugin = new WebpackCLIPlugin({
progress: outputOptions.progress,
});

if (!progressPluginExists) {
new ProgressPlugin().apply(compiler);
}
const addPlugin = (options) => {
if (!options.plugins) {
options.plugins = [];
}
options.plugins.unshift(webpackCLIPlugin);
};
if (Array.isArray(options)) {
options.forEach(addPlugin);
} else {
addPlugin(options);
}

compiler.hooks.watchRun.tap('watchInfo', (compilation) => {
if (compilation.options.bail && isWatchMode) {
logger.warn('You are using "bail" with "watch". "bail" will still exit webpack when the first error is found.');
}

logger.success(`Compilation${compilation.name ? `${compilation.name}` : ''} starting...`);
});
compiler.hooks.done.tap('watchInfo', (compilation) => {
logger.success(`Compilation${compilation.name ? `${compilation.name}` : ''} finished`);
});
}

const callback = (error, stats) => {
if (error) {
logger.error(error);
process.exit(1);
this.handleError(error);
process.exit(2);
}

if (stats.hasErrors()) {
Expand All @@ -314,9 +299,11 @@ class WebpackCLI extends GroupHelper {
return stats;
};

const getStatsOptionsFromCompiler = (compiler) => getStatsOptions(compiler.options ? compiler.options.stats : undefined);

const foundStats = compiler.compilers
? { children: compiler.compilers.map((compiler) => getStatsOptions(compiler.options.stats)) }
: getStatsOptions(compiler.options.stats);
? { children: compiler.compilers.map(getStatsOptionsFromCompiler) }
: getStatsOptionsFromCompiler(compiler);

if (outputOptions.json === true) {
process.stdout.write(JSON.stringify(stats.toJson(foundStats), null, 2) + '\n');
Expand All @@ -335,46 +322,17 @@ class WebpackCLI extends GroupHelper {
} else {
logger.raw(`${stats.toString(foundStats)}`);
}

if (isWatchMode) {
logger.success('watching files for updates...');
}
};

if (isWatchMode) {
const watchOptions = (compiler.options && compiler.options.watchOptions) || {};
compiler = this.createCompiler(options, callback);

if (watchOptions.stdin) {
process.stdin.on('end', function () {
process.exit();
});
process.stdin.resume();
}

return new Promise((resolve) => {
compiler.watch(watchOptions, (error, stats) => {
callback(error, stats);
if (compiler && outputOptions.interactive) {
const interactive = require('./utils/interactive');

resolve();
});
});
} else {
return new Promise((resolve) => {
compiler.run((error, stats) => {
if (compiler.close) {
compiler.close(() => {
callback(error, stats);

resolve();
});
} else {
callback(error, stats);

resolve();
}
});
});
interactive(compiler, options, outputOptions);
}

return Promise.resolve();
}
}

Expand Down
1 change: 0 additions & 1 deletion test/analyze/analyze-flag.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ describe('--analyze flag', () => {

if (data.includes('Webpack Bundle Analyzer is started at')) {
expect(data).toContain('Webpack Bundle Analyzer is started at');

proc.kill();
done();
}
Expand Down
10 changes: 10 additions & 0 deletions test/core-flags/cache-flags.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
'use strict';

const path = require('path');
const rimraf = require('rimraf');
const { run, isWindows } = require('../utils/test-utils');
const { existsSync, writeFileSync, unlinkSync } = require('fs');
const { resolve } = require('path');

describe('cache related flags from core', () => {
beforeEach((done) => {
if (isWindows) return;
piecyk marked this conversation as resolved.
Show resolved Hide resolved

rimraf(path.join(__dirname, '../../node_modules/.cache/webpack/*'), () => {
done();
});
});
piecyk marked this conversation as resolved.
Show resolved Hide resolved

it('should be successful with --cache ', () => {
const { stderr, stdout } = run(__dirname, ['--cache']);
expect(stderr).toBeFalsy();
Expand Down
2 changes: 1 addition & 1 deletion test/utils/cli-plugin-test/plugin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ describe('webpack-cli-test-plugin Test', () => {
if (typeof cli !== 'undefined') {
expect(stdout).toContain(`alias: { alias: [ 'alias1', 'alias2' ] }`);
}
expect(stdout).toContain('plugins: [ WebpackCLITestPlugin { opts: [Array], showAll: true } ]');
expect(stdout).toContain(` WebpackCLITestPlugin { opts: [Array], showAll: true }`);
});
});