feat: 支持定义出码文件路径

This commit is contained in:
“chenhuachun”
2025-07-28 17:22:09 +08:00
parent 10f8e0b252
commit 088f015dcf
6 changed files with 243 additions and 96 deletions

View File

@@ -168,7 +168,7 @@ export interface CreateViteConfigOptions {
/**
* 库模式编译css输出文件名不包含后缀名
*/
cssFileName: string;
cssFileName?: string;
/**
* 自定义 chunk name, 在库模式无效

View File

@@ -23,65 +23,65 @@ const controller: Controller = {
},
getExtension: service.getExtension,
init: service.init,
saveProject: async (req: ApiRequest) => {
saveProject: async (req: ApiRequest, opts: DevToolsOptions) => {
const project = req.data as ProjectSchema;
return service.saveProject(project, req.query?.type);
return service.saveProject(project, req.query?.type, opts);
},
saveFile: async (req: ApiRequest) => {
saveFile: async (req: ApiRequest, opts: DevToolsOptions) => {
const file = req.data as BlockSchema;
return service.saveFile(file);
return service.saveFile(file, opts);
},
getFile: async (req: ApiRequest) => {
getFile: async (req: ApiRequest, opts: DevToolsOptions) => {
const id = req.data as string;
return service.getFile(id);
return service.getFile(id, opts);
},
removeFile: async (req: ApiRequest) => {
removeFile: async (req: ApiRequest, opts: DevToolsOptions) => {
const id = req.data as string;
return service.removeFile(id);
return service.removeFile(id, opts);
},
getHistory: async (req: ApiRequest) => {
getHistory: async (req: ApiRequest, opts: DevToolsOptions) => {
const id = req.data as string;
return service.getHistory(id);
return service.getHistory(id, opts);
},
saveHistory: async (req: ApiRequest) => {
saveHistory: async (req: ApiRequest, opts: DevToolsOptions) => {
const file = req.data as HistorySchema;
return service.saveHistory(file);
return service.saveHistory(file, opts);
},
removeHistory: async (req: ApiRequest) => {
removeHistory: async (req: ApiRequest, opts: DevToolsOptions) => {
const id = req.data as string;
return service.removeHistory(id);
return service.removeHistory(id, opts);
},
getHistoryItem: async (req: ApiRequest) => {
getHistoryItem: async (req: ApiRequest, opts: DevToolsOptions) => {
const { fId, id } = req.data || {};
return service.getHistoryItem(fId, id);
return service.getHistoryItem(fId, id, opts);
},
saveHistoryItem: async (req: ApiRequest) => {
saveHistoryItem: async (req: ApiRequest, opts: DevToolsOptions) => {
const { fId, item } = req.data || {};
return service.saveHistoryItem(fId, item);
return service.saveHistoryItem(fId, item, opts);
},
removeHistoryItem: async (req: ApiRequest) => {
removeHistoryItem: async (req: ApiRequest, opts: DevToolsOptions) => {
const { fId, ids = [] } = req.data || {};
return service.removeHistoryItem(fId, ids);
return service.removeHistoryItem(fId, ids, opts);
},
saveMaterials: async (req: ApiRequest) => {
saveMaterials: async (req: ApiRequest, opts: DevToolsOptions) => {
const { project, materials } = req.data || {};
return service.saveMaterials(project, materials);
return service.saveMaterials(project, materials, opts);
},
publishFile: async (req: ApiRequest) => {
publishFile: async (req: ApiRequest, opts: DevToolsOptions) => {
const { project, file } = req.data || {};
const result = await service.publishFile(project, file);
const result = await service.publishFile(project, file, undefined, opts);
if (project.platform === 'uniapp') {
await service.genUniConfig(project, true);
}
return result;
},
publish: async (req: ApiRequest) => {
publish: async (req: ApiRequest, opts: DevToolsOptions) => {
const project = req.data || {};
return service.publish(project);
return service.publish(project, opts);
},
genVueContent: async (req: ApiRequest) => {
genVueContent: async (req: ApiRequest, opts: DevToolsOptions) => {
const { project, dsl } = req.data || {};
return service.genVueContent(project, dsl);
return service.genVueContent(project, dsl, opts);
},
parseVue: async (req: ApiRequest) => {
const { id, name, source, project } = req.data || {};
@@ -92,26 +92,38 @@ const controller: Controller = {
project
});
},
createRawPage: async (req: ApiRequest) => {
createRawPage: async (req: ApiRequest, opts: DevToolsOptions) => {
const file = req.data as PageFile;
return service.createRawPage(file);
return service.createRawPage(file, opts);
},
removeRawPage: async (req: ApiRequest) => {
removeRawPage: async (req: ApiRequest, opts: DevToolsOptions) => {
const id = req.data as string;
return service.removeRawPage(id);
return service.removeRawPage(id, opts);
},
getStaticFiles: async (_req: ApiRequest, opts?: DevToolsOptions) => {
return service.getStaticFiles(opts as any);
getStaticFiles: async (_req: ApiRequest, opts: DevToolsOptions) => {
return service.getStaticFiles({
staticBase: opts.staticBase,
staticDir: opts.staticDir,
vtjDir: opts.vtjStaticDir || opts.vtjDir
});
},
removeStaticFile: async (req: ApiRequest, opts?: DevToolsOptions) => {
removeStaticFile: async (req: ApiRequest, opts: DevToolsOptions) => {
const name = req.data?.name as string;
return service.removeStaticFile(name, opts as any);
return service.removeStaticFile(name, {
staticBase: opts.staticBase,
staticDir: opts.staticDir,
vtjDir: opts.vtjStaticDir || opts.vtjDir
});
},
clearStaticFiles: async (_req: ApiRequest, opts?: DevToolsOptions) => {
return service.clearStaticFiles(opts as any);
clearStaticFiles: async (_req: ApiRequest, opts: DevToolsOptions) => {
return service.clearStaticFiles({
staticBase: opts.staticBase,
staticDir: opts.staticDir,
vtjDir: opts.vtjStaticDir || opts.vtjDir
});
},
uploader: async (req: any, opts?: DevToolsOptions) => {
uploader: async (req: any, opts: DevToolsOptions) => {
if (!opts) return fail('异常错误');
const uploadDir = resolve(opts.staticDir, opts.vtjDir);
const form = formidable({
@@ -127,7 +139,11 @@ const controller: Controller = {
return;
}
const tempFiles = files.files || [];
const result = service.uploadStaticFiles(tempFiles, opts as any);
const result = service.uploadStaticFiles(tempFiles, {
staticBase: opts.staticBase,
staticDir: opts.staticDir,
vtjDir: opts.vtjStaticDir || opts.vtjDir
});
reslove(result);
});
});
@@ -182,7 +198,7 @@ export const router = async (req: any, opts: DevToolsOptions) => {
stack: e?.stack
}
};
await service.saveLogs(info);
await service.saveLogs(info, opts);
return fail('异常错误', e?.message, e?.stack);
}
}

View File

@@ -25,7 +25,12 @@ export interface DevToolsOptions {
staticDir: string;
link: boolean | string;
linkOptions: LinkOptions | null;
// 本地文件存储目录
vtjDir: string;
// 本地文件静态文件目录, 必须要在staticDir的目录下
vtjStaticDir: string;
// 本地出码vue页面文件目录独立于vtjDir
vtjRawDir: string;
packagesDir: string;
devMode: boolean;
uploader: string;
@@ -344,6 +349,8 @@ export function createDevTools(options: Partial<DevToolsOptions> = {}) {
link: true,
linkOptions: null,
vtjDir: '.vtj',
vtjStaticDir: '.vtj',
vtjRawDir: '.vtj/vue',
packagesDir: '../../packages',
devMode: false,
uploader: '/uploader.json',

View File

@@ -9,12 +9,18 @@ import {
import type { PlatformType } from '@vtj/core';
export interface JsonRepositoryOptions {
dir: string;
platform: PlatformType;
category: string;
}
export class JsonRepository {
private path: string;
constructor(path: string, platform: PlatformType = 'web') {
const dir = platform === 'uniapp' ? 'src/.vtj' : '.vtj';
// const dir = '.vtj';
this.path = resolve(dir, path);
constructor(options: JsonRepositoryOptions) {
const { dir = '.vtj', platform = 'web', category } = options;
const _dir = platform === 'uniapp' ? `src/${dir}` : dir;
this.path = resolve(_dir, category);
}
exist(name: string) {
const filePath = join(this.path, `${name}.json`);

View File

@@ -8,11 +8,18 @@ import {
import type { PlatformType } from '@vtj/core';
export interface VueRepositoryOptions {
dir: string;
platform: PlatformType;
}
export class VueRepository {
private path: string;
constructor(platform: PlatformType = 'web') {
const dir = platform === 'uniapp' ? 'src/pages' : '.vtj/vue';
this.path = resolve(dir);
constructor(options: VueRepositoryOptions) {
const { dir = '.vtj/vue', platform = 'web' } = options;
// uniapp不支持自定义定义
const _dir = platform === 'uniapp' ? `src/pages` : dir;
this.path = resolve(_dir);
}
exist(name: string) {
const filePath = join(this.path, `${name}.vue`);

View File

@@ -42,9 +42,13 @@ export async function notMatch(_req: ApiRequest) {
return fail('找不到处理程序');
}
export async function saveLogs(e: any) {
export async function saveLogs(e: any, opts: DevToolsOptions) {
const name = `error-${timestamp()}`;
const logs = new JsonRepository('logs', _platform);
const logs = new JsonRepository({
platform: _platform,
dir: opts.vtjDir,
category: 'logs'
});
const json = JSON.parse(JSON.stringify(e));
return logs.save(name, json);
}
@@ -102,7 +106,11 @@ export async function init(_body: any, opts: DevToolsOptions) {
const description = vtj.description || pkg.description || '';
const platform = vtj.platform || 'web';
_platform = platform;
const repository = new JsonRepository('projects', _platform);
const repository = new JsonRepository({
platform: _platform,
dir: opts.vtjDir,
category: 'projects'
});
// 如果项目文件已经存在,则直接返回文件内容
let dsl: ProjectSchema = repository.get(id);
const plugins = pluginPepository.getPlugins();
@@ -141,8 +149,16 @@ export async function init(_body: any, opts: DevToolsOptions) {
}
}
export async function saveProject(dsl: ProjectSchema, type?: string) {
const repository = new JsonRepository('projects', dsl.platform);
export async function saveProject(
dsl: ProjectSchema,
type: string,
opts: DevToolsOptions
) {
const repository = new JsonRepository({
platform: dsl.platform || 'web',
dir: opts.vtjDir,
category: 'projects'
});
if (repository.exist(dsl.id as string)) {
const ret = repository.save(dsl.id as string, dsl);
if (dsl.platform === 'uniapp') {
@@ -154,14 +170,22 @@ export async function saveProject(dsl: ProjectSchema, type?: string) {
}
}
export async function saveFile(dsl: BlockSchema) {
const repository = new JsonRepository('files', _platform);
export async function saveFile(dsl: BlockSchema, opts: DevToolsOptions) {
const repository = new JsonRepository({
platform: _platform,
dir: opts.vtjDir,
category: 'files'
});
const ret = repository.save(dsl.id as string, dsl);
return success(ret);
}
export async function getFile(id: string) {
const repository = new JsonRepository('files', _platform);
export async function getFile(id: string, opts: DevToolsOptions) {
const repository = new JsonRepository({
platform: _platform,
dir: opts.vtjDir,
category: 'files'
});
const json = repository.get(id);
if (json) {
return success(json);
@@ -170,14 +194,22 @@ export async function getFile(id: string) {
}
}
export async function removeFile(id: string) {
const repository = new JsonRepository('files', _platform);
export async function removeFile(id: string, opts: DevToolsOptions) {
const repository = new JsonRepository({
platform: _platform,
dir: opts.vtjDir,
category: 'files'
});
const ret = repository.remove(id);
return success(ret);
}
export async function getHistory(id: string) {
const repository = new JsonRepository('histories', _platform);
export async function getHistory(id: string, opts: DevToolsOptions) {
const repository = new JsonRepository({
platform: _platform,
dir: opts.vtjDir,
category: 'histories'
});
const json = repository.get(id);
if (json) {
return success(json);
@@ -186,22 +218,44 @@ export async function getHistory(id: string) {
}
}
export async function saveHistory(file: HistorySchema) {
const repository = new JsonRepository('histories', _platform);
export async function saveHistory(file: HistorySchema, opts: DevToolsOptions) {
const repository = new JsonRepository({
platform: _platform,
dir: opts.vtjDir,
category: 'histories'
});
const ret = repository.save(file.id as string, file);
return success(ret);
}
export async function removeHistory(id: string) {
const repository = new JsonRepository('histories', _platform);
const items = new JsonRepository(`histories/${id}`, _platform);
export async function removeHistory(id: string, opts: DevToolsOptions) {
const repository = new JsonRepository({
platform: _platform,
dir: opts.vtjDir,
category: 'histories'
});
const items = new JsonRepository({
platform: _platform,
dir: opts.vtjDir,
category: `histories/${id}`
});
items.clear();
repository.remove(id);
return success(true);
}
export async function getHistoryItem(fId: string, id: string) {
const repository = new JsonRepository(`histories/${fId}`, _platform);
export async function getHistoryItem(
fId: string,
id: string,
opts: DevToolsOptions
) {
const repository = new JsonRepository({
platform: _platform,
dir: opts.vtjDir,
category: `histories/${fId}`
});
const json = repository.get(id);
if (json) {
return success(json);
@@ -210,14 +264,30 @@ export async function getHistoryItem(fId: string, id: string) {
}
}
export async function saveHistoryItem(fId: string, item: HistoryItem) {
const repository = new JsonRepository(`histories/${fId}`, _platform);
export async function saveHistoryItem(
fId: string,
item: HistoryItem,
opts: DevToolsOptions
) {
const repository = new JsonRepository({
platform: _platform,
dir: opts.vtjDir,
category: `histories/${fId}`
});
repository.save(item.id, item);
return success(true);
}
export async function removeHistoryItem(fId: string, ids: string[]) {
const repository = new JsonRepository(`histories/${fId}`, _platform);
export async function removeHistoryItem(
fId: string,
ids: string[],
opts: DevToolsOptions
) {
const repository = new JsonRepository({
platform: _platform,
dir: opts.vtjDir,
category: `histories/${fId}`
});
ids.forEach((id: string) => {
repository.remove(id);
@@ -228,9 +298,14 @@ export async function removeHistoryItem(fId: string, ids: string[]) {
export async function saveMaterials(
project: ProjectSchema,
materials: Record<string, MaterialDescription>
materials: Record<string, MaterialDescription>,
opts: DevToolsOptions
) {
const repository = new JsonRepository('materials', _platform);
const repository = new JsonRepository({
platform: _platform,
dir: opts.vtjDir,
category: 'materials'
});
repository.save(project.id as string, materials);
return success(true);
}
@@ -238,14 +313,24 @@ export async function saveMaterials(
export async function publishFile(
project: ProjectSchema,
file: PageFile | BlockFile,
componentMap?: Map<string, MaterialDescription>
componentMap: Map<string, MaterialDescription> | undefined,
opts: DevToolsOptions
) {
const materialsRepository = new JsonRepository('materials', project.platform);
const materialsRepository = new JsonRepository({
platform: _platform,
dir: opts.vtjDir,
category: 'materials'
});
const materials = materialsRepository.get(project.id as string);
componentMap =
componentMap ||
new Map<string, MaterialDescription>(Object.entries(materials || {}));
const fileRepository = new JsonRepository('files', project.platform);
const fileRepository = new JsonRepository({
platform: project.platform || _platform,
dir: opts.vtjDir,
category: 'files'
});
const dsl = fileRepository.get(file.id as string);
if (dsl) {
const content = await generator(
@@ -255,17 +340,23 @@ export async function publishFile(
project.platform
).catch((e) => {
try {
saveLogs({
dsl: dsl,
componentMap,
dependencies: project.dependencies,
message: e.message,
stack: e.stack
});
saveLogs(
{
dsl: dsl,
componentMap,
dependencies: project.dependencies,
message: e.message,
stack: e.stack
},
opts
);
} catch (e) {}
throw e;
});
const vueRepository = new VueRepository(_platform);
const vueRepository = new VueRepository({
platform: _platform,
dir: opts.vtjRawDir
});
vueRepository.save(file.id as string, content);
return success(true);
} else {
@@ -273,9 +364,14 @@ export async function publishFile(
}
}
export async function publish(project: ProjectSchema) {
export async function publish(project: ProjectSchema, opts: DevToolsOptions) {
const { pages = [], blocks = [] } = project;
const materialsRepository = new JsonRepository('materials', project.platform);
const materialsRepository = new JsonRepository({
platform: project.platform || _platform,
dir: opts.vtjDir,
category: 'materials'
});
const materials = materialsRepository.get(project.id as string);
const componentMap = new Map<string, MaterialDescription>(
Object.entries(materials)
@@ -283,12 +379,12 @@ export async function publish(project: ProjectSchema) {
for (const block of blocks) {
if (!block.fromType || block.fromType === 'Schema') {
await publishFile(project, block, componentMap);
await publishFile(project, block, componentMap, opts);
}
}
for (const page of pages) {
if (!page.raw) {
await publishFile(project, page, componentMap);
await publishFile(project, page, componentMap, opts);
}
}
if (project.platform === 'uniapp') {
@@ -311,8 +407,16 @@ export async function genUniConfig(
return success(true);
}
export async function genVueContent(project: ProjectSchema, dsl: BlockSchema) {
const materialsRepository = new JsonRepository('materials', project.platform);
export async function genVueContent(
project: ProjectSchema,
dsl: BlockSchema,
opts: DevToolsOptions
) {
const materialsRepository = new JsonRepository({
platform: project.platform || _platform,
dir: opts.vtjDir,
category: 'materials'
});
const materials = materialsRepository.get(project.id as string);
const componentMap = new Map<string, MaterialDescription>(
Object.entries(materials || {})
@@ -338,15 +442,22 @@ export async function parseVue(options: IParseVueOptions) {
return success(errors ? errors : dsl);
}
export async function createRawPage(file: PageFile) {
const repository = new VueRepository(_platform);
export async function createRawPage(file: PageFile, opts: DevToolsOptions) {
const repository = new VueRepository({
platform: _platform,
dir: opts.vtjRawDir
});
const page = await createEmptyPage(file);
repository.save(file.id as string, page);
return success(true);
}
export async function removeRawPage(id: string) {
const repository = new VueRepository(_platform);
export async function removeRawPage(id: string, opts: DevToolsOptions) {
const repository = new VueRepository({
platform: _platform,
dir: opts.vtjRawDir
});
repository.remove(id);
return success(true);
}