translime-sdk 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +153 -0
- package/dist/index.cjs +111 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +93 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.js +111 -0
- package/dist/index.js.map +1 -0
- package/dist/preview/settings.scss +86 -0
- package/dist/preview-mock.cjs +253 -0
- package/dist/preview-mock.cjs.map +1 -0
- package/dist/preview-mock.js +253 -0
- package/dist/preview-mock.js.map +1 -0
- package/dist/preview-template.html +13 -0
- package/dist/preview.cjs +3607 -0
- package/dist/preview.cjs.map +1 -0
- package/dist/preview.js +3589 -0
- package/dist/preview.js.map +1 -0
- package/dist/translime-sdk.css +1224 -0
- package/dist/vite-plugin.cjs +196 -0
- package/dist/vite-plugin.cjs.map +1 -0
- package/dist/vite-plugin.d.cts +22 -0
- package/dist/vite-plugin.d.ts +22 -0
- package/dist/vite-plugin.js +195 -0
- package/dist/vite-plugin.js.map +1 -0
- package/package.json +99 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const url = require("url");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
|
|
7
|
+
const __filename$1 = url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("vite-plugin.cjs", document.baseURI).href);
|
|
8
|
+
const __dirname$1 = path.dirname(__filename$1);
|
|
9
|
+
const VIRTUAL_PREVIEW_ENTRY = "virtual:translime-preview-entry";
|
|
10
|
+
const RESOLVED_VIRTUAL_PREVIEW_ENTRY = `\0${VIRTUAL_PREVIEW_ENTRY}`;
|
|
11
|
+
function getPreviewSettingsPath() {
|
|
12
|
+
return path.resolve(__dirname$1, "preview/settings.scss");
|
|
13
|
+
}
|
|
14
|
+
function getInlineTemplate() {
|
|
15
|
+
return `<!DOCTYPE html>
|
|
16
|
+
<html lang="zh-CN">
|
|
17
|
+
<head>
|
|
18
|
+
<meta charset="UTF-8">
|
|
19
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
20
|
+
<title>Plugin Preview</title>
|
|
21
|
+
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
22
|
+
</head>
|
|
23
|
+
<body>
|
|
24
|
+
<div id="app"></div>
|
|
25
|
+
<script type="module" src="/__PREVIEW_ENTRY__"><\/script>
|
|
26
|
+
</body>
|
|
27
|
+
</html>`;
|
|
28
|
+
}
|
|
29
|
+
function translimeSdk(options = {}) {
|
|
30
|
+
let isPreviewMode = false;
|
|
31
|
+
let resolvedPreviewComponent = "";
|
|
32
|
+
return {
|
|
33
|
+
name: "translime-sdk-plugin",
|
|
34
|
+
enforce: "pre",
|
|
35
|
+
// 确保在核心插件之前执行
|
|
36
|
+
// ----------------------------------------------------------------------
|
|
37
|
+
// Config Hook
|
|
38
|
+
// ----------------------------------------------------------------------
|
|
39
|
+
config(config, { mode, command }) {
|
|
40
|
+
isPreviewMode = mode === "preview";
|
|
41
|
+
if (options.previewComponent) {
|
|
42
|
+
resolvedPreviewComponent = options.previewComponent;
|
|
43
|
+
} else if (config.build?.lib?.entry) {
|
|
44
|
+
resolvedPreviewComponent = config.build.lib.entry;
|
|
45
|
+
}
|
|
46
|
+
if (resolvedPreviewComponent && !resolvedPreviewComponent.startsWith("./") && !resolvedPreviewComponent.startsWith("/")) {
|
|
47
|
+
resolvedPreviewComponent = `./${resolvedPreviewComponent}`;
|
|
48
|
+
}
|
|
49
|
+
const baseConfig = {
|
|
50
|
+
define: {
|
|
51
|
+
__TRANSLIME_PREVIEW__: isPreviewMode
|
|
52
|
+
// 注入全局变量供代码判断环境
|
|
53
|
+
},
|
|
54
|
+
build: {
|
|
55
|
+
rollupOptions: {
|
|
56
|
+
external: ["electron"],
|
|
57
|
+
// 永远排除 electron
|
|
58
|
+
output: {
|
|
59
|
+
globals: {
|
|
60
|
+
electron: "window.electron"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
if (isPreviewMode && command === "serve") {
|
|
67
|
+
const settingsPath = path.resolve(__dirname$1, "preview/settings.scss");
|
|
68
|
+
return {
|
|
69
|
+
...baseConfig,
|
|
70
|
+
// 切换为 SPA 模式 (非库模式)
|
|
71
|
+
build: {
|
|
72
|
+
lib: void 0,
|
|
73
|
+
rollupOptions: {
|
|
74
|
+
external: []
|
|
75
|
+
// Preview 模式下需要打包所有依赖
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
// 启用现代 Sass 编译器 (消除 Deprecation Warning)
|
|
79
|
+
css: {
|
|
80
|
+
preprocessorOptions: {
|
|
81
|
+
sass: { api: "modern-compiler" },
|
|
82
|
+
scss: { api: "modern-compiler" }
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
// 优化依赖: 排除 vuetify (使用我们注入的 mock/core)
|
|
86
|
+
optimizeDeps: {
|
|
87
|
+
exclude: ["vuetify"]
|
|
88
|
+
},
|
|
89
|
+
// 向下游插件传递配置 (如 vite-plugin-vuetify)
|
|
90
|
+
__translimeSdkPreview: {
|
|
91
|
+
settingsPath
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return baseConfig;
|
|
96
|
+
},
|
|
97
|
+
// ----------------------------------------------------------------------
|
|
98
|
+
// Configure Server (Preview Middleware)
|
|
99
|
+
// ----------------------------------------------------------------------
|
|
100
|
+
configureServer(server) {
|
|
101
|
+
if (!isPreviewMode) return;
|
|
102
|
+
server.middlewares.use((req, res, next) => {
|
|
103
|
+
if (req.url === "/" || req.url === "/index.html") {
|
|
104
|
+
const templatePath = path.resolve(__dirname$1, "../preview-template.html");
|
|
105
|
+
let html;
|
|
106
|
+
try {
|
|
107
|
+
html = fs.readFileSync(templatePath, "utf-8");
|
|
108
|
+
} catch (e) {
|
|
109
|
+
html = getInlineTemplate();
|
|
110
|
+
}
|
|
111
|
+
html = html.replace("/__PREVIEW_ENTRY__", `/@id/${VIRTUAL_PREVIEW_ENTRY}`);
|
|
112
|
+
res.setHeader("Content-Type", "text/html");
|
|
113
|
+
res.end(html);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
next();
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
// ----------------------------------------------------------------------
|
|
120
|
+
// Resolve Id (Virtual Entry)
|
|
121
|
+
// ----------------------------------------------------------------------
|
|
122
|
+
resolveId(id) {
|
|
123
|
+
if (id === VIRTUAL_PREVIEW_ENTRY) {
|
|
124
|
+
return RESOLVED_VIRTUAL_PREVIEW_ENTRY;
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
},
|
|
128
|
+
// ----------------------------------------------------------------------
|
|
129
|
+
// Load (Virtual Entry Content)
|
|
130
|
+
// ----------------------------------------------------------------------
|
|
131
|
+
load(id) {
|
|
132
|
+
if (id === RESOLVED_VIRTUAL_PREVIEW_ENTRY) {
|
|
133
|
+
const componentPath = resolvedPreviewComponent || "./src/ui/ui.vue";
|
|
134
|
+
return `import { startPreview } from 'translime-sdk/preview';
|
|
135
|
+
import PluginComponent from '${componentPath}';
|
|
136
|
+
startPreview(PluginComponent);
|
|
137
|
+
`;
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
},
|
|
141
|
+
// ----------------------------------------------------------------------
|
|
142
|
+
// Transform (Auto-Import Components)
|
|
143
|
+
// ----------------------------------------------------------------------
|
|
144
|
+
transform(code, id) {
|
|
145
|
+
if (id.includes("node_modules") || id.startsWith("\0")) return null;
|
|
146
|
+
if (!/\.(js|ts|vue)$/.test(id)) return null;
|
|
147
|
+
const matches = /* @__PURE__ */ new Set();
|
|
148
|
+
const componentRegex = /\b(V[A-Z][\w$]+)\b/g;
|
|
149
|
+
let match;
|
|
150
|
+
while ((match = componentRegex.exec(code)) !== null) {
|
|
151
|
+
matches.add(match[1]);
|
|
152
|
+
}
|
|
153
|
+
if (id.endsWith(".vue")) {
|
|
154
|
+
const templateTagRegex = /<v-([a-z0-9-]+)\b/g;
|
|
155
|
+
while ((match = templateTagRegex.exec(code)) !== null) {
|
|
156
|
+
const name = `V${match[1].split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("")}`;
|
|
157
|
+
matches.add(name);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (matches.size === 0) return null;
|
|
161
|
+
const used = Array.from(matches).filter((name) => {
|
|
162
|
+
if (new RegExp(`import\\s+{[^}]*\\b${name}\\b[^}]*}\\s+from`, "m").test(code)) return false;
|
|
163
|
+
if (new RegExp(`(const|let|var|function|class|import)\\s+\\b${name}\\b`, "m").test(code)) return false;
|
|
164
|
+
if (new RegExp(`\\.\\b${name}\\b`).test(code)) return false;
|
|
165
|
+
return true;
|
|
166
|
+
});
|
|
167
|
+
if (used.length === 0) return null;
|
|
168
|
+
const injection = `
|
|
169
|
+
/* auto-injected by translime-sdk */
|
|
170
|
+
const { ${used.join(", ")} } = (typeof window !== 'undefined' && window.vuetify$?.components || {});
|
|
171
|
+
`;
|
|
172
|
+
let newCode = code;
|
|
173
|
+
if (id.endsWith(".vue")) {
|
|
174
|
+
if (code.includes("<script setup")) {
|
|
175
|
+
newCode = code.replace(/<script\s+setup[^>]*>/, `$&${injection}`);
|
|
176
|
+
} else if (code.includes("<script")) {
|
|
177
|
+
newCode = code.replace(/<script[^>]*>/, `$&${injection}`);
|
|
178
|
+
} else {
|
|
179
|
+
newCode = `<script setup>${injection}<\/script>
|
|
180
|
+
${code}`;
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
newCode = injection + code;
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
code: newCode,
|
|
187
|
+
map: null
|
|
188
|
+
// 可选:生成 sourcemap
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
exports.default = translimeSdk;
|
|
194
|
+
exports.getPreviewSettingsPath = getPreviewSettingsPath;
|
|
195
|
+
exports.translimeSdk = translimeSdk;
|
|
196
|
+
//# sourceMappingURL=vite-plugin.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite-plugin.cjs","sources":["../src/vite-plugin.js"],"sourcesContent":["import { fileURLToPath } from 'url';\nimport { dirname, resolve } from 'path';\nimport { readFileSync } from 'fs';\n\n// 获取当前模块所在目录\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// ----------------------------------------------------------------------\n// Constants\n// ----------------------------------------------------------------------\n\nconst VIRTUAL_PREVIEW_ENTRY = 'virtual:translime-preview-entry';\nconst RESOLVED_VIRTUAL_PREVIEW_ENTRY = `\\0${VIRTUAL_PREVIEW_ENTRY}`;\n\n// ----------------------------------------------------------------------\n// Helpers\n// ----------------------------------------------------------------------\n\n/**\n * 获取 Preview 模式的 Vuetify 样式配置文件路径\n * @description 用于 vite-plugin-vuetify 的 styles.configFile 配置\n * @returns {string} 绝对路径\n */\nexport function getPreviewSettingsPath() {\n return resolve(__dirname, 'preview/settings.scss');\n}\n\n/**\n * 内联的 HTML 模板\n * @description 当项目目录下找不到 preview-template.html 时使用的默认模板\n */\nfunction getInlineTemplate() {\n return `<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Plugin Preview</title>\n <link href=\"https://fonts.googleapis.com/icon?family=Material+Icons\" rel=\"stylesheet\">\n</head>\n<body>\n <div id=\"app\"></div>\n <script type=\"module\" src=\"/__PREVIEW_ENTRY__\"></script>\n</body>\n</html>`;\n}\n\n// ----------------------------------------------------------------------\n// Main Plugin\n// ----------------------------------------------------------------------\n\n/**\n * Translime SDK Vite Plugin\n *\n * 功能:\n * 1. **自动组件导入**: 扫描 Vue/JS 文件,自动从 `window.vuetify$.components` 注入使用到的 Vuetify 组件,\n * 避免在插件源码中手动 import Vuetify 组件 (减小插件体积).\n * 2. **Preview 模式支持**: 提供完整的本地预览环境,包含 HMR、Mock API 和样式注入.\n *\n * @param {Object} options - 插件选项\n * @param {string} [options.previewComponent] - Preview 模式下的入口组件路径 (默认为 build.lib.entry)\n * @returns {import('vite').Plugin}\n */\nexport function translimeSdk(options = {}) {\n let isPreviewMode = false;\n let resolvedPreviewComponent = '';\n\n return {\n name: 'translime-sdk-plugin',\n enforce: 'pre', // 确保在核心插件之前执行\n\n // ----------------------------------------------------------------------\n // Config Hook\n // ----------------------------------------------------------------------\n config(config, { mode, command }) {\n isPreviewMode = mode === 'preview';\n\n // 确定 Preview 入口组件路径\n if (options.previewComponent) {\n resolvedPreviewComponent = options.previewComponent;\n } else if (config.build?.lib?.entry) {\n // 尝试从 lib entry 推断\n resolvedPreviewComponent = config.build.lib.entry;\n }\n\n // 规范化路径 (Vite 需要 ./ 或 / 开头)\n if (resolvedPreviewComponent && !resolvedPreviewComponent.startsWith('./') && !resolvedPreviewComponent.startsWith('/')) {\n resolvedPreviewComponent = `./${resolvedPreviewComponent}`;\n }\n\n // 基础配置 (通用)\n const baseConfig = {\n define: {\n __TRANSLIME_PREVIEW__: isPreviewMode, // 注入全局变量供代码判断环境\n },\n build: {\n rollupOptions: {\n external: ['electron'], // 永远排除 electron\n output: {\n globals: {\n electron: 'window.electron',\n },\n },\n },\n },\n };\n\n // Preview 模式特殊配置 (仅在 serve 阶段生效)\n if (isPreviewMode && command === 'serve') {\n const settingsPath = resolve(__dirname, 'preview/settings.scss');\n\n return {\n ...baseConfig,\n // 切换为 SPA 模式 (非库模式)\n build: {\n lib: undefined,\n rollupOptions: {\n external: [], // Preview 模式下需要打包所有依赖\n },\n },\n // 启用现代 Sass 编译器 (消除 Deprecation Warning)\n css: {\n preprocessorOptions: {\n sass: { api: 'modern-compiler' },\n scss: { api: 'modern-compiler' },\n },\n },\n // 优化依赖: 排除 vuetify (使用我们注入的 mock/core)\n optimizeDeps: {\n exclude: ['vuetify'],\n },\n // 向下游插件传递配置 (如 vite-plugin-vuetify)\n __translimeSdkPreview: {\n settingsPath,\n },\n };\n }\n\n return baseConfig;\n },\n\n // ----------------------------------------------------------------------\n // Configure Server (Preview Middleware)\n // ----------------------------------------------------------------------\n configureServer(server) {\n if (!isPreviewMode) return;\n\n // 拦截 index.html 请求,提供 Preview 模板\n server.middlewares.use((req, res, next) => {\n if (req.url === '/' || req.url === '/index.html') {\n const templatePath = resolve(__dirname, '../preview-template.html');\n let html;\n try {\n html = readFileSync(templatePath, 'utf-8');\n } catch (e) {\n html = getInlineTemplate();\n }\n\n // 注入虚拟入口\n html = html.replace('/__PREVIEW_ENTRY__', `/@id/${VIRTUAL_PREVIEW_ENTRY}`);\n\n res.setHeader('Content-Type', 'text/html');\n res.end(html);\n return;\n }\n next();\n });\n },\n\n // ----------------------------------------------------------------------\n // Resolve Id (Virtual Entry)\n // ----------------------------------------------------------------------\n resolveId(id) {\n if (id === VIRTUAL_PREVIEW_ENTRY) {\n return RESOLVED_VIRTUAL_PREVIEW_ENTRY;\n }\n return null;\n },\n\n // ----------------------------------------------------------------------\n // Load (Virtual Entry Content)\n // ----------------------------------------------------------------------\n load(id) {\n if (id === RESOLVED_VIRTUAL_PREVIEW_ENTRY) {\n // 生成引导代码:导入 Preview 框架 + 用户插件组件\n const componentPath = resolvedPreviewComponent || './src/ui/ui.vue';\n return `import { startPreview } from 'translime-sdk/preview';\nimport PluginComponent from '${componentPath}';\nstartPreview(PluginComponent);\n`;\n }\n return null;\n },\n\n // ----------------------------------------------------------------------\n // Transform (Auto-Import Components)\n // ----------------------------------------------------------------------\n transform(code, id) {\n // 忽略不需要处理的文件\n if (id.includes('node_modules') || id.startsWith('\\0')) return null;\n if (!/\\.(js|ts|vue)$/.test(id)) return null;\n\n const matches = new Set();\n\n // 扫描 JS/TS 中的组件名 (e.g. VBtn, VCard)\n const componentRegex = /\\b(V[A-Z][\\w$]+)\\b/g;\n let match;\n while ((match = componentRegex.exec(code)) !== null) {\n matches.add(match[1]);\n }\n\n // 扫描 Vue 模板中的 kebab-case 标签 (e.g. <v-btn>)\n if (id.endsWith('.vue')) {\n const templateTagRegex = /<v-([a-z0-9-]+)\\b/g;\n while ((match = templateTagRegex.exec(code)) !== null) {\n // camelCase 转换: v-btn -> VBtn\n const name = `V${match[1].split('-').map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join('')}`;\n matches.add(name);\n }\n }\n\n if (matches.size === 0) return null;\n\n // 过滤掉已从其他地方导入或定义的变量\n const used = Array.from(matches).filter((name) => {\n // 检查 import 语句\n if (new RegExp(`import\\\\s+{[^}]*\\\\b${name}\\\\b[^}]*}\\\\s+from`, 'm').test(code)) return false;\n // 检查局部变量定义 (const, let, function, class)\n if (new RegExp(`(const|let|var|function|class|import)\\\\s+\\\\b${name}\\\\b`, 'm').test(code)) return false;\n // 检查属性访问 (e.g. something.VBtn)\n if (new RegExp(`\\\\.\\\\b${name}\\\\b`).test(code)) return false;\n return true;\n });\n\n if (used.length === 0) return null;\n\n // 注入代码\n // 如果运行在 Render 进程 (有 window.vuetify$),则从中解构;否则为空对象\n const injection = `\\n/* auto-injected by translime-sdk */\\nconst { ${used.join(', ')} } = (typeof window !== 'undefined' && window.vuetify$?.components || {});\\n`;\n\n let newCode = code;\n if (id.endsWith('.vue')) {\n if (code.includes('<script setup')) {\n newCode = code.replace(/<script\\s+setup[^>]*>/, `$&${injection}`);\n } else if (code.includes('<script')) {\n newCode = code.replace(/<script[^>]*>/, `$&${injection}`);\n } else {\n // 无 script 标签时,创建 <script setup> (常见于纯模板 Vue 文件)\n newCode = `<script setup>${injection}</script>\\n${code}`;\n }\n } else {\n newCode = injection + code;\n }\n\n return {\n code: newCode,\n map: null, // 可选:生成 sourcemap\n };\n },\n };\n}\n\nexport default translimeSdk;\n\n"],"names":["__filename","fileURLToPath","__dirname","dirname","resolve","readFileSync"],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
|
|
3
|
+
interface TranslimeSdkOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Preview 模式下要渲染的组件路径
|
|
6
|
+
*/
|
|
7
|
+
previewComponent?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Translime SDK Vite Plugin
|
|
12
|
+
* 自动处理 electron 外部化、Preview 模式等构建配置
|
|
13
|
+
*/
|
|
14
|
+
export function translimeSdk(options?: TranslimeSdkOptions): Plugin;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 获取 Preview 模式的 Vuetify 样式配置文件路径
|
|
18
|
+
* 用于 vite-plugin-vuetify 的 styles.configFile 配置
|
|
19
|
+
*/
|
|
20
|
+
export function getPreviewSettingsPath(): string;
|
|
21
|
+
|
|
22
|
+
export default translimeSdk;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
|
|
3
|
+
interface TranslimeSdkOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Preview 模式下要渲染的组件路径
|
|
6
|
+
*/
|
|
7
|
+
previewComponent?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Translime SDK Vite Plugin
|
|
12
|
+
* 自动处理 electron 外部化、Preview 模式等构建配置
|
|
13
|
+
*/
|
|
14
|
+
export function translimeSdk(options?: TranslimeSdkOptions): Plugin;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 获取 Preview 模式的 Vuetify 样式配置文件路径
|
|
18
|
+
* 用于 vite-plugin-vuetify 的 styles.configFile 配置
|
|
19
|
+
*/
|
|
20
|
+
export function getPreviewSettingsPath(): string;
|
|
21
|
+
|
|
22
|
+
export default translimeSdk;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { fileURLToPath } from "url";
|
|
2
|
+
import { dirname, resolve } from "path";
|
|
3
|
+
import { readFileSync } from "fs";
|
|
4
|
+
const __filename$1 = fileURLToPath(import.meta.url);
|
|
5
|
+
const __dirname$1 = dirname(__filename$1);
|
|
6
|
+
const VIRTUAL_PREVIEW_ENTRY = "virtual:translime-preview-entry";
|
|
7
|
+
const RESOLVED_VIRTUAL_PREVIEW_ENTRY = `\0${VIRTUAL_PREVIEW_ENTRY}`;
|
|
8
|
+
function getPreviewSettingsPath() {
|
|
9
|
+
return resolve(__dirname$1, "preview/settings.scss");
|
|
10
|
+
}
|
|
11
|
+
function getInlineTemplate() {
|
|
12
|
+
return `<!DOCTYPE html>
|
|
13
|
+
<html lang="zh-CN">
|
|
14
|
+
<head>
|
|
15
|
+
<meta charset="UTF-8">
|
|
16
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
17
|
+
<title>Plugin Preview</title>
|
|
18
|
+
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
<div id="app"></div>
|
|
22
|
+
<script type="module" src="/__PREVIEW_ENTRY__"><\/script>
|
|
23
|
+
</body>
|
|
24
|
+
</html>`;
|
|
25
|
+
}
|
|
26
|
+
function translimeSdk(options = {}) {
|
|
27
|
+
let isPreviewMode = false;
|
|
28
|
+
let resolvedPreviewComponent = "";
|
|
29
|
+
return {
|
|
30
|
+
name: "translime-sdk-plugin",
|
|
31
|
+
enforce: "pre",
|
|
32
|
+
// 确保在核心插件之前执行
|
|
33
|
+
// ----------------------------------------------------------------------
|
|
34
|
+
// Config Hook
|
|
35
|
+
// ----------------------------------------------------------------------
|
|
36
|
+
config(config, { mode, command }) {
|
|
37
|
+
isPreviewMode = mode === "preview";
|
|
38
|
+
if (options.previewComponent) {
|
|
39
|
+
resolvedPreviewComponent = options.previewComponent;
|
|
40
|
+
} else if (config.build?.lib?.entry) {
|
|
41
|
+
resolvedPreviewComponent = config.build.lib.entry;
|
|
42
|
+
}
|
|
43
|
+
if (resolvedPreviewComponent && !resolvedPreviewComponent.startsWith("./") && !resolvedPreviewComponent.startsWith("/")) {
|
|
44
|
+
resolvedPreviewComponent = `./${resolvedPreviewComponent}`;
|
|
45
|
+
}
|
|
46
|
+
const baseConfig = {
|
|
47
|
+
define: {
|
|
48
|
+
__TRANSLIME_PREVIEW__: isPreviewMode
|
|
49
|
+
// 注入全局变量供代码判断环境
|
|
50
|
+
},
|
|
51
|
+
build: {
|
|
52
|
+
rollupOptions: {
|
|
53
|
+
external: ["electron"],
|
|
54
|
+
// 永远排除 electron
|
|
55
|
+
output: {
|
|
56
|
+
globals: {
|
|
57
|
+
electron: "window.electron"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
if (isPreviewMode && command === "serve") {
|
|
64
|
+
const settingsPath = resolve(__dirname$1, "preview/settings.scss");
|
|
65
|
+
return {
|
|
66
|
+
...baseConfig,
|
|
67
|
+
// 切换为 SPA 模式 (非库模式)
|
|
68
|
+
build: {
|
|
69
|
+
lib: void 0,
|
|
70
|
+
rollupOptions: {
|
|
71
|
+
external: []
|
|
72
|
+
// Preview 模式下需要打包所有依赖
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
// 启用现代 Sass 编译器 (消除 Deprecation Warning)
|
|
76
|
+
css: {
|
|
77
|
+
preprocessorOptions: {
|
|
78
|
+
sass: { api: "modern-compiler" },
|
|
79
|
+
scss: { api: "modern-compiler" }
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
// 优化依赖: 排除 vuetify (使用我们注入的 mock/core)
|
|
83
|
+
optimizeDeps: {
|
|
84
|
+
exclude: ["vuetify"]
|
|
85
|
+
},
|
|
86
|
+
// 向下游插件传递配置 (如 vite-plugin-vuetify)
|
|
87
|
+
__translimeSdkPreview: {
|
|
88
|
+
settingsPath
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return baseConfig;
|
|
93
|
+
},
|
|
94
|
+
// ----------------------------------------------------------------------
|
|
95
|
+
// Configure Server (Preview Middleware)
|
|
96
|
+
// ----------------------------------------------------------------------
|
|
97
|
+
configureServer(server) {
|
|
98
|
+
if (!isPreviewMode) return;
|
|
99
|
+
server.middlewares.use((req, res, next) => {
|
|
100
|
+
if (req.url === "/" || req.url === "/index.html") {
|
|
101
|
+
const templatePath = resolve(__dirname$1, "../preview-template.html");
|
|
102
|
+
let html;
|
|
103
|
+
try {
|
|
104
|
+
html = readFileSync(templatePath, "utf-8");
|
|
105
|
+
} catch (e) {
|
|
106
|
+
html = getInlineTemplate();
|
|
107
|
+
}
|
|
108
|
+
html = html.replace("/__PREVIEW_ENTRY__", `/@id/${VIRTUAL_PREVIEW_ENTRY}`);
|
|
109
|
+
res.setHeader("Content-Type", "text/html");
|
|
110
|
+
res.end(html);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
next();
|
|
114
|
+
});
|
|
115
|
+
},
|
|
116
|
+
// ----------------------------------------------------------------------
|
|
117
|
+
// Resolve Id (Virtual Entry)
|
|
118
|
+
// ----------------------------------------------------------------------
|
|
119
|
+
resolveId(id) {
|
|
120
|
+
if (id === VIRTUAL_PREVIEW_ENTRY) {
|
|
121
|
+
return RESOLVED_VIRTUAL_PREVIEW_ENTRY;
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
},
|
|
125
|
+
// ----------------------------------------------------------------------
|
|
126
|
+
// Load (Virtual Entry Content)
|
|
127
|
+
// ----------------------------------------------------------------------
|
|
128
|
+
load(id) {
|
|
129
|
+
if (id === RESOLVED_VIRTUAL_PREVIEW_ENTRY) {
|
|
130
|
+
const componentPath = resolvedPreviewComponent || "./src/ui/ui.vue";
|
|
131
|
+
return `import { startPreview } from 'translime-sdk/preview';
|
|
132
|
+
import PluginComponent from '${componentPath}';
|
|
133
|
+
startPreview(PluginComponent);
|
|
134
|
+
`;
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
},
|
|
138
|
+
// ----------------------------------------------------------------------
|
|
139
|
+
// Transform (Auto-Import Components)
|
|
140
|
+
// ----------------------------------------------------------------------
|
|
141
|
+
transform(code, id) {
|
|
142
|
+
if (id.includes("node_modules") || id.startsWith("\0")) return null;
|
|
143
|
+
if (!/\.(js|ts|vue)$/.test(id)) return null;
|
|
144
|
+
const matches = /* @__PURE__ */ new Set();
|
|
145
|
+
const componentRegex = /\b(V[A-Z][\w$]+)\b/g;
|
|
146
|
+
let match;
|
|
147
|
+
while ((match = componentRegex.exec(code)) !== null) {
|
|
148
|
+
matches.add(match[1]);
|
|
149
|
+
}
|
|
150
|
+
if (id.endsWith(".vue")) {
|
|
151
|
+
const templateTagRegex = /<v-([a-z0-9-]+)\b/g;
|
|
152
|
+
while ((match = templateTagRegex.exec(code)) !== null) {
|
|
153
|
+
const name = `V${match[1].split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("")}`;
|
|
154
|
+
matches.add(name);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (matches.size === 0) return null;
|
|
158
|
+
const used = Array.from(matches).filter((name) => {
|
|
159
|
+
if (new RegExp(`import\\s+{[^}]*\\b${name}\\b[^}]*}\\s+from`, "m").test(code)) return false;
|
|
160
|
+
if (new RegExp(`(const|let|var|function|class|import)\\s+\\b${name}\\b`, "m").test(code)) return false;
|
|
161
|
+
if (new RegExp(`\\.\\b${name}\\b`).test(code)) return false;
|
|
162
|
+
return true;
|
|
163
|
+
});
|
|
164
|
+
if (used.length === 0) return null;
|
|
165
|
+
const injection = `
|
|
166
|
+
/* auto-injected by translime-sdk */
|
|
167
|
+
const { ${used.join(", ")} } = (typeof window !== 'undefined' && window.vuetify$?.components || {});
|
|
168
|
+
`;
|
|
169
|
+
let newCode = code;
|
|
170
|
+
if (id.endsWith(".vue")) {
|
|
171
|
+
if (code.includes("<script setup")) {
|
|
172
|
+
newCode = code.replace(/<script\s+setup[^>]*>/, `$&${injection}`);
|
|
173
|
+
} else if (code.includes("<script")) {
|
|
174
|
+
newCode = code.replace(/<script[^>]*>/, `$&${injection}`);
|
|
175
|
+
} else {
|
|
176
|
+
newCode = `<script setup>${injection}<\/script>
|
|
177
|
+
${code}`;
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
newCode = injection + code;
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
code: newCode,
|
|
184
|
+
map: null
|
|
185
|
+
// 可选:生成 sourcemap
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
export {
|
|
191
|
+
translimeSdk as default,
|
|
192
|
+
getPreviewSettingsPath,
|
|
193
|
+
translimeSdk
|
|
194
|
+
};
|
|
195
|
+
//# sourceMappingURL=vite-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite-plugin.js","sources":["../src/vite-plugin.js"],"sourcesContent":["import { fileURLToPath } from 'url';\nimport { dirname, resolve } from 'path';\nimport { readFileSync } from 'fs';\n\n// 获取当前模块所在目录\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// ----------------------------------------------------------------------\n// Constants\n// ----------------------------------------------------------------------\n\nconst VIRTUAL_PREVIEW_ENTRY = 'virtual:translime-preview-entry';\nconst RESOLVED_VIRTUAL_PREVIEW_ENTRY = `\\0${VIRTUAL_PREVIEW_ENTRY}`;\n\n// ----------------------------------------------------------------------\n// Helpers\n// ----------------------------------------------------------------------\n\n/**\n * 获取 Preview 模式的 Vuetify 样式配置文件路径\n * @description 用于 vite-plugin-vuetify 的 styles.configFile 配置\n * @returns {string} 绝对路径\n */\nexport function getPreviewSettingsPath() {\n return resolve(__dirname, 'preview/settings.scss');\n}\n\n/**\n * 内联的 HTML 模板\n * @description 当项目目录下找不到 preview-template.html 时使用的默认模板\n */\nfunction getInlineTemplate() {\n return `<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Plugin Preview</title>\n <link href=\"https://fonts.googleapis.com/icon?family=Material+Icons\" rel=\"stylesheet\">\n</head>\n<body>\n <div id=\"app\"></div>\n <script type=\"module\" src=\"/__PREVIEW_ENTRY__\"></script>\n</body>\n</html>`;\n}\n\n// ----------------------------------------------------------------------\n// Main Plugin\n// ----------------------------------------------------------------------\n\n/**\n * Translime SDK Vite Plugin\n *\n * 功能:\n * 1. **自动组件导入**: 扫描 Vue/JS 文件,自动从 `window.vuetify$.components` 注入使用到的 Vuetify 组件,\n * 避免在插件源码中手动 import Vuetify 组件 (减小插件体积).\n * 2. **Preview 模式支持**: 提供完整的本地预览环境,包含 HMR、Mock API 和样式注入.\n *\n * @param {Object} options - 插件选项\n * @param {string} [options.previewComponent] - Preview 模式下的入口组件路径 (默认为 build.lib.entry)\n * @returns {import('vite').Plugin}\n */\nexport function translimeSdk(options = {}) {\n let isPreviewMode = false;\n let resolvedPreviewComponent = '';\n\n return {\n name: 'translime-sdk-plugin',\n enforce: 'pre', // 确保在核心插件之前执行\n\n // ----------------------------------------------------------------------\n // Config Hook\n // ----------------------------------------------------------------------\n config(config, { mode, command }) {\n isPreviewMode = mode === 'preview';\n\n // 确定 Preview 入口组件路径\n if (options.previewComponent) {\n resolvedPreviewComponent = options.previewComponent;\n } else if (config.build?.lib?.entry) {\n // 尝试从 lib entry 推断\n resolvedPreviewComponent = config.build.lib.entry;\n }\n\n // 规范化路径 (Vite 需要 ./ 或 / 开头)\n if (resolvedPreviewComponent && !resolvedPreviewComponent.startsWith('./') && !resolvedPreviewComponent.startsWith('/')) {\n resolvedPreviewComponent = `./${resolvedPreviewComponent}`;\n }\n\n // 基础配置 (通用)\n const baseConfig = {\n define: {\n __TRANSLIME_PREVIEW__: isPreviewMode, // 注入全局变量供代码判断环境\n },\n build: {\n rollupOptions: {\n external: ['electron'], // 永远排除 electron\n output: {\n globals: {\n electron: 'window.electron',\n },\n },\n },\n },\n };\n\n // Preview 模式特殊配置 (仅在 serve 阶段生效)\n if (isPreviewMode && command === 'serve') {\n const settingsPath = resolve(__dirname, 'preview/settings.scss');\n\n return {\n ...baseConfig,\n // 切换为 SPA 模式 (非库模式)\n build: {\n lib: undefined,\n rollupOptions: {\n external: [], // Preview 模式下需要打包所有依赖\n },\n },\n // 启用现代 Sass 编译器 (消除 Deprecation Warning)\n css: {\n preprocessorOptions: {\n sass: { api: 'modern-compiler' },\n scss: { api: 'modern-compiler' },\n },\n },\n // 优化依赖: 排除 vuetify (使用我们注入的 mock/core)\n optimizeDeps: {\n exclude: ['vuetify'],\n },\n // 向下游插件传递配置 (如 vite-plugin-vuetify)\n __translimeSdkPreview: {\n settingsPath,\n },\n };\n }\n\n return baseConfig;\n },\n\n // ----------------------------------------------------------------------\n // Configure Server (Preview Middleware)\n // ----------------------------------------------------------------------\n configureServer(server) {\n if (!isPreviewMode) return;\n\n // 拦截 index.html 请求,提供 Preview 模板\n server.middlewares.use((req, res, next) => {\n if (req.url === '/' || req.url === '/index.html') {\n const templatePath = resolve(__dirname, '../preview-template.html');\n let html;\n try {\n html = readFileSync(templatePath, 'utf-8');\n } catch (e) {\n html = getInlineTemplate();\n }\n\n // 注入虚拟入口\n html = html.replace('/__PREVIEW_ENTRY__', `/@id/${VIRTUAL_PREVIEW_ENTRY}`);\n\n res.setHeader('Content-Type', 'text/html');\n res.end(html);\n return;\n }\n next();\n });\n },\n\n // ----------------------------------------------------------------------\n // Resolve Id (Virtual Entry)\n // ----------------------------------------------------------------------\n resolveId(id) {\n if (id === VIRTUAL_PREVIEW_ENTRY) {\n return RESOLVED_VIRTUAL_PREVIEW_ENTRY;\n }\n return null;\n },\n\n // ----------------------------------------------------------------------\n // Load (Virtual Entry Content)\n // ----------------------------------------------------------------------\n load(id) {\n if (id === RESOLVED_VIRTUAL_PREVIEW_ENTRY) {\n // 生成引导代码:导入 Preview 框架 + 用户插件组件\n const componentPath = resolvedPreviewComponent || './src/ui/ui.vue';\n return `import { startPreview } from 'translime-sdk/preview';\nimport PluginComponent from '${componentPath}';\nstartPreview(PluginComponent);\n`;\n }\n return null;\n },\n\n // ----------------------------------------------------------------------\n // Transform (Auto-Import Components)\n // ----------------------------------------------------------------------\n transform(code, id) {\n // 忽略不需要处理的文件\n if (id.includes('node_modules') || id.startsWith('\\0')) return null;\n if (!/\\.(js|ts|vue)$/.test(id)) return null;\n\n const matches = new Set();\n\n // 扫描 JS/TS 中的组件名 (e.g. VBtn, VCard)\n const componentRegex = /\\b(V[A-Z][\\w$]+)\\b/g;\n let match;\n while ((match = componentRegex.exec(code)) !== null) {\n matches.add(match[1]);\n }\n\n // 扫描 Vue 模板中的 kebab-case 标签 (e.g. <v-btn>)\n if (id.endsWith('.vue')) {\n const templateTagRegex = /<v-([a-z0-9-]+)\\b/g;\n while ((match = templateTagRegex.exec(code)) !== null) {\n // camelCase 转换: v-btn -> VBtn\n const name = `V${match[1].split('-').map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join('')}`;\n matches.add(name);\n }\n }\n\n if (matches.size === 0) return null;\n\n // 过滤掉已从其他地方导入或定义的变量\n const used = Array.from(matches).filter((name) => {\n // 检查 import 语句\n if (new RegExp(`import\\\\s+{[^}]*\\\\b${name}\\\\b[^}]*}\\\\s+from`, 'm').test(code)) return false;\n // 检查局部变量定义 (const, let, function, class)\n if (new RegExp(`(const|let|var|function|class|import)\\\\s+\\\\b${name}\\\\b`, 'm').test(code)) return false;\n // 检查属性访问 (e.g. something.VBtn)\n if (new RegExp(`\\\\.\\\\b${name}\\\\b`).test(code)) return false;\n return true;\n });\n\n if (used.length === 0) return null;\n\n // 注入代码\n // 如果运行在 Render 进程 (有 window.vuetify$),则从中解构;否则为空对象\n const injection = `\\n/* auto-injected by translime-sdk */\\nconst { ${used.join(', ')} } = (typeof window !== 'undefined' && window.vuetify$?.components || {});\\n`;\n\n let newCode = code;\n if (id.endsWith('.vue')) {\n if (code.includes('<script setup')) {\n newCode = code.replace(/<script\\s+setup[^>]*>/, `$&${injection}`);\n } else if (code.includes('<script')) {\n newCode = code.replace(/<script[^>]*>/, `$&${injection}`);\n } else {\n // 无 script 标签时,创建 <script setup> (常见于纯模板 Vue 文件)\n newCode = `<script setup>${injection}</script>\\n${code}`;\n }\n } else {\n newCode = injection + code;\n }\n\n return {\n code: newCode,\n map: null, // 可选:生成 sourcemap\n };\n },\n };\n}\n\nexport default translimeSdk;\n\n"],"names":["__filename","__dirname"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "translime-sdk",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "SDK for Translime plugins",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"require": {
|
|
19
|
+
"types": "./dist/index.d.cts",
|
|
20
|
+
"default": "./dist/index.cjs"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"./vite": {
|
|
24
|
+
"import": {
|
|
25
|
+
"types": "./dist/vite-plugin.d.ts",
|
|
26
|
+
"default": "./dist/vite-plugin.js"
|
|
27
|
+
},
|
|
28
|
+
"require": {
|
|
29
|
+
"types": "./dist/vite-plugin.d.cts",
|
|
30
|
+
"default": "./dist/vite-plugin.cjs"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"./preview": {
|
|
34
|
+
"import": {
|
|
35
|
+
"default": "./dist/preview.js"
|
|
36
|
+
},
|
|
37
|
+
"require": {
|
|
38
|
+
"default": "./dist/preview.cjs"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"./preview-mock": {
|
|
42
|
+
"import": {
|
|
43
|
+
"default": "./dist/preview-mock.js"
|
|
44
|
+
},
|
|
45
|
+
"require": {
|
|
46
|
+
"default": "./dist/preview-mock.cjs"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"author": "slime7",
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"keywords": [
|
|
53
|
+
"translime",
|
|
54
|
+
"sdk",
|
|
55
|
+
"plugin",
|
|
56
|
+
"preview"
|
|
57
|
+
],
|
|
58
|
+
"scripts": {
|
|
59
|
+
"lint": "eslint src --ext .js,.vue --fix",
|
|
60
|
+
"lint:style": "stylelint src/**/*.{vue,scss} --fix",
|
|
61
|
+
"build": "vite build && node scripts/post-build.mjs",
|
|
62
|
+
"prepublishOnly": "npm run build"
|
|
63
|
+
},
|
|
64
|
+
"engines": {
|
|
65
|
+
"node": ">=16.0.0"
|
|
66
|
+
},
|
|
67
|
+
"peerDependencies": {
|
|
68
|
+
"vue": "^3.0.0",
|
|
69
|
+
"vuetify": "^3.0.0"
|
|
70
|
+
},
|
|
71
|
+
"peerDependenciesMeta": {
|
|
72
|
+
"vue": {
|
|
73
|
+
"optional": true
|
|
74
|
+
},
|
|
75
|
+
"vuetify": {
|
|
76
|
+
"optional": true
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"devDependencies": {
|
|
80
|
+
"@eslint/eslintrc": "^3.0.0",
|
|
81
|
+
"@eslint/js": "^9.0.0",
|
|
82
|
+
"@stylistic/stylelint-plugin": "^3.0.0",
|
|
83
|
+
"@vitejs/plugin-vue": "^6.0.3",
|
|
84
|
+
"eslint": "^9.0.0",
|
|
85
|
+
"eslint-config-airbnb-base": "^15.0.0",
|
|
86
|
+
"eslint-plugin-import": "^2.31.0",
|
|
87
|
+
"eslint-plugin-vue": "^10.0.0",
|
|
88
|
+
"globals": "^16.0.0",
|
|
89
|
+
"postcss-html": "^1.5.0",
|
|
90
|
+
"postcss-scss": "^4.0.0",
|
|
91
|
+
"stylelint": "^16.0.0",
|
|
92
|
+
"stylelint-config-recommended-vue": "^1.5.0",
|
|
93
|
+
"stylelint-config-standard-scss": "^14.0.0",
|
|
94
|
+
"stylelint-scss": "^6.0.0",
|
|
95
|
+
"vite": "^7.3.1",
|
|
96
|
+
"vite-plugin-vuetify": "^2.1.1",
|
|
97
|
+
"vuetify": "^3.11.6"
|
|
98
|
+
}
|
|
99
|
+
}
|