Angular 5 lazy loading Error: Cannot find module
Asked Answered
W

8

9

I would like to use lazy loading but I can not understand why it does not work, it gives me error "Cannot find module".
This is my environment:
- Angular 5.2.1
- .NET Core 2
- Webpack 3.10.0
- angular-router-loader 0.8.2
- @angular/cli 1.6.5
I tried different path in loadChildren always without success, i also temporarily disabled all the guards and the children routing. What did I do wrong?

FOLDERS

ClientApp
  app
    components
      users
        users-routing.module.ts
        users.module.ts
  app-routing.module.ts
  app.module.shared.ts

app-routing.module.ts

const appRoutes: Routes = [
    {
        path: 'users',
        loadChildren: './components/users/users.module#UsersModule'/* ,
        canLoad: [AuthGuard] */
    },
    {
        path: '',
        redirectTo: '/login',
        pathMatch: 'full'
    },
    {
        path: '**',
        redirectTo: '/login'
    }
];

@NgModule({
    imports: [
        RouterModule.forRoot(
            appRoutes,
            { enableTracing: false }
        )
    ],
    exports: [
        RouterModule
    ],
    providers: [
        CanDeactivateGuard
    ]
})
export class AppRoutingModule { }

users-routing.module.ts

const usersRoutes: Routes = [
    {
        path: '',
        component: UsersComponent/* ,
        //canActivate: [AuthGuard],
        children: [
            {
                path: 'detail',
                canActivateChild: [AuthGuard],
                children: [
                    {
                        path: ':id',
                        component: UserViewComponent
                    },
                    {
                        path: 'edit/:id',
                        component: UserFormComponent,
                        canDeactivate: [CanDeactivateGuard],
                        resolve: {
                            user: UsersResolver
                          }
                    },
                    {
                        path: '',
                        component: UserFormComponent,
                        canDeactivate: [CanDeactivateGuard]
                    }
                ]
            },
            {
                path: '',
                component: UsersListComponent
            }
        ] */
    }
];

@NgModule({
    imports: [
        RouterModule.forChild(
            usersRoutes
        )
    ],
    exports: [
        RouterModule
    ]
})
export class UsersRoutingModule { }

users.module.ts

@NgModule({
    imports: [
        CommonModule,
        FormsModule,
        UsersRoutingModule,
        RouterModule
    ],
    declarations: [
        UsersComponent,
        UserFormComponent,
        UsersListComponent,
        UserViewComponent
    ],
    providers: [
        UsersResolver,
        RouterModule
    ]
})
export class UsersModule { }

webpack.config.js

const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const AngularCompilerPlugin = require('@ngtools/webpack').AngularCompilerPlugin;
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;

module.exports = (env) => {
    // Configuration in common to both client-side and server-side bundles
    const isDevBuild = !(env && env.prod);
    const sharedConfig = {
        stats: {
            modules: false
        },
        context: __dirname,
        resolve: {
            extensions: ['.js', '.ts']
        },
        output: {
            filename: '[name].js',
            publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
        },
        module: {
            rules: [{
                    test: /\.ts$/,
                    include: /ClientApp/,
                    use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] : '@ngtools/webpack'
                },
                {
                    test: /\.html$/,
                    use: 'html-loader?minimize=false'
                },
                {
                    test: /\.css$/,
                    use: ['to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize']
                },
                {
                    test: /\.(png|jpg|jpeg|gif|svg)$/,
                    use: 'url-loader?limit=25000'
                }
            ],
            loaders: [
                {
                  test: /\.ts$/,
                  loaders: [
                    'awesome-typescript-loader'
                  ]
                },
                {
                  test: /\.(ts|js)$/,
                  loaders: [
                    'angular-router-loader'
                  ]
                }
              ]
        },
        plugins: [new CheckerPlugin()]
    };

    // Configuration for client-side bundle suitable for running in browsers
    const clientBundleOutputDir = './wwwroot/dist';
    const clientBundleConfig = merge(sharedConfig, {
        entry: {
            'main-client': './ClientApp/boot.browser.ts'
        },
        output: {
            path: path.join(__dirname, clientBundleOutputDir)
        },
        plugins: [
            new webpack.DllReferencePlugin({
                context: __dirname,
                manifest: require('./wwwroot/dist/vendor-manifest.json')
            })
        ].concat(isDevBuild ? [
            // Plugins that apply in development builds only
            new webpack.SourceMapDevToolPlugin({
                filename: '[file].map', // Remove this line if you prefer inline source maps
                moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
            })
        ] : [
            // Plugins that apply in production builds only
            new webpack.optimize.UglifyJsPlugin(),
            new AngularCompilerPlugin({
                tsConfigPath: './tsconfig.json',
                entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'),
                exclude: ['./**/*.server.ts']
            })
        ])
    });

    // Configuration for server-side (prerendering) bundle suitable for running in Node
    const serverBundleConfig = merge(sharedConfig, {
        resolve: {
            mainFields: ['main']
        },
        entry: {
            'main-server': './ClientApp/boot.server.ts'
        },
        plugins: [
            new webpack.DllReferencePlugin({
                context: __dirname,
                manifest: require('./ClientApp/dist/vendor-manifest.json'),
                sourceType: 'commonjs2',
                name: './vendor'
            })
        ].concat(isDevBuild ? [] : [
            // Plugins that apply in production builds only
            new AngularCompilerPlugin({
                tsConfigPath: './tsconfig.json',
                entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'),
                exclude: ['./**/*.browser.ts']
            })
        ]),
        output: {
            libraryTarget: 'commonjs',
            path: path.join(__dirname, './ClientApp/dist')
        },
        target: 'node',
        devtool: 'inline-source-map'
    });

    return [clientBundleConfig, serverBundleConfig];
};  

tsconfig.json

{
  "compilerOptions": {
    "module": "es2015",
    "moduleResolution": "node",
    "target": "es5",
    "sourceMap": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "skipDefaultLibCheck": true,
    "skipLibCheck": true, // Workaround for https://github.com/angular/angular/issues/17863. Remove this if you upgrade to a fixed version of Angular.
    "strict": true,
    "lib": [ "es6", "dom" ],
    "types": [ "webpack-env" ], 
    "typeRoots": [
      "node_modules/@types"
    ]
  },
  "exclude": [ "bin", "node_modules" ],
  "atom": { "rewriteTsconfig": false }
}

ERROR MESSAGE

Unhandled Promise rejection: Cannot find module './ClientApp/app/components/users/users.module'. ; Zone: angular ; Task: Promise.then ; Value: Error: Cannot find module './ClientApp/app/components/users/users.module'. at vendor.js?v=AdjSBPSITyauSY4VQBBoZmJ6NdWqor7MEuHgdi2Dgko:34015 at ZoneDelegate.invoke (vendor.js?v=AdjSBPSITyauSY4VQBBoZmJ6NdWqor7MEuHgdi2Dgko:117428) at Object.onInvoke (vendor.js?v=AdjSBPSITyauSY4VQBBoZmJ6NdWqor7MEuHgdi2Dgko:5604) at ZoneDelegate.invoke (vendor.js?v=AdjSBPSITyauSY4VQBBoZmJ6NdWqor7MEuHgdi2Dgko:117427) at Zone.run (vendor.js?v=AdjSBPSITyauSY4VQBBoZmJ6NdWqor7MEuHgdi2Dgko:117178) at vendor.js?v=AdjSBPSITyauSY4VQBBoZmJ6NdWqor7MEuHgdi2Dgko:117898 at ZoneDelegate.invokeTask (vendor.js?v=AdjSBPSITyauSY4VQBBoZmJ6NdWqor7MEuHgdi2Dgko:117461) at Object.onInvokeTask (vendor.js?v=AdjSBPSITyauSY4VQBBoZmJ6NdWqor7MEuHgdi2Dgko:5595) at ZoneDelegate.invokeTask (vendor.js?v=AdjSBPSITyauSY4VQBBoZmJ6NdWqor7MEuHgdi2Dgko:117460) at Zone.runTask (vendor.js?v=AdjSBPSITyauSY4VQBBoZmJ6NdWqor7MEuHgdi2Dgko:117228) Error: Cannot find module './ClientApp/app/components/users/users.module'. at http://localhost:5000/dist/vendor.js?v=AdjSBPSITyauSY4VQBBoZmJ6NdWqor7MEuHgdi2Dgko:34015:9 ... [truncated]

EDIT

link to stackblitz for testing

Winchell answered 25/1, 2018 at 11:7 Comment(5)
app-routing.module.ts is within app folder?Arvie
@VivekDoshi Yes it's rightWinchell
@Winchell Do not edit your question with how you solved it. Instead, answer it below and accept it.Excavator
If you have an answer, please post it as an answer. Do not edit your question for this purpose.Blackbeard
Ok sorry guys and thanks for the editWinchell
O
25

I have found two solutions (via the OP by edit):

  1. Reference to the module, after it has already been resolved with an import statement:

    import { UsersModule } from './components/users/users.module';

then referencing this way:

{
    path: 'users',
    loadChildren: () => UsersModule,
    canLoad: [AuthGuard]
}
  1. I have added ng-router-loader to the application (npm install ng-router-loader --save-dev) and I set up Webpack like this:

         rules: [{
                 test: /\.ts$/,
                 include: /ClientApp/,
                 //use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] : '@ngtools/webpack'
                 use: isDevBuild ? [{ loader: 'ng-router-loader' }, 'awesome-typescript-loader?silent=true', 'angular2-template-loader'] : '@ngtools/webpack'
             },
             {
                 test: /\.html$/,
                 use: 'html-loader?minimize=false'
             },
             {
                 test: /\.css$/,
                 use: ['to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize']
             },
             {
                 test: /\.(png|jpg|jpeg|gif|svg)$/,
                 use: 'url-loader?limit=25000'
             }
         ],
    

then referencing the module by path:

    {
        path: 'users',
        loadChildren: './components/users/users.module#UsersModule',
        canLoad: [AuthGuard]
    }
Organology answered 25/1, 2018 at 11:7 Comment(3)
@wctiger same here, I wonder what was the reason. I've been working on my project for some time and one day it just stopped working.Yet I am certain the loadChildren path is correct. The first way saved my day as well, but it troubles me as to why it works.Caseinogen
But with the first way, I can't enable AOT any more since AOT doesn't support arrow function in decorators.Harwill
I was having the same problem in Angular 9. Adding the import statement to my routing.ts file resolved it for me, even with the loadChildren property set to the path for the module.Portis
A
4

You can use like this:

const rootRoutes: Routes = [
  { path: 'your-path', loadChildren: () => UsersModule }
];
Alyworth answered 13/7, 2020 at 22:59 Comment(0)
J
3

The currently accepted answer, which proposes to exchange the value of loadChildren from a string to a function, removes the possibility of AOT compilation when doing a production build.

What worked for me, was 1) use absolute paths 2) Add the lazy loaded modules as a string array in angular.json under projects > 'projectname' > architect > build > options > lazyModules. The paths should be the same as defined under loadChildren.

So, in your case, I think this should work in your routing module:

loadChildren: 'app/components/users/users.module#UsersModule'

And in angular.json, add this at the location specified above:

lazyModules: ["app/components/users/users.module"]
Johnniejohnny answered 4/4, 2019 at 12:46 Comment(1)
the path in lazyModules must start with src/. i just tested. i m thankful for your answer as it lead me to know about that option in angular.jsonLundy
R
2

Supposing this is AppModule that handles lazyloading and the features of your system are of the same tree as it is:

routes: Routes = [
    {
        path: 'files-pannel',
        loadChildren: () => import('./module-folder/module-name.module').then(m => m.ModuleName)
    }
];
Resorcinol answered 20/3, 2020 at 8:8 Comment(0)
A
0

Its typo folder name is Users not users :

Change

'./components/users/users.module#UsersModule'

to

'./components/Users/users.module#UsersModule'
Arvie answered 25/1, 2018 at 11:14 Comment(8)
The folder name is user, i've edited the post. SorryWinchell
Will you please remove RouterModule from users.module.ts and try again ? @WinchellArvie
@Winchell , will you please create demo on stackblitz?Arvie
I've added a link to stackblitz in the postWinchell
@Winchell , please check this stackblitz.com/edit/angular-route-issue, Make it working click on the first link , you are getting 2 link because of userRooutingModule , there is no need to put path and component there , it will automatically point the userComponent.Arvie
Ok this change make my stackblitz working, but the same change does not help in my application. Always Cannot find moduleWinchell
@Luciano,Then I think you have to find the issue by your self, I have made the stackblitz working, Let me know If there is any other way to help :)Arvie
Thanks Vivek Doshi, i think the problem is with the configuration of the webpack but i do not know what. I do not know how to configure the whole environment on stackblitzWinchell
S
0

try to do n your user.module.ts:

import {UserRoutes } from './User.routing'

@NgModule({
    imports: [
        CommonModule,
        FormsModule,
        UsersRoutingModule.forChild(UserRoutes), //<-- for child
        RouterModule
    ],
    declarations: [
        UsersComponent,
        UserFormComponent,
        UsersListComponent,
        UserViewComponent
    ],
    providers: [
        UsersResolver,
        RouterModule
    ]
})
export class UsersModule { }
Spangler answered 25/1, 2018 at 11:28 Comment(2)
Federico, i don't understand how to implement this, forChild is not a method of UserRoutingModule (it's inside the module)Winchell
yes cause you' re exports: [ RouterModule ] from your user routing .... Give a try!!Spangler
R
0

Usually, it is an error with the path. Change the path.

For example, this solution works for me::

loadChildren: '../changelog/changelog.module#ChangelogModule'

./folder or ../folder or folder

Reames answered 26/11, 2018 at 13:25 Comment(0)
F
0

I have also faced the same issue while loading my module I was getting this error Error: Cannot find module 'app/users/users.module' Then after figuring out it was error related to the path This solution works for me hope it help anyone In the route add this path

{
   path: 'users',
   loadChildren: '../app/users/users.module#UsersModule'
 }

Figure out the path of your module folder like folder or ./folder or ../folder

Happy Coding!!

Farron answered 16/7, 2020 at 14:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.