diff --git a/packages/vite-plugin/dist/index.js b/packages/vite-plugin/dist/index.js index 43bb900..ce4b34d 100644 --- a/packages/vite-plugin/dist/index.js +++ b/packages/vite-plugin/dist/index.js @@ -1317,7 +1317,7 @@ if (typeof window !== 'undefined') { * Vite 插件:自动转换 .uvue 文件中的 Tailwind 类名为安全字符 * 并自动注入 rem 转 rpx 的 PostCSS 插件 */ - function tailwindTransformPlugin() { + function tailwindPlugin() { return { name: "vite-cool-uniappx-tailwind", enforce: "pre", @@ -1364,18 +1364,32 @@ if (typeof window !== 'undefined') { }, }; } + + function codePlugin() { + return { + name: "vite-cool-uniappx-code", + transform(code, id) { + if (id.endsWith(".json")) { + return code.replace("new UTSJSONObject", ""); + } + }, + }; + } + /** * uniappX 入口,自动注入 Tailwind 类名转换插件 * @param options 配置项 * @returns Vite 插件数组 */ function uniappX() { + const plugins = []; if (config.type == "uniapp-x") { + plugins.push(codePlugin()); if (config.tailwind.enable) { - return [tailwindTransformPlugin()]; + plugins.push(tailwindPlugin()); } } - return []; + return plugins; } function cool(options) { diff --git a/packages/vite-plugin/dist/uniapp-x/code.d.ts b/packages/vite-plugin/dist/uniapp-x/code.d.ts new file mode 100644 index 0000000..0f85aef --- /dev/null +++ b/packages/vite-plugin/dist/uniapp-x/code.d.ts @@ -0,0 +1,2 @@ +import type { Plugin } from "vite"; +export declare function codePlugin(): Plugin; diff --git a/packages/vite-plugin/dist/uniapp-x/tailwind.d.ts b/packages/vite-plugin/dist/uniapp-x/tailwind.d.ts new file mode 100644 index 0000000..55f69f2 --- /dev/null +++ b/packages/vite-plugin/dist/uniapp-x/tailwind.d.ts @@ -0,0 +1,6 @@ +import type { Plugin } from "vite"; +/** + * Vite 插件:自动转换 .uvue 文件中的 Tailwind 类名为安全字符 + * 并自动注入 rem 转 rpx 的 PostCSS 插件 + */ +export declare function tailwindPlugin(): Plugin; diff --git a/packages/vite-plugin/src/uniapp-x/code.ts b/packages/vite-plugin/src/uniapp-x/code.ts new file mode 100644 index 0000000..8b1b483 --- /dev/null +++ b/packages/vite-plugin/src/uniapp-x/code.ts @@ -0,0 +1,12 @@ +import type { Plugin } from "vite"; + +export function codePlugin() { + return { + name: "vite-cool-uniappx-code", + transform(code, id) { + if (id.endsWith(".json")) { + return code.replace("new UTSJSONObject", ""); + } + }, + } as Plugin; +} diff --git a/packages/vite-plugin/src/uniapp-x/index.ts b/packages/vite-plugin/src/uniapp-x/index.ts index e694188..13f5424 100644 --- a/packages/vite-plugin/src/uniapp-x/index.ts +++ b/packages/vite-plugin/src/uniapp-x/index.ts @@ -1,348 +1,7 @@ -// @ts-ignore -import valueParser from "postcss-value-parser"; -import { config } from "../config"; import type { Plugin } from "vite"; -import { Config } from "../../types"; - -/** - * Tailwind CSS 特殊字符映射表 - * 用于将类名中的特殊字符转换为安全字符,避免编译或运行时冲突 - */ -const TAILWIND_SAFE_CHAR_MAP: Record = { - "[": "-", - "]": "-", - "(": "-", - ")": "-", - "{": "-", - "}": "-", - $: "-v-", - "#": "-h-", - "!": "-i-", - "/": "-s-", - ":": "-c-", - ",": "-2c-", -}; - -/** - * Tailwind CSS 常用类名前缀集合 - * 按功能分类,便于维护和扩展 - */ -const TAILWIND_CLASS_PREFIXES: string[] = [ - // 间距 - "p-", - "px-", - "py-", - "pt-", - "pr-", - "pb-", - "pl-", - "m-", - "mx-", - "my-", - "mt-", - "mr-", - "mb-", - "ml-", - "gap-", - "gap-x-", - "gap-y-", - "space-x-", - "space-y-", - "inset-", - "top-", - "right-", - "bottom-", - "left-", - - // 尺寸 - "w-", - "h-", - "min-w-", - "min-h-", - "max-w-", - "max-h-", - - // 排版 - "text-", - "font-", - "leading-", - "tracking-", - "indent-", - - // 边框 - "border-", - "border-t-", - "border-r-", - "border-b-", - "border-l-", - "rounded-", - "rounded-t-", - "rounded-r-", - "rounded-b-", - "rounded-l-", - "rounded-tl-", - "rounded-tr-", - "rounded-br-", - "rounded-bl-", - - // 效果 - "shadow-", - "blur-", - "brightness-", - "contrast-", - "drop-shadow-", - "grayscale-", - "hue-rotate-", - "invert-", - "saturate-", - "sepia-", - "backdrop-blur-", - "backdrop-brightness-", - "backdrop-contrast-", - "backdrop-grayscale-", - "backdrop-hue-rotate-", - "backdrop-invert-", - "backdrop-opacity-", - "backdrop-saturate-", - "backdrop-sepia-", - - // 动画 - "transition-", - "duration-", - "delay-", - "animate-", - - // 变换 - "translate-x-", - "translate-y-", - "rotate-", - "scale-", - "scale-x-", - "scale-y-", - "skew-x-", - "skew-y-", - "origin-", - - // 布局 - "columns-", - "break-after-", - "break-before-", - "break-inside-", - - // Flexbox 和 Grid - "basis-", - "grow-", - "shrink-", - "grid-cols-", - "grid-rows-", - "col-span-", - "row-span-", - "col-start-", - "col-end-", - "row-start-", - "row-end-", - - // SVG - "stroke-", - "stroke-w-", - "fill-", -]; - -/** - * Tailwind CSS 颜色变量映射 - * 用于移除不需要的 CSS 变量声明 - */ -const TAILWIND_COLOR_VARS: Record = { - "--tw-text-opacity": 1, - "--tw-bg-opacity": 1, -}; - -/** - * 转换类名中的特殊字符为安全字符 - * @param value 原始类名或值 - * @param isSelector 是否为选择器(true)或普通值(false) - * @returns 转换后的安全字符串 - */ -function toSafeTailwindClass(value: string, isSelector: boolean = false): string { - // 处理任意值语法(如 w-[100px]) - const arbitrary = value.match(/^(.+?)-\[(.*?)\]$/); - if (arbitrary) { - if (isSelector) return value; - const [, prefix, content] = arbitrary; - const safePrefix = toSafeTailwindClass(prefix, isSelector); - const safeContent = content.replace(/[^\d.\w]/g, "-"); - return `${safePrefix}-${safeContent}`; - } - - let safeValue = value; - - // 移除转义字符 - if (safeValue.includes("\\")) { - safeValue = safeValue.replace(/\\/g, ""); - } - - // 替换特殊字符 - for (const [char, rep] of Object.entries(TAILWIND_SAFE_CHAR_MAP)) { - const reg = new RegExp("\\" + char, "g"); - if (reg.test(safeValue)) { - safeValue = safeValue.replace(reg, rep); - } - } - - return safeValue; -} - -/** - * 将现代 rgb 格式(如 rgb(234 179 8 / 0.1))转换为标准 rgba 格式 - * @param value rgb 字符串 - * @returns 标准 rgba 字符串 - */ -function rgbToRgba(value: string): string { - const match = value.match(/rgb\(([\d\s]+)\/\s*([\d.]+)\)/); - if (match) { - const [, rgb, alpha] = match; - const [r, g, b] = rgb.split(/\s+/); - return `rgba(${r}, ${g}, ${b}, ${alpha})`; - } - return value; -} - -/** - * PostCSS 插件:将 rem 单位转换为 rpx,并处理 Tailwind 特殊字符 - * @param options 配置项 - * @returns PostCSS 插件对象 - */ -function postcssRemToRpx() { - return { - postcssPlugin: "vite-cool-uniappx-remToRpx", - prepare() { - const handledSelectors = new Set(); - const { remUnit = 16, remPrecision = 6, rpxRatio = 2 } = config.tailwind; - const factor = remUnit * rpxRatio; - - return { - Rule(rule: any) { - const sel = rule.selector; - if (handledSelectors.has(sel)) return; - const safeSel = toSafeTailwindClass(sel, true); - if (safeSel !== sel) { - rule.selector = safeSel; - handledSelectors.add(sel); - } - }, - Declaration(decl: any) { - if (decl.value.includes("/* no-rem */")) return; - if (TAILWIND_COLOR_VARS[decl.prop]) { - decl.remove(); - return; - } - if (decl.value.includes("rgb(") && decl.value.includes("/")) { - decl.value = rgbToRgba(decl.value); - } - if (decl.value.includes("rpx") && decl.parent.selector.includes("text-")) { - decl.prop = "font-size"; - } - - const parsed = valueParser(decl.value); - let changed = false; - - parsed.walk((node: any) => { - if (node.type === "word") { - // rem 转 rpx - const unit = valueParser.unit(node.value); - if (unit?.unit === "rem") { - const num = unit.number; - const precision = (num.split(".")[1] || "").length; - const rpxVal = (parseFloat(num) * factor) - .toFixed(precision || remPrecision) - .replace(/\.?0+$/, ""); - node.value = `${rpxVal}rpx`; - changed = true; - } - // 特殊字符处理 - if (node.value.includes(".") || /[[\]()#!/:,]/.test(node.value)) { - const safe = toSafeTailwindClass(node.value, true); - if (safe !== node.value) { - node.value = safe; - changed = true; - } - } - } - // 处理 var(--tw-xxx) - if (node.type === "function" && node.value === "var") { - if (node.nodes.length > 0 && node.nodes[0].value.startsWith("--tw-")) { - node.type = "word"; - node.value = TAILWIND_COLOR_VARS[node.nodes[0].value]; - changed = true; - } - } - }); - - if (changed) { - decl.value = parsed.toString(); - } - }, - }; - }, - }; -} -postcssRemToRpx.postcss = true; - -/** - * Vite 插件:自动转换 .uvue 文件中的 Tailwind 类名为安全字符 - * 并自动注入 rem 转 rpx 的 PostCSS 插件 - */ -function tailwindTransformPlugin() { - return { - name: "vite-cool-uniappx-tailwind", - enforce: "pre", - - config() { - return { - css: { - postcss: { - plugins: [postcssRemToRpx()], - }, - }, - }; - }, - - transform(code, id) { - if (!id.includes(".uvue")) return null; - - let resultCode = code; - const tplMatch = resultCode.match(/