mirror of
https://github.com/rhysd/Mstdn.git
synced 2025-01-21 20:52:11 +01:00
load preload plugins after app gets idling
This commit is contained in:
parent
da55de25d1
commit
f8e7d64b08
@ -264,14 +264,14 @@ body {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Preload Plugin
|
## Preload Plugin (experimental)
|
||||||
|
|
||||||
You can make a Node.js package which is preloaded before loading inner mastodon page.
|
You can make a Node.js package which is preloaded before loading inner mastodon page.
|
||||||
|
|
||||||
Preload plugin is enabled if `chromium_sandbox` option is set to `false`. Please read above
|
Preload plugin is enabled if `chromium_sandbox` option is set to `false`. Please read above
|
||||||
configuration section before using any plugin.
|
configuration section before using any plugin.
|
||||||
|
|
||||||
### How to make
|
### How to make a plugin
|
||||||
|
|
||||||
Create `node_modules` directory in your application directory at first. And then, please make
|
Create `node_modules` directory in your application directory at first. And then, please make
|
||||||
`mstdn-preload-hello` directory. It consists a node package.
|
`mstdn-preload-hello` directory. It consists a node package.
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import {Config, Account} from '../main/config';
|
import {Config, Account} from '../main/config';
|
||||||
import * as Ipc from './ipc';
|
import * as Ipc from './ipc';
|
||||||
import setupKeymaps from './key_handler';
|
import setupKeymaps from './key_handler';
|
||||||
import loadPlugins from './plugins';
|
import PluginsLoader from './plugins';
|
||||||
import log from './log';
|
|
||||||
|
|
||||||
Ipc.on('mstdn:config', (c: Config, a: Account) => {
|
Ipc.on('mstdn:config', (c: Config, a: Account) => {
|
||||||
const plugins = loadPlugins(c, a);
|
const loader = new PluginsLoader(c, a);
|
||||||
log.info('Loaded plugins:', plugins);
|
loader.loadAfterAppPrepared();
|
||||||
setupKeymaps(c, a);
|
setupKeymaps(c, a);
|
||||||
document.title = `${document.title} @${a.name}@${a.host}`;
|
document.title = `${document.title} @${a.name}@${a.host}`;
|
||||||
});
|
});
|
||||||
|
@ -8,22 +8,72 @@ interface Plugins {
|
|||||||
[module_path: string]: Plugin;
|
[module_path: string]: Plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function loadPlugins(config: Config, account: Account): Plugins {
|
export default class PluginsLoader {
|
||||||
const ret = {} as Plugins;
|
preloads: Plugins;
|
||||||
|
loaded: boolean;
|
||||||
|
|
||||||
|
constructor(private config: Config, private account: Account) {
|
||||||
|
this.loaded = false;
|
||||||
|
this.preloads = {};
|
||||||
|
|
||||||
if (config.chromium_sandbox) {
|
if (config.chromium_sandbox) {
|
||||||
log.info('Chromium sandbox is enabled. Preload plugin is disabled.');
|
log.info('Chromium sandbox is enabled. Preload plugin is disabled.');
|
||||||
return ret;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const dir_base = path.join(config.__DATA_DIR!, 'node_modules');
|
const dir_base = path.join(config.__DATA_DIR!, 'node_modules');
|
||||||
for (const plugin of config.preload || []) {
|
for (const plugin of config.preload || []) {
|
||||||
const plugin_path = path.join(dir_base, `mstdn-preload-${plugin}`);
|
const plugin_path = path.join(dir_base, `mstdn-preload-${plugin}`);
|
||||||
try {
|
try {
|
||||||
const preloadFunc = r(plugin_path) as Plugin;
|
this.preloads[plugin_path] = r(plugin_path) as Plugin;
|
||||||
preloadFunc(config, account);
|
|
||||||
ret[plugin_path] = preloadFunc;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error(`Failed to load plugin ${plugin_path}:`, e);
|
log.error(`Failed to load plugin ${plugin_path}:`, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
}
|
||||||
|
|
||||||
|
loadAfterAppPrepared() {
|
||||||
|
if (Object.keys(this.preloads).length === 0) {
|
||||||
|
log.info('No preload plugin found. Skip loading');
|
||||||
|
this.loaded = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise<void>(resolve => {
|
||||||
|
// In order not to prevent application's initial loading, load preload plugins
|
||||||
|
// on an idle callback.
|
||||||
|
window.requestIdleCallback(() => {
|
||||||
|
log.debug('Start loading preload plugins', this.config, this.account);
|
||||||
|
if (this.tryLoading()) {
|
||||||
|
return resolve();
|
||||||
|
}
|
||||||
|
this.observeAppPrepared(this.tryLoading).then(resolve);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
observeAppPrepared(callback: () => void) {
|
||||||
|
// TODO:
|
||||||
|
// Make an instance of MutationObserver to observe React root.
|
||||||
|
return Promise.resolve(callback());
|
||||||
|
}
|
||||||
|
|
||||||
|
tryLoading = () => {
|
||||||
|
if (document.querySelector('[data-react-class="Mastodon"]') === null) {
|
||||||
|
log.info('Root element of react app was not found. App seems not to be loaded yet.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key in this.preloads) {
|
||||||
|
const f = this.preloads[key];
|
||||||
|
try {
|
||||||
|
f(this.config, this.account);
|
||||||
|
} catch (e) {
|
||||||
|
log.error(`Error while loading preload plugin '${key}':`, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info('Preload plugins were loaded:', this.preloads);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
9
typings/request-idle-callback.d.ts
vendored
Normal file
9
typings/request-idle-callback.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
interface RequestIdleCallback {
|
||||||
|
didTimeout?: boolean;
|
||||||
|
timeRemaining?: () => number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Window {
|
||||||
|
requestIdleCallback(cb: (deadline: RequestIdleCallback) => any): NodeJS.Timer;
|
||||||
|
cancelIdleCallback(id: NodeJS.Timer): void;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user