提交 f91251db 作者: test

feat: 优化诸多配置及交互效果

上级 4a06282c
......@@ -32,7 +32,13 @@ async function createWindow(): Promise<BrowserWindow> {
contextIsolation: false,
},
// 无边框
// frame: false,
frame: false,
// 自定义 titleBar
// titleBarStyle: 'hidden',
// titleBarOverlay: {
// height: 32,
// },
})
mainWindow.on('ready-to-show', () => {
......
......@@ -19,6 +19,7 @@ import {
Switch,
TimePicker,
TreeSelect,
Typography,
} from 'ant-design-vue'
import ApiRadioGroup from './components/ApiRadioGroup.vue'
......@@ -71,6 +72,8 @@ componentMap.set('InputCountDown', CountdownInput)
componentMap.set('Upload', BasicUpload)
componentMap.set('Divider', Divider)
componentMap.set('Typography.Text', Typography.Text)
componentMap.set('Typography.Paragraph', Typography.Paragraph)
export function add(compName: ComponentType, component: Component) {
componentMap.set(compName, component)
......
......@@ -114,4 +114,6 @@ export type ComponentType =
| 'Slider'
| 'Rate'
| 'Divider'
| 'Typography.Text'
| 'Typography.Paragraph'
| 'ApiTransfer'
......@@ -5,6 +5,8 @@
inset: 0 !important;
width: 100% !important;
height: 100%;
max-width: 100% !important;
margin: 0 !important;
&-content {
height: 100%;
......
import type { App } from 'vue'
import { Input, Layout } from 'ant-design-vue'
import { Input, Layout, Space, Tooltip } from 'ant-design-vue'
import { Button } from './Button'
export function registerGlobComp(app: App) {
app.use(Input).use(Button).use(Layout)
app.use(Input).use(Button).use(Space).use(Tooltip).use(Layout)
}
......@@ -107,6 +107,11 @@ notification.config({
duration: 3,
})
Message.config({
maxCount: 3,
top: '40px',
})
/**
* @description: message
*/
......
import type { ISystem } from '/#/store'
import { defineStore } from 'pinia'
import { store } from '/@/store'
import { useElectron } from '@/hooks/electron/useElectron'
const { ipcRenderer: ipc } = useElectron()
export const useClientStore = defineStore('app-client', () => {
const system = ref<ISystem>({})
async function init() {
await getSystem()
}
async function getSystem() {
system.value = await ipc.invokeAsync<ISystem>('store-get', 'system')
return system.value
}
function setSystem(value: ISystem) {
// 保留 machineId 不允许修改
const machineId = system.value.machineId
system.value = value
system.value.machineId = machineId
ipc.invoke('store-set', 'system', toRaw(system.value))
}
function setDebug(debug: boolean): void {
system.value.debug = debug
ipc.invoke('store-set', 'system', toRaw(system.value))
}
function setAlwaysOnTop(alwaysOnTop: boolean): void {
system.value.alwaysOnTop = alwaysOnTop
ipc.invoke('store-set', 'system', toRaw(system.value))
}
async function reset(...keys: ['system']) {
ipc.invoke('store-reset', keys)
await init()
}
// 初始化
init()
return {
system,
getSystem,
setSystem,
setDebug,
setAlwaysOnTop,
reset,
}
})
// Need to be used outside the setup
export function useClientStoreWithOut() {
return useClientStore(store)
}
<script setup lang="tsx">
import dayjs from 'dayjs'
import { BasicModal } from '/@/components/Modal'
import { Icon } from '/@/components/Icon'
import { useElectron } from '@/hooks/electron/useElectron'
import { useMessage } from '@/hooks/web/useMessage'
import { getEnvText } from '/@/utils/env'
type MessageType =
| 'checking-for-update'
| 'error'
| 'update-available'
| 'update-not-available'
| 'download-progress'
| 'update-downloaded'
const { ipcRenderer: ipc } = useElectron()
const { createMessage } = useMessage()
const startYear = 2021
const currentYear = dayjs().year()
const yearText = ref<string>(currentYear === startYear ? `${currentYear}` : `${startYear} - ${currentYear}`)
const loading = ref<boolean>(false)
// 监听检查更新事件
let hide = null
ipc.on('updater-message', (_e, body: { type: MessageType; text: string }) => {
console.log('updater-message', body)
const { type, text } = body
if (type === 'checking-for-update' || type === 'download-progress') {
loading.value = true
hide = createMessage.loading({
key: 'updating',
content: text,
duration: 0,
})
} else if (type === 'update-available' || type === 'update-not-available' || type === 'update-downloaded') {
createMessage.success(text)
} else if (type === 'error') {
createMessage.error(text)
}
if (type === 'error' || type === 'update-downloaded' || type === 'update-not-available') {
loading.value = false
hide?.()
}
})
</script>
<template>
<BasicModal v-bind="$attrs" centered :footer="null" :canFullscreen="false">
<!-- 关于信息 -->
<template #title>
<a-space>
<Icon icon="ant-design:info-circle-outlined" :size="22" />
<div class="title-text">关于</div>
</a-space>
</template>
<div class="about-wrap">
<!-- 公司 + 版权信息 -->
<div class="about-app-info-wrap">
<div class="app-icon">
<img src="/logo.png" />
</div>
<!-- <div class="app-name">{{ $app.name }}</div> -->
<div class="app-description">{{ $app.description }}</div>
<div class="app-version">
<a-tooltip>
<template #title>
<div class="flex flex-col items-center justify-center">
<div class="version-mode">{{ getEnvText() }}</div>
<div class="update-time">发布时间: {{ $app.lastBuildTime }}</div>
</div>
</template>
<a-button type="text">
<span class="version-text">{{ $app.version }}</span>
</a-button>
</a-tooltip>
</div>
<!-- 检查版本更新按钮 -->
<div class="app-check-update-action">
<a-button type="dashed" :loading="loading" @click="ipc.send('checkForUpdate')">
<Icon icon="ant-design:bulb-outlined" v-show="!loading" />
检查更新
</a-button>
</div>
</div>
<!-- 版本信息 -->
<div class="about-footer">
<div class="company">长沙壹润信息科技发展有限公司</div>
<div class="copyright">
<span>Copyright © {{ yearText }}</span>
<span class="link">
<a target="_blank" href="https://yiring.com">YiRing.com</a>
</span>
</div>
</div>
</div>
</BasicModal>
</template>
<style lang="less" scoped>
.about-wrap {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
}
.about-app-info-wrap {
display: flex;
flex-direction: column;
align-items: center;
> div {
margin-top: 10px;
}
.app-icon {
width: 50px;
}
.app-description {
font-weight: bold;
}
.app-version {
display: flex;
flex-direction: column;
align-items: center;
.version-text::before {
content: 'V';
margin-right: 2px;
}
}
}
.about-footer {
height: 60px;
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: center;
color: #898989;
font-size: 13px;
user-select: none;
letter-spacing: 1px;
.company {
letter-spacing: 2px;
}
.link {
margin-left: 5px;
&:hover {
text-decoration: underline;
cursor: pointer;
}
a {
color: #898989;
margin-left: 3px;
}
}
}
</style>
<script setup lang="ts">
import Versions from './components/Versions.vue'
onMounted(() => {
postMessage({ payload: 'loaded' }, '*')
})
</script>
<template>
<Versions />
<svg class="hero-logo" viewBox="0 0 900 300">
<use xlink:href="../../assets/icons.svg#electron" />
</svg>
<h2 class="hero-text">You've successfully created an Electron project with Vue and TypeScript</h2>
<p class="hero-tagline">Please try pressing <code>F12</code> to open the devTool</p>
<div class="links">
<div class="link-item">
<a target="_blank" href="https://evite.netlify.app">Documentation</a>
</div>
<div class="link-item link-dot"></div>
<div class="link-item">
<a target="_blank" href="https://github.com/alex8088/electron-vite">Getting Help</a>
</div>
<div class="link-item link-dot"></div>
<div class="link-item">
<a target="_blank" href="https://github.com/alex8088/quick-start/tree/master/packages/create-electron">
create-electron
</a>
</div>
</div>
<div class="features">
<div class="feature-item">
<article>
<h2 class="title">Configuring</h2>
<p class="detail">
Config with <span>electron.vite.config.ts</span> and refer to the
<a target="_blank" href="https://evite.netlify.app/config/">config guide</a>.
</p>
</article>
</div>
<div class="feature-item">
<article>
<h2 class="title">HMR</h2>
<p class="detail">
Edit <span>src/renderer</span> files to test HMR. See
<a target="_blank" href="https://evite.netlify.app/guide/hmr-in-renderer.html">docs</a>.
</p>
</article>
</div>
<div class="feature-item">
<article>
<h2 class="title">Hot Reloading</h2>
<p class="detail">
Run <span>'electron-vite dev --watch'</span> to enable. See
<a target="_blank" href="https://evite.netlify.app/guide/hot-reloading.html">docs</a>.
</p>
</article>
</div>
<div class="feature-item">
<article>
<h2 class="title">Debugging</h2>
<p class="detail">
Check out <span>.vscode/launch.json</span>. See
<a target="_blank" href="https://evite.netlify.app/guide/debugging.html">docs</a>.
</p>
</article>
</div>
<div class="feature-item">
<article>
<h2 class="title">Source Code Protection</h2>
<p class="detail">
Supported via built-in plugin <span>bytecodePlugin</span>. See
<a target="_blank" href="https://evite.netlify.app/guide/source-code-protection.html"> docs </a>
.
</p>
</article>
</div>
<div class="feature-item">
<article>
<h2 class="title">Packaging</h2>
<p class="detail">
Use
<a target="_blank" href="https://www.electron.build">electron-builder</a>
and pre-configured to pack your app.
</p>
</article>
</div>
</div>
</template>
<style lang="less">
@import '../../assets/css/styles.less';
</style>
......@@ -5,6 +5,7 @@
import { useElectron } from '@/hooks/electron/useElectron'
import { useMessage } from '@/hooks/web/useMessage'
import { getEnvText } from '/@/utils/env'
import { useClientStoreWithOut } from '@/store/modules/client'
type MessageType =
| 'checking-for-update'
......@@ -14,13 +15,16 @@
| 'download-progress'
| 'update-downloaded'
const clientStore = useClientStoreWithOut()
const { ipcRenderer: ipc } = useElectron()
const { createMessage } = useMessage()
const startYear = 2021
const startYear = 2023
const currentYear = dayjs().year()
const yearText = ref<string>(currentYear === startYear ? `${currentYear}` : `${startYear} - ${currentYear}`)
const loading = ref<boolean>(false)
const versions = reactive({ ...window.electron.process.versions })
const isDebug = computed(() => clientStore.system?.debug)
// 监听检查更新事件
let hide = null
......@@ -38,7 +42,11 @@
} else if (type === 'update-available' || type === 'update-not-available' || type === 'update-downloaded') {
createMessage.success(text)
} else if (type === 'error') {
createMessage.error(text)
if (text.startsWith('net::')) {
createMessage.warn('检查更新失败: 请检查网络或者更新源配置')
} else {
createMessage.error(`检查更新失败: ${text}`)
}
}
if (type === 'error' || type === 'update-downloaded' || type === 'update-not-available') {
......@@ -58,10 +66,10 @@
</a-space>
</template>
<div class="about-wrap">
<div class="about-wrap" :class="{ debug: isDebug }">
<!-- 公司 + 版权信息 -->
<div class="about-app-info-wrap">
<div class="app-icon">
<div class="app-icon relative">
<img src="/logo.png" />
</div>
<!-- <div class="app-name">{{ $app.name }}</div> -->
......@@ -98,6 +106,14 @@
</div>
</div>
</div>
<!-- 应用内核相关信息 -->
<ul class="versions" v-if="isDebug">
<li class="electron-version">Electron v{{ versions.electron }}</li>
<li class="node-version">Node v{{ versions.node }}</li>
<li class="chrome-version">Chromium v{{ versions.chrome }}</li>
<!-- <li class="v8-version">V8 v{{ versions.v8.split('-').shift() }}</li> -->
</ul>
</BasicModal>
</template>
......@@ -107,6 +123,10 @@
flex-direction: column;
justify-content: space-between;
align-items: center;
&.debug {
margin-bottom: 20px;
}
}
.about-app-info-wrap {
......@@ -155,6 +175,7 @@
.link {
margin-left: 5px;
text-decoration: dashed;
&:hover {
text-decoration: underline;
......@@ -167,4 +188,34 @@
}
}
}
.versions {
margin: 0 auto;
float: none;
clear: both;
overflow: hidden;
font-family: Menlo, 'Lucida Console', monospace;
color: #bfbfbf;
line-height: 1;
transition: all 0.3s;
position: absolute;
bottom: 10px;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
left: 0;
li {
display: block;
float: left;
border-right: 1px solid rgb(194 245 255 / 40%);
font-size: 13px;
opacity: 0.8;
+ li {
margin-left: 20px;
}
}
}
</style>
<script setup lang="ts">
import dayjs from 'dayjs'
import { LinkOutlined } from '@ant-design/icons-vue'
const year = ref(dayjs().year())
const company = ref<string>('长沙壹润信息科技发展有限公司')
const copyright = reactive({
link: 'https://yiring.com',
text: 'YiRing.com',
})
</script>
<template>
<div class="footer">
<div class="company">{{ company }}</div>
<div class="copyright">
<span>Copyright © {{ year }}</span>
<span class="link">
<LinkOutlined />
<a target="_blank" :href="copyright.link">{{ copyright.text }}</a>
</span>
</div>
</div>
</template>
<style lang="less" scoped>
.footer {
width: calc(100% - 40px);
height: 52px;
position: fixed;
bottom: 10px;
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: center;
color: #b5b5b5;
font-size: 13px;
user-select: none;
.company {
letter-spacing: 2px;
}
.link {
margin-left: 5px;
&:hover {
text-decoration: underline;
cursor: pointer;
}
a {
color: #b5b5b5;
margin-left: 3px;
}
}
}
</style>
<script setup lang="ts">
import { Icon } from '/@/components/Icon'
import { useModal } from '/@/components/Modal'
import AboutModal from './AboutModal.vue'
import SettingModal from './SettingModal.vue'
import { useElectron } from '@/hooks/electron/useElectron'
import { useMessage } from '@/hooks/web/useMessage'
import { useClientStoreWithOut } from '@/store/modules/client'
const clientStore = useClientStoreWithOut()
const { ipcRenderer: ipc } = useElectron()
const { createConfirm, createMessage } = useMessage()
const isDebug = computed(() => clientStore.system?.debug)
const isAlwaysOnTop = computed(() => clientStore.system?.alwaysOnTop)
const title = ref<string>($app.description)
const [aboutRegister, { openModal: openAboutModal }] = useModal()
const [settingRegister, { openModal: openSettingModal }] = useModal()
function handle(action: 'reload' | 'debug' | 'min' | 'max' | 'close' | 'top') {
if (action === 'close') {
createConfirm({
iconType: 'warning',
content: '确认关闭应用吗?',
onOk() {
ipc.invoke(action)
},
})
return
}
if (action === 'top') {
clientStore.setAlwaysOnTop(!isAlwaysOnTop.value)
createMessage.success(`应用${isAlwaysOnTop.value ? '' : '取消'}置顶`)
ipc.invoke(action, isAlwaysOnTop.value)
return
}
ipc.invoke(action)
}
function about() {
openAboutModal()
}
function setting() {
openSettingModal()
}
// 监听全局通知
ipc.on('app-notify', (_, body) => {
console.log('app-notify', body)
if (body?.message.startsWith('net::')) {
createMessage.warn('更新源访问失败,请检查网络或者更新源配置')
return
}
createMessage[body.type](body.message)
})
</script>
<template>
<div class="header">
<a-space class="title">
<div class="title-icon">
<img src="/logo.png" />
</div>
<div class="title-text">{{ title }}</div>
</a-space>
<a-space class="btns">
<a-tooltip title="重新加载" v-if="isDebug">
<a-button type="text" primary @click="handle('reload')">
<Icon icon="ant-design:reload-outlined" :size="22" />
</a-button>
</a-tooltip>
<a-tooltip title="调试" v-if="isDebug">
<a-button type="text" primary @click="handle('debug')">
<Icon icon="ant-design:bug-outlined" :size="22" />
</a-button>
</a-tooltip>
<a-tooltip title="应用设置">
<a-button type="text" primary @click="setting">
<Icon icon="uil:setting" :size="22" />
</a-button>
</a-tooltip>
<a-tooltip title="关于">
<a-button type="text" primary @click="about">
<Icon icon="uil:info-circle" :size="22" />
</a-button>
</a-tooltip>
<a-tooltip :title="isAlwaysOnTop ? '取消置顶' : '置顶'">
<a-button type="text" primary @click="handle('top')" :class="{ actived: isAlwaysOnTop }">
<Icon icon="ph:push-pin-duotone" :size="22" :color="isAlwaysOnTop ? 'green' : '#000'" />
</a-button>
</a-tooltip>
<a-tooltip title="最小化">
<a-button type="text" primary @click="handle('min')">
<Icon icon="ant-design:minus-outlined" :size="22" />
</a-button>
</a-tooltip>
<a-tooltip title="缩放">
<a-button type="text" primary @click="handle('max')">
<Icon icon="uil:window-maximize" :size="22" />
</a-button>
</a-tooltip>
<a-tooltip title="关闭应用">
<a-button type="text" primary @click="handle('close')" class="close">
<Icon icon="ant-design:close-outlined" :size="22" />
</a-button>
</a-tooltip>
</a-space>
<!-- 关于 -->
<AboutModal @register="aboutRegister" />
<!-- 软件配置 -->
<SettingModal @register="settingRegister" />
</div>
</template>
<style lang="less" scoped>
.header {
width: 100%;
height: 50px;
display: flex;
justify-content: space-between;
padding: 0 10px;
background-color: white;
.title {
-webkit-app-region: drag;
cursor: pointer;
flex: 1;
height: 100%;
font-size: 15px;
font-weight: bold;
display: flex;
align-items: center;
color: #444;
.title-text {
letter-spacing: 1px;
}
.title-icon {
width: 20px;
height: 20px;
margin-left: 10px;
}
}
.btns {
:deep(.ant-btn-text) {
&:hover,
&:focus {
background: rgb(0 0 0 / 7%);
transition: all 0.3s;
}
&.close:hover,
&.clode:focus {
color: white;
background: #fa593b;
}
}
.actived {
background: rgb(0 0 0 / 7%) !important;
}
}
:deep(.ant-tooltip) {
z-index: 1000;
}
}
</style>
<script setup lang="ts">
import { Empty } from 'ant-design-vue'
import { ScrollContainer } from '/@/components/Container'
</script>
<template>
<div class="main">
<ScrollContainer>
<div class="main-content-wrap">
<Empty :image="Empty.PRESENTED_IMAGE_SIMPLE" description="空空如也~" />
</div>
</ScrollContainer>
</div>
</template>
<style lang="less" scoped>
.main {
width: 100%;
height: calc(100vh - 10px - 20px - 20px);
padding: 20px;
display: flex;
align-items: center;
justify-content: center;
.main-content-wrap {
height: auto;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
}
:deep(.scrollbar__view) {
min-height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
</style>
<script setup lang="ts">
import type { Setting } from './types'
import { BasicForm, useForm } from '/@/components/Form'
import { useClientStore } from '@/store/modules/client'
import { useMessage } from '@/hooks/web/useMessage'
const props = defineProps({
setting: {
type: Object as PropType<Setting>,
},
})
const clientStore = useClientStore()
const { createMessage } = useMessage()
const [registerForm] = useForm({
schemas: props.setting.formSchema,
layout: 'horizontal',
labelWidth: 100,
wrapperCol: {
span: 14,
},
colon: true,
labelAlign: 'right',
actionColOptions: {
style: {
marginTop: '5px',
marginLeft: '100px',
},
span: 12,
},
showResetButton: props.setting.actions?.includes('reset') || false,
showSubmitButton: props.setting.actions?.includes('submit') || false,
submitButtonOptions: {
text: '保存',
},
})
async function handleFormSubmit(values: Recordable) {
clientStore.setSystem(values)
createMessage.success('保存成功')
}
function handleFormReset() {
clientStore.reset(props.setting.key)
createMessage.success('重置成功')
}
</script>
<template>
<div class="pt-2 pb-20">
<BasicForm @register="registerForm" @submit="handleFormSubmit" @reset="handleFormReset" />
</div>
</template>
<style lang="less" scoped>
:deep(.ant-input-disabled) {
color: rgb(0 0 0 / 70%);
}
:deep(.ant-typography) {
margin-bottom: 0 !important;
}
</style>
<script setup lang="tsx">
import { Tabs } from 'ant-design-vue'
import type { Setting } from './types'
import { Icon } from '/@/components/Icon'
import { BasicModal } from '/@/components/Modal'
import { ScrollContainer } from '/@/components/Container/index'
import SettingForm from './SettingForm.vue'
import { useClientStore } from '@/store/modules/client'
const clientStore = useClientStore()
const settings = computed((): Setting[] => [
{
key: 'system',
name: '系统设置',
icon: 'ant-design:setting-outlined',
value: clientStore.system,
formSchema: [
{
field: 'machineId',
component: 'Typography.Paragraph',
label: '设备标识',
colProps: {
span: 24,
},
componentProps: {
ellipsis: true,
copyable: true,
content: clientStore.system.machineId,
},
defaultValue: clientStore.system.machineId,
},
{
field: 'debug',
component: 'Switch',
label: '调试模式',
colProps: {
span: 20,
},
componentProps: {
checkedChildren: '是',
unCheckedChildren: '否',
},
defaultValue: clientStore.system.debug,
},
{
field: 'feedURL',
component: 'Input',
label: '更新源',
colProps: {
span: 24,
},
componentProps: {
placeholder: '请输入更新源地址',
},
defaultValue: clientStore.system.feedURL,
},
],
actions: ['reset', 'submit'],
},
])
</script>
<template>
<BasicModal
v-bind="$attrs"
default-fullscreen
destroy-on-close
:canFullscreen="false"
:footer="null"
:draggable="false"
fullscreen
>
<!-- 应用设置 -->
<template #title>
<a-space>
<Icon icon="ant-design:setting-outlined" :size="22" />
<div class="title-text">应用设置</div>
</a-space>
</template>
<!-- 应用设置基本信息 -->
<ScrollContainer>
<div>
<Tabs tab-position="left">
<template v-for="item in settings" :key="item.key">
<Tabs.TabPane>
<template #tab>
<div class="tab-item">
<Icon :icon="item.icon" :size="20" />
<div class="name">{{ item.name }}</div>
</div>
</template>
<!-- Tabs -->
<!-- 表单 -->
<SettingForm :setting="item" />
</Tabs.TabPane>
</template>
</Tabs>
</div>
</ScrollContainer>
</BasicModal>
</template>
<style lang="less" scoped>
//
.tab-item {
display: flex;
align-items: center;
}
</style>
import type { FormSchema } from '@/components/Form'
import type { ISystem } from '/#/store'
export interface Setting {
key: 'system'
name: string
icon: string
value: ISystem
formSchema: FormSchema[]
actions?: ('submit' | 'reset')[]
}
<script setup lang="ts">
import Versions from './components/Versions.vue'
import Main from './components/Main.vue'
import Header from './components/Header.vue'
import Footer from './components/Footer.vue'
onMounted(() => {
postMessage({ payload: 'loaded' }, '*')
......@@ -7,90 +9,22 @@
</script>
<template>
<Versions />
<div class="main-wrap">
<!-- 头部 -->
<Header />
<svg class="hero-logo" viewBox="0 0 900 300">
<use xlink:href="../../assets/icons.svg#electron" />
</svg>
<h2 class="hero-text">You've successfully created an Electron project with Vue and TypeScript</h2>
<p class="hero-tagline">Please try pressing <code>F12</code> to open the devTool</p>
<!-- 主体部分 -->
<Main />
<div class="links">
<div class="link-item">
<a target="_blank" href="https://evite.netlify.app">Documentation</a>
</div>
<div class="link-item link-dot"></div>
<div class="link-item">
<a target="_blank" href="https://github.com/alex8088/electron-vite">Getting Help</a>
</div>
<div class="link-item link-dot"></div>
<div class="link-item">
<a target="_blank" href="https://github.com/alex8088/quick-start/tree/master/packages/create-electron">
create-electron
</a>
</div>
</div>
<div class="features">
<div class="feature-item">
<article>
<h2 class="title">Configuring</h2>
<p class="detail">
Config with <span>electron.vite.config.ts</span> and refer to the
<a target="_blank" href="https://evite.netlify.app/config/">config guide</a>.
</p>
</article>
</div>
<div class="feature-item">
<article>
<h2 class="title">HMR</h2>
<p class="detail">
Edit <span>src/renderer</span> files to test HMR. See
<a target="_blank" href="https://evite.netlify.app/guide/hmr-in-renderer.html">docs</a>.
</p>
</article>
</div>
<div class="feature-item">
<article>
<h2 class="title">Hot Reloading</h2>
<p class="detail">
Run <span>'electron-vite dev --watch'</span> to enable. See
<a target="_blank" href="https://evite.netlify.app/guide/hot-reloading.html">docs</a>.
</p>
</article>
</div>
<div class="feature-item">
<article>
<h2 class="title">Debugging</h2>
<p class="detail">
Check out <span>.vscode/launch.json</span>. See
<a target="_blank" href="https://evite.netlify.app/guide/debugging.html">docs</a>.
</p>
</article>
</div>
<div class="feature-item">
<article>
<h2 class="title">Source Code Protection</h2>
<p class="detail">
Supported via built-in plugin <span>bytecodePlugin</span>. See
<a target="_blank" href="https://evite.netlify.app/guide/source-code-protection.html"> docs </a>
.
</p>
</article>
</div>
<div class="feature-item">
<article>
<h2 class="title">Packaging</h2>
<p class="detail">
Use
<a target="_blank" href="https://www.electron.build">electron-builder</a>
and pre-configured to pack your app.
</p>
</article>
</div>
<!-- 底部 -->
<Footer v-show="false" />
</div>
</template>
<style lang="less">
@import '../../assets/css/styles.less';
.main-wrap {
width: 100vw;
height: 100vh;
background-color: #fbfbfb;
}
</style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论