Search code examples
typescriptnpmwebpackangular-cling-packagr

NPM package is not imported in angular production app


Goal

I'm trying to deliver a typescript module augmentation of rxjs as an npm package to be used in Angular projects.

Problem

Using the package in an Angular app works fine in local dev mode but once the app is built for production the package is not being imported in the final dist.

Details

  • Mostly the augmentation is providing a new method : Observable.safeSubscribe()
    (complete source code here: ngx-safe-subscribe.ts)

    import { Observable, Subscription } from 'rxjs';
    
    declare module 'rxjs/internal/Observable' {
        interface Observable<T> {
            safeSubscribe: typeof safeSubscribe;
        }
    }
    
    export function safeSubscribe<T>(...): Subscription {
        ...
    }
    Observable.prototype.safeSubscribe = safeSubscribe;
    
  • The package is built with ng-packagr

  • Once imported and used in an Angular project, everything works fine:
    (complete demo here: demo)

    import { Component, OnDestroy } from '@angular/core';
    import { of } from 'rxjs';
    import '@badisi/ngx-safe-subscribe';
    
    @Component({
        selector: 'my-app',
        templateUrl: './app.component.html'
    })
    export class AppComponent implements OnDestroy  {
        constructor() {
            of([]).safeSubscribe(this, () => { console.log('ok'); });
        }
        ngOnDestroy(): void {}
    }
    
  • Once built for production the package is not imported in the final dist:

    ng serve --prod
    
    [error in console]: TypeError: Object(...)(...).safeSubscribe is not a function
    
  • My last attempts were made with everything latest

    [email protected], [email protected], [email protected]
    
  • On a side note, using the named import style in Visual Studio Code results in the following:

    import { safeSubscribe } from '@badisi/ngx-safe-subscribe';
    
    [ts] 'safeSubscribe' is declared but its value is never read. 
    

It's hard to tell if the problem comes from typescript, angular-cli, webpack or even ng-packagr not being able to recognize the augmentation and properly import it in the final dist.

So any help would be very very appreciated!
Thanks.


Solution

  • Found the answer myself but not without difficulties..

    Quick answer

    Add the following property to the npm package:

    package.json {
        sideEffects: true
    } 
    

    Explanation

    The issue was related to ng-packagr that sets sideEffects:false in the dist version of the package.json file.

    This is recommended setting by the Angular Package Format v6 to optimize the distribution bundle:

    "Packages that contain this property set to false will be processed by webpack more aggressively than those that don't. The end result of these optimizations should be smaller bundle size and better code distribution in bundle chunks after code-splitting" [source]

    When set to false only real used portion of code will be bundled. However in my case the augmentation is recognized as "declared but never read" thus being ignored during the build process. With sideEffects sets to true webpack will simply bundle the whole package unquestioningly.