svg 模块独立

This commit is contained in:
icssoa 2025-04-23 17:14:01 +08:00
parent 9592a61e72
commit 34f8849f34
22 changed files with 1849 additions and 3664 deletions

1547
build/cool/eps.d.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -39,7 +39,7 @@
"xlsx": "^0.18.5"
},
"devDependencies": {
"@cool-vue/vite-plugin": "^8.0.3",
"@cool-vue/vite-plugin": "^8.1.0",
"@intlify/unplugin-vue-i18n": "^6.0.3",
"@rushstack/eslint-patch": "^1.10.5",
"@tsconfig/node20": "^20.1.4",

View File

@ -41,6 +41,9 @@
},
],
},
svg: {
skipNames: ["base"],
},
};
// 根目录
@ -851,13 +854,23 @@
const dirs = fs.readdirSync(dir, {
withFileTypes: true,
});
// 获取当前目录的模块名
const moduleName = dir.match(/[\/\\](?:src\/(?:plugins|modules)\/)([^\/\\]+)/)?.[1] || "";
for (const d of dirs) {
if (d.isDirectory()) {
arr.push(...findSvg(dir + d.name + "/"));
}
else {
if (path.extname(d.name) == ".svg") {
svgIcons.push(path.basename(d.name, ".svg"));
const baseName = path.basename(d.name, ".svg");
// 判断是否需要跳过拼接模块名
let shouldSkip = config.svg.skipNames?.includes(moduleName);
// 跳过包含icon-
if (baseName.includes("icon-")) {
shouldSkip = true;
}
const iconName = shouldSkip ? baseName : `${moduleName}-${baseName}`;
svgIcons.push(iconName);
const svg = fs.readFileSync(dir + d.name)
.toString()
.replace(/(\r)|(\n)/g, "")
@ -876,7 +889,7 @@
if (!/(viewBox="[^>+].*?")/g.test($2)) {
content += `viewBox="0 0 ${width} ${height}"`;
}
return `<symbol id="icon-${d.name.replace(".svg", "")}" ${content}>`;
return `<symbol id="icon-${iconName}" ${content}>`;
})
.replace("</svg>", "</symbol>");
arr.push(svg);
@ -995,6 +1008,10 @@ if (typeof window !== 'undefined') {
config.reqUrl = getProxyTarget(options.proxy);
// 是否开启名称标签
config.nameTag = options.nameTag ?? true;
// svg
if (options.svg) {
lodash.assign(config.svg, options.svg);
}
// Eps
if (options.eps) {
const { dist, mapping, api, enable = true } = options.eps;

View File

@ -1,6 +1,6 @@
{
"name": "@cool-vue/vite-plugin",
"version": "8.0.3",
"version": "8.1.0",
"description": "cool-admin、cool-uni builder",
"types": "./dist/index.d.ts",
"main": "/dist/index.js",

File diff suppressed because it is too large Load Diff

View File

@ -38,4 +38,7 @@ export const config: Config.Data = {
},
],
},
svg: {
skipNames: ["base"],
},
};

View File

@ -4,7 +4,7 @@ import { demo } from "./demo";
import { getProxyTarget } from "./proxy";
import type { Config } from "../types";
import { virtual } from "./virtual";
import { merge } from "lodash";
import { assign, merge } from "lodash";
export function cool(options: Config.Options) {
// 应用类型admin | app
@ -16,6 +16,11 @@ export function cool(options: Config.Options) {
// 是否开启名称标签
config.nameTag = options.nameTag ?? true;
// svg
if (options.svg) {
assign(config.svg, options.svg);
}
// Eps
if (options.eps) {
const { dist, mapping, api, enable = true } = options.eps;

View File

@ -2,6 +2,7 @@ import { readFileSync, readdirSync } from "fs";
import { basename, extname } from "path";
import { rootDir } from "../utils";
import svgo from "svgo";
import { config } from "../config";
let svgIcons: string[] = [];
@ -10,12 +11,28 @@ function findSvg(dir: string) {
const dirs = readdirSync(dir, {
withFileTypes: true,
});
// 获取当前目录的模块名
const moduleName = dir.match(/[\/\\](?:src\/(?:plugins|modules)\/)([^\/\\]+)/)?.[1] || "";
for (const d of dirs) {
if (d.isDirectory()) {
arr.push(...findSvg(dir + d.name + "/"));
} else {
if (extname(d.name) == ".svg") {
svgIcons.push(basename(d.name, ".svg"));
const baseName = basename(d.name, ".svg");
// 判断是否需要跳过拼接模块名
let shouldSkip = config.svg.skipNames?.includes(moduleName);
// 跳过包含icon-
if (baseName.includes("icon-")) {
shouldSkip = true;
}
const iconName = shouldSkip ? baseName : `${moduleName}-${baseName}`;
svgIcons.push(iconName);
const svg = readFileSync(dir + d.name)
.toString()
@ -37,7 +54,7 @@ function findSvg(dir: string) {
if (!/(viewBox="[^>+].*?")/g.test($2)) {
content += `viewBox="0 0 ${width} ${height}"`;
}
return `<symbol id="icon-${d.name.replace(".svg", "")}" ${content}>`;
return `<symbol id="icon-${iconName}" ${content}>`;
})
.replace("</svg>", "</symbol>");
@ -45,6 +62,7 @@ function findSvg(dir: string) {
}
}
}
return arr;
}

View File

@ -78,9 +78,13 @@ export declare namespace Ctx {
export declare namespace Config {
type Type = "app" | "admin";
interface Eps {
// 是否开启Eps
enable: boolean;
// 请求地址
api: "app" | "admin" | (string & {});
// 输出目录
dist: string;
// 映射
mapping: {
type?: string;
test?: string[];
@ -88,11 +92,21 @@ export declare namespace Config {
}[];
}
interface Options {
// 应用类型
type: Config.Type;
// 代理配置
proxy: any;
// Eps
eps?: Partial<Config.Eps>;
// 是否开启演示模式
demo?: boolean;
// 是否开启名称标签
nameTag?: boolean;
// svg
svg?: {
// 跳过拼接模块名
skipNames?: string[];
};
}
interface Data {
type: Config.Type;

1482
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

6
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,6 @@
onlyBuiltDependencies:
- '@parcel/watcher'
- core-js
- es5-ext
- esbuild
- vue-demi

View File

@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1719536095395" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2583" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M61.44 512C61.44 263.168 263.168 61.44 512 61.44s450.56 201.728 450.56 450.56-201.728 450.56-450.56 450.56S61.44 760.832 61.44 512z m397.312 180.85888c29.61408 31.92832 76.88192 31.92832 106.496 0l199.63904-215.28576 0.90112-1.00352c17.01888-19.456 16.52736-50.44224-1.10592-69.2224-19.29216-20.52096-48.82432-23.81824-71.4752-7.96672l-150.58944 105.49248c-18.67776 13.1072-42.55744 13.1072-61.2352 0L330.1376 398.9504c-22.26176-15.5648-51.3024-12.34944-70.26688 7.84384l-0.55296 0.57344a46.8992 46.8992 0 0 0-0.90112 1.024c-17.14176 19.31264-16.83456 50.29888 0.69632 69.2224l199.65952 215.26528z" p-id="2584"></path></svg>

Before

Width:  |  Height:  |  Size: 957 B

View File

@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1719377496622" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6926" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M213.333 128h85.334v85.333h-85.334v213.334A85.333 85.333 0 0 1 128 512a85.333 85.333 0 0 1 85.333 85.333v213.334h85.334V896h-85.334C167.68 884.48 128 857.6 128 810.667V640a85.333 85.333 0 0 0-85.333-85.333H0v-85.334h42.667A85.333 85.333 0 0 0 128 384V213.333A85.333 85.333 0 0 1 213.333 128m597.334 0A85.333 85.333 0 0 1 896 213.333V384a85.333 85.333 0 0 0 85.333 85.333H1024v85.334h-42.667A85.333 85.333 0 0 0 896 640v170.667A85.333 85.333 0 0 1 810.667 896h-85.334v-85.333h85.334V597.333A85.333 85.333 0 0 1 896 512a85.333 85.333 0 0 1-85.333-85.333V213.333h-85.334V128h85.334M512 640a42.667 42.667 0 0 1 42.667 42.667A42.667 42.667 0 0 1 512 725.333a42.667 42.667 0 0 1-42.667-42.666A42.667 42.667 0 0 1 512 640m-170.667 0A42.667 42.667 0 0 1 384 682.667a42.667 42.667 0 0 1-42.667 42.666 42.667 42.667 0 0 1-42.666-42.666A42.667 42.667 0 0 1 341.333 640m341.334 0a42.667 42.667 0 0 1 42.666 42.667 42.667 42.667 0 0 1-42.666 42.666A42.667 42.667 0 0 1 640 682.667 42.667 42.667 0 0 1 682.667 640z" p-id="6927"></path></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,18 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
t="1739266182011"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="16931"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="128"
height="128"
>
<path
class="p"
d="M305.572 958.122c-20.41-0.01-36.95-16.56-36.94-36.97 0-3.35 0.46-6.69 1.36-9.92l84.28-302.19-184.32 1.42a36.055 36.055 0 0 1-30.89-16.24 36.946 36.946 0 0 1-3.6-34.7l193.8-474.36a36.97 36.97 0 0 1 34.22-22.98h362.23c20.42 0.01 36.96 16.57 36.95 36.99 0 4.65-0.88 9.27-2.6 13.6l-117.61 296.37h210.65c20.41 0.01 36.95 16.56 36.94 36.97 0 10.71-4.65 20.88-12.74 27.9l-547.57 475.05a36.875 36.875 0 0 1-24.16 9.06z m97.47-423.35c20.41 0.01 36.95 16.56 36.94 36.97 0 3.35-0.46 6.68-1.36 9.9l-64.45 231.07 379.98-329.68h-166.05c-20.39 0.02-36.94-16.5-36.96-36.89 0-4.68 0.88-9.33 2.61-13.68l117.62-296.39h-283.04l-163.49 400.05 177.9-1.42 0.3 0.07z"
p-id="16932"
></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -2,7 +2,7 @@
<div class="i18n-switch">
<el-dropdown trigger="click">
<div class="cl-comm__icon">
<cl-svg name="lang" />
<cl-svg name="i18n-lang" />
</div>
<template #dropdown>

View File

@ -29,7 +29,7 @@
<template v-else>
<!-- 图标 -->
<div class="cl-upload-item__icon">
<cl-svg :name="item.type" />
<cl-svg :name="'upload-' + item.type" />
</div>
<!-- 文件名 -->
<div class="cl-upload-item__name">

View File

@ -39,13 +39,13 @@ export default (): ModuleConfig => {
name: '文档',
type: 'word',
color: '#53B7F4',
exts: ['doc', 'dot', 'wps', 'wpt', 'docx', 'dotx', 'docm', 'dotm']
exts: ['doc', 'docx', 'docm', 'dot', 'dotx', 'dotm']
},
{
name: '表格',
type: 'excel',
color: '#53D39C',
exts: ['xls', 'xlt', 'et', 'xlsx', 'xltx', 'xlsm', 'xltm']
exts: ['xls', 'xlsx', 'xlsm', 'xlt', 'xltx', 'xltm']
},
{
name: '演示',

View File

@ -0,0 +1 @@
export * from './utils';

View File

@ -35,7 +35,7 @@ export function fileRule(path?: string) {
// 获取规则
export function getRule(type?: string) {
return (rules.find(e => e.type == type) || last(rules))!;
return (rules.find(e => e.type == type?.replace('application/', '')) || last(rules))!;
}
// 获取类型

View File

@ -23,6 +23,8 @@
<cl-svg name="plus-border" />
</div>
</el-tooltip>
<slot name="left-op"></slot>
</div>
<div v-if="config.enableKeySearch" class="search">
@ -114,7 +116,11 @@
:selected="selected"
:index="index"
>
<span>{{ item.name }}</span>
<span
class="text-ellipsis overflow-hidden mr-2"
>
{{ item.name }}
</span>
</slot>
<cl-svg
@ -143,7 +149,11 @@
<!-- 右侧 -->
<div class="cl-view-group__right">
<div class="head">
<div class="icon" :class="{ 'is-fold': !isExpand }" @click="expand()">
<div
class="icon is-bg absolute left-[10px]"
:class="{ 'is-fold': !isExpand }"
@click="expand()"
>
<cl-svg name="back" />
</div>
@ -152,6 +162,10 @@
{{ config.title }}{{ selected?.name || $t('未选择') }}
</span>
</slot>
<div class="absolute right-[10px]">
<slot name="right-op"></slot>
</div>
</div>
<div v-if="selected || config.custom" class="content">
@ -425,7 +439,7 @@ function onContextMenu(e: any, item: ClViewGroup.Item) {
list: [
{
label: t('编辑'),
hidden: !config.service._permission.update,
hidden: !config.service._permission?.update,
callback(done) {
done();
edit(item);
@ -433,7 +447,7 @@ function onContextMenu(e: any, item: ClViewGroup.Item) {
},
{
label: t('删除'),
hidden: !config.service._permission.delete,
hidden: !config.service._permission?.delete,
callback(done) {
done();
remove(item);
@ -474,7 +488,7 @@ defineExpose({
$left-width: v-bind('config.leftWidth');
$bg: var(--el-bg-color);
.icon {
:deep(.icon) {
display: flex;
align-items: center;
justify-content: center;
@ -490,6 +504,10 @@ defineExpose({
color: var(--el-text-color-primary);
}
&.is-bg {
background-color: var(--el-fill-color-lighter);
}
&.is-fold {
transform: rotate(180deg);
}
@ -647,16 +665,6 @@ defineExpose({
white-space: nowrap;
overflow: hidden;
}
.icon {
position: absolute;
left: 10px;
background-color: var(--el-fill-color-lighter);
&:hover {
background-color: var(--el-fill-color-light);
}
}
}
.content {

View File

@ -1,13 +1,13 @@
import { fileURLToPath, URL } from "node:url";
import { ConfigEnv, UserConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx";
import compression from "vite-plugin-compression";
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
import vueDevTools from "vite-plugin-vue-devtools";
import { visualizer } from "rollup-plugin-visualizer";
import { proxy } from "./src/config/proxy";
import { cool } from "@cool-vue/vite-plugin";
import { fileURLToPath, URL } from 'node:url';
import { ConfigEnv, UserConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import compression from 'vite-plugin-compression';
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
import vueDevTools from 'vite-plugin-vue-devtools';
import { visualizer } from 'rollup-plugin-visualizer';
import { proxy } from './src/config/proxy';
import { cool } from '@cool-vue/vite-plugin';
function toPath(dir: string) {
return fileURLToPath(new URL(dir, import.meta.url));
@ -15,7 +15,7 @@ function toPath(dir: string) {
// https://vitejs.dev/config
export default ({ mode }: ConfigEnv): UserConfig => {
const isDev = mode === "development";
const isDev = mode === 'development';
return {
plugins: [
@ -24,12 +24,15 @@ export default ({ mode }: ConfigEnv): UserConfig => {
vueJsx(),
// vueDevTools(),
cool({
type: "admin",
type: 'admin',
proxy,
eps: {
enable: true
},
demo: mode == "demo" // 是否开启演示模式
svg: {
skipNames: ['base', 'theme']
},
demo: mode == 'demo' // 是否开启演示模式
}),
// visualizer({
// open: false,
@ -37,10 +40,10 @@ export default ({ mode }: ConfigEnv): UserConfig => {
// brotliSize: true
// }),
VueI18nPlugin({
include: [toPath("./src/{modules,plugins}/**/locales/**")]
include: [toPath('./src/{modules,plugins}/**/locales/**')]
})
],
base: "/",
base: '/',
server: {
port: 9000,
proxy,
@ -52,23 +55,23 @@ export default ({ mode }: ConfigEnv): UserConfig => {
preprocessorOptions: {
scss: {
charset: false,
api: "modern-compiler"
api: 'modern-compiler'
}
}
},
resolve: {
alias: {
"/@": toPath("./src"),
"/$": toPath("./src/modules"),
"/#": toPath("./src/plugins"),
"/~": toPath("./packages")
'/@': toPath('./src'),
'/$': toPath('./src/modules'),
'/#': toPath('./src/plugins'),
'/~': toPath('./packages')
}
},
esbuild: {
drop: isDev ? [] : ["console", "debugger"]
drop: isDev ? [] : ['console', 'debugger']
},
build: {
minify: "esbuild",
minify: 'esbuild',
// terserOptions: {
// compress: {
// drop_console: true,
@ -78,23 +81,23 @@ export default ({ mode }: ConfigEnv): UserConfig => {
sourcemap: isDev,
rollupOptions: {
output: {
chunkFileNames: "static/js/[name]-[hash].js",
entryFileNames: "static/js/[name]-[hash].js",
assetFileNames: "static/[ext]/[name]-[hash].[ext]",
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
manualChunks(id) {
if (id.includes("node_modules")) {
if (!["@cool-vue/crud"].find((e) => id.includes(e))) {
if (id.includes("prettier")) {
if (id.includes('node_modules')) {
if (!['@cool-vue/crud'].find(e => id.includes(e))) {
if (id.includes('prettier')) {
return;
}
return id
.toString()
.split("node_modules/")[1]
.replace(".pnpm/", "")
.split("/")[0];
.split('node_modules/')[1]
.replace('.pnpm/', '')
.split('/')[0];
} else {
return "comm";
return 'comm';
}
}
}