diff --git a/packages/docusaurus/src/webpack/base.ts b/packages/docusaurus/src/webpack/base.ts index b100296ae3b0..f7fcb238de8f 100644 --- a/packages/docusaurus/src/webpack/base.ts +++ b/packages/docusaurus/src/webpack/base.ts @@ -13,8 +13,8 @@ import { getCustomizableJSLoader, getStyleLoaders, getCustomBabelConfigFilePath, - getMinimizer, } from './utils'; +import {getMinimizer} from './minification'; import {loadThemeAliases, loadDocusaurusAliases} from './aliases'; import type {Configuration} from 'webpack'; import type {Props} from '@docusaurus/types'; @@ -66,8 +66,7 @@ export async function createBaseConfig({ } = props; const totalPages = routesPaths.length; const isProd = process.env.NODE_ENV === 'production'; - const minimizeEnabled = minify && isProd && !isServer; - const useSimpleCssMinifier = process.env.USE_SIMPLE_CSS_MINIFIER === 'true'; + const minimizeEnabled = minify && isProd; const fileLoaderUtils = getFileLoaderUtils(); @@ -160,9 +159,7 @@ export async function createBaseConfig({ // Only minimize client bundle in production because server bundle is only // used for static site generation minimize: minimizeEnabled, - minimizer: minimizeEnabled - ? getMinimizer(useSimpleCssMinifier) - : undefined, + minimizer: minimizeEnabled ? getMinimizer() : undefined, splitChunks: isServer ? false : { diff --git a/packages/docusaurus/src/webpack/minification.ts b/packages/docusaurus/src/webpack/minification.ts new file mode 100644 index 000000000000..5ea877d8e179 --- /dev/null +++ b/packages/docusaurus/src/webpack/minification.ts @@ -0,0 +1,102 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import TerserPlugin from 'terser-webpack-plugin'; +import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'; +import type {CustomOptions, CssNanoOptions} from 'css-minimizer-webpack-plugin'; +import type {WebpackPluginInstance} from 'webpack'; + +// See https://github.com/webpack-contrib/terser-webpack-plugin#parallel +function getTerserParallel() { + let terserParallel: boolean | number = true; + if (process.env.TERSER_PARALLEL === 'false') { + terserParallel = false; + } else if ( + process.env.TERSER_PARALLEL && + parseInt(process.env.TERSER_PARALLEL, 10) > 0 + ) { + terserParallel = parseInt(process.env.TERSER_PARALLEL, 10); + } + return terserParallel; +} + +function getJsMinifierPlugin() { + return new TerserPlugin({ + parallel: getTerserParallel(), + terserOptions: { + parse: { + // We want uglify-js to parse ecma 8 code. However, we don't want it + // to apply any minification steps that turns valid ecma 5 code + // into invalid ecma 5 code. This is why the 'compress' and 'output' + // sections only apply transformations that are ecma 5 safe + // https://github.com/facebook/create-react-app/pull/4234 + ecma: 2020, + }, + compress: { + ecma: 5, + }, + mangle: { + safari10: true, + }, + output: { + ecma: 5, + comments: false, + // Turned on because emoji and regex is not minified properly using + // default. See https://github.com/facebook/create-react-app/issues/2488 + ascii_only: true, + }, + }, + }); +} + +function getAdvancedCssMinifier() { + // Using the array syntax to add 2 minimizers + // see https://github.com/webpack-contrib/css-minimizer-webpack-plugin#array + return new CssMinimizerPlugin<[CssNanoOptions, CustomOptions]>({ + minimizerOptions: [ + // CssNano options + { + preset: require.resolve('@docusaurus/cssnano-preset'), + }, + // CleanCss options + { + inline: false, + level: { + 1: { + all: false, + removeWhitespace: true, + }, + 2: { + all: true, + restructureRules: true, + removeUnusedAtRules: false, + }, + }, + }, + ], + minify: [ + CssMinimizerPlugin.cssnanoMinify, + CssMinimizerPlugin.cleanCssMinify, + ], + }); +} + +export function getMinimizer(): WebpackPluginInstance[] { + // This is an historical env variable to opt-out of the advanced minifier + // Sometimes there's a bug in it and people are happy to disable it + const useSimpleCssMinifier = process.env.USE_SIMPLE_CSS_MINIFIER === 'true'; + + const minimizer: WebpackPluginInstance[] = [getJsMinifierPlugin()]; + + if (useSimpleCssMinifier) { + minimizer.push(new CssMinimizerPlugin()); + } else { + minimizer.push(getAdvancedCssMinifier()); + } + + return minimizer; +} diff --git a/packages/docusaurus/src/webpack/server.ts b/packages/docusaurus/src/webpack/server.ts index e29bf762ce3a..10d274aa6663 100644 --- a/packages/docusaurus/src/webpack/server.ts +++ b/packages/docusaurus/src/webpack/server.ts @@ -23,7 +23,9 @@ export default async function createServerConfig(params: { const baseConfig = await createBaseConfig({ props, isServer: true, - minify: true, // TODO is it worth it to minify server bundle??? benchmark + + // Minification of server bundle reduces size but doubles bundle time :/ + minify: false, }); const outputFilename = 'server.bundle.js'; diff --git a/packages/docusaurus/src/webpack/utils.ts b/packages/docusaurus/src/webpack/utils.ts index 643475a9d64e..ee6c61f1ec66 100644 --- a/packages/docusaurus/src/webpack/utils.ts +++ b/packages/docusaurus/src/webpack/utils.ts @@ -16,15 +16,8 @@ import { customizeArray, customizeObject, } from 'webpack-merge'; -import webpack, { - type Configuration, - type RuleSetRule, - type WebpackPluginInstance, -} from 'webpack'; -import TerserPlugin from 'terser-webpack-plugin'; -import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'; +import webpack, {type Configuration, type RuleSetRule} from 'webpack'; import formatWebpackMessages from 'react-dev-utils/formatWebpackMessages'; -import type {CustomOptions, CssNanoOptions} from 'css-minimizer-webpack-plugin'; import type {TransformOptions} from '@babel/core'; import type { Plugin, @@ -418,87 +411,3 @@ export async function getHttpsConfig(): Promise< } return isHttps; } - -// See https://github.com/webpack-contrib/terser-webpack-plugin#parallel -function getTerserParallel() { - let terserParallel: boolean | number = true; - if (process.env.TERSER_PARALLEL === 'false') { - terserParallel = false; - } else if ( - process.env.TERSER_PARALLEL && - parseInt(process.env.TERSER_PARALLEL, 10) > 0 - ) { - terserParallel = parseInt(process.env.TERSER_PARALLEL, 10); - } - return terserParallel; -} - -export function getMinimizer( - useSimpleCssMinifier = false, -): WebpackPluginInstance[] { - const minimizer: WebpackPluginInstance[] = [ - new TerserPlugin({ - parallel: getTerserParallel(), - terserOptions: { - parse: { - // We want uglify-js to parse ecma 8 code. However, we don't want it - // to apply any minification steps that turns valid ecma 5 code - // into invalid ecma 5 code. This is why the 'compress' and 'output' - // sections only apply transformations that are ecma 5 safe - // https://github.com/facebook/create-react-app/pull/4234 - ecma: 2020, - }, - compress: { - ecma: 5, - }, - mangle: { - safari10: true, - }, - output: { - ecma: 5, - comments: false, - // Turned on because emoji and regex is not minified properly using - // default. See https://github.com/facebook/create-react-app/issues/2488 - ascii_only: true, - }, - }, - }), - ]; - if (useSimpleCssMinifier) { - minimizer.push(new CssMinimizerPlugin()); - } else { - minimizer.push( - // Using the array syntax to add 2 minimizers - // see https://github.com/webpack-contrib/css-minimizer-webpack-plugin#array - new CssMinimizerPlugin<[CssNanoOptions, CustomOptions]>({ - minimizerOptions: [ - // CssNano options - { - preset: require.resolve('@docusaurus/cssnano-preset'), - }, - // CleanCss options - { - inline: false, - level: { - 1: { - all: false, - removeWhitespace: true, - }, - 2: { - all: true, - restructureRules: true, - removeUnusedAtRules: false, - }, - }, - }, - ], - minify: [ - CssMinimizerPlugin.cssnanoMinify, - CssMinimizerPlugin.cleanCssMinify, - ], - }), - ); - } - - return minimizer; -}