Tips for creating TypeScript Google Cloud Functions using webpack

I'm currently facing a challenge while coding a Google Cloud Function using TypeScript. The concept involves having handler functions defined for various Cloud Functions in separate files within the source repository, along with some code that is shared among all handlers. After compiling my sources with tsc, I realized the need to webpack them in order to generate a single index.js file that can be loaded by Cloud Functions. Consequently, I require webpack to merge all handlers into one file.

Below is my configuration file tsconfig.json:

{
  "compilerOptions": {
    "incremental": true,
    "target": "es2016",
    "module": "commonjs",
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "noImplicitAny": true,
    "noImplicitThis": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "moduleResolution": "node"
  },
  "include": ["src/**/*.ts"]
}

Shown below is the code for a handler from src/TheHandler.ts:

import { EventFunction } from "@google-cloud/functions-framework";

export const TheHandler: EventFunction = (
  message,
  context
) => {
  console.log(message);
  console.log(context);
};

The above code compiles to JavaScript without encountering any issues.

However, upon feeding it into webpack, using the following webpack.config.js:

const path = require("path");
const fs = require("fs");
const nodeExternals = require("webpack-node-externals");

const files = fs
  .readdirSync("src")
  .filter((item) => item.match(/\.ts$/))
  .map((file) => `./src/${file}`);

module.exports = {
  mode: "production",
  entry: files,
  externalsPresets: { node: true },
  externals: [nodeExternals()],
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: "ts-loader",
        exclude: /node_modules/,
      },
    ],
  },
  resolve: {
    extensions: [".ts"],
  },
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
};

The result is an empty dist/bundle.js, as confirmed by the webpack output:

asset bundle.js 0 bytes [compared for emit] [minimized] (name: main)
./src/TheHandler.ts 612 bytes [built] [code generated]
webpack 5.50.0 compiled successfully in 1937 ms

Could this issue be related to the module format or webpack attempting to bundle everything before ts-loader compiles src/TheHandler.ts? Or could it be something else entirely?

Answer №1

In order to make it work, I included the line

libraryTarget: "commonjs2"
inside the output section of my webpack.config.js.

Answer №2

In your exploration, you discovered that setting the libraryTarget parameter is crucial to create a webpack bundle that can be imported by external modules outside of the webpack build (such as cloud functions).

If you're looking for a smoother experience and improved developer productivity with reliable Hot Module Replacement (HMR), you might consider using webpack-cloud-functions (which happens to be developed by me). This tool simplifies much of the webpack configuration required for working with cloud functions, including handling the libraryTarget.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

typescript create object with immutable property already set

Can you create an object literal in JavaScript and define its interface with read-only properties simultaneously? For instance let obj = { readonly prop1: 'hello', readonly prop2: 'world' } ...

Conditional type/interface attribute typing

Below are the interfaces I am working with: interface Movie { id: number; title: string; } interface Show { title: string; ids: { trakt: number; imdb: string; tmdb?: number; }; } interface Props { data: Movie | Show; inCountdown ...

having difficulty accessing the value within the Angular constructor

My current issue arises when I click on a button and set a value within the button click method. Despite declaring the variable in the constructor, I am unable to retrieve that value. The code snippet below demonstrates this problem as I keep getting &apos ...

What is the equivalent of defining conditional string types in Typescript similar to flow?

type UpsertMode = | 'add' | 'update' | 'delete'; interface IUpsertMembers { mode: UpsertMode; } const MagicButton = ({ mode: UpsertMode }) => { return ( <button>{UpsertMode}</button> ); } const Upse ...

In Deno, it is possible to confirm that a variable is an instance of a String

I'm having trouble asserting instances of string in Deno: import { assertInstanceOf } from "https://deno.land/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2642405050405e445e59445e">[email protected]</a& ...

Matching TypeScript against the resulting type of a string literal template

My type declaration looks like this: type To_String<N extends number> = `${N}` I have created a Type that maps the resulting string number as follows: type Remap<Number> = Number extends '0' ? 'is zero' : Number ...

Vue 3 app encountering error due to element having an 'any' type implicitly

I want to incorporate lucidev icons into my component, but I am fairly new to typescript. You can find the lucidev icons here: https://github.com/lucide-icons/lucide <template> <component :is="icon" /> </template> <script ...

Maximizing Jest's potential with multiple presets in a single configuration file/setup

Currently, the project I am working on has Jest configured and testing is functioning correctly. Here is a glimpse of the existing jest.config.js file; const ignores = [...]; const coverageIgnores = [...]; module.exports = { roots: ['<rootDir&g ...

Choose a specific div element from a collection of dynamically generated divs in Angular

I have been working on a code to dynamically generate div elements using the *ngFor directive. Here is what I have so far: <div *ngFor = "let item of Items"> <p>Item : {{item}} </p> </div> The challenge I encountered is that w ...

Why does my Visual Studio Code always display "building" when I launch an extension?

https://code.visualstudio.com/api/get-started/your-first-extension I followed a tutorial to create a hello world extension. Why does my VSCode always display 'building' when I run the extension? Executing task: npm run watch < [email p ...

Navigating from a Card to a new View in Angular

I am currently developing a project using Angular (latest version). Within my application, I have the functionality to dynamically generate bootstrap cards from an Order Array and display them in my "Order-Item-Component through its respective template. ...

We could not find the requested command: nodejs-backend

As part of my latest project, I wanted to create a custom package that could streamline the initial setup process by using the npx command. Previously, I had success with a similar package created with node.js and inquirer. When running the following comma ...

Unable to access the redux store directly outside of the component

When trying to access my store from a classic function outside the component, I encountered an error while calling getState(): Property 'getState' does not exist on type '(initialState: any) => any' Below is the declaration and im ...

Convert TypeScript model to JSON while excluding properties with null values

When working with an Angular 4 App and a typescript model, I have defined a Person class as follows: export class Person{ fname:string, lname?:string } The 'lname' property in the model is optional. To populate the model in a component, I u ...

How to Pass Data as an Empty Array in Angular 6

After successfully implementing a search function that filters names from an array based on user input, I encountered an issue when trying to make the searchData dynamic by fetching it from a Firebase database: getArray(): void { this.afDatabase.list( ...

Set up webpack to select jquery.min.js over jquery.js located in the node_modules directory

Can webpack be instructed to use `jquery.min.js` instead of `jquery.js` from the `node_modules/jquery` directory when generating the `bundle.js` file? ...

Webpack Plugin System for Building Web Applications

In the context of my project, I am currently working on a product utilizing Symfony for the back-end and react/react-router for the front-end, all connected via Webpack. My plan is to structure my app into different "extensions", which would consist of a " ...

Ways to incorporate forms.value .dirty into an if statement for an Angular reactive form

I'm a beginner with Angular and I'm working with reactive Angular forms. In my form, I have two password fields and I want to ensure that only one password is updated at a time. If someone tries to edit both Password1 and Password2 input fields s ...

Typescript function incorrectly returns Protractor's "element.all" output as Promise<string> instead of Promise<string[]>

Kindly review the code snippet provided below. The function getAllGroupIds() is designed to return an array of IDs belonging to "group" elements. The goal is to retrieve all the group-ids both before and after a test action, in order to compare them. Howe ...

I'm struggling to figure out how to specify the data type for storing an array of objects in a variable using React.useState

I am currently working on extracting values from an .xlsx file using the SheetJS library. Below, I will provide the code snippets, errors encountered, and the different approaches I have attempted. Data extracted from var dataToJson: (6) [{…}, {…}, { ...