Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webpack Code Splitting 'Loading chunk failed' error wrong file path

I'm using React + Typescript with Webpack and I'm trying to load some of my react components when they are actually needed.

The issue is that when the chunk is requested via lazy loading I'm getting the following error:

Uncaught Error: Loading chunk 1 failed. (error: http://localhost:58988/1.chunk.js) at HTMLScriptElement.onScriptComplete (bootstrap:114)

This chunk is generated successfully and without any errors, it's just that the path is wrong - http://localhost:58988/1.chunk.js and it should be http://localhost:58988/dist/1.chunk.js

I've also tried using the newest React.lazy to lazy load react components but I'm getting the same issue. So, is there a way to tell the compiler how to resolve these file paths?

Here's some of the code:

MyComponent.tsx

import * as React from "react";
import * as ES5Promise from "promise";

export class MyComponent extends React.Component<{}, {}> {
    constructor(props) {
        super(props);
    }

    private readonly onLoadModuleClickHandler = (): void => {
        import("./Button").then((module) => {
            console.log(module);
        });
    }

    render() {
        return (
            <div>
                <input type="button" value="Load another module" onClick={this.onLoadModuleClickHandler}/>
            </div>
        );
    }
}

tsconfig.json

{
  "compilerOptions": {
    "moduleResolution": "node",
    "noImplicitAny": false,
    "noEmitOnError": true,
    "module": "esnext",
    "removeComments": false,
    "sourceMap": false,
    "target": "es5",
    "jsx": "react",
    "noEmit": true,
    "importHelpers": true,
    "lib": ["dom", "es5", "es2015.promise"]
  },
  "exclude": [
    "node_modules",
    "wwwroot"
  ]
}

webpack.config.js

module.exports = {
    entry: {
        "app": "./src/App.tsx"
    },
    output: {
        path: path.resolve(__dirname, 'wwwroot/dist'),
        filename: "[name].bundle.js",
        chunkFilename: "[name].chunk.js"
    },
    module: {
        rules: [
            {
                test: /\.(ts|tsx)?$/,
                use: "awesome-typescript-loader",
                exclude: /node_modules/
            },
            {
                test: /\.(css|less)?$/,
                use: [{
                    loader: "style-loader"
                }, {
                    loader: "css-loader?modules&localIdentName=[local]--[hash:base64:5]"
                }, {
                    loader: "less-loader"
                }]
            },
        ]
    },
    resolve: {
        extensions: [".js", ".jsx", ".ts", ".tsx", ".css", ".less"]
    }
};
like image 574
Martin Shishkov Avatar asked Dec 10 '18 11:12

Martin Shishkov


3 Answers

That happens because output.publicPath by default is /.

Just update output.publicPath to point where you want it to be => /dist/.

like image 148
PlayMa256 Avatar answered Nov 19 '22 04:11

PlayMa256


When redeploying, on rebuilding the app bundles make sure NOT to clean the output folder with previous chunk files, because users that already have the app loaded will try to fetch previous chunk files that will not exist anymore.

Best thing to do is to have an app version tracking (using AJAX and read from db or dynamic config file) and when the app detects a newer version, message the user about it and ask them to reload the page.

like image 24
Christos Lytras Avatar answered Nov 19 '22 03:11

Christos Lytras


Let's not over fixate on this. It only happened 5 times. I believe that somebody has excalidraw opened for a while, we push a new version in the meantime and when they get back, they try to load some lazy chunk and it is no longer there.

The way we solve this at Facebook is that we keep the previous chunks on our CDN for a week and we force refresh the app for people if the bundle is more than a week old. This way we don't need to care about very old versions.

The above response is from vjeux.

My plan is to listen for errors in window.onerror, and then prompt the user to refresh the browser.

window.addEventListener('error', e => {
  // prompt user to confirm refresh
  if (/Loading chunk [\d]+ failed/.test(e.message)) {
    window.location.reload();
  }
});
like image 8
weiliang Avatar answered Nov 19 '22 05:11

weiliang