hot-module-replacement icon indicating copy to clipboard operation
hot-module-replacement copied to clipboard

live bindings

Open cztomsik opened this issue 7 years ago • 6 comments

In webpack this would work:

import App from './App'
import { render } from ...

const nativeNode = ...

const renderApp = () => render(<App />, nativeNode)

if (module.hot) {
  module.hot.accept('./App', renderApp)
}

It probably works because webpack actually transpiles everything and so if module is replaced, it's really visible everywhere then.

I don't know if this was intentional but it doesn't work currently with your module (which I find really great, thx).

Would you want to support such thing? I could help, I know I could easily do this for anything that is already transpiled (babel, typescript), because those are live bindings already and all we need is just to monkey-patch original esModule

On the other hand I don't know if it would work with .mjs files at all, transpilation or proxies are needed for such functionality and I don't think node is transpiling anything with .mjs files. But it could be known issue, which can easily be fixed with esm loader, which does transpilation and so there are live-bindings again and we can monkey-patch.

Do you want me to do this?

BTW: here's something on live bindings if anyone is reading this and is not familiar with the concept http://2ality.com/2015/07/es6-module-exports.html

cztomsik avatar Dec 13 '18 11:12 cztomsik

I started looking at esm hot reloading (with built in node esm modules or via esm package) and looks like it would have completely different implementation (if possible at all)

Scope of this module is allowing hot reload without any bundle/transpilation steps so might be not easy

Any help would really appreciated!

sidorares avatar Dec 13 '18 11:12 sidorares

I can give it a try but it's more about if you want it to monkey-patch original esModule or not. Webpack does this (App !== oldApp after replacement). I don't know if this was your intentional decision (less magic) or if it should be fixed so it's compatible.

cztomsik avatar Dec 13 '18 12:12 cztomsik

Not sure I follow. Here after replacement newModule !== oldModule as well

sidorares avatar Dec 13 '18 12:12 sidorares

This only works with webpack:

import * as React from 'react'
import { Window } from 'node-webrender'
import { render } from 'node-webrender/src/react'
import { App } from './App'

const w = new Window("Hello", 400, 500)

const renderRoot = () =>
  render(<App />, w)

if ('hot' in module) {
  (module as any).hot.accept('./App', () => {
    renderRoot()
  })
}

renderRoot()

To make it work with your module I had to do it this way:

import * as React from 'react'
import { Window } from 'node-webrender'
import { render } from 'node-webrender/src/react'
import { App } from './App'

const w = new Window("Hello", 400, 500)

let Root = App

const renderRoot = () =>
  render(<Root />, w)

if ('hot' in module) {
  (module as any).hot.accept('./App', () => {
    Root = require('./App').App
    renderRoot()
  })
}

renderRoot()

cztomsik avatar Dec 13 '18 14:12 cztomsik

I don't see an easy way to support that. Also it's easy to break:

import * as React from 'react'
import { Window } from 'node-webrender'
import { render } from 'node-webrender/src/react'
import { App } from './App'

const w = new Window("Hello", 400, 500)
const App2 = App;

const renderRoot = () =>
  render(<App2  />, w) // after update App2 points to old

if ('hot' in module) {
  (module as any).hot.accept('./App', () => {
    renderRoot()
  })
}

renderRoot()

sidorares avatar Dec 13 '18 19:12 sidorares

I think I was experiencing something similar with deep objects.

Example:

data.json

{"value": {"nestedValue": "false"}}
var json = require('./data')

console.log(json) // {"value": {"nestedValue": "false"}}

json.value.nestedValue = true

console.log(json.value.nestedValue) // true, but consistently false after the first update

As a workaround I am creating a deep copy of the original object like this:

var json = JSON.parse(JSON.stringify(require('./data')))

console.log(json) // {"value": {"nestedValue": "false"}}

json.value.nestedValue = true

console.log(json.value.nestedValue) // always true

kireerik avatar Dec 14 '18 20:12 kireerik