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


用electron把clojurescript编译后的静态资源文件打包成windows安装程序

简书地址

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. 打包文件

electron打包文件

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,会优先使用缓存中的文件。注意版本一致。
    扔上去可能是这样:
    手动下载cache

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

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 桌面应用安装程序


评论
  目录