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:
-
[X] Type Selector
h1
-
[X] Id Selector
#foo
-
[X] Class Selector
.foo
-
[X] Attribute Selector
li[title]
-
[X] Descendant combinator
.foo .bar
-
[X] Child combinator
.foo>.bar
-
[X] Adjacent sibling combinator
.foo+.bar
-
[X] General sibling combinator
.foo~.bar
-
[X] Pseudo class
.foo:hover
-
[X] Pseudo selector
.foo::before
-
[X]
:not()
selectora:not(.hello)
Known limitations
This preprocess currently doesn't handle the following selectors:
- multiple pseudo selectors (e.g.
.foo:active .bar:hover
)
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
The world fastest framework agonistic CSS-in-JS library.