Skip to content

Instantly share code, notes, and snippets.

@didi0613
Last active March 22, 2021 08:46
Show Gist options
  • Save didi0613/03165e58630e2d9e35f36859c663fd78 to your computer and use it in GitHub Desktop.
Save didi0613/03165e58630e2d9e35f36859c663fd78 to your computer and use it in GitHub Desktop.
Shorten css class names for css module

Shorten css class names for css module

Jira Ticket

https://jira.walmart.com/browse/CEECORE-255

Background

Electrode Application can use css-modules as one of the style options, CSS names can get long with local identifier name and random hash.

In order to improve this, app archetype uses babel-plugin-react-css-modules to shorten the selector names.

AC

dev env, class name composes by [name]__[local]___[hash:base64:5], ex) .skeleton__offset-by-four___1X84H

prod env, class name should generate shorten class names by [hash:base64:5], ex) ___1X84H

"clap dev" should show webapp using long CSS class names from CSS modules

"clap prod-start" should show webapp using short class names from CSS modules

Steps to reproduce

  • install electrode-ignite

  • generate a new app

  • do "npm run prod-start"

  • load page in browser

  • check page source and find the link to the CSS, open it, and observe all the class names

  • Ideally the class names in production should be shorten to something like "_1A5LB"

Basic example apps

App archetype changes: https://github.com/electrode-io/electrode/compare/master...didi0613:shorten-classnames-prod?expand=1

Example apps are based on the new apps generated with ignite:

css modules example: https://github.com/didi0613/basic-shorten-css

pure css example: https://github.com/didi0613/basic-shorten-css/tree/pure-css

scss + css modules example: https://github.com/didi0613/basic-shorten-css/tree/css-modules-scss

pure scss example: https://github.com/didi0613/basic-shorten-css/tree/pure-scss

pure stylus example: https://github.com/didi0613/basic-shorten-css/tree/pure-stylus

Results

Based on the testing apps above, css bundle size decreased from 13.2 kb to 9.94 kb, which is roughly 24.8% decreased.

Blocked section

stylus + css modules example: https://github.com/didi0613/basic-shorten-css/tree/css-modules-stylus

The current error with css modules + stylus:

Cannot use styleName attribute without importing at least one stylesheet.

The current babel config for .scss and .styl:

"filetypes": {
  ".scss": {
    "syntax": "postcss-scss",
    "plugins": [
      "postcss-nested"
    ]
  },
  ".styl": {
    "syntax": "sugarss"
  }
}

This happens when the app imports the .styl file but it still complaining about no stylesheet imported.

After some researches, the root cause is because there is no PostCSS parser for stylus, although its possible to configure syntax parsers. SugarCSS syntax is similar to Stylus, which why people think it might be able to share the syntax parsers, but there still exists some issues here.

Issue reported:

gajus/babel-plugin-react-css-modules#9

postcss/postcss#602 (comment)

How does it work?

  • Builds index of all stylesheet imports per file (imports of files with .css or .scss extension).

  • Uses postcss to parse the matching CSS files.

  • Iterates through all JSX element declarations.

  • Parses the styleName attribute value into anonymous and named CSS module references.

  • Finds the CSS class name matching the CSS module reference:

    • If styleName value is a string literal, generates a string literal value.

    • If styleName value is a jSXExpressionContainer, uses a helper function (getClassName) to construct the className value at the runtime.

  • Removes the styleName attribute from the element.

  • Appends the resulting className to the existing className value (creates className attribute if one does not exist).

How to enable Shorten CSS Names

Requirements

  • Please make sure your electrode-archetype-react-app(-dev) version is >= 5.4.0
  • Please make sure you are using css modules as your styles.

Steps

  • set true to enableShortenCSSNames flag

    Option #1: Enable through app config at archetype/config/index.js

    module.exports = {
      webpack: {
        enableShortenCSSNames: true
      }
    };
    

    Option #2: Enable through env variable at xclap.js

    process.env.ENABLE_SHORTEN_CSS_NAMES = true;
    
  • Update the CSS references

    • if there is only one stylesheet import, you can use Anonymous reference

      Format: CSS module name.

      Change from

      import style from "foo1.css";
      // Imports "a" CSS module from ./foo1.css.
      <div className={style.a}>hello world</div>
      

      into

      import "./foo1.css";
      // Imports "a" CSS module from ./foo1.css.
      <div styleName="a">hello world</div>;
      
    • if you need to refer a specific stylesheet, you can use Name reference

      Format: [name of the import].[CSS module name]

      Change from

      import foo from './foo1.css';
      import bar from './bar1.css';
      
      // Imports "a" CSS module from ./foo1.css.
      <div className={foo.a}></div>;
      
      // Imports "a" CSS module from ./bar1.css.
      <div className={bar.a}"></div>;
      

      into

      import foo from './foo1.css';
      import bar from './bar1.css';
      
      // Imports "a" CSS module from ./foo1.css.
      <div styleName="foo.a"></div>;
      
      // Imports "a" CSS module from ./bar1.css.
      <div styleName="bar.a"></div>;
      

demo

https://github.com/didi0613/electrode-basic-app-with-shorten-css

Resources

babel plugin react css modules

blog: reduce css bundle size by cutting the class names

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment