Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFE] @std/http/file_server - Allow to modify file contents on-the-fly #6380

Open
TriMoon opened this issue Feb 4, 2025 · 3 comments
Open

Comments

@TriMoon
Copy link

TriMoon commented Feb 4, 2025

Is your feature request related to a problem? Please describe.
It would be nice (i would like tobe able) if we could modify the file contents of certain files served "On-The-Fly", eg, before actual sending of the contents.

Excuse me for still being a total noob wrt deno, TypeScript, et all...

I would like to automatically inject, for example the below, inside the <head> tag of html files that will be served:

  • <!-- https://guybedford.com/es-module-shims-2.0 -->
    <!-- Load ES Module Shims from your CDN of choice -->
    <script async src="https://ga.jspm.io/npm:[email protected]/dist/es-module-shims.js"></script>
    <!-- Enable the TypeScript and CSS Import features (only import maps are polyfilled by default) -->
    <script type="esms-options">
      { "polyfillEnable": ["typescript", "css-modules"] }
    </script>
    <!-- Set dependencies in import map -->
    <script type="importmap">
    {
      "imports": {
        // This is just an example ofcourse, replace or add to your needs...
        "vue": "https://ga.jspm.io/npm:[email protected]/dist/vue.esm-browser.prod.js"
      }
    }
    </script>
  • <!DOCTYPE html>
    <html>
    <head>
       <meta charset="UTF-8"/>
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <title>blabla</title>
    
       <!-- The above would be inserted here -->
    
       <!-- ES Module Shims will find this and handle the rest -->
       <script src="app.ts" type="module"></script>
    </head>
    ...

Describe the solution you'd like
Somekind of hook/callback we could add to the function call, that modifies the text-data from the file before that data is send out, depending on file type and name.

  • // myFilter.mts
    interface FilterParams {
      fname: string,
      fext: string,
      fdata: Array<string>; // One string per \n delimited line fe...
    };
    
    export const filter =
      (resp:FilterParams): string[] => {
        if (resp.fname === 'index'
          && resp.fext === "html"
        ) {
          /*
            Do some processing on resp.fdata
            1. Find the 'head' element
            2. Insert some html before the first script tag using Array() functionality.
            3. Optionally add some SRI to respective tags, or some CSP.
          */
        }
        // resp.fdata will now hold the altered or unaltered file data.
        return resp.fdata;
      };
  1. Usage inside a module:

    // serve.ts
    import { filter } from "./myFilter.mts";
    import { serveDir } from "@std/http/file-server";
    
    // Something like this, i don't know how to use this yet but you get the idea...
    Deno.serve({
      serveDir(req),
      filter
    });
  2. Or from command line:

    $ file-server --filter=./myFilter.mts ./src
    

The above would process each request and serve the file(s) that is/are requested

  • unaltered UNLESS it is intercepted and changed by the filter.

Describe alternatives you've considered

No idea yet, as i'm still in the process of reading deno docs and learning TypeScript 🤷‍♀

If what i describe is already possible please show me the way to do it with an example and if possible add it to the docs. 😉

@TriMoon TriMoon changed the title [RFE] http/file_server - Allow to modify file contents on-the-fly [RFE] @std/http/file_server - Allow to modify file contents on-the-fly Feb 4, 2025
@kt3k
Copy link
Member

kt3k commented Feb 5, 2025

Doesn't sounds like a common needs to a static file server.

I'd recommend you should read the file on your own handler, modify it, and respond:

Deno.serve(async (req) => {
  const path = new URL(req.url).pathname;
  let text: string
  try {
    text = await Deno.readTextFile("." + path);
  } catch {
    return new Response("Not found", { status: 404 });
  }
  if (condition(req)) {
    return new Response(text, { headers: { "content-type": "text/html" } });
  }
  return new Response(addHeader(text), { headers: { "content-type": "text/html" } });
});

@TriMoon
Copy link
Author

TriMoon commented Feb 11, 2025

Isn't the purpose of Deno.serve to eliminate the need for everyone to re-invent the same wheel? 🤔
I don't think it's such a "special" case (to add a filter hook), that should be excluded from this ready-to-use wheel. 🤷‍♀

Anyhow thanks for the example code you provided and i will try to make use of it...
Although i have no idea how to pass the control back to the default request handler in case it is not my targeted file in your example.

  • Plus If im not mistaken you are adding the contents of that file as a HTTP-Header not as text inside the original contents of the requested file...
    • ohhh aha wait a sec, addHeader in your example is meant to call my custom filter function?

All in all, i'm still lost as a new deno user...
I'm getting old i guess 🤷‍♀

@kt3k
Copy link
Member

kt3k commented Feb 12, 2025

Deno.serve and @std/http covers common needs around HTTP protocol, but they don't try to be a ready-to-use web framework.

I guess what you are looking for is web frameworks (such as hono, fresh, lume, etc)

ohhh aha wait a sec, addHeader in your example is meant to call my custom filter function?

Yeah, I meant addHeader modifies the file contents and generates some html.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants