Winter vacation idle at home, no hobbies, leisure time like to learn good-looking CSS effect, but every time to change the style need to refresh the browser, so to find a hot loading tool, failed, he wrote a 🚀

Of course, you could do this with crA and similar tools provided by React, but I just wanted to edit CSS in a simpler way, so I didn’t want to do that

Hot loading of web pages below refers to this requirement

Note: If you want to use it in a production environment, there is no need to look further

Train of thought

Web hot loading can be divided into the following steps

  1. Enable a port to implement the HTTP service

  2. Server listening folder

  3. When the folder changes, it is sent to the client through SSE

  4. Refresh the client page and obtain the page again

So the tools we’re going to use are

  • The Node package:http.fs
  • WebAPIs:localtion.reload().EventSource

start

providehttpservice

First, we open a port to provide the HTTP service

const http = require('http');

const server = http.createServer((req, res) = >{}); server.listen(8080.() = > {
    console.log(` 🚀 server running on http://localhost:8080/... `)});Copy the code

Run node, the service is already enabled http://localhost:8080/

The next step is to provide access to static resources so that we can see our web pages

Here we use fs.readfile to read the file and respond to the HTTP request

Notice âš âš  Change the path of the static resource folder

const fs = require('fs');
// Don't forget to change your listening folder
fs.readFile("/Users/shwei/code/livereload/public" + url, (err, data) = > {
  if (err) {
    res.writeHead(404);
    res.end("File Not Found");
    return;
  }
  res.writeHead(200);
  res.end(data);
});
Copy the code

That’s what happens when you add it to our HTTP service

Here we default to the root directory and return index.html, wrapped in a function for other static resources to reuse

const http = require("http");
const fs = require("fs");
const getStaticResource = (url, res) = > {
  fs.readFile("/Users/shwei/code/livereload/public" + url, (err, data) = > {
    if (err) {
      res.writeHead(404);
      res.end("File Not Found");
      return;
    }
    res.writeHead(200);
    res.end(data);
  });
};
const server = http.createServer((req, res) = > {
  const { headers, url, method } = req;
  if (url.toLowerCase() === "/" && method.toLowerCase() === "get") {
    getStaticResource("/index.html", res);
    return;
  }
  if (method.toLowerCase() === "get") getStaticResource(url, res);
});

server.listen(8080.() = > {
  console.log(` 🚀 server running on http://localhost:8080/... `);
});
Copy the code

In this case, we can create index.html in the appropriate folder at http://localhost:8080/

See our website

useSSEAnd file monitoring to achieve hot loading

The next step is to implement hot loading

First of all, our webpage must be linked to a JS file by default, which puts the browser-side API we need for SSE

//sse.js
const events = new EventSource("/events"); // Listen for the /events route in our HTTP service
events.onmessage = (event) = > {
  location.reload();
};
Copy the code

Set up the route to listen to, just set up to refresh the page when the message is received

Don’t forget to link to HTML

<script src="sse.js"></script>
Copy the code

The next step is to implement our server-side services

The first is the file listener apifs. watch, which we need to work with to send messages to the browser

As usual, write a function wrapper, and it should be executed immediately (because we want to open the port to use, if there is business logic do not follow me)

(function watchFile() {
  fs.watch("./public", { encoding: "buffer" }, () = > {
    client.writeHead(200, {
    "Content-Type": "text/event-stream"."Connection": "keep-alive"."Cache-Control": "no-cache"
  });/ / headers
    client.end("data: reflush\n\n");// Don't forget data: and \n\n}); }) ();Copy the code

You may notice that I have an extra client variable here, but don’t worry I’ll explain it later, pay attention to SSE communication standards (comments in the code)

The essence of SSE is to continuously send GET requests to the server to keep the connection uninterrupted

We only need to send a message to the browser when the file changes, so I arranged the response this way

if (url.toLowerCase() === "/events" && method.toLowerCase() === "get") {
    client = res;
    return;
  }
Copy the code

We only need to save the “pointer” for each response so that we can find it when the file changes

Global variables are a little inelegant here, but don’t worry too much about them

At this point we are fully functional

All code

const http = require("http");
const fs = require("fs");
let client;

const server = http.createServer((req, res) = > {
  const { headers, url, method } = req;
  if (url.toLowerCase() === "/" && method.toLowerCase() === "get") {
    getStaticResource("/index.html", res);
    return;
  }
  if (url.toLowerCase() === "/events" && method.toLowerCase() === "get") {
    client = res;
    return;
  }
  if (method.toLowerCase() === "get") getStaticResource(url, res);
});

server.listen(8080.() = > {
  console.log(` 🚀 server running on http://localhost:8080/... `);
});

(function watchFile() {
  fs.watch("./public", { encoding: "buffer" }, () = > {
    client.writeHead(200, {
    "Content-Type": "text/event-stream"."Connection": "keep-alive"."Cache-Control": "no-cache"
  });/ / headers
    client.end("data: reflush\n\n");// Don't forget data and /n/n}); }) ();const getStaticResource = (url, res) = > {
  fs.readFile("/Users/shwei/code/livereload/public" + url, (err, data) = > {
    if (err) {
      res.writeHead(404);
      res.end("File Not Found");
      return;
    }
    res.writeHead(200);
    res.end(data);
  });
};
Copy the code

Open your code editor and http://localhost:8080/

Enjoy!