1
- const { Plugin, Notice} = require ( "obsidian" ) ;
1
+ const { Plugin, Notice, debounce } = require ( "obsidian" ) ;
2
2
const fs = require ( "fs" ) ;
3
3
4
4
const watchNeeded = window . process . platform !== "darwin" && window . process . platform !== "win32" ;
5
5
6
6
module . exports = class HotReload extends Plugin {
7
7
8
- onload ( ) { this . app . workspace . onLayoutReady ( this . _onload . bind ( this ) ) ; }
8
+ statCache = new Map ( ) ; // path -> Stat
9
+ queue = Promise . resolve ( ) ;
9
10
10
- async _onload ( ) {
11
- this . pluginReloaders = { } ;
12
- this . inProgress = null ;
13
- await this . getPluginNames ( ) ;
14
- this . reindexPlugins = this . debouncedMethod ( 500 , this . getPluginNames ) ;
15
- this . registerEvent ( this . app . vault . on ( "raw" , this . onFileChange . bind ( this ) ) ) ;
16
- this . watch ( ".obsidian/plugins" ) ;
11
+ run ( val , err ) {
12
+ return this . queue = this . queue . then ( val , err ) ;
13
+ }
14
+
15
+ reindexPlugins = debounce ( ( ) => this . run ( ( ) => this . getPluginNames ( ) ) , 500 , true ) ;
16
+ requestScan = debounce ( ( ) => this . run ( ( ) => this . checkVersions ( ) ) , 250 , true ) ;
17
+
18
+ onload ( ) {
19
+ app . workspace . onLayoutReady ( async ( ) => {
20
+ this . pluginReloaders = { } ;
21
+ this . inProgress = null ;
22
+ await this . getPluginNames ( ) ;
23
+ this . registerEvent ( this . app . vault . on ( "raw" , this . requestScan ) ) ;
24
+ this . watch ( ".obsidian/plugins" ) ;
25
+ this . requestScan ( ) ;
26
+ this . addCommand ( {
27
+ id : "scan-for-changes" ,
28
+ name : "Check plugins for changes and reload them" ,
29
+ callback : ( ) => this . requestScan ( )
30
+ } )
31
+ } ) ;
17
32
}
18
33
19
34
watch ( path ) {
@@ -25,6 +40,22 @@ module.exports = class HotReload extends Plugin {
25
40
}
26
41
}
27
42
43
+ async checkVersions ( ) {
44
+ const base = this . app . plugins . getPluginFolder ( ) ;
45
+ for ( const dir of Object . keys ( this . pluginNames ) ) {
46
+ for ( const file of [ "manifest.json" , "main.js" , "styles.css" , ".hotreload" ] ) {
47
+ const path = `${ base } /${ dir } /${ file } ` ;
48
+ const stat = await app . vault . adapter . stat ( path ) ;
49
+ if ( stat ) {
50
+ if ( this . statCache . has ( path ) && stat . mtime !== this . statCache . get ( path ) . mtime ) {
51
+ this . onFileChange ( path ) ;
52
+ }
53
+ this . statCache . set ( path , stat ) ;
54
+ }
55
+ }
56
+ }
57
+ }
58
+
28
59
async getPluginNames ( ) {
29
60
const plugins = { } , enabled = new Set ( ) ;
30
61
for ( const { id, dir} of Object . values ( app . plugins . manifests ) ) {
@@ -50,34 +81,30 @@ module.exports = class HotReload extends Plugin {
50
81
if ( base !== "main.js" && base !== "styles.css" ) return ;
51
82
if ( ! this . enabledPlugins . has ( plugin ) ) return ;
52
83
const reloader = this . pluginReloaders [ plugin ] || (
53
- this . pluginReloaders [ plugin ] = this . debouncedMethod ( 750 , this . requestReload , plugin )
84
+ this . pluginReloaders [ plugin ] = debounce ( ( ) => this . run ( ( ) => this . reload ( plugin ) , console . error ) , 750 , true )
54
85
) ;
55
86
reloader ( ) ;
56
87
}
57
88
58
- requestReload ( plugin ) {
59
- const next = this . inProgress = this . reload ( plugin , this . inProgress ) ;
60
- next . finally ( ( ) => { if ( this . inProgress === next ) this . inProgress = null ; } )
61
- }
89
+ async reload ( plugin ) {
90
+ const plugins = app . plugins ;
91
+
92
+ // Don't reload disabled plugins
93
+ if ( ! plugins . enabledPlugins . has ( plugin ) ) return ;
94
+
95
+ await plugins . disablePlugin ( plugin ) ;
96
+ console . debug ( "disabled" , plugin ) ;
62
97
63
- async reload ( plugin , previous ) {
64
- const plugins = this . app . plugins ;
98
+ // Ensure sourcemaps are loaded (Obsidian 14+)
99
+ const oldDebug = localStorage . getItem ( "debug-plugin" ) ;
100
+ localStorage . setItem ( "debug-plugin" , "1" ) ;
65
101
try {
66
- // Wait for any other queued/in-progress reloads to finish
67
- await previous ;
68
- await plugins . disablePlugin ( plugin ) ;
69
- console . debug ( "disabled" , plugin ) ;
70
102
await plugins . enablePlugin ( plugin ) ;
71
- console . debug ( "enabled" , plugin ) ;
72
- new Notice ( `Plugin "${ plugin } " has been reloaded` ) ;
73
- } catch ( e ) { }
74
- }
75
-
76
- debouncedMethod ( ms , func , ...args ) {
77
- var timeout ;
78
- return ( ) => {
79
- if ( timeout ) clearTimeout ( timeout ) ;
80
- timeout = setTimeout ( ( ) => { timeout = null ; func . apply ( this , args ) ; } , ms ) ;
103
+ } finally {
104
+ // Restore previous setting
105
+ if ( oldDebug === null ) localStorage . removeItem ( "debug-plugin" ) ; else localStorage . setItem ( "debug-plugin" , oldDebug ) ;
81
106
}
107
+ console . debug ( "enabled" , plugin ) ;
108
+ new Notice ( `Plugin "${ plugin } " has been reloaded` ) ;
82
109
}
83
- }
110
+ }
0 commit comments