Public commit
This commit is contained in:
92
scripts/plugins/esbuild-css-modules.ts
Normal file
92
scripts/plugins/esbuild-css-modules.ts
Normal file
@ -0,0 +1,92 @@
|
||||
import { relative, resolve } from "path"
|
||||
import { promises as fs } from "fs"
|
||||
import type { Plugin } from "esbuild"
|
||||
import postcss from "postcss"
|
||||
// @ts-expect-error
|
||||
import postcssSass from "@csstools/postcss-sass"
|
||||
import cssModules from "postcss-modules"
|
||||
|
||||
type Options = Parameters<typeof cssModules>[0]
|
||||
|
||||
const PLUGIN_NAME = "esbuild-css-modules"
|
||||
|
||||
async function buildCSSModule(cssFullPath: string, options: Options) {
|
||||
options = {
|
||||
localsConvention: "camelCaseOnly",
|
||||
...options,
|
||||
}
|
||||
const source = await fs.readFile(cssFullPath)
|
||||
|
||||
let classNames = {}
|
||||
const { css } = await postcss([
|
||||
postcssSass(),
|
||||
cssModules({
|
||||
getJSON(_, json) {
|
||||
classNames = json
|
||||
return classNames
|
||||
},
|
||||
...options,
|
||||
}),
|
||||
]).process(source, {
|
||||
from: cssFullPath,
|
||||
map: false,
|
||||
})
|
||||
|
||||
return {
|
||||
css,
|
||||
classNames,
|
||||
}
|
||||
}
|
||||
|
||||
const srcDir = resolve(__dirname, "../../src")
|
||||
|
||||
const plugin = (options: Options = {}): Plugin => ({
|
||||
name: PLUGIN_NAME,
|
||||
async setup(build) {
|
||||
const memfs = new Map<string, string>()
|
||||
const FS_NAMESPACE = PLUGIN_NAME + "-fs"
|
||||
|
||||
build.onResolve({ filter: /\.modules?\.s?css$/, namespace: "file" }, async args => {
|
||||
const res = await build.resolve(args.path, {
|
||||
kind: "import-statement",
|
||||
resolveDir: args.resolveDir,
|
||||
})
|
||||
|
||||
// This is just the unique ID for this CSS module. We use a relative path to make it easier to debug.
|
||||
const path = relative(srcDir, res.path)
|
||||
|
||||
return {
|
||||
path,
|
||||
namespace: PLUGIN_NAME,
|
||||
pluginData: {
|
||||
realPath: res.path,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
build.onResolve({ filter: /^@css-modules\/.*/ }, ({ path }) => ({
|
||||
path,
|
||||
namespace: FS_NAMESPACE,
|
||||
}))
|
||||
|
||||
build.onLoad({ filter: /./, namespace: FS_NAMESPACE }, ({ path }) => ({
|
||||
contents: memfs.get(path)!,
|
||||
loader: "css",
|
||||
}))
|
||||
|
||||
build.onLoad({ filter: /./, namespace: PLUGIN_NAME }, async args => {
|
||||
const tmpFilePath = "@css-modules/" + args.path
|
||||
const { classNames, css } = await buildCSSModule(args.pluginData.realPath, options)
|
||||
memfs.set(tmpFilePath, css)
|
||||
|
||||
return {
|
||||
contents:
|
||||
`import ${JSON.stringify(tmpFilePath)};\n` +
|
||||
`module.exports = ${JSON.stringify(classNames)};`,
|
||||
loader: "js",
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export { plugin as cssModules }
|
Reference in New Issue
Block a user