Is there a way to refresh static files without server restart? - javascript

My simple Node.js app serves static files, e.g. html/txt
app.use(express.static('public'))
I want to reflect my changes to those files without restarting the app.
I.e. want to be able to modify any txt/help/read.me static files to it's available right away for the clients without restarting the app. How do I do it?

To determine if a file has changed, you can use fs.watch from the built-in fs module. It works like this: fs.watch('filename_or_directory', function(event, file) {}) . The callback's first parameter is "event", a string which is either "rename" or "change", depending on what type of change happened. The second parameter is the filename that changed.
For the client to automatically know that a change has occurred on the server is a bit more complex. There needs to be some form of communication with the server; you can do this with polling or with web sockets. If you go the socket route, you can use a library like socket.io or ws to establish a connection between server and client; when the server notices a change in a file from fs.watch, it can broadcast that change as a JSON "event object" to all clients, which can then receive the message and determine how to proceed (reload the current page, request updated data via AJAX, ignore it because it's an unrelated file, etc.).
If you go the polling route, you don't need any web socket libraries. You'd just keep track of the timestamp of each change from fs.watch in an array, then set up a route like /api/getChanges or something. You have the client, at regular intervals, post the timestamp of the last client update to that route, and the server can respond with all change objects in the array after that time.
Note: Express doesn't need to know that a file has changed. It will re-read files as they're requested. It's the client that needs to know when to refresh.

Fixed this way:
app.use(express.static('public’, {etag: false}))

Related

Node JS + Express JS: refresh page from other location

I have the following problem: I want to change one variable on a page. The input comes from another page so:
I'm using Node.js, Express.js and Ejs for this task.
Server - storing the values
Index page - Control page with input fields and send button
Display page - Shows the variable
I'm sending the variable with fetch post to the server. On the server I change the variable with the request body value and when I reload the "Display page" manually I see the new value. The problem is: I need to change it without any manual refresh or other things, because that won't be possible.
There is the possibility with "location.reload()" to refresh it every X second. But that's not the way I want to use, I really just want to refresh it when the variable changes. Is there a function (from express.js for example) I can use for it?
edit: I should mention that this project would be just used in our network and its not open for other users. Like an in-house company dashboard kind of.
So a "quick and dirty" solution can work too, but I want to learn something and wanted to do it the right way though.
This is a very common scenario that has several solutions:
Polling - The display page runs ajax calls in a loop every N seconds asking the server for the lastest version of the variable. This is simple to implement, is very common, and perfectly acceptable. However, it is a little outdated, and there are more modern and efficient methods. I suggest you try this first, and move on to others only as needed.
WebSockets - WebSockets maintain a connection between the client and server. This allows the server to send messages to the client application if/when needed. These are a little more complex to setup than just plain ajax calls, but if you have a lot of messages getting sent back and forth they are much more efficient.
WebRTC - This is taking it to another level, and is certainly overkill for your use case. WebRTC allows direct messaging between clients. It is more complicated to configure than WebSockets and is primarily intended for streaming audio or video between clients. It can however send simple text messages as well. Technically, if you want to persist the message on the server, then this is not suitable at all, but it's worth a mention to give a complete picture of what's available.
The simplest solution that came to mind is to have the server return the updated post in the body, then use that to update the page.
You can also read about long/short polling and Websockets.
One possible solution would be to add page reload code after a successful post-operation with fetch.
fetch(url, {
method: 'post',
body: body
}).then(function(response) {
return response.json();
}).then((data) => {
// refresh page here
window.location.replace(url);
});
Proper solution (WebSockets):
Add WebSocket server as a part of your Node.JS app
Implement subscriptions for the WebSocket, implement function 'state changed'.
subscribe on a method 'state changed' from your client browser app.
call ws server from your express app to update the clients when your variable is changed
Outdated (Polling):
Add express endpoint route: 'variable-state' Call server from your
client every n ms and check whether variable state is changed.
Refresh the page if variable is changed.

Node JS - file generator architecture

Need to add file generator REST API endpoint to web app. So far I've came up with following idea:
client sends file parameters to endpoint
server receives request and using AMQP sends parameters to dedicated service
dedicated service creates a file, puts it into server folder and sends responce that file created with file name
endpoint sends response to client with file
I'm not sure if's a good idea to keep REST request on a server for so long. But still don't want to use email with generated link or sockets.
Do I need to set timeout time in request so it will not be declined after a long wait time?
As far as I know maximum timeout is 120sec for rest api call. If it takes more time for the service to create a file then I need to use sockets, is that right?
The way I've handled similar is to do something like this:
Client sends request for file.
Server adds this to a queue with a 'requested' state, and responds (to the client) almost immediately with a reponse which includes a URL to retrieve the file.
Some background thread/worker/webJob/etc is running in a separate process from the actual web server and is constantly monitoring the queue - when it sees a new entry appear it updates the queue to a 'being generated' state & begins generating the file. When it finishes it updates the queue to a 'ready' state and moves on...
when the server receives a request to download the file (via the URL it gave the client), it can check the status of the file on the queue. If not ready, it can give a response indicating this. If it IS ready, it can simply respond with the file contents.
The Client can use the response to the initial request to re-query the url it was given after a suitable length of time, or repeatedly query it every couple of seconds or whatever is most suitable.
You need some way to store the queue that is accessible easily by both parts of the system - a database is the obvious one, but there are other things you could use...
This approach avoids either doing too much on a request thread or having the client 'hanging' on a request whilst the server is compiling the file.
That's what I've done (successfully) in these sorts of situations. It also makes it easy to add things like lifetimes to the queue, so a file can automatically 'expire' after a while too...

(Node.js) How to get URL of a binary file stored in server?

I am developing a service using node.js, which returns a url to a file stored in my service's database. In my program, I save the file to, for example, "./aFolder/filename.jpg". I'm going to use DigitalOcean.
My questions are:
1. What is the form of such a url?
2. How can I get that url in my code using node.js?
Thank you in advance.
The URL will be whatever you want to make it since you'll presumably be the one writing the code to handle incoming requests.
Something like http://uri/download/aFolder/filename.jpg seems like a reasonable choice, but you'd need to write your app to accept those paths.
You may want to look into Express where you can add route handlers via app.route() such that anything to /download gets processed by a particular callback that facilitates the mapping of the URL onto your filesystem and will likely be sending the correct file over using res.download()
A basic skeleton might be:
app.route('/download:path')
.all(function(req, res, next) {
res.download(req.params.path)
})

Getting backbone routing to work with pushstate and node.js/express as server

I'm trying to build a single page app with backbone.js on front end and node.js/express as server, I want to have a base HTML file for the root, and then when user navigates to any path such as
mydomain.com/foo/bar
I want to be able to handle that path on the client side by javascript instead of making a round trip to server. I am reading about backbone routing and HTML5 push state. In this article he describes push state like this,
In fact, PushState is really nothing more than a standard API for JavaScript, that allows us to manipulate the browser history by “push”ing full URLs into the browser’s URL without making a round trip to the server, and respond to changes in the URL with Javascript – all without the use of URL hash fragments.
but when I use push state it does actually makes a server request and expects server to deliver contents under /foo/bar . I don't understand how I can avoid that.
Now let's assume that even with push state, your client is going to make a server request under mydomain.com/foo/bar when you visit this URL directly. In that case, since I'm serving the default HTML file, and this default HTML file has links to scripts in it:
<script type="text/javascript" src="/scripts/myscript.js" ></script>
When this HTML loads, it starts looking for scripts under /foo directory instead of root since the server was requested under /foo which obviously does not exist. How do I fix this?
I'm really confused at this point. I'd like to know how URL routing is usually done in a single page application. Any help will be greatly appreciated. You can also refer to this other question I have posted about the same issue: Backbone Router : Get rid of # in the URL
The solution you're trying to implement is very interesting but not that simple. When your server gets a request to mydomain.com/foo/bar, you should redirect to your root with some parameter that the frontend (JavaScript) app can pick-up to know what the original request was for. For example:
Client sends GET http://mydomain.com/foo/bar
Server redirects (responds 302 with Location header set) to http://mydomain.com/#!/foo/bar
Your SPA is loaded in the browser, and on startup you check for the hash and find #!/foo/bar, so you remove the hash and trigger the /foo/bar route (that's a push-state). Your resulting URL is again http://mydomain.com/foo/bar: the original URL the user browsed to.
Grooveshark does something similar to this, though it actually responds with a page to the request sent in 1., which does the hash replacement in the client and then sends another request to the server. It looks unnecessary to me, maybe I'm overlooking something.

Running code from Socket.io notification

I'm running a NodeJS server which is sending notifications to the clients when somebody does something, for example, when a client deletes a row from a grid, Socket.io informs the rest of the clients that a row got deleted.
In that example, I could add something like actionType: rowdeleted to the socket.io message and then just detect the actionType on the client side and refresh the grid. Anyways, the problem is that there can be infinite number of actions (and new ones can be added), so I can't code a function for each action type on the client side.
Then I thought maybe I can send some code via socket.io and make the client run it, but I'm not sure if that is the best way for doing what I want. Also, how are the clients going to run that code? Via eval?
I'm open to any suggestion :)
Have you considered something similar, but not as eval. You clearly must have the code to execute somewhere, be it on the server side. Why not create a way to let the client know what script/code/action to get and execute it.
I have used something similar out of a similar need. The action type referenced a script in a specific path on my server (/js/actions/ACTION.js). Upon getting the command to run the action, the client would check if it has the action, if not, it would go get the action. After that it would run the action on the script. RequireJS is good for this kind of thing. It will keep track of what actions you have and what actions you don't have. It will also make sure to get the action if it doesn't have it before it run some function that needs it.
eval is evil (c)
so I can't code a function for each action type on the client side.
there's no point emiting events from server if they wont be handled on the client(s)
have a client handle funcion for each type of event your server is emiting.
Otherwise bind on all events and handle then

Categories

Resources