From 44473fea97e7b7c1abf1cdfd9ca8ad01b4e16cd1 Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Thu, 5 Sep 2024 01:56:49 +0100 Subject: [PATCH 01/12] Check for bundle and build if exists --- resources/js/electron-builder.js | 108 +++++++++++++++++-------------- 1 file changed, 61 insertions(+), 47 deletions(-) diff --git a/resources/js/electron-builder.js b/resources/js/electron-builder.js index 72d174a0..f314fc8c 100644 --- a/resources/js/electron-builder.js +++ b/resources/js/electron-builder.js @@ -58,59 +58,73 @@ if (isBuilding) { // As we can't copy into a subdirectory of ourself we need to copy to a temp directory let tmpDir = mkdtempSync(join(os.tmpdir(), 'nativephp')); - copySync(process.env.APP_PATH, tmpDir, { - overwrite: true, - dereference: true, - filter: (src, dest) => { - let skip = [ - // Skip .git and Dev directories - join(process.env.APP_PATH, '.git'), - join(process.env.APP_PATH, 'docker'), - join(process.env.APP_PATH, 'packages'), - - // Only needed for local testing - join(process.env.APP_PATH, 'vendor', 'nativephp', 'electron', 'vendor'), - join(process.env.APP_PATH, 'vendor', 'nativephp', 'laravel', 'vendor'), - - join(process.env.APP_PATH, 'vendor', 'nativephp', 'php-bin'), - join(process.env.APP_PATH, 'vendor', 'nativephp', 'electron', 'bin'), - join(process.env.APP_PATH, 'vendor', 'nativephp', 'electron', 'resources'), - join(process.env.APP_PATH, 'node_modules'), - join(process.env.APP_PATH, 'dist'), - ]; - - let shouldSkip = false; - skip.forEach((path) => { - if (src.indexOf(path) === 0) { - shouldSkip = true; - } - }); - - return !shouldSkip; - } - }); - - copySync(tmpDir, appPath); - - // Electron build removes empty folders, so we have to create dummy files - // dotfiles unfortunately don't work. - writeJsonSync(join(appPath, 'storage', 'framework', 'cache', '_native.json'), {}) - writeJsonSync(join(appPath, 'storage', 'framework', 'sessions', '_native.json'), {}) - writeJsonSync(join(appPath, 'storage', 'framework', 'testing', '_native.json'), {}) - writeJsonSync(join(appPath, 'storage', 'framework', 'views', '_native.json'), {}) - writeJsonSync(join(appPath, 'storage', 'app', 'public', '_native.json'), {}) - writeJsonSync(join(appPath, 'storage', 'logs', '_native.json'), {}) - - removeSync(tmpDir); + let bundle = join(process.env.APP_PATH, 'build', '__nativephp_app_bundle'); + + if (existsSync(bundle)) { + copySync(bundle, appPath); + } else { + console.warn('====================='); + console.warn('* * * INSECURE BUILD * * *'); + console.warn('Secure app bundle not found! Building with exposed source files.'); + console.warn('See https://nativephp.com/docs/publishing/building#security for more details'); + console.warn('====================='); + + copySync(process.env.APP_PATH, tmpDir, { + overwrite: true, + dereference: true, + filter: (src, dest) => { + let skip = [ + // Skip .git and Dev directories + join(process.env.APP_PATH, '.git'), + join(process.env.APP_PATH, 'docker'), + join(process.env.APP_PATH, 'packages'), + + // Only needed for local testing + join(process.env.APP_PATH, 'vendor', 'nativephp', 'electron', 'vendor'), + join(process.env.APP_PATH, 'vendor', 'nativephp', 'laravel', 'vendor'), + + join(process.env.APP_PATH, 'vendor', 'nativephp', 'php-bin'), + join(process.env.APP_PATH, 'vendor', 'nativephp', 'electron', 'bin'), + join(process.env.APP_PATH, 'vendor', 'nativephp', 'electron', 'resources'), + join(process.env.APP_PATH, 'node_modules'), + join(process.env.APP_PATH, 'dist'), + ]; + + let shouldSkip = false; + skip.forEach((path) => { + if (src.indexOf(path) === 0) { + shouldSkip = true; + } + }); + + return !shouldSkip; + } + }); + + copySync(tmpDir, appPath); + + // Electron build removes empty folders, so we have to create dummy files + // dotfiles unfortunately don't work. + writeJsonSync(join(appPath, 'storage', 'framework', 'cache', '_native.json'), {}) + writeJsonSync(join(appPath, 'storage', 'framework', 'sessions', '_native.json'), {}) + writeJsonSync(join(appPath, 'storage', 'framework', 'testing', '_native.json'), {}) + writeJsonSync(join(appPath, 'storage', 'framework', 'views', '_native.json'), {}) + writeJsonSync(join(appPath, 'storage', 'app', 'public', '_native.json'), {}) + writeJsonSync(join(appPath, 'storage', 'logs', '_native.json'), {}) + + removeSync(tmpDir); + } console.log('====================='); console.log('Copied app to resources'); console.log(join(process.env.APP_PATH, 'dist')); console.log('====================='); - const artisanPath = join(appPath, 'artisan'); - // We'll use the default PATH PHP binary here, as we can cross-compile for all platforms. This shouldn't be changed. - execSync(`php ${artisanPath} native:minify ${appPath}`); + if (! existsSync(bundle)) { + const artisanPath = join(appPath, 'artisan'); + // We'll use the default PATH PHP binary here, as we can cross-compile for all platforms. This shouldn't be changed. + execSync(`php ${artisanPath} native:minify ${appPath}`); + } } catch (e) { console.error('====================='); console.error('Error copying app to resources'); From 42ce4b698a96e78f05f41016881ea451fad1f30e Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Thu, 5 Sep 2024 01:58:27 +0100 Subject: [PATCH 02/12] Fix app name setting in the package.json Node doesn't like the name to contain spaces, so we need to get rid of them --- src/Commands/BuildCommand.php | 4 ++++ src/Commands/DevelopCommand.php | 18 ++++++------------ src/Traits/SetsAppName.php | 25 +++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 12 deletions(-) create mode 100644 src/Traits/SetsAppName.php diff --git a/src/Commands/BuildCommand.php b/src/Commands/BuildCommand.php index 4adce24a..ea167b36 100644 --- a/src/Commands/BuildCommand.php +++ b/src/Commands/BuildCommand.php @@ -9,12 +9,14 @@ use Native\Electron\Facades\Updater; use Native\Electron\Traits\InstallsAppIcon; use Native\Electron\Traits\OsAndArch; +use Native\Electron\Traits\SetsAppName; class BuildCommand extends Command { use InstallsAppIcon; use LocatesPhpBinary; use OsAndArch; + use SetsAppName; protected $signature = 'native:build {os? : The operating system to build for (all, linux, mac, win)} @@ -27,6 +29,8 @@ public function handle(): void { $this->info('Build NativePHP app…'); + $this->setAppName(slugify: true); + Process::path(__DIR__.'/../../resources/js/') ->env($this->getEnvironmentVariables()) ->forever() diff --git a/src/Commands/DevelopCommand.php b/src/Commands/DevelopCommand.php index faa9f712..f27265af 100644 --- a/src/Commands/DevelopCommand.php +++ b/src/Commands/DevelopCommand.php @@ -6,13 +6,17 @@ use Native\Electron\Traits\Developer; use Native\Electron\Traits\Installer; use Native\Electron\Traits\InstallsAppIcon; +use Native\Electron\Traits\SetsAppName; use function Laravel\Prompts\intro; use function Laravel\Prompts\note; class DevelopCommand extends Command { - use Developer, Installer, InstallsAppIcon; + use Developer; + use Installer; + use InstallsAppIcon; + use SetsAppName; protected $signature = 'native:serve {--no-queue} {--D|no-dependencies} {--installer=npm}'; @@ -35,7 +39,7 @@ public function handle(): void $this->patchPlist(); } - $this->patchPackageJson(); + $this->setAppName(); $this->installIcon(); @@ -59,14 +63,4 @@ protected function patchPlist(): void file_put_contents(__DIR__.'/../../resources/js/node_modules/electron/dist/Electron.app/Contents/Info.plist', $pList); } - - protected function patchPackageJson(): void - { - $packageJsonPath = __DIR__.'/../../resources/js/package.json'; - $packageJson = json_decode(file_get_contents($packageJsonPath), true); - - $packageJson['name'] = config('app.name'); - - file_put_contents($packageJsonPath, json_encode($packageJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); - } } diff --git a/src/Traits/SetsAppName.php b/src/Traits/SetsAppName.php new file mode 100644 index 00000000..1b7af39d --- /dev/null +++ b/src/Traits/SetsAppName.php @@ -0,0 +1,25 @@ +lower()->kebab(); + } + + $packageJson['name'] = $name; + + file_put_contents($packageJsonPath, json_encode($packageJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + } +} From 2646655f0f7a72d184f116751585da6904aa0b4e Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Thu, 5 Sep 2024 01:58:52 +0100 Subject: [PATCH 03/12] Copy the installer icon --- src/Traits/InstallsAppIcon.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Traits/InstallsAppIcon.php b/src/Traits/InstallsAppIcon.php index d8e18e57..1239f08a 100644 --- a/src/Traits/InstallsAppIcon.php +++ b/src/Traits/InstallsAppIcon.php @@ -14,6 +14,7 @@ public function installIcon() @copy(public_path('icon.png'), __DIR__.'/../../resources/js/resources/icon.png'); @copy(public_path('IconTemplate.png'), __DIR__.'/../../resources/js/resources/IconTemplate.png'); @copy(public_path('IconTemplate@2x.png'), __DIR__.'/../../resources/js/resources/IconTemplate@2x.png'); + @copy(public_path('icon.png'), __DIR__.'/../../resources/js/build/icon.png'); note('App icons copied'); } From a48d16ad5005b9ab51a8ec3927fa453159f116d0 Mon Sep 17 00:00:00 2001 From: simonhamp Date: Thu, 5 Sep 2024 00:59:30 +0000 Subject: [PATCH 04/12] Fix styling --- src/Traits/SetsAppName.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Traits/SetsAppName.php b/src/Traits/SetsAppName.php index 1b7af39d..5281db64 100644 --- a/src/Traits/SetsAppName.php +++ b/src/Traits/SetsAppName.php @@ -2,9 +2,6 @@ namespace Native\Electron\Traits; -use function Laravel\Prompts\intro; -use function Laravel\Prompts\note; - trait SetsAppName { protected function setAppName(bool $slugify = false): void From 1f429ea4296ee469ff1b581e8b4933f85bea543d Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Thu, 5 Sep 2024 18:21:28 +0100 Subject: [PATCH 05/12] Update to latest binaries --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3d6277cb..b633d341 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ "illuminate/contracts": "^10.0|^11.0", "laravel/prompts": "^0.1.1", "nativephp/laravel": "*", - "nativephp/php-bin": "^0.4", + "nativephp/php-bin": "^0.5", "spatie/laravel-package-tools": "^1.14.0" }, "require-dev": { From 7daf9fd8b2254a4faff70be963fefcbaaa74007d Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Wed, 11 Sep 2024 13:53:24 +0100 Subject: [PATCH 06/12] Fix bundle copy --- resources/js/electron-builder.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/js/electron-builder.js b/resources/js/electron-builder.js index f314fc8c..871e32b0 100644 --- a/resources/js/electron-builder.js +++ b/resources/js/electron-builder.js @@ -55,14 +55,14 @@ if (isBuilding) { removeSync(appPath); - // As we can't copy into a subdirectory of ourself we need to copy to a temp directory - let tmpDir = mkdtempSync(join(os.tmpdir(), 'nativephp')); - let bundle = join(process.env.APP_PATH, 'build', '__nativephp_app_bundle'); if (existsSync(bundle)) { - copySync(bundle, appPath); + copySync(bundle, join(appPath, 'bundle', '__nativephp_app_bundle')); } else { + // As we can't copy into a subdirectory of ourself we need to copy to a temp directory + let tmpDir = mkdtempSync(join(os.tmpdir(), 'nativephp')); + console.warn('====================='); console.warn('* * * INSECURE BUILD * * *'); console.warn('Secure app bundle not found! Building with exposed source files.'); From 8b0e43d1876928872fea8532259fa6156534a058 Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Mon, 9 Dec 2024 07:36:38 +0000 Subject: [PATCH 07/12] Restore changes from other PR Source: https://github.com/NativePHP/electron-plugin/pull/36 --- .../js/electron-plugin/src/server/php.ts | 215 +++++++++++------- 1 file changed, 128 insertions(+), 87 deletions(-) diff --git a/resources/js/electron-plugin/src/server/php.ts b/resources/js/electron-plugin/src/server/php.ts index 92208e3a..2240073a 100644 --- a/resources/js/electron-plugin/src/server/php.ts +++ b/resources/js/electron-plugin/src/server/php.ts @@ -1,17 +1,17 @@ -import {mkdirSync, statSync, writeFileSync, existsSync} from 'fs' -import {copySync} from 'fs-extra' -import Store from 'electron-store' -import {promisify} from 'util' -import {join} from 'path' -import {app} from 'electron' -import {exec, execFile, spawn} from 'child_process' +import { mkdirSync, statSync, writeFileSync, existsSync } from 'fs'; +import { copySync } from 'fs-extra'; +import Store from 'electron-store'; +import { promisify } from 'util'; +import { join } from 'path'; +import { app } from 'electron'; +import { exec, execFile, spawn } from 'child_process'; import state from "./state"; import getPort from 'get-port'; import { ProcessResult } from "./ProcessResult"; -const storagePath = join(app.getPath('userData'), 'storage') -const databasePath = join(app.getPath('userData'), 'database') -const databaseFile = join(databasePath, 'database.sqlite') +const storagePath = join(app.getPath('userData'), 'storage'); +const databasePath = join(app.getPath('userData'), 'database'); +const databaseFile = join(databasePath, 'database.sqlite'); const argumentEnv = getArgumentEnv(); const appPath = getAppPath(); @@ -23,18 +23,24 @@ async function getPhpPort() { } async function retrievePhpIniSettings() { - const env = { - NATIVEPHP_RUNNING: 'true', - NATIVEPHP_STORAGE_PATH: storagePath, - NATIVEPHP_DATABASE_PATH: databaseFile, - }; - - const phpOptions = { - cwd: appPath, - env - }; - - return await promisify(execFile)(state.php, ['artisan', 'native:php-ini'], phpOptions); + const env = { + NATIVEPHP_RUNNING: 'true', + NATIVEPHP_STORAGE_PATH: storagePath, + NATIVEPHP_DATABASE_PATH: databaseFile, + }; + + const phpOptions = { + cwd: appPath, + env, + }; + + let command = ['artisan', 'native:php-ini']; + + if (runningSecureBuild()) { + command.unshift(join(appPath, 'build', '__nativephp_app_bundle')); + } + + return await promisify(execFile)(state.php, command, phpOptions); } async function retrieveNativePHPConfig() { @@ -46,25 +52,39 @@ async function retrieveNativePHPConfig() { const phpOptions = { cwd: appPath, - env + env, }; - return await promisify(execFile)(state.php, ['artisan', 'native:config'], phpOptions); + let command = ['artisan', 'native:config']; + + if (runningSecureBuild()) { + command.unshift(join(appPath, 'build', '__nativephp_app_bundle')); + } + + return await promisify(execFile)(state.php, command, phpOptions); } function callPhp(args, options, phpIniSettings = {}) { - let defaultIniSettings = { - 'memory_limit': '512M', - 'curl.cainfo': state.caCert, - 'openssl.cafile': state.caCert + if (args[0] === 'artisan' && runningSecureBuild()) { + args.unshift(join(appPath, 'build', '__nativephp_app_bundle')); } + let defaultIniSettings = { + 'memory_limit': '512M', + 'curl.cainfo': state.caCert, + 'openssl.cafile': state.caCert, + }; + let iniSettings = Object.assign(defaultIniSettings, phpIniSettings); Object.keys(iniSettings).forEach(key => { - args.unshift('-d', `${key}=${iniSettings[key]}`); + args.unshift('-d', `${key}=${iniSettings[key]}`); }); + if (parseInt(process.env.SHELL_VERBOSITY) > 0) { + console.log('Calling PHP', state.php, args); + } + return spawn( state.php, args, @@ -72,7 +92,7 @@ function callPhp(args, options, phpIniSettings = {}) { cwd: options.cwd, env: { ...process.env, - ...options.env + ...options.env, }, } ); @@ -87,6 +107,7 @@ function getArgumentEnv() { } = { }; + envArgs.forEach(arg => { const [key, value] = arg.slice(6).split('='); env[key] = value; @@ -96,26 +117,27 @@ function getArgumentEnv() { } function getAppPath() { - let appPath = join(__dirname, '../../resources/app/').replace('app.asar', 'app.asar.unpacked') + let appPath = join(__dirname, '../../resources/app/').replace('app.asar', 'app.asar.unpacked'); if (process.env.NODE_ENV === 'development' || argumentEnv.TESTING == 1) { appPath = process.env.APP_PATH || argumentEnv.APP_PATH; } + return appPath; } function ensureAppFoldersAreAvailable() { if (! existsSync(storagePath) || process.env.NODE_ENV === 'development') { - copySync(join(appPath, 'storage'), storagePath) + copySync(join(appPath, 'storage'), storagePath); } - mkdirSync(databasePath, {recursive: true}) + mkdirSync(databasePath, {recursive: true}); // Create a database file if it doesn't exist try { - statSync(databaseFile) + statSync(databaseFile); } catch (error) { - writeFileSync(databaseFile, '') + writeFileSync(databaseFile, ''); } } @@ -127,12 +149,12 @@ function startQueueWorker(secret, apiPort, phpIniSettings = {}) { NATIVEPHP_DATABASE_PATH: databaseFile, NATIVEPHP_API_URL: `http://localhost:${apiPort}/api/`, NATIVEPHP_RUNNING: true, - NATIVEPHP_SECRET: secret + NATIVEPHP_SECRET: secret, }; const phpOptions = { cwd: appPath, - env + env, }; return callPhp(['artisan', 'queue:work'], phpOptions, phpIniSettings); @@ -143,99 +165,113 @@ function startScheduler(secret, apiPort, phpIniSettings = {}) { const phpOptions = { cwd: appPath, - env + env, }; return callPhp(['artisan', 'schedule:run'], phpOptions, phpIniSettings); } function getPath(name: string) { - try { - // @ts-ignore - return app.getPath(name); - } catch (error) { - return ''; - } + try { + // @ts-ignore + return app.getPath(name); + } catch (error) { + return ''; + } } function getDefaultEnvironmentVariables(secret, apiPort) { - return { - APP_ENV: process.env.NODE_ENV === 'development' ? 'local' : 'production', - APP_DEBUG: process.env.NODE_ENV === 'development' ? 'true' : 'false', - NATIVEPHP_STORAGE_PATH: storagePath, - NATIVEPHP_DATABASE_PATH: databaseFile, - NATIVEPHP_API_URL: `http://localhost:${apiPort}/api/`, - NATIVEPHP_RUNNING: true, - NATIVEPHP_SECRET: secret, - NATIVEPHP_USER_HOME_PATH: getPath('home'), - NATIVEPHP_APP_DATA_PATH: getPath('appData'), - NATIVEPHP_USER_DATA_PATH: getPath('userData'), - NATIVEPHP_DESKTOP_PATH: getPath('desktop'), - NATIVEPHP_DOCUMENTS_PATH: getPath('documents'), - NATIVEPHP_DOWNLOADS_PATH: getPath('downloads'), - NATIVEPHP_MUSIC_PATH: getPath('music'), - NATIVEPHP_PICTURES_PATH: getPath('pictures'), - NATIVEPHP_VIDEOS_PATH: getPath('videos'), - NATIVEPHP_RECENT_PATH: getPath('recent'), - }; + return { + APP_ENV: process.env.NODE_ENV === 'development' ? 'local' : 'production', + APP_DEBUG: process.env.NODE_ENV === 'development' ? 'true' : 'false', + LARAVEL_STORAGE_PATH: storagePath, + NATIVEPHP_STORAGE_PATH: storagePath, + NATIVEPHP_DATABASE_PATH: databaseFile, + NATIVEPHP_API_URL: `http://localhost:${apiPort}/api/`, + NATIVEPHP_RUNNING: true, + NATIVEPHP_SECRET: secret, + NATIVEPHP_USER_HOME_PATH: getPath('home'), + NATIVEPHP_APP_DATA_PATH: getPath('appData'), + NATIVEPHP_USER_DATA_PATH: getPath('userData'), + NATIVEPHP_DESKTOP_PATH: getPath('desktop'), + NATIVEPHP_DOCUMENTS_PATH: getPath('documents'), + NATIVEPHP_DOWNLOADS_PATH: getPath('downloads'), + NATIVEPHP_MUSIC_PATH: getPath('music'), + NATIVEPHP_PICTURES_PATH: getPath('pictures'), + NATIVEPHP_VIDEOS_PATH: getPath('videos'), + NATIVEPHP_RECENT_PATH: getPath('recent'), + }; +} + +function runningSecureBuild() { + return existsSync(join(appPath, 'build', '__nativephp_app_bundle')) } function serveApp(secret, apiPort, phpIniSettings): Promise { return new Promise(async (resolve, reject) => { const appPath = getAppPath(); - console.log('Starting PHP server...', `${state.php} artisan serve`, appPath, phpIniSettings) + console.log('Starting PHP server...', `${state.php} artisan serve`, appPath, phpIniSettings); ensureAppFoldersAreAvailable(); - console.log('Making sure app folders are available') + console.log('Making sure app folders are available'); const env = getDefaultEnvironmentVariables(secret, apiPort); const phpOptions = { cwd: appPath, - env + env, }; const store = new Store(); // Make sure the storage path is linked - as people can move the app around, we // need to run this every time the app starts - callPhp(['artisan', 'storage:link', '--force'], phpOptions, phpIniSettings) + if (! runningSecureBuild()) { + callPhp(['artisan', 'storage:link', '--force'], phpOptions, phpIniSettings) + } // Migrate the database - if (store.get('migrated_version') !== app.getVersion() && process.env.NODE_ENV !== 'development') { - console.log('Migrating database...') - callPhp(['artisan', 'migrate', '--force'], phpOptions, phpIniSettings) - store.set('migrated_version', app.getVersion()) + if (shouldMigrateDatabase(store)) { + console.log('Migrating database...'); + callPhp(['artisan', 'migrate', '--force'], phpOptions, phpIniSettings); + store.set('migrated_version', app.getVersion()); } if (process.env.NODE_ENV === 'development') { - console.log('Skipping Database migration while in development.') - console.log('You may migrate manually by running: php artisan native:migrate') + console.log('Skipping Database migration while in development.'); + console.log('You may migrate manually by running: php artisan native:migrate'); } const phpPort = await getPhpPort(); - const serverPath = join(appPath, 'vendor', 'laravel', 'framework', 'src', 'Illuminate', 'Foundation', 'resources', 'server.php') + let serverPath = join(appPath, 'build', '__nativephp_app_bundle'); + + if (! runningSecureBuild()) { + console.log('* * * Running from source * * *'); + serverPath = join(appPath, 'vendor', 'laravel', 'framework', 'src', 'Illuminate', 'Foundation', 'resources', 'server.php'); + } + const phpServer = callPhp(['-S', `127.0.0.1:${phpPort}`, serverPath], { cwd: join(appPath, 'public'), - env - }, phpIniSettings) + env, + }, phpIniSettings); - const portRegex = /Development Server \(.*:([0-9]+)\) started/gm + const portRegex = /Development Server \(.*:([0-9]+)\) started/gm; phpServer.stdout.on('data', (data) => { - const match = portRegex.exec(data.toString()) + const match = portRegex.exec(data.toString()); + if (match) { - console.log("PHP Server started on port: ", match[1]) - const port = parseInt(match[1]) + console.log("PHP Server started on port: ", match[1]); + const port = parseInt(match[1]); resolve({ port, - process: phpServer - }) + process: phpServer, + }); } - }) + }); phpServer.stderr.on('data', (data) => { const error = data.toString(); @@ -246,7 +282,7 @@ function serveApp(secret, apiPort, phpIniSettings): Promise { console.log("PHP Server started on port: ", port); resolve({ port, - process: phpServer + process: phpServer, }); } else { // 27 is the length of the php -S output preamble @@ -262,9 +298,14 @@ function serveApp(secret, apiPort, phpIniSettings): Promise { }); phpServer.on('error', (error) => { - reject(error) - }) + reject(error); + }); }) } -export {startQueueWorker, startScheduler, serveApp, getAppPath, retrieveNativePHPConfig, retrievePhpIniSettings} +function shouldMigrateDatabase(store) { + return store.get('migrated_version') !== app.getVersion() + && process.env.NODE_ENV !== 'development'; +} + +export { startQueueWorker, startScheduler, serveApp, getAppPath, retrieveNativePHPConfig, retrievePhpIniSettings }; From 093880668ff881b3e5206f647860daffbe561f1c Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Tue, 10 Dec 2024 07:03:17 +0000 Subject: [PATCH 08/12] Move trait --- src/Commands/BuildCommand.php | 2 +- src/Commands/PublishCommand.php | 2 +- src/Traits/ExecuteCommand.php | 2 +- src/{Concerns => Traits}/LocatesPhpBinary.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/{Concerns => Traits}/LocatesPhpBinary.php (93%) diff --git a/src/Commands/BuildCommand.php b/src/Commands/BuildCommand.php index 7fcf837e..01c43769 100644 --- a/src/Commands/BuildCommand.php +++ b/src/Commands/BuildCommand.php @@ -5,9 +5,9 @@ use Illuminate\Console\Command; use Illuminate\Support\Facades\Process; use Illuminate\Support\Str; -use Native\Electron\Concerns\LocatesPhpBinary; use Native\Electron\Facades\Updater; use Native\Electron\Traits\InstallsAppIcon; +use Native\Electron\Traits\LocatesPhpBinary; use Native\Electron\Traits\OsAndArch; use Native\Electron\Traits\SetsAppName; diff --git a/src/Commands/PublishCommand.php b/src/Commands/PublishCommand.php index e5b13751..26dbf78b 100644 --- a/src/Commands/PublishCommand.php +++ b/src/Commands/PublishCommand.php @@ -4,7 +4,7 @@ use Illuminate\Console\Command; use Illuminate\Support\Facades\Artisan; -use Native\Electron\Concerns\LocatesPhpBinary; +use Native\Electron\Traits\LocatesPhpBinary; use Native\Electron\Traits\OsAndArch; class PublishCommand extends Command diff --git a/src/Traits/ExecuteCommand.php b/src/Traits/ExecuteCommand.php index 24dd7bf9..4b9f0dfb 100644 --- a/src/Traits/ExecuteCommand.php +++ b/src/Traits/ExecuteCommand.php @@ -3,7 +3,7 @@ namespace Native\Electron\Traits; use Illuminate\Support\Facades\Process; -use Native\Electron\Concerns\LocatesPhpBinary; +use Native\Electron\Traits\LocatesPhpBinary; use function Laravel\Prompts\note; diff --git a/src/Concerns/LocatesPhpBinary.php b/src/Traits/LocatesPhpBinary.php similarity index 93% rename from src/Concerns/LocatesPhpBinary.php rename to src/Traits/LocatesPhpBinary.php index e613ef1f..c5763572 100644 --- a/src/Concerns/LocatesPhpBinary.php +++ b/src/Traits/LocatesPhpBinary.php @@ -1,6 +1,6 @@ Date: Thu, 19 Dec 2024 10:35:50 +0000 Subject: [PATCH 09/12] Add env file processing in build step --- src/Commands/BuildCommand.php | 6 +++++ src/Traits/CleansEnvFile.php | 48 +++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/Traits/CleansEnvFile.php diff --git a/src/Commands/BuildCommand.php b/src/Commands/BuildCommand.php index 01c43769..de0fc728 100644 --- a/src/Commands/BuildCommand.php +++ b/src/Commands/BuildCommand.php @@ -6,6 +6,7 @@ use Illuminate\Support\Facades\Process; use Illuminate\Support\Str; use Native\Electron\Facades\Updater; +use Native\Electron\Traits\CleansEnvFile; use Native\Electron\Traits\InstallsAppIcon; use Native\Electron\Traits\LocatesPhpBinary; use Native\Electron\Traits\OsAndArch; @@ -13,6 +14,7 @@ class BuildCommand extends Command { + use CleansEnvFile; use InstallsAppIcon; use LocatesPhpBinary; use OsAndArch; @@ -29,6 +31,8 @@ public function handle(): void { $this->info('Build NativePHP app…'); + $this->prepareNativeEnv(); + $this->setAppName(slugify: true); Process::path(__DIR__.'/../../resources/js/') @@ -68,6 +72,8 @@ public function handle(): void ->run("npm run {$buildCommand}:{$os}", function (string $type, string $output) { echo $output; }); + + $this->restoreWebEnv(); } protected function getEnvironmentVariables(): array diff --git a/src/Traits/CleansEnvFile.php b/src/Traits/CleansEnvFile.php new file mode 100644 index 00000000..166d3727 --- /dev/null +++ b/src/Traits/CleansEnvFile.php @@ -0,0 +1,48 @@ +line('Preparing production .env file…'); + + $envFile = app()->environmentFilePath(); + + if (! file_exists($backup = $this->getBackupEnvFilePath())) { + copy($envFile, $backup); + } + + $this->cleanEnvFile($envFile); + } + + protected function cleanEnvFile(string $path): void + { + $cleanUpKeys = config('nativephp.cleanup_env_keys', []); + + $contents = collect(file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)) + ->filter(function (string $line) use ($cleanUpKeys) { + $key = str($line)->before('='); + + return ! $key->is($cleanUpKeys) + && ! $key->startsWith('#'); + }) + ->join("\n"); + + file_put_contents($path, $contents); + } + + protected function restoreWebEnv(): void + { + copy($this->getBackupEnvFilePath(), app()->environmentFilePath()); + unlink($this->getBackupEnvFilePath()); + } + + protected function getBackupEnvFilePath(): string + { + return base_path('.env.backup'); + } +} From 461acb3d4cd2ce2ecc1c823d0f3fcc411609377e Mon Sep 17 00:00:00 2001 From: simonhamp Date: Thu, 19 Dec 2024 10:36:43 +0000 Subject: [PATCH 10/12] Fix styling --- src/Traits/CleansEnvFile.php | 2 -- src/Traits/ExecuteCommand.php | 1 - 2 files changed, 3 deletions(-) diff --git a/src/Traits/CleansEnvFile.php b/src/Traits/CleansEnvFile.php index 166d3727..06916723 100644 --- a/src/Traits/CleansEnvFile.php +++ b/src/Traits/CleansEnvFile.php @@ -2,8 +2,6 @@ namespace Native\Electron\Traits; -use function Laravel\Prompts\note; - trait CleansEnvFile { protected function prepareNativeEnv(): void diff --git a/src/Traits/ExecuteCommand.php b/src/Traits/ExecuteCommand.php index 4b9f0dfb..26e98c06 100644 --- a/src/Traits/ExecuteCommand.php +++ b/src/Traits/ExecuteCommand.php @@ -3,7 +3,6 @@ namespace Native\Electron\Traits; use Illuminate\Support\Facades\Process; -use Native\Electron\Traits\LocatesPhpBinary; use function Laravel\Prompts\note; From bd9419ef9e2c620d4bee6481385dea5b31970755 Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Thu, 19 Dec 2024 10:36:53 +0000 Subject: [PATCH 11/12] Don't copy builds, logs or caches --- resources/js/electron-builder.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/resources/js/electron-builder.js b/resources/js/electron-builder.js index fbd50891..11dce835 100644 --- a/resources/js/electron-builder.js +++ b/resources/js/electron-builder.js @@ -30,12 +30,8 @@ if (isDarwin) { targetOs = 'mac'; } - let updaterConfig = {}; -// We wouldn't need these since its not representing the target platform -console.log("Arch: ", process.arch) -console.log("Platform: ", process.platform) try { updaterConfig = process.env.NATIVEPHP_UPDATER_CONFIG; updaterConfig = JSON.parse(updaterConfig); @@ -44,6 +40,8 @@ try { } if (isBuilding) { + console.log("Current platform: ", process.platform) + console.log("Current arch: ", process.arch) console.log(); console.log('==================================================================='); @@ -91,6 +89,10 @@ if (isBuilding) { join(process.env.APP_PATH, 'vendor', 'nativephp', 'electron', 'resources'), join(process.env.APP_PATH, 'node_modules'), join(process.env.APP_PATH, 'dist'), + join(process.env.APP_PATH, 'build'), + + join(process.env.APP_PATH, 'storage', 'framework'), + join(process.env.APP_PATH, 'storage', 'logs'), ]; let shouldSkip = false; From 3f5996d90a5437a336d13649bf21035f0737a71d Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Thu, 2 Jan 2025 23:17:14 +0000 Subject: [PATCH 12/12] Clear the view cache on boot --- resources/js/electron-plugin/src/server/php.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/js/electron-plugin/src/server/php.ts b/resources/js/electron-plugin/src/server/php.ts index c3acdaa3..2e50ec4d 100644 --- a/resources/js/electron-plugin/src/server/php.ts +++ b/resources/js/electron-plugin/src/server/php.ts @@ -213,7 +213,8 @@ function serveApp(secret, apiPort, phpIniSettings): Promise { // Make sure the storage path is linked - as people can move the app around, we // need to run this every time the app starts if (! runningSecureBuild()) { - callPhp(['artisan', 'storage:link', '--force'], phpOptions, phpIniSettings) + callPhp(['artisan', 'storage:link', '--force'], phpOptions, phpIniSettings); + callPhp(['artisan', 'view:cache'], phpOptions, phpIniSettings); } // Migrate the database