5

I have an angular module for demo purposes (DevShowcaseModule). This module should not be included in the production build. In order to hide this demos from the endusers and prevent demo code errors in the production.

Environment:

  • Angular Version: 7.2.5
  • Angular CLI: 7.3.2

This is my app-routing.module.ts

{
    path: APP_NAV_ITEMS.DEV_SHOWCASE,
    canActivate: [ AuthGuard ],
    loadChildren: './_dev-showcase/dev-showcase.module#DevShowcaseModule',
}

I have tried to exclude the module folder from the tsconfig.json. But it doesnt work, i can still call the route and the demo module is loaded.

{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "importHelpers": true,
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "module": "es2015",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,

    "noUnusedLocals": true,
    "noUnusedParameters": true,

    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2018",
      "dom"
    ]
  },
  "exclude": [
    "app/_dev-showcase/*"

  ]
}

Any idea how to do it properly?

Thanks!

Hien Nguyen
  • 24,551
  • 7
  • 52
  • 62
Webworx23
  • 121
  • 2
  • 9
  • 1
    Either dynamically build routes or guard the dev route with a route guard. – Roberto Zvjerković May 09 '19 at 12:14
  • use https://angular.io/api/router/CanLoad – Joel Joseph May 09 '19 at 12:15
  • CanLoad - Decides if a module can be loaded lazily, Controls if a route can even be loaded. This becomes useful for feature modules that are lazy loaded. They won’t even load if the guard returns false. – Joel Joseph May 09 '19 at 12:18
  • @ritaj Hi, thank you. I saw that solution, but If i do it over the routes, is the DevShowcaseModule code included in the prod build? I want DevShowcaseModule and his components completely removed from the prod build code. – Webworx23 May 09 '19 at 12:19
  • oh i see , if you don't want the code use this solution : https://hackernoon.com/conditional-module-imports-in-angular-518294aa4cc – Joel Joseph May 09 '19 at 12:20
  • @JoelJoseph Thank you also for the idea, but same question like for ritaj. If i do it over the routes, is the DevShowcaseModule code included in the prod build? – Webworx23 May 09 '19 at 12:21
  • @JoelJoseph ok thanks, i will take a look at the article. – Webworx23 May 09 '19 at 12:23
  • It's not included in prod build, no lazy loaded modules are included anywhere untill their routes are activated. – Roberto Zvjerković May 09 '19 at 12:24
  • @ritaj ...sounds weird, how should a module be loaded (lazy) if the code for that module is not included in the prod build? – Webworx23 May 09 '19 at 12:25
  • if you are importing the modules it means it will be added in the production build . if not specified to exclude it. You can control how it loads . it has to be part of the bundle to be lazy loaded – Joel Joseph May 09 '19 at 12:31
  • Its all about the demo module. Its not imported anywhere besides the lazy loading over the route. Thats the only place where the demo module is mentioned. In the dev we want it to be loaded, doenst matter if lazy or not. But in the prod, we dont want any piece of that demo code. – Webworx23 May 09 '19 at 12:35
  • 1
    @Webworx23 the method you specified only worked until Angular 4 i guess . after migration to angular 6 , TS seems to build any files it sees an 'import' statement for regardless of if it's in the 'exclude' property in tsconfig.json. Controlling the import seems to be the only working option as i mentioned above – Joel Joseph May 09 '19 at 12:37
  • Because that's the point of lazy loading. You don't send the code over the internet to the browser if the client will not use it. So if the route is never activated, module is never loaded. – Roberto Zvjerković May 09 '19 at 12:38
  • @ritaj Yes you are right , but he want the code to be excluded to reduce the build size while delivering the build file. So lazy loading wont help him. he will have to control the import – Joel Joseph May 09 '19 at 12:41
  • @JoelJoseph hmm thats bad. ok, thank you. I try to make the entry for the demo module in the app-routing.module.ts conditionally if possible. This seems to be the best solution. – Webworx23 May 09 '19 at 12:43

2 Answers2

9

I think you can leverage CLI fileReplacements feature like:

angular.json

"configurations": {
  "production": {
    "fileReplacements": [
      ...
      {
        "replace": "src/app/demo.routes.ts",
        "with": "src/app/demo.routes.prod.ts"
      }
    ],

demo.routes.ts

import { Routes } from '@angular/router';

export const demoRoutes: Routes = [
  {
    path: 'demo',
    loadChildren: './demo/demo.module#DemoModule'
  }
];

demo.routes.prod.ts

export const demoRoutes = [];

The root router configuration should look like:

import { demoRoutes } from './demo.routes';

RouterModule.forRoot([
  {
    path: '',
    component: HomeComponent
  },
  ...demoRoutes
])

Using this method the cli will only bundle the DemoModule in dev mode.

yurzui
  • 205,937
  • 32
  • 433
  • 399
  • 1
    Hello yurzui, thats exactly what i have planned to do, based on the suggestions from the comments above. Awesome, this is really great. Thank you very much for the complete code snippet! I will try it tomorrow... – Webworx23 May 09 '19 at 18:17
  • Hello yurzui, i have found an easier way to achieve the same result. But with less code and easier understanding for other developers. I have updated your answer. Correct me if it was the wrong way or placement. – Webworx23 May 10 '19 at 13:10
  • I think in your example on the first run cli won't be able to find lazy module so it won't be bundled because it should be statically analyzed. But on the reload(as soon as you make any changes) it will work https://monosnap.com/file/dg1ijVIWo1MhrrCUgzUgRm0fW1rzD2 – yurzui May 10 '19 at 15:06
  • Thanks. Thats true, my first test worked like you described. But in my second test i cant manage it to load the DemoModule in the dev at all. And i really would like to understand why it is working once after one reload and then even after few reloads not at all. – Webworx23 May 10 '19 at 15:13
0

This is another possible solution. PROD Mode is working fine.
The only disadvantage is, DemoModule is not loaded after ng serve. It needs a code change to start the compiler, afterwards DemoModule is loaded.

Is there any chance to load the lazy loaded DemoModule without a code change?

if(!environment.production) {
    console.log('Application is running in dev mode');
    routes.unshift(
        {
            path: APP_NAV_ITEMS.DEV_SHOWCASE,
            canActivate: [ AuthGuard ],
            loadChildren: './_demo/demo.module#DemoModule',
        },
    )
}else{
    console.log('Application is running in production mode');
}

@NgModule({
    imports: [ RouterModule.forRoot(routes, { useHash: true }) ],
    exports: [ RouterModule ]
})
export class AppRoutingModule {
}
Webworx23
  • 121
  • 2
  • 9