Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Hot reload - #73

Merged
T4rk1n merged 22 commits into
masterfrom
hot-reload
Nov 14, 2018
Merged

Hot reload#73
T4rk1n merged 22 commits into
masterfrom
hot-reload

Conversation

@T4rk1n

@T4rk1nT4rk1n commented Aug 31, 2018

Copy link
Copy Markdown
Contributor

Available with the following version:

  • dash==0.27.0rc7
  • dash-renderer==0.14.0rc6

Add hot-reload capability on project file changes by periodically requesting a hash and checking it's the same hash as the initial one.

Adds:

  • Reloader component
  • reloadRequest api thunk.

Need plotly/dash#362

@T4rk1nT4rk1n mentioned this pull request Aug 31, 2018
@T4rk1nT4rk1n changed the title [WIP] Hot reloadHot reloadSep 6, 2018
@T4rk1n

Copy link
Copy Markdown
ContributorAuthor

@plotly/dash Ready for review!

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! There's two questions I had, and two newlines missing

}),
dispatch => ({dispatch})
)(Reloader);

No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline

Comment threadsrc/actions/api.js Outdated
if (!disabled && !this._intervalId) {
this._intervalId = setInterval(() => {
if (!this.state.reloading) {
dispatch(getReloadHash());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should state.reloading be set to true here? I do not see anywhere that state.reloading is changed, it seems to always be false.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a leftover from something I tried, I will remove thanks.

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I there extra stuff in state that is stripped when you do this? I don't see what these two lines do, I don't think state is changed here

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything but the history is stripped down, it triggers a soft reload.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh okay so everything else gets set to default except the history, looks good

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

@valentijnniemanvalentijnnieman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left you a couple of questions!

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

}
if (reloadHash.content.reloadHash !== this.state.hash) {
// eslint-disable-next-line no-undef
window.clearInterval(this._intervalId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the no-undef rule here should not trigger if it's sure that this._intervalId is set, right? Maybe it's better to write a check here that makes sure that it's not null, instead of disabling the rule.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The no-undef is for window, it highlight as error in pycharm.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rootReducer is for soft-reload, it destroy the state of the store and then the other reducers can reload the application. I think it's cleaner to keep it separate as the logic for the historyReducer come after and they do different operations.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok! Hmm maybe that rule can be turned off globally then, if it's always going to trigger on window?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last question: isn't it maybe better to put the rootReducer in a separate file, and call it something else, like reloadReducer or whatever?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe that rule can be turned off globally then

I think we can put window in a global exclude or something. Anyway it underline as error in IDE, I just hit alt-enter and select a fix, doesn't take more than a second.

Last question: isn't it maybe better to put the rootReducer in a separate file

It's only a couple lines and is the last reducer exported, keeping it in reducer make more sense to me.

if (reloadHash.content.hard) {
// Assets file have changed, need to reload them.
// eslint-disable-next-line no-undef
window.top.location.reload();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, why is the no-undef rule triggering here?

Comment threadsrc/reducers/reducer.js Outdated
dependenciesRequest: API.dependenciesRequest,
layoutRequest: API.layoutRequest,
loginRequest: API.loginRequest,
reloadHash: API.reloadRequest,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why it's named reloadHash here and reloadRequest on API.reloadRequest?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I refactored reloadHash to reloadRequest to conform to the other API, I guess that one didn't follow up.

disabled: true
}
}
this._intervalId = null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can _intervalId not be in state as well?

hash: null,
interval,
disabled: false
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if this state is also handled in a reducer? Would there be value in having this state in the store? Perhaps saving the hash in the store for example would make it easier to at some point in the future to enable the store to be saved client-side, so that it can be rehydrated upon refreshing.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hash is null at first, it is set in the state from the server on the first hash request so I don't think it needs to be rehydrated.

@T4rk1n
T4rk1nforce-pushed the hot-reload branch 2 times, most recently from 9c9c797 to 232b6a4CompareSeptember 13, 2018 17:25

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few minor style changes 💃

Comment thread.gitignore

*.csv
.idea/
.vscode

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

disabled: false,
intervalId: null,
packages: null,
max_retry: max_retry,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just max_retry

);
let node = it.iterateNext();

while (node) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is node a proper iterator? You should be able to do const nodesToDisable = [...it.iterateNext()]

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a proper iterator but it doesn't work, if there's no element found (asset file added) it will fail to make an array with the iterator.

nodesToDisable.push(node);
node = it.iterateNext();
}
nodesToDisable.forEach(n =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we are trying to use ramda 🐏 in this repo even when a core library function would do the job. I think R.forEach would do the job.

} else if (reloadRequest.status === 500) {
if (this._retry > this.state.max_retry) {
window.clearInterval(this.state.intervalId);
// Integrate with dev tools ui?!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@T4rk1n@valentijnnieman@rmarren1
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Hot reload by T4rk1n · Pull Request #73 · plotly/dash-renderer · GitHub
Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Hot reload - #73

Merged
T4rk1n merged 22 commits into
masterfrom
hot-reload
Nov 14, 2018
Merged

Hot reload#73
T4rk1n merged 22 commits into
masterfrom
hot-reload

Conversation

@T4rk1n

@T4rk1nT4rk1n commented Aug 31, 2018

Copy link
Copy Markdown
Contributor

Available with the following version:

  • dash==0.27.0rc7
  • dash-renderer==0.14.0rc6

Add hot-reload capability on project file changes by periodically requesting a hash and checking it's the same hash as the initial one.

Adds:

  • Reloader component
  • reloadRequest api thunk.

Need plotly/dash#362

@T4rk1nT4rk1n mentioned this pull request Aug 31, 2018
@T4rk1nT4rk1n changed the title [WIP] Hot reloadHot reloadSep 6, 2018
@T4rk1n

Copy link
Copy Markdown
ContributorAuthor

@plotly/dash Ready for review!

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! There's two questions I had, and two newlines missing

}),
dispatch => ({dispatch})
)(Reloader);

No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline

Comment threadsrc/actions/api.js Outdated
if (!disabled && !this._intervalId) {
this._intervalId = setInterval(() => {
if (!this.state.reloading) {
dispatch(getReloadHash());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should state.reloading be set to true here? I do not see anywhere that state.reloading is changed, it seems to always be false.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a leftover from something I tried, I will remove thanks.

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I there extra stuff in state that is stripped when you do this? I don't see what these two lines do, I don't think state is changed here

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything but the history is stripped down, it triggers a soft reload.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh okay so everything else gets set to default except the history, looks good

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

@valentijnniemanvalentijnnieman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left you a couple of questions!

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

}
if (reloadHash.content.reloadHash !== this.state.hash) {
// eslint-disable-next-line no-undef
window.clearInterval(this._intervalId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the no-undef rule here should not trigger if it's sure that this._intervalId is set, right? Maybe it's better to write a check here that makes sure that it's not null, instead of disabling the rule.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The no-undef is for window, it highlight as error in pycharm.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rootReducer is for soft-reload, it destroy the state of the store and then the other reducers can reload the application. I think it's cleaner to keep it separate as the logic for the historyReducer come after and they do different operations.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok! Hmm maybe that rule can be turned off globally then, if it's always going to trigger on window?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last question: isn't it maybe better to put the rootReducer in a separate file, and call it something else, like reloadReducer or whatever?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe that rule can be turned off globally then

I think we can put window in a global exclude or something. Anyway it underline as error in IDE, I just hit alt-enter and select a fix, doesn't take more than a second.

Last question: isn't it maybe better to put the rootReducer in a separate file

It's only a couple lines and is the last reducer exported, keeping it in reducer make more sense to me.

if (reloadHash.content.hard) {
// Assets file have changed, need to reload them.
// eslint-disable-next-line no-undef
window.top.location.reload();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, why is the no-undef rule triggering here?

Comment threadsrc/reducers/reducer.js Outdated
dependenciesRequest: API.dependenciesRequest,
layoutRequest: API.layoutRequest,
loginRequest: API.loginRequest,
reloadHash: API.reloadRequest,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why it's named reloadHash here and reloadRequest on API.reloadRequest?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I refactored reloadHash to reloadRequest to conform to the other API, I guess that one didn't follow up.

disabled: true
}
}
this._intervalId = null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can _intervalId not be in state as well?

hash: null,
interval,
disabled: false
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if this state is also handled in a reducer? Would there be value in having this state in the store? Perhaps saving the hash in the store for example would make it easier to at some point in the future to enable the store to be saved client-side, so that it can be rehydrated upon refreshing.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hash is null at first, it is set in the state from the server on the first hash request so I don't think it needs to be rehydrated.

@T4rk1n
T4rk1nforce-pushed the hot-reload branch 2 times, most recently from 9c9c797 to 232b6a4CompareSeptember 13, 2018 17:25

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few minor style changes 💃

Comment thread.gitignore

*.csv
.idea/
.vscode

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

disabled: false,
intervalId: null,
packages: null,
max_retry: max_retry,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just max_retry

);
let node = it.iterateNext();

while (node) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is node a proper iterator? You should be able to do const nodesToDisable = [...it.iterateNext()]

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a proper iterator but it doesn't work, if there's no element found (asset file added) it will fail to make an array with the iterator.

nodesToDisable.push(node);
node = it.iterateNext();
}
nodesToDisable.forEach(n =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we are trying to use ramda 🐏 in this repo even when a core library function would do the job. I think R.forEach would do the job.

} else if (reloadRequest.status === 500) {
if (this._retry > this.state.max_retry) {
window.clearInterval(this.state.intervalId);
// Integrate with dev tools ui?!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@T4rk1n@valentijnnieman@rmarren1
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Hot reload by T4rk1n · Pull Request #73 · plotly/dash-renderer · GitHub
Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Hot reload - #73

Merged
T4rk1n merged 22 commits into
masterfrom
hot-reload
Nov 14, 2018
Merged

Hot reload#73
T4rk1n merged 22 commits into
masterfrom
hot-reload

Conversation

@T4rk1n

@T4rk1nT4rk1n commented Aug 31, 2018

Copy link
Copy Markdown
Contributor

Available with the following version:

  • dash==0.27.0rc7
  • dash-renderer==0.14.0rc6

Add hot-reload capability on project file changes by periodically requesting a hash and checking it's the same hash as the initial one.

Adds:

  • Reloader component
  • reloadRequest api thunk.

Need plotly/dash#362

@T4rk1nT4rk1n mentioned this pull request Aug 31, 2018
@T4rk1nT4rk1n changed the title [WIP] Hot reloadHot reloadSep 6, 2018
@T4rk1n

Copy link
Copy Markdown
ContributorAuthor

@plotly/dash Ready for review!

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! There's two questions I had, and two newlines missing

}),
dispatch => ({dispatch})
)(Reloader);

No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline

Comment threadsrc/actions/api.js Outdated
if (!disabled && !this._intervalId) {
this._intervalId = setInterval(() => {
if (!this.state.reloading) {
dispatch(getReloadHash());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should state.reloading be set to true here? I do not see anywhere that state.reloading is changed, it seems to always be false.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a leftover from something I tried, I will remove thanks.

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I there extra stuff in state that is stripped when you do this? I don't see what these two lines do, I don't think state is changed here

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything but the history is stripped down, it triggers a soft reload.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh okay so everything else gets set to default except the history, looks good

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

@valentijnniemanvalentijnnieman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left you a couple of questions!

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

}
if (reloadHash.content.reloadHash !== this.state.hash) {
// eslint-disable-next-line no-undef
window.clearInterval(this._intervalId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the no-undef rule here should not trigger if it's sure that this._intervalId is set, right? Maybe it's better to write a check here that makes sure that it's not null, instead of disabling the rule.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The no-undef is for window, it highlight as error in pycharm.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rootReducer is for soft-reload, it destroy the state of the store and then the other reducers can reload the application. I think it's cleaner to keep it separate as the logic for the historyReducer come after and they do different operations.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok! Hmm maybe that rule can be turned off globally then, if it's always going to trigger on window?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last question: isn't it maybe better to put the rootReducer in a separate file, and call it something else, like reloadReducer or whatever?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe that rule can be turned off globally then

I think we can put window in a global exclude or something. Anyway it underline as error in IDE, I just hit alt-enter and select a fix, doesn't take more than a second.

Last question: isn't it maybe better to put the rootReducer in a separate file

It's only a couple lines and is the last reducer exported, keeping it in reducer make more sense to me.

if (reloadHash.content.hard) {
// Assets file have changed, need to reload them.
// eslint-disable-next-line no-undef
window.top.location.reload();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, why is the no-undef rule triggering here?

Comment threadsrc/reducers/reducer.js Outdated
dependenciesRequest: API.dependenciesRequest,
layoutRequest: API.layoutRequest,
loginRequest: API.loginRequest,
reloadHash: API.reloadRequest,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why it's named reloadHash here and reloadRequest on API.reloadRequest?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I refactored reloadHash to reloadRequest to conform to the other API, I guess that one didn't follow up.

disabled: true
}
}
this._intervalId = null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can _intervalId not be in state as well?

hash: null,
interval,
disabled: false
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if this state is also handled in a reducer? Would there be value in having this state in the store? Perhaps saving the hash in the store for example would make it easier to at some point in the future to enable the store to be saved client-side, so that it can be rehydrated upon refreshing.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hash is null at first, it is set in the state from the server on the first hash request so I don't think it needs to be rehydrated.

@T4rk1n
T4rk1nforce-pushed the hot-reload branch 2 times, most recently from 9c9c797 to 232b6a4CompareSeptember 13, 2018 17:25

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few minor style changes 💃

Comment thread.gitignore

*.csv
.idea/
.vscode

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

disabled: false,
intervalId: null,
packages: null,
max_retry: max_retry,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just max_retry

);
let node = it.iterateNext();

while (node) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is node a proper iterator? You should be able to do const nodesToDisable = [...it.iterateNext()]

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a proper iterator but it doesn't work, if there's no element found (asset file added) it will fail to make an array with the iterator.

nodesToDisable.push(node);
node = it.iterateNext();
}
nodesToDisable.forEach(n =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we are trying to use ramda 🐏 in this repo even when a core library function would do the job. I think R.forEach would do the job.

} else if (reloadRequest.status === 500) {
if (this._retry > this.state.max_retry) {
window.clearInterval(this.state.intervalId);
// Integrate with dev tools ui?!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@T4rk1n@valentijnnieman@rmarren1
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Hot reload by T4rk1n · Pull Request #73 · plotly/dash-renderer · GitHub
Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Hot reload - #73

Merged
T4rk1n merged 22 commits into
masterfrom
hot-reload
Nov 14, 2018
Merged

Hot reload#73
T4rk1n merged 22 commits into
masterfrom
hot-reload

Conversation

@T4rk1n

@T4rk1nT4rk1n commented Aug 31, 2018

Copy link
Copy Markdown
Contributor

Available with the following version:

  • dash==0.27.0rc7
  • dash-renderer==0.14.0rc6

Add hot-reload capability on project file changes by periodically requesting a hash and checking it's the same hash as the initial one.

Adds:

  • Reloader component
  • reloadRequest api thunk.

Need plotly/dash#362

@T4rk1nT4rk1n mentioned this pull request Aug 31, 2018
@T4rk1nT4rk1n changed the title [WIP] Hot reloadHot reloadSep 6, 2018
@T4rk1n

Copy link
Copy Markdown
ContributorAuthor

@plotly/dash Ready for review!

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! There's two questions I had, and two newlines missing

}),
dispatch => ({dispatch})
)(Reloader);

No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline

Comment threadsrc/actions/api.js Outdated
if (!disabled && !this._intervalId) {
this._intervalId = setInterval(() => {
if (!this.state.reloading) {
dispatch(getReloadHash());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should state.reloading be set to true here? I do not see anywhere that state.reloading is changed, it seems to always be false.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a leftover from something I tried, I will remove thanks.

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I there extra stuff in state that is stripped when you do this? I don't see what these two lines do, I don't think state is changed here

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything but the history is stripped down, it triggers a soft reload.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh okay so everything else gets set to default except the history, looks good

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

@valentijnniemanvalentijnnieman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left you a couple of questions!

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

}
if (reloadHash.content.reloadHash !== this.state.hash) {
// eslint-disable-next-line no-undef
window.clearInterval(this._intervalId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the no-undef rule here should not trigger if it's sure that this._intervalId is set, right? Maybe it's better to write a check here that makes sure that it's not null, instead of disabling the rule.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The no-undef is for window, it highlight as error in pycharm.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rootReducer is for soft-reload, it destroy the state of the store and then the other reducers can reload the application. I think it's cleaner to keep it separate as the logic for the historyReducer come after and they do different operations.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok! Hmm maybe that rule can be turned off globally then, if it's always going to trigger on window?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last question: isn't it maybe better to put the rootReducer in a separate file, and call it something else, like reloadReducer or whatever?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe that rule can be turned off globally then

I think we can put window in a global exclude or something. Anyway it underline as error in IDE, I just hit alt-enter and select a fix, doesn't take more than a second.

Last question: isn't it maybe better to put the rootReducer in a separate file

It's only a couple lines and is the last reducer exported, keeping it in reducer make more sense to me.

if (reloadHash.content.hard) {
// Assets file have changed, need to reload them.
// eslint-disable-next-line no-undef
window.top.location.reload();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, why is the no-undef rule triggering here?

Comment threadsrc/reducers/reducer.js Outdated
dependenciesRequest: API.dependenciesRequest,
layoutRequest: API.layoutRequest,
loginRequest: API.loginRequest,
reloadHash: API.reloadRequest,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why it's named reloadHash here and reloadRequest on API.reloadRequest?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I refactored reloadHash to reloadRequest to conform to the other API, I guess that one didn't follow up.

disabled: true
}
}
this._intervalId = null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can _intervalId not be in state as well?

hash: null,
interval,
disabled: false
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if this state is also handled in a reducer? Would there be value in having this state in the store? Perhaps saving the hash in the store for example would make it easier to at some point in the future to enable the store to be saved client-side, so that it can be rehydrated upon refreshing.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hash is null at first, it is set in the state from the server on the first hash request so I don't think it needs to be rehydrated.

@T4rk1n
T4rk1nforce-pushed the hot-reload branch 2 times, most recently from 9c9c797 to 232b6a4CompareSeptember 13, 2018 17:25

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few minor style changes 💃

Comment thread.gitignore

*.csv
.idea/
.vscode

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

disabled: false,
intervalId: null,
packages: null,
max_retry: max_retry,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just max_retry

);
let node = it.iterateNext();

while (node) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is node a proper iterator? You should be able to do const nodesToDisable = [...it.iterateNext()]

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a proper iterator but it doesn't work, if there's no element found (asset file added) it will fail to make an array with the iterator.

nodesToDisable.push(node);
node = it.iterateNext();
}
nodesToDisable.forEach(n =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we are trying to use ramda 🐏 in this repo even when a core library function would do the job. I think R.forEach would do the job.

} else if (reloadRequest.status === 500) {
if (this._retry > this.state.max_retry) {
window.clearInterval(this.state.intervalId);
// Integrate with dev tools ui?!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@T4rk1n@valentijnnieman@rmarren1
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Hot reload by T4rk1n · Pull Request #73 · plotly/dash-renderer · GitHub
Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Hot reload - #73

Merged
T4rk1n merged 22 commits into
masterfrom
hot-reload
Nov 14, 2018
Merged

Hot reload#73
T4rk1n merged 22 commits into
masterfrom
hot-reload

Conversation

@T4rk1n

@T4rk1nT4rk1n commented Aug 31, 2018

Copy link
Copy Markdown
Contributor

Available with the following version:

  • dash==0.27.0rc7
  • dash-renderer==0.14.0rc6

Add hot-reload capability on project file changes by periodically requesting a hash and checking it's the same hash as the initial one.

Adds:

  • Reloader component
  • reloadRequest api thunk.

Need plotly/dash#362

@T4rk1nT4rk1n mentioned this pull request Aug 31, 2018
@T4rk1nT4rk1n changed the title [WIP] Hot reloadHot reloadSep 6, 2018
@T4rk1n

Copy link
Copy Markdown
ContributorAuthor

@plotly/dash Ready for review!

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! There's two questions I had, and two newlines missing

}),
dispatch => ({dispatch})
)(Reloader);

No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline

Comment threadsrc/actions/api.js Outdated
if (!disabled && !this._intervalId) {
this._intervalId = setInterval(() => {
if (!this.state.reloading) {
dispatch(getReloadHash());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should state.reloading be set to true here? I do not see anywhere that state.reloading is changed, it seems to always be false.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a leftover from something I tried, I will remove thanks.

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I there extra stuff in state that is stripped when you do this? I don't see what these two lines do, I don't think state is changed here

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything but the history is stripped down, it triggers a soft reload.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh okay so everything else gets set to default except the history, looks good

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

@valentijnniemanvalentijnnieman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left you a couple of questions!

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

}
if (reloadHash.content.reloadHash !== this.state.hash) {
// eslint-disable-next-line no-undef
window.clearInterval(this._intervalId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the no-undef rule here should not trigger if it's sure that this._intervalId is set, right? Maybe it's better to write a check here that makes sure that it's not null, instead of disabling the rule.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The no-undef is for window, it highlight as error in pycharm.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rootReducer is for soft-reload, it destroy the state of the store and then the other reducers can reload the application. I think it's cleaner to keep it separate as the logic for the historyReducer come after and they do different operations.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok! Hmm maybe that rule can be turned off globally then, if it's always going to trigger on window?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last question: isn't it maybe better to put the rootReducer in a separate file, and call it something else, like reloadReducer or whatever?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe that rule can be turned off globally then

I think we can put window in a global exclude or something. Anyway it underline as error in IDE, I just hit alt-enter and select a fix, doesn't take more than a second.

Last question: isn't it maybe better to put the rootReducer in a separate file

It's only a couple lines and is the last reducer exported, keeping it in reducer make more sense to me.

if (reloadHash.content.hard) {
// Assets file have changed, need to reload them.
// eslint-disable-next-line no-undef
window.top.location.reload();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, why is the no-undef rule triggering here?

Comment threadsrc/reducers/reducer.js Outdated
dependenciesRequest: API.dependenciesRequest,
layoutRequest: API.layoutRequest,
loginRequest: API.loginRequest,
reloadHash: API.reloadRequest,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why it's named reloadHash here and reloadRequest on API.reloadRequest?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I refactored reloadHash to reloadRequest to conform to the other API, I guess that one didn't follow up.

disabled: true
}
}
this._intervalId = null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can _intervalId not be in state as well?

hash: null,
interval,
disabled: false
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if this state is also handled in a reducer? Would there be value in having this state in the store? Perhaps saving the hash in the store for example would make it easier to at some point in the future to enable the store to be saved client-side, so that it can be rehydrated upon refreshing.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hash is null at first, it is set in the state from the server on the first hash request so I don't think it needs to be rehydrated.

@T4rk1n
T4rk1nforce-pushed the hot-reload branch 2 times, most recently from 9c9c797 to 232b6a4CompareSeptember 13, 2018 17:25

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few minor style changes 💃

Comment thread.gitignore

*.csv
.idea/
.vscode

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

disabled: false,
intervalId: null,
packages: null,
max_retry: max_retry,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just max_retry

);
let node = it.iterateNext();

while (node) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is node a proper iterator? You should be able to do const nodesToDisable = [...it.iterateNext()]

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a proper iterator but it doesn't work, if there's no element found (asset file added) it will fail to make an array with the iterator.

nodesToDisable.push(node);
node = it.iterateNext();
}
nodesToDisable.forEach(n =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we are trying to use ramda 🐏 in this repo even when a core library function would do the job. I think R.forEach would do the job.

} else if (reloadRequest.status === 500) {
if (this._retry > this.state.max_retry) {
window.clearInterval(this.state.intervalId);
// Integrate with dev tools ui?!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@T4rk1n@valentijnnieman@rmarren1
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Hot reload by T4rk1n · Pull Request #73 · plotly/dash-renderer · GitHub
Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Hot reload - #73

Merged
T4rk1n merged 22 commits into
masterfrom
hot-reload
Nov 14, 2018
Merged

Hot reload#73
T4rk1n merged 22 commits into
masterfrom
hot-reload

Conversation

@T4rk1n

@T4rk1nT4rk1n commented Aug 31, 2018

Copy link
Copy Markdown
Contributor

Available with the following version:

  • dash==0.27.0rc7
  • dash-renderer==0.14.0rc6

Add hot-reload capability on project file changes by periodically requesting a hash and checking it's the same hash as the initial one.

Adds:

  • Reloader component
  • reloadRequest api thunk.

Need plotly/dash#362

@T4rk1nT4rk1n mentioned this pull request Aug 31, 2018
@T4rk1nT4rk1n changed the title [WIP] Hot reloadHot reloadSep 6, 2018
@T4rk1n

Copy link
Copy Markdown
ContributorAuthor

@plotly/dash Ready for review!

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! There's two questions I had, and two newlines missing

}),
dispatch => ({dispatch})
)(Reloader);

No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline

Comment threadsrc/actions/api.js Outdated
if (!disabled && !this._intervalId) {
this._intervalId = setInterval(() => {
if (!this.state.reloading) {
dispatch(getReloadHash());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should state.reloading be set to true here? I do not see anywhere that state.reloading is changed, it seems to always be false.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a leftover from something I tried, I will remove thanks.

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I there extra stuff in state that is stripped when you do this? I don't see what these two lines do, I don't think state is changed here

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything but the history is stripped down, it triggers a soft reload.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh okay so everything else gets set to default except the history, looks good

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

@valentijnniemanvalentijnnieman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left you a couple of questions!

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

}
if (reloadHash.content.reloadHash !== this.state.hash) {
// eslint-disable-next-line no-undef
window.clearInterval(this._intervalId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the no-undef rule here should not trigger if it's sure that this._intervalId is set, right? Maybe it's better to write a check here that makes sure that it's not null, instead of disabling the rule.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The no-undef is for window, it highlight as error in pycharm.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rootReducer is for soft-reload, it destroy the state of the store and then the other reducers can reload the application. I think it's cleaner to keep it separate as the logic for the historyReducer come after and they do different operations.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok! Hmm maybe that rule can be turned off globally then, if it's always going to trigger on window?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last question: isn't it maybe better to put the rootReducer in a separate file, and call it something else, like reloadReducer or whatever?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe that rule can be turned off globally then

I think we can put window in a global exclude or something. Anyway it underline as error in IDE, I just hit alt-enter and select a fix, doesn't take more than a second.

Last question: isn't it maybe better to put the rootReducer in a separate file

It's only a couple lines and is the last reducer exported, keeping it in reducer make more sense to me.

if (reloadHash.content.hard) {
// Assets file have changed, need to reload them.
// eslint-disable-next-line no-undef
window.top.location.reload();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, why is the no-undef rule triggering here?

Comment threadsrc/reducers/reducer.js Outdated
dependenciesRequest: API.dependenciesRequest,
layoutRequest: API.layoutRequest,
loginRequest: API.loginRequest,
reloadHash: API.reloadRequest,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why it's named reloadHash here and reloadRequest on API.reloadRequest?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I refactored reloadHash to reloadRequest to conform to the other API, I guess that one didn't follow up.

disabled: true
}
}
this._intervalId = null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can _intervalId not be in state as well?

hash: null,
interval,
disabled: false
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if this state is also handled in a reducer? Would there be value in having this state in the store? Perhaps saving the hash in the store for example would make it easier to at some point in the future to enable the store to be saved client-side, so that it can be rehydrated upon refreshing.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hash is null at first, it is set in the state from the server on the first hash request so I don't think it needs to be rehydrated.

@T4rk1n
T4rk1nforce-pushed the hot-reload branch 2 times, most recently from 9c9c797 to 232b6a4CompareSeptember 13, 2018 17:25

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few minor style changes 💃

Comment thread.gitignore

*.csv
.idea/
.vscode

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

disabled: false,
intervalId: null,
packages: null,
max_retry: max_retry,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just max_retry

);
let node = it.iterateNext();

while (node) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is node a proper iterator? You should be able to do const nodesToDisable = [...it.iterateNext()]

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a proper iterator but it doesn't work, if there's no element found (asset file added) it will fail to make an array with the iterator.

nodesToDisable.push(node);
node = it.iterateNext();
}
nodesToDisable.forEach(n =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we are trying to use ramda 🐏 in this repo even when a core library function would do the job. I think R.forEach would do the job.

} else if (reloadRequest.status === 500) {
if (this._retry > this.state.max_retry) {
window.clearInterval(this.state.intervalId);
// Integrate with dev tools ui?!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@T4rk1n@valentijnnieman@rmarren1
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Hot reload by T4rk1n · Pull Request #73 · plotly/dash-renderer · GitHub
Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Hot reload - #73

Merged
T4rk1n merged 22 commits into
masterfrom
hot-reload
Nov 14, 2018
Merged

Hot reload#73
T4rk1n merged 22 commits into
masterfrom
hot-reload

Conversation

@T4rk1n

@T4rk1nT4rk1n commented Aug 31, 2018

Copy link
Copy Markdown
Contributor

Available with the following version:

  • dash==0.27.0rc7
  • dash-renderer==0.14.0rc6

Add hot-reload capability on project file changes by periodically requesting a hash and checking it's the same hash as the initial one.

Adds:

  • Reloader component
  • reloadRequest api thunk.

Need plotly/dash#362

@T4rk1nT4rk1n mentioned this pull request Aug 31, 2018
@T4rk1nT4rk1n changed the title [WIP] Hot reloadHot reloadSep 6, 2018
@T4rk1n

Copy link
Copy Markdown
ContributorAuthor

@plotly/dash Ready for review!

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! There's two questions I had, and two newlines missing

}),
dispatch => ({dispatch})
)(Reloader);

No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline

Comment threadsrc/actions/api.js Outdated
if (!disabled && !this._intervalId) {
this._intervalId = setInterval(() => {
if (!this.state.reloading) {
dispatch(getReloadHash());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should state.reloading be set to true here? I do not see anywhere that state.reloading is changed, it seems to always be false.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a leftover from something I tried, I will remove thanks.

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I there extra stuff in state that is stripped when you do this? I don't see what these two lines do, I don't think state is changed here

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything but the history is stripped down, it triggers a soft reload.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh okay so everything else gets set to default except the history, looks good

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

@valentijnniemanvalentijnnieman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left you a couple of questions!

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

}
if (reloadHash.content.reloadHash !== this.state.hash) {
// eslint-disable-next-line no-undef
window.clearInterval(this._intervalId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the no-undef rule here should not trigger if it's sure that this._intervalId is set, right? Maybe it's better to write a check here that makes sure that it's not null, instead of disabling the rule.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The no-undef is for window, it highlight as error in pycharm.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rootReducer is for soft-reload, it destroy the state of the store and then the other reducers can reload the application. I think it's cleaner to keep it separate as the logic for the historyReducer come after and they do different operations.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok! Hmm maybe that rule can be turned off globally then, if it's always going to trigger on window?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last question: isn't it maybe better to put the rootReducer in a separate file, and call it something else, like reloadReducer or whatever?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe that rule can be turned off globally then

I think we can put window in a global exclude or something. Anyway it underline as error in IDE, I just hit alt-enter and select a fix, doesn't take more than a second.

Last question: isn't it maybe better to put the rootReducer in a separate file

It's only a couple lines and is the last reducer exported, keeping it in reducer make more sense to me.

if (reloadHash.content.hard) {
// Assets file have changed, need to reload them.
// eslint-disable-next-line no-undef
window.top.location.reload();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, why is the no-undef rule triggering here?

Comment threadsrc/reducers/reducer.js Outdated
dependenciesRequest: API.dependenciesRequest,
layoutRequest: API.layoutRequest,
loginRequest: API.loginRequest,
reloadHash: API.reloadRequest,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why it's named reloadHash here and reloadRequest on API.reloadRequest?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I refactored reloadHash to reloadRequest to conform to the other API, I guess that one didn't follow up.

disabled: true
}
}
this._intervalId = null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can _intervalId not be in state as well?

hash: null,
interval,
disabled: false
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if this state is also handled in a reducer? Would there be value in having this state in the store? Perhaps saving the hash in the store for example would make it easier to at some point in the future to enable the store to be saved client-side, so that it can be rehydrated upon refreshing.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hash is null at first, it is set in the state from the server on the first hash request so I don't think it needs to be rehydrated.

@T4rk1n
T4rk1nforce-pushed the hot-reload branch 2 times, most recently from 9c9c797 to 232b6a4CompareSeptember 13, 2018 17:25

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few minor style changes 💃

Comment thread.gitignore

*.csv
.idea/
.vscode

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

disabled: false,
intervalId: null,
packages: null,
max_retry: max_retry,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just max_retry

);
let node = it.iterateNext();

while (node) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is node a proper iterator? You should be able to do const nodesToDisable = [...it.iterateNext()]

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a proper iterator but it doesn't work, if there's no element found (asset file added) it will fail to make an array with the iterator.

nodesToDisable.push(node);
node = it.iterateNext();
}
nodesToDisable.forEach(n =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we are trying to use ramda 🐏 in this repo even when a core library function would do the job. I think R.forEach would do the job.

} else if (reloadRequest.status === 500) {
if (this._retry > this.state.max_retry) {
window.clearInterval(this.state.intervalId);
// Integrate with dev tools ui?!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@T4rk1n@valentijnnieman@rmarren1
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Hot reload by T4rk1n · Pull Request #73 · plotly/dash-renderer · GitHub
Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Hot reload - #73

Merged
T4rk1n merged 22 commits into
masterfrom
hot-reload
Nov 14, 2018
Merged

Hot reload#73
T4rk1n merged 22 commits into
masterfrom
hot-reload

Conversation

@T4rk1n

@T4rk1nT4rk1n commented Aug 31, 2018

Copy link
Copy Markdown
Contributor

Available with the following version:

  • dash==0.27.0rc7
  • dash-renderer==0.14.0rc6

Add hot-reload capability on project file changes by periodically requesting a hash and checking it's the same hash as the initial one.

Adds:

  • Reloader component
  • reloadRequest api thunk.

Need plotly/dash#362

@T4rk1nT4rk1n mentioned this pull request Aug 31, 2018
@T4rk1nT4rk1n changed the title [WIP] Hot reloadHot reloadSep 6, 2018
@T4rk1n

Copy link
Copy Markdown
ContributorAuthor

@plotly/dash Ready for review!

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! There's two questions I had, and two newlines missing

}),
dispatch => ({dispatch})
)(Reloader);

No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline

Comment threadsrc/actions/api.js Outdated
if (!disabled && !this._intervalId) {
this._intervalId = setInterval(() => {
if (!this.state.reloading) {
dispatch(getReloadHash());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should state.reloading be set to true here? I do not see anywhere that state.reloading is changed, it seems to always be false.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a leftover from something I tried, I will remove thanks.

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I there extra stuff in state that is stripped when you do this? I don't see what these two lines do, I don't think state is changed here

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything but the history is stripped down, it triggers a soft reload.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh okay so everything else gets set to default except the history, looks good

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

@valentijnniemanvalentijnnieman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left you a couple of questions!

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

}
if (reloadHash.content.reloadHash !== this.state.hash) {
// eslint-disable-next-line no-undef
window.clearInterval(this._intervalId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the no-undef rule here should not trigger if it's sure that this._intervalId is set, right? Maybe it's better to write a check here that makes sure that it's not null, instead of disabling the rule.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The no-undef is for window, it highlight as error in pycharm.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rootReducer is for soft-reload, it destroy the state of the store and then the other reducers can reload the application. I think it's cleaner to keep it separate as the logic for the historyReducer come after and they do different operations.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok! Hmm maybe that rule can be turned off globally then, if it's always going to trigger on window?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last question: isn't it maybe better to put the rootReducer in a separate file, and call it something else, like reloadReducer or whatever?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe that rule can be turned off globally then

I think we can put window in a global exclude or something. Anyway it underline as error in IDE, I just hit alt-enter and select a fix, doesn't take more than a second.

Last question: isn't it maybe better to put the rootReducer in a separate file

It's only a couple lines and is the last reducer exported, keeping it in reducer make more sense to me.

if (reloadHash.content.hard) {
// Assets file have changed, need to reload them.
// eslint-disable-next-line no-undef
window.top.location.reload();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, why is the no-undef rule triggering here?

Comment threadsrc/reducers/reducer.js Outdated
dependenciesRequest: API.dependenciesRequest,
layoutRequest: API.layoutRequest,
loginRequest: API.loginRequest,
reloadHash: API.reloadRequest,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why it's named reloadHash here and reloadRequest on API.reloadRequest?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I refactored reloadHash to reloadRequest to conform to the other API, I guess that one didn't follow up.

disabled: true
}
}
this._intervalId = null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can _intervalId not be in state as well?

hash: null,
interval,
disabled: false
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if this state is also handled in a reducer? Would there be value in having this state in the store? Perhaps saving the hash in the store for example would make it easier to at some point in the future to enable the store to be saved client-side, so that it can be rehydrated upon refreshing.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hash is null at first, it is set in the state from the server on the first hash request so I don't think it needs to be rehydrated.

@T4rk1n
T4rk1nforce-pushed the hot-reload branch 2 times, most recently from 9c9c797 to 232b6a4CompareSeptember 13, 2018 17:25

@rmarren1rmarren1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few minor style changes 💃

Comment thread.gitignore

*.csv
.idea/
.vscode

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

disabled: false,
intervalId: null,
packages: null,
max_retry: max_retry,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just max_retry

);
let node = it.iterateNext();

while (node) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is node a proper iterator? You should be able to do const nodesToDisable = [...it.iterateNext()]

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a proper iterator but it doesn't work, if there's no element found (asset file added) it will fail to make an array with the iterator.

nodesToDisable.push(node);
node = it.iterateNext();
}
nodesToDisable.forEach(n =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we are trying to use ramda 🐏 in this repo even when a core library function would do the job. I think R.forEach would do the job.

} else if (reloadRequest.status === 500) {
if (this._retry > this.state.max_retry) {
window.clearInterval(this.state.intervalId);
// Integrate with dev tools ui?!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@T4rk1n@valentijnnieman@rmarren1