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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@aemvite/vite-plugin-aem-css-url-passthrough

v0.7.0

Published

Vite plugin that rewrites CSS url() references in built clientlib stylesheets back to ../resources/<sub>/<file> form, mirroring webpack css-loader { url: false } for AEM clientlibs.

Readme

@aemvite/vite-plugin-aem-css-url-passthrough

Vite plugin that rewrites CSS url(...) references in built AEM clientlib stylesheets back to the canonical ../resources/<sub>/<file> form. Drop-in replacement for webpack's css-loader: { url: false } in AEM clientlib builds.

Part of the @aemvite/* toolchain.

Install

npm i -D @aemvite/vite-plugin-aem-css-url-passthrough
  • Peer dependency: vite ^8
  • Engines: Node ^20.19.0 || ^22.18.0 || >=24.11.0
  • No runtime dependencies — uses only Node's built-in node:fs and node:path.

What it does

AEM clientlibs serve CSS at <clientlib>/css/<name>.css and static assets at <clientlib>/resources/<sub>/<file>. SCSS authors typically write url("../resources/images/foo.svg") relative to the final clientlib layout. The webpack stack preserved those literals via css-loader: { url: false }, but Vite/Rolldown by default rewrites url() relative to the source SCSS file, producing paths like ../../components/header/resources/images/foo.svg that 404 against the deployed clientlib.

This plugin runs at writeBundle, scans every emitted .css file in the build output directory, and rewrites every url(...) whose body contains resources/<configured-sub>/ to the canonical ../resources/<sub>/<rest> form. Other URLs are left untouched.

writeBundle is used (not generateBundle) because Vite's lib-mode CSS extraction emits the .css outside the Rollup chunk map.

Usage

Direct (any Vite project)

// vite.config.ts
import { defineConfig } from "vite";
import { aemCssUrlPassthrough } from "@aemvite/vite-plugin-aem-css-url-passthrough";

export default defineConfig({
  plugins: [
    aemCssUrlPassthrough({
      // Optional; defaults to ["images", "fonts"].
      resourceDirs: ["images", "fonts", "icons", "storybook-assets"],
    }),
  ],
});

Through @aemvite/aem-config (recommended)

Set the cssUrlPassthrough flag in your aem.config.{ts,mjs} and the plugin is auto-wired into every clientlib build:

import { defineAemConfig } from "@aemvite/aem-config";

export default defineAemConfig({
  clientLibRoot: "../ui.apps/.../clientlibs",
  cssUrlPassthrough: true, // or: { resourceDirs: ["images", "fonts", "icons"] }
  clientlibs: [
    /* ... */
  ],
});

The same field is available per-clientlib and takes precedence over the global value.

API reference

Plugin

| Export | Signature | Notes | |---|---|---| | aemCssUrlPassthrough | (options?: AemCssUrlPassthroughOptions) => Plugin | Vite plugin (also the package default export). apply: "build", runs at writeBundle. |

Types

interface AemCssUrlPassthroughOptions {
  /** Default: ["images", "fonts"]. */
  resourceDirs?: readonly string[];
}

Behavior

  • Only .css files in the build output directory are scanned. No URL rewriting touches the bundled JavaScript or any nested subdirectory.
  • Only url(...)s whose body contains resources/<configured-sub>/ are rewritten. The rewritten URL becomes ../resources/<sub>/<rest>.
  • Data URIs, absolute http(s):// URLs, and protocol-relative //host URLs are skipped. External CDN references are never touched.
  • Idempotent. A url() already in canonical form (url(../resources/...)) is matched and rewritten to the identical string.
  • Sync content only. The plugin runs once per build, after Rollup writes the bundle, and rewrites in place.

Notes & caveats

  • The plugin only walks the top level of the build output directory. AEM clientlib builds emit a single flat <name>.css per clientlib, so this is by design.
  • Configure every resources/<sub>/ bucket your stylesheets reference. If a url() goes through a directory you didn't list, it will be left as-is and will likely 404 against the AEM clientlib.

License

MIT © Luca Nerlich

Repository

https://github.com/LucaNerlich/aem-vite (this package lives in packages/vite-plugin-aem-css-url-passthrough).