Firebaseui-web: Webpack and ES6 compiling inefficiency

Created on 12 Jun 2017  路  16Comments  路  Source: firebase/firebaseui-web

Issue
When importing Firebase UI js as an ES6 module and compiling with Webpack + Babel (though I expect the same is true of a require setup) you end up with unnecessarily large filesizes.

Thoughts
There is a greedy import at the top of npm.js in the package. require('firebase') imports the entire Firebase library as a dependency. Is this necessary?

For an application only using auth the efficient way to load Firebase through modules is:

> ES6
import * as firebase from 'firebase/app';
import 'firebase/auth';

> Require
var firebase = require('firebase/app');
require('firebase/auth');

But when Firebase UI imports the entire module as a dependency, your final build will include firebase/storage and firebase/database despite those not being dependencies of Firebase UI (from what I can tell).

Proposed solution
Change the import to:

var firebase = require('firebase/app'); require('firebase/auth');

If in fact only the Auth component is needed.

Interim solution
I'm using my compiler (Webpack) to replace var firebase = require('firebase') with var firebase = require('firebase/app'); require('firebase/auth'); in Firebase UI.

Most helpful comment

Made a similar issue a while back #133 . No real response about it yet.

I must say that the way this library has been packaged is very wasteful. Also, it seems most of the other dependencies that the code uses are pre-bundled into the library, further preventing optimizations... at least from what I can see from my bundle analyser. Here's a screenshot:

image

As you can see there is just one large piece of code inside the firebaseui package called npm.js - which I assume is all the bundled up dependencies that it uses (and it is clearly a lot of code). If you look at the other libraries, you can see a much more modular approach which allows libraries to share code when there are overlaps.

BTW, the only reason my Firebase module has been pulled out and set aside, as you can see in this bundle, is because I've aligned the versions of Firebase I use to exactly what firebaseui uses - so there is no possibility of duplication. Not ideal because Firebase versioning in my app is completely at the mercy of firebaseui now.

For the seemingly simple tasks this library sets out to solve, there is way too much bloat. Considering just wrapping the basic functionality myself over the base Firebase libraries.

All 16 comments

Whoa, I came here to post exactly this same issue! Good proposed solution, too.
Unless you want to, I could do up a PR for this (assuming the admins agree). Thoughts?

Documenting here to help others find this issue and solution.
Context: firebaseui 2.1.1, firebase 4.1.2, using npm and webpack2, no CDN files

In my app's main.js, new firebaseui.auth.Auth(...) was hitting a nasty runtime error ("firebase.initializeApp is not a function") that I could finally trace to the import statement in npm.js

I already had an ES6 import in my main.js file like so (for other reasons):

import * as firebase from 'firebase/app'
import 'firebase/auth'

Switching these statements to their "require" equivalents did nothing to help and switching to the greedy import in main.js is not an option in my case.
I could not get my head around this error for a full day until I tried the change below and it finally worked flawlessly:

in npm.js :
- (function() { var firebase=require('firebase');/*
+ (function() { var firebase=require('firebase/app');/*

I don't really understand what's at work here and don't have the luxury to explore any deeper, but the greedy import seems to not mix well with the segmented imports, and I think your solution is going to fix many people's problem (i.e. all the no-CDN installations that follow the current FirebaseUI/Firebase docs, which recommend using segmented imports).

+1 for a PR, the sooner the better.

Made a similar issue a while back #133 . No real response about it yet.

I must say that the way this library has been packaged is very wasteful. Also, it seems most of the other dependencies that the code uses are pre-bundled into the library, further preventing optimizations... at least from what I can see from my bundle analyser. Here's a screenshot:

image

As you can see there is just one large piece of code inside the firebaseui package called npm.js - which I assume is all the bundled up dependencies that it uses (and it is clearly a lot of code). If you look at the other libraries, you can see a much more modular approach which allows libraries to share code when there are overlaps.

BTW, the only reason my Firebase module has been pulled out and set aside, as you can see in this bundle, is because I've aligned the versions of Firebase I use to exactly what firebaseui uses - so there is no possibility of duplication. Not ideal because Firebase versioning in my app is completely at the mercy of firebaseui now.

For the seemingly simple tasks this library sets out to solve, there is way too much bloat. Considering just wrapping the basic functionality myself over the base Firebase libraries.

bump
nobody else cares? really?!

This issue seems specific to webpack.
I was not involved in the npm packaging of FirebaseUI but I will take this one.
FirebaseUI depends on Firebase app and auth modules. There is some interest to introduce features that could depend on other Firebase services such as Storage, etc.

I just tested using auth with just the following in an node script:

var firebase = require('firebase/app');
require('firebase/auth');

Calling any auth method will throw the error:
The XMLHttpRequest compatibility library was not found.

This happens when building in a node script (firebase polyfills this for node and other environments). As this will realistically be packaged for a browser environment, we can get away with that.

We can consider this change. However, there is some low risk removing the additional modules could break existing apps that already depend on this behavior and knowing in the future we would re-introduce these currently unused dependencies.

I +1 this issue

Currently the whole firebase library is a bit large (It adds 470 KB to my un-gzipped bundle) .
The issue with firebaseui importing the whole firebase library is that we can't load only firebase-app and firebase-auth and even if we use other parts of the Firebase lib we can't lazy load them (webpack has a really cool feature for this).

Since firebaseui is likely to be one of the first part of the app to be displayed we can't lazy-load firebaseui and this means loading the while Firebase SDK upfront (not great).

btw for developers looking into how to replace the require statement using Webpack here is how:

install the string-replace-loader Webpack loader:

npm install --save-dev string-replace-loader

In your webpack.config.js add this rule:

  module: {
    rules: [
      {
        test: /npm\.js$/,
        loader: 'string-replace-loader',
        include: path.resolve('node_modules/firebaseui/dist'),
        query: {
          search: 'require(\'firebase\');',
          replace: 'require(\'firebase/app\');require(\'firebase/auth\');',
        }
      }
    ]
  }

Just sent a PR to fix the NPM distro: https://github.com/firebase/firebaseui-web/pull/205

IMO given the size of the Firebase SDK we should only load what's needed for now and make further features that would use other parts of the SDK modular.

Looks like some of your tests are failing, hoping you can clean those up since I'd love to see this make it's way in soon!

Fixed it 2 weeks ago although now we need to wait for the next release to take advantage of it :)

Just a quick correction to @nicolasgarnier's string-replace-loader fix for those wondering why it didn't work:

module: {
  rules: [
    {
      test: /npm\.js$/,
      loader: 'string-replace-loader',
      include: path.resolve('node_modules/firebaseui/dist'),
      query: {
        search: 'var firebase=require(\'firebase\');',
        replace: 'var firebase=require(\'firebase/app\');require(\'firebase/auth\');',
      }
    }
  ]
}

FWIW I'll probably still go with the CDN links to avoid double-including firebase (and whatever else is in npm.js that I happen to be already bundling).

Thanks @tclift. I updated my code above :)

Is this fix released yet ?
Still having that huge npm.js with firebaseui 2.6.2

Just posting that firebaseui is still a very large package (60kb gzipped) and I feel downsizing this should be a priority. It's by far the largest package I'm using, next to the firebase library itself.

Our upcoming efforts will be focused on modularizing the core SDK first. We will look into downsizing FirebaseUI afterwards.

still happening!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

drixie picture drixie  路  3Comments

polo13999 picture polo13999  路  3Comments

jin-chong picture jin-chong  路  5Comments

JarmoKukkola picture JarmoKukkola  路  4Comments

joshkuhar picture joshkuhar  路  5Comments