CSS Issues
CSS processing and styling problems
CSS Issues
Packem processes CSS through @visulima/rollup-plugin-css, configured under the rollup.css key. This page covers the most common CSS problems: styles not extracting or injecting, PostCSS configuration, and CSS Modules.
CSS not extracted or injected
Problem
You import a CSS file but nothing ends up in the output, or it lands inline when you expected a separate .css file (or vice versa).
Cause
The CSS plugin's mode controls where processed CSS goes, and the default is "inject" — CSS is embedded inside the JS bundle and injected into <head> at runtime. The available modes are:
"inject"(default) — embeds CSS inside JS and injects it into<head>at runtime."extract"— extracts CSS to the same location as the JS file but with a.cssextension."emit"— emits pure processed CSS and passes it along the build pipeline for other plugins.
If you expected a standalone stylesheet but never set mode, you got the default injection behavior instead.
Solution
Set the mode explicitly under rollup.css:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
transformer,
rollup: {
css: {
mode: 'extract'
}
}
})If CSS still does not show up at all, confirm the basics:
- The CSS file is actually imported from your JS/TS entry (
import './styles.css'). - The import path is correct.
- CSS processing is not disabled (
rollup.cssis not set tofalse).
PostCSS config not applied
Problem
Your PostCSS plugins (autoprefixer, cssnano, Tailwind) do not run.
Cause
Packem reads PostCSS configuration either from a standalone postcss.config.js (via postcss-load-config) or from the loaders you register on rollup.css. PostCSS support also requires its dependencies to be installed — they are not bundled by default.
Solution
Install the PostCSS toolchain:
npm install --save-dev postcss postcss-load-config postcss-modules \
postcss-modules-extract-imports postcss-modules-local-by-default \
postcss-modules-scope postcss-modules-values postcss-value-parser icss-utilsRegister the PostCSS loader in packem.config.ts:
import { defineConfig } from '@visulima/packem/config'
import postcssLoader from '@visulima/packem/css/loader/postcss'
import sourceMapLoader from '@visulima/packem/css/loader/sourcemap'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
transformer,
rollup: {
css: {
loaders: [postcssLoader, sourceMapLoader]
}
}
})A standalone postcss.config.js is picked up automatically:
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer'),
require('cssnano')({ preset: 'default' })
]
}Preprocessor errors (Sass, Less, Stylus)
Problem
Importing .scss, .less, or .styl throws or produces no output.
Cause
Preprocessor support is opt-in: the preprocessor package must be installed, and its loader must be registered on rollup.css. Without the loader, the file is treated as plain CSS.
Solution
Install the preprocessor and register its loader. For example, Less:
npm install --save-dev lessimport { defineConfig } from '@visulima/packem/config'
import lessLoader from '@visulima/packem/css/loader/less'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
transformer,
rollup: {
css: {
mode: 'extract',
loaders: [lessLoader]
}
}
})For Sass, sass-embedded is recommended (sass and node-sass also work).
CSS Modules not scoping
Problem
Class names from a CSS Modules file come through unhashed, or import styles from './x.module.css' returns an empty object.
Cause
CSS Modules in Packem are driven by the autoModules option, which scopes files named [name].module.[ext] (for example foo.module.css, bar.module.stylus). If autoModules is off, or the file is not named with the .module. infix, it is processed as a normal global stylesheet.
Solution
Enable autoModules and use the .module. naming convention:
import { defineConfig } from '@visulima/packem/config'
import transformer from '@visulima/packem/transformer/esbuild'
export default defineConfig({
transformer,
rollup: {
css: {
mode: 'extract',
autoModules: true
}
}
})// src/Button.ts
import styles from './Button.module.css'
button.className = styles.buttonThe .module. infix is required for autoModules to kick in. A file named Button.css is global even with autoModules: true; rename it to Button.module.css.