Migrate Vikunja from electron to tauri #127
17
README.md
|
@ -4,26 +4,27 @@
|
|||
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](LICENSE)
|
||||
[![Download](https://img.shields.io/badge/download-v0.20.0-brightgreen.svg)](https://dl.vikunja.io)
|
||||
|
||||
The Vikunja frontend all repackaged as an electron app to run as a desktop app!
|
||||
The Vikunja frontend all repackaged as a tauri app to run as a desktop app!
|
||||
|
||||
## Dev
|
||||
|
||||
As this repo does not contain any code, only a thin wrapper around electron, you will need to do this to get the
|
||||
As this repo does not contain any code, only a thin wrapper around tauri, you will need to do this to get the
|
||||
actual frontend bundle and build the app:
|
||||
|
||||
```bash
|
||||
rm -rf frontend vikunja-frontend-master.zip
|
||||
wget https://dl.vikunja.io/frontend/vikunja-frontend-master.zip
|
||||
unzip vikunja-frontend-master.zip -d frontend
|
||||
wget https://dl.vikunja.io/frontend/vikunja-frontend-0.20.0.zip
|
||||
unzip vikunja-frontend-0.20.0.zip -d frontend
|
||||
sed -i 's/\/api\/v1//g' frontend/index.html # Make sure to trigger the "enter the Vikunja url" prompt
|
||||
```
|
||||
|
||||
## Building for release
|
||||
|
||||
1. Run the snippet from above, but with a valid frontend version instead of `master`
|
||||
2. Change the version in `package.json` (That's the one that will be used by electron-builder`
|
||||
3. `yarn install`
|
||||
4. `yarn dist --linux --windows`
|
||||
1. Make sure that you have `cargo` installed
|
||||
2. Run the snippet from above, but with a valid frontend version instead of `master`
|
||||
3. Change the version in `src-tauri/tauri.conf.json` (That's the one that will be used by tauri`
|
||||
4. `cargo install tauri-cli`
|
||||
5. `cargo tauri build`
|
||||
|
||||
## Sponsors
|
||||
|
||||
|
|
68
main.js
|
@ -1,68 +0,0 @@
|
|||
const {app, BrowserWindow, shell} = require('electron')
|
||||
const path = require('path')
|
||||
const express = require('express')
|
||||
const eApp = express()
|
||||
const portInUse = require('./portInUse.js')
|
||||
|
||||
const frontendPath = 'frontend/'
|
||||
|
||||
function createWindow() {
|
||||
// Create the browser window.
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 1680,
|
||||
height: 960,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
}
|
||||
})
|
||||
|
||||
// Open external links in the browser
|
||||
mainWindow.webContents.on('new-window', function (e, url) {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
|
||||
// Hide the toolbar
|
||||
mainWindow.setMenuBarVisibility(false)
|
||||
|
||||
// We try to use the same port every time and only use a different one if that does not succeed.
|
||||
let port = 45735
|
||||
portInUse(port, used => {
|
||||
if(used) {
|
||||
console.log(`Port ${port} already used, switching to a random one`)
|
||||
port = 0 // This lets express choose a random port
|
||||
}
|
||||
|
||||
// Start a local express server to serve static files
|
||||
eApp.use(express.static(path.join(__dirname, frontendPath)))
|
||||
// Handle urls set by the frontend
|
||||
eApp.get('*', (request, response, next) => {
|
||||
response.sendFile(`${__dirname}/${frontendPath}index.html`);
|
||||
})
|
||||
const server = eApp.listen(port, '127.0.0.1', () => {
|
||||
console.log(`Server started on port ${server.address().port}`)
|
||||
mainWindow.loadURL(`http://127.0.0.1:${server.address().port}`)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS 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 (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
// for applications and their menu bar to stay active until the user quits
|
||||
// explicitly with Cmd + Q.
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
|
61
package.json
|
@ -1,61 +0,0 @@
|
|||
{
|
||||
"name": "vikunja-desktop",
|
||||
"version": "0.16.0-dev",
|
||||
"description": "Vikunja's frontend as a standalone desktop application.",
|
||||
"main": "main.js",
|
||||
"repository": "https://code.vikunja.io/desktop",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"author": {
|
||||
"email": "maintainers@vikunja.io",
|
||||
"name": "Vikunja Team"
|
||||
},
|
||||
"homepage": "https://vikunja.io",
|
||||
"scripts": {
|
||||
"start": "electron .",
|
||||
"pack": "electron-builder --dir",
|
||||
"dist": "electron-builder"
|
||||
},
|
||||
"build": {
|
||||
"appId": "io.vikunja.desktop",
|
||||
"productName": "Vikunja Desktop",
|
||||
"artifactName": "${productName}-${version}.${ext}",
|
||||
"icon": "build/icon.icns",
|
||||
"linux": {
|
||||
"target": [
|
||||
"deb",
|
||||
"AppImage",
|
||||
"snap",
|
||||
"pacman",
|
||||
"apk",
|
||||
"freebsd",
|
||||
"rpm",
|
||||
"zip",
|
||||
"tar.gz"
|
||||
],
|
||||
"category": "Productivity"
|
||||
},
|
||||
"win": {
|
||||
"target": [
|
||||
"nsis",
|
||||
"portable",
|
||||
"msi",
|
||||
"zip"
|
||||
]
|
||||
},
|
||||
"mac": {
|
||||
"category": "public.app-category.productivity",
|
||||
"target": [
|
||||
"dmg",
|
||||
"zip"
|
||||
]
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "21.2.2",
|
||||
"electron-builder": "23.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"connect-history-api-fallback": "^1.6.0",
|
||||
"express": "^4.17.1"
|
||||
}
|
||||
}
|
18
portInUse.js
|
@ -1,18 +0,0 @@
|
|||
const net = require('net');
|
||||
|
||||
module.exports = function(port, callback) {
|
||||
const server = net.createServer(function(socket) {
|
||||
socket.write('Echo server\r\n');
|
||||
socket.pipe(socket);
|
||||
})
|
||||
|
||||
server.listen(port, '127.0.0.1');
|
||||
server.on('error', function (e) {
|
||||
callback(true)
|
||||
})
|
||||
server.on('listening', function (e) {
|
||||
server.close()
|
||||
callback(false)
|
||||
})
|
||||
}
|
||||
|
3
src-tauri/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
4082
src-tauri/Cargo.lock
generated
Normal file
32
src-tauri/Cargo.toml
Normal file
|
@ -0,0 +1,32 @@
|
|||
[package]
|
||||
name = "app"
|
||||
|
||||
version = "0.1.0"
|
||||
konrad
commented
Can we set this dynamically in ci? Can we set this dynamically in ci?
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
license = ""
|
||||
repository = ""
|
||||
default-run = "app"
|
||||
edition = "2021"
|
||||
konrad
commented
Is this a configurable value? Is this a configurable value?
CL0Pinette
commented
The The `default-run` value should be the same as the package name because it is this package that needs to be run on start
|
||||
rust-version = "1.57"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1.1.1", features = [] }
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = { version = "1.1.1", features = ["api-all"] }
|
||||
warp = "0.3.3"
|
||||
portpicker = "0.1.1"
|
||||
thread = "0.1.0"
|
||||
tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] }
|
||||
|
||||
[features]
|
||||
# by default Tauri runs in production mode
|
||||
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
|
||||
default = [ "custom-protocol" ]
|
||||
# this feature is used for production builds where `devPath` points to the filesystem
|
||||
# DO NOT remove this
|
||||
custom-protocol = [ "tauri/custom-protocol" ]
|
3
src-tauri/build.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
BIN
src-tauri/icons/128x128.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
src-tauri/icons/128x128@2x.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
src-tauri/icons/32x32.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
src-tauri/icons/Square107x107Logo.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
src-tauri/icons/Square142x142Logo.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
src-tauri/icons/Square150x150Logo.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
src-tauri/icons/Square284x284Logo.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
src-tauri/icons/Square30x30Logo.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src-tauri/icons/Square310x310Logo.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
src-tauri/icons/Square44x44Logo.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
src-tauri/icons/Square71x71Logo.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
src-tauri/icons/Square89x89Logo.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
src-tauri/icons/StoreLogo.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
src-tauri/icons/icon.icns
Normal file
BIN
src-tauri/icons/icon.ico
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
src-tauri/icons/icon.png
Normal file
After Width: | Height: | Size: 49 KiB |
10
src-tauri/src/main.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
#![cfg_attr(
|
||||
all(not(debug_assertions), target_os = "windows"),
|
||||
windows_subsystem = "windows"
|
||||
)]
|
||||
|
||||
fn main() {
|
||||
tauri::Builder::default()
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
65
src-tauri/tauri.conf.json
Normal file
|
@ -0,0 +1,65 @@
|
|||
{
|
||||
"build": {
|
||||
"beforeBuildCommand": "",
|
||||
"beforeDevCommand": "",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../frontend"
|
||||
},
|
||||
"package": {
|
||||
"productName": "vikunja-desktop",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
"all": true
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"category": "DeveloperTool",
|
||||
"copyright": "",
|
||||
"deb": {
|
||||
"depends": []
|
||||
},
|
||||
"externalBin": [],
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"identifier": "io.vikunja.desktop",
|
||||
"longDescription": "",
|
||||
"macOS": {
|
||||
"entitlements": null,
|
||||
"exceptionDomain": "",
|
||||
"frameworks": [],
|
||||
"providerShortName": null,
|
||||
"signingIdentity": null
|
||||
},
|
||||
"resources": [],
|
||||
"shortDescription": "",
|
||||
"targets": "all",
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": ""
|
||||
}
|
||||
},
|
||||
"security": {
|
||||
"csp": null
|
||||
},
|
||||
"updater": {
|
||||
"active": false
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"fullscreen": false,
|
||||
"height": 600,
|
||||
"resizable": true,
|
||||
"title": "vikunja-desktop",
|
||||
"width": 800
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
What should the value of this be?
The Cargo.yml declares dependencies and the package itself when we use it with another rust package for example. We sure can change the values in the
package
section to whatever we want :...