Home

Awesome

css-media-splitter

<p align="center"> <img src="./assets/css-media-splitter.png" alt="css-media-splitter logo" height="200"> </p>

The tool extracts all @media at-rules into dedicated files and download them only when the user device matches the media query.

This technique is the most valuable for mobile-first applications. It reduces the size of the CSS downloaded and increases the coverage ratio, so makes page loading faster and prevents a "Reduce unused CSS code" issue in the Lighthouse report.

The package exposes:

Your favorite framework is not supported yet? - please refer to CONTRIBUTION.md.

How it works

The tool is modifying the application by transforming HTML and CSS files. It was developed to be used on the final bundle after any build process was finished.

The algorithm:

  1. run through all CSS source files and extract all @media at-rules.
  2. remove all @media at-rules from CSS source files.
  3. write dedicated media files with all CSS rules grouped under one @media at-rule.
  4. generate manifest with relations between source files and media files.
  5. include the loader into all HTML files.

source file in scope of this tool equals to a compiled CSS or HTML file from your final bundle. Please, don't confuse with the file you actually work with.

Usage

Install the package

npm i -D css-media-splitter
yarn add -D css-media-splitter
pnpm add -D css-media-splitter

Plain app

import processCssMediaSplitter from "css-media-splitter/plain"

const result = await processCssMediaSplitter({ distDir: "dist" })

Use result which contain manifest, loader and report depending on the project setup.

Example could be found in playground.

Vite

// vite.config.ts
import { defineConfig } from "vite"
import VitePluginCssMediaSplitter from "css-media-splitter/vite-plugin"

export default defineConfig({
  plugins: [
    VitePluginCssMediaSplitter(),
  ],
})

Examples could be found for:

Nuxt

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ["css-media-splitter/nuxt-module"],
})

Example could be found in playground

Options

distDir

Available in: plain

Path to dist folder. Should be an absolute fs path or the folder name relative to the root folder.

In vite-plugin and nuxt-module is set based on vite/nuxt config respectively.

mediaFileMinSize

Available in: plain, vite-plugin, nuxt-module

Use this option to define how large media file content should be, so it will be extract into a dedicated file.

This option is useful when media file content is small and it will take more space in the loader manifest than having it in the CSS source file.

By default equals to 100 (experimentally calculated, not recommended to set a smaller size).

In Vite project: vite.config.ts

{
  plugins: [ VitePluginCssMediaSplitter({ mediaFileMinSize: 250 }) ],
}

In Nuxt project: nuxt.config.ts

{
  modules: [ ["css-media-splitter/nuxt-module", { mediaFileMinSize: 250 }] ],
}

Internals

Loader

By default, the loader will be included before the first link/style/script with the src path ends with .css or .js extension.

In some scenarios it is not relevant, then you can put comment <!-- css-media-splitter:loader --> in place before any link/style/script is defined and the comment will be replaced automatically.

Example in vue-ssr playground - comment on line 7.

When the comment is not the case too, the loader can be inserted programmatically using functions from css-media-splitter/api.

Example in nuxt-module - nuxt.hook "close" on line 42.

Credits