溯水流光 发表于 2025-4-29 10:28:29

教程:如何开发桌面App?PWA也许是你的答案

本帖最后由 溯水流光 于 2025-4-29 10:44 编辑


> 文章的下载和备份:
>
> Gitee: https://gitee.com/HHandHsome/pwa-tutorial
>
> GitHub: https://github.com/HHsomeHand/pwa-tutorial

# 如何快速开发桌面 APP?PWA 也许是你的答案

> 本文是上一篇文章《如何快速开发手机 APP?PWA 也许是你的答案》的延续。是其的姊妹篇。
>
> 上一篇我们介绍了 PWA 是什么,分析了它的优缺点,并通过 Vue + Vant + Tailwind 快速搭建了一个手机端 DEMO,并成功部署到 GitHub Pages 上, 还打包为了 apk, 体验了 PWA 的开发流程。
>
> 上篇文章的传送门: https://bbs.tampermonkey.net.cn/thread-8537-1-1.html


---

随着 Web 技术的发展,开发一个跨平台的桌面 App 已不再是难事。

特别是对于前端开发者来说,利用现有技术栈,我们可以迅速搭建出一个桌面 Web App。

本篇文章将延续上一篇的思路,打造一个桌面端的小工具,并通过 GitHub Actions 自动部署为 GitHub Pages。

我们会一起完成以下几个步骤:

1. 使用 Vite 快速初始化 Vue + Tailwind 项目, 并 git init(与上篇相同,不再赘述, 你可以直接 git clone element Plus 的最佳实践, 见下)
2. 引入 Element Plus 并配置自动按需导入
3. 开发一个简单的桌面小 Demo
4. 配置 GitHub Actions 实现 CI/CD 自动部署到 GitHub Pages

> 你可以直接 git clone https://github.com/sxzz/element-plus-best-practices.git
>
> https://github.com/sxzz/element-plus-best-practices 是 Element Plus 的最佳实践
>
> 可以节省很多搭建环境的时间, 你也可以把你常用的模板托管在 Github 上, 这样需要的使用的时候, 再 git clone 就 OK 了!

---

## 一、引入 Element Plus 并配置按需导入

我们先为项目引入适用于桌面端的 UI 框架 —— (https://element-plus.org/zh-CN/guide/installation.html)。

```bash
pnpm install element-plus
```

> 文档: https://element-plus.org/zh-CN/guide/installation.html

为了提升开发效率,我们还需要配置自动导入 Element Plus 的组件和函数:

```bash
pnpm install -D unplugin-vue-components unplugin-auto-import
```

> 文档: https://element-plus.org/zh-CN/guide/quickstart.html

然后修改 `vite.config.js`:

```js
// vite.config.js
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import {ElementPlusResolver} from 'unplugin-vue-components/resolvers'
import tailwindcss from '@tailwindcss/vite'

// https://vite.dev/config/
export default defineConfig({
    plugins: [
      vue(),
      AutoImport({
            imports: ['vue'],
            resolvers: ,
      }),
      Components({
            resolvers: ,
      }),
      tailwindcss(),
    ],
})

```

### 插件说明:

#### AutoImport

该插件可以扫描 `<script>` 和 `.js` `.ts`, 自动导入`Element Plus`的全局函数

```js
// 你的代码
ElMessage.success('Hello')

// AutoImport 自动生成的等效代码
import { ElMessage } from 'element-plus'
ElMessage.success('Hello')
```

----

```
imports: ['vue'],
```

这行配置可以让应用程序支持自动导入 `vue` 的 `ref` `watch` 等`setup` `api`函数

#### Components

该插件可以扫描`<template>`, 自动导入组件

```vue
<template>
<ElButton>Click me</ElButton>
</template>

<!-- 原本需要手动 -->
<script>
import { ElButton } from 'element-plus'

</script>

<!-- 使用 Components 插件后,自动生成上述代码 -->
```

---

## 二、开发一个字符分割的小工具

下面是我们要实现的桌面端小工具:

<img src="data/attachment/forum/202504/29/102204ezrfpsddrzr3pzrp.png" width="500" />


**功能说明:**

输入一个字符串,如 `hzx`,输出为字符数组形式:`['h', 'z', 'x']`,并支持一键复制。

虽然如今这种字符处理可以交给 AI 来完成(比如豆包),但它仍是个非常合适的练习案例。

`App.vue` 核心代码如下:

```vue
<script setup>
const input = ref("");

const result = ref("");

// 输入"hzx", 输出 "{'h', 'z', 'x'}"
function splitStringToText(str) {
let content = str.split('') // "hzx" -> ["h", "z", "x"]
      .map(ch => `'${ch}'`) // ["h", "z", "x"] -> ["'h'", "'z'", "'x'"]
      .join(', ') // ["'h'", "'z'", "'x'"] -> "'h', 'z', 'x'"

return '{' + content + '}';
}

watch(input, (newValue) => {
result.value = splitStringToText(newValue);
}, {immediate: true});

function onCopyBtnClick() {
copyText(result.value);
}

/**
* 复制字符串到剪贴板,并显示提示
* @param {string} text - 要复制的字符串
* @returns {Promise<void>}
*/
async function copyText(text) {
try {
    // 检查输入是否为字符串且不为空
    if (typeof text !== 'string' || text.trim() === '') {
      throw new Error('输入的文本无效');
    }

    // 使用 Clipboard API 复制文本
    await navigator.clipboard.writeText(text);

    // 复制成功,显示成功提示
    ElMessage({
      message: '复制成功!',
      type: 'success',
      duration: 2000, // 提示显示2秒
    });
} catch (error) {
    // 复制失败,显示错误提示
    ElMessage({
      message: '复制失败:' + error.message,
      type: 'error',
      duration: 3000, // 错误提示显示3秒
    });
}
}
</script>

<template>
<div class="app">
    <div class="app__container">
      <el-input
          v-model="input"
          class="app__input"
          type="textarea"
          autosize
          placeholder="Please input"
      />

      <el-input
          v-model="result"
          class="app__input"
          type="textarea"
          readonly
          autosize
      />

      <el-button type="primary" @click="onCopyBtnClick">复制!</el-button>
    </div>
</div>
</template>

<style scoped>
@import "tailwindcss";

.app {
@apply w-screen h-screen flex justify-center items-center;
}

.app__container {
@apply flex flex-col gap-3 w-50;
}
</style>
```

---

## 三、GitHub Actions 自动部署到 GitHub Pages

我们接下来要把项目发布到 GitHub Pages,并实现自动化 CI/CD 流程。

### 1. 设置 `base`

假设你的项目仓库地址是:
```
https://github.com/HHsomeHand/pwa-str-separate
```
那么在 `vite.config.js` 中配置:

```js
base: '/pwa-str-separate/'
```

### 2. 安装 PWA 插件

```bash
pnpm add -D vite-plugin-pwa
```

并添加到 `vite.config.js`:

```js
import { VitePWA } from 'vite-plugin-pwa'

VitePWA({
registerType: 'autoUpdate',
devOptions: {
    enabled: false,
},
workbox: {
    globPatterns: ['**/*.{mjs,js,css,html,png,jpg,gif,svg,woff,woff2}'],
},
manifest: false
})
```

### 3. 设置 favicon 和图标

可以使用 (https://favicon.inbrowser.app/tools/favicon-generator) 来生成图标, 并记得配置 `Start URL` 和 `icons 路径`, 不然部署在 Github Pages 上时, 访问网页, 控制台会报 404, 找不到 PWA 的图标。

---

## GitHub Actions

GitHub Actions 是一个自动化工具,它会检测你的仓库中是否存在 `.github/workflows/[任意名称].yml` 文件。当你将代码推送到远程仓库时,GitHub 会检查是否满足触发条件,如果是, 就会分配一台服务器给你, 来执行:

+ 下载你的代码
+ 运行 `pnpm install`
+ `pnpm build` 构建项目
+ 并将结果推送到 `gh-pages` 分支

部署完成后,你可以设置仓库的 Github Pages 分支为 `gh-pages`, 并通过 GitHub Pages 访问你的网站。

### 配置工作流

在仓库中创建文件 `.github/workflows/deploy.yml`(注意 `github` 和 `workflows` 拼写不能出错)。文件名可以自定义,没有强制要求。

以下是 `deploy.yml` 文件的配置内容:

```yaml
name: Deploy to GitHub Pages

on:
push:
    branches:

jobs:
build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
      uses: actions/checkout@v4

      - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
          node-version: '20'

      - name: Setup pnpm
      uses: pnpm/action-setup@v2
      with:
          version: 8

      - name: Install Dependencies
      run: pnpm install

      - name: Build
      run: pnpm build
      env:
          VITE_BASE_URL: /pwa-str-separate/

      - name: Deploy
      uses: JamesIves/github-pages-deploy-action@v4
      with:
          branch: gh-pages
          folder: dist
```

+ ubuntu-latest 是分给你的服务器带的系统
+ Checkout 是下载你的代码
+ Setup Node.js 是安装 Node.js
+ Setup pnpm 是安装 pnpm
+ Install Dependencies 执行 `pnpm install`
+ Build 执行 `pnpm build`
+ Deploy 就是将打包结果推送到 `gh-pages` 分支

### 配置 Github Actions 的权限

我们需要开启 Github Actions 的权限, 使其可以正常读写我们的项目, 并让其可以正常提交内容到我们的`gh-pages`分支

<img src="data/attachment/forum/202504/29/102306k7bdsby3jvh32b3t.png" width="1400" />
向下滚动:
<img src="data/attachment/forum/202504/29/102316tg4kzhab3p6yakf4.png" width="1200" />


### 推送到远端服务器

确定 Save保存后, 再git push, 推送我们的代码到服务器, 等 GitHub Actions 构建和部署完毕后, 我们设置 `gh-pages` 为 GitHub Pages 的展示页面。配置后, 记得点击 Save 保存, 不然配置不会生效。
<img src="data/attachment/forum/202504/29/102446syalkq3q7ahzmmta.png" width="1000" />

<img src="data/attachment/forum/202504/29/102500emd0duy5vv25uxvv.png" width="1200" />


等待几分钟, 访问`https://hhsomehand.github.io/pwa-str-separate/`, 再保存到桌面就OK了!
<img src="data/attachment/forum/202504/29/102510ash8hocssws1wovr.png" width="1200" />

后续的开发中,只用执行 `git push`,GitHub 就会自动为你部署。

你本地下载好的 PWA APP, 也会因为服务器的更新, 而自动更新, 如果本地没有更新, 请刷新页面并检查网络链接。

### 什么是 CI? 什么是 CD?

CI 是自动打包,如我推送代码到远端git服务器,自动触发GitHub actions,然后帮我打包好了代码。

CD 是自动部署, 这里自动把代码写入gh-page分支,这就算自动部署了。

粗糙地理解: CI 完整的名字是"持续集成". “集成”这个词的字面意思,就是合在一起的意思。“把代码合在一起”就是集成,“把代码合在一起” 也可以抽象地理解为 `pnpm build`, 因为打包也相当于把代码合在一起。CD可以自动把结果部署。

---

## PWA Builder 打包

PWA Builder 仅支持打包为`MSIX`格式,无法生成单体 exe 文件。其需安装后才能运行,类似`apk`。其实我觉得通过浏览器安装到本地已经够用了, 所以这里就不讲了

## 尾声

感谢你的阅读, 如果遇到问题, 欢迎评论区讨论

王一之 发表于 2025-4-29 10:53:48

感谢哥哥分享

youhou22322 发表于 7 天前

谢谢楼主分享啊!
页: [1]
查看完整版本: 教程:如何开发桌面App?PWA也许是你的答案