From 487a9f98e434b4e8bf1da75ab60cd5f7ba039840 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Fri, 13 Nov 2020 16:06:24 +0300 Subject: [PATCH] feat(v2): introduce new minification of CSS bundle (#3716) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(v2): optimize CSS bundle * Move to separate preset * Move custom scrollbar styles to separate class * Cleanup styles * Remove unactual styles * Various CSS optimizations, cleanup styles for NProgress * Add ability to back to old way of minifying CSS * chore(v2): downgrade babel-plugin-dynamic-import-node to 2.3.0 * Use env var for back to simple CSS minifier * remove unnecessary typing [skip-ci] * Remove missing dep * Update website/docs/cli.md Co-authored-by: Sébastien Lorber --- packages/docusaurus-cssnano-preset/index.js | 21 +++++ .../docusaurus-cssnano-preset/package.json | 21 +++++ .../__snapshots__/index.test.js.snap | 19 ++++ .../__tests__/fixtures/important_rule.css | 8 ++ .../__tests__/fixtures/normal.css | 7 ++ .../__tests__/index.test.js | 33 +++++++ .../index.js | 42 +++++++++ .../src/theme/CodeBlock/styles.module.css | 6 +- .../src/theme/DocSidebar/styles.module.css | 2 - .../src/theme/Heading/styles.css | 1 - .../src/theme/Toggle/styles.module.css | 39 +------- packages/docusaurus/package.json | 2 + .../src/client/PendingNavigation.tsx | 2 +- packages/docusaurus/src/client/nprogress.css | 36 ++++++++ packages/docusaurus/src/webpack/base.ts | 63 ++----------- packages/docusaurus/src/webpack/server.ts | 4 +- packages/docusaurus/src/webpack/utils.ts | 88 +++++++++++++++++++ website/docs/cli.md | 8 ++ website/src/pages/styles.module.css | 4 +- yarn.lock | 87 ++++++++++++++++++ 20 files changed, 386 insertions(+), 107 deletions(-) create mode 100644 packages/docusaurus-cssnano-preset/index.js create mode 100644 packages/docusaurus-cssnano-preset/package.json create mode 100644 packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/__snapshots__/index.test.js.snap create mode 100644 packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/fixtures/important_rule.css create mode 100644 packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/fixtures/normal.css create mode 100644 packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/index.test.js create mode 100644 packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/index.js create mode 100644 packages/docusaurus/src/client/nprogress.css diff --git a/packages/docusaurus-cssnano-preset/index.js b/packages/docusaurus-cssnano-preset/index.js new file mode 100644 index 0000000000..8c0a50f86c --- /dev/null +++ b/packages/docusaurus-cssnano-preset/index.js @@ -0,0 +1,21 @@ +/** + * 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. + */ + +const advancedBasePreset = require('cssnano-preset-advanced'); +const postCssCombineDuplicatedSelectors = require('postcss-combine-duplicated-selectors'); +const postCssSortMediaQueries = require('postcss-sort-media-queries'); +const postCssRemoveOverriddenCustomProperties = require('./src/remove-overridden-custom-properties'); + +const preset = advancedBasePreset({autoprefixer: {add: true}}); + +preset.plugins.unshift( + [postCssCombineDuplicatedSelectors, {removeDuplicatedProperties: true}], + [postCssSortMediaQueries], + [postCssRemoveOverriddenCustomProperties], +); + +module.exports = preset; diff --git a/packages/docusaurus-cssnano-preset/package.json b/packages/docusaurus-cssnano-preset/package.json new file mode 100644 index 0000000000..f0d1f484ea --- /dev/null +++ b/packages/docusaurus-cssnano-preset/package.json @@ -0,0 +1,21 @@ +{ + "name": "@docusaurus/cssnano-preset", + "version": "2.0.0-alpha.66", + "description": "Advanced cssnano preset for maximum optimization", + "main": "index.js", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/facebook/docusaurus.git", + "directory": "packages/docusaurus-cssnano-preset" + }, + "dependencies": { + "postcss": "^7.0.2", + "postcss-combine-duplicated-selectors": "^9.1.0", + "postcss-sort-media-queries": "^1.7.26", + "cssnano-preset-advanced": "^4.0.7" + }, + "devDependencies": { + "to-vfile": "^6.0.0" + } +} diff --git a/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/__snapshots__/index.test.js.snap b/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/__snapshots__/index.test.js.snap new file mode 100644 index 0000000000..38cf2d2195 --- /dev/null +++ b/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/__snapshots__/index.test.js.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`remove-overridden-custom-properties overridden custom properties should be removed 1`] = ` +":root { + --color-secondary: green; + --color-primary: blue; + --color-header: gray; +} +" +`; + +exports[`remove-overridden-custom-properties overridden custom properties with \`!important\` rule should not be removed 1`] = ` +":root { + --color-primary: blue; + --color-header: gray !important; + --color-secondary: yellow !important; +} +" +`; diff --git a/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/fixtures/important_rule.css b/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/fixtures/important_rule.css new file mode 100644 index 0000000000..7a9b223da8 --- /dev/null +++ b/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/fixtures/important_rule.css @@ -0,0 +1,8 @@ +:root { + --color-primary: red; + --color-secondary: green; + --color-primary: blue; + --color-header: gray !important; + --color-header: black; + --color-secondary: yellow !important; +} diff --git a/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/fixtures/normal.css b/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/fixtures/normal.css new file mode 100644 index 0000000000..22dd142958 --- /dev/null +++ b/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/fixtures/normal.css @@ -0,0 +1,7 @@ +:root { + --color-primary: red; + --color-primary: red; + --color-secondary: green; + --color-primary: blue; + --color-header: gray; +} diff --git a/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/index.test.js b/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/index.test.js new file mode 100644 index 0000000000..3d25209da3 --- /dev/null +++ b/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/__tests__/index.test.js @@ -0,0 +1,33 @@ +/** + * 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. + */ + +const path = require('path'); +const vfile = require('to-vfile'); +const postcss = require('postcss'); +const postCssRemoveOverriddenCustomProperties = require('../index'); + +const processFixture = (name) => { + const input = vfile.readSync( + path.join(__dirname, 'fixtures', `${name}.css`), + 'utf8', + ); + const output = postcss([postCssRemoveOverriddenCustomProperties]).process( + input, + ); + + return output.css; +}; + +describe('remove-overridden-custom-properties', () => { + test('overridden custom properties should be removed', () => { + expect(processFixture('normal')).toMatchSnapshot(); + }); + + test('overridden custom properties with `!important` rule should not be removed', () => { + expect(processFixture('important_rule')).toMatchSnapshot(); + }); +}); diff --git a/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/index.js b/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/index.js new file mode 100644 index 0000000000..2ee67fec89 --- /dev/null +++ b/packages/docusaurus-cssnano-preset/src/remove-overridden-custom-properties/index.js @@ -0,0 +1,42 @@ +/** + * 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. + */ + +const postcss = require('postcss'); + +/* +This PostCSS plugin will remove duplicate/same custom properties (which are actually overridden ones) **only** from `:root` selector. + +Depending on the presence of an `!important` rule in value of custom property, the following actions will happens: + +- If the same custom properties do **not** have an `!important` rule, then all of them will be removed except for the last one (which will actually be applied). +- If the same custom properties have at least one `!important` rule, then only those properties that do not have this rule will be removed. +*/ + +module.exports = postcss.plugin( + 'postcss-remove-overridden-custom-properties', + () => { + return (root) => { + root.walkDecls((decl) => { + if (decl.parent.selector !== ':root') { + return; + } + + const sameProperties = + decl.parent.nodes.filter((n) => n.prop === decl.prop) || []; + const hasImportantProperties = sameProperties.some((p) => + p.hasOwnProperty('important'), + ); + + const overriddenProperties = hasImportantProperties + ? sameProperties.filter((p) => !p.hasOwnProperty('important')) + : sameProperties.slice(0, -1); + + overriddenProperties.map((p) => p.remove()); + }); + }; + }, +); diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css b/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css index 190e770004..cc3cf38cd4 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css @@ -45,11 +45,7 @@ } .codeBlockTitle:hover + .codeBlockContent .copyButton, -.codeBlockContent:hover > .copyButton { - outline: none; - opacity: 1; -} - +.codeBlockContent:hover > .copyButton, .copyButton:focus { opacity: 1; } diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebar/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocSidebar/styles.module.css index 3cf845bb80..3d42eeed52 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebar/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebar/styles.module.css @@ -107,11 +107,9 @@ width: 24px; } -/* TODO: Move to Infima */ :global(.menu__list) :global(.menu__list) { overflow-y: hidden; will-change: height; - /* Same as "arrow" transition */ transition: height var(--ifm-transition-fast) linear; } diff --git a/packages/docusaurus-theme-classic/src/theme/Heading/styles.css b/packages/docusaurus-theme-classic/src/theme/Heading/styles.css index 7a9b4f73a5..01ca951111 100644 --- a/packages/docusaurus-theme-classic/src/theme/Heading/styles.css +++ b/packages/docusaurus-theme-classic/src/theme/Heading/styles.css @@ -9,7 +9,6 @@ display: block; position: relative; top: -0.5rem; - outline: none; } .hash-link { diff --git a/packages/docusaurus-theme-classic/src/theme/Toggle/styles.module.css b/packages/docusaurus-theme-classic/src/theme/Toggle/styles.module.css index 1ac128ce8c..6a0f2288f3 100644 --- a/packages/docusaurus-theme-classic/src/theme/Toggle/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/Toggle/styles.module.css @@ -10,7 +10,6 @@ display: flex; height: 10px; justify-content: center; - position: relative; width: 10px; } .toggle::before { @@ -25,21 +24,10 @@ */ :global(.react-toggle) { touch-action: pan-x; - display: inline-block; position: relative; cursor: pointer; - background-color: transparent; - border: 0; - padding: 0; - - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; user-select: none; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -webkit-tap-highlight-color: transparent; } @@ -50,7 +38,6 @@ height: 1px; margin: -1px; overflow: hidden; - padding: 0; position: absolute; width: 1px; } @@ -62,11 +49,8 @@ :global(.react-toggle-track) { width: 50px; height: 24px; - padding: 0; border-radius: 30px; background-color: #4d4d4d; - -webkit-transition: all 0.2s ease; - -moz-transition: all 0.2s ease; transition: all 0.2s ease; } @@ -76,21 +60,16 @@ height: 10px; top: 0px; bottom: 0px; - margin-top: auto; - margin-bottom: auto; + margin: auto 0; line-height: 0; left: 8px; opacity: 0; - -webkit-transition: opacity 0.25s ease; - -moz-transition: opacity 0.25s ease; transition: opacity 0.25s ease; } :global([data-theme='dark'] .react-toggle .react-toggle-track-check), :global(.react-toggle--checked .react-toggle-track-check) { opacity: 1; - -webkit-transition: opacity 0.25s ease; - -moz-transition: opacity 0.25s ease; transition: opacity 0.25s ease; } @@ -100,13 +79,10 @@ height: 10px; top: 0px; bottom: 0px; - margin-top: auto; - margin-bottom: auto; + margin: auto 0; line-height: 0; right: 10px; opacity: 1; - -webkit-transition: opacity 0.25s ease; - -moz-transition: opacity 0.25s ease; transition: opacity 0.25s ease; } @@ -125,13 +101,6 @@ border: 1px solid #4d4d4d; border-radius: 50%; background-color: #fafafa; - - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - - -webkit-transition: all 0.25s ease; - -moz-transition: all 0.25s ease; transition: all 0.25s ease; } @@ -142,13 +111,9 @@ } :global(.react-toggle--focus .react-toggle-thumb) { - -webkit-box-shadow: 0px 0px 3px 2px #0099e0; - -moz-box-shadow: 0px 0px 3px 2px #0099e0; box-shadow: 0px 0px 2px 3px #0099e0; } :global(.react-toggle:active:not(.react-toggle--disabled) .react-toggle-thumb) { - -webkit-box-shadow: 0px 0px 5px 5px #0099e0; - -moz-box-shadow: 0px 0px 5px 5px #0099e0; box-shadow: 0px 0px 5px 5px #0099e0; } diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index 4b02965657..313b66dd31 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -45,6 +45,7 @@ "@babel/preset-typescript": "^7.12.1", "@babel/runtime": "^7.12.5", "@babel/runtime-corejs3": "^7.12.5", + "@docusaurus/cssnano-preset": "2.0.0-alpha.66", "@docusaurus/types": "2.0.0-alpha.66", "@docusaurus/utils": "2.0.0-alpha.66", "@docusaurus/utils-validation": "2.0.0-alpha.66", @@ -56,6 +57,7 @@ "cache-loader": "^4.1.0", "chalk": "^3.0.0", "chokidar": "^3.4.3", + "clean-css": "^4.2.3", "commander": "^4.0.1", "copy-webpack-plugin": "^6.3.0", "core-js": "^2.6.5", diff --git a/packages/docusaurus/src/client/PendingNavigation.tsx b/packages/docusaurus/src/client/PendingNavigation.tsx index 9ef01f6167..1b2ae12ec1 100644 --- a/packages/docusaurus/src/client/PendingNavigation.tsx +++ b/packages/docusaurus/src/client/PendingNavigation.tsx @@ -13,7 +13,7 @@ import clientLifecyclesDispatcher from './client-lifecycles-dispatcher'; import preload from './preload'; import normalizeLocation from './normalizeLocation'; -import 'nprogress/nprogress.css'; +import './nprogress.css'; nprogress.configure({showSpinner: false}); diff --git a/packages/docusaurus/src/client/nprogress.css b/packages/docusaurus/src/client/nprogress.css new file mode 100644 index 0000000000..376e577a72 --- /dev/null +++ b/packages/docusaurus/src/client/nprogress.css @@ -0,0 +1,36 @@ +/** + * 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. + */ + +/** + * Styles for NProgress + * Copied over to remove unused styles for the spinner. + * https://github.com/rstacruz/nprogress/blob/master/nprogress.css + */ + +#nprogress { + pointer-events: none; +} + +#nprogress .bar { + background: #29d; + position: fixed; + z-index: 1031; + top: 0; + left: 0; + width: 100%; + height: 2px; +} + +#nprogress .peg { + position: absolute; + right: 0px; + width: 100px; + height: 100%; + box-shadow: 0 0 10px #29d, 0 0 5px #29d; + opacity: 1; + transform: rotate(3deg) translate(0px, -4px); +} diff --git a/packages/docusaurus/src/webpack/base.ts b/packages/docusaurus/src/webpack/base.ts index 46ff7c6883..74d356fed4 100644 --- a/packages/docusaurus/src/webpack/base.ts +++ b/packages/docusaurus/src/webpack/base.ts @@ -7,18 +7,16 @@ import fs from 'fs-extra'; import MiniCssExtractPlugin from 'mini-css-extract-plugin'; -import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin'; import PnpWebpackPlugin from 'pnp-webpack-plugin'; import path from 'path'; -import TerserPlugin from 'terser-webpack-plugin'; import {Configuration, Loader} from 'webpack'; - import {Props} from '@docusaurus/types'; import { getBabelLoader, getCacheLoader, getStyleLoaders, getFileLoaderUtils, + getMinimizer, } from './utils'; import {BABEL_CONFIG_FILE_NAME} from '../constants'; @@ -38,26 +36,17 @@ export function excludeJS(modulePath: string): boolean { ); } -// See https://github.com/webpack-contrib/terser-webpack-plugin#parallel -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); -} - export function createBaseConfig( props: Props, isServer: boolean, - minify: boolean, + minify: boolean = true, ): Configuration { const {outDir, siteDir, baseUrl, generatedFilesDir, routesPaths} = 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 customBabelConfigurationPath = path.join( siteDir, @@ -108,46 +97,10 @@ export function createBaseConfig( optimization: { removeAvailableModules: false, // Only minimize client bundle in production because server bundle is only used for static site generation - minimize: minify && isProd && !isServer, - minimizer: - minify && isProd - ? [ - new TerserPlugin({ - cache: true, - parallel: terserParallel, - sourceMap: false, - terserOptions: { - parse: { - // we want uglify-js to parse ecma 8 code. However, we don't want it - // to apply any minfication 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: 8, - }, - compress: { - ecma: 5, - warnings: false, - }, - mangle: { - safari10: true, - }, - output: { - ecma: 5, - comments: false, - // Turned on because emoji and regex is not minified properly using default - // https://github.com/facebook/create-react-app/issues/2488 - ascii_only: true, - }, - }, - }), - new OptimizeCSSAssetsPlugin({ - cssProcessorPluginOptions: { - preset: 'default', - }, - }), - ] - : undefined, + minimize: minimizeEnabled, + minimizer: minimizeEnabled + ? getMinimizer(useSimpleCssMinifier) + : undefined, splitChunks: isServer ? false : { diff --git a/packages/docusaurus/src/webpack/server.ts b/packages/docusaurus/src/webpack/server.ts index 25d10d9568..715e7b06d6 100644 --- a/packages/docusaurus/src/webpack/server.ts +++ b/packages/docusaurus/src/webpack/server.ts @@ -17,11 +17,9 @@ import LogPlugin from './plugins/LogPlugin'; export default function createServerConfig({ props, - minify = true, onLinksCollected = () => {}, }: { props: Props; - minify?: boolean; onLinksCollected?: (staticPagePath: string, links: string[]) => void; }): Configuration { const { @@ -34,7 +32,7 @@ export default function createServerConfig({ ssrTemplate, siteConfig: {noIndex}, } = props; - const config = createBaseConfig(props, true, minify); + const config = createBaseConfig(props, true); const routesLocation = {}; // Array of paths to be rendered. Relative to output directory diff --git a/packages/docusaurus/src/webpack/utils.ts b/packages/docusaurus/src/webpack/utils.ts index 45ddb1dda3..d87fa43b4d 100644 --- a/packages/docusaurus/src/webpack/utils.ts +++ b/packages/docusaurus/src/webpack/utils.ts @@ -9,12 +9,16 @@ import MiniCssExtractPlugin from 'mini-css-extract-plugin'; import env from 'std-env'; import merge from 'webpack-merge'; import webpack, {Configuration, Loader, RuleSetRule, Stats} from 'webpack'; +import TerserPlugin from 'terser-webpack-plugin'; +import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin'; +import CleanCss from 'clean-css'; import fs from 'fs'; import path from 'path'; import crypto from 'crypto'; import chalk from 'chalk'; import {TransformOptions} from '@babel/core'; import {ConfigureWebpackFn} from '@docusaurus/types'; +import CssNanoPreset from '@docusaurus/cssnano-preset'; import {version as cacheLoaderVersion} from 'cache-loader/package.json'; import {STATIC_ASSETS_DIR_NAME} from '../constants'; @@ -336,3 +340,87 @@ export function getHttpsConfig(): boolean | {cert: Buffer; key: Buffer} { } 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) { + const minimizer = [ + new TerserPlugin({ + cache: true, + parallel: getTerserParallel(), + sourceMap: false, + 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: 8, + }, + compress: { + ecma: 5, + warnings: false, + }, + mangle: { + safari10: true, + }, + output: { + ecma: 5, + comments: false, + // Turned on because emoji and regex is not minified properly using default + // https://github.com/facebook/create-react-app/issues/2488 + ascii_only: true, + }, + }, + }), + ]; + + if (useSimpleCssMinifier) { + minimizer.push( + new OptimizeCSSAssetsPlugin({ + cssProcessorPluginOptions: { + preset: 'default', + }, + }), + ); + } else { + minimizer.push( + ...[ + new OptimizeCSSAssetsPlugin({ + cssProcessorPluginOptions: { + preset: CssNanoPreset, + }, + }), + new OptimizeCSSAssetsPlugin({ + cssProcessor: CleanCss, + cssProcessorOptions: { + level: { + 1: { + all: false, + }, + 2: { + all: true, + restructureRules: true, + }, + }, + }, + }), + ], + ); + } + + return minimizer; +} diff --git a/website/docs/cli.md b/website/docs/cli.md index 8dcd27ee2b..e91b21f355 100644 --- a/website/docs/cli.md +++ b/website/docs/cli.md @@ -85,6 +85,14 @@ Compiles your site for production. | `--out-dir` | `build` | The full path for the new output directory, relative to the current workspace. | | `--no-minify` | `false` | Build website without minimizing JS/CSS bundles. | +:::info + +For advanced minification of CSS bundle, we use the [advanced cssnano preset](https://github.com/cssnano/cssnano/tree/master/packages/cssnano-preset-advanced) (along with additional several PostCSS plugins) and [level 2 optimization of clean-css](https://github.com/jakubpawlowicz/clean-css#level-2-optimizations). +If as a result of this advanced CSS minification you find broken CSS, build your website with the environment variable `USE_SIMPLE_CSS_MINIFIER=true` to minify CSS with the [default cssnano preset](https://github.com/cssnano/cssnano/tree/master/packages/cssnano-preset-default). +**Please [fill out an issue](https://github.com/facebook/docusaurus/issues/new?labels=bug%2C+needs+triage&template=bug.md) if you experience CSS minification bugs.** + +::: + ### `docusaurus swizzle` :::caution diff --git a/website/src/pages/styles.module.css b/website/src/pages/styles.module.css index e4e5630b44..65f09d6149 100644 --- a/website/src/pages/styles.module.css +++ b/website/src/pages/styles.module.css @@ -103,14 +103,12 @@ } .indexCtasGetStartedButton { - border: 1px solid var(--ifm-color-primary); - display: inline-block; + border: 2px solid var(--ifm-color-primary); line-height: 1.2em; text-decoration: none !important; text-transform: uppercase; transition: background 0.3s, color 0.3s; border-radius: 8px; - border-width: 2px; color: #fff; font-size: 24px; font-weight: bold; diff --git a/yarn.lock b/yarn.lock index 7e18fef041..ac2cb72f8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5961,6 +5961,19 @@ autolinker@~0.28.0: dependencies: gulp-header "^1.7.1" +autoprefixer@^9.4.7: + version "9.8.6" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" + integrity sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg== + dependencies: + browserslist "^4.12.0" + caniuse-lite "^1.0.30001109" + colorette "^1.2.1" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^7.0.32" + postcss-value-parser "^4.1.0" + autoprefixer@^9.6.1: version "9.7.3" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.3.tgz#fd42ed03f53de9beb4ca0d61fb4f7268a9bb50b4" @@ -6987,6 +7000,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30000989, can resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001157.tgz" integrity sha512-gOerH9Wz2IRZ2ZPdMfBvyOi3cjaz4O4dgNwPGzx8EhqAs4+2IL/O+fJsbt+znSigujoZG8bVcIAUM/I/E5K3MA== +caniuse-lite@^1.0.30001109: + version "1.0.30001156" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001156.tgz#75c20937b6012fe2b02ab58b30d475bf0718de97" + integrity sha512-z7qztybA2eFZTB6Z3yvaQBIoJpQtsewRD74adw2UbRWwsRq3jIPvgrQGawBMbfafekQaD21FWuXNcywtTDGGCw== + capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" @@ -8452,6 +8470,18 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== +cssnano-preset-advanced@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-4.0.7.tgz#d981527b77712e2f3f3f09c73313e9b71b278b88" + integrity sha512-j1O5/DQnaAqEyFFQfC+Z/vRlLXL3LxJHN+lvsfYqr7KgPH74t69+Rsy2yXkovWNaJjZYBpdz2Fj8ab2nH7pZXw== + dependencies: + autoprefixer "^9.4.7" + cssnano-preset-default "^4.0.7" + postcss-discard-unused "^4.0.1" + postcss-merge-idents "^4.0.1" + postcss-reduce-idents "^4.0.2" + postcss-zindex "^4.0.1" + cssnano-preset-default@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz#51ec662ccfca0f88b396dcd9679cdb931be17f76" @@ -17220,6 +17250,14 @@ postcss-colormin@^4.0.3: postcss "^7.0.0" postcss-value-parser "^3.0.0" +postcss-combine-duplicated-selectors@^9.1.0: + version "9.4.0" + resolved "https://registry.yarnpkg.com/postcss-combine-duplicated-selectors/-/postcss-combine-duplicated-selectors-9.4.0.tgz#dae866debae5f93b58e13e6cc69419105e91336a" + integrity sha512-rMnO1H3wgR1T6QSlK3i8Slz9p3xD+0yOi4J7qwh/5PGR3z8jbgYvRlNKAIvXDtGBQbJKoWs4df5skL3a/fdUEA== + dependencies: + postcss "^7.0.0" + postcss-selector-parser "^6.0.0" + postcss-convert-values@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" @@ -17287,6 +17325,15 @@ postcss-discard-overridden@^4.0.1: dependencies: postcss "^7.0.0" +postcss-discard-unused@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-4.0.1.tgz#ee7cc66af8c7e8c19bd36f12d09c4bde4039abea" + integrity sha512-/3vq4LU0bLH2Lj4NYN7BTf2caly0flUB7Xtrk9a5K3yLuXMkHMqMO/x3sDq8W2b1eQFSCyY0IVz2L+0HP8kUUA== + dependencies: + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + uniqs "^2.0.0" + postcss-double-position-gradients@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz#fc927d52fddc896cb3a2812ebc5df147e110522e" @@ -17415,6 +17462,16 @@ postcss-media-query-parser@^0.2.3: resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" integrity sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ= +postcss-merge-idents@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-4.0.1.tgz#b7df282a92f052ea0a66c62d8f8812e6d2cbed23" + integrity sha512-43S/VNdF6II0NZ31YxcvNYq4gfURlPAAsJW/z84avBXQCaP4I4qRHUH18slW/SOlJbcxxCobflPNUApYDddS7A== + dependencies: + cssnano-util-same-parent "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + postcss-merge-longhand@^4.0.11: version "4.0.11" resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" @@ -17680,6 +17737,14 @@ postcss-pseudo-class-any-link@^6.0.0: postcss "^7.0.2" postcss-selector-parser "^5.0.0-rc.3" +postcss-reduce-idents@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-4.0.2.tgz#30447a6ec20941e78e21bd4482a11f569c4f455b" + integrity sha512-Tz70Ri10TclPoCtFfftjFVddx3fZGUkr0dEDbIEfbYhFUOFQZZ77TEqRrU0e6TvAvF+Wa5VVzYTpFpq0uwFFzw== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + postcss-reduce-initial@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" @@ -17787,6 +17852,14 @@ postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: indexes-of "^1.0.1" uniq "^1.0.1" +postcss-sort-media-queries@^1.7.26: + version "1.31.21" + resolved "https://registry.yarnpkg.com/postcss-sort-media-queries/-/postcss-sort-media-queries-1.31.21.tgz#3225ec6eb490402602284ac99963b80461783cee" + integrity sha512-h+HbXXfOVFeLvCJOzl/Z9SqQ25MNpG/73k71756ftisaaJy75h06/Dn6KOwC4OCMN10ewT2PXMzHV03JNKwBbg== + dependencies: + postcss "^7.0.27" + sort-css-media-queries "1.5.0" + postcss-svgo@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.2.tgz#17b997bc711b333bab143aaed3b8d3d6e3d38258" @@ -17839,6 +17912,15 @@ postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: indexes-of "^1.0.1" uniq "^1.0.1" +postcss-zindex@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-4.0.1.tgz#8db6a4cec3111e5d3fd99ea70abeda61873d10c1" + integrity sha512-d/8BlQcUdEugZNRM9AdCA2V4fqREUtn/wcixLN3L6ITgc2P/FMcVVYz8QZkhItWT9NB5qr8wuN2dJCE4/+dlrA== + dependencies: + has "^1.0.0" + postcss "^7.0.0" + uniqs "^2.0.0" + postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.18, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.23, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.31, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6, postcss@^7.0.7: version "7.0.32" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.32.tgz#4310d6ee347053da3433db2be492883d62cec59d" @@ -20059,6 +20141,11 @@ socks@~2.3.2: ip "1.1.5" smart-buffer "^4.1.0" +sort-css-media-queries@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/sort-css-media-queries/-/sort-css-media-queries-1.5.0.tgz#8f605ad372caad0b81be010311882c046e738093" + integrity sha512-QofNE7CEVH1AKdhS7L9IPbV9UtyQYNXyw++8lC+xG6iOLlpzsmncZRiKbihTAESvZ8wOhwnPoesHbMrehrQyyw== + sort-keys-length@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188"