Transcript from the "server.js Walkthrough" Lesson
>> Kyle: We're not gonna start this complex, we're gonna start with something a bit less complex. What I'm gonna do is stop that server. I'm using a tool called forever to run my node processes in the back end. And I'm gonna recommend if you don't already have that installed, if you have your node environment up and going, if you do NPM install minus G, so that you can install it globally and then do forever.
[00:00:52] Anyway what I'm going to do is switch to the base version of this code. Node. I'm sorry .server. If you're running on a Windows machine by the way, you're not gonna be able to use the bash script that I've provided, that server.sh, but if you look at server.sh, it's not really doing something entirely crazy.
[00:01:12] It's basically killing the previous one so you can do that yourself, you can say forever stop and kill the previous one. And then [COUGH] it's starting it up again, you can run that command the forever start. You don't need these other things like the up times and spin sleep times or just forever, and then start and then give it a code in it or it'll run and manage it for you or you can just run the command line like run it through node, we'll get to that in just a minute.
[00:01:37] For me I'm just gonna run served.sh to start up. The base version of this code. And I'll go back to port 8050. So you see a really baseline version where I don't have any of this stuff going on about interactions or stuff, but this is kind of our starting point, what I'm gonna do is spend a little bit of time talking to you about how this code currently works this base version, I'm in a walk you through different files and point out some things that I did.
[00:02:04] And then time permitting, we'll try to put in a few little extra things to make it look more and more like what I was doing with the secure phrase site, and you have both of those code bases from here on that you can kind of go and refer to.
[00:02:32] There's a few little libraries that I pull in to help with stuff, forever is a nice little helpful tool, but this isn't like I'm writing some agular app and I've bought into some big ecosystem. These are principles that I think are at a lower level of the stack than what framework you choose.
[00:02:48] And what bugs me frankly a little bit about framework choices that people make is that it restricts you from making some of these decisions yourself. Kind of forces you down a particular path, I don't like to be forced down those paths, I like to have total freedom. This is sort of our frameworkless way to do shared code.
[00:03:33] If I take a value in one form and I convert it to another form and then I can come back and I get the exact same value, that's called an isomorphism. And the principle of isomorphism means that I need to actually something in a different form. But that's not actually what we're doing here.
>> Kyle: Take a look at some of the code. I'm gonna start by share JS, I'm gonna start by opening up the secret .JS file.
[00:05:10] Cuz this is where I set up some configuration constants, I just want you to be aware of what configuration constants I'm setting up. I'm setting up that the server address for listening only on local hosts. Sometimes people, sometimes your machine won't work if you actually say local host here even though it ought to.
[00:05:29] I've seen weirdness with node in the past, I always specify the 127 address, and then I picked port 8050, I don't know why. It's just one of my favorite numbers for demonstrating stuff, port 8050 is the port I chose. Some of these other ones really aren't even actually being used, but they're there in case you would use them in the future, like some of the headers that you send out if you wanna make cross origin XHR requests and things like that.
[00:05:54] This is if we're doing static file caching, we can set up some links. Mostly we're basically just using the server name, server address, and server port. Now, let's open up server.JS, it's kind of the main meat, that's where our main portion of our server works. And, right off the bat, you'll see that I'm starting out in strict mode.
[00:06:17] That's a really important thing, it's easy to forget, I think you ought to be running in strict mode. Put that at the top of all your files, just get into the habit of making sure that your code is running in strict mode. I'm gonna uncomment this, I have it commented out because we don't necessarily need it running all the time.
[00:06:34] This is actually it's kind of a useful like debugging trick if you haven't heard about this in node. In node, if an uncaught exception chokes the server, it will actually kill the server and throw it into this weird state. But there are times when you actually want some sort of interactive debugging going on.
[00:06:56] There is a way to debug node processes, we won't get into a lot of that. But there's times when you don't actually want it to just kill the node process. And it's especially true if you've got some bug, and you're running something like forever, Which is gonna keep restarting it, and keep getting the same bug.
[00:07:11] Turning this on, turning this uncaught exception handler on, allows you to catch it in a graceful way. You're not gonna necessarily wanna keep the server running once that happens, but it does prevent the system from entirely going away and restarting, I found that to be a useful little trick to listen for the uncaught exception handler.
[00:07:31] Okay, the top, I start setting up my variables, this is a style that I've recently fallen into which is that I put all my variables at the top of my functions at the bottom I only do that in node. My browser's code, I actually end up doing the reverse and I can't really fully articulate why, but it's just a style I've fallen into recently.
[00:07:50] I find it easier to have all my module declarations and my require statements at the very top so I can see it a glance everything that's being pulled in, and I think that's going to likely be more how we structure our modules in the future anyway. We're gonna be doing a lot of import statements.
[00:08:26] URL parser, this one parses URL strings. This watch one, I'll explain later, but that's how you watch a file system and do stuff if things change. Now I start setting up some variables which I'm not doing anything with yet, but these are some variables. These are basically the representations of the modules that I plan to use in both places.
[00:08:48] ASQ that's gonna be my a sequence library. Grips is my templating engine. EventEmitter2 is an event library that lets you have very lightweight PubSub kind of thing. Events is gonna be my actual module that uses that, or my actual instance of EventEmitter2. Tmpls is gonna be my templates manager.
[00:09:11] It interacts, that's actually the compiled templates from grips. Pages is gonna kind of be a page controllers. It's gonna handle mostly in the browser, a little bit on the server, but mostly in the browser, it's gonna handle things like managing my history objects so that my URLs, in a single page app, my URLs are properly mapping with my back button and stuff like that.
[00:09:31] When you use the history API and that one, the view module is directly interacting with my templates. And the request module is abstracting away. If I wanna request something when I'm in the server context, a request is just a file system load, but if I'm in the browser, it's an AJAX, I just create a little wrapper on top of that so I don't have to think and I can use the same request in both places.
[00:09:56] And then finally, a variable called routes which is gonna be an array of basically if you've done any work with Express, or if you've done maybe something like KOA that's another generator's based routing server that is similar to Express, and there's even modules that let you use them together but essentially I'm gonna recreate that without a framework.
[00:10:17] And I'm gonna do it in just a few lines of code and my router writes as a series of functions that will perform my middleware pounds. Here I start pulling in some stuff this is requiring in that secret file, setting up some static file options. These aren't used yet in ours but, they're used a little bit but not a lot right now.
[00:10:38] You notice that I have it set up so that you can switch this from Dev to Prod which changes file caching modes and things like that, all right. Here I start loading in those modules that I was talking about earlier. And there's something interesting that is definitely typically considered an evil thing to do with note.
[00:10:58] Most people say you should stay away from the global object entirely. I can't fully endorse this technique without any side effects, but I would say that it has become increasingly useful in the process of sharing code if I treat my hybrid modules, their name spaces as being on the global object.
[00:11:22] The difference is if I wanted to do this in a fully modularized way I'd have a very different mechanism running in the browser or something like require, that would be managing my module instances in the browser, and it would look very different with how I would interact with those modules in the node server.
[00:11:40] And I don't want things to look significantly differently or it kinda defeats the purpose of trying to share code. Even if the code itself was shared if the way that I use it is very different, I don't really wanna go about that. I'm also not a big fan of jury factor.
[00:11:58] Sure you could re-factor server JS. This was a quick and dirty site that I built in three or four days for the purposes of showing off some stuff, this is certainly not production quality perfect code. What I'm doing is I'm basically setting a local variable instance in my program but I'm also making a reference to that same thing on the global namespace.
[00:12:23] And what that means in my code is that inside of those modules if one module is using another one, I don't need to worry about different sorts of imports on the server as I do in the browser. The other way of going about this by the way if you don't want to go this route with setting the Globals, is you write server side modules and then you use some tool like Browserify which completely rewrites your code and makes it look like something that will run in the browser.
[00:12:48] And I've done that before and I'm not saying Browserify is bad, actually it's a great tool. But it's a lot more mental juggling to think about the code that's running in the browser has been transformed now It's rewritten your code, and I would rather literally use the same code while I'm learning things and so forth.
[00:13:06] For me Browserify was heavier than I wanted to go with this project but it is another way of handling what I'm doing here. I'm loading in some of these libraries like asynquence this is the contrib packages on top, here's the grips, templating engine, my EventEmitter these are me loading in those pages in views and requests.
[00:13:27] All right so I have a function which I'll show you a little bit down below called load templates. It's supposed to go and take this templates JS file, which I'll show you where that comes from, but it's to take that file, run it in my current context of my engine so that my server side process can render templates if necessary.
[00:13:47] And the principle here is, what I call sort of hybrid rendering which is that on the initial page request or any page requests that actually goes to the server. That rendering engine should be invoked and should render a full HTML page ready to ship out to the server with all of its data.
[00:14:22] What I'm doing here is I'm loading up the templates into the server instance so they can make those initial requests but we do the exact same thing we load those things up into the browser as well and it's literally identical code. It's the same templating engine it's the same templates that have been compiled.
[00:14:37] Everything is exactly the same and it runs the same in both places. It's really a significant amount of sharing that's going on and what I need to do is basically load up this file so let's take a divergence and ask, there's a question what is the purpose of asynquence?
[00:14:52] Asynquence is a flow control library. It manages things like promises and generators. Anything that you're doing asynchronously instead of using native promises or whatever, this is a library that kind of helps glue all of that stuff together in a better way. And so I'm gonna be using a sequence down below to do, and across the modules in quite a few places.
[00:15:14] That's what it's for, we're gonna use it in quite a few places.