ClojureScript + Electron + Packaging

This is a follow-up post from here: ClojureScript + Electron.

Well, that was short-lived. I don’t particularly like how NPM handles its dependencies. Basically, it flattens all of them exposing the inner details of the dependency graph to the project. Part of this is aid in sharing those dependencies. This is why I went with the Grunt task to download Electron.

But… often times, we need to make trade-offs. It’s always a trade-off to take a dependency on a project vs. write it ourself. This is one of those times where I simply want to take the dependency as its surface area is extremely narrow.

The dependency? electron-packager. This makes it extremely easy to package up our app into a proper distributable app bundle.

The side-effect from taking this dependency? We need to take the electron package from npm as well. This means getting rid of our Grunt task.

Just a brief aside… a little more explanation of why I don’t like this approach. I basically have a “hello world” app at this point. I have dependencies on Grunt, NPM, Le, Leiningen, and Electron. My node_modules directory is sitting at 210 dependencies and over 150 MB.

That is ridiculous.

Grunt Updates

First things first, we need to update the Grunt file to get rid of the download-electron bits.

diff --git a/Gruntfile.js b/Gruntfile.js
index abf0abf..bbb9ead 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,11 +1,6 @@
 module.exports = function(grunt) {
         pkg: grunt.file.readJSON("package.json"),
-        "download-electron": {
-            version: "<%= pkg.config.electron.version %>",
-            outputDir: "<%= pkg.config.electron.installDir %>",
-            rebuild: true
-        },
         "generate-manifest": {
             name: "<%= %>",
             version: "<%= pkg.version %>",
@@ -27,7 +22,6 @@ module.exports = function(grunt) {
-    grunt.loadNpmTasks("grunt-download-electron");

That’s the git diff output. Basically, just delete all of the download-electron bits.

NPM Updates

For NPM, we need to add in the dependencies:

diff --git a/package.json b/package.json
index d5d8127..c4818a5 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,8 @@
   "version": "0.1.0",
   "description": "Test configuration",
   "devDependencies": {
+    "electron": "1.5.0",
+    "electron-packager": "^8.5.1",
     "grunt": "^1.0.0",
     "grunt-download-electron": "^2.1.4",
     "grunt-contrib-symlink": "^1.0.0"
@@ -12,7 +14,6 @@
   "config": {
     "electron": {
       "version": "1.5.0",
-      "installDir": ".deps/electron",
       "manifestDir": ".out/app",
       "main": "electron-host"
@@ -20,8 +21,5 @@
       "src": "ui/public",
       "dest": ".out/app/public"
-  },
-  "scripts": {
-    "postinstall": "mkdir -p .deps/electron; grunt download-electron"

Basically, just remove the download-electron bits and add the electron and electron-package dependencies.

Run npm install and rm -rf .deps to pull down the packages and delete the old Electron shell that is no longer necessary.

Project File Updates

Lastly, it’s time to integrate in the new packaging system.

diff --git a/project.clj b/project.clj
index 440e10e..432fbba 100644
--- a/project.clj
+++ b/project.clj
@@ -20,7 +20,8 @@
                        ["cljsbuild" "once" "main"]
                        ["shell" "grunt" "generate-mainjs"]
                        ["shell" "grunt" "symlink"]
-                       ["cljsbuild" "once" "ui"]]}
+                       ["cljsbuild" "once" "ui"]]
+           "electron-package" ["shell" 
								".out/app" "--out=.dist"]}
  :cljsbuild {:builds {:main {:source-paths ["app/src"]
                              :incremental true
@@ -37,7 +38,7 @@
                            :incremental true
                            :assert true
                            :compiler {:output-to ".out/app/ui.js"
-                                      :output-dir ".out/lib/ui"
+                                      :output-dir ".out/app/lib/ui"
                                       :warnings true
                                       :elide-asserts true
                                       :optimizations :none

There are two primary changes here:

  1. Add in the electron-package alias to package up our app.
  2. Update the output-dir for our library output.

The second step is required because the electron-package tool expects all of our content to be within the .out/app folder. This makes sense. Note that we also need to update our index.html file:

See diff here: ui/public/index.html

I cannot for the life of me get WordPress to render HTML properly, even if it is escaped…

This changes the reference location of our libs.

Project Cleanup

One thing you’ll probably run into is that rebuilds don’t always seem to work. This is especially true for HTML file changes. Let’s create a nice alias to help us out with that:

diff --git a/project.clj b/project.clj
index 432fbba..7627d52 100644
--- a/project.clj
+++ b/project.clj
@@ -21,7 +21,8 @@
                        ["shell" "grunt" "generate-mainjs"]
                        ["shell" "grunt" "symlink"]
                        ["cljsbuild" "once" "ui"]]
-           "electron-package" ["shell" "./node_modules/electron-packager/cli.js" ".out/app" "--out=.dist"]}
+           "electron-package" ["shell" "./node_modules/electron-packager/cli.js" ".out/app" "--out=.dist"]
+           "electron-clean" ["shell" "rm" "-rf" ".out" ".tmp" ".dist"]}
  :cljsbuild {:builds {:main {:source-paths ["app/src"]
                              :incremental true

Wrapping Up

Now we have everything we need to package up our app! Sure, we will still be packaging up our unoptimized JavaScript, but that’s for another day.

To get a nice, clean build with a package up output, simply run:

lein electron-clean
lein electron
lein electron-package

There we go!

open .dist/blog-post-darwin-x64/

The full source can be found here:

Of course… now I want to completely get rid of the Grunt dependency. 😉

ClojureScript + Electron + Packaging

2 thoughts on “ClojureScript + Electron + Packaging

Comments are closed.