feat(v2): Allow plugins to consume webpack stats (#4021)

* refactor(v2): Allow plugins to consume webpack stats

Signed-off-by: Reece Dunham <me@rdil.rocks>

* Warn level only

* Fix issue

* Revert start.ts change
This commit is contained in:
Reece Dunham 2021-01-11 09:34:42 -05:00 committed by GitHub
parent a406a3c9aa
commit 66cc7364cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 24 additions and 11 deletions

View file

@ -7,7 +7,7 @@
// ESLint doesn't understand types dependencies in d.ts // ESLint doesn't understand types dependencies in d.ts
// eslint-disable-next-line import/no-extraneous-dependencies // eslint-disable-next-line import/no-extraneous-dependencies
import {Loader, Configuration} from 'webpack'; import {Loader, Configuration, Stats} from 'webpack';
import {Command} from 'commander'; import {Command} from 'commander';
import {ParsedUrlQueryInput} from 'querystring'; import {ParsedUrlQueryInput} from 'querystring';
import {MergeStrategy} from 'webpack-merge'; import {MergeStrategy} from 'webpack-merge';
@ -178,6 +178,13 @@ export interface Props extends LoadContext, InjectedHtmlTags {
plugins: Plugin<any, unknown>[]; plugins: Plugin<any, unknown>[];
} }
/**
* Same as `Props` but also has webpack stats appended.
*/
export interface PropsPostBuild extends Props {
stats: Stats.ToJsonOutput;
}
export interface PluginContentLoadedActions { export interface PluginContentLoadedActions {
addRoute(config: RouteConfig): void; addRoute(config: RouteConfig): void;
createData(name: string, data: any): Promise<string>; createData(name: string, data: any): Promise<string>;
@ -206,7 +213,7 @@ export interface Plugin<T, U = unknown> {
actions: PluginContentLoadedActions; actions: PluginContentLoadedActions;
}): void; }): void;
routesLoaded?(routes: RouteConfig[]): void; // TODO remove soon, deprecated (alpha-60) routesLoaded?(routes: RouteConfig[]): void; // TODO remove soon, deprecated (alpha-60)
postBuild?(props: Props): void; postBuild?(props: PropsPostBuild): void;
postStart?(props: Props): void; postStart?(props: Props): void;
configureWebpack?( configureWebpack?(
config: Configuration, config: Configuration,
@ -224,6 +231,7 @@ export interface Plugin<T, U = unknown> {
postBodyTags?: HtmlTags; postBodyTags?: HtmlTags;
}; };
getSwizzleComponentList?(): string[]; getSwizzleComponentList?(): string[];
// TODO before/afterDevServer implementation
// translations // translations
getTranslationFiles?(): Promise<TranslationFiles>; getTranslationFiles?(): Promise<TranslationFiles>;

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import chalk = require('chalk'); import chalk from 'chalk';
import CopyWebpackPlugin from 'copy-webpack-plugin'; import CopyWebpackPlugin from 'copy-webpack-plugin';
import fs from 'fs-extra'; import fs from 'fs-extra';
import path from 'path'; import path from 'path';
@ -193,7 +193,7 @@ async function buildLocale({
} }
// Run webpack to build JS bundle (client) and static html files (server). // Run webpack to build JS bundle (client) and static html files (server).
await compile([clientConfig, serverConfig]); const finalCompileResult = await compile([clientConfig, serverConfig]);
// Remove server.bundle.js because it is not needed. // Remove server.bundle.js because it is not needed.
if ( if (
@ -215,7 +215,7 @@ async function buildLocale({
if (!plugin.postBuild) { if (!plugin.postBuild) {
return; return;
} }
await plugin.postBuild(props); await plugin.postBuild({...props, stats: finalCompileResult});
}), }),
); );

View file

@ -198,22 +198,24 @@ function filterWarnings(
return warnings.filter((warning) => !isWarningFiltered(warning)); return warnings.filter((warning) => !isWarningFiltered(warning));
} }
export function compile(config: Configuration[]): Promise<void> { export function compile(config: Configuration[]): Promise<Stats.ToJsonOutput> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const compiler = webpack(config); const compiler = webpack(config);
compiler.run((err, stats) => { compiler.run((err, stats) => {
if (err) { if (err) {
reject(new Error(err.toString())); reject(new Error(err.toString()));
} }
// let plugins consume all the stats
const allStats = stats?.toJson('errors-warnings');
if (stats?.hasErrors()) { if (stats?.hasErrors()) {
stats.toJson('errors-only').errors.forEach((e) => { allStats.errors.forEach((e) => {
console.error(e); console.error(e);
}); });
reject(new Error('Failed to compile with errors.')); reject(new Error('Failed to compile with errors.'));
} }
if (stats?.hasWarnings()) { if (stats?.hasWarnings()) {
// Custom filtering warnings (see https://github.com/webpack/webpack/issues/7841). // Custom filtering warnings (see https://github.com/webpack/webpack/issues/7841).
let {warnings} = stats.toJson('errors-warnings'); let warnings = [...allStats.warnings];
const warningsFilter = ((config[0].stats as Stats.ToJsonOptionsObject) const warningsFilter = ((config[0].stats as Stats.ToJsonOptionsObject)
?.warningsFilter || []) as WarningFilter[]; ?.warningsFilter || []) as WarningFilter[];
@ -226,7 +228,7 @@ export function compile(config: Configuration[]): Promise<void> {
console.warn(warning); console.warn(warning);
}); });
} }
resolve(); resolve(allStats);
}); });
}); });
} }

View file

@ -362,20 +362,23 @@ type Props = {
postBodyTags: string; postBodyTags: string;
routesPaths: string[]; routesPaths: string[];
plugins: Plugin<any>[]; plugins: Plugin<any>[];
stats: Stats.ToJsonOutput;
}; };
``` ```
Example: Example:
```js {4-9} title="docusaurus-plugin/src/index.js" ```js {4-11} title="docusaurus-plugin/src/index.js"
module.exports = function (context, options) { module.exports = function (context, options) {
return { return {
name: 'docusaurus-plugin', name: 'docusaurus-plugin',
async postBuild({siteConfig = {}, routesPaths = [], outDir}) { async postBuild({siteConfig = {}, routesPaths = [], outDir, stats}) {
// Print out to console all the rendered routes. // Print out to console all the rendered routes.
routesPaths.map((route) => { routesPaths.map((route) => {
console.log(route); console.log(route);
}); });
// Print out to console all the webpack stats.
console.log(stats);
}, },
}; };
}; };