Skip to content

Usage with Hot Module Replacement #180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
buzinas opened this issue Apr 9, 2016 · 2 comments
Closed

Usage with Hot Module Replacement #180

buzinas opened this issue Apr 9, 2016 · 2 comments

Comments

@buzinas
Copy link

buzinas commented Apr 9, 2016

TL;DR
I am trying to use this (or any other) typescript loader combined with vanilla's Webpack HMR, but I'm stuck with the method hot.module.accept. It seems that TypeScript modules don't play well with it.


I spent many hours on this, but still couldn't figure out what's going on (although I think I'm really close).

I was trying to implement HMR in a TS project I have, and wasn't advancing, so I decided to take a simpler approach:

I have an ES6 project here that I'm able to use webpack's HMR, e.g:

if (hot.module) {
  hot.module.accept('./path-to-my-dependency/file', () => {
    reRenderStuff();
  });
}

With the code above, if I change any file in my project, HMR replaces the dependent modules, reloads my previous state, and everything works as I expect.

Then, I ported this ES6 project to TypeScript, so I could try to use HMR in a smaller project - but for some reason - the hot.module.accept doesn't work well with it.

[HMR] The following modules couldn't be hot updated: (Full reload needed)
This is usually because the modules which have changed (and their parents) do not know how to hot reload themselves. See http://webpack.github.io/docs/hot-module-replacement-with-webpack.html for more details.

  • ./src/common/components/Counter.tsx

If I create a generic approach for hot.module.accept, e.g:

if (hot.module) {
  hot.module.accept(() => {
    reRenderStuff();
  });
}

Doing this way, HMR replaces my modules correctly, but it destroys my state, since I have another rule for updating it.

[HMR] Checking for updates on the server...
Provider.js:29 <Provider> does not support changing `store` on the fly.
process-update.js:100 [HMR] Updated modules:
process-update.js:102 [HMR]  - ./src/common/components/Counter.tsx
process-update.js:102 [HMR]  - ./src/common/containers/App.ts
process-update.js:102 [HMR]  - ./src/client/index.tsx
process-update.js:107 [HMR] App is up to date.

So, I'd like to know what's the correct approach to use hot.module.accept with the typescript loader, since I can use it smoothly with babel.

I'd already tried all the typescript loaders, but none seems to be compatible with hot.module.accept. Any thoughts?

PS: Already tried to use Babel as an intermmediary in all the imaginable ways, but same problem persists. I hope you have some simple and magical solution for this :)

PS2: Already tried all the examples mentioned in the other issue, but none of them works with vanilla HMR.

@buzinas
Copy link
Author

buzinas commented Apr 9, 2016

Now, I'm absolutely sure it's a bug, found that module.hot.accept is doubling the moduleId, take a look:

    var redux_1 = __webpack_require__(45);
    var thunk = __webpack_require__(233);
    var index_1 = __webpack_require__(74);
    function configureStore(initialState) {
        var store = redux_1.createStore(index_1.default, initialState, redux_1.applyMiddleware(thunk));
        if (true) {
            // Enable Webpack hot module replacement for reducers
            module.hot.accept(7474, function () {
                var nextRootReducer = __webpack_require__(74).default;
                store.replaceReducer(nextRootReducer);
            });
        }
        return store;
    }

It should be module.hot.accept(74, instead of 7474.

Any ideas how can I solve this? It only happens when using TypeScript (tried both ts-loader and awesome-typescript-loader). When using Babel, it works as expected.

@buzinas
Copy link
Author

buzinas commented Apr 9, 2016

Guys, I finally could solve the problem! 👯

Firstly, the problem was happening because since there is no .hot in module, TypeScript was throwing errors, and then I started using module['hot'].

Webpack HMR has a transformer which looks for module.hot exactly, so it was never changing the moduleId parameter sent to the accept method.

I fixed that by creating a .d.ts file with the content:

interface NodeModule {
  hot: { accept: Function };
}

Then, the other problem was that I was using the HotModuleReplacement plugin twice, and then Webpack was doubling the moduleIds.

After fixing both things, everything started working as expected! :)


PS: The main reason it was not working in my first post in this issue is because I was using module['hot'] instead of module.hot. Babel was working because I was using module.hot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant