Skip to content

Commit a16cf81

Browse files
committed
Hot-reload on adding/removing assets files.
1 parent b97f6c9 commit a16cf81

File tree

2 files changed

+56
-14
lines changed

2 files changed

+56
-14
lines changed

dash/_watch.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,27 @@ def watch(folders, on_change, pattern=None, sleep_time=0.1):
99
watched = collections.defaultdict(lambda: -1)
1010

1111
def walk():
12+
walked = []
1213
for folder in folders:
1314
for current, _, files, in os.walk(folder):
1415
for f in files:
1516
if pattern and not pattern.search(f):
1617
continue
1718
path = os.path.join(current, f)
19+
1820
info = os.stat(path)
1921
new_time = info.st_mtime
22+
2023
if new_time > watched[path] > 0:
21-
on_change(path)
24+
on_change(path, new_time, False)
25+
2226
watched[path] = new_time
27+
walked.append(path)
28+
29+
# Look for deleted files
30+
for w in (x for x in watched.keys() if x not in walked):
31+
del watched[w]
32+
on_change(w, -1, True)
2333

2434
while True:
2535
walk()

dash/dash.py

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ def add_url(name, view_func, methods=('GET',)):
226226
self._cached_layout = None
227227
self.routes = []
228228

229+
self._assets_files = []
230+
229231
# hot reload
230232
self._reload_hash = _generate_hash() \
231233
if hot_reload else ''
@@ -942,19 +944,20 @@ def _setup_server(self):
942944
self._generate_scripts_html()
943945
self._generate_css_dist_html()
944946

947+
def _add_assets_resource(self, url_path, file_path):
948+
res = {'asset_path': url_path, 'filepath': file_path}
949+
if self.config.assets_external_path:
950+
res['external_url'] = '{}{}'.format(
951+
self.config.assets_external_path, url_path)
952+
self._assets_files.append(file_path)
953+
return res
954+
945955
def _walk_assets_directory(self):
946956
walk_dir = self._assets_folder
947957
slash_splitter = re.compile(r'[\\/]+')
948958
ignore_filter = re.compile(self.assets_ignore) \
949959
if self.assets_ignore else None
950960

951-
def add_resource(p, filepath):
952-
res = {'asset_path': p, 'filepath': filepath}
953-
if self.config.assets_external_path:
954-
res['external_url'] = '{}{}'.format(
955-
self.config.assets_external_path, path)
956-
return res
957-
958961
for current, _, files in os.walk(walk_dir):
959962
if current == walk_dir:
960963
base = ''
@@ -979,9 +982,9 @@ def add_resource(p, filepath):
979982

980983
if f.endswith('js'):
981984
self.scripts.append_script(
982-
add_resource(path, full))
985+
self._add_assets_resource(path, full))
983986
elif f.endswith('css'):
984-
self.css.append_css(add_resource(path, full))
987+
self.css.append_css(self._add_assets_resource(path, full))
985988
elif f == 'favicon.ico':
986989
self._favicon = path
987990

@@ -995,12 +998,41 @@ def get_asset_url(self, path):
995998

996999
return asset
9971000

998-
def _on_assets_change(self, _):
999-
# The `_` argument is the name of the file that changed.
1000-
# If we ever setup a logging system, we could use the parameter.
1001+
# noinspection PyProtectedMember
1002+
def _on_assets_change(self, filename, _, deleted):
1003+
# The `_` argument is the time modified, to be used later.
10011004
self._lock.acquire()
1002-
self._hard_reload = True
1005+
self._hard_reload = True # filename.endswith('js')
10031006
self._reload_hash = _generate_hash()
1007+
1008+
asset_path = filename.replace(self._assets_folder, '')\
1009+
.replace('\\', '/').lstrip('/')
1010+
1011+
if filename not in self._assets_files and not deleted:
1012+
res = self._add_assets_resource(asset_path, filename)
1013+
if filename.endswith('js'):
1014+
self.scripts.append_script(res)
1015+
elif filename.endswith('css'):
1016+
self.css.append_css(res)
1017+
1018+
if deleted:
1019+
if filename in self._assets_files:
1020+
self._assets_files.remove(filename)
1021+
1022+
def delete_resource(resources):
1023+
to_delete = None
1024+
for r in resources:
1025+
if r.get('asset_path') == asset_path:
1026+
to_delete = r
1027+
break
1028+
if to_delete:
1029+
resources.remove(to_delete)
1030+
1031+
if filename.endswith('js'):
1032+
delete_resource(self.scripts._resources._resources)
1033+
elif filename.endswith('css'):
1034+
delete_resource(self.css._resources._resources)
1035+
10041036
self._lock.release()
10051037

10061038
def run_server(self,

0 commit comments

Comments
 (0)