Piece 开发小记
Thinking
Piece 是一个简单的用于临时记录的 Mac App。最初会想到做这么一个 App 是因为在生活中,有时候会喜欢先在纸上记一下最近待办的事情,或者睡前也会想想明早起来要做什么先记下来。(在写这篇文章的时候发现 Piece 还可以用来记下提纲或思路,放在一边置于桌面最前端,边看边写)。加上最近对 GitHub 发布的 Electron 跨平台的开发挺感兴趣的,于是一拍即合,写了起来。
大概先从上周五开始去了解 Electron 的一些基本概念和实现思路,做了一些初步的 UI 设计,大概周六开始正式开发。期间遇到了一些坑,踩进去了又出来了;也产生了一些新的想法和感悟,都在这里小记一下。
Coding
这次一来为了更方便进行跨平台开发,二来想尝试一下 Electron,便没有用 Objective-C 编写。看了一下 GitHub 上的统计,现在 74% 的代码是 JavaScript,其他的是 HTML 和 CSS。
首先是项目开始前的准备工作,包括初始版本主要功能的确定,一些界面的简单设计,项目结构设计与项目构建等。在酝酿了一两天的基础上,这些工作有部分已经基本完成。但其实在初始版本主要功能的确定上还不太明确,这也导致了开发过程中部分功能初步实现了但是最后并没有加到项目里。
项目的基本构建完成后,接着就开始把静态的页面写出来了。这次用了 React 来写 UI,很喜欢这种 UI 组件化的思想。项目目前还比较简单,这次使用 React 主要用来实现 View 部分,没有使用 Redux 或 Flux。样式方面算是第一次正式尝试用 Less 而不是 Sass。两者虽说相近,但 Less 的确比 Sass 要 “Less” 一些。Piece 的产品哲学是 Less equals More,也勉强算是用 Less 进行样式开发的一个原因吧。
页面完成后,慢慢地添加交互部分与一些细节功能。说来好似轻松,但在写页面时,就因为不太明确“是否要在初始版本加入简单的富文本编辑功能”而尝试着去开发富文本编辑器了……富文本编辑器的实现方式最常见的就是使用 iframe 加上 JavaScript 对 DOM 的操作。但实际上这里面还藏了大大小小的坑。最终虽说实现了想要的简单富文本编辑的雏形,但离理想的样子还是要继续努力。在最终确定了初始版本的功能后,这部分也先“藏”了起来,但花在这上面的时间和精力还是蛮多的。
除去前面富文本编辑的实现外,主要就是和系统原生功能打交道啦,像 Tray 类型非经典 Dock 类型 App 的实现,菜单与全局快键键的实现等等。部分 UI 设计也是在这过程中完成。
项目用的是 Webpack 进行构建,而因为在 Electron 开发的 App 中,除了需要 Browser 环境来运行最终 Webpack 编译好的 JavsScript 代码外,同时又需要一些 Node.js 环境的模块用来和系统原生功能交互,比如文件系统。因而若直接使用 Webpack 编译代码会导致与系统原生功能有关的模块出现问题。最后是通过在 Webpack 的配置文件中加入插件如下解决。
new webpack.IgnorePlugin(new RegExp("^(fs|nconf|path)$"))
最后是打包与发行项目。到这一步以为已经迈过了许多坑坑洼洼,但实际上这部分的坑坑洼洼也有很多。先用 electron-package 进行打包,但打包之后只有 .app 格式的文件,而且文件信息里的版本号是 Electron 的版本号而不是 App 本身的版本号。作为开发者来说,看着还是挺不舒服的。
于是接下来再进行正式的发行打包工作,用 electron-builder 来进行各个平台的发行,不过初始版本打算暂时只支持 Mac 平台。用 electron-builder 之前先把项目结构改成了 Two package.json,Development 和 Application 各一个,同时在这个过程中把发行打包需要的图标文件画好准备好。打包好之后,产物是 .app 文件,包含 .app 文件的压缩包 .zip 以及常见的 Mac App 安装包 .dmg。打开 .dmg 看到界面显示将左侧 Piece 图标拖动至右侧的 Applications 文件夹时,还是蛮有成就感的。
但打包之后运行起来就会发现还是有些地方不太一样了。比如开发过程中,每次运行 App 时都会有系统默认的原生菜单(其实是 Electron 的菜单),比如 Edit 和 Window 等。但打包后,由于是 Tray 类型的 App,一开始并没有发现是因为原生菜单没有了导致了基本的文本编辑功能失效,包括全选,撤销,剪切,粘贴等。其实只要自己再定义一下 App 的 Edit 菜单就可以了。
同时,文件保存也是一个小小的坑洼。打包之前还能够通过 nconf 便捷地对项目内的用户配置文件进行读写,但打包之后就不太行了。最后是改变配置文件的路径来实现。
最后一个比较具体的问题是,窗口关闭时触发的 Close Event 并没有将最终 ipc 传来的方法进行响应,有可能是来不及响应。用于窗口关闭时会触发 window.onbeforeunload
,最后也是通过改变触发方法的地方来解决。
window.onbeforeunload = (e) => {
ipcRenderer.send('save-content', content);
};
最终完成之后,在 GitHub 上 release 了项目的 1.0.0 版本。第一次超认真地写起 readme.md。然后发给 Mac 的朋友们试试,尝尝鲜。
Thinking Again
之后还会有新的版本更新,但总的来说还是保持简单的状态。毕竟 Piece 的产品哲学是 Less equals More. 除了新的功能比如前面所说的简单富文本编辑外,之后的版本里还会加上对 Windows / Linux 的支持,自动更新 App 的功能的。
Landing Page 有空也要为 Piece 写一写,吸引更多用户。还有就是一些 Bug 的修复啦。
其实无论是设计也好还是开发也好,第一件事情应该是确定产品版本功能的迭代规划以及 Bug 的去除。包括像产品的哲学。每件产品都应该有专属的故事,把故事想好、讲好,这才是最重要的。
总之以后可以在睡前写下明天一早起来要干些什么,工作时有一些细碎的想法也可以立刻写下来啦。