0
votes

I'm starting to build a small app based on React, TypeScript and Webpack for building. I've followed this article: https://www.typescriptlang.org/docs/handbook/react-&-webpack.html

All the sources are stored at GitHub repo: https://github.com/aszmyd/webpack-react-typescript-bug

The issue:

When i start webpack dev server for local development it properly serves files under localhost:8080 and properly injects dynamic assets according to webpack configuration. But when i change something in source files, the rebuild gets fired and everything seems to be triggered properly but the dynamic assets are not injected into index.html. So after any change in source tsx files i get empty screen at localhost:8080 because the bundle.js file IS NOT INJECTED


So steps to reporoduce:

  1. Clone my test case repo: https://github.com/aszmyd/webpack-react-typescript-bug
  2. Install deps with npm install
  3. Run npm start
  4. Go to http://localhost:8080
  5. Change something in i.e. src/components/Hello.tsx

The initial generated index.html looks as follows:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>Hello React!</title>
</head>
<body>
<div id="example"></div>
<script type="text/javascript" src="bundle.js"></script></body>
</html>

And after at least 1 webpack dev server watch tour and build:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>Hello React!</title>
</head>
<body>
<div id="example"></div>
</body>
</html>
1

1 Answers

1
votes

You use both html-webpack-plugin and copy-webpack-plugin to create an index.html in the dist directory.

plugins: [
    new CopyWebpackPlugin([
        {from: 'index.html'},
    ], {
        copyUnmodified: true
    }),
    new HtmlWebpackPlugin({
        filename: 'index.html',
        template: 'index.html'
    }),
    new HtmlWebpackIncludeAssetsPlugin({
        assets: [], append: false, hash: true
    })
]

You don't need copy-webpack-plugin for this as the html-webpack-plugin already generates the index.html and automatically puts it in the dist directory. Despite that it's not needed, it actually causes problems with hot reloading, because webpack-dev-server thinks that the new index.html is the copied one, instead of the generated one. To see why this is happening you can take a look at the output after recompiling.

with copy plugin

                                   Asset       Size  Chunks                    Chunk Names
                               bundle.js    1.06 MB       0  [emitted]  [big]  main
    0.135a3b584db27942bf6f.hot-update.js    1.36 kB       0  [emitted]         main
    135a3b584db27942bf6f.hot-update.json   43 bytes          [emitted]
                           bundle.js.map    1.26 MB       0  [emitted]         main
0.135a3b584db27942bf6f.hot-update.js.map  894 bytes       0  [emitted]         main
                              index.html  146 bytes          [emitted]

without copy plugin

                                   Asset       Size  Chunks                    Chunk Names
                               bundle.js    1.06 MB       0  [emitted]  [big]  main
    0.135a3b584db27942bf6f.hot-update.js    1.36 kB       0  [emitted]         main
    135a3b584db27942bf6f.hot-update.json   43 bytes          [emitted]
                           bundle.js.map    1.26 MB       0  [emitted]         main
0.135a3b584db27942bf6f.hot-update.js.map  894 bytes       0  [emitted]         main

The difference is that with the copy plugin you emit a new index.html, which is just the copied one, because the html-webpack-plugin didn't see any changes and therefore didn't emit a new one. Hence webpack-dev-server serves this newly emitted index.html.

Note: If you had used a hash in your filename (e.g. bundle.[hash].js) it would have worked, because it emits a new index.html after every recompilation. Regardless, it's not a good idea to have conflicting plugins.