How to make Angular 8 build faster while library development

Viewed 47

I have an Angular application and it is structured in a way that each of the different feature is built as a library and integrated with the host application. So for leave management I have a library and same for user management, project management etc. Now in the development stage, I use the following command to build the library.

ng build --project my-ng-lib-project-management --watch

This shows following output

Building Angular Package

------------------------------------------------------------------------------
Building entry point 'my-ng-lib-project-management'
------------------------------------------------------------------------------
Compiling TypeScript sources through ngc

Bundling to FESM2015

WARNING: 'FormGroup' is imported from external module '@angular/forms' but never used
WARNING: 'TreeTable' and 'OverlayPanel' are imported from external module 'primeng/primeng' but never used

Bundling to FESM5

WARNING: 'FormGroup' is imported from external module '@angular/forms' but never used
WARNING: 'TreeTable' and 'OverlayPanel' are imported from external module 'primeng/primeng' but never used
Bundling to UMD
WARNING: No name was provided for external module 'my-ng-lib-core' in output.globals – guessing 'myNgLibCore'
WARNING: No name was provided for external module 'util' in output.globals – guessing 'util'
WARNING: No name was provided for external module 'primeng/api' in output.globals – guessing 'api'
WARNING: No name was provided for external module '@ngx-translate/core' in output.globals – guessing 'core$1'
WARNING: No name was provided for external module 'my-ng-lib-dms' in output.globals – guessing 'myNgLibDms'
WARNING: No name was provided for external module 'moment' in output.globals – guessing 'moment_'
WARNING: No name was provided for external module 'jspdf' in output.globals – guessing 'jsPDF'
WARNING: No name was provided for external module 'html2canvas' in output.globals – guessing 'html2canvas'
WARNING: No name was provided for external module 'primeng/primeng' in output.globals – guessing 'primeng'
WARNING: No name was provided for external module 'ngx-daterangepicker-material' in output.globals – guessing 'ngxDaterangepickerMaterial'
WARNING: No name was provided for external module 'primeng/table' in output.globals – guessing 'table'
WARNING: No name was provided for external module '@ng-bootstrap/ng-bootstrap' in output.globals – guessing 'ngBootstrap'
WARNING: No name was provided for external module 'my-ng-lib-user-mgmt' in output.globals – guessing 'myNgLibUserMgmt'
WARNING: No name was provided for external module 'my-ng-lib-organisation-setup' in output.globals – guessing 'myNgLibOrganisationSetup'
WARNING: No name was provided for external module 'primeng/editor' in output.globals – guessing 'editor'
WARNING: No name was provided for external module 'primeng/inputswitch' in output.globals – guessing 'inputswitch'
WARNING: No name was provided for external module 'primeng/dropdown' in output.globals – guessing 'dropdown'
WARNING: No name was provided for external module 'primeng/button' in output.globals – guessing 'button'
WARNING: No name was provided for external module 'primeng/radiobutton' in output.globals – guessing 'radiobutton'
WARNING: No name was provided for external module 'primeng/inputtext' in output.globals – guessing 'inputtext'
WARNING: No name was provided for external module 'primeng/autocomplete' in output.globals – guessing 'autocomplete'
WARNING: No name was provided for external module '@fullcalendar/daygrid' in output.globals – guessing 'dayGridPlugin'
WARNING: No name was provided for external module '@fullcalendar/timegrid' in output.globals – guessing 'timeGridPlugin'
WARNING: No name was provided for external module '@fullcalendar/interaction' in output.globals – guessing 'interactionPlugin'
WARNING: No name was provided for external module 'primeng/fullcalendar' in output.globals – guessing 'fullcalendar'
WARNING: No name was provided for external module 'primeng/fileupload' in output.globals – guessing 'fileupload'
WARNING: No name was provided for external module 'my-ng-lib-common' in output.globals – guessing 'myNgLibCommon'
WARNING: No name was provided for external module 'primeng/multiselect' in output.globals – guessing 'multiselect'
WARNING: No name was provided for external module 'my-ng-lib-accounts-project' in output.globals – guessing 'myNgLibAccountsProject'
WARNING: No name was provided for external module 'primeng/toast' in output.globals – guessing 'toast'
WARNING: No name was provided for external module 'primeng/inputtextarea' in output.globals – guessing 'inputtextarea'
WARNING: No name was provided for external module 'primeng/messages' in output.globals – guessing 'messages'
WARNING: No name was provided for external module 'primeng/message' in output.globals – guessing 'message'
WARNING: No name was provided for external module 'primeng/dragdrop' in output.globals – guessing 'dragdrop'
WARNING: No name was provided for external module 'primeng/paginator' in output.globals – guessing 'paginator'
WARNING: No name was provided for external module 'ngx-pagination' in output.globals – guessing 'ngxPagination'
WARNING: No name was provided for external module 'primeng/treetable' in output.globals – guessing 'treetable'
WARNING: No name was provided for external module 'primeng/tabview' in output.globals – guessing 'tabview'
WARNING: No name was provided for external module 'primeng/tree' in output.globals – guessing 'tree'
WARNING: No name was provided for external module 'primeng/scrollpanel' in output.globals – guessing 'scrollpanel'
WARNING: No name was provided for external module 'primeng/accordion' in output.globals – guessing 'accordion'
WARNING: No name was provided for external module 'primeng/dialog' in output.globals – guessing 'dialog'
WARNING: No name was provided for external module 'primeng/slider' in output.globals – guessing 'slider'
WARNING: No name was provided for external module 'primeng/overlaypanel' in output.globals – guessing 'overlaypanel'
WARNING: No name was provided for external module 'primeng/confirmdialog' in output.globals – guessing 'confirmdialog'
WARNING: No name was provided for external module 'primeng/inputmask' in output.globals – guessing 'inputmask'
WARNING: No name was provided for external module 'primeng/keyfilter' in output.globals – guessing 'keyfilter'
WARNING: No name was provided for external module 'primeng/selectbutton' in output.globals – guessing 'selectbutton'
WARNING: No name was provided for external module 'primeng/sidebar' in output.globals – guessing 'sidebar'
WARNING: No name was provided for external module 'primeng/calendar' in output.globals – guessing 'calendar'
WARNING: No name was provided for external module 'ngx-bootstrap/datepicker' in output.globals – guessing 'datepicker'
WARNING: No name was provided for external module 'ngx-bootstrap/utils' in output.globals – guessing 'utils'
WARNING: No name was provided for external module 'primeng/components/calendar/calendar' in output.globals – guessing 'calendar$1'
WARNING: No name was provided for external module 'primeng/checkbox' in output.globals – guessing 'checkbox'
WARNING: No name was provided for external module 'ng2-pdf-viewer' in output.globals – guessing 'ng2PdfViewer'

WARNING: Creating a browser bundle that depends on Node.js built-in module ('util'). You might need to include https://www.npmjs.com/package/rollup-plugin-node-builtins

Minifying UMD bundle

Copying declaration files

Writing package metadata

Built my-ng-lib-project-management

------------------------------------------------------------------------------
Built Angular Package!
 - from: /path/my-ng-lib-project-management/projects/my-ng-lib-project-management
 - to:   /path/my-ng-lib-project-management/dist/my-ng-lib-project-management
------------------------------------------------------------------------------

Compilation complete. Watching for file changes...

and then I use

ng serve --aot to start the development server.

10% building 3/3 modules 0 active(node:28389) [DEP0131] DeprecationWarning: The legacy HTTP parser is deprecated.
ℹ 「wds」: Project is running at http://localhost:4200/webpack-dev-server/
ℹ 「wds」: webpack output is served from /
ℹ 「wds」: 404s will fallback to //index.html

chunk {0} 0.js, 0.js.map () 30.4 kB  [rendered]
chunk {1} 1.js, 1.js.map () 48.4 kB  [rendered]
chunk {2} 2.js, 2.js.map () 66.5 kB  [rendered]
chunk {3} 3.js, 3.js.map () 6.08 kB  [rendered]
chunk {4} 4.js, 4.js.map () 16.5 kB  [rendered]

The issue here is in the development phase, the build is taking more than a minute to finish after a code change and then the ng serve is taking another 1.5 minutes. Especially in the ng serve command,

14% building 34/41 modules 7 active ...odules/webpack/hot sync nonrecursive /^\.\/log$/ is taking a lot of time to get finished.

I am using Angular 8 for this project. Now is there any better workflow or how can I make the build process fast ?

1 Answers

For those who do not want to build/install many library modules just to debug the app project, One trick is to statically link app to libraries using Typescript path aliases that work only in development mode.

This way when the app project is built/served in development mode, the libraries are considered to be part of app sources and need not be compiled separately.

Exposing angular library sources:

Place a file called index.ts just next to the public-api.ts:

myNgLibrary
 |_src
    |_public-api.ts
    |_index.js

And set the content of index.ts to:

export * from './public-api';

Note that index.ts is never really going to be compiled or part of the library. This is because ng-packager uses public-api.ts as entry point. However, it exposes the library API from path: myNgLibrary/src, which we will use in the next step.

Adding a lookup path in Angular application:

Now take a moment to read about the Typescript Path Mapping feature, It essentially says that compiler can be told to look into additional locations when resolving a module (import).

The angular app project should have a tsconfig.json. By default, angular CLI creates several for an app project:

tsconfig.app.json
tsconfig.json
tsconfig.spec.json

Depending on your setup, one of these will be there in angular.json, used for compiling the app (tsconfig.app.json for example). After determining which tsconfig is used for app compilation, we make a copy of it, for example: tsconfig.app.dev.json. It would differ from original tsconfig in one respect:

  "compilerOptions": {
    "paths": {
      "@myOrg/myNgLibrary": [
        "local/path/to/myNgLibrary/src"
      ]
    }
  }

This path mapping will cause compiler to look into local library project sources when it tries to resolve @myOrg/myNgLibrary. Now you can compile the app project and compiler will take library sources from local projects instead of node_modules.

But we don't want this to happen for production builds, so, update the angular.json's architect/build/configuration with:

"configurations": {
  "production": {
    "tsConfig": "./tsconfig.app.json"
  },
  "development": {
    "tsConfig": "./tsconfig.app.dev.json"
  }
}

Now in development mode, @myOrg/myNgLibrary is resolved from library project sources. In production mode there is no such path mapping in the other tsconfig and @myOrg/myNgLibrary is resolved from its installed path: node_modules.

You can also add additional lookup paths for css styles via configuring in angular.json:

"stylePreprocessorOptions": {
   "includePaths": [
    "local/path/to/myNgLibrary/src/styles"
   ]
}
Related