Search code examples
node.jsweb-component

how to provide a very basic node server to serve a webcomponent for local tests?


I just want to test my webcomponets and I am getting

simple-call.js:1 Failed to load module script: The server responded with a non-JavaScript MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.

Reading around I found several answers to start node but this is exactly what I am doing. There is a significant difference in my case: index.html import a Webcomponent and this may add extra requirements I didn´t find yet.

So my straight question is, how can I start a very simple Web Server to serve the bellow index.html without getting the error mentioned above?

server.js

var http = require('http');
var fs = require('fs');

const PORT=8082; 

fs.readFile('./index.html', function (err, html) {

    if (err) throw err;    

    http.createServer(function(request, response) {  
        response.writeHeader(200, {"Content-Type": "text/html"});  
        response.write(html);  
        response.end();  
    }).listen(PORT);
});

index.html (just two lines for now)

<script type="module" src="./simple-call.js"></script>

<simple-call></simple-call>

simple-call.js (a very simple vanilla webcomponet)

const template = document.createElement('template');
template.innerHTML = `<input id="inputSimpleRequest"/>`;

class SimpleCall extends HTMLElement {
  constructor() {
    super();
  }

  connectedCallback() {

    this.attachShadow({mode: 'open'})
    this.shadowRoot.appendChild(template.content.cloneNode(true))

    const inputSimpleRequest = this.shadowRoot.getElementById('inputSimpleRequest');
    const url = 'http://localhost:8081/';

    fetch(url)
    .then(response => response.json())
    .then(data => {
      inputSimpleRequest.value = data.somephrase; 
    })
    .catch(error => console.error(error));

  }
}

window.customElements.define("simple-call", SimpleCall);

Solution

  • Flip it around a little:

    var http = require('http');
    var fs = require('fs');
    
    const PORT=8888;
    
    http.createServer((request, response) => {
      fs.readFile('./index.html', (err, html) => {
        if (err) {
          response.writeHeader(500, {"Content-Type": "text/html"});
          response.write(JSON.stringify(err, 0, 2));
        }
        else {
          response.writeHeader(200, {"Content-Type": "text/html"});
          response.write(html);
        }
    
        response.end();
      });
    }).listen(PORT);

    UPDATE: I changed and tested the code above. It does work as long as there is a file named index.html otherwise it displays an error page.

    I did not test this, but the idea is to re-read the HTML file every time it is requested and not just once.

    Or you can use express and make it serve up real files based on the URL:

    const express = require('express');
    
    const app = express();
    const PORT = process.env.PORT = 4000;
    
    // The magic happens here
    app.use(express.static('public'));
    
    app.listen(PORT, () => {
      console.log('Server is running at:',PORT);
    });

    Then you create a folder called public and place your files and sub-folders in there.

    Further Update:

    Here is a slightly better server without express.

    var http = require('http');
    var fs = require('fs');
    
    const PORT=8888;
    
    http.createServer((request, response) => {
      let url = '.'+request.url;
      if (url === './') {
        url += 'index.html';
      }
      console.log(url);
      fs.readFile(url, (err, html) => {
        if (err) {
          response.writeHeader(404, {"Content-Type": "text/html"});
          response.write(JSON.stringify(err, 0, 2));
        }
        else {
          response.writeHeader(200, {"Content-Type": "text/html"});
          response.write(html);
        }
    
        response.end();
      });
    }).listen(PORT);

    This allows you to access any file in the existing folder structure.

    Be careful though. There is no protection and someone could attempt to load files in paths below the current path. DO NOT USE IN PRODUCTION