Lädt...

🔧 Stylify CSS: Automagic CSS bundles splitting into CSS layers in Astro.build


Nachrichtenbereich: 🔧 Programmierung
🔗 Quelle: dev.to

Utility first CSS bundles can be very small. But what if, we could make them even smaller? Split them for each page/layout for example? Some pages might not need styles from another one. Learn how to split CSS bundles in Astro.build automatically using Stylify CSS.

Video Guide

Stylify CSS introduction

Stylify is a library that uses CSS-like selectors to generate optimized utility-first CSS based on what you write.

  • ✨ CSS-like selectors
  • 💎 No framework to study
  • 💡 Less time spent in docs
  • 🧰 Mangled & Extremely small CSS
  • 🤘 No purge needed
  • 🚀 Components, Variables, Custom selectors
  • 📦 It can generate multiple CSS bundles

Also we have a page about what problems Stylify CSS solves and why you should give it a try!

Motivation

Each bundle can contain only necessary CSS. This means almost zero unused CSS and in production, it can be mangled and minified, so the CSS is even smaller (more info below).
Stylify example

The code

Ok, first the code, then the explanation. This code uses Stylify Astro Integration and the snippet can be found on Stylify Astro Snippets section. Even though the code can look complicated, it is actually pretty simple:

import stylify from '@stylify/astro';
import { hooks } from '@stylify/bundler';
import fastGlob from 'fast-glob';
import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';

const pagesDir = 'src/pages';
const layoutsDir = 'src/layouts';
const stylesDir = 'src/styles';

/** @type { import('@stylify/bundler').BundlerConfigInterface[]} */
const stylifyBundles = [];
const layoutCssLayerName = 'layout';
const pageCssLayerName = 'page';

const getFileCssLayerName = (filePath) =>
  filePath.includes('/pages/') ? pageCssLayerName : layoutCssLayerName;

const getOutputFileName = (file) => {
  const parsedFile = path.parse(file);
  const fileName = parsedFile.name.toLowerCase();
  const dirNameCleanupRegExp = new RegExp(`${pagesDir}|${layoutsDir}|\\W`, 'g');
  const dir = parsedFile.dir.replace(dirNameCleanupRegExp, '');
  return `${dir.length ? `${dir}-` : ''}${fileName}.css`;
};

const createBundle = (file) => {
  const fileCssLayerName = getFileCssLayerName(file);

  return {
    outputFile: `${stylesDir}/${fileCssLayerName}/${getOutputFileName(file)}`,
    files: [file],
    cssLayer: fileCssLayerName,
  };
};

const createBundles = (files) => {
  for (const file of files) {
    stylifyBundles.push(createBundle(file));
  }
};

// 1. Map files in layouts/pages and create bundles
createBundles(fastGlob.sync(`${pagesDir}/**/*.astro`));
createBundles(fastGlob.sync(`${layoutsDir}/**/*.astro`));

// 2. Init Stylify Astro Integraton
const stylifyIntegration = stylify({
  bundler: {
    id: 'astro',
    // Set CSS @layers order
    cssLayersOrder: {
      // Order will be @layer layout,page;
      order: [layoutCssLayerName, pageCssLayerName].join(','),
      // Layers order will be exported into file with layout @layer
      exportLayer: [layoutCssLayerName],
    },
  },
  bundles: stylifyBundles,
});

// 3. Add hook that processes opened files
/** @param { import('@stylify/bundler').BundleFileDataInterface } data */
hooks.addListener('bundler:fileToProcessOpened', (data) => {
  let { content, filePath } = data;

  // 3.1 Only for layout and page files
  if (filePath.includes('/pages/') || filePath.includes('/layouts/')) {
    const cssFilePathImport = `import '/${stylesDir}/${getFileCssLayerName(
      filePath
    )}/${getOutputFileName(filePath)}';`;

    if (!content.includes(cssFilePathImport)) {
      if (/import \S+ from (?:'|")\S+(\/layouts\/\S+)(?:'|");/.test(content)) {
        content = content.replace(
          /import \S+ from (?:'|")\S+\/layouts\/\S+(?:'|");/,
          `$&\n${cssFilePathImport}`
        );
      } else if (/^\s*---\n/.test(content)) {
        content = content.replace(/^(\s*)---\n/, `$&${cssFilePathImport}\n`);
      } else {
        content = `---\n${cssFilePathImport}\n---\n${content}`;
      }

      fs.writeFileSync(filePath, content);
    }
  }

  // 3.2 For all files
  const regExp = new RegExp(
    `import \\S+ from (?:'|")\\S+(\\/components\\/\\S+)(?:'|");`,
    'g'
  );
  let importedComponent;
  const importedComponentFiles = [];
  const rootDir = path.dirname(fileURLToPath(import.meta.url));

  while ((importedComponent = regExp.exec(content))) {
    importedComponentFiles.push(
      path.join(rootDir, 'src', importedComponent[1])
    );
  }

  data.contentOptions.files = importedComponentFiles;
});

// 4. Wait for bundler to initialize and watch for directories
// to create new bundles when a file is added
hooks.addListener('bundler:initialized', ({ bundler }) => {
  // Watch layouts and pages directories
  // If you plan to use nested directories like blog/_slug.astro
  // for which you want to automatize bundles configuration
  // You will need to add the path to them here
  const dirsToWatchForNewBundles = [layoutsDir, pagesDir];
  for (const dir of dirsToWatchForNewBundles) {
    fs.watch(dir, (eventType, fileName) => {
      const fileFullPath = path.join(dir, fileName);

      if (eventType !== 'rename' || !fs.existsSync(fileFullPath)) {
        return;
      }

      bundler.bundle([createBundle(fileFullPath)]);
    });
  }
});

export default {
  // 5. Add Stylify Astro Integration
  integrations: [stylifyIntegration]
};

How it works

The code above is split into 5 steps:

  1. It finds all pages in src/pages and all layouts in src/layouts and calls the createBundles to create bundles configuration for us with the correct layer name and output file.
  2. The Stylify integration is initialized and CSS layers order is configured so it will generate the order only into a file, that has the layout CSS layer name.
  3. bundler:fileToProcessOpened hook is added. This hook has two parts. One part is done, when this file is a layout or a page and the another for every opened file.
    • When a layout or a page file is opened, it checks, whether it contains a path to CSS file and if not, it adds it to the head of the file.
    • For all other files, it tries to check for imports. If any component import is found, it maps it as a dependency. This way it can map a whole components dependency tree automatically so you just keep adding/removing them and the CSS is generated correctly
  4. When Bundler is initialized we can start watching for newly added files within the layout and pages directory. Every time a new file is added, we create a new Bundle.
  5. The Stylify Integration is added to the Astro config.

When we run the dev command, Stylify will do the following:

  1. Map layout/page files
  2. Generate CSS into correct files, wrap the content into the correct CSS layer and adds links to these files into Astro templates.
  3. If a new file in layout/pages is created a new bundle is automatically added

And how does the output looks for production?
Layout (src/layouts/Layout.astro):

@layer layout,page;
@layer layout {.b{font-size:16px}}

Page (src/pages/index.astro):

@layer page {.a{color:darkblue}}

Integration example

Check out the interactive example on Stack Blitz.

Configuration

The examples above don't include everything Stylify can do:

Feel free to check out the docs to learn more 💎.

Let me know what you think!

I will be happy for any feedback! The Stylify is still a new Library and there is a lot of space for improvement 🙂.

...

🔧 Stylify CSS: Automagic CSS bundles splitting into CSS layers in Astro.build


📈 138.39 Punkte
🔧 Programmierung

🔧 Stylify CSS: Code your Remix website faster with CSS-like utilities


📈 38.34 Punkte
🔧 Programmierung

🔧 Stylify CSS: Code your Laravel website faster with CSS-like utilities


📈 38.34 Punkte
🔧 Programmierung

🔧 Stylify CSS: Code your SvelteKit website faster with CSS-like utilities


📈 38.34 Punkte
🔧 Programmierung

🔧 Using Beautiful Material Themes from Material Theme Builder in Stylify CSS


📈 33.82 Punkte
🔧 Programmierung

📰 Automagic wird eingestampft


📈 32.65 Punkte
📰 IT Nachrichten

🎥 DEF CON 27 AI Village - Jon Hawes - A buyers guide to the market promise of automagic AI


📈 32.65 Punkte
🎥 IT Security Video

🔧 Exploring Astro: A Journey into Modern Web Development with Astro JS


📈 30.09 Punkte
🔧 Programmierung

🔧 I Learned the Astro Framework in 3 Hours: A Journey from Next.js to Astro with TailwindCSS V4 🚀


📈 25.03 Punkte
🔧 Programmierung

🔧 Astro vs Gatsby: Is Astro becoming a replacement for Gatsby?


📈 25.03 Punkte
🔧 Programmierung

🔧 Password Authentication with Auth.js in Astro and Customizing Session Information (auth-astro)


📈 25.03 Punkte
🔧 Programmierung

📰 Amazon Discontinues Astro for Business Robot Security Guard To Focus on Astro Home Robot


📈 25.03 Punkte
📰 IT Security Nachrichten

🔧 Astro and Express: SSR in Astro


📈 25.03 Punkte
🔧 Programmierung

🔧 How to add Astro social share to your Astro application


📈 25.03 Punkte
🔧 Programmierung

🪟 Add a splash of color to your Astro headset with ASTRO.ID


📈 25.03 Punkte
🪟 Windows Tipps

📰 Sony PlayStation 5: Vergünstigte Bundles mit „Astro Bot“ sind ab sofort erhältlich


📈 24.36 Punkte
📰 IT Nachrichten

🎥 App Bundles: Testing bundles with bundletool and the Play Console - MAD Skills


📈 23.68 Punkte
🎥 Video | Youtube

🎥 App Bundles: Benefits of Android App Bundles - MAD Skills


📈 23.68 Punkte
🎥 Video | Youtube

🔧 How to upgrade an Astro JS project from Tailwind CSS v3 to Tailwind CSS v4 ( Alpha )


📈 21.55 Punkte
🔧 Programmierung

🔧 Build a Sleek, Fast, and SEO-Optimized Developer Portfolio with Astro and Tailwind CSS


📈 21.52 Punkte
🔧 Programmierung

🐧 The Open Build Service now supports building Flatpak bundles, so you can build your own!


📈 20.81 Punkte
🐧 Linux Tipps

🔧 #143 — Expand One Row into Multiple Rows after Splitting Text


📈 20.04 Punkte
🔧 Programmierung

🔧 Why Feature Scaling Should Be Done After Splitting Your Dataset into Training and Test Sets


📈 20.04 Punkte
🔧 Programmierung

🔧 Splitting the Difference: My Journey into Ergonomic Keyboards and Pain-Free Productivity


📈 20.04 Punkte
🔧 Programmierung

🐧 Embracer Group splitting into three companies


📈 20.04 Punkte
🐧 Linux Tipps

📰 Gaming Giant Embracer Group Is Splitting Into Three Companies


📈 20.04 Punkte
📰 IT Security Nachrichten

📰 Linux Mint Devs Work on Splitting Cinnamon into Multiple Processes, Improvements


📈 20.04 Punkte
📰 IT Security Nachrichten

📰 Investor Tim Draper Pushes Ballot Measure Splitting California Into 3 States


📈 20.04 Punkte
📰 IT Security Nachrichten

📰 New Catalyst Is Better At Splitting Water Into Hydrogen And Oxygen


📈 20.04 Punkte
📰 IT Security Nachrichten

matomo