Ilja
Ilja

Reputation: 46479

How to build / compile firebase cloud functions with webpack

I am using webpack to build my cloud functions (several reasons to this as path aliases, typescript and some other configs)

I have my index.ts file as well as src folder containing individual files for each function.

My index.ts file then exports them like this

import admin from 'firebase-admin';

admin.initializeApp();

export const func1 = require('./src/func1').default;
export const func2 = require('./src/func2').default;

The issue with webpack compared to something like tsc is that it requires all the code from required files and bundles it in index file, which for cloud functions is not ideal due to cold start performance.

What would be correct way to split these files into separate ones and ensure good cold start performance (i.e. only code for function that is being called is required).

My webpack config for firebase looks like this

const config = {
  entry: {
    index: path.resolve(__dirname, './index.ts')
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, './dist'),
    libraryTarget: 'commonjs'
  },
  mode: 'production',
  optimization: {
    nodeEnv: 'production',
    splitChunks: {
      chunks: 'all'
    },
    minimize: true,
    minimizer: [
      new ESBuildMinifyPlugin({
        target: 'es2020',
        minifyWhitespace: true,
        minifyIdentifiers: true,
        minifySyntax: true
      })
    ]
  },
  resolve: {
    alias: {
      $tools: path.resolve(__dirname, '../../tools'),
      $types: path.resolve(__dirname, '../../types')
    },
    extensions: ['.tsx', '.ts', '.js', '.mjs', '.json']
  },
  externals: ['firebase-functions', 'firebase-admin'],
  target: 'node',
  module: {
    rules: [
      {
        test: /\.(m?js|ts)$/u,
        exclude: /(node_modules)$/u,
        use: {
          loader: 'esbuild-loader',
          options: {
            loader: 'ts',
            target: 'es2020',
            tsconfigRaw: require('./tsconfig.json')
          }
        }
      }
    ]
  },
  plugins: [new CleanWebpackPlugin(), new ESBuildPlugin()]
};

Upvotes: 3

Views: 1287

Answers (2)

Ilja
Ilja

Reputation: 46479

Here is solution I was able to cook up.

First, make each function its own entry in webpack, you can do so manually or via something like this

const fs = require('fs');
const path = require('path');

// Get all functions and store their names in an array, based on filename, use .js instead of .ts if thats your case
const functions = fs.readdirSync('./src').map(file => file.split('.ts')[0]);

// Add all functions to entries object
const entries = {};
functions.forEach(file => {
  entries[file] = path.resolve(__dirname, `src/${file}.ts`);
});

// Finally add your index file to entries object (if it is not already in src folder together with functions)
entries.index = path.resolve(__dirname, './index.ts');

// Use this in your webpack congig
const config = {
 entry: entries,
 // ...
}

This will result in something like this

dist/
  func1.js
  func2.js
  index.js

Then in your index file use non_webpack_require, this way webpack keeps them as require() in compiled code. Export all your functions, remember that each file will be at the root of the compiled folder.

import admin from 'firebase-admin';

admin.initializeApp();

export const func1 = __non_webpack_require__('./func1');
export const func2 = __non_webpack_require__('./func2');

Upvotes: 3

guillaume blaquiere
guillaume blaquiere

Reputation: 75745

The principle of webpack is to tranform and optimise the JS, to minimize it and to pack it into a single file (for browser download optimization for example, not the topic here).

In your case, you have only 1 entry point. Webpack will follow all the dependencies and pack them into the same file.

The solution here is to have 2 separate/independant entry points, and like this you will have 2 output files. But sometime it's boring to do this because you want to mutualize some part of the code/initialization. It's always a matter of tradeoff

Upvotes: 0

Related Questions