firebasegoogle-cloud-functions

How do I lazy load dependencies for cloud functions that are split in single files?


I am trying to improve the cold start time of my firebase cloud function. As the firebase team recommends, dependencies that might not be needed can be put inside the function itself in order to only load it when it is needed. But how does this relate to the case when I already split my functions in single files? Are the dependencies I import there automatically only loaded when the function is called?


Solution

  • This is exactly the situation I address in this blog post.

    The basic strategy is to use async imports (for TypeScript) or a JavaScript require inside the function itself in order to defer the loading of the per-function script file until execution. This prevents one function's dependencies from being loaded for all functions.

    Here's what a couple functions would looks like in TypeScript:

    import * as functions from 'firebase-functions'
    
    export const httpFn =
    functions.https.onRequest(async (request, response) => {
        // Move the implementation of this function to fn/httFn.ts
        await (await import('./fn/httpFn')).default(request, response)
    })
    
    export const firestoreFn =
    functions.firestore.document("users/{id}")
    .onCreate(async (snapshot, context) => {
        // Move the implementation of this function to fn/firestoreFn.ts
        await (await import('./fn/firestoreFn')).default(snapshot, context)
    })
    

    Then, for the HTTP function, the implementation in fn/httpFn.ts looks like this:

    import * as functions from 'firebase-functions'
    import * as admin from 'firebase-admin'
    admin.initializeApp()
    
    // Note: Need to be explicit about parameter types here for HTTP
    // type functions, to support type safety and IDE assistance.
    export default async (
        request: functions.https.Request,
        response: functions.Response
    ) => {
        // Here we can use the admin SDK to get a document
        const snapshot = await admin.firestore()
            .collection('users')
            .doc('uid')
            .get()
        const data = snapshot.data()
        response.send(data)
    }
    

    In JavaScript, the strategy is the same. You would just use a require instead of await import.