Skip to content

Commit ef3e04d

Browse files
committed
Abstract Webpack third-party plugins
1 parent 9f6f3a9 commit ef3e04d

File tree

6 files changed

+108
-76
lines changed

6 files changed

+108
-76
lines changed

packages/docusaurus/src/webpack/base.ts

+4-8
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@
88
import fs from 'fs-extra';
99
import path from 'path';
1010
import {md5Hash, getFileLoaderUtils} from '@docusaurus/utils';
11-
import {
12-
createJsLoaderFactory,
13-
getStyleLoaders,
14-
getCustomBabelConfigFilePath,
15-
} from './utils';
11+
import {createJsLoaderFactory, getCustomBabelConfigFilePath} from './utils';
1612
import {getMinimizers} from './minification';
1713
import {loadThemeAliases, loadDocusaurusAliases} from './aliases';
1814
import {getCSSExtractPlugin} from './currentBundler';
@@ -94,7 +90,7 @@ export async function createBaseConfig({
9490

9591
const createJsLoader = await createJsLoaderFactory({siteConfig});
9692

97-
const CSSExtractPlugin = getCSSExtractPlugin({
93+
const CSSExtractPlugin = await getCSSExtractPlugin({
9894
currentBundler: configureWebpackUtils.currentBundler,
9995
});
10096

@@ -234,7 +230,7 @@ export async function createBaseConfig({
234230
{
235231
test: CSS_REGEX,
236232
exclude: CSS_MODULE_REGEX,
237-
use: getStyleLoaders(isServer, {
233+
use: configureWebpackUtils.getStyleLoaders(isServer, {
238234
importLoaders: 1,
239235
sourceMap: !isProd,
240236
}),
@@ -243,7 +239,7 @@ export async function createBaseConfig({
243239
// using the extension .module.css
244240
{
245241
test: CSS_MODULE_REGEX,
246-
use: getStyleLoaders(isServer, {
242+
use: configureWebpackUtils.getStyleLoaders(isServer, {
247243
modules: {
248244
// Using the same CSS Module class pattern in dev/prod on purpose
249245
// See https://github.com/facebook/docusaurus/pull/10423

packages/docusaurus/src/webpack/client.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ async function createBaseClientConfig({
6464
new WebpackBar({
6565
name: 'Client',
6666
}),
67-
await createStaticDirectoriesCopyPlugin({props}),
67+
await createStaticDirectoriesCopyPlugin({
68+
props,
69+
currentBundler: configureWebpackUtils.currentBundler,
70+
}),
6871
].filter(Boolean),
6972
});
7073
}

packages/docusaurus/src/webpack/configure.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
customizeArray,
1111
customizeObject,
1212
} from 'webpack-merge';
13-
import {createJsLoaderFactory, getStyleLoaders} from './utils';
13+
import {createJsLoaderFactory, createStyleLoadersFactory} from './utils';
1414
import {getCurrentBundler} from './currentBundler';
1515
import type {Configuration, RuleSetRule} from 'webpack';
1616
import type {
@@ -31,10 +31,12 @@ export async function createConfigureWebpackUtils({
3131
Parameters<typeof getCurrentBundler>[0]['siteConfig'];
3232
}): Promise<ConfigureWebpackUtils> {
3333
const currentBundler = await getCurrentBundler({siteConfig});
34+
const getStyleLoaders = await createStyleLoadersFactory({currentBundler});
35+
const getJSLoader = await createJsLoaderFactory({siteConfig});
3436
return {
3537
currentBundler,
3638
getStyleLoaders,
37-
getJSLoader: await createJsLoaderFactory({siteConfig}),
39+
getJSLoader,
3840
};
3941
}
4042

packages/docusaurus/src/webpack/currentBundler.ts

+15-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import webpack from 'webpack';
99
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
10+
import CopyWebpackPlugin from 'copy-webpack-plugin';
1011
import logger from '@docusaurus/logger';
1112
import type {CurrentBundler, DocusaurusConfig} from '@docusaurus/types';
1213

@@ -41,13 +42,25 @@ export async function getCurrentBundler({
4142
};
4243
}
4344

44-
export function getCSSExtractPlugin({
45+
export async function getCSSExtractPlugin({
4546
currentBundler,
4647
}: {
4748
currentBundler: CurrentBundler;
48-
}): typeof MiniCssExtractPlugin {
49+
}): Promise<typeof MiniCssExtractPlugin> {
4950
if (currentBundler.name === 'rspack') {
5051
throw new Error('Rspack bundler is not supported yet');
5152
}
5253
return MiniCssExtractPlugin;
5354
}
55+
56+
export async function getCopyPlugin({
57+
currentBundler,
58+
}: {
59+
currentBundler: CurrentBundler;
60+
}): Promise<typeof CopyWebpackPlugin> {
61+
if (currentBundler.name === 'rspack') {
62+
throw new Error('Rspack bundler is not supported yet');
63+
}
64+
// https://github.com/webpack-contrib/copy-webpack-plugin
65+
return CopyWebpackPlugin;
66+
}

packages/docusaurus/src/webpack/plugins/StaticDirectoriesCopyPlugin.ts

+11-4
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,21 @@
77

88
import path from 'path';
99
import fs from 'fs-extra';
10-
import CopyWebpackPlugin from 'copy-webpack-plugin';
11-
import type {Props} from '@docusaurus/types';
10+
import {getCopyPlugin} from '../currentBundler';
11+
import type {CurrentBundler, Props} from '@docusaurus/types';
12+
import type {WebpackPluginInstance} from 'webpack';
1213

1314
export async function createStaticDirectoriesCopyPlugin({
1415
props,
16+
currentBundler,
1517
}: {
1618
props: Props;
17-
}): Promise<CopyWebpackPlugin | undefined> {
19+
currentBundler: CurrentBundler;
20+
}): Promise<WebpackPluginInstance | undefined> {
21+
const CopyPlugin = await getCopyPlugin({
22+
currentBundler,
23+
});
24+
1825
const {
1926
outDir,
2027
siteDir,
@@ -44,7 +51,7 @@ export async function createStaticDirectoriesCopyPlugin({
4451
return undefined;
4552
}
4653

47-
return new CopyWebpackPlugin({
54+
return new CopyPlugin({
4855
patterns: staticDirectories.map((dir) => ({
4956
from: dir,
5057
to: outDir,

packages/docusaurus/src/webpack/utils.ts

+70-59
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ import path from 'path';
1010
import crypto from 'crypto';
1111
import logger from '@docusaurus/logger';
1212
import {BABEL_CONFIG_FILE_NAME} from '@docusaurus/utils';
13-
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
14-
import webpack, {type Configuration, type RuleSetRule} from 'webpack';
13+
import webpack, {type Configuration} from 'webpack';
1514
import formatWebpackMessages from 'react-dev-utils/formatWebpackMessages';
1615
import {importSwcJsLoaderFactory} from '../faster';
17-
import type {ConfigureWebpackUtils, DocusaurusConfig} from '@docusaurus/types';
16+
import {getCSSExtractPlugin} from './currentBundler';
17+
import type {
18+
ConfigureWebpackUtils,
19+
CurrentBundler,
20+
DocusaurusConfig,
21+
} from '@docusaurus/types';
1822
import type {TransformOptions} from '@babel/core';
1923

2024
export function formatStatsErrorMessage(
@@ -42,68 +46,75 @@ export function printStatsWarnings(
4246
}
4347
}
4448

45-
// Utility method to get style loaders
46-
export function getStyleLoaders(
47-
isServer: boolean,
48-
cssOptionsArg: {
49-
[key: string]: unknown;
50-
} = {},
51-
): RuleSetRule[] {
52-
const cssOptions: {[key: string]: unknown} = {
53-
// TODO turn esModule on later, see https://github.com/facebook/docusaurus/pull/6424
54-
esModule: false,
55-
...cssOptionsArg,
56-
};
49+
export async function createStyleLoadersFactory({
50+
currentBundler,
51+
}: {
52+
currentBundler: CurrentBundler;
53+
}): Promise<ConfigureWebpackUtils['getStyleLoaders']> {
54+
const CssExtractPlugin = await getCSSExtractPlugin({currentBundler});
5755

58-
// On the server we don't really need to extract/emit CSS
59-
// We only need to transform CSS module imports to a styles object
60-
if (isServer) {
61-
return cssOptions.modules
62-
? [
63-
{
64-
loader: require.resolve('css-loader'),
65-
options: cssOptions,
66-
},
67-
]
68-
: // Ignore regular CSS files
69-
[{loader: require.resolve('null-loader')}];
70-
}
56+
return function getStyleLoaders(
57+
isServer: boolean,
58+
cssOptionsArg: {
59+
[key: string]: unknown;
60+
} = {},
61+
) {
62+
const cssOptions: {[key: string]: unknown} = {
63+
// TODO turn esModule on later, see https://github.com/facebook/docusaurus/pull/6424
64+
esModule: false,
65+
...cssOptionsArg,
66+
};
7167

72-
return [
73-
{
74-
loader: MiniCssExtractPlugin.loader,
75-
options: {
76-
esModule: true,
68+
// On the server we don't really need to extract/emit CSS
69+
// We only need to transform CSS module imports to a styles object
70+
if (isServer) {
71+
return cssOptions.modules
72+
? [
73+
{
74+
loader: require.resolve('css-loader'),
75+
options: cssOptions,
76+
},
77+
]
78+
: // Ignore regular CSS files
79+
[{loader: require.resolve('null-loader')}];
80+
}
81+
82+
return [
83+
{
84+
loader: CssExtractPlugin.loader,
85+
options: {
86+
esModule: true,
87+
},
88+
},
89+
{
90+
loader: require.resolve('css-loader'),
91+
options: cssOptions,
7792
},
78-
},
79-
{
80-
loader: require.resolve('css-loader'),
81-
options: cssOptions,
82-
},
8393

84-
// TODO apart for configurePostCss(), do we really need this loader?
85-
// Note: using postcss here looks inefficient/duplicate
86-
// But in practice, it's not a big deal because css-loader also uses postcss
87-
// and is able to reuse the parsed AST from postcss-loader
88-
// See https://github.com/webpack-contrib/css-loader/blob/master/src/index.js#L159
89-
{
90-
// Options for PostCSS as we reference these options twice
91-
// Adds vendor prefixing based on your specified browser support in
92-
// package.json
93-
loader: require.resolve('postcss-loader'),
94-
options: {
95-
postcssOptions: {
96-
// Necessary for external CSS imports to work
97-
// https://github.com/facebook/create-react-app/issues/2677
98-
ident: 'postcss',
99-
plugins: [
100-
// eslint-disable-next-line global-require
101-
require('autoprefixer'),
102-
],
94+
// TODO apart for configurePostCss(), do we really need this loader?
95+
// Note: using postcss here looks inefficient/duplicate
96+
// But in practice, it's not a big deal because css-loader also uses postcss
97+
// and is able to reuse the parsed AST from postcss-loader
98+
// See https://github.com/webpack-contrib/css-loader/blob/master/src/index.js#L159
99+
{
100+
// Options for PostCSS as we reference these options twice
101+
// Adds vendor prefixing based on your specified browser support in
102+
// package.json
103+
loader: require.resolve('postcss-loader'),
104+
options: {
105+
postcssOptions: {
106+
// Necessary for external CSS imports to work
107+
// https://github.com/facebook/create-react-app/issues/2677
108+
ident: 'postcss',
109+
plugins: [
110+
// eslint-disable-next-line global-require
111+
require('autoprefixer'),
112+
],
113+
},
103114
},
104115
},
105-
},
106-
];
116+
];
117+
};
107118
}
108119

109120
export async function getCustomBabelConfigFilePath(

0 commit comments

Comments
 (0)