@@ -9,14 +9,88 @@ import 'dart:async';
9
9
import 'dart:convert' ;
10
10
import 'dart:html' ;
11
11
12
- import 'package:build_runner/src/server/hot_reload_client/reload_handler.dart' ;
13
-
14
12
import 'package:js/js.dart' ;
15
13
import 'package:js/js_util.dart' ;
16
14
15
+ import 'reload_handler.dart' ;
16
+ import 'reloading_manager.dart' ;
17
+
17
18
final _assetsDigestPath = r'$assetDigests' ;
18
19
final _buildUpdatesProtocol = r'$livereload' ;
19
20
21
+ @anonymous
22
+ @JS ()
23
+ abstract class HotReloadableModule {
24
+ /// Implement this function with any code to release resources before destroy.
25
+ ///
26
+ /// Any object returned from this function will be passed to update hooks. Use
27
+ /// it to save any state you need to be preserved between hot reloadings.
28
+ /// Try do not use any custom types here, as it might prevent their code from
29
+ /// reloading. Better serialise to JSON or plain types.
30
+ ///
31
+ /// This function will be called on old version of module before unloading.
32
+ @JS ()
33
+ external Object hot$onDestroy ();
34
+
35
+ /// Implement this function to handle update of the module itself.
36
+ ///
37
+ /// May return nullable bool. To indicate that reload completes successfully
38
+ /// return true. To indicate that hot-reload is undoable return false - this
39
+ /// will lead to full page reload. If null returned, reloading will be
40
+ /// propagated to parent.
41
+ ///
42
+ /// If any state was saved from previous version, it will be passed to [data] .
43
+ ///
44
+ /// This function will be called on new version of module after reloading.
45
+ @JS ()
46
+ external bool hot$onSelfUpdate ([Object data]);
47
+
48
+ /// Implement this function to handle update of child modules.
49
+ ///
50
+ /// May return nullable bool. To indicate that reload of child completes
51
+ /// successfully return true. To indicate that hot-reload is undoable for this
52
+ /// child return false - this will lead to full page reload. If null returned,
53
+ /// reloading will be propagated to current module itself.
54
+ ///
55
+ /// The name of the child will be provided in [childId] . New version of child
56
+ /// module object will be provided in [child] .
57
+ /// If any state was saved from previous version, it will be passed to [data] .
58
+ ///
59
+ /// This function will be called on old version of module current after child
60
+ /// reloading.
61
+ @JS ()
62
+ external bool hot$onChildUpdate (String childId, HotReloadableModule child,
63
+ [Object data]);
64
+ }
65
+
66
+ class ModuleWrapper implements Module {
67
+ final HotReloadableModule _internal;
68
+
69
+ ModuleWrapper (this ._internal);
70
+
71
+ @override
72
+ bool get hasOnDestroy =>
73
+ _internal != null && hasProperty (_internal, r'hot$onDestroy' );
74
+
75
+ @override
76
+ bool get hasOnSelfUpdate =>
77
+ _internal != null && hasProperty (_internal, r'hot$onSelfUpdate' );
78
+
79
+ @override
80
+ bool get hasOnChildUpdate =>
81
+ _internal != null && hasProperty (_internal, r'hot$onChildUpdate' );
82
+
83
+ @override
84
+ Object onDestroy () => _internal.hot$onDestroy ();
85
+
86
+ @override
87
+ bool onSelfUpdate ([Object data]) => _internal.hot$onSelfUpdate (data);
88
+
89
+ @override
90
+ bool onChildUpdate (String childId, Module child, [Object data]) => _internal
91
+ .hot$onChildUpdate (childId, (child as ModuleWrapper )._internal, data);
92
+ }
93
+
20
94
@JS ('Map' )
21
95
abstract class JsMap <K , V > {
22
96
@JS ()
@@ -32,42 +106,70 @@ class DartLoader {
32
106
@JS ()
33
107
external JsMap <String , String > get urlToModuleId;
34
108
109
+ @JS ()
110
+ external JsMap <String , List <String >> get moduleParentsGraph;
111
+
35
112
@JS ()
36
113
external void forceLoadModule (
37
- String moduleId, void Function (Object module) callback);
114
+ String moduleId, void Function (HotReloadableModule module) callback);
115
+
116
+ @JS ()
117
+ external void loadModule (
118
+ String moduleId, void Function (HotReloadableModule module) callback);
38
119
}
39
120
40
121
@JS (r'$dartLoader' )
41
122
external DartLoader get dartLoader;
42
123
43
124
@JS ('Array.from' )
44
- external List jsArrayFrom (Object any);
125
+ external List _jsArrayFrom (Object any);
45
126
46
- List <String > get _moduleUrls {
47
- return List .from (jsArrayFrom (dartLoader.urlToModuleId .keys ()));
127
+ List <K > keys < K , V >( JsMap < K , V > map) {
128
+ return List .from (_jsArrayFrom (map .keys ()));
48
129
}
49
130
50
- String _moduleIdByPath (String path) =>
51
- dartLoader.urlToModuleId.get (window.location.origin + '/' + path);
131
+ Future <Module > _reloadModule (String moduleId) {
132
+ var completer = Completer <Module >();
133
+ dartLoader.forceLoadModule (
134
+ moduleId,
135
+ allowInterop ((HotReloadableModule module) =>
136
+ completer.complete (ModuleWrapper (module))));
137
+ return completer.future;
138
+ }
52
139
53
- Future <Object > _reloadModule (String moduleId) {
54
- var completer = Completer <Object >();
55
- dartLoader.forceLoadModule (moduleId, allowInterop (completer.complete));
140
+ Future <Module > _loadModule (String moduleId) {
141
+ var completer = Completer <Module >();
142
+ dartLoader.loadModule (
143
+ moduleId,
144
+ allowInterop ((HotReloadableModule module) =>
145
+ completer.complete (ModuleWrapper (module))));
56
146
return completer.future;
57
147
}
58
148
149
+ void _reloadPage () {
150
+ window.location.reload ();
151
+ }
152
+
59
153
main () async {
60
- var modulePaths = _moduleUrls
61
- .map ((key) => key.replaceFirst (window.location.origin + '/' , '' ))
154
+ var currentOrigin = window.location.origin + '/' ;
155
+ var modulePaths = keys (dartLoader.urlToModuleId)
156
+ .map ((key) => key.replaceFirst (currentOrigin, '' ))
62
157
.toList ();
63
158
var modulePathsJson = json.encode (modulePaths);
64
159
65
160
var request = await HttpRequest .request ('/$_assetsDigestPath ' ,
66
161
responseType: 'json' , sendData: modulePathsJson, method: 'POST' );
67
162
var digests = (request.response as Map ).cast <String , String >();
68
163
69
- var handler = ReloadHandler (digests, _moduleIdByPath, _reloadModule,
70
- (module) => callMethod (getProperty (module, 'main' ), 'main' , []));
164
+ var manager = ReloadingManager (
165
+ _reloadModule,
166
+ _loadModule,
167
+ _reloadPage,
168
+ (module) => dartLoader.moduleParentsGraph.get (module),
169
+ () => keys (dartLoader.moduleParentsGraph));
170
+
171
+ var handler = ReloadHandler (digests,
172
+ (path) => dartLoader.urlToModuleId.get (currentOrigin + path), manager);
71
173
72
174
var webSocket =
73
175
WebSocket ('ws://' + window.location.host, [_buildUpdatesProtocol]);
0 commit comments