Skip to content

A svelte preprocess for safely minimizing CSS class footprint for unbeliveable performance gain. 🚀 🚀 🚀

License

Notifications You must be signed in to change notification settings

winston0410/glory-svelte-preprocess

Repository files navigation

glory-svelte-preprocess

A svelte preprocess minimize CSS class footprint with statical analysis for unbeliveable performance gain. 🚀 🚀 🚀

Disclaimers

Although this preprocess has been tested extensively, this is not stable yet and expect a bug or two given the complexity of the whole process. Do open an issue and let me know if something go south, and I will try to fix as fast as I can.

tldr;

Given the following input:

<style>
    .hello{
        color: red;
        font-size: 12px;
    }

    @media screen and (min-width: 600px) {
      .hello{
        margin: none;
      }
    }

    .world{
        color: red;
        font-size: 16px;
    }
</style>

<h1 class="hello">This preprocess</h1>
<h2 class="world">
    <p>does magic!</p>
</h2>

This preprocess will turn this into the following output in Svelte:

<style>
    :global(.a){
        color: red;
    }

    :global(.b){
        font-size: 12px;
    }

    :global(.c){
        font-size: 16px;
    }

    @media screen and (min-width: 600px) {
      :global(.d){
        margin: none;
      }
    }
</style>

<h1 class="a b d">This preprocess</h1>
<h2 class="a c">
    <p>does magic!</p>
</h2>

And Svelte will generate the following HTML and CSS(should be external stylesheet, using <style> here for demo purpose):

<style>
  .a {
    color: red;
  }

  .b {
    font-size: 12px;
  }

  .c {
    font-size: 16px;
  }

  @media screen and (min-width: 600px) {
    .d {
      margin: none;
    }
  }
</style>

<h1 class="a b d">This preprocess</h1>
<h2 class="a c">
  <p>does magic!</p>
</h2>

Supported selectors

This preprocess will transform rules with the following selectors:

  • Type Selector h1

  • Id Selector #foo

  • Class Selector .foo

  • Attribute Selector li[title]

  • Descendant combinator .foo .bar

  • Child combinator .foo>.bar

  • Adjacent sibling combinator .foo+.bar

  • General sibling combinator .foo~.bar

  • Pseudo class .foo:hover

  • Pseudo selector .foo::before

  • :not() selector a:not(.hello)

Known limitations

This preprocess currently doesn't handle the following selectors. It will not transform rules with theses selectors.

  • multiple pseudo selectors (e.g. .foo:active .bar:hover)

  • :global() selector (as svelte/compiler doesn't parse its value correctly right now)

FAQ

No hash for classname?

Unlike other CSS hashing solutions that hash based on the content of the stylesheet(e.g. CSS Module), Glory hashes based on declarations(declaration refers to the combination of property and value, like font-size:20px).

With that, classnames are now irrelavent and that abstration layer is removed. You are basically writing declarations to the component directly, as if using inline style attribute, but everything in a nicer way.

Why do you turn everything global? Is there any scope for isolation?

As the hash is built based on declarations, you can maximize the compression gain only if you share the hash across all components.

Furthermore, with :global(), svelte will remove all injected .svelte-xxxxxx hash, compressing the CSS footprint to the very fine edge.

Despite turning everything global, during compile time all pre-transformed classnames are additionally hashed by filename, therefore no additional hash is needed in the classname.

This test verifies the scoping implementation.

Are global CSS lazy-loaded?

Yes they are lazy-loaded by default. Declarations that are found in both components and __layout.svelte will be hoisted to it, or else it will be kept in its own stylesheet. Therefore the lazy-loaded feature of Svelte is preserved.

However, you may observe a greater reduction in CSS size by serving all of them in __layout.svelte with opts.lazyLoad

Will this affect all my CSS?

This preprocessor will only affect all CSS defined inline inside svelte-component.

All unrelated rules will be kept untouched.

Installation

npm install glory-svelte-preprocess

Options

gloryPreprocess takes an object of options.

opts.lazyLoad(default to true)

Setting this to false will generate all classes in __layout.svelte

Usage

Just import this preprocessor in your svelte.config.js

import gloryPreprocess from "glory-svelte-preprocess";
import preprocess from "svelte-preprocess";

const config = {
  preprocess: [gloryPreprocess(), preprocess()],

  kit: {
    target: "#svelte",
    adapter: adapter(),
  },
};

export default config;

If you are using any preprocessor(e.g. ScSS, PostCSS) that works with non-standard CSS syntax, set up the preprocess with a wrapper.

Related project

glory

The world fastest framework agonistic CSS-in-JS library.

About

A svelte preprocess for safely minimizing CSS class footprint for unbeliveable performance gain. 🚀 🚀 🚀

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published