Moritz
Moritz

Reputation: 1125

How to externalize a lib with vue-cli

In my vue-cli project (@vue/cli 4.4.4), I want to exclude firebase at build time and include it at runtime (via index.html).

In my package.json I have those imports

{
 ...
 "dependencies": {
   ...
    "firebase": "^7.24.0",
    "firebaseui": "^4.7.1"
  },
}

which I want to exclude from the build. Research in Google / SO had me include those lines in my vue.config.js:

module.exports = {
 ...
  configureWebpack: {
    externals: {
      firebaseui: "firebaseui",
      firebase: "firebase",
    },
  }
};

And also in webpack.config.js:

module.exports = {
  externals: {
    firebase: "firebase",
    firebaseui: "firebaseui",
  },
};

This, however, does not work. Firebase is still included in the generated js files in the dist/js folder.

How can I use webpack's exclude feature from vue-cli to bundle only my own code with some small deps?

Upvotes: 1

Views: 1944

Answers (1)

zxcsv
zxcsv

Reputation: 71

I also stumbled upon this question. Firebase Web SDK is quite large when bundled.

What I did:

Imported Firebase Web SDK via their CDN and placed it in the public/index.html:

<!-- public/index.html -->
<head>
  ...

  <title>...</title>

  <!-- Firebase App, then all other used services in your app -->
  <script src="https://www.gstatic.com/firebasejs/8.3.1/firebase-app.js"></script>
  <script src="https://www.gstatic.com/firebasejs/8.3.1/firebase-auth.js"></script>
  <script src="https://www.gstatic.com/firebasejs/8.3.1/firebase-firestore.js"></script>

  <!-- Firebase UI -->
  <script src="https://www.gstatic.com/firebasejs/ui/4.8.0/firebase-ui-auth.js"></script>
</head>

Create a src/firebase.js as a single entry point to initialize my firebase.

// src/firebase.js
import "firebase/app";

const firebaseConfig = {
    ...
};

firebase.initializeApp(firebaseConfig);

export default firebase;

Then imported it in my src/main.js file, before mounting the app.

// src/main.js
import "@/firebase.js"; // @ is shorthand to /src

import { createApp } from "vue";
...

Use Webpack Externals to map the global firebase exposed by the CDN to any imports with "firebase/app". We do not need to import other services (i.e. auth, firestore) in the vue files since it will be provided by the CDN.

// vue.config.js
module.exports = {
  ...
  chainWebpack: (config) => {
    config.externals({
      "firebase/app": "firebase",
      firebaseui: "firebaseui",
    });
  },
  ...
};

Notice that I didn't include a name for the default export of the imports above. Doing so by naming it also as firebase (to get intellisense to work) throws me a warning in the browser: Firebase is already defined in the global scope. You could either:

  • Use a different name for the import, such as: import fb from "firebase/app". This will enable intellisense to work when using fb.<restOfObject>

  • Or just don't include a name if you're just about to deploy the app and don't need the intellisense.

Either way, all of the firebase.<restOfObject> functions will work on your code, since the Webpack Externals will map the firebase global name exposed by the CDN to all your imports with firebase/app.

All other components have access now to the global firebase object even without importing.

// Sample of a .vue file
<script>
const auth = firebase.auth(); // this still works

const ui = new firebaseui.auth.AuthUI(auth); // this too

export default {
  data() {
      ...
  }
};
</script>

Vue Build Size

webpack-bundle-analyzer Result

References

There might be mistakes in what I indicated here. Any improvement to this answer is appreciated. This is my first answer and I hope I could help.

Upvotes: 2

Related Questions