angularfire icon indicating copy to clipboard operation
angularfire copied to clipboard

Bundle includes unused firebase modules with the new angularfire API

Open blasco opened this issue 4 years ago • 3 comments

Version info

Angular: 13.0.0

Firebase: 9.4.1

AngularFire: 7.2.0

How to reproduce these conditions

I'm using the new angular fire API and I see great improvements in comparison with the old compat api regarding bundle size. Nevertheless I still see in the final bundle that it includes some things (like analytics, app-check, messaging) that I'm not using.

These functions are never imported in the code, and my firebase module looks like this:

import { NgModule } from '@angular/core';
import { environment } from 'src/environments/environment';
import { getApp, initializeApp, provideFirebaseApp } from '@angular/fire/app';
import { 
  provideAuth, initializeAuth, browserPopupRedirectResolver, 
  indexedDBLocalPersistence 
} from '@angular/fire/auth';
import { getFirestore, provideFirestore } from '@angular/fire/firestore';
import { getFunctions, provideFunctions  } from '@angular/fire/functions';
import { getStorage, provideStorage } from '@angular/fire/storage';
import { 
  connectAuthEmulatorInDevMode, 
  connectFirestoreEmulatorInDevMode, 
  connectFunctionsEmulatorInDevMode, 
  connectStorageEmulatorInDevMode 
} from './emulators';

@NgModule({
  imports: [
    provideFirebaseApp(() => initializeApp(environment.firebase)),
    provideFirestore(() => {
      const firestore = getFirestore();
      if (environment.firebase.localEmulator) {
        connectFirestoreEmulatorInDevMode(firestore);
      }
      return firestore;
    }),
    provideFunctions(() => {
      const functions = getFunctions();
      if (environment.firebase.localEmulator) {
          connectFunctionsEmulatorInDevMode(functions);
      }
      return functions;
    }),
  ]
})
export class FirebaseModule {}

@NgModule({
  imports: [
    provideStorage(() => {
      const storage = getStorage();
      if (environment.firebase.localEmulator) {
          connectStorageEmulatorInDevMode(storage);
      }
      return storage;
    }),
    provideAuth(() => {
      const auth = initializeAuth(getApp(), {
        persistence: indexedDBLocalPersistence,
        popupRedirectResolver: browserPopupRedirectResolver,
      });
      if (environment.firebase.localEmulator) {
        connectAuthEmulatorInDevMode(auth);
      }
      return auth;
    })
  ]
})
export class FirebaseBrowserModule {}

As I'm using only storage, firestore, functions, and auth, I would expect to only see that in the generated bundle:

image

It seems that the other modules are being included.

Is this the expected behavior? I thought that the new structure allowed to actually prevent this.

Also, is that a normal firestore bundle size? I'm using only these:

import { 
  collection, doc, docData, Firestore, query, collectionSnapshots, 
  DocumentSnapshot, QueryDocumentSnapshot, DocumentData, updateDoc, setDoc, 
  DocumentReference, UpdateData, addDoc, deleteDoc, QueryConstraint 
} from '@angular/fire/firestore';

For reference I include here the same app, but with the compat API:

image

So the improvement is already quite good, from 167 KB to 113 KB. I hope there is still room for improvement.

blasco avatar Nov 24 '21 11:11 blasco

Are you building for production? E.g, tree-shaking? Otherwise unnecessary modules will not be stripped

jamesdaniels avatar Dec 07 '21 18:12 jamesdaniels

Yes I think I am. This is the command I'm using to build:

ng build --configuration=production --source-map --named-chunks=true

And this is the production configuration in my angular.js:

"production": {
    "deleteOutputPath": false,
    "aot": true,
    "optimization": true,
    "outputHashing": "all",
    "sourceMap": false,
    "namedChunks": false,
    "extractLicenses": true,
    "vendorChunk": false,
    "buildOptimizer": true,
    "budgets": [
        {
            "type": "initial",
            "maximumWarning": "500kb",
            "maximumError": "1mb"
        },
        {
            "type": "anyComponentStyle",
            "maximumWarning": "2kb",
            "maximumError": "7kb"
        }
    ],
    "serviceWorker": true,
    "ngswConfigPath": "ngsw-config.json",
    "fileReplacements": [
        {
            "replace": "src/environments/environment.ts",
            "with": "src/environments/environment.prod.ts"
        },
        {
            "replace": "src/app/modules/firebase/emulators.ts",
            "with": "src/app/modules/firebase/emulators.prod.ts"
        }
    ]
}

Am I missing some option?

blasco avatar Dec 07 '21 18:12 blasco

Hey, were you able to figure the issue?

DogAndDoll avatar Feb 23 '22 20:02 DogAndDoll

I am using "firebase": "9.15.0" and "@angular/fire": "7.5.0" with 100% modular imports (no compat imports left), via a standalone component (killed all modules in favor of standalone). I can observe the same problem: my prod build still contains messaging, remote config, app-check, which are never used anywhere in my app.

Judp0m avatar Dec 26 '22 08:12 Judp0m

Any updates? Same problem here.

kkachniarz220 avatar Jan 27 '23 09:01 kkachniarz220

in https://github.com/angular/angularfire/blob/master/src/core.ts#L4

import { isSupported as isRemoteConfigSupported } from 'firebase/remote-config';
import { isSupported as isMessagingSupported } from 'firebase/messaging';
import { isSupported as isAnalyticsSupported } from 'firebase/analytics';

this is the root cause of the problem and since this is in the core package, importing anything will lead to importing 50 KB of totally unused code

robertIsaac avatar May 29 '23 00:05 robertIsaac

@davideast for the app-check the problem is in this kind of import inside almost every module https://github.com/angular/angularfire/blob/master/src/auth/auth.module.ts#L63 is there a way to fix it? I'm thinking to move it to core, and use it from core everywhere

robertIsaac avatar Jun 27 '23 11:06 robertIsaac