Browse Source

新增设置模块功能并重构工具类代码

- 新增 `electron.vite.config.1749712333417.mjs` 配置文件,配置Vite构建相关插件和参数
- 创建 `packages/utils/index.ts` 工具类文件,添加通用工具函数 `isPromise` 和 `slash`
- 扩展 `packages/utils/main/index.ts` 工具类,新增 `getFileUrl` 和 `getPreloadUrl` 方法
- 新增 `packages/utils/main/session/cookies.ts` 实现Electron会话cookie管理功能
- 新增 `packages/utils/main/session/index.ts` 实现Electron多会话隔离功能
- 重构多处代码引用路径,将原 `main/utils` 迁移至 `packages/utils` 统一管理
- 新增设置模块相关代码:`src/common/event/Setting/*` 实现配置同步保存功能
- 新增设置页面 `src/renderer/src/pages/setting/index.vue` 提供UI交互
- 优化导航栏菜单逻辑,移除模块切换功能,整合为统一菜单
main
谢亚昕 6 days ago
parent
commit
0433b60dfc
  1. 133
      electron.vite.config.1749712333417.mjs
  2. 11
      packages/utils/index.ts
  3. 17
      packages/utils/main/index.ts
  4. 0
      packages/utils/main/session/cookies.ts
  5. 0
      packages/utils/main/session/index.ts
  6. 2
      src/common/event/PlatForm/main/command.ts
  7. 63
      src/common/event/Setting/hook.ts
  8. 23
      src/common/event/Setting/index.ts
  9. 13
      src/common/event/Setting/main/command.ts
  10. 16
      src/common/event/Updater/hook.ts
  11. 18
      src/common/event/Updater/index.ts
  12. 17
      src/common/lib/abstract.ts
  13. 5
      src/common/lib/browser.ts
  14. 5
      src/common/lib/electron.ts
  15. 2
      src/main/modules/commands/index.ts
  16. 2
      src/main/modules/window-manager/windowsMap.ts
  17. 28
      src/main/utils/index.ts
  18. 4
      src/renderer/src/pages/index/index.vue
  19. 18
      src/renderer/src/pages/setting/index.vue
  20. 9
      src/renderer/src/store/index.ts
  21. 30
      src/renderer/src/store/module.store.ts
  22. 126
      src/renderer/src/ui/NavBar.vue
  23. 1
      src/renderer/typed-router.d.ts
  24. 4
      tsconfig.node.json

133
electron.vite.config.1749712333417.mjs

@ -0,0 +1,133 @@
// electron.vite.config.ts
import { resolve } from "path";
import { defineConfig, externalizeDepsPlugin } from "electron-vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx";
import UnoCSS from "unocss/vite";
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import VueMacros from "unplugin-vue-macros/vite";
import { VueRouterAutoImports } from "unplugin-vue-router";
import VueRouter from "unplugin-vue-router/vite";
import Layouts from "vite-plugin-vue-layouts";
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
import monacoEditorPlugin from "vite-plugin-monaco-editor";
import IconsResolver from "unplugin-icons/resolver";
import Icons from "unplugin-icons/vite";
var __electron_vite_injected_dirname = "D:\\@code\\xyx\\electron-app";
var electron_vite_config_default = defineConfig({
main: {
resolve: {
alias: {
config: resolve("config"),
main: resolve("src/main"),
common: resolve("src/common"),
"@res": resolve("resources")
}
},
plugins: [externalizeDepsPlugin()]
},
preload: {
build: {
lib: {
entry: {
index: resolve(__electron_vite_injected_dirname, "./src/preload/index.ts"),
plugin: resolve(__electron_vite_injected_dirname, "./src/preload/plugin.ts")
}
}
},
plugins: [externalizeDepsPlugin()]
},
renderer: {
root: resolve(__electron_vite_injected_dirname, "./src/renderer"),
resolve: {
alias: {
config: resolve("config"),
common: resolve("src/common"),
"@": resolve("src/renderer/src"),
"@res": resolve("resources")
}
},
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/assets/style/global" as *;
`,
api: "modern-compiler"
}
}
},
build: {
rollupOptions: {
input: {
main: resolve(__electron_vite_injected_dirname, "./src/renderer/index.html"),
about: resolve(__electron_vite_injected_dirname, "./src/renderer/about.html")
}
}
},
plugins: [
UnoCSS(),
VueMacros({
plugins: {
vue: vue(),
vueJsx: vueJsx(),
vueRouter: VueRouter({
root: resolve(__electron_vite_injected_dirname, "src/renderer"),
// https://github.com/posva/unplugin-vue-router
extensions: [".vue", ".setup.tsx"],
exclude: ["**/_ui"]
})
}
}),
VueI18nPlugin({
compositionOnly: false,
include: resolve(__electron_vite_injected_dirname, "packages/locales/languages/**")
}),
Layouts({
layoutsDirs: "src/layouts",
pagesDirs: "src/pages",
defaultLayout: "default",
extensions: ["vue", "setup.tsx"],
exclude: ["**/_ui"]
}),
// https://github.com/antfu/unplugin-auto-import
AutoImport({
imports: [
"vue",
"@vueuse/core",
VueRouterAutoImports,
{
// add any other imports you were relying on
"vue-router/auto": ["useLink"]
},
"vue-i18n"
],
dts: true,
dirs: ["src/composables"],
vueTemplate: true
}),
// https://github.com/antfu/vite-plugin-components
Components({
dts: true,
dirs: ["src/components", "src/ui"],
resolvers: [
IconsResolver({
prefix: "icon"
})
]
}),
Icons(),
// https://wf0.github.io/example/plugins/Formatter.html
// @ts-ignore ...
monacoEditorPlugin.default({
publicPath: "monacoeditorwork",
customDistPath() {
return resolve(__electron_vite_injected_dirname, "out/renderer/monacoeditorwork");
}
})
]
}
});
export {
electron_vite_config_default as default
};

11
packages/utils/index.ts

@ -0,0 +1,11 @@
export function isPromise(value: () => any) {
return value && Object.prototype.toString.call(value) === "[object Promise]"
}
export function slash(path: string) {
const isExtendedLengthPath = path.startsWith("\\\\?\\")
if (isExtendedLengthPath) {
return path
}
return path.replace(/\\/g, "/")
}

17
packages/utils/main/index.ts

@ -1,5 +1,22 @@
import { is } from "@electron-toolkit/utils"
import { webContents } from "electron" import { webContents } from "electron"
import { join } from "node:path"
import { slash } from "utils"
export const broadcast = <T extends Record<string, (...argu: any[]) => void>>(event: keyof T, ...args: Parameters<T[keyof T]>) => { export const broadcast = <T extends Record<string, (...argu: any[]) => void>>(event: keyof T, ...args: Parameters<T[keyof T]>) => {
webContents.getAllWebContents().forEach(browser => browser.send(event as any, ...args)) webContents.getAllWebContents().forEach(browser => browser.send(event as any, ...args))
} }
export function getFileUrl(app: string) {
let winURL = ""
if (is.dev && process.env["ELECTRON_RENDERER_URL"]) {
winURL = process.env["ELECTRON_RENDERER_URL"] + `/${app}#/`
} else {
winURL = join(__dirname, `../renderer/${app}#/`)
}
return slash(winURL)
}
export function getPreloadUrl(file) {
return join(__dirname, `../preload/${file}.mjs`)
}

0
src/main/utils/session/cookies.ts → packages/utils/main/session/cookies.ts

0
src/main/utils/session/index.ts → packages/utils/main/session/index.ts

2
src/common/event/PlatForm/main/command.ts

@ -3,10 +3,10 @@ import { inject } from "inversify"
import errorHandler from "logger/main-error" import errorHandler from "logger/main-error"
import Tabs from "main/modules/tabs" import Tabs from "main/modules/tabs"
import WindowManager from "main/modules/window-manager" import WindowManager from "main/modules/window-manager"
import { getFileUrl } from "main/utils"
import icon from "@res/icon.png?asset" import icon from "@res/icon.png?asset"
import setting from "setting/main" import setting from "setting/main"
import { LogLevel } from "logger/common" import { LogLevel } from "logger/common"
import { getFileUrl } from "utils/main"
export default class PlatFormCommand { export default class PlatFormCommand {
constructor( constructor(

63
src/common/event/Setting/hook.ts

@ -0,0 +1,63 @@
import { defineStore } from "pinia"
import { Setting } from "."
import type { IConfig } from "config"
let rawConfig: IConfig = Setting.getInstance().sync() as unknown as IConfig
export const useSettingStore = defineStore(
"Setting",
() => {
const config = ref(JSON.parse(JSON.stringify(rawConfig)))
const diffKeys = ref<(keyof IConfig)[]>([])
const isSame = computed(() => {
return diffKeys.value.length === 0
})
watch(
() => config.value,
() => {
diffKeys.value = []
;(Object.keys(config.value) as (keyof IConfig)[]).forEach((key: keyof IConfig) => {
if (config.value[key] !== rawConfig[key]) {
diffKeys.value.push(key)
}
})
},
{
deep: true,
immediate: true,
},
)
const reset = () => {
const tempConfig = JSON.parse(JSON.stringify(rawConfig))
config.value = tempConfig
}
const isSaving = ref(false)
const save = async () => {
if (isSaving.value) {
return
}
isSaving.value = true
try {
const tempConfig = JSON.parse(JSON.stringify(unref(config)))
await Setting.getInstance().save(tempConfig)
isSaving.value = false
rawConfig = JSON.parse(JSON.stringify(tempConfig))
config.value = tempConfig
} catch (error) {
isSaving.value = false
throw error
}
}
return {
config,
isSame,
isSaving,
diffKeys,
reset,
save,
}
},
{
persist: false,
},
)

23
src/common/event/Setting/index.ts

@ -0,0 +1,23 @@
import { ApiFactory } from "common/lib/abstract"
import { BaseSingleton } from "base"
import { IConfig } from "config"
class Setting extends BaseSingleton {
constructor() {
super()
}
private get api() {
return ApiFactory.getApiClient()
}
sync() {
return this.api.callSync("SettingCommand.sync")
}
save(config: IConfig) {
return this.api.call("SettingCommand.save", config)
}
}
export { Setting }

13
src/common/event/Setting/main/command.ts

@ -0,0 +1,13 @@
import Setting, { IConfig } from "setting/main"
export default class SettingCommand {
static init() {
console.log("SettingCommand init")
}
sync() {
return Setting.config()
}
save(config: IConfig) {
return Setting.set(config)
}
}

16
src/common/event/Updater/hook.ts

@ -0,0 +1,16 @@
import { EventMaps } from "helper/updater/common"
import { defineStore } from "pinia"
export const useSettingStore = defineStore(
"Updater",
() => {
getApi<EventMaps>().on("update-progress", (_, data) => {
console.log(data)
})
return {}
},
{
persist: false,
},
)

18
src/common/event/Updater/index.ts

@ -1,15 +1,13 @@
import { EventMaps } from "helper/updater/common" import { BaseEvent } from "common/lib/abstract"
const curProgress = ref(0) class Updater extends BaseEvent {
constructor() {
getApi<EventMaps>().on("update-progress", (_, data) => { super()
console.log(data) }
})
function useUpdate() { test() {
return { this.api
curProgress,
} }
} }
export { useUpdate } export { Updater }

17
src/common/lib/abstract.ts

@ -1,9 +1,11 @@
import { ElectronApiClient } from "common/lib/electron" import { ElectronApiClient } from "common/lib/electron"
import { BrowserApiClient } from "common/lib/browser" import { BrowserApiClient } from "common/lib/browser"
import { BaseSingleton } from "base/index"
// 定义抽象 API 接口 // 定义抽象 API 接口
export interface IApiClient { export interface IApiClient {
call<T = any>(command: string, ...args: any[]): Promise<T> call<T = any>(command: string, ...args: any[]): Promise<T>
callSync(command: string, ...args: any[]): void
on<K extends string>(channel: K, callback: (...args: any[]) => void): void on<K extends string>(channel: K, callback: (...args: any[]) => void): void
off<K extends string>(channel: K, callback: (...args: any[]) => void): void off<K extends string>(channel: K, callback: (...args: any[]) => void): void
offAll<K extends string>(channel: K): void offAll<K extends string>(channel: K): void
@ -15,6 +17,11 @@ class NullApiClient implements IApiClient {
console.warn(`API call to ${command} failed: API client not initialized`) console.warn(`API call to ${command} failed: API client not initialized`)
return undefined as any return undefined as any
} }
callSync(command: string, ...args: any[]): void {
args
console.warn(`API callSync to ${command} failed: API client not initialized`)
return undefined as any
}
on<K extends string>(channel: K, callback: (...args: any[]) => void): void { on<K extends string>(channel: K, callback: (...args: any[]) => void): void {
callback callback
@ -51,3 +58,13 @@ export class ApiFactory {
return this.instance return this.instance
} }
} }
export class BaseEvent extends BaseSingleton {
constructor() {
super()
}
public get api() {
return ApiFactory.getApiClient()
}
}

5
src/common/lib/browser.ts

@ -11,6 +11,11 @@ export class BrowserApiClient implements IApiClient {
}).then(res => res.json()) }).then(res => res.json())
} }
callSync(): void {
// 浏览器特定实现,可能使用 fetch 或其他方式
console.log("不支持 callSync 方法")
}
// 实现其他方法... // 实现其他方法...
on<K extends string>(channel: K, callback: (...args: any[]) => void): void { on<K extends string>(channel: K, callback: (...args: any[]) => void): void {
// 浏览器中可能使用 WebSocket 或其他方式 // 浏览器中可能使用 WebSocket 或其他方式

5
src/common/lib/electron.ts

@ -6,6 +6,11 @@ export class ElectronApiClient implements IApiClient {
return window.api.call(command, ...args) return window.api.call(command, ...args)
} }
callSync<T = any>(command: string, ...args: any[]): Promise<T> {
// Electron 特定实现
return window.api.callSync(command, ...args)
}
on<K extends string>(channel: K, callback: (...args: any[]) => void): void { on<K extends string>(channel: K, callback: (...args: any[]) => void): void {
window.api.on(channel, callback) window.api.on(channel, callback)
} }

2
src/main/modules/commands/index.ts

@ -3,8 +3,8 @@ import { ipcMain, Menu, MenuItem } from "electron"
import { inject } from "inversify" import { inject } from "inversify"
import IOC from "main/_ioc" import IOC from "main/_ioc"
import BaseClass from "main/base/base" import BaseClass from "main/base/base"
import { isPromise } from "main/utils"
import WindowManager from "../window-manager" import WindowManager from "../window-manager"
import { isPromise } from "utils"
export default class Commands extends BaseClass { export default class Commands extends BaseClass {
destroy() { destroy() {

2
src/main/modules/window-manager/windowsMap.ts

@ -1,7 +1,7 @@
import Config from "config" import Config from "config"
import { BrowserWindowConstructorOptions } from "electron" import { BrowserWindowConstructorOptions } from "electron"
import { getFileUrl, getPreloadUrl } from "main/utils"
import icon from "@res/icon.png?asset" import icon from "@res/icon.png?asset"
import { getFileUrl, getPreloadUrl } from "utils/main"
export type Param = Partial<IConfig> & Required<Pick<IConfig, "name">> export type Param = Partial<IConfig> & Required<Pick<IConfig, "name">>

28
src/main/utils/index.ts

@ -1,28 +0,0 @@
import { is } from "@electron-toolkit/utils"
import { join } from "node:path"
export function getFileUrl(app: string) {
let winURL = ""
if (is.dev && process.env["ELECTRON_RENDERER_URL"]) {
winURL = process.env["ELECTRON_RENDERER_URL"] + `/${app}#/`
} else {
winURL = join(__dirname, `../renderer/${app}#/`)
}
return slash(winURL)
}
export function getPreloadUrl(file) {
return join(__dirname, `../preload/${file}.mjs`)
}
export function isPromise(value: () => any) {
return value && Object.prototype.toString.call(value) === "[object Promise]"
}
export function slash(path: string) {
const isExtendedLengthPath = path.startsWith("\\\\?\\")
if (isExtendedLengthPath) {
return path
}
return path.replace(/\\/g, "/")
}

4
src/renderer/src/pages/index/index.vue

@ -1,9 +1,7 @@
<script setup lang="ts"></script> <script setup lang="ts"></script>
<template> <template>
<div h-full flex flex-col> <div h-full flex flex-col>sad</div>
<div v-for="i in 200" :key="i">{{ i }}</div>
</div>
</template> </template>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

18
src/renderer/src/pages/setting/index.vue

@ -0,0 +1,18 @@
<template>
<div h-full flex>
<div w="200px" border-r="#E5E5E5 solid 1px">左侧菜单</div>
<div flex="1" w="0">
{{ settingStore.isSame }}--{{ settingStore.diffKeys }}
<input v-model="settingStore.config['update.repo']" type="text" />
{{ settingStore.config["update.repo"] }}
<button v-if="!settingStore.isSame" :disabled="settingStore.isSaving" @click="settingStore.save()">保存</button>
</div>
</div>
</template>
<script setup lang="ts">
import { useSettingStore } from "common/event/Setting/hook"
const settingStore = useSettingStore()
console.log(settingStore.config)
</script>

9
src/renderer/src/store/index.ts

@ -1,11 +1,8 @@
import { createPinia } from "pinia"
import { createPinia } from 'pinia' import piniaPluginPersistedstate from "pinia-plugin-persistedstate"
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia() const pinia = createPinia()
pinia.use(piniaPluginPersistedstate) pinia.use(piniaPluginPersistedstate)
export default pinia export default pinia
export { export { pinia }
pinia
}

30
src/renderer/src/store/module.store.ts

@ -1,30 +0,0 @@
import { defineStore } from "pinia"
export enum ModuleType {
CommonPanel = 0,
CodeMgr = 1,
LinkBox = 2,
}
export const useModuleStore = defineStore("module", () => {
const curModuleId = ref<ModuleType>(ModuleType.CommonPanel)
const modules: Record<"id" | "label", string | ModuleType>[] = [
{ id: ModuleType.CommonPanel, label: "全能面板" },
{ id: ModuleType.CodeMgr, label: "代码管家" },
{ id: ModuleType.LinkBox, label: "超链鉴宝" },
]
const setModule = (type: ModuleType) => {
console.log(type);
curModuleId.value = type
}
const curModule = computed(() => {
return modules.find(m => m.id === curModuleId.value)
})
return {
ModuleType,
setModule,
modules,
curModule,
}
})

126
src/renderer/src/ui/NavBar.vue

@ -15,9 +15,7 @@
<img w="16px" h="16px" :src="icon" /> <img w="16px" h="16px" :src="icon" />
<div relative h-full inline-flex items-center text-sm>{{ Config.ExeConfig.name }}</div> <div relative h-full inline-flex items-center text-sm>{{ Config.ExeConfig.name }}</div>
<div relative class="list"> <div relative class="list">
<div class="item" @click="onClickMenu">{{ t("browser.navbar.menu.label") }}</div> <div v-for="(menu, index) in menuList" :key="index" class="item" @click="menu.click">{{ menu.label }}</div>
<div class="item" @click="onClickPage">{{ ModuleStore.curModule?.label ?? "选择模块" }}</div>
<div class="item" @click="onClickSetting">设置</div>
</div> </div>
</div> </div>
<div float-right h-full flex items-center relative style="-webkit-app-region: no-drag"> <div float-right h-full flex items-center relative style="-webkit-app-region: no-drag">
@ -61,7 +59,6 @@
import { PopupMenu } from "@/bridge/PopupMenu" import { PopupMenu } from "@/bridge/PopupMenu"
import { usePlatForm } from "common/event/PlatForm/hook" import { usePlatForm } from "common/event/PlatForm/hook"
import { LogLevel } from "logger/common" import { LogLevel } from "logger/common"
import { useModuleStore } from "@/store/module.store"
const PlatForm = usePlatForm() const PlatForm = usePlatForm()
@ -82,76 +79,77 @@
return false return false
}) })
// function backHome() {
// router.push("/")
// }
function back() { function back() {
router.back() router.back()
} }
const { t } = useI18n() const { t } = useI18n()
const onClickMenu = async e => { const menuList = [
const menu = new PopupMenu([ {
{ label: t("browser.navbar.menu.label"),
label: isFullScreen.value ? t("browser.navbar.menu.quit-fullscreen") : t("browser.navbar.menu.fullscreen"), async click(e) {
async click() { const menu = new PopupMenu([
await PlatForm.toggleFullScreen() {
isFullScreen.value = !isFullScreen.value label: "首选项",
}, async click() {
router.push("/setting")
},
},
{
label: t("browser.navbar.menu.toggleDevTools"),
async click() {
PlatForm.toggleDevTools()
},
},
{
label: "重载",
async click() {
PlatForm.reload()
},
},
{
label: "崩溃",
async click() {
PlatForm.crash()
},
},
{
label: curLogLevel.value === LogLevel.TRACE ? "关闭调试模式" : "开启调试模式",
async click() {
if (curLogLevel.value === LogLevel.TRACE) {
await PlatForm.logSetLevel(LogLevel.INFO)
curLogLevel.value = LogLevel.INFO
return
}
await PlatForm.logSetLevel(LogLevel.TRACE)
curLogLevel.value = LogLevel.TRACE
},
},
])
const obj = e.target.getBoundingClientRect()
menu.show({ x: ~~obj.x, y: ~~(obj.y + obj.height) })
}, },
{ },
label: t("browser.navbar.menu.toggleDevTools"), {
async click() { label: "查看",
PlatForm.toggleDevTools() async click(e) {
}, const menu = new PopupMenu([
{
label: isFullScreen.value ? t("browser.navbar.menu.quit-fullscreen") : t("browser.navbar.menu.fullscreen"),
async click() {
await PlatForm.toggleFullScreen()
isFullScreen.value = !isFullScreen.value
},
},
])
const obj = e.target.getBoundingClientRect()
menu.show({ x: ~~obj.x, y: ~~(obj.y + obj.height) })
}, },
{ },
label: "重载", ]
async click() {
PlatForm.reload()
},
},
{
label: "崩溃",
async click() {
PlatForm.crash()
},
},
{
label: curLogLevel.value === LogLevel.TRACE ? "关闭调试模式" : "开启调试模式",
async click() {
if (curLogLevel.value === LogLevel.TRACE) {
await PlatForm.logSetLevel(LogLevel.INFO)
curLogLevel.value = LogLevel.INFO
return
}
await PlatForm.logSetLevel(LogLevel.TRACE)
curLogLevel.value = LogLevel.TRACE
},
},
])
const obj = e.target.getBoundingClientRect()
menu.show({ x: ~~obj.x, y: ~~(obj.y + obj.height) })
}
const onClickAbout = () => { const onClickAbout = () => {
PlatForm.showAbout() PlatForm.showAbout()
} }
const ModuleStore = useModuleStore()
const onClickPage = async e => {
const menu = new PopupMenu(toRaw(ModuleStore.modules as any))
menu.setClickEvent(item => {
ModuleStore.setModule(item.id)
// if (item.id === ModuleStore.ModuleType.CommonPanel) {}
})
const obj = e.target.getBoundingClientRect()
menu.show({ x: ~~obj.x, y: ~~(obj.y + obj.height) })
}
const onClickSetting = () => {
router.push("/setting")
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

1
src/renderer/typed-router.d.ts

@ -24,5 +24,6 @@ declare module 'vue-router/auto-routes' {
'about': RouteRecordInfo<'about', '/about', Record<never, never>, Record<never, never>>, 'about': RouteRecordInfo<'about', '/about', Record<never, never>, Record<never, never>>,
'/browser': RouteRecordInfo<'/browser', '/browser', Record<never, never>, Record<never, never>>, '/browser': RouteRecordInfo<'/browser', '/browser', Record<never, never>, Record<never, never>>,
'/demo': RouteRecordInfo<'/demo', '/demo', Record<never, never>, Record<never, never>>, '/demo': RouteRecordInfo<'/demo', '/demo', Record<never, never>, Record<never, never>>,
'/setting/': RouteRecordInfo<'/setting/', '/setting', Record<never, never>, Record<never, never>>,
} }
} }

4
tsconfig.node.json

@ -19,12 +19,16 @@
"packages/**/main.ts", "packages/**/main.ts",
"packages/**/*.common.ts", "packages/**/*.common.ts",
"packages/**/common.ts", "packages/**/common.ts",
"packages/**/*",
"src/common/**/*.main.ts", "src/common/**/*.main.ts",
"src/common/**/main/**/*", "src/common/**/main/**/*",
"src/common/**/main.ts", "src/common/**/main.ts",
"src/common/**/*.common.ts", "src/common/**/*.common.ts",
"src/common/**/common.ts" "src/common/**/common.ts"
], ],
"exclude": [
"packages/renderer/**/*",
],
"compilerOptions": { "compilerOptions": {
"composite": true, "composite": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,

Loading…
Cancel
Save