1

I'm trying to serve bootstrap locally via npm-installed package. However, Node is serving my html file in place of my bootstrap CSS and JS files. This is perplexing to me.

I'm specifying both folders to express.static to ensure they are accessible publicly:

app.use(express.static(path.join(__dirname,"public")));
app.use(express.static(path.join(__dirname, "node_modules")));

Here is my directory tree structure:

.
├── Assets
│   ├── 11-express-homework-demo-01.png
│   └── 11-express-homework-demo-02.png
├── Develop
│   ├── db
│   ├── node_modules
│   ├── package-lock.json
│   ├── package.json
│   ├── public
│       ├── notes.ejs
│       ├── index.html
│   ├── server.js
│   └── views
├── README.md
└── result.txt

wherein

server.js is where I'm running express from, node_modules is where bootstrap lives (default npm installation can be assumed)

and in both notes.ejs and index.html, I have the following resources included:

<link type="text/css" rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css" >
<script type="script" src="/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>

index.html is simply a static landing page and notes.ejs is the app's main user-interactive screen.

index.html is as follows:

<!DOCTYPE html>
<html lang="en-US">
   <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Note Taker</title>
      <link type="text/css" rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css" >
   </head>
   <body>
      <nav class="navbar bg-info">
         <a class="navbar-brand text-light p-3" href="/">Note Taker
         </a>
      </nav>
      <div class="container">
         <div style="margin-top: 80px;" class="text-center p-5 mb-4 bg-light">
            <h1 class="display-4">Note Taker <span role="img" aria-label="Memo"></span></h1>
            <h4 class="mt-4">Take notes with Express</h4>
            <a class="btn btn-primary btn-lg mt-4" href="/notes" role="button">Get Started</a>
         </div>
      </div>
      <script type="script" src="/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
   </body>
</html>

notes.ejs is as follows:

<!DOCTYPE html>
<html lang="en-US">
   <head>
      <meta charset="UTF-8" >
      <meta name="viewport" content="width=device-width, initial-scale=1.0" >
      <meta http-equiv="X-UA-Compatible" content="ie=edge" >
      <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
      <meta http-equiv="Pragma" content="no-cache">
      <meta http-equiv="Expires" content="0">
      <title>Note Taker</title>
      <link
         rel="stylesheet"
         href="https://use.fontawesome.com/releases/v5.3.1/css/all.css"
         integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU"
         crossorigin="anonymous"
         >
      <link type="text/css" rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css" >
   </head>
   <body>
      <nav class="navbar bg-info">
         <a class="navbar-brand text-light p-3" href="/">Note Taker </a>
         <div class="icons">
            <i class="fas fa-save text-light save-note"></i>
            <i class="fas fa-plus text-light new-note"></i>
         </div>
      </nav>
      <div class="container-fluid">
         <div class="row">
            <div class="col-4 list-container">
               <div class="card">
                  <ul class="list-group list-group-flush">
                     <%- titles %>
                     <!-- https://stackoverflow.com/a/33701518/9095603 -->
                  </ul>
               </div>
            </div>
            <div class="col-8">
               <input
                  class="note-title form-control form-control-lg"
                  placeholder="Note Title"
                  maxlength="28"
                  type="text"
                  >
               <textarea class="note-textarea" class="form-control" placeholder="Note Text" style="min-width: 100%"></textarea>
            </div>
         </div>
      </div>
      <script type="script" src="/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
   </body>
</html>

Addendum - also in case you needed to see my server.js:

// This application uses the Express.js framework to create a REST API that allows clients to perform CRUD (create, read, update, delete) operations on notes stored in a JSON file. The API has three endpoints:

// - `GET /notes` retrieves a list of all notes stored in the `notes.json` file.
// - `POST /notes` adds a new note to the list of notes stored in the `notes.json` file. The new note data is passed in the request body as JSON.
// - `DELETE /notes/:id` deletes a note from the list of notes stored in the `notes.json` file. The ID of the note to delete is passed in the URL as a path parameter.



const express = require("express");
const path = require("path");
const fs = require("fs");

// const bootstrap = require('bootstrap')
// import 'bootstrap/dist/css/bootstrap.css';
const app = express();

const PORT = 3001;

// EJS (alternatively use Pug for dynamic HTML)
// https://www.youtube.com/watch?v=yXEesONd_54

// register view engine
app.set("view engine", "ejs");
// inform ejs which is your views folder because you don't use the default folder name views, but rather 'public'
app.set("views", path.join(__dirname,"public"));

app.use(express.static(path.join(__dirname,"public")));
app.use(express.static(path.join(__dirname, "node_modules")));

var titles = "";
app.get("/notes", (req, res) => {
  

  fs.readFile("db/db.json", "utf-8", (err, data) => {
    if (err) {
      res.status(500).send({ error: "Could not read file" });
    } else {
      data = JSON.parse(data);
      //   res.send(JSON.parse(data));
      if (data) {
        console.log(typeof data);
        console.log(data);
        for (let i = 0; i < data.length; i++) {
          titles += `<li class="list-group-item">${data[i].title}</li>`;
        }
        console.log(titles);
      }
    }
  });

  // res.sendFile(path.join(__dirname,'public/notes.html'))

  res.render("notes", { titles });
  // render: https://youtu.be/yXEesONd_54?t=597
});

app.use((req, res) => {
  res.sendFile(path.join(__dirname, "public/index.html"));
});

// app.get('/', (req, res) => {
//     res.render('index', { title: 'some title'})
// })
app.listen(PORT, () => console.log(`Server is running on port ${PORT}`));

I have tried the above to no avail. In place of the linked bootstrap CSS file and the bootstrap JS file, it's serving my html file. I don't understand what is happening.

majorian
  • 23
  • 4

1 Answers1

1

Precisely because you have specified

app.use(express.static(path.join(__dirname, "node_modules")));

Then your link and script tags should not include /node_modules/ at the front of your resource paths.

That is, currently you have:

<link type="text/css" rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css" >
<script type="script" src="/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>

Instead try:

<link type="text/css" rel="stylesheet" href="bootstrap/dist/css/bootstrap.min.css" >
<script type="script" src="bootstrap/dist/js/bootstrap.bundle.min.js"></script>

That should solve your problem. As for the logic of why the html file is loaded instead of the css and js files when you do it your original way, someone else can comment on that, because I'm not sure.

majorian
  • 23
  • 4
  • is not ideal to serve all of `node_modules`, `app.use('/bootstrap', express.static(path.join(__dirname, 'node_modules', 'bootstrap')))` or make a router which is mapped to each of the express.static middlewares – Lawrence Cherone Feb 05 '23 at 17:06
  • make a router which is mapped to each of the express.static middlewares: what does this look like? Can you illustrate with a snippet? Thank you. – majorian Feb 06 '23 at 01:30