Electron Buildin

Shocking discoveries abound Oct 11, 2018 Tags: Javascript Electron Programming

So I created another app for macOS mininote (available: here), the reason I created this is simple…I have a convoluted process for making small notes or pasting them from my clipboard and it involves alfred -> textedit.app -> cmd+p or jotting down my note. Or sometimes I’ll open up the note app. But honestly I really got tired of doing that, and I didn’t want to keep either of them in my dock if only purely for aesthetics (I am chuckling as I write this). So I decided why not make a small scratchpad app that will live in my menu bar. I did some surface level searching for one, and came across evernote’s application but I didn’t want all the other crap it came with. I wasn’t trying to organize, sort, and archive my notes. I literally just wanted something I could quickly cmd+v something into or jot down random note and then go about my day until I needed it again. I figured, why not build it, how hard could it be?

It wasn’t really hard, but it was involved. First question what language I was going to write this in. I actually early on thought about doing it with Swift (and honestly might do a rewrite), but then I thought what if I want to distribute it on Windows because I run into the same issue there despite the fact that nowadays I only use my Windows machine to play games on Steam/Uplay/Origin. I’ve created two tiny apps with C# and .NET but I didn’t want to have to create one version of my app on macOS in Swift then another for windows in C#, that’s way too much work for my small app. So that left the only logical choice, Javascript and using Electron. There was also Java but…no. Don’t get me wrong, Java as a language is cool I guess, but yea no.

I have a few issues with Electron, mostly memory management. After learning C/C++, the various *allocs, pointers and referencing (not saying I’m a pro but I understand now). I’ve grown a great appreciation for performant, efficient code.

I am familiar with Electron as I’ve made an app with it previously called Reader, despite how it looks, it was pretty simple when you break it down. The hardest parts were related to interaction because I only used CSS/HTML for that instead of a UI framework like React or Vue.

With this project I decided I would use React, I’m familiar with it and feel confident enough that I can get something simple like mininotes to play nice. I will go into detail in another post on all of the things I did, this post serves mostly to write what I learned creating this app.

First thing I learned: Ejecting…still no reason to it at all! React build is still going to be your friend as it allows you to update as React receives updates. Another thing I learned…sometimes documentation isn’t the most clear from the examples given. I didn’t git commit them but I assure I spent a good week or two slamming my head against my machine trying to figure out why I couldn’t get menu icons to show up using Electron-Builder but everything worked with Electron-Packager.

Finding a React Markdown component was fairly simple, I started with React-Ace but I was searching for a way to do inline text manipulation without needing a second screen and it seemed like I had to jump through hoops to get React-Ace to do the basics of that, though I did like the various languages it would parse, if the need for more arised. So I kept looking until I stumbled upon React-SimpleMDE. It allowed same window editing but had editor icons associated with it. That was no problem, I figured I’d just hack them out (which I proceeded to do until seeing the option to remove it lol). Did the neessary React setup (creating an handleChange…handler and setting the text to the user passed value). Even though I’m decent with React, I quite often find myself forgetting some of the basics and needing to consult other projects I’ve done to remind myself (es un poco molesto). Once I got that working, I was essentially done as I didn’t need to pass the data back to electron as React was responsible for the UI (this will also make persistence straightfoward later, if I choose to implement it).

From here I spent time styling the app (admittedly it wasn’t a whole bunch to style but still I I needed it to look nice), most of my time was spent on logo and menu icon design more than anything, I’m not trying to set the world on fire and win awards so I kept it simple, only doing three sketches before I opened Sketch and went to work. Now that I had that out of the way, it was time to package the app. Sidenote: I settled on 32x32 for the @2x menu icon size, and 16x16 for the @1x, in case anyone is reading this and wants to know the dimensions. I tried larger (44x44) but it looked entirely too big and had no padding so it sat at the edge of the top and bottom of the menubar, and it just looked hilariously out of place next to my other menubar apps’ icons.

Now it’s time to package this sucker, I initially decided on using Electron-Packager for this figuring that Electron-Builder was for more complex applications (I am not sure WHY I thought this), something I didn’t realise until this app was that Electron-Packager with it’s default settings just shoves the entire project folder as it is into your .dmg file, which is like holy shit why?! As a result of this, my app was over 700mb in size…yea that was unacceptable, I was determined to get Electron-Builder to work, Electron apps are already huge because they require chrominium instance to run and that’s 40MB by itself.

Where I messed up with Electron-Builder: The build section of package.json; looking at various examples online, I thought the only thing I needed was my build directory that is produced by yarn/react build command. But this isn’t actually correct, I pretty much forgot that build will only produce code related to React (I know I know how did I forget this lol) so for a good 4 days, I sat in frustration wondering why things weren’t working when I packaged the app but worked fine when I ran electron .. I didn’t have to do any of this with Readr because again it was CSS/HTML in the sense of not using a UI framework that utilized webpack or Rollup.js, or anything. Just a couple of files contained within the same folder (note to self, go back and separate things into different folders honestly). So once the lightbulb went out that reminded me I needed to include my electron folder (for two of those days, I honestly thought it was the way I was naming my folder containing my electron code 😂). So I had to tell Electron-Builder the folders it needs, which looks like

  "build": {
    "files": [
      "build/**/* (this is the react build folder and all it's sub-folders)",
      "electron/**/*" (all my electron code and sub-folders)",
      "assets/**/* (contains the obvious)"
    ]
  }

Ran Electron-builder and…nope, so close! An error slightly unrelated to my project, I got a node error regarding fsevents, which was not resolved by npm installing it, well fuck so what do I do? Well apparently I could get around it by simply running the same command via yarn…I don’t understand exacly why that I but honestly I didn’t research into it too much, this was supposed to be a weekend project that ended up becoming a two week project smh. (Note: the project was longer than the github log suggests, I duplicated the folder later and setup a new git).

So the build is now working? No, apparently Electron-builder could not find main.js despite the fact I specified it in my package.json, some internet searching told me to add homepage:'./' to my package.json file, alright. So I tried that…and no dice. Hmm, well that addtion does make sense, as it would tell Electron what the entry point is for the app but yet it produces nothing. So some more digging on the interwebs taught me about Electron-Builder’s metadata option, which basically let’s you inject a file during the build project. After conflicting information on the correct syntax to use, which was -c.extraMetadata.main=electron/main.js (in my case the main.js was located in the electron folder). Again I emphasis that electron/main.js is specified as the starting point, which is fine for Electron itself (running electron . produces no issues), but apparently means nothing to Electron-Builder? Anyways, that option fixes it. But I the npm fsevents issue popped back up. So I created a script called electron-pack to build the app using the aforementioned flag and much like last time it worked.

Alright, so everything builds and actually runs! Yatta, but one final issue stood in my way, Mojave came out and I introduced a dark mode. So now I had to figure out how to account for people using the dark mode menu bar, scheiße! I sat for about an hour searching through Electron documentation for API hooks for Mojave’s dark mode. I figured it’d be a pretty simple if statement, dark mode ? dark menubar icon : light menubar icon. I ended up finding out it was even more simple than that! Because I’ve always used dark mode (and prior a dark menu bar) I created the mininote icon in white…which is wrong. All I had to do was create the icon in #000 black, and make sure the file name ended with Template.png ex: trayIconTemplate.png, and macOS takes care of making it white when used with dark mode, or leaving the icon as it’s default black when used in light mode.

So that’s the basic run down of the creation of this app, or rather some of the random hangups I had while creating it.