Skip to content

Commit

Permalink
feat(v2): allow extend PostCSS config
Browse files Browse the repository at this point in the history
  • Loading branch information
lex111 committed Feb 6, 2021
1 parent a6f7715 commit 433f1dc
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 27 deletions.
2 changes: 2 additions & 0 deletions packages/docusaurus-types/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ export interface Plugin<T, U = unknown> {
isServer: boolean,
utils: ConfigureWebpackUtils,
): Configuration & {mergeStrategy?: ConfigureWebpackFnMergeStrategy};
configurePostCss?(options: {[name: string]: any}): Configuration;
getThemePath?(): string;
getTypeScriptThemePath?(): string;
getPathsToWatch?(): string[];
Expand Down Expand Up @@ -253,6 +254,7 @@ export interface Plugin<T, U = unknown> {

export type ConfigureWebpackFn = Plugin<unknown>['configureWebpack'];
export type ConfigureWebpackFnMergeStrategy = Record<string, MergeStrategy>;
export type ConfigurePostCssFn = Plugin<unknown>['configurePostCss'];

export type PluginOptions = {id?: string} & Record<string, unknown>;

Expand Down
37 changes: 22 additions & 15 deletions packages/docusaurus/src/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ import {handleBrokenLinks} from '../server/brokenLinks';
import {BuildCLIOptions, Props} from '@docusaurus/types';
import createClientConfig from '../webpack/client';
import createServerConfig from '../webpack/server';
import {compile, applyConfigureWebpack} from '../webpack/utils';
import {
compile,
applyConfigureWebpack,
applyConfigurePostCss,
} from '../webpack/utils';
import CleanWebpackPlugin from '../webpack/plugins/CleanWebpackPlugin';
import {loadI18n} from '../server/i18n';
import {mapAsyncSequencial} from '@docusaurus/utils';
Expand Down Expand Up @@ -166,24 +170,27 @@ async function buildLocale({
});
}

// Plugin Lifecycle - configureWebpack.
// Plugin Lifecycle - configureWebpack and configurePostCss.
plugins.forEach((plugin) => {
const {configureWebpack} = plugin;
if (!configureWebpack) {
return;
const {configureWebpack, configurePostCss} = plugin;

if (configurePostCss) {
clientConfig = applyConfigurePostCss(configurePostCss, clientConfig);
}

clientConfig = applyConfigureWebpack(
configureWebpack.bind(plugin), // The plugin lifecycle may reference `this`.
clientConfig,
false,
);
if (configureWebpack) {
clientConfig = applyConfigureWebpack(
configureWebpack.bind(plugin), // The plugin lifecycle may reference `this`.
clientConfig,
false,
);

serverConfig = applyConfigureWebpack(
configureWebpack.bind(plugin), // The plugin lifecycle may reference `this`.
serverConfig,
true,
);
serverConfig = applyConfigureWebpack(
configureWebpack.bind(plugin), // The plugin lifecycle may reference `this`.
serverConfig,
true,
);
}
});

// Make sure generated client-manifest is cleaned first so we don't reuse
Expand Down
27 changes: 17 additions & 10 deletions packages/docusaurus/src/commands/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ import {load} from '../server';
import {StartCLIOptions} from '@docusaurus/types';
import {CONFIG_FILE_NAME, STATIC_DIR_NAME} from '../constants';
import createClientConfig from '../webpack/client';
import {applyConfigureWebpack, getHttpsConfig} from '../webpack/utils';
import {
applyConfigureWebpack,
applyConfigurePostCss,
getHttpsConfig,
} from '../webpack/utils';
import {getCLIOptionHost, getCLIOptionPort} from './commandUtils';
import {getTranslationsLocaleDirPath} from '../server/translations/translations';

Expand Down Expand Up @@ -134,18 +138,21 @@ export default async function start(
],
});

// Plugin Lifecycle - configureWebpack.
// Plugin Lifecycle - configureWebpack and configurePostCss.
plugins.forEach((plugin) => {
const {configureWebpack} = plugin;
if (!configureWebpack) {
return;
const {configureWebpack, configurePostCss} = plugin;

if (configurePostCss) {
config = applyConfigurePostCss(configurePostCss, config);
}

config = applyConfigureWebpack(
configureWebpack.bind(plugin), // The plugin lifecycle may reference `this`.
config,
false,
);
if (configureWebpack) {
config = applyConfigureWebpack(
configureWebpack.bind(plugin), // The plugin lifecycle may reference `this`.
config,
false,
);
}
});

// https://webpack.js.org/configuration/dev-server
Expand Down
47 changes: 46 additions & 1 deletion packages/docusaurus/src/webpack/__tests__/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@ import {
} from 'webpack';
import path from 'path';

import {applyConfigureWebpack, getFileLoaderUtils} from '../utils';
import {
applyConfigureWebpack,
applyConfigurePostCss,
getFileLoaderUtils,
getStyleLoaders,
} from '../utils';
import {
ConfigureWebpackFn,
ConfigureWebpackFnMergeStrategy,
ConfigurePostCssFn,
} from '@docusaurus/types';

describe('extending generated webpack config', () => {
Expand Down Expand Up @@ -148,3 +154,42 @@ describe('getFileLoaderUtils()', () => {
);
});
});

describe('extending PostCSS', () => {
test('user plugin should be appended in PostCSS loader', () => {
let config: Configuration = {
output: {
path: __dirname,
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.css$/,
use: getStyleLoaders(false),
},
],
},
};
const postCssPlugin = jest.fn(() => {
return {
postcssPlugin: 'appended-plugin',
};
});
const configurePostCss: ConfigurePostCssFn = (postCssConfig) => {
postCssConfig.plugins.push(postCssPlugin());
return postCssConfig;
};

config = applyConfigurePostCss(configurePostCss, config);

const postCssLoader = config.module.rules[0].use.slice(-1)[0];
const postCssPlugins = postCssLoader.options.postcssOptions.plugins.map(
(plugin) => {
return plugin.postcssPlugin;
},
);

expect(postCssPlugins).toContain('appended-plugin');
});
});
30 changes: 29 additions & 1 deletion packages/docusaurus/src/webpack/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import merge from 'webpack-merge';
import webpack, {
Configuration,
Loader,
NewLoader,
Plugin,
RuleSetRule,
Stats,
Expand All @@ -23,7 +24,7 @@ import path from 'path';
import crypto from 'crypto';
import chalk from 'chalk';
import {TransformOptions} from '@babel/core';
import {ConfigureWebpackFn} from '@docusaurus/types';
import {ConfigureWebpackFn, ConfigurePostCssFn} from '@docusaurus/types';
import CssNanoPreset from '@docusaurus/cssnano-preset';
import {version as cacheLoaderVersion} from 'cache-loader/package.json';
import {BABEL_CONFIG_FILE_NAME, STATIC_ASSETS_DIR_NAME} from '../constants';
Expand Down Expand Up @@ -175,6 +176,33 @@ export function applyConfigureWebpack(
return config;
}

export function applyConfigurePostCss(
configurePostCss: ConfigurePostCssFn,
config: Configuration,
): Configuration {
const isPostCssLoader = (loader) =>
JSON.stringify(loader).includes('postcss-loader');
const postCssLoader = getStyleLoaders(false).find((loader) =>
isPostCssLoader(loader),
) as NewLoader;
const mutatedPostCssOptions = configurePostCss!(
postCssLoader?.options?.postcssOptions,
);

config.module?.rules
.filter((rule) => rule.test!.toString().includes('.css'))
.forEach((rule) => {
for (const loader of rule.use as NewLoader[]) {
if (isPostCssLoader(loader)) {
console.log(1, loader);
loader.options!.postcssOptions = mutatedPostCssOptions;
}
}
});

return config;
}

// See https://webpack.js.org/configuration/stats/#statswarningsfilter
// @slorber: note sure why we have to re-implement this logic
// just know that legacy had this only partially implemented, so completed it
Expand Down
35 changes: 35 additions & 0 deletions website/docs/lifecycle-apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,41 @@ module.exports = function (context, options) {

Read the [webpack-merge strategy doc](https://github.com/survivejs/webpack-merge#merging-with-strategies) for more details.

## `configurePostCss(options)`

Modifies [`postcssOptions` of `postcss-loader`](https://webpack.js.org/loaders/postcss-loader/#postcssoptions) during generating client bundle. Should return mutated options.

By default, `postcssOptions` looks like this:

```js
postcssOptions: {
ident: 'postcss',
plugins: [
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009',
},
stage: 4,
}),
],
},
```

Example:

```js {4-11} title="docusaurus-plugin/src/index.js"
module.exports = function (context, options) {
return {
name: 'docusaurus-plugin',
configurePostCss(options) {
// Appends new PostCSS plugin.
options.plugins.push(require('postcss-import'));
return options;
},
};
};
```

## `postBuild(props)`

Called when a (production) build finishes.
Expand Down

0 comments on commit 433f1dc

Please sign in to comment.