uAid Clipboard —— 基于Electron的一个小工具的自我总结

简介

概述

  • 场景背景:现在但凡有一点深度讲解的文章动辄上万字,当我们沉浸式阅读时,为了保证阅读质量会避免不必要的应用切换,但是又要做文章的摘要,uAid Clipboard 提供了这个功能,而你要做的只是选中句子右键复制,Clipboard 会帮你记录好,等你完成连续性阅读后再回过头来复习下看看你做了什么。
  • 技术背景:尝试下Electron应用开发

使用介绍

主面板

main.png
usage.png
setting.png

关于隐私

uAid Clipboard 记录的内容都保存在你的本地,绝对不会上传到服务,你可以从源码上分析出来。

安装

有2种形式来获取安装包:

  • 直接下载dmg文件安装,安装包地址:(暂不提供)。注意:受到苹果开发者权限限制,安装后无法打开应用,可以通过右键应用打开的方式打开,访达(Finder) -> 应用程序(Applications) -> uaid Clipboard -> 右键 -> 打开(open)
  • 下载原码包本地构建安装
    1. git clone git@github.com:cowboykx/uaid-clipboard.git
    2. cnpm install
    3. npm run pack
    4. cd dist
    5. open dmg file

架构

运行环境依赖

runtime.png
  • 整体面向用户侧使用React,状态管理使用 mobx,快捷键使用hotkeys-js
  • nodejs执行环境使用了,menubar来做菜单样式,nedb来处理本地存储,electron-clipboard-watcher 来监听系统粘贴板信息

编译环境

pack.png

这里 main.js 指的是在electron nodejs执行环境的js文件,考虑webpack编译nodejs文件没带来太多的价值,只是使用tsc做了一个typescript的编译功能。在webkit执行的 js browser.js 和 preload.js 使用了webpack打包

遇到的问题

webpack 构建器

webpack打包nodejs文件:起初想用webpack打包nodejs文件,需要在webpack配置文件里配置nodejs各种环境,例如 __dirname,但是总体来说带来的收益不大,后来直接使用 ts 做编译。

配置 __dirname,参考文档:https://zhuanlan.zhihu.com/p/20782320

...
context: __dirname,
node: {
    __filename: false,
    __dirname: false
},
...

babel@8.x.x 的配置

起初没有引入ts,使用babel来编译js,配置webpack和babel真的是一个头疼的事情,花了不少时间,一定要注意babel 和 babel-loader版本,这里记录先之前配置的信息

package.json

{
  "@babel/cli": "^7.0.0-beta.40",
  "@babel/core": "^7.0.0-beta.40",
  "@babel/plugin-proposal-class-properties": "^7.8.3",
  "@babel/plugin-proposal-decorators": "^7.8.3",
  "@babel/preset-env": "^7.8.4",
  "@babel/preset-es2015": "^7.0.0-beta.53",
  "@babel/preset-react": "^7.0.0-beta.40",
  "@babel/preset-stage-0": "^7.0.0",
  "babel-loader": "^8.0.0-beta.0",
  "css-loader": "^3.4.2",
  "extract-text-webpack-plugin": "^4.0.0-beta.0",
  "less": "^3.11.1",
  "less-loader": "^5.0.0",
  "style-loader": "^1.1.3",
  "webpack": "^4.41.6",
  "webpack-cli": "^3.3.11"
}

webpack.config.js

const Ex = require('extract-text-webpack-plugin');
const path = require('path');
const fs = require('fs');

const projectRoot = path.join(__dirname, '..');

module.exports = {
  mode: 'production',
  entry: {
    'browser': './src/browser/index.jsx'
  },
  output: {
    path: projectRoot,
    filename: './out/[name].js'
  },
  target: 'node',
  optimization: {
    minimize: false
  },
  resolve: {
    extensions: [".jsx", ".js"]
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        loader: "babel-loader"
      },
      {
        test: /\.less|\.css$/,
        loader: Ex.extract({
          fallback: 'style-loader',
          use: ['css-loader', 'less-loader']
        })
      }
    ]
  },
  plugins: [
    new Ex('./out/[name].css'),
  ],
  externals: {
    "antd": "antd",
    "react": "React",
    "react-dom": "ReactDOM",
    "moment": "moment"
  }
}

typescript

tsconfig.json

tsconfig没什么好说,在webpack里可以指定tsconfig,针对 browser/preload/main 分别使用三个json,

{
  test: /\.(ts|tsx)?$/,
  loader: 'ts-loader',
  exclude: /node_modules/,
  options: {
    configFile: path.resolve(__dirname, '../tsconfig.browser.json')
  }
}

tsconfig编译参数

这里只提常用的

  • target:指定需要编译js的版本
  • module: 指定编译后的模块方案
  • lib: 指定要包含在编译中的库文件,例如:"es5", "es6", "es7", "dom"
  • jsx: 指定支持的jsx类型,react-native react preserve
  • declaration: 是否生成 *.d.ts 文件
  • outDir:输出文件目录,如果是用webpack编译的话,这个选项可以不用
  • typeRoots 和 types:这2个参数用来指定 @type 文件的目录和引入哪些 types,平常我们不会用到。
    • typeRoots 默认为 ./node_modules/@types
    • types:如果设定了,就只会从 typeRoots 取对应的
  • experimentalDecorators: 开启装饰器,请设置打开吧

如下为我常用的配置
tsconfig.base.json

{
  "compilerOptions": {
    "baseUrl": ".",
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "allowJs": false,
    "alwaysStrict": true,
    "importHelpers": true,
    "lib": ["es5", "es6", "es7", "dom"],
    "module": "CommonJS",
    "moduleResolution": "node",
    "noEmitOnError": true,
    "noImplicitThis": true,
    "noImplicitAny": false,
    "sourceMap": false,
    "declaration": false,
    "declarationMap": false,
    "target": "es2017",
    "resolveJsonModule": true,
    "paths": {
    }
  }
}

tsconfig.node.json

{
  "extends": "./tsconfig.base",
  "compilerOptions": {
    "target": "ES5",
    "outDir": "out/node"
  },
  "include": [
    "./src/node"
  ]
}

Mobx

mobx store

请开启 enforceActions,修改数值必须通过 action

import { configure } from 'mobx';

configure({
  enforceActions: true
});

mobx 异步修改状态

大部分时间我们使用 async/await 来做协程,async 函数里我们只能通过 runInAction 来改变状态

import { runInAction, action } from 'mobx';

class Store {
 ...
 @action
    update() {
    ...
    runInAction(() => {
        ...
    })
    ...
  }
 
 ...
  
}

npm

关闭 package-lock.json 文件生成

vim ~/.npmrc

package-lock=false

设置淘宝源

vim ~/.npmrc

registry=https://registry.npm.taobao.org/

Electron

设置 electron 源文件地址

受到网络影响,国外站点的资源无法获取,可以设置下electron的国内镜像地址<br />vim ~/.npmrc<br />

ELECTRON_MIRROR=http://npm.taobao.org/mirrors/electron/

CSP 同源策略

在html里异步加载资源会报错,例如antd在做状态时会动态插入一些样式,这个时候你需要指定下同源策略

<head>
    <meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline'; script-src 'self'">
    <meta http-equiv="X-Content-Security-Policy" content="default-src 'unsafe-inline'; script-src 'self'">
</head>

打包

使用 electron-builder 打包(https://www.electron.build/),包的icon放到 根目录的build目录下,https://www.electron.build/icons

打包脚本,package.json

scripts: {
    "pack": "npm run build && electron-builder --mac --x64"
}

打包镜像下载

electron-builder 在打包时会检测cache中是否有electron 包,如果没有的话会从github上拉去,在国内网络环境中拉取的过程大概率会失败,所以你可以自己去下载一个包放到cache目录里,参考:https://github.com/electron/get#how-it-works

各个平台的目录地址

  • Linux: $XDG_CACHE_HOME or ~/.cache/electron/
  • MacOS: ~/Library/Caches/electron/
  • Windows: %LOCALAPPDATA%/electron/Cache or ~/AppData/Local/electron/Cache/

例如在macos平台打包electron应用,执行 electron-builder --mac --x64

➜  clipboard git:(master) ✗ npm run dist
> clipboard@1.0.0 dist /Users/xx/workspace/electron/clipboard
> electron-builder --mac --x64
  • electron-builder  version=22.3.2 os=18.7.0
  • loaded configuration  file=package.json ("build" field)
  • writing effective config  file=dist/builder-effective-config.yaml
  • packaging       platform=darwin arch=x64 electron=8.0.0 appOutDir=dist/mac
  • downloading     url=https://github.com/electron/electron/releases/download/v8.0.0/electron-v8.0.0-darwin-x64.zip size=66 MB parts=8

可以单独下载这个包 https://github.com/electron/electron/releases/download/v8.0.0/electron-v8.0.0-darwin-x64.zip, 放到~/Library/Caches/electron/ 目录下

谢谢

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容