Skip to content

Instantly share code, notes, and snippets.

@hyrious
Created August 3, 2025 14:58
Show Gist options
  • Save hyrious/942d6bf606a7b5494ef205bd393f72e1 to your computer and use it in GitHub Desktop.
Save hyrious/942d6bf606a7b5494ef205bd393f72e1 to your computer and use it in GitHub Desktop.
Simple esbuild plugin to bundle ".module.scss" files.
import { Plugin } from 'esbuild'
import { default as Postcss } from 'postcss'
import { default as PostcssModulesPlugin } from 'postcss-modules'
import { compile, Options } from 'sass'
export type CSSModulesOptions = Parameters<typeof PostcssModulesPlugin>[0]
export interface CSSOptions {
/// https://github.com/css-modules/postcss-modules
modules?: CSSModulesOptions
/// https://sass-lang.com/documentation/js-api/interfaces/options
scss?: Options<'sync'>
/// https://sass-lang.com/documentation/js-api/interfaces/options
sass?: Options<'sync'>
}
export function css(options: CSSOptions = {}): Plugin {
const NAME = 'module-sass'
return {
name: NAME,
setup(build) {
const cache = new Map<string, string>()
build.onLoad({ filter: /\.module.(sass|scss)$/ }, async args => {
if (args.with[NAME]) {
const css = cache.get(args.path)!
cache.delete(args.path)
return { contents: css, loader: 'css' }
}
const stage1 = compile(args.path, args.path.endsWith('.scss') ? options.scss : options.sass)
let module!: object
const stage2 = await Postcss(PostcssModulesPlugin({
...options.modules,
getJSON(cssFileName, json, outputFileName) {
module = json
if (options.modules && typeof options.modules.getJSON == 'function') {
options.modules.getJSON(cssFileName, json, outputFileName)
}
}
})).process(stage1.css, { from: args.path, to: args.path })
cache.set(args.path, stage2.css)
const js = [
`import ${JSON.stringify(args.path)} with ${JSON.stringify({ [NAME]: "1" })}`,
`export default ${JSON.stringify(module)}`,
].join('\n')
return { contents: js }
})
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment