clojurescript编译后用electron打包成桌面应用安装程序

clojurescript最终还是编译成javascript在浏览器执行,本文描述的是在项目本身在C/S环境上运行没有问题的情况下,怎么将这些资源文件用electron打包成windows或者mac的B/S应用。

技术语言和工具:

第一步:打包cljs成可通过浏览器浏览的网络资源

我这个项目是用figwheel编译的,打包命令如下:

lein cljsbuild once min-doctor

如果是用shadow-cljs编译项目的话,命令应该是这样的:

shadow-cljs release app 

重点来了:这些编译文件只是将cljs打包成app.js文件,目录一般在target目录的某个问题,这两种方式都是这样的。
但是众所周知,运行一个网页只要一个js肯定是不行的,在用luminus创建出来的模板里,css和image文件都在resource/public目录下,包括入口的index.html文件。

用nginx等部署时需要将这些文件也一并copy到nginx服务器上,这一步就不说了。

第二步:将这些网络资源打包成electron安装程序

有了上面的入口文件,css和image,以及唯一的一个js文件,我们只需要将这些文件和electron的配置文件放在一起便可以了进行下一步了。

1. 构建electron的打包目录

我在项目根目录创建了个electron文件夹,会将资源文件copy到这个位置下。所以整个项目结构大概如下:

├── project
    │   ├── resource
    │   │     └──public
    │   │            └── img
    │   │                    ├── logo.png
    │   │                    ├── user-header.png
    │   │            └── css
    │   │            └── js
    │   │            └── index.html
    │   ├── src
    │   ├── electron
    │   │      └──public
    │   │            └── img
    │   │                    ├── logo.png
    │   │                    ├── user-header.png
    │   │            └── css
    │   │            └── js
    │   │            └── index.html
    │   │      └──package.json
    │   │      └──main.js

其中electron下的public文件夹内容结构就跟往nginx部署时是一样的,main.jspackage.json是为electron手动加入的。main.js是win的默认行为的指定文件,内容如下:

// Modules to control application life and create native browser window
const {app, BrowserWindow} = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
const mainWindowURL = 'http://localhost:10386/doc.html';

function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({
    //fullscreen: true,
    webPreferences: {
    },
  })

  // and load the index.html of the app.
//   mainWindow.loadFile('index.html')
  mainWindow.loadURL(mainWindowURL)


  // Emitted when the window is closed.
  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null
  })
}



function bootstrapServer() {
  const handler = require('serve-handler');
  const http = require('http');

  const server = http.createServer((request, response) => {
    // You pass two more arguments for config and middleware
    // More details here: https://github.com/zeit/serve-handler#options
    return handler(request, response, {
      public: 'resources/app.asar/public',
    });
  })

  server.listen(10386, () => {
    createWindow()
  });
}

app.on('ready', bootstrapServer)

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow()
  }
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

package.json的内容如下:

{
  "name": "eallergy",
  "version": "1.0.0",
  "license": "",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "dist": "electron-builder -c.extraMetadata.main=main.js",
    "dist-32": "electron-builder -c.extraMetadata.main=main.js --ia32"
  },
  "build": {
    "productName": "eallergy",
    "appId": "alk.doctor",
    "copyright":"小马***公司",
    "directories": {
      "buildResources": "public"
    },
    "files": [
      "main.js",
      "public/**/*",
      "node_modules/**/*"
    ],
    "mac": {
      "category": "your.app.category.type"
    }
  },
  "devDependencies": {
    "electron": "^5.0.7",
    "electron-builder": "^21.0.15"
  },
  "dependencies": {
    "serve-handler": "^6.1.0"
  }
}

将资源文件copy到electron/public/位置后执行yarnyarn dist命令(执行出错的请看下面的解决方案)。

2. 打包

执行打包之前还有点环境准备工作

安装node
安装yarn
安装electron
安装electron-builder

然后可以在electron目录下载执行打包操作

# yarn
yarn install v1.21.1
warning package.json: License should be a valid SPDX license expression
warning eallergy@1.0.0: License should be a valid SPDX license expression
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
Done in 13.47s.
$
$
$
$ yarn dist
yarn run v1.21.1
warning package.json: License should be a valid SPDX license expression
$ electron-builder -c.extraMetadata.main=main.js
  • electron-builder  version=21.0.15 os=10.0.18363
  • loaded configuration  file=package.json ("build" field)
  • description is missed in the package.json  appPackageFile=Z:\git\redcreation\alk-wxapi\alk-web\electron\package.json
  • author is missed in the package.json  appPackageFile=Z:\git\redcreation\alk-wxapi\alk-web\electron\package.json
  • packaging       platform=win32 arch=x64 electron=5.0.7 appOutDir=dist\win-unpacked
  • default Electron icon is used  reason=application icon is not set
  • building        target=nsis file=dist\eallergy Setup 1.0.0.exe archs=x64 oneClick=true perMachine=false
  • building block map  blockMapFile=dist\eallergy Setup 1.0.0.exe.blockmap
Done in 45.81s.
$

3. 打包文件

image.png

electron和electron-builder相关文件安装失败解决方案

错误版本不尽相同,但是大概如下吧

$ yarn dist
yarn run v1.21.1
warning package.json: License should be a valid SPDX license expression
$ electron-builder -c.extraMetadata.main=main.js
  • electron-builder  version=21.0.15 os=10.0.18363
  • loaded configuration  file=package.json ("build" field)
  • description is missed in the package.json  appPackageFile=Z:\git\redcreation\alk-wxapi\alk-web\electron\package.json
  • author is missed in the package.json  appPackageFile=Z:\git\redcreation\alk-wxapi\alk-web\electron\package.json
  • packaging       platform=win32 arch=x64 electron=5.0.7 appOutDir=dist\win-unpacked
  • default Electron icon is used  reason=application icon is not set
  • building        target=nsis file=dist\eallergy Setup 1.0.0.exe archs=x64 oneClick=true perMachine=false
  • downloading     url=https://github.com/electron-userland/electron-builder-binaries/releases/download/nsis-3.0.3.2/nsis-3.0.3.2.7z size=1.4 MB parts=1
  • retrying        attempt=1
  • retrying        attempt=2
  • retrying        attempt=3
  ⨯ part download request failed with status code 403
github.com/develar/app-builder/pkg/download.(*Part).doRequest
        /Volumes/data/Documents/app-builder/pkg/download/Part.go:126
github.com/develar/app-builder/pkg/download.(*Part).download
        /Volumes/data/Documents/app-builder/pkg/download/Part.go:67
github.com/develar/app-builder/pkg/download.(*Downloader).DownloadResolved.func1.1
        /Volumes/data/Documents/app-builder/pkg/download/downloader.go:107
github.com/develar/app-builder/pkg/util.MapAsyncConcurrency.func2
        /Volumes/data/Documents/app-builder/pkg/util/async.go:68
runtime.goexit
        /usr/local/Cellar/go/1.12.7/libexec/src/runtime/asm_amd64.s:1337
  ⨯ Z:\git\redcreation\alk-wxapi\alk-web\electron\node_modules\app-builder-lib\node_modules\app-builder-bin\win\x64\app-builder.exe exited with code ERR_ELECTRON_BUILDER_CANNOT_EXECUTE  stackTrace=
          Error: Z:\git\redcreation\alk-wxapi\alk-web\electron\node_modules\app-builder-lib\node_modules\app-builder-bin\win\x64\app-builder.exe exited with code ERR_ELECTRON_BUILDER_CANNOT_EXECUTE
at ChildProcess.childProcess.once.code (Z:\git\redcreation\alk-wxapi\alk-web\electron\node_modules\app-builder-lib\node_modules\builder-util\src\util.ts:239:14)
                   at Object.onceWrapper (events.js:273:13)
                                                                                                                                                                                                at ChildProcess.emit (events.js:182:13)
                                                                                                                                                                                                at maybeClose (internal/child_process.js:962:16)
                                                                                                                                                                                                at Process.ChildProcess._handle.onexit (internal/child_process.js:251:5)
                                                                                                                                                                                            From previous event:
                                                                                                                                                                                                at processImmediate (timers.js:632:19)
                                                                                                                                                                                            From previous event:
                                                                                                                                                                                                at NsisTarget.buildInstaller (Z:\git\redcreation\alk-wxapi\alk-web\electron\node_modules\app-builder-lib\src\targets\nsis\NsisTarget.ts:202:29)

安装electron依赖时被墙基本上躲不过去的,运气不好的时候就是一定躲不过去,这时候有三种方案

  • 设置electron的镜像为淘宝镜像,然后继续执行(推荐此方案
set ELECTRON_MIRROR=http://npm.taobao.org/mirrors/electron/

set SELENIUM_CDNURL=http://npm.taobao.org/mirrorss/selenium

set CHROMEDRIVER_CDNURL=https://npm.taobao.org/mirrors/chromedriver

set SASS_BINARY_SITE=https://npm.taobao.org/mirrors/node-sass/
  • 使用迅雷或者浏览器手动下载download失败的文件
    下载完后拖到C:\Users\mahaiqiang\AppData\Local\electron-builder\Cache\这个目录,解压好,重新dist,会优先使用缓存中的文件。注意版本一致。
    扔上去可能是这样:

    image.png

  • 在出错的命令上手动指定镜像
    执行类似下面的命令,在真正的命令前加参数

ELECTRON_MIRROR=https://npm.taobao.org/mirrors/electron/ yarn install

推荐方案一。

第三步:配置更新----这一步没有成功就换方案了,不值得看

$ npm install electron-updater --save
npm WARN rm not removing /Users/mahaiqiang/git/redcreation/alk-wxapi/alk-web/electron/node_modules/.bin/semver as it wasn't installed by /Users/mahaiqiang/git/redcreation/alk-wxapi/alk-web/electron/node_modules/semver

> ejs@2.7.4 postinstall /Users/mahaiqiang/git/redcreation/alk-wxapi/alk-web/electron/node_modules/ejs
> node ./postinstall.js

Thank you for installing EJS: built with the Jake JavaScript build tool (https://jakejs.com/)

npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN eallergy@1.0.0 No repository field.
npm WARN eallergy@1.0.0 No license field.

+ electron-updater@4.2.0
added 20 packages from 19 contributors, removed 10 packages, updated 289 packages and audited 909 packages in 304.234s
found 0 vulnerabilities

为了配合打包 package.json 需要给 build 新增配置项:

"build": {
    "publish": [
        {
          "provider": "generic",
          "url": "http://127.0.0.1:5500/" #这里是我本地开的服务器的地址
        }
    ],
    ...
}

参考文档:

electron入门心得
使用 electron-builder 与 electron-packager 的 JSAPI 构建 electron 桌面应用安装程序

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

推荐阅读更多精彩内容