Is it possible to use the Electron built in auto updater with Gitlab tags?
I have seen that you can use Electron with GitHub releases, via electron-builder, but I am not sure the same can be said with Gitlab, as the use of Github tokens is required.
If there is no option to use Gitlab, are the only other options (a) a self hosted squirrel server, or (b) github releases?
You can use a generic host which is the easiest method, see:
https://gist.github.com/iffy/0ff845e8e3f59dbe7eaf2bf24443f104
You can edit updates.json/yml to point to the gitlab release, and it will be no worse than a generic server. It won't check the gitlab credentials, though.
You can use Amazon S3 or Bintray, see:
https://github.com/electron-userland/electron-builder/wiki/Publishing-Artifacts
Google Compute claims that they can be setup to be compatible with S3, so you could probably use them as well.
You may be able to use Gitlab releases the same as Github using the git+ssh syntax. Haven't tested that, but see Install npm module from gitlab private repository
My working example
.gitlab-ci
variables:
VERSION_ID: '1.0.$CI_PIPELINE_ID'
stages:
- build
build:
image: slauta93/electron-builder-win
stage: build
artifacts:
paths:
- $CI_PROJECT_DIR/dist/*.*
script:
- sed "s/0.0.0/${VERSION_ID}/g" package.json > _package.json && mv _package.json package.json
- npm install && npm run build
main.js
// Inital app
const electron = require("electron");
const updater = require("electron-updater");
const autoUpdater = updater.autoUpdater;
...
///////////////////
// Auto upadater //
///////////////////
autoUpdater.requestHeaders = { "PRIVATE-TOKEN": "Personal access Token" };
autoUpdater.autoDownload = true;
autoUpdater.setFeedURL({
provider: "generic",
url: "https://gitlab.com/_example_repo_/-/jobs/artifacts/master/raw/dist?job=build"
});
autoUpdater.on('checking-for-update', function () {
sendStatusToWindow('Checking for update...');
});
autoUpdater.on('update-available', function (info) {
sendStatusToWindow('Update available.');
});
autoUpdater.on('update-not-available', function (info) {
sendStatusToWindow('Update not available.');
});
autoUpdater.on('error', function (err) {
sendStatusToWindow('Error in auto-updater.');
});
autoUpdater.on('download-progress', function (progressObj) {
let log_message = "Download speed: " + progressObj.bytesPerSecond;
log_message = log_message + ' - Downloaded ' + parseInt(progressObj.percent) + '%';
log_message = log_message + ' (' + progressObj.transferred + "/" + progressObj.total + ')';
sendStatusToWindow(log_message);
});
autoUpdater.on('update-downloaded', function (info) {
sendStatusToWindow('Update downloaded; will install in 1 seconds');
});
autoUpdater.on('update-downloaded', function (info) {
setTimeout(function () {
autoUpdater.quitAndInstall();
}, 1000);
});
autoUpdater.checkForUpdates();
function sendStatusToWindow(message) {
console.log(message);
}
...
package.json
{
"name": "electron-updater-gitlab",
"version": "0.0.0",
"main": "main.js",
"scripts": {
"start": "electron .",
"pack": "node_modules/.bin/electron-builder --dir",
"build": "node_modules/.bin/electron-builder --win",
"postinstall": "",
"install": "node-gyp install",
},
"build": {
"appId": "com.electron.app",
"publish": [
{
"provider": "generic",
"url": "https://gitlab.com"
}
],
"win": {
"target": [
"nsis"
],
"verifyUpdateCodeSignature": false
},
"mac": {
"category": "public.app-category.productivity",
"identity": "Mac Developer: username (XXXXXXXX)",
"target": [
"dmg"
]
},
"linux": {
"target": [
"AppImage"
]
}
},
"dependencies": {
"electron-updater": "^2.7.2"
},
"devDependencies": {
"electron": "1.6.11",
"electron-builder": "^19.16.2"
}
}
After considering the answers in this issue and others, I ended up using GitLab Pages to publish my build artifacts. This allowed me to make make the installer files freely available to everyone in my organization without opening up the repo to everyone.
.gitlab-ci.yml:
stages:
- test
- build
- deploy
test-app:
stage: test
image: node:lts-alpine
script:
- npm install
- npm run test:colors
electron-release-build:
only:
- master
stage: build
image: electronuserland/builder:wine
script:
- npm ci
- npm run package:publish
artifacts:
paths:
- electron-release/*.exe*
- electron-release/*.yml
expire_in: 1 month
pages:
stage: deploy
only:
- master
image: alpine:latest
dependencies:
- electron-release-build
script:
# Note that `public` already exists in this repo, and has an index.html to
# to act as a downloads page.
- cp electron-release/*.exe electron-release/*.blockmap electron-release/*.yml public
- EXE_FILENAME=$(find ./electron-release -maxdepth 1 -name "Maestro*.exe")
- EXE_BASENAME=$(basename "$EXE_FILENAME")
- sed -i "s/INSERT_FILE_NAME/${EXE_BASENAME}/g" ./public/index.html
artifacts:
paths:
- public
Relevant part of package.json:
{
"build": {
"asar": true,
"appId": "com.myapp.app",
"productName": "myapp",
"directories": {
"output": "electron-release"
},
"extraFiles": [
"build/icon.ico"
],
"detectUpdateChannel": false,
"publish": {
"provider": "generic",
"url": "https://myappgroup.pages.example.com/myapp"
},
"win": {
"target": "nsis",
"verifyUpdateCodeSignature": false,
"icon": "build/icon.ico"
},
"nsis": {
"oneClick": false,
"perMachine": false,
"allowElevation": true,
"allowToChangeInstallationDirectory": true
}
}
}
No changes were needed anywhere else.
This also simplified things a bit, since I don't think I could use the provider URL proposed in another answer due to permissions (https://gitlab.com/_example_repo_/-/jobs/artifacts/master/raw/dist?job=build 404s for me).
Related
I'm building a Nuxt-electron-prisma app and I kinda stuck here. when I use prisma normally as guided every thing is fine on dev but on build i get this error :
A javascript error occurred in the main process
Uncaught exception:
Error: can not find module : '.prisma/client'
I tried changing prisma provider output to ../resources/prisma/client
generator client {
provider = "prisma-client-js"
output = "../resources/prisma/client"
}
and in main.js of electron
const { PrismaClient } = require('../resources/prisma/client');
const prisma = new PrismaClient()
but I get error Cannot find module '_http_common' at webpackMissingModules in both dev and build ! which by others opinion is caused when using prisma on client-side but I only use it on background.js (main.js of the my boilerplate)
I'm using Nuxtron boilerplate for Nuxt-electron which is using yml file for electron-builder config file and in it I also added prisma to files property:
appId: com.example.app
productName: nuxt-electron-prisma
copyright: Copyright © 2021
nsis:
oneClick: false
perMachine: true
allowToChangeInstallationDirectory: true
directories:
output: dist
buildResources: resources
files:
- "resources/prisma/database.db"
- "node_modules/.prisma/**"
- "node_modules/#prisma/client/**"
- from: .
filter:
- package.json
- app
publish: null
and still get errors
in my win-unpacked/resources I have this only: win-unpacked\resources\app.asar.unpacked\node_modules\#prisma\engines
and of course my package.json
{
"private": true,
"name": "nuxt-electron-prisma",
"productName": "nuxt-electron-prisma",
"description": "",
"version": "1.0.0",
"author": "",
"main": "app/background.js",
"scripts": {
"dev": "nuxtron",
"build": "nuxtron build"
},
"dependencies": {
"electron-serve": "^1.0.0",
"electron-store": "^6.0.1",
"#prisma/client": "^3.0.2"
},
"devDependencies": {
"#mdi/font": "^6.1.95",
"#nuxtjs/axios": "^5.13.6",
"#nuxtjs/device": "^2.1.0",
"#nuxtjs/dotenv": "^1.4.1",
"#nuxtjs/vuetify": "1.12.1",
"core-js": "^3.15.1",
"electron": "^10.1.5",
"electron-builder": "^22.9.1",
"glob": "^7.1.7",
"noty": "^3.2.0-beta",
"nuxt": "^2.15.7",
"nuxtron": "^0.3.1",
"sass": "1.32.13",
"swiper": "^5.4.5",
"prisma": "^3.0.2",
"vue-awesome-swiper": "^4.1.1"
}
}
The solution provided by Mojtaba Barari works but it results in #prisma packages being present in both resources/app/node_modules and resources/node_modules.
There is a better way how to do it:
{
"build": {
"extraResources": [
{
"from": "node_modules/.prisma/client/",
"to": "app/node_modules/.prisma/client/"
}
],
}
}
In this case, the Prisma client files will be copied directly to resources/app/node_modules where other #prisma packages are already present and so you will save ~ 10 MB compared to the other solution.
EDIT:
My previous solution doesn't work if an application is packaged into an asar archive. You need to use files field instead:
{
"build": {
"files": [
{
"from": "node_modules/.prisma/client/",
"to": "node_modules/.prisma/client/"
}
],
}
}
This is a universal solution which works even if you don't use an asar archive.
Ok, I finally solved it!!
first of all no need to change client generator output direction!
//schema.prisma
datasource db {
provider = "sqlite"
url = "file:../resources/database.db"
}
generator client {
provider = "prisma-client-js"
// output = "../resources/prisma/client" !! no need for this!
}
then in electron-builder config add ./prisma , #prisma and database
// my config file was a .yml
extraResources:
- "resources/database.db"
- "node_modules/.prisma/**/*"
- "node_modules/#prisma/client/**/*"
// or in js
extraResources:[
"resources/database.db"
"node_modules/.prisma/**/*"
"node_modules/#prisma/client/**/*"
]
this solved `Error: cannot find module : '.prisma/client'
but this alone won't read DB in built exe file!
so in main.js where importing #prisma/client should change DB reading directory:
import { join } from 'path';
const isProd = process.env.NODE_ENV === 'production';
import { PrismaClient } from '#prisma/client';
const prisma = new PrismaClient({
datasources: {
db: {
url: `file:${isProd ? join(process.resourcesPath, 'resources/database.db') : join(__dirname, '../resources/database.db')}`,
},
},
})
with these configs I could fetch data from my sqlite DB
Until today, builds were succesfull without any errors, only warning about build size (I am using socket.io-client and some other packages without issues). I have made many succesfull builds with my simple config.
I am not using typescript, it's a simple single page website, the site is live and running with production build scripts from yesterday.
But today, after running npm update (which updated nothing), I can't make any changes because the build fails no matter what I try to fix it.
Any help is appreciated.
I am getting the following error:
ERROR in ./node_modules/angular/angular.js 2115:9
Module parse failed: Unexpected token (2115:9)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| * throw error if the argument is falsy.
| */
> function assertArg(arg, name, reason) {
| if (!arg) {
| throw ngMinErr('areq', 'Argument \'{0}\' is {1}', (name || '?'), (reason || 'required'));
# ./node_modules/angular/index.js 1:0-20
# ./resources/assets/app/index.js 15:14-32
webpack 5.45.0 compiled with 1 error and 1 warning in 38636 ms
The error is generated by the babel-loader, using version 8.2.2:
"node_modules/babel-loader": {
"version": "8.2.2",
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.2.tgz",
"integrity": "sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g==",
"dev": true,
"dependencies": {
"find-cache-dir": "^3.3.1",
"loader-utils": "^1.4.0",
"make-dir": "^3.1.0",
"schema-utils": "^2.6.5"
},
"engines": {
"node": ">= 8.9"
},
"peerDependencies": {
"#babel/core": "^7.0.0",
"webpack": ">=2"
}
},
My webpack.common.js:
const config = {
resolve: {
modules: [path.resolve(__dirname, 'resources/assets'), 'node_modules'],
},
entry: {
app: './resources/assets/app/index.js',
},
output: {
// ...
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
]
},
plugins: [
new MiniCssExtractPlugin(), new WebpackBuildNotifierPlugin(
{
title: "Build Complete!",
sound: true,
}
),
],
optimization: {
sideEffects: true,
usedExports: false,
removeEmptyChunks: true,
concatenateModules: true,
mangleExports: 'size',
}
};
module.exports = config;
Then I use that config in my webpack.dev.js:
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge( common, {
mode: 'development',
devtool: 'inline-source-map',
});
Running dev build with:
webpack --mode development --watch --config webpack.dev.js
According to package-lock.json my angular version is 1.8.2:
"node_modules/angular": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/angular/-/angular-1.8.2.tgz",
"integrity": "sha512-IauMOej2xEe7/7Ennahkbb5qd/HFADiNuLSESz9Q27inmi32zB0lnAsFeLEWcox3Gd1F6YhNd1CP7/9IukJ0Gw=="
},
My npm and node versions:
$ npm -v
7.19.1
$ node -v
v16.5.0
Finally solved the issue. In the end I removed node_modules folder, removed all unnecessary packages from package.json, did a clean npm install and build are working now. I made no changes to the webpack configs.
So I really don't know what was the problem, it might be some module acting up.
So i have this very simple electron.js test-project which works fine with npm start:
const { app, nativeImage } = require('electron');
const electron = require('electron');
const path = require('path');
const Tray = electron.Tray
const iconpath = path.join(__dirname, './logo_transparent_white_512x512.png')
app.on('ready', function(){
icon = nativeImage.createFromPath(iconpath);
icon = icon.resize({ width: 16, height: 16})
new Tray(icon);
console.log('ready');
})
The package.json looks like this:
{
"name": "electronbuilder",
"version": "1.0.2",
"description": "dadlu",
"main": "main.js",
"homepage": "www.test.com",
"dependencies": {
"path": "^0.12.7"
},
"devDependencies": {
"electron": "^11.1.1",
"electron-builder": "^22.9.1"
},
"scripts": {
"start": "electron .",
"dist": "electron-builder"
},
"author": "test-author",
"license": "ISC",
"build": {
"appId": "com.elecctron.builder",
"productName": "testBuild",
"linux": {
"target": [
"deb"
],
"maintainer": "test-maintainer",
},
"deb": {
"depends": [
"libappindicator1",
"libnotify4"
]
},
"extraFiles": [
"./logo_transparent_white_512x512.png"
]
}
}
After running:
yarn dist
and waiting a minute, I can install the package. But running it doesn't do anything.
when enabling the console ('add to desktop', 'open with Text Editor', 'Terminal=true') I can observe, that the app started successfully:
console.log('ready') got executed
I tried all sorts of ways to get the tray icon to work, stubbing across the weirdest things. F.e. when building the Icon like this:
tray = new Tray(./logo_transparent_white_512x512.png);
it does work with npm start, but after yarn dist, nothing happends. Though, going into the applications folder and running
$ ./{name}
it starts up fine, including the tray icon. (./logo_transparent_white_512x512.png isn't 512x512, i already resized it to 256x256)
its cant be an lib problem either, because this project can be build fine on my system.
I hope someone can help me, ive got my first real project ready, but can only start it with npm start. Any attempts to build it fail, meaning the tray icon doesn't show up.
If some information is missing, feel free to ask.
UPDATE: index.js file content added.
I have this electron app that is executing some bash scrips(*.sh) files to perform some task.
Everything is working absolutely fine in the development environment but when building the production build for deb installer for Ubuntu platform, everything is working, like opening on the app, other NodeJS stuff, but bash scripts are not executing.
Problem Statement: How to execute shell scripts in the production build of an electron app for Linux(Ubuntu OS). Getting this error
app/terminal_scripts/timer.sh Not Found
Below are the detailed explanation for the app.
**Project Directory Setup**:
ProjectName
|
app > css | images | js | renders
terminal_scripts
node_modules
package.json
package-lock.json
Where inside the app directory, I have all CSS, images, js, HTML, and terminal scripts.
package.json:
{
"name": "timer",
"productName": "Timely",
"version": "1.0.25",
"description": "This desktop app shows you system clock",
"main": "app/js/main/index.js",
"scripts": {
"start": "electron .",
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "nodemon --exec 'electron .'",
"dist": "electron-builder"
},
"homepage": ".",
"keywords": [
"Electron",
"Desktop App"
],
"author": "NotABot Ltd <contact#notabot.com>",
"contributors": [
{
"name": "Not A Bot",
"email": "nab#notabot.com"
}
],
"license": "ISC",
"dependencies": {
"desandro-matches-selector": "^2.0.2",
"electron-context-menu": "^1.0.0",
"electron-is": "^3.0.0",
"fix-path": "^3.0.0",
"isotope-layout": "^3.0.6",
"jquery": "^3.5.0",
"jquery-bridget": "^2.0.1"
},
"build": {
"appId": "com.test.timely",
"productName": "Timely",
"linux": {
"target": "deb",
"category": "System"
}
},
"devDependencies": {
"electron": "^8.1.1",
"electron-builder": "^22.6.0"
}
}
HTML:
<html>
<head>
<title>Timely</title>
</head>
<body>
<button onclick="displayTime()">Display Time</button>
<textarea rows="20" cols="90" id="command-output" disabled="true"></textarea>
<script>
const {app} = require('electron');
function displayTime(){
console.log("button clicked");
let cmd = `bash app/terminal_scripts/timer.sh`;
let completeMessage = 'This is the message';
backgroundProcess(cmd, completeMessage);
}
function getCommandOutput() { return document.getElementById("command-output"); };
function getStatus() { return document.getElementById("status"); };
function appendOutput(msg) { getCommandOutput().value += (msg+'\n'); };
function setStatus(msg) { getStatus().innerHTML = msg; };
function backgroundProcess(cmd, completeMessage){
const process = require('child_process');
var child = process.execFile(cmd, [] , {shell: true} );
appendOutput("Processing......");
child.on('error', function(err) {
appendOutput('stderr: '+err );
});
child.stdout.on('data', function (data) {
appendOutput(data);
});
child.stderr.on('data', function (data) {
appendOutput(data );
});
return new Promise((resolve, reject) => {
child.on('close', function (code) {
console.log(`code is: ${code}`);
if (code == 0){
setStatus(completeMessage);
resolve(1);
}
else{
setStatus('Exited with error code ' + code);
resolve(-1);
}
});
});
}
</script>
</body>
</html>
Bash Script:
#!/bin/bash
timer="$(date)"
echo "$timer"
Permission is set 777 for this shell file
Platform Information:
OS: Ubuntu 18.04.4 LTS
NodeJS: 13.6.0
NPM: 6.14.5
Electron: 8.1.1
Electron Builder: 22.6.0
index.js
const {app, BrowserWindow, Menu, Tray, ipcMain, MenuItem} = require('electron');
const path = require('path');
const contextMenu = require('electron-context-menu');
let splashWindow;
function createMainWindow(){
mainWindow = new BrowserWindow({
minHeight: 700,
minWidth: 800,
webPreferences: {
nodeIntegration: true,
webviewTag: true
},
show: false
});
//For dev only
// mainWindow.webContents.openDevTools();
mainWindow.loadFile('app/renderer/index.html');
mainWindow.maximize();
}
app.on('ready', () =>{
createMainWindow();
});
Another way is to move flies to a new directory outside app directory and call it as extraResources.
Inside that directory you can add all your bash files and for production you can use below method.
let urlPath = path.join(process.resourcesPath, '/extraResources/')
and then use let cmd = `${urlPath}timer.sh`;
I have created a new directory alongside the app directory called the termainal_scripts.
Inside this, I have my bash file timer.sh.
I figured out how to execute shell scripts, in production by using process.resourcesPath inside path.join().
So, let the fixed path be as:
let fixedURL = path.join(process.resourcesPath, '/terminal_scripts/');
Then the command to execute will be:
let cmd = `${fixedURL}timer.sh`
Background
I am very new to Node.js so please don't hate..
I found NPM very useful because I can install Node.js packages globally and then use them like standalone, available-on-path apps.
This does work on Windows, which really suprises me.
For instance I installed UglifyJS this way, via npm install -g uglifyjs and now I can run it from anywhere in my system, from the console via uglifyjs <rest of command> (not node uglifyjs .. or sth else).
I'd like to create my own stand-alone Node.js application. How do I get starded? I am asking here because most tutorials only cover how to write a simple script and then run it va node (which I already covered)
My current config
package.json:
{
"name": "hash",
"version": "1.0.0",
"author": "Kiel V.",
"engines": [
"node >= 0.8.0"
],
"main": "hash.js",
"dependencies": {
"commander" : "1.2.0"
},
"scripts": {
"start": "node hash.js"
}
}
hash.js:
var crypto = require('crypto'),
commander = require('commander');
/* For use as a library */
function hash(algorithm, str) {
return crypto.createHash(algorithm).update(str).digest('hex');
}
exports.hash = hash;
/* For use as a stand-alone app */
commander
.version('1.0.0')
.usage('[options] <plain ...>')
.option('-a, --algorithm [algorithm]', 'Hash algorithm', 'md5')
.parse(process.argv);
commander.args.forEach(function(plain){
console.log( plain + ' -> ' + hash(commander.algorithm, plain) );
});
Question:
Suppose I have only these two files in node-hash directory. How do I install this project, so that later I can run it in cmd.exe via hash -a md5 plaintext just like coffescript, jslint etc. installs ?
You have to add some code into package.json and hash.js, then you can run this command to install the package from local folder.
npm install -g ./node-hash
package.json
{
"name": "hash",
"version": "1.0.0",
"author": "Kiel V.",
"engines": [
"node >= 0.8.0"
],
"bin": {
"hash": "hash.js"
},
"main": "hash.js",
"dependencies": {
"commander" : "1.2.0"
},
"scripts": {
"start": "node hash.js"
}
}
hash.js
#!/usr/bin/env node
var crypto = require('crypto'),
commander = require('commander');
/* For use as a library */
function hash(algorithm, str) {
return crypto.createHash(algorithm).update(str).digest('hex');
}
exports.hash = hash;
/* For use as a stand-alone app */
commander
.version('1.0.0')
.usage('[options] <plain ...>')
.option('-a, --algorithm [algorithm]', 'Hash algorithm', 'md5')
.parse(process.argv);
commander.args.forEach(function(plain){
console.log( plain + ' -> ' + hash(commander.algorithm, plain) );
});