Skip to content

Instantly share code, notes, and snippets.

@Grawl
Last active May 3, 2025 04:39
Show Gist options
  • Save Grawl/3ae35d9e7a250d1dcf3b8fd5583f2b2b to your computer and use it in GitHub Desktop.
Save Grawl/3ae35d9e7a250d1dcf3b8fd5583f2b2b to your computer and use it in GitHub Desktop.
unplugin-mantine-autoload-css
import { readdirSync } from 'node:fs'
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tsconfigPaths from 'vite-tsconfig-paths'
import { createVitePlugin, type UnpluginFactory } from 'unplugin'
const pattern = new RegExp(/import\s*{([\n\s\w,]+)}\s*from\s*['"]@mantine\/core['"]/gm)
const mantineCoreStylesDirectory = '@mantine/core/styles'
// https://mantine.dev/styles/css-files-list/#components-dependencies
// shared subcomponents dependencies are not detected by this module
// so we load them all
// all these files are ~30KB combined VS more than 200 KB of all Mantine styles combined
const shared = [
'ScrollArea',
'UnstyledButton',
'VisuallyHidden',
'Paper',
'Popover',
'CloseButton',
'Group',
'Loader',
'Overlay',
'ModalBase',
'Input',
'InlineInput',
'Flex',
'FloatingIndicator',
'ActionIcon',
]
const mantineAutoloadCSSFactory: UnpluginFactory<{ layer: boolean } | undefined> = (
{ layer } = { layer: true },
) => {
const selectVariant = (name: string): string => [name, layer ? '.layer.css' : '.css'].join('')
const cssFileNames = readdirSync(`node_modules/${mantineCoreStylesDirectory}`)
return {
name: 'unplugin-mantine-autoload-css',
transformInclude: (id) => id.endsWith('.ts') || id.endsWith('.tsx'),
transform: (code) => {
const match = pattern.exec(code)
if (match === null) return code
const [, group] = match
if (group === undefined) return code
const maybeComponents = group.split(',').map((string) => {
const [renamed] = string.split(' as ')
if (renamed === undefined) return string.trim()
return renamed.trim()
})
const stylesToAdd = cssFileNames
.filter((fileName) =>
maybeComponents.find((maybeComponent) => fileName.startsWith(maybeComponent)),
)
.filter((fileName) => {
const isLayer = fileName.endsWith('.layer.css')
return layer ? isLayer : !isLayer
})
if (stylesToAdd.length > 0) {
// add global styles and all variants
const files = [selectVariant('global'), ...shared.map(selectVariant), ...stylesToAdd]
return [
...files.map((fileName) => `import '${mantineCoreStylesDirectory}/${fileName}'`),
code,
].join('\n')
}
return code
},
}
}
const mantineAutoloadCSS = createVitePlugin(mantineAutoloadCSSFactory)
export default defineConfig({
plugins: [react(), tsconfigPaths(), mantineAutoloadCSS()],
})
@Grawl
Copy link
Author

Grawl commented Apr 23, 2025

TODO: use unplugin AST to get rid of const shared and look into dependency tree to see internal imports

@Grawl
Copy link
Author

Grawl commented May 3, 2025

added support for renamed imports like import { Pagination as MantinePagination } from '@mantine/core'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment