ishtms / velocy

A blazing fast, minimal backend framework for Node.js
23 stars 1 forks source link

Serving static assets from a specific directory #2

Open LebCit opened 10 months ago

LebCit commented 10 months ago

Hello, Thank you very much for your time and efforts to bring this minimalist and effective Node.js framework. How to serve static assets like CSS, JS and images files from a specific directory using Velocy ? Consider the following route:

app.get("/", (req, res) => {
    res.writeHead(200, { "Content-Type": "text/html" })
    const page = eta.render("test.html")
    res.end(page)
})

And test.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Test page</title>
    <link rel="stylesheet" href="/static/styles/main.css">
</head>
<body>
    <h1>Just a test page</h1>
    <p>Created with Velocy, A blazing fast, minimal backend framework for Node.js, and Eta</p>
</body>
</html>

As you can see I want to load main.css from the styles folder which is in the static folder. The idea is to have a way to load static assets from a specific folder like other frameworks.

Thanks a lot again for your time and efforts. SYA

LebCit commented 10 months ago

Hello,

Anyone looking for a simple solution, here is my code to load static assets from a folder called static at the root of the app :

import { readFileSync, readdirSync, statSync } from "fs"
import path from "path"

// Function to get files from their directory recursively.
const getFiles = (dirName) => {
    let files = []
    const items = readdirSync(dirName, { withFileTypes: true })

    for (const item of items) {
        if (item.isDirectory()) {
            files = [...files, ...getFiles(`${dirName}/${item.name}`)]
        } else {
            files.push(`${dirName}/${item.name}`)
        }
    }

    return files
}

// Function to support different content types
const getContentType = (file) => {
    const extname = path.extname(file)
    if (extname === ".css") {
        return "text/css"
    } else if (extname === ".js") {
        return "application/javascript"
    } else if (extname === ".png") {
        return "image/png"
    } else if (extname === ".jpg" || extname === ".jpeg") {
        return "image/jpeg"
    } else if (extname === ".gif") {
        return "image/gif"
    } else if (extname === ".avif") {
        return "image/avif"
    }
    return "application/octet-stream" // Default to binary data if the content type is not recognized
}

const staticAssets = getFiles("static")

staticAssets.forEach((el) => {
    app.get(`/${el}`, (req, res) => {
        const filePath = path.join(process.cwd(), `/${el}`)

        try {
            const stats = statSync(filePath)
            if (stats.isFile()) {
                const contentType = getContentType(filePath)
                res.setHeader("Content-Type", contentType)

                const fileContents = readFileSync(filePath)
                res.end(fileContents)
            } else {
                // If it's not a file, send a 404 Not Found response.
                res.end("Not Found")
            }
        } catch (err) {
            // Handle any potential errors.
            console.error(`Error while serving file: ${err.message}`)
            res.end("Internal Server Error")
        }
    })
})

Hope this will be useful. SYA

ishtms commented 10 months ago

Hi @LebCit, This framework is a product that we're building as a part of our open source Node.js book. We haven't made enough progress yet, so this does not tackle static file serving for now.

You may check the current progress at Learn Node.js the Hard Way

LebCit commented 10 months ago

Hi @ishtms Thank you for this reply. I now understand why some functionalities are not yet implemented. As a side note on using Velocy, if I create a route with dynamic parameters:

app.get("/:folder/:filename", async (req, res) => {...})

where the folder parameter's value can be posts, and then I create a /posts route:

app.get("/posts", async (req, res) => {---})

The /posts route works but the route with dynamic parameters returns Route Not Found if the folder parameter's value is posts .

Velocy is great, straightforward, easy to use, without any dependency and lightweight. Thanks again for your time and this amazing framework.