You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
7.1 KiB
189 lines
7.1 KiB
const { packageExists } = require('./package-exists');
|
|
const webpack = packageExists('webpack') ? require('webpack') : undefined;
|
|
const logger = require('./logger');
|
|
const { writeFileSync } = require('fs');
|
|
const bailAndWatchWarning = require('./warnings/bailAndWatchWarning');
|
|
|
|
const assignWatchHooks = (compiler) => {
|
|
compiler.hooks.watchRun.tap('watchInfo', (compilation) => {
|
|
const compilationName = compilation.name || '';
|
|
logger.raw(`\nCompilation ${compilationName} starting…\n`);
|
|
});
|
|
compiler.hooks.done.tap('watchInfo', (compilation) => {
|
|
const compilationName = compilation.name || '';
|
|
logger.raw(`\nCompilation ${compilationName} finished\n`);
|
|
});
|
|
};
|
|
|
|
const watchInfo = (compiler) => {
|
|
if (compiler.compilers) {
|
|
compiler.compilers.map((comp) => {
|
|
assignWatchHooks(comp);
|
|
});
|
|
} else {
|
|
assignWatchHooks(compiler);
|
|
}
|
|
};
|
|
|
|
class Compiler {
|
|
constructor() {
|
|
this.compilerOptions = {};
|
|
}
|
|
setUpHookForCompilation(compilation, outputOptions, options) {
|
|
const { ProgressPlugin } = webpack;
|
|
let progressPluginExists;
|
|
if (options.plugins) {
|
|
progressPluginExists = options.plugins.find((e) => e instanceof ProgressPlugin);
|
|
}
|
|
|
|
compilation.hooks.beforeRun.tap('webpackProgress', () => {
|
|
if (outputOptions.progress) {
|
|
if (!progressPluginExists) {
|
|
new ProgressPlugin().apply(compilation);
|
|
} else {
|
|
if (!progressPluginExists.handler) {
|
|
options.plugins = options.plugins.filter((e) => e !== progressPluginExists);
|
|
Object.keys(progressPluginExists).map((opt) => {
|
|
ProgressPlugin.defaultOptions[opt] = progressPluginExists[opt];
|
|
});
|
|
new ProgressPlugin().apply(compilation);
|
|
} else {
|
|
progressPluginExists.apply(compilation);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
generateOutput(outputOptions, stats) {
|
|
logger.raw(`${stats.toString(this.compilerOptions.stats)}\n`);
|
|
if (outputOptions.watch) {
|
|
logger.info('watching files for updates...');
|
|
}
|
|
}
|
|
|
|
compilerCallback(err, stats, lastHash, options, outputOptions) {
|
|
const statsErrors = [];
|
|
|
|
if (!outputOptions.watch || err) {
|
|
// Do not keep cache anymore
|
|
this.compiler.purgeInputFileSystem();
|
|
}
|
|
if (err) {
|
|
lastHash = null;
|
|
logger.error(err.stack || err);
|
|
process.exit(1);
|
|
}
|
|
if (!outputOptions.watch && stats.hasErrors()) {
|
|
process.exitCode = 1;
|
|
}
|
|
if (outputOptions.json === true) {
|
|
process.stdout.write(JSON.stringify(stats.toJson(outputOptions), null, 2) + '\n');
|
|
} else if (stats.hash !== lastHash) {
|
|
lastHash = stats.hash;
|
|
if (stats.compilation && stats.compilation.errors.length !== 0) {
|
|
const errors = stats.compilation.errors;
|
|
errors.forEach((statErr) => {
|
|
const errLoc = statErr.module ? statErr.module.resource : null;
|
|
statsErrors.push({ name: statErr.message, loc: errLoc });
|
|
});
|
|
}
|
|
const JSONStats = JSON.stringify(stats.toJson(outputOptions), null, 2);
|
|
if (typeof outputOptions.json === 'string') {
|
|
try {
|
|
writeFileSync(outputOptions.json, JSONStats);
|
|
logger.success(`stats are successfully stored as json to ${outputOptions.json}`);
|
|
} catch (err) {
|
|
logger.error(err);
|
|
}
|
|
}
|
|
return this.generateOutput(outputOptions, stats, statsErrors);
|
|
}
|
|
}
|
|
|
|
async invokeCompilerInstance(lastHash, options, outputOptions) {
|
|
// eslint-disable-next-line no-async-promise-executor
|
|
return new Promise(async (resolve) => {
|
|
await this.compiler.run((err, stats) => {
|
|
if (this.compiler.close) {
|
|
this.compiler.close(() => {
|
|
const content = this.compilerCallback(err, stats, lastHash, options, outputOptions);
|
|
resolve(content);
|
|
});
|
|
} else {
|
|
const content = this.compilerCallback(err, stats, lastHash, options, outputOptions);
|
|
resolve(content);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
async invokeWatchInstance(lastHash, options, outputOptions, watchOptions) {
|
|
return this.compiler.watch(watchOptions, (err, stats) => {
|
|
return this.compilerCallback(err, stats, lastHash, options, outputOptions);
|
|
});
|
|
}
|
|
|
|
async createCompiler(options) {
|
|
try {
|
|
this.compiler = await webpack(options);
|
|
this.compilerOptions = options;
|
|
} catch (err) {
|
|
// 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 (err instanceof ValidationError) {
|
|
logger.error(`\n${err.message}`);
|
|
} else {
|
|
logger.error(`\n${err}`);
|
|
}
|
|
process.exit(2);
|
|
}
|
|
}
|
|
|
|
get getCompiler() {
|
|
return this.compiler;
|
|
}
|
|
|
|
async webpackInstance(opts) {
|
|
const { outputOptions, options } = opts;
|
|
const lastHash = null;
|
|
|
|
const { ProgressPlugin } = webpack;
|
|
if (options.plugins) {
|
|
options.plugins = options.plugins.filter((e) => e instanceof ProgressPlugin);
|
|
}
|
|
|
|
if (outputOptions.interactive) {
|
|
const interactive = require('./interactive');
|
|
return interactive(options, outputOptions);
|
|
}
|
|
if (this.compiler.compilers) {
|
|
this.compiler.compilers.forEach((comp, idx) => {
|
|
bailAndWatchWarning(comp); //warn the user if bail and watch both are used together
|
|
this.setUpHookForCompilation(comp, outputOptions, options[idx]);
|
|
});
|
|
} else {
|
|
bailAndWatchWarning(this.compiler);
|
|
this.setUpHookForCompilation(this.compiler, outputOptions, options);
|
|
}
|
|
|
|
if (outputOptions.watch) {
|
|
const watchOptions = outputOptions.watchOptions || {};
|
|
if (watchOptions.stdin) {
|
|
process.stdin.on('end', function () {
|
|
process.exit();
|
|
});
|
|
process.stdin.resume();
|
|
}
|
|
watchInfo(this.compiler);
|
|
await this.invokeWatchInstance(lastHash, options, outputOptions, watchOptions);
|
|
} else {
|
|
return await this.invokeCompilerInstance(lastHash, options, outputOptions);
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = { Compiler };
|
|
|