Make files public
Learn how to serve static assets, shared folders, and manual file responses.
Overview
Most of the time, JopiJS handles file exposure automatically. However, there are cases where you need more control, such as serving global assets or creating a custom file server.
In this guide, you will learn:
- How JopiJS automatically handles CSS and images.
- How to use the global
public/folder. - How to manually return a file as a response.
- How to serve entire directories using catch-all routes.
1. Automatic Exposure (Recommended)
Before manually exposing files, remember that JopiJS automatically exposes any asset imported via code.
When you do this:
import "./styles.css";
import logo from "./logo.png";JopiJS detects the imports, optimizes the files, and serves them via an internal URL. You don't need to do anything else.
Use imports whenever possible. It ensures your assets are bundled, hashed (for better caching), and optimized (e.g., small images inlined as base64).
2. The Global public/ Folder
If you have assets that aren't imported in React but need to be accessible via a direct URL (like robots.txt or a legacy image folder), use the public/ folder at your project root.
Structure:
my-jopi-app/
├── public/
│ ├── favicon.ico
│ └── docs/
│ └── manual.pdf
└── src/ ...Access:
http://localhost:3000/favicon.icohttp://localhost:3000/docs/manual.pdf
3. Manually Returning a File
Sometimes you need an API route (e.g., onGET.ts) to return a specific file based on some logic (like checking if a user is authenticated).
Using file_returnFile
Returns a file based on an absolute path or a path relative to the project root.
import { JopiRequest } from "jopijs";
export default function(req: JopiRequest) {
// Check some permission...
if (!isAuthorized(req)) return req.res_redirect("/login");
// Relative to the project root
return req.file_returnFile("./storage/reports/annual-report.pdf");
}Using file_returnRelFile
Returns a file relative to the current source file.
export default function(req: JopiRequest) {
// Relative to this .ts file
return req.file_returnRelFile("./invoice.pdf", import.meta);
}4. Serving Entire Directories
If you want to serve a whole local folder under a specific URL prefix, you can use a Catch-all route ([...]) combined with file_serveFromDir.
Example: Serving a "Reports" folder
We want to serve ./my-internal-files/ via the URL /view-reports/*.
Structure:
src/
└── mod_admin/
└── @routes/
└── view-reports/
└── [...]/ # <--- Catch-all URLs from /view-reports/
└── onGET.tsImplementation:
import { JopiRequest } from "jopijs";
export default function(req: JopiRequest) {
// 1. Prepare the path (remove the route prefix)
// For URL /view-reports/2024/jan.pdf, we want to look for 2024/jan.pdf
const relativePath = req.req_urlInfos.pathname.substring(req.routeInfos.route.length - 2);
req.req_urlInfos.pathname = relativePath;
// 2. Serve from the directory my-internal-files
// This directory is at the root of the project.
//
return req.file_serveFromDir("./my-internal-files");
}Security Note: Be extremely careful when serving directories. Ensure that users cannot use ".." in the URL to navigate outside the intended folder. JopiJS provides built-in protections, but always validate your inputs.