mirror of
https://github.com/cool-team-official/cool-admin-vue.git
synced 2025-12-10 20:02:54 +00:00
Compare commits
2 Commits
ca823845ab
...
c496af0566
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c496af0566 | ||
|
|
c5e2ac3805 |
@ -165,10 +165,10 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="preload__wrap" id="Loading">
|
<div class="preload__wrap" id="Loading">
|
||||||
<div class="preload__container">
|
<div class="preload__container">
|
||||||
<p class="preload__name"></p>
|
<div class="preload__name"></div>
|
||||||
<div class="preload__loading"></div>
|
<div class="preload__loading"></div>
|
||||||
<p class="preload__title"></p>
|
<div class="preload__title"></div>
|
||||||
<p class="preload__sub-title"></p>
|
<div class="preload__sub-title"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
24
packages/vite-plugin/dist/index.d.ts
vendored
24
packages/vite-plugin/dist/index.d.ts
vendored
@ -1,2 +1,24 @@
|
|||||||
import type { Config } from "../types";
|
import type { Config } from "../types";
|
||||||
export declare function cool(options: Config.Options): (import("vite").Plugin<any> | Promise<import("vite").Plugin<any>>)[];
|
export declare function cool(options: Config.Options): (import("vite").Plugin<any> | Promise<import("vite").Plugin<any>> | {
|
||||||
|
name: string;
|
||||||
|
enforce: "pre";
|
||||||
|
config(): {
|
||||||
|
css: {
|
||||||
|
postcss: {
|
||||||
|
plugins: {
|
||||||
|
postcssPlugin: string;
|
||||||
|
prepare(): {
|
||||||
|
Rule(rule: any): void;
|
||||||
|
Declaration(decl: any): void;
|
||||||
|
};
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
transform(code: string, id: string): {
|
||||||
|
code: string;
|
||||||
|
map: {
|
||||||
|
mappings: string;
|
||||||
|
};
|
||||||
|
} | null;
|
||||||
|
}[])[];
|
||||||
|
|||||||
403
packages/vite-plugin/dist/index.js
vendored
403
packages/vite-plugin/dist/index.js
vendored
@ -1,8 +1,8 @@
|
|||||||
(function (global, factory) {
|
(function (global, factory) {
|
||||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('fs'), require('path'), require('prettier'), require('axios'), require('lodash'), require('@vue/compiler-sfc'), require('magic-string'), require('glob'), require('node:util'), require('svgo')) :
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('fs'), require('path'), require('prettier'), require('axios'), require('lodash'), require('@vue/compiler-sfc'), require('magic-string'), require('glob'), require('node:util'), require('svgo'), require('postcss-value-parser')) :
|
||||||
typeof define === 'function' && define.amd ? define(['exports', 'fs', 'path', 'prettier', 'axios', 'lodash', '@vue/compiler-sfc', 'magic-string', 'glob', 'node:util', 'svgo'], factory) :
|
typeof define === 'function' && define.amd ? define(['exports', 'fs', 'path', 'prettier', 'axios', 'lodash', '@vue/compiler-sfc', 'magic-string', 'glob', 'node:util', 'svgo', 'postcss-value-parser'], factory) :
|
||||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.index = {}, global.fs, global.path, global.prettier, global.axios, global.lodash, global.compilerSfc, global.magicString, global.glob, global.util, global.svgo));
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.index = {}, global.fs, global.path, global.prettier, global.axios, global.lodash, global.compilerSfc, global.magicString, global.glob, global.util, global.svgo, global.valueParser));
|
||||||
})(this, (function (exports, fs, path, prettier, axios, lodash, compilerSfc, magicString, glob, util, svgo) { 'use strict';
|
})(this, (function (exports, fs, path, prettier, axios, lodash, compilerSfc, magicString, glob, util, svgo, valueParser) { 'use strict';
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
type: "admin",
|
type: "admin",
|
||||||
@ -50,6 +50,7 @@
|
|||||||
function rootDir(path$1) {
|
function rootDir(path$1) {
|
||||||
switch (config.type) {
|
switch (config.type) {
|
||||||
case "app":
|
case "app":
|
||||||
|
case "uniapp-x":
|
||||||
return path.join(process.env.UNI_INPUT_DIR, path$1);
|
return path.join(process.env.UNI_INPUT_DIR, path$1);
|
||||||
default:
|
default:
|
||||||
return path.join(process.cwd(), path$1);
|
return path.join(process.cwd(), path$1);
|
||||||
@ -136,6 +137,7 @@
|
|||||||
}
|
}
|
||||||
switch (url) {
|
switch (url) {
|
||||||
case "app":
|
case "app":
|
||||||
|
case "uniapp-x":
|
||||||
url = "/app/base/comm/eps";
|
url = "/app/base/comm/eps";
|
||||||
break;
|
break;
|
||||||
case "admin":
|
case "admin":
|
||||||
@ -319,8 +321,8 @@
|
|||||||
}
|
}
|
||||||
return t0;
|
return t0;
|
||||||
}
|
}
|
||||||
// 创建 Service
|
// 创建 Controller
|
||||||
async function createDts() {
|
async function createController() {
|
||||||
let controller = "";
|
let controller = "";
|
||||||
let chain = "";
|
let chain = "";
|
||||||
// 处理数据
|
// 处理数据
|
||||||
@ -379,7 +381,7 @@
|
|||||||
case "/page":
|
case "/page":
|
||||||
res = `
|
res = `
|
||||||
{
|
{
|
||||||
pagination: { size: number; page: number; total: number; [key: string]: any };
|
pagination: { size: number; page: number; total: number; [key: string]: any; };
|
||||||
list: ${en} [];
|
list: ${en} [];
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
@ -444,7 +446,7 @@
|
|||||||
|
|
||||||
${controller}
|
${controller}
|
||||||
|
|
||||||
type Service = {
|
interface Service {
|
||||||
/**
|
/**
|
||||||
* 基础请求
|
* 基础请求
|
||||||
*/
|
*/
|
||||||
@ -453,10 +455,7 @@
|
|||||||
method?: "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
|
method?: "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
|
||||||
data?: any;
|
data?: any;
|
||||||
params?: any;
|
params?: any;
|
||||||
headers?: {
|
headers?: any,
|
||||||
authorization?: string;
|
|
||||||
[key: string]: any;
|
|
||||||
},
|
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
proxy?: boolean;
|
proxy?: boolean;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
@ -469,19 +468,33 @@
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
// 文件内容
|
// 文件内容
|
||||||
const text = `
|
let text = `
|
||||||
declare namespace Eps {
|
${createEntity()}
|
||||||
${createEntity()}
|
${await createController()}
|
||||||
${await createDts()}
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
// 文件名
|
||||||
|
let name = "eps.d.ts";
|
||||||
|
if (config.type == "uniapp-x") {
|
||||||
|
name = "eps.uts";
|
||||||
|
text = text
|
||||||
|
.replaceAll("interface ", "export interface ")
|
||||||
|
.replaceAll("type Dict", "export type Dict")
|
||||||
|
.replaceAll("[key: string]: any;", "");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
text = `
|
||||||
|
declare namespace Eps {
|
||||||
|
${text}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
// 文本内容
|
// 文本内容
|
||||||
const content = await formatCode(text);
|
const content = await formatCode(text);
|
||||||
const local_content = readFile(getEpsPath("eps.d.ts"));
|
const local_content = readFile(getEpsPath(name));
|
||||||
// 是否需要更新
|
// 是否需要更新
|
||||||
if (content && content != local_content) {
|
if (content && content != local_content) {
|
||||||
// 创建 eps 描述文件
|
// 创建 eps 描述文件
|
||||||
fs.createWriteStream(getEpsPath("eps.d.ts"), {
|
fs.createWriteStream(getEpsPath(name), {
|
||||||
flags: "w",
|
flags: "w",
|
||||||
}).write(content);
|
}).write(content);
|
||||||
}
|
}
|
||||||
@ -541,8 +554,18 @@
|
|||||||
}
|
}
|
||||||
// 创建 dict
|
// 创建 dict
|
||||||
async function createDict() {
|
async function createDict() {
|
||||||
const url = config.reqUrl + "/" + config.type + "/dict/info/types";
|
let p = "";
|
||||||
return axios
|
switch (config.type) {
|
||||||
|
case "app":
|
||||||
|
case "uniapp-x":
|
||||||
|
p = "/app";
|
||||||
|
break;
|
||||||
|
case "admin":
|
||||||
|
p = "/admin";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const url = config.reqUrl + p + "/dict/info/types";
|
||||||
|
const text = await axios
|
||||||
.get(url)
|
.get(url)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const { code, data } = res.data;
|
const { code, data } = res.data;
|
||||||
@ -557,6 +580,7 @@
|
|||||||
.catch(() => {
|
.catch(() => {
|
||||||
error(`[cool-eps] Error:${url}`);
|
error(`[cool-eps] Error:${url}`);
|
||||||
});
|
});
|
||||||
|
return text || "";
|
||||||
}
|
}
|
||||||
// 创建 eps
|
// 创建 eps
|
||||||
async function createEps() {
|
async function createEps() {
|
||||||
@ -787,7 +811,7 @@
|
|||||||
let ctx = {
|
let ctx = {
|
||||||
serviceLang: "Node",
|
serviceLang: "Node",
|
||||||
};
|
};
|
||||||
if (config.type == "app") {
|
if (config.type == "app" || config.type == "uniapp-x") {
|
||||||
const manifest = readFile(rootDir("manifest.json"), true);
|
const manifest = readFile(rootDir("manifest.json"), true);
|
||||||
// 文件路径
|
// 文件路径
|
||||||
const ctxPath = rootDir("pages.json");
|
const ctxPath = rootDir("pages.json");
|
||||||
@ -1018,6 +1042,339 @@ if (typeof window !== 'undefined') {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
/**
|
||||||
|
* Tailwind CSS 特殊字符映射表
|
||||||
|
* 用于将类名中的特殊字符转换为安全字符,避免编译或运行时冲突
|
||||||
|
*/
|
||||||
|
const TAILWIND_SAFE_CHAR_MAP = {
|
||||||
|
"[": "-",
|
||||||
|
"]": "-",
|
||||||
|
"(": "-",
|
||||||
|
")": "-",
|
||||||
|
"#": "-h-",
|
||||||
|
"!": "-i-",
|
||||||
|
"/": "-s-",
|
||||||
|
":": "-c-",
|
||||||
|
",": "-2c-",
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Tailwind CSS 常用类名前缀集合
|
||||||
|
* 按功能分类,便于维护和扩展
|
||||||
|
*/
|
||||||
|
const TAILWIND_CLASS_PREFIXES = [
|
||||||
|
// 间距
|
||||||
|
"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 = {
|
||||||
|
"--tw-text-opacity": 1,
|
||||||
|
"--tw-bg-opacity": 1,
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 转换类名中的特殊字符为安全字符
|
||||||
|
* @param value 原始类名或值
|
||||||
|
* @param isSelector 是否为选择器(true)或普通值(false)
|
||||||
|
* @returns 转换后的安全字符串
|
||||||
|
*/
|
||||||
|
function toSafeTailwindClass(value, isSelector = false) {
|
||||||
|
// 处理任意值语法(如 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) {
|
||||||
|
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(options) {
|
||||||
|
return {
|
||||||
|
postcssPlugin: "vite-cool-uniappx-remToRpx",
|
||||||
|
prepare() {
|
||||||
|
const handledSelectors = new Set();
|
||||||
|
const { remUnit = 16, remPrecision = 6, rpxRatio = 2 } = options;
|
||||||
|
const factor = remUnit * rpxRatio;
|
||||||
|
return {
|
||||||
|
Rule(rule) {
|
||||||
|
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) {
|
||||||
|
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) => {
|
||||||
|
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 插件
|
||||||
|
* @param options 配置项
|
||||||
|
* @returns Vite 插件对象
|
||||||
|
*/
|
||||||
|
function tailwindTransformPlugin(options = {}) {
|
||||||
|
const merged = {
|
||||||
|
remUnit: 16,
|
||||||
|
remPrecision: 6,
|
||||||
|
rpxRatio: 2,
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
name: "vite-cool-uniappx-tailwind",
|
||||||
|
enforce: "pre",
|
||||||
|
config() {
|
||||||
|
return {
|
||||||
|
css: {
|
||||||
|
postcss: {
|
||||||
|
plugins: [postcssRemToRpx(merged)],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
transform(code, id) {
|
||||||
|
if (!id.includes(".uvue"))
|
||||||
|
return null;
|
||||||
|
let resultCode = code;
|
||||||
|
const tplMatch = resultCode.match(/<template>([\s\S]*?)<\/template>/);
|
||||||
|
if (!tplMatch?.[1])
|
||||||
|
return null;
|
||||||
|
let tpl = tplMatch[1];
|
||||||
|
const tplOrigin = tpl;
|
||||||
|
TAILWIND_CLASS_PREFIXES.forEach((prefix) => {
|
||||||
|
for (const [char, rep] of Object.entries(TAILWIND_SAFE_CHAR_MAP)) {
|
||||||
|
const reg = new RegExp(`(${prefix}[^\\s'"]*?\\${char}[^\\s'"]*?)`, "g");
|
||||||
|
const matches = [...tpl.matchAll(reg)];
|
||||||
|
matches.forEach((m) => {
|
||||||
|
const raw = m[1];
|
||||||
|
const safe = raw.replace(new RegExp("\\" + char, "g"), rep);
|
||||||
|
if (process.env.NODE_ENV === "development") {
|
||||||
|
console.log(`类名转换: ${raw} → ${safe}`);
|
||||||
|
}
|
||||||
|
tpl = tpl.replace(raw, safe);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (tpl !== tplOrigin) {
|
||||||
|
resultCode = resultCode.replace(tplMatch[0], `<template>${tpl}</template>`);
|
||||||
|
return {
|
||||||
|
code: resultCode,
|
||||||
|
map: { mappings: "" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* uniappX 入口,自动注入 Tailwind 类名转换插件
|
||||||
|
* @param options 配置项
|
||||||
|
* @returns Vite 插件数组
|
||||||
|
*/
|
||||||
|
function uniappX(options) {
|
||||||
|
if (config.type == "uniapp-x") {
|
||||||
|
return [tailwindTransformPlugin(options?.tailwind)];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
function cool(options) {
|
function cool(options) {
|
||||||
// 应用类型,admin | app
|
// 应用类型,admin | app
|
||||||
config.type = options.type;
|
config.type = options.type;
|
||||||
@ -1047,7 +1404,7 @@ if (typeof window !== 'undefined') {
|
|||||||
lodash.merge(config.eps.mapping, mapping);
|
lodash.merge(config.eps.mapping, mapping);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [base(), virtual(), demo(options.demo)];
|
return [base(), virtual(), uniappX(), demo(options.demo)];
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.cool = cool;
|
exports.cool = cool;
|
||||||
|
|||||||
67
packages/vite-plugin/dist/uniapp-x.d.ts
vendored
Normal file
67
packages/vite-plugin/dist/uniapp-x.d.ts
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
interface PostcssRemToRpxOptions {
|
||||||
|
remUnit?: number;
|
||||||
|
remPrecision?: number;
|
||||||
|
rpxRatio?: number;
|
||||||
|
}
|
||||||
|
interface TailwindTransformOptions extends PostcssRemToRpxOptions {
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Vite 插件:自动转换 .uvue 文件中的 Tailwind 类名为安全字符
|
||||||
|
* 并自动注入 rem 转 rpx 的 PostCSS 插件
|
||||||
|
* @param options 配置项
|
||||||
|
* @returns Vite 插件对象
|
||||||
|
*/
|
||||||
|
export declare function tailwindTransformPlugin(options?: TailwindTransformOptions): {
|
||||||
|
name: string;
|
||||||
|
enforce: "pre";
|
||||||
|
config(): {
|
||||||
|
css: {
|
||||||
|
postcss: {
|
||||||
|
plugins: {
|
||||||
|
postcssPlugin: string;
|
||||||
|
prepare(): {
|
||||||
|
Rule(rule: any): void;
|
||||||
|
Declaration(decl: any): void;
|
||||||
|
};
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
transform(code: string, id: string): {
|
||||||
|
code: string;
|
||||||
|
map: {
|
||||||
|
mappings: string;
|
||||||
|
};
|
||||||
|
} | null;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* uniappX 入口,自动注入 Tailwind 类名转换插件
|
||||||
|
* @param options 配置项
|
||||||
|
* @returns Vite 插件数组
|
||||||
|
*/
|
||||||
|
export declare function uniappX(options?: {
|
||||||
|
tailwind?: TailwindTransformOptions;
|
||||||
|
}): {
|
||||||
|
name: string;
|
||||||
|
enforce: "pre";
|
||||||
|
config(): {
|
||||||
|
css: {
|
||||||
|
postcss: {
|
||||||
|
plugins: {
|
||||||
|
postcssPlugin: string;
|
||||||
|
prepare(): {
|
||||||
|
Rule(rule: any): void;
|
||||||
|
Declaration(decl: any): void;
|
||||||
|
};
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
transform(code: string, id: string): {
|
||||||
|
code: string;
|
||||||
|
map: {
|
||||||
|
mappings: string;
|
||||||
|
};
|
||||||
|
} | null;
|
||||||
|
}[];
|
||||||
|
export {};
|
||||||
9
packages/vite-plugin/dist/uniapp-x/color.d.ts
vendored
Normal file
9
packages/vite-plugin/dist/uniapp-x/color.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
type primaryColor = "emerald" | "green" | "lime" | "orange" | "amber" | "yellow" | "teal" | "cyan" | "sky" | "blue" | "indigo" | "violet" | "purple" | "fuchsia" | "pink";
|
||||||
|
type surfaceColor = "slate" | "gray" | "zinc" | "neutral" | "stone" | "soho" | "viva" | "ocean";
|
||||||
|
export declare function colorPalette(options: {
|
||||||
|
primary: primaryColor;
|
||||||
|
surface: surfaceColor;
|
||||||
|
}): {
|
||||||
|
[x: string]: string;
|
||||||
|
};
|
||||||
|
export {};
|
||||||
38
packages/vite-plugin/dist/uniapp-x/index.d.ts
vendored
Normal file
38
packages/vite-plugin/dist/uniapp-x/index.d.ts
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
interface PostcssRemToRpxOptions {
|
||||||
|
remUnit?: number;
|
||||||
|
remPrecision?: number;
|
||||||
|
rpxRatio?: number;
|
||||||
|
}
|
||||||
|
interface TailwindTransformOptions extends PostcssRemToRpxOptions {
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* uniappX 入口,自动注入 Tailwind 类名转换插件
|
||||||
|
* @param options 配置项
|
||||||
|
* @returns Vite 插件数组
|
||||||
|
*/
|
||||||
|
export declare function uniappX(options?: {
|
||||||
|
tailwind?: TailwindTransformOptions;
|
||||||
|
}): {
|
||||||
|
name: string;
|
||||||
|
enforce: "pre";
|
||||||
|
config(): {
|
||||||
|
css: {
|
||||||
|
postcss: {
|
||||||
|
plugins: {
|
||||||
|
postcssPlugin: string;
|
||||||
|
prepare(): {
|
||||||
|
Rule(rule: any): void;
|
||||||
|
Declaration(decl: any): void;
|
||||||
|
};
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
transform(code: string, id: string): {
|
||||||
|
code: string;
|
||||||
|
map: {
|
||||||
|
mappings: string;
|
||||||
|
};
|
||||||
|
} | null;
|
||||||
|
}[];
|
||||||
|
export {};
|
||||||
@ -13,7 +13,7 @@ export async function createCtx() {
|
|||||||
serviceLang: "Node",
|
serviceLang: "Node",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (config.type == "app") {
|
if (config.type == "app" || config.type == "uniapp-x") {
|
||||||
const manifest = readFile(rootDir("manifest.json"), true);
|
const manifest = readFile(rootDir("manifest.json"), true);
|
||||||
|
|
||||||
// 文件路径
|
// 文件路径
|
||||||
|
|||||||
@ -20,6 +20,7 @@ function getEpsUrl() {
|
|||||||
|
|
||||||
switch (url) {
|
switch (url) {
|
||||||
case "app":
|
case "app":
|
||||||
|
case "uniapp-x":
|
||||||
url = "/app/base/comm/eps";
|
url = "/app/base/comm/eps";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -237,8 +238,8 @@ async function createDescribe({ list, service }: { list: Eps.Entity[]; service:
|
|||||||
return t0;
|
return t0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建 Service
|
// 创建 Controller
|
||||||
async function createDts() {
|
async function createController() {
|
||||||
let controller = "";
|
let controller = "";
|
||||||
let chain = "";
|
let chain = "";
|
||||||
|
|
||||||
@ -311,7 +312,7 @@ async function createDescribe({ list, service }: { list: Eps.Entity[]; service:
|
|||||||
case "/page":
|
case "/page":
|
||||||
res = `
|
res = `
|
||||||
{
|
{
|
||||||
pagination: { size: number; page: number; total: number; [key: string]: any };
|
pagination: { size: number; page: number; total: number; [key: string]: any; };
|
||||||
list: ${en} [];
|
list: ${en} [];
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
@ -387,7 +388,7 @@ async function createDescribe({ list, service }: { list: Eps.Entity[]; service:
|
|||||||
|
|
||||||
${controller}
|
${controller}
|
||||||
|
|
||||||
type Service = {
|
interface Service {
|
||||||
/**
|
/**
|
||||||
* 基础请求
|
* 基础请求
|
||||||
*/
|
*/
|
||||||
@ -396,10 +397,7 @@ async function createDescribe({ list, service }: { list: Eps.Entity[]; service:
|
|||||||
method?: "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
|
method?: "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
|
||||||
data?: any;
|
data?: any;
|
||||||
params?: any;
|
params?: any;
|
||||||
headers?: {
|
headers?: any,
|
||||||
authorization?: string;
|
|
||||||
[key: string]: any;
|
|
||||||
},
|
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
proxy?: boolean;
|
proxy?: boolean;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
@ -413,22 +411,37 @@ async function createDescribe({ list, service }: { list: Eps.Entity[]; service:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 文件内容
|
// 文件内容
|
||||||
const text = `
|
let text = `
|
||||||
declare namespace Eps {
|
${createEntity()}
|
||||||
${createEntity()}
|
${await createController()}
|
||||||
${await createDts()}
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
// 文件名
|
||||||
|
let name = "eps.d.ts";
|
||||||
|
|
||||||
|
if (config.type == "uniapp-x") {
|
||||||
|
name = "eps.uts";
|
||||||
|
text = text
|
||||||
|
.replaceAll("interface ", "export interface ")
|
||||||
|
.replaceAll("type Dict", "export type Dict")
|
||||||
|
.replaceAll("[key: string]: any;", "");
|
||||||
|
} else {
|
||||||
|
text = `
|
||||||
|
declare namespace Eps {
|
||||||
|
${text}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
// 文本内容
|
// 文本内容
|
||||||
const content = await formatCode(text);
|
const content = await formatCode(text);
|
||||||
|
|
||||||
const local_content = readFile(getEpsPath("eps.d.ts"));
|
const local_content = readFile(getEpsPath(name));
|
||||||
|
|
||||||
// 是否需要更新
|
// 是否需要更新
|
||||||
if (content && content != local_content) {
|
if (content && content != local_content) {
|
||||||
// 创建 eps 描述文件
|
// 创建 eps 描述文件
|
||||||
createWriteStream(getEpsPath("eps.d.ts"), {
|
createWriteStream(getEpsPath(name), {
|
||||||
flags: "w",
|
flags: "w",
|
||||||
}).write(content);
|
}).write(content);
|
||||||
}
|
}
|
||||||
@ -500,9 +513,22 @@ function createService() {
|
|||||||
|
|
||||||
// 创建 dict
|
// 创建 dict
|
||||||
async function createDict() {
|
async function createDict() {
|
||||||
const url = config.reqUrl + "/" + config.type + "/dict/info/types";
|
let p = "";
|
||||||
|
|
||||||
return axios
|
switch (config.type) {
|
||||||
|
case "app":
|
||||||
|
case "uniapp-x":
|
||||||
|
p = "/app";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "admin":
|
||||||
|
p = "/admin";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = config.reqUrl + p + "/dict/info/types";
|
||||||
|
|
||||||
|
const text = await axios
|
||||||
.get(url)
|
.get(url)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const { code, data } = res.data as { code: number; data: any[] };
|
const { code, data } = res.data as { code: number; data: any[] };
|
||||||
@ -520,6 +546,8 @@ async function createDict() {
|
|||||||
.catch(() => {
|
.catch(() => {
|
||||||
error(`[cool-eps] Error:${url}`);
|
error(`[cool-eps] Error:${url}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return text || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建 eps
|
// 创建 eps
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { getProxyTarget } from "./proxy";
|
|||||||
import type { Config } from "../types";
|
import type { Config } from "../types";
|
||||||
import { virtual } from "./virtual";
|
import { virtual } from "./virtual";
|
||||||
import { assign, merge } from "lodash";
|
import { assign, merge } from "lodash";
|
||||||
|
import { uniappX } from "./uniapp-x";
|
||||||
|
|
||||||
export function cool(options: Config.Options) {
|
export function cool(options: Config.Options) {
|
||||||
// 应用类型,admin | app
|
// 应用类型,admin | app
|
||||||
@ -44,5 +45,5 @@ export function cool(options: Config.Options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [base(), virtual(), demo(options.demo)];
|
return [base(), virtual(), uniappX(), demo(options.demo)];
|
||||||
}
|
}
|
||||||
|
|||||||
370
packages/vite-plugin/src/uniapp-x/index.ts
Normal file
370
packages/vite-plugin/src/uniapp-x/index.ts
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
// @ts-ignore
|
||||||
|
import valueParser from "postcss-value-parser";
|
||||||
|
import { config } from "../config";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tailwind CSS 特殊字符映射表
|
||||||
|
* 用于将类名中的特殊字符转换为安全字符,避免编译或运行时冲突
|
||||||
|
*/
|
||||||
|
const TAILWIND_SAFE_CHAR_MAP: Record<string, string> = {
|
||||||
|
"[": "-",
|
||||||
|
"]": "-",
|
||||||
|
"(": "-",
|
||||||
|
")": "-",
|
||||||
|
"#": "-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<string, number> = {
|
||||||
|
"--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;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PostcssRemToRpxOptions {
|
||||||
|
remUnit?: number;
|
||||||
|
remPrecision?: number;
|
||||||
|
rpxRatio?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PostCSS 插件:将 rem 单位转换为 rpx,并处理 Tailwind 特殊字符
|
||||||
|
* @param options 配置项
|
||||||
|
* @returns PostCSS 插件对象
|
||||||
|
*/
|
||||||
|
function postcssRemToRpx(options: PostcssRemToRpxOptions) {
|
||||||
|
return {
|
||||||
|
postcssPlugin: "vite-cool-uniappx-remToRpx",
|
||||||
|
prepare() {
|
||||||
|
const handledSelectors = new Set<string>();
|
||||||
|
const { remUnit = 16, remPrecision = 6, rpxRatio = 2 } = options;
|
||||||
|
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;
|
||||||
|
|
||||||
|
interface TailwindTransformOptions extends PostcssRemToRpxOptions {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vite 插件:自动转换 .uvue 文件中的 Tailwind 类名为安全字符
|
||||||
|
* 并自动注入 rem 转 rpx 的 PostCSS 插件
|
||||||
|
* @param options 配置项
|
||||||
|
* @returns Vite 插件对象
|
||||||
|
*/
|
||||||
|
function tailwindTransformPlugin(options: TailwindTransformOptions = {}) {
|
||||||
|
const merged: Required<TailwindTransformOptions> = {
|
||||||
|
remUnit: 16,
|
||||||
|
remPrecision: 6,
|
||||||
|
rpxRatio: 2,
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "vite-cool-uniappx-tailwind",
|
||||||
|
enforce: "pre" as const,
|
||||||
|
|
||||||
|
config() {
|
||||||
|
return {
|
||||||
|
css: {
|
||||||
|
postcss: {
|
||||||
|
plugins: [postcssRemToRpx(merged)],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
transform(code: string, id: string) {
|
||||||
|
if (!id.includes(".uvue")) return null;
|
||||||
|
|
||||||
|
let resultCode = code;
|
||||||
|
const tplMatch = resultCode.match(/<template>([\s\S]*?)<\/template>/);
|
||||||
|
if (!tplMatch?.[1]) return null;
|
||||||
|
|
||||||
|
let tpl = tplMatch[1];
|
||||||
|
const tplOrigin = tpl;
|
||||||
|
|
||||||
|
TAILWIND_CLASS_PREFIXES.forEach((prefix) => {
|
||||||
|
for (const [char, rep] of Object.entries(TAILWIND_SAFE_CHAR_MAP)) {
|
||||||
|
const reg = new RegExp(`(${prefix}[^\\s'"]*?\\${char}[^\\s'"]*?)`, "g");
|
||||||
|
const matches = [...tpl.matchAll(reg)];
|
||||||
|
matches.forEach((m) => {
|
||||||
|
const raw = m[1];
|
||||||
|
const safe = raw.replace(new RegExp("\\" + char, "g"), rep);
|
||||||
|
if (process.env.NODE_ENV === "development") {
|
||||||
|
console.log(`类名转换: ${raw} → ${safe}`);
|
||||||
|
}
|
||||||
|
tpl = tpl.replace(raw, safe);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (tpl !== tplOrigin) {
|
||||||
|
resultCode = resultCode.replace(tplMatch[0], `<template>${tpl}</template>`);
|
||||||
|
return {
|
||||||
|
code: resultCode,
|
||||||
|
map: { mappings: "" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uniappX 入口,自动注入 Tailwind 类名转换插件
|
||||||
|
* @param options 配置项
|
||||||
|
* @returns Vite 插件数组
|
||||||
|
*/
|
||||||
|
export function uniappX(options?: { tailwind?: TailwindTransformOptions }) {
|
||||||
|
if (config.type == "uniapp-x") {
|
||||||
|
return [tailwindTransformPlugin(options?.tailwind)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
@ -7,6 +7,7 @@ import prettier from "prettier";
|
|||||||
export function rootDir(path: string) {
|
export function rootDir(path: string) {
|
||||||
switch (config.type) {
|
switch (config.type) {
|
||||||
case "app":
|
case "app":
|
||||||
|
case "uniapp-x":
|
||||||
return join(process.env.UNI_INPUT_DIR!, path);
|
return join(process.env.UNI_INPUT_DIR!, path);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
7
packages/vite-plugin/types/index.d.ts
vendored
7
packages/vite-plugin/types/index.d.ts
vendored
@ -1,4 +1,4 @@
|
|||||||
export declare type Type = "app" | "admin";
|
export declare type Type = "admin" | "app" | "uniapp-x";
|
||||||
|
|
||||||
export declare namespace Eps {
|
export declare namespace Eps {
|
||||||
interface Column {
|
interface Column {
|
||||||
@ -76,7 +76,6 @@ export declare namespace Ctx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export declare namespace Config {
|
export declare namespace Config {
|
||||||
type Type = "app" | "admin";
|
|
||||||
interface Eps {
|
interface Eps {
|
||||||
// 是否开启Eps
|
// 是否开启Eps
|
||||||
enable: boolean;
|
enable: boolean;
|
||||||
@ -93,7 +92,7 @@ export declare namespace Config {
|
|||||||
}
|
}
|
||||||
interface Options {
|
interface Options {
|
||||||
// 应用类型
|
// 应用类型
|
||||||
type: Config.Type;
|
type: Type;
|
||||||
// 代理配置
|
// 代理配置
|
||||||
proxy: any;
|
proxy: any;
|
||||||
// Eps
|
// Eps
|
||||||
@ -109,7 +108,7 @@ export declare namespace Config {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
interface Data {
|
interface Data {
|
||||||
type: Config.Type;
|
type: Type;
|
||||||
reqUrl: string;
|
reqUrl: string;
|
||||||
eps: Config.Eps;
|
eps: Config.Eps;
|
||||||
demo: boolean;
|
demo: boolean;
|
||||||
|
|||||||
1369
pnpm-lock.yaml
generated
1369
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -50,10 +50,19 @@ export default (): ModuleConfig => {
|
|||||||
const loading = document.querySelector('#Loading');
|
const loading = document.querySelector('#Loading');
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
loading.querySelector('.preload__name')!.innerHTML = config.app.name;
|
const name = loading.querySelector('.preload__name');
|
||||||
loading.querySelector('.preload__title')!.innerHTML = t('正在加载资源...');
|
const title = loading.querySelector('.preload__title');
|
||||||
loading.querySelector('.preload__sub-title')!.innerHTML =
|
const subTitle = loading.querySelector('.preload__sub-title');
|
||||||
t('初次加载资源可能需要较多时间,请耐心等待');
|
|
||||||
|
if (name) {
|
||||||
|
name.innerHTML = config.app.name;
|
||||||
|
}
|
||||||
|
if (title) {
|
||||||
|
title.innerHTML = t('正在加载资源...');
|
||||||
|
}
|
||||||
|
if (subTitle) {
|
||||||
|
subTitle.innerHTML = t('初次加载资源可能需要较多时间,请耐心等待');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async onLoad() {
|
async onLoad() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user