Search code examples
webpackvue-cli

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?


Solution

  • 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.