s-panferov / awesome-typescript-loader

Awesome TypeScript loader for webpack
Other
2.35k stars 179 forks source link

Hot Module Replacement Inconsistencies #576

Open NTARelix opened 6 years ago

NTARelix commented 6 years ago

Expected Behaviour

HMR should behave consistently with plain-old-js HMR (no awesome-typescript-loader)

Actual Behaviour

With HMR enabled and awesome-typescript-loader used, HMR fails to replace imported values from hot-replaced modules and doesn't call HMR .accept callback function more than once.

Also doesn't work in ts-loader: https://github.com/TypeStrong/ts-loader/issues/761

Steps to Reproduce the Problem

See README of demo repo linked below. Here's a sample of the HMR code that should work, but doesn't:

// ./src/index.ts
///<reference types="webpack-env" />
import { stringToLog } from './exports-string';

console.log('Initial value:', stringToLog);

if (module.hot) {
  module.hot.accept('./exports-string', () => {
    console.log('New value:', stringToLog);
  });
}
// ./src/exports-string.ts
export const stringToLog = 'initial value';

Location of a Minimal Repository that Demonstrates the Issue.

https://github.com/NTARelix/hmr-fail

NTARelix commented 6 years ago

I got HMR working with ts-loader by adding transpileOnly: true to the loader options. However, that solution changed nothing about the inconsistent HMR behavior with awesome-typescript-loader. I tried adding that option both to the loader options:

{
  test: /\.ts$/,
  use: {
    loader: 'awesome-typescript-loader',
    options: { transpileOnly: true }
  }
}

as well as the tsconfig.json loader options:

{ "awesomeTypescriptLoaderOptions": { "transpileOnly": true } }

chrisui commented 6 years ago

Would be great to get this working in the "least surprising way".

In this case to reference the original webpack docs:

When using ESM import all imported symbols from dependencies are automatically updated. Note: The dependency string must match exactly with the from string in the import. In some cases callback can even be omitted. Using require() in the callback doesn't make sense here.

Would be great if typescript imports could do this too.

chrisui commented 6 years ago

Ok just managed to get this working as expected by compiling modules to ES2015 format rather than commonjs.

"module": "es2015" in tsconfig.json

NickDubelman commented 6 years ago

Above solution worked for me, not quite sure why?

chrisui commented 6 years ago

@NickDubelman Webpack requires ES Module syntax to do auto updating of module exports/imports. By default TS will compile to commonjs and so webpack can't make the same assumptions about those imports/exports. "module": "es2015" tells it to compile using ES Module syntax and so webpack sees them. 🙌

alexcheuk commented 5 years ago

Setting

"module": "esnext",
"moduleResolution": "node"

in tsconfig.json fixed this for me