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

GrumpyCrouton
  • 8,486
  • 7
  • 32
  • 71
Luciano
  • 450
  • 1
  • 7
  • 17

8 Answers8

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]
    }
moritzg
  • 4,266
  • 3
  • 37
  • 62
Blue
  • 22,608
  • 7
  • 62
  • 92
  • @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. – daisura99 Aug 29 '18 at 16:56
  • 3
    But with the first way, I can't enable AOT any more since AOT doesn't support arrow function in decorators. – Fang Liu Mar 08 '19 at 02:38
  • 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. – Marcus Santodonato Jun 29 '20 at 19:11
4

You can use like this:

const rootRoutes: Routes = [
  { path: 'your-path', loadChildren: () => UsersModule }
];
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"]
Fredrik_Borgstrom
  • 2,504
  • 25
  • 32
  • 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.json` – Harkal Oct 30 '20 at 10:31
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)
    }
];
Char
  • 2,073
  • 8
  • 28
  • 45
0

Its typo folder name is Users not users :

Change

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

to

'./components/Users/users.module#UsersModule'
Vivek Doshi
  • 56,649
  • 12
  • 110
  • 122
  • The folder name is user, i've edited the post. Sorry – Luciano Jan 25 '18 at 11:25
  • Will you please remove `RouterModule` from users.module.ts and try again ? @Luciano – Vivek Doshi Jan 25 '18 at 12:55
  • @Luciano , will you please create demo on stackblitz? – Vivek Doshi Jan 25 '18 at 13:51
  • I've added a link to stackblitz in the post – Luciano Jan 25 '18 at 14:41
  • @Luciano , please check this https://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. – Vivek Doshi Jan 25 '18 at 16:26
  • Ok this change make my stackblitz working, but the same change does not help in my application. Always Cannot find module – Luciano Jan 26 '18 at 09:05
  • @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 :) – Vivek Doshi Jan 26 '18 at 09:07
  • 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 stackblitz – Luciano Jan 26 '18 at 09:30
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 { }
federico scamuzzi
  • 3,708
  • 1
  • 17
  • 24
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

Ishaan Javali
  • 1,711
  • 3
  • 13
  • 23
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!!

Rashi Goyal
  • 933
  • 9
  • 15