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
-
Enable a port to implement the HTTP service
-
Server listening folder
-
When the folder changes, it is sent to the client through SSE
-
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
providehttp
service
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
useSSE
And 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!