mirror of
https://github.com/Eugeny/tabby.git
synced 2025-07-20 02:18:01 +00:00
more electron/web separation
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { app, ipcMain, Menu, Tray, shell, screen, globalShortcut, MenuItemConstructorOptions } from 'electron'
|
||||
import * as promiseIpc from 'electron-promise-ipc'
|
||||
import * as remote from '@electron/remote/main'
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
|
||||
import { loadConfig } from './config'
|
||||
import { Window, WindowOptions } from './window'
|
||||
@@ -17,6 +19,7 @@ export class Application {
|
||||
private tray?: Tray
|
||||
private ptyManager = new PTYManager()
|
||||
private windows: Window[] = []
|
||||
userPluginsPath: string
|
||||
|
||||
constructor () {
|
||||
remote.initialize()
|
||||
@@ -36,12 +39,12 @@ export class Application {
|
||||
}
|
||||
})
|
||||
|
||||
;(promiseIpc as any).on('plugin-manager:install', (path, name, version) => {
|
||||
return pluginManager.install(path, name, version)
|
||||
;(promiseIpc as any).on('plugin-manager:install', (name, version) => {
|
||||
return pluginManager.install(this.userPluginsPath, name, version)
|
||||
})
|
||||
|
||||
;(promiseIpc as any).on('plugin-manager:uninstall', (path, name) => {
|
||||
return pluginManager.uninstall(path, name)
|
||||
;(promiseIpc as any).on('plugin-manager:uninstall', (name) => {
|
||||
return pluginManager.uninstall(this.userPluginsPath, name)
|
||||
})
|
||||
|
||||
const configData = loadConfig()
|
||||
@@ -53,6 +56,15 @@ export class Application {
|
||||
}
|
||||
}
|
||||
|
||||
this.userPluginsPath = path.join(
|
||||
app.getPath('userData'),
|
||||
'plugins',
|
||||
)
|
||||
|
||||
if (!fs.existsSync(this.userPluginsPath)) {
|
||||
fs.mkdirSync(this.userPluginsPath)
|
||||
}
|
||||
|
||||
app.commandLine.appendSwitch('disable-http-cache')
|
||||
app.commandLine.appendSwitch('max-active-webgl-contexts', '9000')
|
||||
app.commandLine.appendSwitch('lang', 'EN')
|
||||
@@ -70,7 +82,7 @@ export class Application {
|
||||
}
|
||||
|
||||
async newWindow (options?: WindowOptions): Promise<Window> {
|
||||
const window = new Window(options)
|
||||
const window = new Window(this, options)
|
||||
this.windows.push(window)
|
||||
window.visible$.subscribe(visible => {
|
||||
if (visible) {
|
||||
|
@@ -9,6 +9,7 @@ import * as path from 'path'
|
||||
import macOSRelease from 'macos-release'
|
||||
import * as compareVersions from 'compare-versions'
|
||||
|
||||
import type { Application } from './app'
|
||||
import { parseArgs } from './cli'
|
||||
import { loadConfig } from './config'
|
||||
|
||||
@@ -43,7 +44,7 @@ export class Window {
|
||||
get visible$ (): Observable<boolean> { return this.visible }
|
||||
get closed$ (): Observable<void> { return this.closed }
|
||||
|
||||
constructor (options?: WindowOptions) {
|
||||
constructor (private application: Application, options?: WindowOptions) {
|
||||
this.configStore = loadConfig()
|
||||
|
||||
options = options ?? {}
|
||||
@@ -299,16 +300,10 @@ export class Window {
|
||||
executable: app.getPath('exe'),
|
||||
windowID: this.window.id,
|
||||
isFirstWindow: this.window.id === 1,
|
||||
userPluginsPath: this.application.userPluginsPath,
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('window-focus', event => {
|
||||
if (!this.window || event.sender !== this.window.webContents) {
|
||||
return
|
||||
}
|
||||
this.window.focus()
|
||||
})
|
||||
|
||||
ipcMain.on('window-toggle-maximize', event => {
|
||||
if (!this.window || event.sender !== this.window.webContents) {
|
||||
return
|
||||
|
@@ -11,7 +11,7 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
|
||||
import { ipcRenderer } from 'electron'
|
||||
|
||||
import { getRootModule } from './app.module'
|
||||
import { findPlugins, loadPlugins, PluginInfo } from './plugins'
|
||||
import { findPlugins, initModuleLookup, loadPlugins } from './plugins'
|
||||
import { BootstrapData, BOOTSTRAP_DATA } from '../../terminus-core/src/api/mainProcess'
|
||||
|
||||
// Always land on the start view
|
||||
@@ -29,12 +29,12 @@ if (process.env.TERMINUS_DEV && !process.env.TERMINUS_FORCE_ANGULAR_PROD) {
|
||||
enableProdMode()
|
||||
}
|
||||
|
||||
async function bootstrap (plugins: PluginInfo[], bootstrapData: BootstrapData, safeMode = false): Promise<NgModuleRef<any>> {
|
||||
async function bootstrap (bootstrapData: BootstrapData, safeMode = false): Promise<NgModuleRef<any>> {
|
||||
if (safeMode) {
|
||||
plugins = plugins.filter(x => x.isBuiltin)
|
||||
bootstrapData.installedPlugins = bootstrapData.installedPlugins.filter(x => x.isBuiltin)
|
||||
}
|
||||
|
||||
const pluginModules = await loadPlugins(plugins, (current, total) => {
|
||||
const pluginModules = await loadPlugins(bootstrapData.installedPlugins, (current, total) => {
|
||||
(document.querySelector('.progress .bar') as HTMLElement).style.width = `${100 * current / total}%` // eslint-disable-line
|
||||
})
|
||||
const module = getRootModule(pluginModules)
|
||||
@@ -53,20 +53,24 @@ async function bootstrap (plugins: PluginInfo[], bootstrapData: BootstrapData, s
|
||||
ipcRenderer.once('start', async (_$event, bootstrapData: BootstrapData) => {
|
||||
console.log('Window bootstrap data:', bootstrapData)
|
||||
|
||||
initModuleLookup(bootstrapData.userPluginsPath)
|
||||
|
||||
let plugins = await findPlugins()
|
||||
if (bootstrapData.config.pluginBlacklist) {
|
||||
plugins = plugins.filter(x => !bootstrapData.config.pluginBlacklist.includes(x.name))
|
||||
}
|
||||
plugins = plugins.filter(x => x.name !== 'web')
|
||||
bootstrapData.installedPlugins = plugins
|
||||
|
||||
console.log('Starting with plugins:', plugins)
|
||||
try {
|
||||
await bootstrap(plugins, bootstrapData)
|
||||
await bootstrap(bootstrapData)
|
||||
} catch (error) {
|
||||
console.error('Angular bootstrapping error:', error)
|
||||
console.warn('Trying safe mode')
|
||||
window['safeModeReason'] = error
|
||||
try {
|
||||
await bootstrap(plugins, bootstrapData, true)
|
||||
await bootstrap(bootstrapData, true)
|
||||
} catch (error2) {
|
||||
console.error('Bootstrap failed:', error2)
|
||||
}
|
||||
|
@@ -1,8 +1,11 @@
|
||||
import * as fs from 'mz/fs'
|
||||
import * as path from 'path'
|
||||
import * as remote from '@electron/remote'
|
||||
import { PluginInfo } from '../../terminus-core/src/api/mainProcess'
|
||||
|
||||
const nodeModule = require('module') // eslint-disable-line @typescript-eslint/no-var-requires
|
||||
const nodeRequire = (global as any).require
|
||||
|
||||
const nodeRequire = global['require']
|
||||
|
||||
function normalizePath (p: string): string {
|
||||
const cygwinPrefix = '/cygdrive/'
|
||||
@@ -13,45 +16,8 @@ function normalizePath (p: string): string {
|
||||
return p
|
||||
}
|
||||
|
||||
global['module'].paths.map((x: string) => nodeModule.globalPaths.push(normalizePath(x)))
|
||||
|
||||
if (process.env.TERMINUS_DEV) {
|
||||
nodeModule.globalPaths.unshift(path.dirname(remote.app.getAppPath()))
|
||||
}
|
||||
|
||||
const builtinPluginsPath = process.env.TERMINUS_DEV ? path.dirname(remote.app.getAppPath()) : path.join((process as any).resourcesPath, 'builtin-plugins')
|
||||
|
||||
const userPluginsPath = path.join(
|
||||
remote.app.getPath('userData'),
|
||||
'plugins',
|
||||
)
|
||||
|
||||
if (!fs.existsSync(userPluginsPath)) {
|
||||
fs.mkdir(userPluginsPath)
|
||||
}
|
||||
|
||||
Object.assign(window, { builtinPluginsPath, userPluginsPath })
|
||||
nodeModule.globalPaths.unshift(builtinPluginsPath)
|
||||
nodeModule.globalPaths.unshift(path.join(userPluginsPath, 'node_modules'))
|
||||
// nodeModule.globalPaths.unshift(path.join((process as any).resourcesPath, 'app.asar', 'node_modules'))
|
||||
if (process.env.TERMINUS_PLUGINS) {
|
||||
process.env.TERMINUS_PLUGINS.split(':').map(x => nodeModule.globalPaths.push(normalizePath(x)))
|
||||
}
|
||||
|
||||
export type ProgressCallback = (current: number, total: number) => void // eslint-disable-line @typescript-eslint/no-type-alias
|
||||
|
||||
export interface PluginInfo {
|
||||
name: string
|
||||
description: string
|
||||
packageName: string
|
||||
isBuiltin: boolean
|
||||
version: string
|
||||
author: string
|
||||
homepage?: string
|
||||
path?: string
|
||||
info?: any
|
||||
}
|
||||
|
||||
const builtinModules = [
|
||||
'@angular/animations',
|
||||
'@angular/common',
|
||||
@@ -71,25 +37,42 @@ const builtinModules = [
|
||||
'zone.js/dist/zone.js',
|
||||
]
|
||||
|
||||
const cachedBuiltinModules = {}
|
||||
builtinModules.forEach(m => {
|
||||
cachedBuiltinModules[m] = nodeRequire(m)
|
||||
})
|
||||
export type ProgressCallback = (current: number, total: number) => void // eslint-disable-line @typescript-eslint/no-type-alias
|
||||
|
||||
const originalRequire = (global as any).require
|
||||
;(global as any).require = function (query: string) {
|
||||
if (cachedBuiltinModules[query]) {
|
||||
return cachedBuiltinModules[query]
|
||||
}
|
||||
return originalRequire.apply(this, [query])
|
||||
}
|
||||
export function initModuleLookup (userPluginsPath: string): void {
|
||||
global['module'].paths.map((x: string) => nodeModule.globalPaths.push(normalizePath(x)))
|
||||
|
||||
const originalModuleRequire = nodeModule.prototype.require
|
||||
nodeModule.prototype.require = function (query: string) {
|
||||
if (cachedBuiltinModules[query]) {
|
||||
return cachedBuiltinModules[query]
|
||||
if (process.env.TERMINUS_DEV) {
|
||||
nodeModule.globalPaths.unshift(path.dirname(remote.app.getAppPath()))
|
||||
}
|
||||
|
||||
nodeModule.globalPaths.unshift(builtinPluginsPath)
|
||||
nodeModule.globalPaths.unshift(path.join(userPluginsPath, 'node_modules'))
|
||||
// nodeModule.globalPaths.unshift(path.join((process as any).resourcesPath, 'app.asar', 'node_modules'))
|
||||
if (process.env.TERMINUS_PLUGINS) {
|
||||
process.env.TERMINUS_PLUGINS.split(':').map(x => nodeModule.globalPaths.push(normalizePath(x)))
|
||||
}
|
||||
|
||||
const cachedBuiltinModules = {}
|
||||
builtinModules.forEach(m => {
|
||||
cachedBuiltinModules[m] = nodeRequire(m)
|
||||
})
|
||||
|
||||
const originalRequire = (global as any).require
|
||||
;(global as any).require = function (query: string) {
|
||||
if (cachedBuiltinModules[query]) {
|
||||
return cachedBuiltinModules[query]
|
||||
}
|
||||
return originalRequire.apply(this, [query])
|
||||
}
|
||||
|
||||
const originalModuleRequire = nodeModule.prototype.require
|
||||
nodeModule.prototype.require = function (query: string) {
|
||||
if (cachedBuiltinModules[query]) {
|
||||
return cachedBuiltinModules[query]
|
||||
}
|
||||
return originalModuleRequire.call(this, query)
|
||||
}
|
||||
return originalModuleRequire.call(this, query)
|
||||
}
|
||||
|
||||
export async function findPlugins (): Promise<PluginInfo[]> {
|
||||
@@ -167,8 +150,6 @@ export async function findPlugins (): Promise<PluginInfo[]> {
|
||||
}
|
||||
|
||||
foundPlugins.sort((a, b) => a.name > b.name ? 1 : -1)
|
||||
|
||||
;(window as any).installedPlugins = foundPlugins
|
||||
return foundPlugins
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user