Serve local files using a flow
In some cases, you may want to serve local project files (e.g., CSS, JavaScript, images) directly from your Node-RED flow rather than using a static folder configuration. While the Serving Static Files approach works, it tightly couples your project to an absolute path, making it hard to relocate.
Using a flow to serve files from your project folder provides more flexibility and keeps the project self-contained.
Prerequisites
Define an environment variable pointing to your project directory:
If using Node-RED Projects:
ENV_PROJECT_A = C:\ProgramData\Objectif Lune\OL Connect Automate\projects\project_a
If not using Projects (User Data Folder):
ENV_PROJECT_A = C:\ProgramData\Objectif Lune\OL Connect Automate\projects\project_a
Assume the static resources are stored under a subfolder called assets, e.g.:
assets/
├── styles.css
├── javascripts.js
└── logo.png
Note: While you could include assets in the environment variable path itself, keeping it separate allows for more modular and extensible setups.
Flow setup
Create the end point
Insert an http in node, configured to set the Method to GET and URL to:
/assets/:resource
This sets up a route where :resource is a path variable (e.g. styles.css). The requested filename will be available as msg.req.params.resource.
Load the file
Add a read file name and set the filename using a JSONata expression:
$env("ENV_PROJECT_A") & "\\assets\\" & msg.req.params.resource
This dynamically reads the requested file from the local assets folder.
Set the Content-Type header
The HTTP Content-Type header is used to indicate the original media type of a resource before any content encoding is applied. The Content-Type header informs the client about the media type of the returned data and is essential for browsers to interpret resources properly.
In our scenario we will set this dynamically based on the file extension of the requested file. Add a function node after the file read to assign the correct Content-Type header based on the file extension.
const resource = msg.req.params.resource; // the name of the requested file resource
const ext = resource.split('.').pop().toLowerCase(); // get the file extenion without the dot
const mimeTypes = {
'css' : 'text/css',
'js' : 'application/javascript',
'html': 'text/html',
'json': 'application/json',
'png' : 'image/png',
'jpg' : 'image/jpeg',
'jpeg': 'image/jpeg',
'svg' : 'image/svg+xml'
};
msg.headers = {
'Content-Type': mimeTypes[ext] || 'application/octet-stream' // fall back to octet-stream for unknown types
};
return msg;
Result
When you navigate to:
http://localhost:1880/assets/styles.css
OL Connect Automate:
-
Reads
styles.cssfrom the localassetsfolder (underENV_PROJECT_A). -
Serves it with the correct
Content-Typeheader (text/css).
This makes your project more portable and avoids hardcoded file paths outside the flow logic.