Serving Dynamic Images in Node.js with Typescript : A Simple Guide
Published: 2024-02-01 10:33:35

While working on a Node.js project with TypeScript, I encountered a fascinating challenge regarding serving static and dynamic image assets. Everything functioned flawlessly in the development environment, with static and dynamic assets residing in the public folder. However, upon deploying to production, an unexpected issue arose.

**The Issue**

The development setup seamlessly served static and dynamic images from the public folder. The complication emerged during the deployment process to the production environment. Here's what happened:

* As part of the deployment, the TypeScript codebase was transpiled to JavaScript. This step also involved copying all static assets from the public folder to a designated production folder.

* The static images, being part of the pre-defined assets, were successfully transferred to the production environment. They continued to load without any issues, just as they did in the development environment.

* The real problem surfaced with dynamic assets. Despite the initial setup working in development, the dynamic images failed to display in production. This was perplexing, as the deployment process didn't inherently account for assets created post-build — those dynamic images generated on the fly and intended to be served from the same public folder.

**Root Cause**

The crux of the issue lies in the deployment strategy for the TypeScript application. The build process, designed to prepare the production application, inadvertently overlooked the nature of dynamically generated assets. These assets, unlike their static counterparts, weren't part of the initial asset copying to the production folder. Consequently, when new dynamic images were created, they were not accessible in the structured production environment, leading to the observed issue of missing images.


The above problem could have been easily addressed by saving the images in external storage like S3 or Firebase storage but I wanted to solve it in the existing architecture itself. 

So this is how is solved.

**Solution**

* To address the challenge of serving dynamic assets in production, I implemented a strategy that ensures both static and dynamic images are accessible, regardless of the environment. Here's how I tackled the issue:

*  The first step was recognizing that the deployment process did not accommodate dynamically generated images. While static assets were copied to the production directory during the build process, dynamic assets created at runtime were not being served from the expected directory.

*  To ensure dynamic assets were accessible, I decided to serve them from a directory outside the build output (dist). This approach prevents dynamic assets from being overwritten or missed during the build process.

* I configured the Express server to serve static files from two directories: one for the pre-existing static assets and another for dynamic assets. Here's an example of how I set it up in Express:


```
import express from 'express';
import path from 'path';

const app = express();

var env = process.env.NODE_ENV || 'development';

if(env === "development") {
  // In development, serve static files from 'public'
  app.use('/static', express.static(path.join(__dirname, "public")));
} else {
  // In production, serve dynamic files from 'dynamic', located outside of 'dist'
  app.use('/dynamic', express.static(path.join(__dirname, '..', "dynamic")));
}


```
Key Aspects of the Solution:

Environment-Aware Configuration: By leveraging the NODE_ENV environment variable, the server dynamically adjusts its behavior based on the current environment—development or production. This ensures that the correct set of assets is served in each context.

* In the development environment, the server serves static assets from the public directory. This setup is straightforward and aligns with the typical Express.js configuration for handling static files.

* I needed a way to access the dynamic directory, which resides outside `dist`. By employing path.join(__dirname, '..', 'dynamic'), I effectively directed the server to step out of the dist directory and into the dynamic directory to serve the runtime-generated assets.

* Directory Navigation with '..': The '..' in the path plays a crucial role, instructing the server to navigate up one directory level from its current location (dist) and then into the dynamic directory. This ensures that dynamic assets generated post-deployment are accessible, without being constrained by the build output directory structure.

###Finally###

As you embark on this journey, feel free to use my [project](https://github.com/vijeth-simha/education-documents-organizer) as a practical example to follow along with the steps outlined above.

Should you encounter any challenges or have questions during the process, please don't hesitate to leave a comment below.

Feel free to reach out to me on

* [Twitter](https://twitter.com/vijeth_simha)
* [Linkedin](https://www.linkedin.com/in/vijeth-simha/)
* [Github](https://github.com/vijeth-simha)