Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: ensure consistent CSS ordering #6222

Merged
merged 7 commits into from
Dec 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions website/_dogfooding/clientModuleCSS.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* 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.
*/

/* Used to test CSS insertion order */
.test-marker-site-client-module {
content: "site-client-module";
}
12 changes: 12 additions & 0 deletions website/_dogfooding/dogfooding.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ const dogfoodingPluginInstances = [
routeBasePath: '/tests/pages',
}),
],

/** @type {import('@docusaurus/types').Plugin} */
function clientModuleTestPlugin() {
return {
getClientModules() {
return [
require.resolve('./clientModuleExample.ts'),
require.resolve('./clientModuleCSS.css'),
];
},
};
},
];

exports.dogfoodingPluginInstances = dogfoodingPluginInstances;
1 change: 0 additions & 1 deletion website/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ const config = {
'static',
path.join(__dirname, '_dogfooding/_asset-tests'),
],
clientModules: [require.resolve('./_dogfooding/clientModuleExample.ts')],
themes: ['live-codeblock'],
plugins: [
FeatureRequestsPlugin,
Expand Down
5 changes: 3 additions & 2 deletions website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@
"deploy": "docusaurus deploy",
"clear": "docusaurus clear",
"serve": "docusaurus serve",
"test:css-order": "node testCSSOrder.js",
"write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids",
"start:baseUrl": "cross-env BASE_URL='/build/' yarn start",
"build:baseUrl": "cross-env BASE_URL='/build/' yarn build",
"start:blogOnly": "cross-env yarn start --config=docusaurus.config-blog-only.js",
"build:blogOnly": "cross-env yarn build --config=docusaurus.config-blog-only.js",
"build:fast": "cross-env BUILD_FAST=true yarn build --locale en",
"netlify:build:production": "yarn docusaurus write-translations && yarn netlify:crowdin:delay && yarn netlify:crowdin:uploadSources && yarn netlify:crowdin:downloadTranslations && yarn build",
"netlify:build:deployPreview": "yarn docusaurus write-translations --locale fr --messagePrefix '(fr) ' && yarn build",
"netlify:build:production": "yarn docusaurus write-translations && yarn netlify:crowdin:delay && yarn netlify:crowdin:uploadSources && yarn netlify:crowdin:downloadTranslations && yarn build && yarn test:css-order",
"netlify:build:deployPreview": "yarn docusaurus write-translations --locale fr --messagePrefix '(fr) ' && yarn build && yarn test:css-order",
"netlify:crowdin:delay": "node delayCrowdin.js",
"netlify:crowdin:wait": "node waitForCrowdin.js",
"netlify:crowdin:downloadTranslations": "yarn netlify:crowdin:wait && yarn --cwd .. crowdin:download:website",
Expand Down
8 changes: 8 additions & 0 deletions website/src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,11 @@ div[class^='announcementBar_'] {
width: 1px;
white-space: nowrap;
}

/* Used to test CSS insertion order */
.test-marker-site-custom-css-unique-rule {
content: "site-custom-css-unique-rule";
}
.test-marker-site-custom-css-shared-rule {
max-width: 100%;
}
5 changes: 5 additions & 0 deletions website/src/pages/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,8 @@
display: none;
}
}

/* Used to test CSS insertion order */
.test-marker-site-index-page {
content: "site-index-page";
}
17 changes: 17 additions & 0 deletions website/src/theme/Layout/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* 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 React from 'react';
import type {Props} from '@theme/Layout';
import Layout from '@theme-original/Layout';

// This component is only used to test for CSS insertion order
import './styles.module.css';

export default function LayoutWrapper(props: Props): JSX.Element {
return <Layout {...props} />;
}
12 changes: 12 additions & 0 deletions website/src/theme/Layout/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* 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.
*/

/* Used to test CSS insertion order */
.test-marker-theme-layout {
content: "theme-layout";
}

110 changes: 110 additions & 0 deletions website/testCSSOrder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* 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 fs = require('fs');

/*
This verifies CSS ordering on the Docusaurus site itself,

There are multiple ways to provide some CSS to Docusaurus
and Docusaurus should guarantee a consistent CSS ordering over time

See also
- https://github.com/facebook/docusaurus/issues/3678
- https://github.com/facebook/docusaurus/pull/5987

TODO we should probably add a real e2e test in core instead of using our own website?
Current solution looks good-enough for now

*/

// TODO temporary, the current order is bad and we should change/fix that
const EXPECTED_CSS_MARKERS = [
// Note, Infima and site classes are optimized/deduplicated and put at the top
// We don't agree yet on what should be the order for those classes
// See https://github.com/facebook/docusaurus/pull/6222
'.markdown>h2',
'.button--outline.button--active',
'.DocSearch-Hit-content-wrapper',
'.navbar__title',
'--ifm-color-scheme:light',
'.test-marker-site-custom-css-shared-rule',
'.col[class*=col--]',
'.padding-vert--xl',
'.footer__link-item',
'.pagination__item',
'.pills__item',
'.tabs__item',

// Test markers
'.test-marker-site-custom-css-unique-rule',
'.test-marker-site-client-module',
'.test-marker-theme-layout',
'.test-marker-site-index-page',

// lazy loaded lib
'.DocSearch-Modal',
];
Copy link
Collaborator Author

@slorber slorber Dec 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lex111 @Josh-Cena as we can see the output CSS is currently in a weird order.

Due to CSS optimizations, Infima classes are re-ordered. Site custom CSS classes are "merged" with Infima classes sharing similar rules and put at the very beginning. We end up with CSS classes from different places (site, client modules, Infima, theme...) being interleaved in an unpredictable way.

I'm not sure if this is the correct thing to do in all cases, and I'd rather disable such optimizations, as it's better to do something that works than save a few Kb.

Are these optimizations always guaranteed 100% safe?


The main problem remains that site custom CSS should rather be last so that a site owner can more easily override existing CSS without !important

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, if it's because of optimization it makes perfect sense, and that's the entire purpose of optimization: combine duplicated classes where it can. If you have two class names that are identical in every way, it will be safe to combine them. I wouldn't worry about that since there's nothing to override in this case either.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have a bloated bundle size that I've been looking for ways to minimize (e.g. #3655 could be a way out). Optimizations are meant to be optimizations: there aren't behavior differences but you can't expect everything to be the same, in the same way you can't rely on someFunction.name since it can be minified


const cssDirName = path.join(__dirname, 'build', 'assets', 'css');

const cssFileNames = fs
.readdirSync(cssDirName)
.filter((file) => file.endsWith('.css'));

if (cssFileNames.length !== 1) {
throw new Error('unexpected: more than 1 css file');
}
const cssFile = path.join(cssDirName, cssFileNames[0]);

console.log('Inspecting CSS file for test CSS markers', cssFile);

const cssFileContent = fs.readFileSync(cssFile, 'utf8');

const cssMarkersWithPositions = EXPECTED_CSS_MARKERS.map((marker) => {
const position = cssFileContent.indexOf(marker);
return {marker, position};
});

const missingCSSMarkers = cssMarkersWithPositions
.filter((m) => m.position === -1)
.map((m) => m.marker);

if (missingCSSMarkers.length > 0) {
throw new Error(
`Some expected CSS marker classes could not be found in file ${cssFile}: \n- ${missingCSSMarkers.join(
'\n- ',
)}`,
);
}

// https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_sortby-and-_orderby
const sortBy = (key) => (a, b) =>
// eslint-disable-next-line no-nested-ternary
a[key] > b[key] ? 1 : b[key] > a[key] ? -1 : 0;

const sortedCSSMarkers = cssMarkersWithPositions
.concat()
.sort(sortBy('position'))
.map(({marker}) => marker);

if (JSON.stringify(sortedCSSMarkers) === JSON.stringify(EXPECTED_CSS_MARKERS)) {
console.log(`Test CSS markers were found in the expected order:
- ${sortedCSSMarkers.join('\n- ')}`);
} else {
throw new Error(`Test CSS markers were found in an incorrect order.

Expected order:
- ${EXPECTED_CSS_MARKERS.join('\n- ')};

Actual order:
- ${sortedCSSMarkers.join('\n- ')};

CSS file: ${cssFile}
`);
}