From 10c60032dd9854650b804705901e67cc4973c9cf Mon Sep 17 00:00:00 2001 From: Ben Peachey Date: Sun, 2 Jun 2024 12:47:49 +0200 Subject: [PATCH 1/3] Add details for install, usage and development. --- README.md | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 125 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index abc2fd5..5e65840 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,130 @@ # Electron build for Simplycode -To build: +[![SimplyEdit][simplyedit-shield]][simplyedit-site] +[![Project stage: Development][project-stage-badge: Development]][project-stage-page] +[![License][license-shield]][license-link] +[![standard-readme compliant][standard-readme-shield]][standard-readme-link] +Electron environment to create **SimplyCode** applications in. + +## Install + +Currently, there is no pre-compiled binary available, so the project needs to be built from source. + +To do so, clone the repository, install the dependencies, and run the build script: + +```sh +git clone https://github.com/SimplyEdit/simplycode-electron.git +npm --prefix simplycode-electron install +npm --prefix simplycode-electron run make +``` + +The build will create an `out` directory with distributable files (in the `make` directory) and an executable Electron application (in a `simply-code-app-*` directory). For instance, on Linux: `simply-code-app-linux-x64`. + +Depending on the platform a package is built for, different dependencies are required. For instance for Debian-based distributions require `dpkg` and `fakeroot`. For Red Hat-based distributions `rpm` is required. + +Please refer to [the Electron Forge makers documentation](https://www.electronforge.io/config/makers) for specific requirements. + +to run the build in a Docker container, the following command can be used: + +```sh +docker run \ + --interactive \ + --network=host \ + --rm \ + --tty \ + --volume "${PWD}:/app" \ + --workdir=/app \ + node:lts \ + bash -c 'apt update && apt install -y dpkg fakeroot rpm && npm install && npm run make' ``` -npm install -npm run make + +## Usage + +The compiled electron application can be started by opening it from a graphical file manager or by running the executable from the command line. For instance, on Linux: + +```sh +./out/simply-code-app-linux-x64/simply-code-app ``` + +## Contribute + +Feedback and contributions are welcome. Please open an issue or create a pull request. + +### Development + +To develop in Electron, please defer to the [Electron documentation](https://www.electronjs.org/docs/latest/). + +To run, packaged and build the app [Electron Forge](https://www.electronforge.io/) is used. + +For ease of use, NPM script commands have been added to wrap the most common Electron Forge commands. + +For instance to start the application in development mode, instead of running `electron-forge start`, use: + +```sh +npm run start +``` + +#### Debugging in Visual Studio Code (VS Code) + +To debug the application using VS Code, VS Code needs to attach to the main and the renderer processes. This is done by creating a `launch.json` configuration in the `.vscode` folder in the project. + +
Contents of launch.json + +```json +{ + "version": "0.2.0", + "compounds": [ + { + "name": "Main + renderer", + "configurations": ["Main", "Renderer"], + "stopAll": true + } + ], + "configurations": [ + { + "name": "Renderer", + "port": 9222, + "request": "attach", + "type": "chrome", + "webRoot": "${workspaceFolder}" + }, + { + "name": "Main", + "type": "node", + "request": "launch", + "cwd": "${workspaceFolder}", + "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron", + "windows": { + "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd" + }, + "args": [".", "--remote-debugging-port=9222"], + "outputCapture": "std", + "console": "integratedTerminal" + } + ] + } +``` + +For more details about the `launch.js`, visit [the "Debugging from VS Code" section](https://www.electronjs.org/docs/latest/tutorial/tutorial-first-app#optional-debugging-from-vs-code) in the [Building your First App](https://www.electronjs.org/docs/latest/tutorial/tutorial-first-app) tutorial. + +
+ +Next, in VS Code, select the "Run and Debug" option from the sidebar. + +A "Main + renderer" option will appear. Amongst other things, it is now possible to set breakpoints and inspect variables. + +For more information on debugging in VS Code, visit the ["Debugging in VSCode" tutorial](https://www.electronjs.org/docs/latest/tutorial/debugging-vscode). + +## License + +Created by [SimplyEdit](https://simplyedit.io) under an MIT License. + +[license-link]: ./LICENSE +[license-shield]: https://img.shields.io/github/license/simplyedit/simplycode-electron.svg +[simplyedit-shield]: https://img.shields.io/badge/Simply-Edit-F26522?labelColor=939598 +[simplyedit-site]: https://simplyedit.io/ +[project-stage-badge: Development]: https://img.shields.io/badge/Project%20Stage-Development-yellowgreen.svg +[project-stage-page]: https://blog.pother.ca/project-stages/ +[standard-readme-link]: https://github.com/RichardLitt/standard-readme +[standard-readme-shield]: https://img.shields.io/badge/-Standard%20Readme-brightgreen.svg From 61fd3419cbaf711e8bf8ad2106fa73e63f16b7c2 Mon Sep 17 00:00:00 2001 From: "govert@muze.nl" Date: Mon, 3 Jun 2024 15:01:46 +0200 Subject: [PATCH 2/3] initial commit with action file content commented out and some tweaks on icons --- .github/workflows/release.yml | 26 ++++++++++++++++++++++ forge.config.js | 41 +++++++++++++++++++++++++++++------ main.js | 11 +++++++--- package.json | 7 ++++-- 4 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..aeb5c43 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,26 @@ +# name: Release app +# on: +# workflow_dispatch: +# jobs: +# build: +# strategy: +# matrix: +# os: +# [ +# { name: 'linux', image: 'ubuntu-latest' }, +# { name: 'windows', image: 'windows-latest' }, +# { name: 'macos', image: 'macos-latest' }, +# ] +# runs-on: ${{ matrix.os.image }} +# steps: +# - name: Github checkout +# uses: actions/checkout@v4 +# - name: Use Node.js +# uses: actions/setup-node@v4 +# with: +# node-version: 20 +# - run: npm ci +# - name: Publish app +# env: +# GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} +# run: npm run publish \ No newline at end of file diff --git a/forge.config.js b/forge.config.js index fa4a113..8f85ceb 100644 --- a/forge.config.js +++ b/forge.config.js @@ -4,29 +4,44 @@ const { FuseV1Options, FuseVersion } = require('@electron/fuses'); module.exports = { packagerConfig: { asar: true, + icon: '/simplycode/camil_512x512.png', }, rebuildConfig: {}, makers: [ { name: '@electron-forge/maker-squirrel', - config: {}, + config: { + bin: 'simply-code', + icon:path.join(__dirname, '/simplycode/camil_192x192.png'), + } }, { - name: '@electron-forge/maker-zip', - platforms: ['darwin'], + name: '@electron-forge/maker-dmg', + config: { + bin: 'simply-code', + icon:path.join(__dirname, '/simplycode/camil_192x192.png'), + }, }, { name: '@electron-forge/maker-deb', - config: {}, + config: { + bin: 'simply-code', + options: { + icon:path.join(__dirname, '/simplycode/camil_192x192.png'), + }, + } }, { name: '@electron-forge/maker-rpm', - config: {}, - }, + config: { + bin: 'simply-code', + icon:path.join(__dirname, '/simplycode/camil_192x192.png'), + } + } ], plugins: [ { - name: '@electron-forge/plugin-auto-unpack-natives', + name: '@SimplyEdit/simplycode-electron/tree/electron-forge-github-actions', config: {}, }, // Fuses are used to enable/disable various Electron functionality @@ -41,4 +56,16 @@ module.exports = { [FuseV1Options.OnlyLoadAppFromAsar]: true, }), ], + publishers: [ + { + name: 'simply-code', + config: { + repository: { + owner: 'Govert Combée', + name: 'simply-code' + }, + prerelease: true + } + } + ] }; diff --git a/main.js b/main.js index 1a2e713..4a2240f 100755 --- a/main.js +++ b/main.js @@ -17,7 +17,9 @@ const createWindow = () => { preload: path.join(__dirname, 'preload.js'), webSecurity: false, allowRunningInsecureContent : true - } + }, + icon: path.join(__dirname, '/simplycode/camil_512x512.png') + }) win.loadURL('simplycode://index.html') @@ -32,7 +34,8 @@ const createSecondWindow = (dataDir) => { preload: path.join(__dirname, 'preload.js'), webSecurity: false, allowRunningInsecureContent : true - } + }, + icon: path.join(__dirname,'/simplycode/camil_512x512.png') }) win2.loadURL('simplyapp://generated.html') @@ -133,6 +136,8 @@ async function createComponentFile(componentPath, filecontent){ } app.whenReady().then(() => { + if (require('electron-squirrel-startup') === true) app.quit(); // prevents Squirrel.Windows from launching your app multiple times during the installation/updating/uninstallation. + protocol.handle('simplycode', (request) => { let componentPath = new URL(request.url).pathname console.log(componentPath) @@ -261,7 +266,7 @@ app.whenReady().then(() => { createWindow() createSecondWindow(dataDir) - app.on('activate', () => { + app.on('activate', () => { // needed for macos if (BrowserWindow.getAllWindows().length === 0) { dataDir = dialog.showOpenDialogSync({properties: ['openDirectory']})[0]; if (!dataDir.match(/\/$/)) { diff --git a/package.json b/package.json index 8d65b2e..625f773 100755 --- a/package.json +++ b/package.json @@ -8,8 +8,10 @@ "start": "electron-forge start", "package": "electron-forge package", "make": "electron-forge make", - "postinstall": "scripts/post-install.sh" + "postinstall": "scripts/post-install.sh", + "publish": "electron-forge publish" }, + "productName": "simply-code", "keywords": [ "javascript", "html", @@ -25,8 +27,9 @@ "@electron-forge/maker-zip": "^7.4.0", "@electron-forge/plugin-auto-unpack-natives": "^7.4.0", "@electron-forge/plugin-fuses": "^7.4.0", + "@electron-forge/publisher-github": "^7.4.0", "@electron/fuses": "^1.8.0", - "electron": "^30.0.2" + "electron": "^30.0.9" }, "dependencies": { "electron-squirrel-startup": "^1.0.1", From 35e476ac2ce00958a4c9fa5377bfceac05547211 Mon Sep 17 00:00:00 2001 From: "govert@muze.nl" Date: Mon, 3 Jun 2024 17:09:01 +0200 Subject: [PATCH 3/3] needed to bundle a partof the registerSchemesAsPrivileged --- main.js | 61 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/main.js b/main.js index 4a2240f..367f4f0 100755 --- a/main.js +++ b/main.js @@ -103,10 +103,7 @@ protocol.registerSchemesAsPrivileged([ secure: true, supportFetchAPI: true } - } -]) - -protocol.registerSchemesAsPrivileged([ + }, { scheme: 'simplyapp', privileges: { @@ -204,20 +201,22 @@ app.whenReady().then(() => { }) } else { var target = __dirname + '/simplycode' + componentDirectory + '\/' + componentName; - if (fs.lstatSync(target).isDirectory()) { - // Do the recursive read thing; + if (fs.existsSync(target)){ + if (fs.lstatSync(target).isDirectory()) { + // Do the recursive read thing; + } else { + const filestuff = fs.readFileSync(__dirname + '/simplycode' + componentDirectory + '\/' + componentName) + return new Response(filestuff, { + // headers: { 'content-type': 'text/html' } + }) + } } else { - const filestuff = fs.readFileSync(__dirname + '/simplycode' + componentDirectory + '\/' + componentName) - return new Response(filestuff, { - // headers: { 'content-type': 'text/html' } - }) + return new Response('"Not found"', { status: 404}) } } break } } - - }) protocol.handle('simplyapp', (request) => { @@ -227,41 +226,47 @@ app.whenReady().then(() => { componentPath = componentPath.substring(0, (componentPath.length - 1)) } - let pathicles = componentPath.split('\/'); + let pathicles = componentPath.split('\/'); // also splits on an empty string + let componentName = pathicles.pop(); - let componentDirectory = pathicles.join('/'); - pathicles.shift(); + if (pathicles[0] == ''){ + pathicles.shift() + } + + let componentDirectory = pathicles.join('/'); switch (request.method){ default: if(componentPath.endsWith('\/')){ componentPath = componentPath.substring(0, (componentPath.length - 1)) - } + } if (!componentPath || componentPath === "/") { const filestuff = fs.readFileSync(dataDir + '/generated.html') return new Response(filestuff, { // headers: { 'content-type': 'text/html' } }) - } else { - const filestuff = fs.readFileSync(dataDir + componentDirectory + '\/' + componentName) - return new Response(filestuff, { - // headers: { 'content-type': 'text/html' } - }) + } else {{ + if (fs.existsSync(dataDir + componentDirectory + '\/' + componentName)){ + const filestuff = fs.readFileSync(dataDir + componentDirectory + '\/' + componentName) + return new Response(filestuff, { + // headers: { 'content-type': 'text/html' } + }) + } else { + return new Response('"Not found"', { status: 404}) + } } break - } - - - - + } + } }) dataDir = dialog.showOpenDialogSync({properties: ['openDirectory']})[0]; console.log(dataDir); if (!dataDir.match(/\/$/)) { dataDir += "/"; + console.log(dataDir); } createWindow() createSecondWindow(dataDir) @@ -269,6 +274,8 @@ app.whenReady().then(() => { app.on('activate', () => { // needed for macos if (BrowserWindow.getAllWindows().length === 0) { dataDir = dialog.showOpenDialogSync({properties: ['openDirectory']})[0]; + console.log('were here') + console.log(dataDir) if (!dataDir.match(/\/$/)) { dataDir += "/"; } @@ -276,8 +283,6 @@ app.whenReady().then(() => { createSecondWindow(dataDir) } }) - - }) app.on('window-all-closed', () => {