chore: unCRLF
This commit is contained in:
parent
d605f783af
commit
9aa70d3131
12
.gitignore
vendored
12
.gitignore
vendored
@ -1,7 +1,7 @@
|
||||
# node
|
||||
node_modules
|
||||
package-lock.json
|
||||
|
||||
# gluon
|
||||
build
|
||||
# node
|
||||
node_modules
|
||||
package-lock.json
|
||||
|
||||
# gluon
|
||||
build
|
||||
chrome_data
|
40
LICENSE
40
LICENSE
@ -1,21 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 OpenAsar
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 OpenAsar
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
92
README.md
92
README.md
@ -1,47 +1,47 @@
|
||||
# Gluon
|
||||
Minimal integrated ecosystem for making "desktop apps" from websites easily using Chromium and NodeJS. Uses system installed Chromium and NodeJS, with optional bundling if you want that too (soon). ***VERY*** early and probably never finished/production ready. Doesn't use WebView2.
|
||||
|
||||
<br>
|
||||
|
||||
## Ecosystem
|
||||
- [Gluon](gluon): the Gluon library (NodeJS)
|
||||
- [Glugun](glugun): builds Gluon apps into releasable builds with optional bundling (soon)
|
||||
|
||||
### Apps
|
||||
- [Gluworld](gluworld): basic Hello World demo app
|
||||
- [Glucord](glucord): minimal desktop Discord client loading official webapp (demo/example)
|
||||
|
||||
<br>
|
||||
|
||||
## Release Schedule
|
||||
Gluon (and it's subprojects) use a `major.patch` version format, with major releases being released daily if there are changes present in `main`, while using `X.0-dev` in the meantime. Patch releases may happen inbetween to fix bugs (not adding anything new or breaking).
|
||||
|
||||
<br>
|
||||
|
||||
## Comparisons
|
||||
### Internals
|
||||
| Part | Gluon | Electron | Tauri | Neutralinojs |
|
||||
| ---- | ----- | -------- | ------------ | ----- |
|
||||
| Frontend | System installed Chromium | Self-contained Chromium | System installed webview | System installed webview |
|
||||
| Backend | System installed Node.JS | Self-contained Node.JS | Native (Rust) | Native (Any) |
|
||||
| IPC | None (WIP) | Preload | Window object | Window object |
|
||||
| Status | Early in development | "Production ready" | Usable | Usable |
|
||||
| Ecosystem | Integrated | Distributed | Integrated | Integrated |
|
||||
|
||||
|
||||
### Benchmark / Stats
|
||||
Basic (plain HTML) Hello World demo, measured on up to date Windows 10. Used latest stable versions of all frameworks as of 9th Dec 2022.
|
||||
|
||||
| Stat | Gluon | Electron | Tauri | Neutralinojs |
|
||||
| ---- | ----- | -------- | ------------ | ----- |
|
||||
| Build Size | ~0.5MB[^system][^gluon][^1] | ~190MB | ~1.8MB[^system] | ~2.6MB[^system] |
|
||||
| Memory Usage | ~90MB[^gluon] | ~100MB | ~90MB | ~90MB |
|
||||
| Backend[^2] Memory Usage | ~13MB[^gluon] | ~22MB | ~3MB | ~3MB |
|
||||
|
||||
*Extra info: All HTML/CSS/JS is unminified (including Gluon). Built in release configuration. All binaries were left as compiled with common size optimizations enabled for that language, no stripping/packing done.*
|
||||
|
||||
[^system]: Does not include system installed components.
|
||||
[^gluon]: Early/WIP data, may change in future.
|
||||
|
||||
[^1]: *How is Gluon so small?* Since NodeJS is expected as a system installed component, it is "just" bundled and minified Node code.
|
||||
# Gluon
|
||||
Minimal integrated ecosystem for making "desktop apps" from websites easily using Chromium and NodeJS. Uses system installed Chromium and NodeJS, with optional bundling if you want that too (soon). ***VERY*** early and probably never finished/production ready. Doesn't use WebView2.
|
||||
|
||||
<br>
|
||||
|
||||
## Ecosystem
|
||||
- [Gluon](gluon): the Gluon library (NodeJS)
|
||||
- [Glugun](glugun): builds Gluon apps into releasable builds with optional bundling (soon)
|
||||
|
||||
### Apps
|
||||
- [Gluworld](gluworld): basic Hello World demo app
|
||||
- [Glucord](glucord): minimal desktop Discord client loading official webapp (demo/example)
|
||||
|
||||
<br>
|
||||
|
||||
## Release Schedule
|
||||
Gluon (and it's subprojects) use a `major.patch` version format, with major releases being released daily if there are changes present in `main`, while using `X.0-dev` in the meantime. Patch releases may happen inbetween to fix bugs (not adding anything new or breaking).
|
||||
|
||||
<br>
|
||||
|
||||
## Comparisons
|
||||
### Internals
|
||||
| Part | Gluon | Electron | Tauri | Neutralinojs |
|
||||
| ---- | ----- | -------- | ------------ | ----- |
|
||||
| Frontend | System installed Chromium | Self-contained Chromium | System installed webview | System installed webview |
|
||||
| Backend | System installed Node.JS | Self-contained Node.JS | Native (Rust) | Native (Any) |
|
||||
| IPC | None (WIP) | Preload | Window object | Window object |
|
||||
| Status | Early in development | "Production ready" | Usable | Usable |
|
||||
| Ecosystem | Integrated | Distributed | Integrated | Integrated |
|
||||
|
||||
|
||||
### Benchmark / Stats
|
||||
Basic (plain HTML) Hello World demo, measured on up to date Windows 10. Used latest stable versions of all frameworks as of 9th Dec 2022.
|
||||
|
||||
| Stat | Gluon | Electron | Tauri | Neutralinojs |
|
||||
| ---- | ----- | -------- | ------------ | ----- |
|
||||
| Build Size | ~0.5MB[^system][^gluon][^1] | ~190MB | ~1.8MB[^system] | ~2.6MB[^system] |
|
||||
| Memory Usage | ~90MB[^gluon] | ~100MB | ~90MB | ~90MB |
|
||||
| Backend[^2] Memory Usage | ~13MB[^gluon] | ~22MB | ~3MB | ~3MB |
|
||||
|
||||
*Extra info: All HTML/CSS/JS is unminified (including Gluon). Built in release configuration. All binaries were left as compiled with common size optimizations enabled for that language, no stripping/packing done.*
|
||||
|
||||
[^system]: Does not include system installed components.
|
||||
[^gluon]: Early/WIP data, may change in future.
|
||||
|
||||
[^1]: *How is Gluon so small?* Since NodeJS is expected as a system installed component, it is "just" bundled and minified Node code.
|
||||
[^2]: Backend like non-Web (not Chromium/WebView2/etc).
|
@ -1,17 +1,17 @@
|
||||
# Glucord
|
||||
A minimal Discord client loading Discord Web, using system-installed Chromium/Node. Example/demo of Gluon.
|
||||
|
||||
<br>
|
||||
|
||||
## Testing
|
||||
> **Note** |
|
||||
> Gluon is currently **Windows only**.
|
||||
|
||||
1. Have recentish Chrome Stable/Canary and NodeJS installed
|
||||
1. Clone the Gluon repo
|
||||
2. `npm install` in `gluon`
|
||||
3. `node glucord` (in repo root)
|
||||
|
||||
## Building
|
||||
1. Cd into the repo root
|
||||
# Glucord
|
||||
A minimal Discord client loading Discord Web, using system-installed Chromium/Node. Example/demo of Gluon.
|
||||
|
||||
<br>
|
||||
|
||||
## Testing
|
||||
> **Note** |
|
||||
> Gluon is currently **Windows only**.
|
||||
|
||||
1. Have recentish Chrome Stable/Canary and NodeJS installed
|
||||
1. Clone the Gluon repo
|
||||
2. `npm install` in `gluon`
|
||||
3. `node glucord` (in repo root)
|
||||
|
||||
## Building
|
||||
1. Cd into the repo root
|
||||
2. `node glugun glucord glucord`
|
File diff suppressed because one or more lines are too long
230
glugun/index.js
230
glugun/index.js
@ -1,116 +1,116 @@
|
||||
import { cp, writeFile, readFile, readdir, rm, mkdir, stat, access } from 'fs/promises';
|
||||
import { join, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
import * as Esbuild from 'esbuild';
|
||||
import * as HTMLMinifier from 'html-minifier-terser';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const rgb = (r, g, b, msg) => `\x1b[38;2;${r};${g};${b}m${msg}\x1b[0m`;
|
||||
const log = (...args) => console.log(`[${rgb(235, 69, 158, 'Glugun')}]`, ...args);
|
||||
|
||||
const minifyBackend = process.argv.includes('--minify');
|
||||
|
||||
const esbuildPlugin = { // esbuild to fix some things in src files
|
||||
name: 'glugun-esbuild',
|
||||
setup(build) {
|
||||
build.onLoad({ filter: /\.js$/ }, async (args) => {
|
||||
let source = await readFile(args.path, 'utf8');
|
||||
|
||||
source = source
|
||||
.replace(`const __filename = fileURLToPath(import.meta.url);\r\nconst __dirname = dirname(__filename);`, ''); // remove setting __filename/__dirname cause ESM -> CJS
|
||||
|
||||
return { contents: source };
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const exists = path => access(path).then(() => true).catch(() => false);
|
||||
|
||||
const dirSize = async dir => {
|
||||
const files = await readdir(dir, { withFileTypes: true });
|
||||
|
||||
const paths = files.map(async file => {
|
||||
const path = join(dir, file.name);
|
||||
|
||||
if (file.isDirectory()) return await dirSize(path);
|
||||
if (file.isFile()) return (await stat(path)).size;
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
return (await Promise.all(paths)).flat(Infinity).reduce((acc, x) => acc + x, 0);
|
||||
};
|
||||
|
||||
|
||||
const buildDir = join(__dirname, '..', 'build');
|
||||
const _buildWin32 = async (name, dir, attrs) => {
|
||||
// reset build dir
|
||||
await rm(buildDir, { recursive: true, force: true });
|
||||
await mkdir(buildDir, { recursive: true });
|
||||
|
||||
await cp(dir, join(buildDir, 'src'), { recursive: true }); // copy project src to build
|
||||
await cp(join(__dirname, '..', 'gluon'), join(buildDir, 'src', 'gluon'), { recursive: true }); // copy gluon into build
|
||||
|
||||
for (const m of [ 'ws', 'chrome-remote-interface' ]) {
|
||||
const dest = join(buildDir, 'src', 'node_modules', m);
|
||||
await cp(join(__dirname, '..', 'node_modules', m), dest, { recursive: true }); // copy gluon deps into build
|
||||
|
||||
for (const x of await readdir(dest)) {
|
||||
if ([ 'bin', 'README.md', 'webpack.config.json', 'browser.js' ].includes(x)) await rm(join(dest, x), { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
// await writeFile(join(buildDir, 'gluon_info.txt'), `Gluon 0.1, built with Glugun 0.1 (win32 ${attrs.join(',')})`);
|
||||
let indexContent = await readFile(join(buildDir, 'src', 'index.js'), 'utf8');
|
||||
|
||||
indexContent = indexContent.replace('../gluon/', './gluon/')
|
||||
.replaceAll('GLUGUN_VERSION', '2.1')
|
||||
.replaceAll('SYSTEM_CHROMIUM', attrs.includes('system-chromium'))
|
||||
.replaceAll('SYSTEM_NODE', attrs.includes('system-node'));
|
||||
|
||||
await writeFile(join(buildDir, 'src', 'index.js'), indexContent);
|
||||
|
||||
await writeFile(join(buildDir, `${name}.bat`), `node %~dp0${minifyBackend ? 'out.js' : 'src'}`);
|
||||
|
||||
if (minifyBackend) {
|
||||
log(`pre-minify build size: ${((await dirSize(buildDir)) / 1024 / 1024).toFixed(2)}MB`);
|
||||
|
||||
await Esbuild.build({ // bundle and minify into 1 file
|
||||
entryPoints: [ join(buildDir, 'src', 'index.js') ],
|
||||
bundle: true,
|
||||
minify: true,
|
||||
format: 'iife',
|
||||
platform: 'node',
|
||||
outfile: join(buildDir, 'out.js'),
|
||||
plugins: [ esbuildPlugin ]
|
||||
});
|
||||
|
||||
const htmlPath = join(buildDir, 'src', 'index.html');
|
||||
if (await exists(htmlPath)) {
|
||||
const content = await readFile(htmlPath, 'utf8');
|
||||
writeFile(join(buildDir, 'index.html'), await HTMLMinifier.minify(content));
|
||||
}
|
||||
|
||||
await rm(join(buildDir, 'src'), { recursive: true }); // delete original src
|
||||
}
|
||||
};
|
||||
|
||||
export const build = async (name, dir, platform = 'win32', attrs = 'system-chromium,system-node') => {
|
||||
log('building', name, 'on', platform, 'with', attrs.split(',').join(', ') + '...');
|
||||
|
||||
console.log();
|
||||
const startTime = performance.now();
|
||||
switch (platform) {
|
||||
case 'win32': await _buildWin32(name, dir, attrs.split(','));
|
||||
}
|
||||
|
||||
console.log();
|
||||
log(`finished build in: ${((performance.now() - startTime) / 1024).toFixed(2)}s`);
|
||||
log(`final build size: ${((await dirSize(buildDir)) / 1024 / 1024).toFixed(2)}MB`);
|
||||
};
|
||||
|
||||
const [ name, dir ] = process.argv.slice(2);
|
||||
import { cp, writeFile, readFile, readdir, rm, mkdir, stat, access } from 'fs/promises';
|
||||
import { join, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
import * as Esbuild from 'esbuild';
|
||||
import * as HTMLMinifier from 'html-minifier-terser';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const rgb = (r, g, b, msg) => `\x1b[38;2;${r};${g};${b}m${msg}\x1b[0m`;
|
||||
const log = (...args) => console.log(`[${rgb(235, 69, 158, 'Glugun')}]`, ...args);
|
||||
|
||||
const minifyBackend = process.argv.includes('--minify');
|
||||
|
||||
const esbuildPlugin = { // esbuild to fix some things in src files
|
||||
name: 'glugun-esbuild',
|
||||
setup(build) {
|
||||
build.onLoad({ filter: /\.js$/ }, async (args) => {
|
||||
let source = await readFile(args.path, 'utf8');
|
||||
|
||||
source = source
|
||||
.replace(`const __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);`, ''); // remove setting __filename/__dirname cause ESM -> CJS
|
||||
|
||||
return { contents: source };
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const exists = path => access(path).then(() => true).catch(() => false);
|
||||
|
||||
const dirSize = async dir => {
|
||||
const files = await readdir(dir, { withFileTypes: true });
|
||||
|
||||
const paths = files.map(async file => {
|
||||
const path = join(dir, file.name);
|
||||
|
||||
if (file.isDirectory()) return await dirSize(path);
|
||||
if (file.isFile()) return (await stat(path)).size;
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
return (await Promise.all(paths)).flat(Infinity).reduce((acc, x) => acc + x, 0);
|
||||
};
|
||||
|
||||
|
||||
const buildDir = join(__dirname, '..', 'build');
|
||||
const _buildWin32 = async (name, dir, attrs) => {
|
||||
// reset build dir
|
||||
await rm(buildDir, { recursive: true, force: true });
|
||||
await mkdir(buildDir, { recursive: true });
|
||||
|
||||
await cp(dir, join(buildDir, 'src'), { recursive: true }); // copy project src to build
|
||||
await cp(join(__dirname, '..', 'gluon'), join(buildDir, 'src', 'gluon'), { recursive: true }); // copy gluon into build
|
||||
|
||||
for (const m of [ 'ws', 'chrome-remote-interface' ]) {
|
||||
const dest = join(buildDir, 'src', 'node_modules', m);
|
||||
await cp(join(__dirname, '..', 'node_modules', m), dest, { recursive: true }); // copy gluon deps into build
|
||||
|
||||
for (const x of await readdir(dest)) {
|
||||
if ([ 'bin', 'README.md', 'webpack.config.json', 'browser.js' ].includes(x)) await rm(join(dest, x), { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
// await writeFile(join(buildDir, 'gluon_info.txt'), `Gluon 0.1, built with Glugun 0.1 (win32 ${attrs.join(',')})`);
|
||||
let indexContent = await readFile(join(buildDir, 'src', 'index.js'), 'utf8');
|
||||
|
||||
indexContent = indexContent.replace('../gluon/', './gluon/')
|
||||
.replaceAll('GLUGUN_VERSION', '2.1')
|
||||
.replaceAll('SYSTEM_CHROMIUM', attrs.includes('system-chromium'))
|
||||
.replaceAll('SYSTEM_NODE', attrs.includes('system-node'));
|
||||
|
||||
await writeFile(join(buildDir, 'src', 'index.js'), indexContent);
|
||||
|
||||
await writeFile(join(buildDir, `${name}.bat`), `node %~dp0${minifyBackend ? 'out.js' : 'src'}`);
|
||||
|
||||
if (minifyBackend) {
|
||||
log(`pre-minify build size: ${((await dirSize(buildDir)) / 1024 / 1024).toFixed(2)}MB`);
|
||||
|
||||
await Esbuild.build({ // bundle and minify into 1 file
|
||||
entryPoints: [ join(buildDir, 'src', 'index.js') ],
|
||||
bundle: true,
|
||||
minify: true,
|
||||
format: 'iife',
|
||||
platform: 'node',
|
||||
outfile: join(buildDir, 'out.js'),
|
||||
plugins: [ esbuildPlugin ]
|
||||
});
|
||||
|
||||
const htmlPath = join(buildDir, 'src', 'index.html');
|
||||
if (await exists(htmlPath)) {
|
||||
const content = await readFile(htmlPath, 'utf8');
|
||||
writeFile(join(buildDir, 'index.html'), await HTMLMinifier.minify(content));
|
||||
}
|
||||
|
||||
await rm(join(buildDir, 'src'), { recursive: true }); // delete original src
|
||||
}
|
||||
};
|
||||
|
||||
export const build = async (name, dir, platform = 'win32', attrs = 'system-chromium,system-node') => {
|
||||
log('building', name, 'on', platform, 'with', attrs.split(',').join(', ') + '...');
|
||||
|
||||
console.log();
|
||||
const startTime = performance.now();
|
||||
switch (platform) {
|
||||
case 'win32': await _buildWin32(name, dir, attrs.split(','));
|
||||
}
|
||||
|
||||
console.log();
|
||||
log(`finished build in: ${((performance.now() - startTime) / 1024).toFixed(2)}s`);
|
||||
log(`final build size: ${((await dirSize(buildDir)) / 1024 / 1024).toFixed(2)}MB`);
|
||||
};
|
||||
|
||||
const [ name, dir ] = process.argv.slice(2);
|
||||
build(name, dir);
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.16.3",
|
||||
"html-minifier-terser": "^7.1.0"
|
||||
}
|
||||
{
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.16.3",
|
||||
"html-minifier-terser": "^7.1.0"
|
||||
}
|
||||
}
|
200
gluon/index.js
200
gluon/index.js
@ -1,100 +1,100 @@
|
||||
const rgb = (r, g, b, msg) => `\x1b[38;2;${r};${g};${b}m${msg}\x1b[0m`;
|
||||
const log = (...args) => console.log(`[${rgb(88, 101, 242, 'Gluon')}]`, ...args);
|
||||
|
||||
process.versions.gluon = '2.1';
|
||||
|
||||
const presets = { // Presets from OpenAsar
|
||||
'base': '--autoplay-policy=no-user-gesture-required --disable-features=WinRetrieveSuggestionsOnlyOnDemand,HardwareMediaKeyHandling,MediaSessionService', // Base Discord
|
||||
'perf': '--enable-gpu-rasterization --enable-zero-copy --ignore-gpu-blocklist --enable-hardware-overlays=single-fullscreen,single-on-top,underlay --enable-features=EnableDrDc,CanvasOopRasterization,BackForwardCache:TimeToLiveInBackForwardCacheInSeconds/300/should_ignore_blocklists/true/enable_same_site/true,ThrottleDisplayNoneAndVisibilityHiddenCrossOriginIframes,UseSkiaRenderer,WebAssemblyLazyCompilation --disable-features=Vulkan --force_high_performance_gpu', // Performance
|
||||
'battery': '--enable-features=TurnOffStreamingMediaCachingOnBattery --force_low_power_gpu', // Known to have better battery life for Chromium?
|
||||
'memory': '--in-process-gpu --js-flags="--lite-mode --optimize_for_size --wasm_opt --wasm_lazy_compilation --wasm_lazy_validation --always_compact" --renderer-process-limit=2 --enable-features=QuickIntensiveWakeUpThrottlingAfterLoading' // Less (?) memory usage
|
||||
};
|
||||
|
||||
import { exec } from 'child_process';
|
||||
import { join, dirname } from 'path';
|
||||
import { access } from 'fs/promises';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
import CDP from 'chrome-remote-interface';
|
||||
|
||||
const chromiumPathsWin = {
|
||||
stable: join(process.env.PROGRAMFILES, 'Google', 'Chrome', 'Application', 'chrome.exe'),
|
||||
canary: join(process.env.LOCALAPPDATA, 'Google', 'Chrome SxS', 'Application', 'chrome.exe'),
|
||||
edge: join(process.env['PROGRAMFILES(x86)'], 'Microsoft', 'Edge', 'Application', 'msedge.exe')
|
||||
};
|
||||
|
||||
const exists = path => access(path).then(() => true).catch(() => false);
|
||||
|
||||
const findChromiumPath = async () => {
|
||||
let whichChromium = '';
|
||||
|
||||
for (const x of [ 'stable', 'canary', 'edge' ]) {
|
||||
if (process.argv.includes('--' + x)) whichChromium = x;
|
||||
}
|
||||
|
||||
if (!whichChromium) {
|
||||
for (const x in chromiumPathsWin) {
|
||||
log(x, chromiumPathsWin[x], await exists(chromiumPathsWin[x]));
|
||||
|
||||
if (await exists(chromiumPathsWin[x])) {
|
||||
whichChromium = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!whichChromium) return null;
|
||||
|
||||
return chromiumPathsWin[whichChromium];
|
||||
};
|
||||
|
||||
const getDataPath = () => join(__dirname, '..', 'chrome_data');
|
||||
|
||||
|
||||
const startChromium = (url, { windowSize }) => new Promise(async res => {
|
||||
const dataPath = getDataPath();
|
||||
const chromiumPath = await findChromiumPath();
|
||||
|
||||
log('chromium path:', chromiumPath);
|
||||
log('data path:', dataPath);
|
||||
|
||||
if (!chromiumPath) return log('failed to find a good chromium install');
|
||||
|
||||
const debugPort = 9222;
|
||||
|
||||
exec(`"${chromiumPath}" --app=${url} --remote-debugging-port=${debugPort} --user-data-dir="${dataPath}" ${windowSize ? `--window-size=${windowSize.join(',')}` : ''} --new-window --disable-extensions --disable-default-apps --disable-breakpad --disable-crashpad --disable-background-networking --disable-domain-reliability --disable-component-update --disable-sync --disable-features=AutofillServerCommunication ${presets.perf}`, (err, stdout, stderr) => {
|
||||
log(err, stdout, stderr);
|
||||
});
|
||||
|
||||
setTimeout(() => res(debugPort), 500);
|
||||
});
|
||||
|
||||
export const open = async (url, onLoad = () => {}, { windowSize } = {}) => {
|
||||
log('starting chromium...');
|
||||
|
||||
const debugPort = await startChromium(url, { windowSize });
|
||||
log('connecting to CDP...');
|
||||
|
||||
const { Runtime, Page } = await CDP({ port: debugPort });
|
||||
|
||||
// const run = async js => (await Runtime.evaluate({ expression: js })).result.value;
|
||||
const run = async js => log(await Runtime.evaluate({ expression: js }));
|
||||
|
||||
const toRun = `(() => {
|
||||
if (window.self !== window.top) return; // inside frame
|
||||
|
||||
const GLUON_VERSION = '${process.versions.gluon}';
|
||||
const NODE_VERSION = '${process.versions.node}';
|
||||
const CHROMIUM_VERSION = navigator.userAgentData.brands.find(x => x.brand === "Chromium").version;
|
||||
|
||||
(${onLoad.toString()})();
|
||||
})()`;
|
||||
|
||||
run(toRun);
|
||||
|
||||
await Page.enable();
|
||||
await Page.addScriptToEvaluateOnNewDocument({ source: toRun });
|
||||
};
|
||||
const rgb = (r, g, b, msg) => `\x1b[38;2;${r};${g};${b}m${msg}\x1b[0m`;
|
||||
const log = (...args) => console.log(`[${rgb(88, 101, 242, 'Gluon')}]`, ...args);
|
||||
|
||||
process.versions.gluon = '2.1';
|
||||
|
||||
const presets = { // Presets from OpenAsar
|
||||
'base': '--autoplay-policy=no-user-gesture-required --disable-features=WinRetrieveSuggestionsOnlyOnDemand,HardwareMediaKeyHandling,MediaSessionService', // Base Discord
|
||||
'perf': '--enable-gpu-rasterization --enable-zero-copy --ignore-gpu-blocklist --enable-hardware-overlays=single-fullscreen,single-on-top,underlay --enable-features=EnableDrDc,CanvasOopRasterization,BackForwardCache:TimeToLiveInBackForwardCacheInSeconds/300/should_ignore_blocklists/true/enable_same_site/true,ThrottleDisplayNoneAndVisibilityHiddenCrossOriginIframes,UseSkiaRenderer,WebAssemblyLazyCompilation --disable-features=Vulkan --force_high_performance_gpu', // Performance
|
||||
'battery': '--enable-features=TurnOffStreamingMediaCachingOnBattery --force_low_power_gpu', // Known to have better battery life for Chromium?
|
||||
'memory': '--in-process-gpu --js-flags="--lite-mode --optimize_for_size --wasm_opt --wasm_lazy_compilation --wasm_lazy_validation --always_compact" --renderer-process-limit=2 --enable-features=QuickIntensiveWakeUpThrottlingAfterLoading' // Less (?) memory usage
|
||||
};
|
||||
|
||||
import { exec } from 'child_process';
|
||||
import { join, dirname } from 'path';
|
||||
import { access } from 'fs/promises';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
import CDP from 'chrome-remote-interface';
|
||||
|
||||
const chromiumPathsWin = {
|
||||
stable: join(process.env.PROGRAMFILES, 'Google', 'Chrome', 'Application', 'chrome.exe'),
|
||||
canary: join(process.env.LOCALAPPDATA, 'Google', 'Chrome SxS', 'Application', 'chrome.exe'),
|
||||
edge: join(process.env['PROGRAMFILES(x86)'], 'Microsoft', 'Edge', 'Application', 'msedge.exe')
|
||||
};
|
||||
|
||||
const exists = path => access(path).then(() => true).catch(() => false);
|
||||
|
||||
const findChromiumPath = async () => {
|
||||
let whichChromium = '';
|
||||
|
||||
for (const x of [ 'stable', 'canary', 'edge' ]) {
|
||||
if (process.argv.includes('--' + x)) whichChromium = x;
|
||||
}
|
||||
|
||||
if (!whichChromium) {
|
||||
for (const x in chromiumPathsWin) {
|
||||
log(x, chromiumPathsWin[x], await exists(chromiumPathsWin[x]));
|
||||
|
||||
if (await exists(chromiumPathsWin[x])) {
|
||||
whichChromium = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!whichChromium) return null;
|
||||
|
||||
return chromiumPathsWin[whichChromium];
|
||||
};
|
||||
|
||||
const getDataPath = () => join(__dirname, '..', 'chrome_data');
|
||||
|
||||
|
||||
const startChromium = (url, { windowSize }) => new Promise(async res => {
|
||||
const dataPath = getDataPath();
|
||||
const chromiumPath = await findChromiumPath();
|
||||
|
||||
log('chromium path:', chromiumPath);
|
||||
log('data path:', dataPath);
|
||||
|
||||
if (!chromiumPath) return log('failed to find a good chromium install');
|
||||
|
||||
const debugPort = 9222;
|
||||
|
||||
exec(`"${chromiumPath}" --app=${url} --remote-debugging-port=${debugPort} --user-data-dir="${dataPath}" ${windowSize ? `--window-size=${windowSize.join(',')}` : ''} --new-window --disable-extensions --disable-default-apps --disable-breakpad --disable-crashpad --disable-background-networking --disable-domain-reliability --disable-component-update --disable-sync --disable-features=AutofillServerCommunication ${presets.perf}`, (err, stdout, stderr) => {
|
||||
log(err, stdout, stderr);
|
||||
});
|
||||
|
||||
setTimeout(() => res(debugPort), 500);
|
||||
});
|
||||
|
||||
export const open = async (url, onLoad = () => {}, { windowSize } = {}) => {
|
||||
log('starting chromium...');
|
||||
|
||||
const debugPort = await startChromium(url, { windowSize });
|
||||
log('connecting to CDP...');
|
||||
|
||||
const { Runtime, Page } = await CDP({ port: debugPort });
|
||||
|
||||
// const run = async js => (await Runtime.evaluate({ expression: js })).result.value;
|
||||
const run = async js => log(await Runtime.evaluate({ expression: js }));
|
||||
|
||||
const toRun = `(() => {
|
||||
if (window.self !== window.top) return; // inside frame
|
||||
|
||||
const GLUON_VERSION = '${process.versions.gluon}';
|
||||
const NODE_VERSION = '${process.versions.node}';
|
||||
const CHROMIUM_VERSION = navigator.userAgentData.brands.find(x => x.brand === "Chromium").version;
|
||||
|
||||
(${onLoad.toString()})();
|
||||
})()`;
|
||||
|
||||
run(toRun);
|
||||
|
||||
await Page.enable();
|
||||
await Page.addScriptToEvaluateOnNewDocument({ source: toRun });
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"chrome-remote-interface": "^0.31.3"
|
||||
}
|
||||
}
|
||||
{
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"chrome-remote-interface": "^0.31.3"
|
||||
}
|
||||
}
|
||||
|
@ -1,78 +1,78 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="https://raw.githubusercontent.com/OpenAsar/gluon/main/assets/logo.png">
|
||||
<title>Gluworld</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>
|
||||
Gluon <code id="gluon_version"></code> <br>
|
||||
built with <code id="glugun_version"></code>
|
||||
</h1>
|
||||
|
||||
<div id="versions">
|
||||
<h2>
|
||||
Chromium <br>
|
||||
<code id="chromium_version"></code>
|
||||
</h2>
|
||||
|
||||
<h2>
|
||||
Node <br>
|
||||
<code id="node_version"></code>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=Roboto:ital,wght@0,400;0,700;1,500&display=swap'); */
|
||||
@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@300;400;500;600;700&family=Inter:wght@300;400;500;600;700;800;900');
|
||||
|
||||
html, body {
|
||||
background: #101418;
|
||||
color: #fff;
|
||||
font-family: Inter, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
width: 90%;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
h1, h2, code {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 900;
|
||||
font-size: 34px;
|
||||
}
|
||||
|
||||
h1 > code {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: 800;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 100%;
|
||||
font-family: Fira Code;
|
||||
}
|
||||
|
||||
#versions {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
width: 100%;
|
||||
|
||||
margin-top: 20vh;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="https://raw.githubusercontent.com/OpenAsar/gluon/main/assets/logo.png">
|
||||
<title>Gluworld</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>
|
||||
Gluon <code id="gluon_version"></code> <br>
|
||||
built with <code id="glugun_version"></code>
|
||||
</h1>
|
||||
|
||||
<div id="versions">
|
||||
<h2>
|
||||
Chromium <br>
|
||||
<code id="chromium_version"></code>
|
||||
</h2>
|
||||
|
||||
<h2>
|
||||
Node <br>
|
||||
<code id="node_version"></code>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=Roboto:ital,wght@0,400;0,700;1,500&display=swap'); */
|
||||
@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@300;400;500;600;700&family=Inter:wght@300;400;500;600;700;800;900');
|
||||
|
||||
html, body {
|
||||
background: #101418;
|
||||
color: #fff;
|
||||
font-family: Inter, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
width: 90%;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
h1, h2, code {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 900;
|
||||
font-size: 34px;
|
||||
}
|
||||
|
||||
h1 > code {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: 800;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 100%;
|
||||
font-family: Fira Code;
|
||||
}
|
||||
|
||||
#versions {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
width: 100%;
|
||||
|
||||
margin-top: 20vh;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
@ -1,22 +1,22 @@
|
||||
import * as Gluon from '../gluon/index.js';
|
||||
|
||||
import { fileURLToPath, pathToFileURL } from 'url';
|
||||
import { join, dirname } from 'path';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
Gluon.open(pathToFileURL(join(__dirname, 'index.html')).href, () => {
|
||||
const setVersions = () => {
|
||||
if (typeof chromium_version === 'undefined') return setTimeout(setVersions, 100);
|
||||
|
||||
chromium_version.textContent = CHROMIUM_VERSION;
|
||||
node_version.textContent = NODE_VERSION;
|
||||
gluon_version.textContent = GLUON_VERSION;
|
||||
glugun_version.textContent = 'GLUGUN_VERSION' === 'G\LUGUN_VERSION' ? 'nothing' : 'Glugun GLUGUN_VERSION';
|
||||
};
|
||||
|
||||
setVersions();
|
||||
}, {
|
||||
windowSize: [ 800, 450 ]
|
||||
import * as Gluon from '../gluon/index.js';
|
||||
|
||||
import { fileURLToPath, pathToFileURL } from 'url';
|
||||
import { join, dirname } from 'path';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
Gluon.open(pathToFileURL(join(__dirname, 'index.html')).href, () => {
|
||||
const setVersions = () => {
|
||||
if (typeof chromium_version === 'undefined') return setTimeout(setVersions, 100);
|
||||
|
||||
chromium_version.textContent = CHROMIUM_VERSION;
|
||||
node_version.textContent = NODE_VERSION;
|
||||
gluon_version.textContent = GLUON_VERSION;
|
||||
glugun_version.textContent = 'GLUGUN_VERSION' === 'G\LUGUN_VERSION' ? 'nothing' : 'Glugun GLUGUN_VERSION';
|
||||
};
|
||||
|
||||
setVersions();
|
||||
}, {
|
||||
windowSize: [ 800, 450 ]
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user