How can I return n HTML file in a route built with Elysia and Bun?

1.4k Views Asked by At

Here's my HTTP server built with Elysia and Bun:

import { Elysia } from 'elysia'
import { staticPlugin } from '@elysiajs/static'
import { html } from '@elysiajs/html'

// Instantiating the HTTP server
const server = new Elysia()

// Serving 'dist' folder to clients
server.use(staticPlugin('./dist'))

server.get('*', async () => {
  return Bun.file('./dist/index.html')
})

server.listen(3000, () => {
  console.log(`Website server is listening on port 3000`);
})

When I hit http://localhost:5002/

I get an error saying:

Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.

I wonder if what I have to do in order to return an HTML file from a route with Elysia, so that the file will load it's script properly.

5

There are 5 best solutions below

0
Renish Gotecha On

You can resolve it with below changes

const server = new Elysia()
server.use(staticPlugin({
  assets : "./dist"
}))
server.use(html())
server.get('*', async () => {
  return Bun.file('./dist/index.html')
})
server.listen(3000);
0
calebeaires On

This guide illustrates the process of deploying a Vue Single Page Application (SPA) by:

  1. Placing 'vue dist' files in a public folder.
  2. Configuring the staticPlugin.
  3. Setting a prefix based on the requisite relative path. In my case, it's the root path.

Below is the corresponding code:


import {Elysia} from "elysia";
import { staticPlugin } from '@elysiajs/static';

// Instantiate an Elysia application
const app = new Elysia();

app
    // Register static plugin, set the prefix as root
    .use(staticPlugin({ 
        prefix: '/',
        alwaysStatic: true,
    }))
    // Define simple JSON endpoint
    .get('/ping', () => ({
        test: 23423
    }))
    // Define main route to serve Vue app
    .get('/', async () => {
        return Bun.file('./public/index.html');
    })
    // Listen on port 3000
    .listen(3000);

// Log server details
console.log(
    ` Elysia is running at ${app.server?.hostname}:${app.server?.port}`
);

0
Aryxst On

If using just Bun is okay for you here's my personal solution:

const server = Bun.serve({
  fetch(req, server) {
    
    // #region Setting up static router
    // Sym... stands for ipothetical object
    const url = new URL(req.url);
    const symLink = join("public", url.pathname);
    const symIndex = join(symLink, "index.html");
    if (url.pathname.endsWith("/")) {
      if (existsSync(symLink) && existsSync(symIndex)) {
        console.log("Method 1");
        return new Response(Bun.file(symIndex));
      }
    } else {
      console.log("Method 2");
      if (existsSync(symLink)) {
        console.log("HERE %s", symLink);
        return new Response(Bun.file(symLink));
      }
    }
    // #endregion
  },
});
0
Erlend On

I had the same issue and it was because the staticPlugin uses public as the default prefix for assets (e.g. you need to include files in your index.html with public/style.css by default).

Try the following:

// index.html
server.get('/', (c) => Bun.file('dist/index.html'))

// static files
server.use(staticPlugin({ assets: 'dist', prefix: '' }))

We change the assets to dist and set the prefix to an empty string.

Ref:

https://elysiajs.com/plugins/static.html#static-plugin

https://github.com/elysiajs/elysia/issues/352

0
Wickramaranga On

A really easy way to serve a static folder, and an index.html when the route has no file name in it is:

  .use(
    staticPlugin({
      prefix: '/subfolder/if/needed/',
      alwaysStatic: true,
      indexHTML: true, // <--
    }),
  )

If someone requests /subfolder/if/needed/, it will send the public/index.html. If someone requests /subfolder/if/needed/a/code.js, it will send the public/a/code.js file. Of course you can override the folder served (default=public) by changing assets option.

This works with Elysia > 1. I think this isn't documented yet.