electron + vue + vite 开发环境搭建1

本章将介绍如何通过vite搭建electron + vue-ts 开发环境。nodejs版本16.16.0,vite版本3.2.0,包管理工具pnpm

使用vite创建vue-ts项目

# 使用vite vue-ts模板创建项目
pnpm create vite file-manager --template vue-ts

# 进入到项目目录下,安装依赖
cd file-manager
pnpm install

修改项目结构

  • src 目录下创建 render 目录,将 src 下原有的目录及文件移入至 render 目录

  • src 目录下创建 mainpreload 目录

  • 将项目根目录下的 index.htmlpublic 目录移入至 render 目录下,修改 index.html 中引入资源的路径

    DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <link rel="icon" type="image/svg+xml" href="/vite.svg" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Vite + Vue + TStitle>
      head>
      <body>
        <div id="app">div>
        <script type="module" src="/main.ts">script>
      body>
    html>
    
  • 修改 vite 配置文件 vite.config.ts

    需要安装 @types/node 模块用于让nodejs相关api支持ts

    import { defineConfig } from "vite";
    import type { BuildOptions } from "vite";
    import vue from "@vitejs/plugin-vue";
    import { resolve } from "path";
    
    export default defineConfig(({ mode }) => {
        const build: BuildOptions = {
            outDir: resolve(__dirname, "./dist/render")
        };
    
        return {
            base: "./",
            root: resolve(__dirname, "./src/render"),
            build,
            plugins: [vue()]
        }
    });
    
  • 修改 package.json 文件

    // 修改scripts属性值为如下
    "scripts": {
        "dev:render": "vite",
        "build:render": "vue-tsc && vite build"
    }
    

到此,目录结构修改完毕。

执行 pnpm dev:render 运行web,在浏览器中查看web是否可以正常显示

执行 pnpm build:render 打包web,查看打包出的内容路径与vite中配置的 outDir 是否一致。

以上两步均没问题则说明项目目录修改成功。

目录说明:

  • main 目录,electron主线程入口目录

  • preload目录,electron preload 目录(preload中的内容将会挂载到web window对象中,用于web内调用node相关API)

  • render目录,web目录

限制nodejs版本跟包管理器

package.json 中添加配置

{
    // ...
    "packageManager": "[email protected]",
    "engines": {
        "node": "16.16.0"
    },
    "scripts": {
        "preinstall": "npx only-allow pnpm",
        // ...
    }
    // ...
}

在项目根目录创建npm配置文件, .npmrc 文件,添加如下内容:

engine-strict = true

代码规范设置

使用 eslint 进行代码规范。eslint 用于语法检测及代码风格约束。

  • 安装 eslint

    pnpm install -D eslint
    
  • 初始化 eslint

    npx eslint --init
    

    执行eslint初始化目录后,根据项目需要在命令行交互界面选择对应选项即可。

  • 修改 eslint 配置文件

    由于我在初始化时选择用JavaScript作为配置文件语言,所以首先要在 env 属性中加入对node的支持,否则配置文件本身会提示异常

    "env": {
         "browser": true,
         "es2021": true,
         "node": true,
    },
    

    由于使用vue-ts环境作为web开发环境所以还需要增加对vue的支持

    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "ecmaVersion": "latest",
        "sourceType": "module"
    },
    

    在配置中存在上述配置,需要将 parser 移入 parserOptions 中,并重新定义 parser 值为 vue-eslint-parser 即可。

    parser: "vue-eslint-parser",
    parserOptions: {
        ecmaVersion: 'latest',
        sourceType: 'module',
        parser: "@typescript-eslint/parser"
    },
    
  • 安装 vite-plugin-eslint 插件,开启vite对eslint的支持,当使用vite命令时会进行eslint验证

    pnpm install -D vite-plugin-eslint
    

    在vite配置文件中引入此插件,并在plugins中声明即可。

    import eslintPlugin from "vite-plugin-eslint";
    
    // ...
    return {
        //...
        plugins: [
            eslintPlugin()
            // ...
        ]
    };
    

初始化 git

需提前在本地安装 git

git init

引入 husky + lint-staged

husky 用于设置git钩子回调

lint-staged 用于验证暂存区文件

  • 安装依赖

    pnpm install -D husky lint-staged
    
  • 配置 lint-staged

    "lint-staged": {
        "*.{vue,ts}": "eslint"
    }
    

    在执行 npx lint-staged 时会验证暂存区后缀为 vuets 的所有文件。

  • 配置 husky

    # 安装husky
    npx husky install
    
    # 添加git钩子
    npx husky add .husky/pre-commit "npx lint-staged"
    

    也就是说在 git commit 前执行,会先执行 npx lint-staged

引入electron

  • 安装依赖

    pnpm install -D electron
    
  • src > main 目录中添加入口文件

    • 在该目录下初始化 typescript npx tsc --init

      // 具体配置如下
      {
        "compilerOptions": {
          "allowJs": true,
          "alwaysStrict": true,
          "esModuleInterop": true,
          "forceConsistentCasingInFileNames": true,
          "isolatedModules": true,
          "jsx": "preserve",
          "lib": ["dom", "es2017"],
          "module": "commonjs",
          "moduleResolution": "node",
          "noEmit": false,
          "noFallthroughCasesInSwitch": true,
          "noUnusedLocals": false,
          "noUnusedParameters": true,
          "resolveJsonModule": true,
          "skipLibCheck": true,
          "strict": true,
          "target": "esnext",
          "outDir": "../../dist/main",
        },
        "exclude": ["node_modules"],
        "include": ["**/*.ts", "**/*.tsx", "**/*.js"]
      }
      
    • 创建 index.ts 文件,和 main-window.ts 文件。其中 index 作为项目入口,main-window 用于定义创建 BrowserWindow 的相关方法。

      // main-window.ts
      import { BrowserWindow, app } from "electron";
      import { resolve } from "path";
      const isDev = !app.isPackaged;
      
      export function createWindow (): BrowserWindow {    
          const minWidth = 800;
          const minHeight = 600;
          // const preloadUrl = "";
          const window = new BrowserWindow({
              minWidth,
              minHeight,
              frame: false,
              backgroundColor: "#ffffff",
              // webPreferences: {
              //     preload: preloadUrl
              // }
          });
          
          if (isDev) {
              window?.loadURL(`http://localhost:${process.env.PORT || 5173}`);
              window.webContents.openDevTools();
          } else {
              window?.loadFile(resolve(__dirname, "../render/index.html"));
              window.removeMenu();
          }
      
          window.on("closed", () => {
              window.destroy();
          });
      
          return window;
      }
      
      
      // index.ts
      import { app } from "electron";
      import { createWindow } from "./main-window";
      
      
      async function bootstrap () {
          app.on("ready", () => {
              const window = createWindow();
          });
      }
      
      bootstrap();
      
  • package.json 文件中添加启动命令

    需要安装 concurrently 依赖,用于启动多个监听服务。(web服务和electron服务)

    pnpm install -D concurrently
    
    {
        "scripts": {
            "preinstall": "npx only-allow pnpm",
            "dev:render": "vite",
            "build:render": "vue-tsc && vite build",
            "build:electron": "tsc -p ./src/main",
            "dev:electron": "npm run build:electron && electron .",
            "dev": "concurrently \"npm run dev:render\" \"npm run dev:electron\""
        }
    }
    
  • src > render > index.html 文件中添加 meta标签 设置安全策略,避免 electron 告警 Insecure Content-Security-Policy

    <meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline';">
    
  • 设置 preload 相关内容

    • 在该目录下初始化 typescript npx tsc --init

      {
        "compilerOptions": {
          "allowJs": true,
          "alwaysStrict": true,
          "esModuleInterop": true,
          "forceConsistentCasingInFileNames": true,
          "isolatedModules": true,
          "jsx": "preserve",
          "lib": ["dom", "es2017"],
          "module": "commonjs",
          "moduleResolution": "node",
          "noEmit": false,
          "noFallthroughCasesInSwitch": true,
          "noUnusedLocals": false,
          "noUnusedParameters": true,
          "resolveJsonModule": true,
          "skipLibCheck": true,
          "strict": true,
          "target": "esnext",
          "outDir": "../../dist/preload",
        },
        "exclude": ["node_modules"],
        "include": ["**/*.ts", "**/*.tsx", "**/*.js"]
      }
      
      
    • src > preload 目录中创建 index.tstypes.d.ts 文件。其中:index.ts 作为 preload 入口文件;types.d.ts 文件用于定义preload相关类型,并将其挂载于web端window对象上。

      // index.ts
      import { contextBridge, ipcRenderer } from "electron";
      const sayHello = () => {
          console.log("hello");
      };
      
      const apis = {
          sayHello: sayHello
      };
      
      export type Apis = typeof apis;
      
      contextBridge.exposeInMainWorld("ipcRenderer", ipcRenderer);
      contextBridge.exposeInMainWorld("Main", apis);
      
      // types.d.ts
      import type { ipcRenderer } from "electron";
      import type { Apis } from "./index";
      
      declare global {
          interface Window {
              ipcRenderer: typeof ipcRenderer;
              Main: Apis;
          }
      }
      
    • src > main > main-window.ts 文件中引入preload并将其挂载于 webPrefrences 上,以达到在web端正常访问 preload 相关api的目的。

      // ...
      const window = new BrowserWindow({
          // ...
          webPreferences: {
              preload: resolve(__dirname, "../preload/index.js")
          }
      });
      // ...
      

    到此electron以引入完毕,可在web端,可通过如下代码测试

    if (window.Main) {
    	window.Main.sayHello();
    }
    

引入 electron-builder 处理打包事宜

  • 安装

    pnpm install -D electron-builder
    
  • 配置

    productName: 资料管理
    nsis:
      oneClick: false
      shortcutName: 资料管理
      allowToChangeInstallationDirectory: true
      installerIcon: ./src/render/public/logo.ico
      uninstallerIcon: ./src/render/public/logo.ico
      installerHeaderIcon: ./src/render/public/logo.ico
    files:
      - dist
    directories:
      output: dist
    extraResources:
      - data
    win:
      icon: ./src/render/public/logo.ico
      target:
        - target: nsis
          arch:
            - x64
      artifactName: 资料管理.exe
    
  • 修改 package.json 文件

    // 增加包描述
    "description": "本地资料管理平台",
    "author": {
        "email": "[email protected]",
        "name": "wkj"
    },
    
    // 设置脚本 (增加 build 、 dist命令,用于构建资源、打包成windows应用)
    "scripts": {
        "prepare": "husky install",
        "preinstall": "npx only-allow pnpm",
        "dev:render": "vite",
        "build:render": "vue-tsc && vite build",
        "dev:electron": "npm run build:electron && electron .",
        "build:electron": "npm run build:preload && tsc -p ./src/main",
        "build:preload": "tsc -p ./src/preload",
        "dev": "concurrently \"npm run dev:render\" \"npm run dev:electron\"",
        "build": "npm run build:render && npm run build:electron",
        "dist": "electron-builder"
    },
    

你可能感兴趣的:(vue.js,electron,javascript)