vue+ts+electron踩坑记录
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue+ts+electron踩坑记录相关的知识,希望对你有一定的参考价值。
参考技术A在日常使用中发现某工具用得不太顺手,于是有了自己做一个工具的想法。想做一个跨平台的桌面应用, electron 是个不错的选择,于是开始了我的踩坑之旅。
有了 vue-cli 脚手架在,搭建 vue+TS 的初始环境非常简单,运行后把语言选上 typescript 就行。
初始化完成后,会生成一个模板项目,我们可以基于模板进行开发。
这里要提一句,如果想把原来的项目升级成使用 ts 的,其实非常简单,使用 vue-cli 执行 vue add @vue/typescript 就可以了,自动帮你处理好依赖问题。而且更方便的是,升级后兼容原来的写法和新写法,只要在 scrip 标签中不加 lang="ts" 就可以继续使用原来的写法,方便给原有项目逐步升级。
注,如果遇到重名的,模板文件会覆盖原有文件。所以最好在有git的情况下执行命令。此外,此方法只支持用vue-cli初始化的项目,直接使用 webpack 的项目请按照官方说明进行升级。
初始化后,可以安装你需要的依赖,比如 element-ui 。 element-ui 自带 types 文件夹,自动补全非常方便。现在常用的依赖基本都有声明文件 d.ts ,在编码的时候可以很明显得感觉到便利,这也是 Typescript 的优势之一。
添加 electron 依赖: npm install --save-dev electron ,然后在 package.json 的 scripts 加一行 "electron": "electron ." ,方便执行。
electron 是 node 服务端内容,而 import 默认是由 webpack 来处理,相当于是浏览器进程来尝试加载。浏览器进程不能调用服务进程的一些接口,如 fs 模块只能在服务端加载。在浏览器进程加载 electron 就会报错。
解决方案:
使用 electron 暴露出来的接口: const ipcMain = window.require(\'electron\') 。
由于 window.require 是由 electron 暴露出来的, TS 无法识别。在 main.ts 中加入声明即可:
此外,如果在页面中提示 require 没有定义,那么需要在electron主进程中 new BrowserWindow 里添加如下选项:
自electron 5.X开始, nodeIntegration 就默认为 false 了,所以需要手动引入。
一般这种情况是没有 export 类出来,导出一个空类即可。使用 TS 后,不允许空 script 存在,即使页面没有任何内容都需要加一个空类。
需要在 main.ts 中加入声明:
在对应类中添加注释即可。这里以 element-ui 的某个组件为例:
这里有多个坑:
用 electron 来集成vue-devtools过于麻烦,一个简单的方法是使用远程调试。
yarn global add @vue/devtools 安装,然后运行 vue-devtools ,在模板 index.html 中引入脚本就可以开始调试了。
简单看了下文档,macos程序的打包只能在macos环境下,linux下打包window需要借助wine或者docker,window倒是很方便打包window和linux的程序。本人在linux下开发,不想折腾docker和wine,所以只写linux for linux的打包过程。
ignore 中可以写你需要除外的文件。
到这里,基础配置部分已经完成了,我们只需要编译vue后,将dist文件夹移动到electron入口文件index.js同级下,最后执行 electron-forge make 就可以等结果了。
PS:以上操作适用于electron主进程和vue项目分离的情况,两者有各自独立的 package.json 和 node_modules 。否则, electron-forge 在打包时会把 node_modules 内所有文件复制过去,造成最后打包的文件非常大。如果在这种情况下需要进行优化,可以使用webpack打包electron主进程,然后打包时删掉 node_modules 文件夹等多余文件。
在 Vue 中使用 Typescript
前言
恕我直言,用 Typescript 写 Vue 真的很难受,Vue 对 ts 的支持一般,如非万不得已还是别在 Vue 里边用吧,不过听说 Vue3 会增强对 ts 的支持,正式登场之前还是期待一下吧嘻嘻。
本篇不会过多讲述 ts 语法,着重记录下 在 Vue 中使用 ts 的方法以及踩坑经过。
如果是使用 Vue Cli2 搭建的项目,要注意 webpack 版本可能与 ts-loader 版本不匹配,可以降低 ts-loader 版本到 3.0+ 或者 将 webpack升级到 4.0+ (本篇所用版本 webpack@3.6.0 + ts-loader@3.5.0)
主要步骤
1. 先要让 vue 项目可以识别 .ts 文件。安装关键依赖 npm i typescript ts-loader -D
2. 在 webpack.base.config.js 中添加 ts-loader
//resolve.extensions 里面加上.ts 后缀 之后引入.ts的时候可以不写后缀 { test: /.tsx?$/, loader: ‘ts-loader‘, exclude: /node_modules/, options: { appendTsSuffixTo: [/.vue$/], //关键 } }
3. 在根目录建tsconfig.json文件 下面的配置仅供参考
{ "include": [ "src/**/*" ], "exclude": [ "node_modules" ], "compilerOptions": { "allowSyntheticDefaultImports": true, "experimentalDecorators": true, "allowJs": true, "module": "esnext", "target": "es5", "moduleResolution": "node", "isolatedModules": true, "lib": [ "dom", "es5", "es2015.promise" ], "sourceMap": true, "pretty": true } }
4. 接着需要确保在 vue 中可以正常使用 ts 。安装 vue-class-component(为vue组件提供修饰器) vue-property-decorator(更多的结合vue特性的修饰器) [ tslint tslint-loader tslint-config-standard(可选 约束.ts/.tsx代码格式)],这样就可以在 vue 文件中使用诸如 @Component、@Prop等装饰器了。注意:.vue 文件中的 script 标签要加上 lang="ts"。关于 装饰器的使用可以参看下这位大哥的文章:https://segmentfault.com/a/1190000019906321
<template> <div class="count-down" v-html="countDown(endDate)"> </div> </template> <script lang="ts"> import { Component, Prop, Vue, Emit } from "vue-property-decorator" import moment from ‘moment‘ @Component export default class CountDown extends Vue { @Prop() endDate!: string // 变量后加!是非空断言 now: any = moment() mounted() { setInterval((): void =>{ this.now = moment() },1000) } destroyed() { } get countDown(): object{ return function(endDate: any): string { let m1: any = this.now let m2: any = moment(endDate) let du: any = moment.duration(m2 - m1, ‘ms‘) let hours: number = du.get(‘hours‘) let mins: number = du.get(‘minutes‘) let ss: number = du.get(‘seconds‘) if(hours <= 0 && mins <= 0 && ss <= 0) { // this.$emit(‘timeout‘) this.timeout() return "今日已结束" }else { return `${this.PrefixInteger(hours,2)} <span style="font-size: 16px;">小时</span> ${this.PrefixInteger(mins,2)} <span style="font-size: 16px;">分钟</span><span style="color: #F56C6C;"> ${this.PrefixInteger(ss,2)} </span><span style="font-size: 16px;">秒</span>` } } } @Emit() timeout(){} //数字前补 0 // num传入的数字,n需要的字符长度 PrefixInteger(num: number, n: number): string { return (Array(n).join(‘0‘) + num).slice(-n) } } </script> <style lang="less" scoped> //... </style>
5. 将main.js 变成 main.ts 并且在 webpack.base.conf.js 修改入口为main.ts,这一步至关重要。
6. 在 src 目录下新建文件 shims-vue.d.ts ,告诉 TypeScript *.vue 后缀的文件可以交给 vue 模块来处理,注意 在代码中导入 *.vue 文件的时候,需要写上 .vue 后缀,这里可以参考官网说明:增强类型以配合插件使用
declare module "*.vue" { import Vue from "vue"; export default Vue; }
踩坑记录
1. 报错如下,报错原因一是没有将入口文件改成 ts,二是 webpack.base.conf.js 中引入 ts-loader 错误,没有加上 options: { appendTsSuffixTo: [/.vue$/], }
Module build failed: Error: Could not find source file: ‘XXX/src/App.vue‘.
2. 全局属性报错 如 Vue.prototype.$msg = XXX,需要将全局属性在 .d.ts 文件中声明
import Vue from "vue"; import { AxiosInstance } from "axios"; import { ElMessage } from "element-ui/types/message"; declare module "*.vue" { export default Vue; } declare module ‘vue/types/vue‘ { interface Vue { $http: AxiosInstance, $message: ElMessage } }
3. 使用上面这种声明全局属性的方式又会带来新的问题,报错 import App from ‘./App.vue‘处,找不到 App.vue 这个模块,虽然不影响编译,但是这红色的波浪线就像老鼠屎,看着那叫一个难受呀。解决方法:将 shims-vue.d.ts 文件一分为二,将全局属性声明和 Vue 的声明分离;在 shims-vue.d.ts 文件同级目录下新建 vue.d.ts(名字不一定叫 vue,如 xxx.d.ts 也可以);关键是要将以下代码放在单独的 .d.ts 文件中
declare module ‘*.vue‘ { import Vue from ‘vue‘ export default Vue }
以上是关于vue+ts+electron踩坑记录的主要内容,如果未能解决你的问题,请参考以下文章