UNPKG

@unocss/nuxt

Version:

Nuxt module for UnoCSS

173 lines (167 loc) 6.19 kB
import { dirname, resolve } from 'node:path'; import process from 'node:process'; import { fileURLToPath } from 'node:url'; import { defineNuxtModule, addPluginTemplate, isNuxt2, addComponentsDir, addTemplate, findPath, isNuxt3, extendViteConfig, extendWebpackConfig } from '@nuxt/kit'; import { createRecoveryConfigLoader } from '@unocss/config'; import { cssIdRE } from '@unocss/core'; import presetAttributify from '@unocss/preset-attributify'; import presetIcons from '@unocss/preset-icons'; import presetTagify from '@unocss/preset-tagify'; import presetTypography from '@unocss/preset-typography'; import presetWebFonts from '@unocss/preset-web-fonts'; import presetWind3 from '@unocss/preset-wind3'; import presetWind4 from '@unocss/preset-wind4'; const defaultPipelineExclude = [cssIdRE]; async function resolveOptions(options) { if (options.wind3 && options.wind4) { console.warn("[unocss/nuxt]: wind3 and wind4 presets are mutually exclusive. wind3 will be disabled in favor of wind4."); options.wind3 = false; } if (options.presets == null) { options.presets = []; const presetMap = { wind3: presetWind3, wind4: presetWind4, attributify: presetAttributify, icons: presetIcons, webFonts: presetWebFonts, typography: presetTypography, tagify: presetTagify }; for (const [key, preset] of Object.entries(presetMap)) { const option = options[key]; if (option) { options.presets.push(preset(typeof option === "boolean" ? {} : option)); } } } options.content ??= {}; options.content.pipeline ??= {}; if (options.content.pipeline !== false) { options.content.pipeline.exclude ??= defaultPipelineExclude; if (Array.isArray(options.content.pipeline.exclude)) options.content.pipeline.exclude.push(/\?macro=true/); } } const dir = dirname(fileURLToPath(import.meta.url)); const index = defineNuxtModule({ meta: { name: "unocss", configKey: "unocss" }, defaults: { mode: "global", autoImport: true, preflight: false, components: true, disableNuxtInlineStyle: true, nuxtLayers: false, // presets attributify: false, webFonts: false, icons: false, wind3: true, wind4: false }, async setup(options, nuxt) { resolveOptions(options); const loadConfig = createRecoveryConfigLoader(); options.mode ??= "global"; const InjectModes = ["global", "dist-chunk"]; if (options.disableNuxtInlineStyle) { nuxt.options.features ||= {}; nuxt.options.features.inlineStyles = false; } if (options.injectPosition != null) console.warn("[unocss/nuxt] options `injectPosition` is temporary removed due to the incompatibility with Nuxt 3.9. We are seeking for better solution. It's not effective at this moment."); if (options.autoImport) { addPluginTemplate({ filename: "unocss.mjs", getContents: () => { const lines = [ InjectModes.includes(options.mode) ? "import 'uno.css'" : "", isNuxt2() ? "export default () => {}" : "import { defineNuxtPlugin } from '#imports'; export default defineNuxtPlugin(() => {})" ]; if (options.preflight) lines.unshift("import '@unocss/reset/tailwind.css'"); return lines.join("\n"); } }); } if (options.components) { addComponentsDir({ path: resolve(dir, "../runtime"), watch: false }); } if (options.nuxtLayers) { addTemplate({ filename: "uno.config.mjs", async getContents() { const configPaths = (await Promise.all(nuxt.options._layers.slice(1).map( (layer) => findPath(options.configFile || ["uno.config", "unocss.config"], { cwd: layer.config.rootDir }) ))).filter(Boolean).reverse(); return `import { mergeConfigs } from '@unocss/core' ${configPaths.map((path, index) => `import cfg${index} from '${path}'`.trimStart()).join("\n").trimEnd()} export default mergeConfigs([${configPaths.map((_, index) => `cfg${index}`).join(", ")}]) `; }, write: true }); } nuxt.hook("build:before", async () => { const { config: unoConfig } = await loadConfig( process.cwd(), { configFile: options.configFile }, [], options ); if (isNuxt3() && nuxt.options.builder === "@nuxt/vite-builder" && nuxt.options.postcss.plugins.cssnano && unoConfig.transformers?.some((t) => t.name === "@unocss/transformer-directives" && t.enforce !== "pre")) { const preset = nuxt.options.postcss.plugins.cssnano.preset; nuxt.options.postcss.plugins.cssnano = { preset: [preset?.[0] || "default", Object.assign( // Following optimizations result in invalid CSS if the directives not transformed yet { mergeRules: false, normalizeWhitespace: false, discardComments: false }, preset?.[1] )] }; } await nuxt.callHook("unocss:config", unoConfig); extendViteConfig(async (config) => { const { default: VitePlugin } = await import('@unocss/vite'); config.plugins = config.plugins || []; config.plugins.unshift(...VitePlugin({ mode: options.mode }, unoConfig)); }); extendWebpackConfig(async (config) => { const { default: WebpackPlugin } = await import('@unocss/webpack'); config.plugins = config.plugins || []; config.plugins.unshift(WebpackPlugin({}, unoConfig)); }); }); if (nuxt.options.dev) { nuxt.hook("devtools:customTabs", (tabs) => { tabs.push({ title: "UnoCSS", name: "unocss", icon: "/__unocss/favicon.svg", view: { type: "iframe", src: "/__unocss/" } }); }); } if (isNuxt2()) { nuxt.hook("app:resolve", (config) => { const plugin = { src: "unocss.mjs", mode: "client" }; if (config.plugins) config.plugins.push(plugin); else config.plugins = [plugin]; }); } } }); export { index as default };