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
44 changes: 44 additions & 0 deletions packages/webpack-cli/lib/plugins/WebpackCLIPlugin.js
@@ -0,0 +1,44 @@
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 } = webpack;
piecyk marked this conversation as resolved.
Show resolved Hide resolved

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`);
});
}
}

module.exports = WebpackCLIPlugin;
131 changes: 49 additions & 82 deletions packages/webpack-cli/lib/webpack-cli.js
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,34 @@ 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');

return interactive(compiler, options, outputOptions);
}
let compiler;
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 Down Expand Up @@ -336,45 +320,28 @@ class WebpackCLI extends GroupHelper {
logger.raw(`${stats.toString(foundStats)}`);
}

let isWatchMode = false;

if (Array.isArray(options)) {
isWatchMode = options.some((options) => options.watch);
} else {
isWatchMode = options.watch;
}

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

if (isWatchMode) {
const watchOptions = (compiler.options && compiler.options.watchOptions) || {};

if (watchOptions.stdin) {
process.stdin.on('end', function () {
process.exit();
});
process.stdin.resume();
}
compiler = this.createCompiler(options, callback);

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
8 changes: 5 additions & 3 deletions test/analyze/analyze-flag.test.js
Expand Up @@ -8,13 +8,15 @@ describe('--analyze flag', () => {

proc.stdout.on('data', (chunk) => {
const data = chunk.toString();
// console.log(data)

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

proc.kill();
done();
}
// FIXME

proc.kill();
done();
});
});
});
2 changes: 1 addition & 1 deletion test/utils/cli-plugin-test/plugin.test.js
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 }`);
});
});