Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using React.js lazy loading when I navigate to a nested route the main bundle doesn't load

I'm using react router with component lazy loading and using Webpack as a bundler, When I access to the home page / I can see in the network tab that the bundle.js is loaded and also when I click on a specific item in the sidebar the correspondent component is loaded successfully with its file name for example 0.bundle.js, However when I navigate directly from the search bar to a nested route (example http://127.0.0.1:8080/forms/select) i get an error like the following:

GET http://127.0.0.1:8080/forms/bundle.js net::ERR_ABORTED 404 (Not Found)

This error indicates that the bundle.js is not loaded which means that it cannot load the other chunks.

webpack.config.js

const webpack = require('webpack');
module.exports = {
    entry: './src/index.js',
    module: {
        rules: [],
    },
    resolve: {
        extensions: ['*', '.js', '.jsx'],
    },
    output: {
        path: __dirname + '/dist',
        publicPath: '/',
        filename: 'bundle.js',
    },
    plugins: [new webpack.HotModuleReplacementPlugin()],
    devtool: 'cheap-module-eval-source-map',
    devServer: {
        contentBase: './dist',
        hot: true,
        historyApiFallback: true,
        
    },
};

.babelrc

{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ],
    "plugins": ["@babel/plugin-syntax-dynamic-import"]
}

routes.js

import { lazy } from 'react';

const Forms = lazy(() => import('../components/uiViews/Forms'));
const SelectForm = lazy(() => import('../components/uiViews/Forms/SelectForm'));
const FormValidation = lazy(() => import('../components/uiViews/Forms/FormValidation'));

const routes = [

    {
        icon: 'form',
        label: 'forms',
        path: '/forms',
        component: Forms,
        children: [
            {
                icon: 'select',
                label: 'selectInput',
                path: '/forms/select',
                component: SelectForm,
            },
            { icon: 'issues-close', label: 'formValidation', path: '/forms/validation', component: FormValidation },
            {
                icon: 'form',
                label: 'wizardForm',
                path: '/forms/wizard',
                component: WizardForm,
            }],
    },
    

];

export default routes;

routes rendering

<Suspense fallback={<div className="spin-loading">  <Spin size="large" /></div>}>
                {routes.map((route, i) => {
                    return route.component ? RouteWithSubRoutes( {...route},`r${i}`) : null;
                })}
</Suspense>

....


function RouteWithSubRoutes(route,key) {
    return route.children ? (
        route.children.map((subRoute,j) => {
            return RouteWithSubRoutes(subRoute,`sr${j}`);
        })
    ) : (
        <Route key={key}  path={route.path} exact component={() =>route.component? <route.component />:<ComingSoon/>} />
    );
}
like image 886
Boussadjra Brahim Avatar asked Jan 16 '20 11:01

Boussadjra Brahim


People also ask

How does react JS handle lazy loading?

The lazy component should then be rendered inside a Suspense component, which allows us to show some fallback content (such as a loading indicator) while we're waiting for the lazy component to load. The fallback prop accepts any React elements that you want to render while waiting for the component to load.


1 Answers

After some days of trying out different solutions, finally i found this one that saves my day :

... I finally figured out the actual issue and it is not directly related to either Webpack or React Hot Loader or React Router or any other library at least for now at least for me. When using HTML5 push state to manipulate browsers history WE MUST PROVIDE tag in our html head section. After providing to the head section of my html, HMR works like a charm even in nested routes.

<!DOCTYPE html>
<html>
    <head>
        <base href="/" /> <!-- THIS TINY LITTLE THING -->
        <meta charset="UTF-8" />
        <title>Hello React!</title>
    </head>
    <body>
        <div id="root"></div>
        <script src="/main.bundle.js"></script>
    </body>
</html>


like image 137
Boussadjra Brahim Avatar answered Sep 28 '22 05:09

Boussadjra Brahim