awesome-typescript-loader
awesome-typescript-loader copied to clipboard
Hot Module Replacement Inconsistencies
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.
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 } }
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.
Ok just managed to get this working as expected by compiling modules to ES2015 format rather than commonjs.
"module": "es2015" in tsconfig.json
Above solution worked for me, not quite sure why?
@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. 🙌
Setting
"module": "esnext",
"moduleResolution": "node"
in tsconfig.json fixed this for me