npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

breezify

v1.1.3

Published

A tool for minifying CSS class names

Downloads

172

Readme

Breezify

Twitter post - 1

NPM Version NPM Downloads GitHub License GitHub Issues GitHub Pull Requests GitHub Sponsors

Give some fresh air to your production HTML, JS and CSS! Breezify is a library that replaces class names in your build files with shorter ones.

Works with most frameworks. Next.js is now supported!

Sponsored by

Foxie Solutions

If you like the project and want to support it, you can donate to the author:

Installation

  1. npm i -g breezify
  2. breezify init in your project folder to create a config file

Usage

CLI usage

  • Update your build command in package.json like that: { "build": "your-build-command && breezify do" }
  • Use breezify do -h for the list of options

API usage

CommonJS:

const breezify = require('breezify');

breezify(options);

ESM:

import breezify from 'breezify';

breezify(options);

Webpack 5 Plugin (Next.js)

Initialize the plugin in your next.config.js:

const { BreezifyWebpack5Plugin } = require("breezify");

module.exports = {
  webpack: (config) => {
    if (config.mode === "production") {
      config.plugins.push(new BreezifyWebpack5Plugin());
    }
    return config;
  },
}

You can pass options to the plugin:

new BreezifyWebpack5Plugin({
  css: {
    prefix: "tw-",
  },
});

Examples

  • See https://github.com/glebgorokhov/breezify-examples

Ask Question or Discuss

Abstract

Long class names are great for development, but they can make your production files unnecessarily large. Replacing class names with shorter ones can reduce the file sizes and improve performance.

Breezify turns this:

<div class="w-full max-w-content px-6 md:px-9 grid mx-auto z-[1] relative gap-x-6 md:gap-x-10 gap-y-6 md:gap-y-10 grid-cols-1 md:grid-cols-2 justify-items-start items-start">
  <a
    href="#"
    class="gap-2 items-center mb-10 transition-all text-theme-text-interactive dark:text-dark-text-interactive group-hover:text-theme-text-interactive-hover hover:text-theme-text-interactive-hover dark:hover:text-dark-text-interactive-hover dark:group-hover:text-dark-text-interactive-hover"
  >
    Carts
  </a>
</div>

into this:

<div class="a b c d e f g h i j k l m n o p">
  <a href="#" class="q r s t u v y z A B">
    Carts
  </a>
</div>

439 characters of class names reduced to 50 characters! (89% less)

Breezify uses AST tree parsing and manipulations for JS and CSS to carefully transform the code, so in JS it turns this:

const mySpecialClass = "primary-color";
const decorated = "decorated";

const header = document.querySelector(
  `.header[role='decorated']:not(.decorated) .aside, ${decorated}, aside > .aside, ${mySpecialClass}`,
);

into this:

const mySpecialClass = "a";
const decorated = "b";

const header = document.querySelector(
  `.c[role='decorated']:not(.b) .d, ${decorated}, aside > .d, ${mySpecialClass}`,
);

In CSS, it turns this:

.focus\:border-\[blue-500\]:focus {
    border-color: #4299e1;
}

.group:hover .group-hover\:text-\[blue-400\] {
    color: #63b3ed;
}

into this:

.a:focus {
  border-color: #4299e1;
}

.b:hover .c {
  color: #63b3ed;
}

It also works with inline scripts and styles, and it's customizable to fit your needs.

Reasons

Every byte counts – money, load times, performance, and user experience.

Debugging

In case of code in most cases there is no much difference between your class name and any other string. So when Breezify replaces your class name with a new one there is a possibility of replacing the wrong value which can cause a bug.

Best Practice: Use Prefix for Class Names

The best way to run Breezify without any issues is to prefix your class names with a unique prefix, like tw- for Tailwind CSS. You can also use includeClassPatterns and ignoreClassPatterns options to include or ignore class names by patterns.

{
  css: {
    includeClassPatterns: ["^tw-"],
    ignoreClassPatterns: ["^ProseMirror"],
  }
}

Prefix your Breezify Class Names for Debugging

To make it easier to find and fix bugs, you can add a prefix to the class names in the config file. When you see a bug, you can find this place in the code and replace a conflicting class name with a safe one in your source files. After that you can remove the prefix.

{
  css: {
    prefix: "breezify-",
  }
}

Use Custom Skip Rules for JS

If you have a problem with JS, you can use skip rules to ignore certain nodes when replacing the class names. See ESTree, Acorn, and example skip rules.

Example:

/**
 * Skip local storage methods
 * @param node {AnyNode} - AST node
 * @param ancestors {AnyNode[]} - Ancestors of the AST node
 */
function skipLocalStorageMethods(
  node: AnyNode,
  ancestors: AnyNode[],
): boolean {
  return (
    ancestors[ancestors.length - 2]?.callee?.object?.name === "localStorage"
  );
}

const options: BreezifyOptions = {
  js: {
    skipRules: [skipLocalStorageMethods],
  }
}

This will ignore class names in the localStorage methods, for example, in this case:

localStorage.setItem("favoriteClassName", "myClassName");

Breezify Options API Documentation

BreezifyOptions

Options for configuring Breezify.

  • config (string): The path to the Breezify config file.
  • ignoreConfig (boolean): Whether to ignore the config file.
  • files (FilesOptions): Configuration options for file handling.
  • css (CSSOptions): Configuration options for CSS processing.
  • js (JSOptions): Configuration options for JavaScript processing.
  • html (HTMLOptions): Configuration options for HTML processing.

FilesOptions

Options related to file handling.

  • buildDir (string): The directory where the files are located. Default: "dist".
  • outputDir (string | undefined): The directory where the files should be outputted.
  • pattern (string): The pattern to match files relative to the build folder. Default: "**/*.{css,js,html}". See glob for pattern syntax.
  • ignore (string[]): The RegExp patterns to ignore. Use as strings, without modifiers. Example: ["^node_modules/"].

CSSOptions

Options for CSS processing.

  • includeClassPatterns (string[] | undefined): The RegExp patterns to include. Example: ["^tw-"] for class names with "tw-" prefix.
  • ignoreClassPatterns (string[] | undefined): The RegExp patterns to ignore. Use as strings, without modifiers. Example: ["^ProseMirror"] for class names with "ProseMirror" prefix.
  • shuffle (boolean | undefined): Whether to shuffle class names. Default: true.
  • prefix (string | undefined): The prefix to add to the class names.
  • minify (boolean | undefined): Whether to minify the output CSS. Default: true.
  • extractClassesFromHtml (boolean | undefined): Whether to extract class names from tags found in HTML files. Default: true.
  • restructure (boolean | undefined): Whether to restructure the output CSS with CSSO for more efficient minification. Can break your styles! Default: false.
  • forceMediaMerge (boolean | undefined): Whether to force merging media queries with CSSO for more efficient minification. Can break your styles! Default: false.

JSOptions

Options for JavaScript processing.

  • ignoreStringPatterns (string[] | undefined): The RegExp patterns to ignore when replacing class names in strings in JS files. Use as strings, without modifiers. Example: ["^%s"].
  • skipRules (SkipRule[] | undefined): Skip rules to ignore certain nodes. See ESTree, Acorn, and example skip rules.
  • mode ("acorn" | "simple" | undefined): The mode to use for parsing JS files. Default: "acorn".
  • minify (boolean | undefined): Whether to minify the output JS. Default: true.
  • minifyInlineJS (boolean | undefined): Whether to minify inline JS (inside HTML files). Default: true.

HTMLOptions

Options for HTML processing.

  • attributes (string[]): The attributes you use for class names in HTML files. You may want to include some data attributes in addition to default. Default: ["class"].
  • beautify (boolean | PrettyOptions | undefined): Whether to beautify the output HTML.
  • minify (boolean | Options | undefined): Whether to minify the output HTML. If true, minifyHtmlDefaultOptions will be used. See html-minifier.

Default configuration

const options: BreezifyOptions = {
  files: {
    buildDir: "dist",
    pattern: "**/*.{css,js,html}",
    ignore: [],
  },
  css: {
    minify: true,
    extractClassesFromHtml: true,
  },
  js: {
    mode: "acorn",
    minify: true,
  },
  html: {
    attributes: ["class"],
    minify: true,
  },
}

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

I appreciate any help with the project!

Please read CONTRIBUTING.md and CODE_OF_CONDUCT.md for details.