FoldersJS

Written in October 2020

A month or so ago, I wrote about my grand ambitions for a project called The Folders Project - an experiment with frontend development building the same application in a variety of different ways. These ways will include different frameworks, different libraries/methodologies in those frameworks and all sorts of experimental stuff along the way.

This post aims to talk about the very first of these FoldersJS, and all the things that I had to do to get this effort out the door. There are a lot of items to mention in this post, so this one will probably be a little bit long.

foldersjs.gif

Introducing FoldersJS

As this is my first “folder”, this one had a couple of goals from the outset:

  • Create a simple app that can act as a relative baseline for the future folders
  • Have a frontend to develop a backend against
  • Have a frontend to figure out some base level styling with
  • Do all of this just in JS, no jQuery, no mootools (🐮lol), nothin’.

I’ll talk a bit more about the backend and the styling in a separate post somewhere down the line, this post will probably end up being too long as it is. But, in general, I’d say . . . Goal complete!

yes.gif

There was also another super fun wrinkle with this particular Folder - I started it five years ago in 2015. 2015 was a totally different world (in terms of web dev at least) five years ago! ES2015 was some cutting edge stuff that people were still trying to get a hang of, people were still using jquery to build their sites and features a lot of time, and frameworks had really just come onto the scene and were starting to be super popular.

Sure, Backbone, Ember, AngularJS, and even React had been around for a little bit at that point - but the front end dev ecosystem was nowhere as robust and first class as it is now. Heck, the world was only just starting to move to Gulp from Grunt - never mind Webpack!

So, stepping back into this project from 2015 was fun in a few ways:

  • It let me see how 2015 Hunter might approach this problem
  • It reminded me of all the “fun” stuff that we had to do in the web dev world back then
  • It still worked!

JHAl.gif

So, let’s take a look at some of the fun stuff that this project involved. I will probably keep each item short - just because there’s a lot of them and it’ll take a while to go too in depth on any of them. But here’s the items I’ll talk about:

  • API interactions
  • Routing (lol)
  • Styling
  • Models?
  • Templates!
  • Build system

API Interactions

So, back in 2015 the fetch browser API . . . wasn’t really a thing. It had just gotten introduced, but nothing really supported it and no one really knew how to use it too much (don’t even get me started on promises around this time). This meant that, if I was going to be interacting with an API, I was going to have to use the good ol’ reliable XMLHttpRequest.

Now, like many devs, I really don’t want to have to actually develop against the XMLHttpRequest very often; it’s not a very convenient API and it’s got a lot of steps compared to leveraging a library for API interactions - something that Axios and others were pretty popular for at the time. Instead, I decided to create an API wrapper that would surface the two sort of requests that I would need to talk to my server: fetch and post.

api.gif

Here’s what the wrapper for fetch looks like:

var API = {
fetch: function (path, callback) {
var uri = BASE_URI + "/" + path;
var request = new XMLHttpRequest();

    request.open("GET", uri, true);
    request.onload = function () {
      if (request.status >= 200 && request.status < 400) {
        callback(JSON.parse(request.response));
      }
    };

    request.onerror = function () {
      reject(new Error("Something Went wrong on the API"));
    };

    request.send();

},
...

This will bind the fetch method to the window’s API object and allow us to create a GET request against a REST API based on two values we pass in - path and callback.

CALLBACK! Callbacks were super common in 2015 because it was essentially the only way to tell your code to wait for an asynchronous action to happen and to fire an even after it’s done. We do still see this today in some cases, but super less often than we used to.

If we wanted to use this fetch method anywhere throughout the codebase we could invoke it like this:

API.fetch('resources', (data) => console.log(data))

This would call the /resources API endpoint with a get request and then log out whatever the JSON parsed value was that I got from that endpoint - pretty neat!

gimme.gif

Similarly, there’s a separate method for POST named …post… that will send a post request. The main difference here is that with POST requests, you normally want to attach some data.

post: function (path, data, callback) {
var uri = BASE_URI + "/" + path;
var request = new XMLHttpRequest();

    request.open("POST", uri, true);
    request.setRequestHeader("Content-Type", "application/json; charset=UTF-8");

    request.onload = function () {
      if (request.status >= 200 && request.status < 400) {
        callback(JSON.parse(request.response));
      }
    };

    request.onerror = function () {
      reject(new Error("Something Went wrong on the API"));
    };

    request.send(data);

},

It’s very similar code that can be called with something like:

API.post('resources', {name: 'Folder'}, (response) => console.log(response);

And this call will send a post request to the server’s resources POST endpoint, passing it our super simple object and logging out whatever the server responds with.

Super neat!

These sorts of API wrappers were relatively common back in the day if you wanted to roll your own - however this was really such a common thing that there were lots of libraries to help you out. There were helpers in jquery, there were libraries built into some frameworks like Angular’s $http service, and libraries dedicated to handling API requests like Axios. API handlers are still pretty common today - but if I were starting this project from scratch I wouldn’t need them, as the built in fetch api would fit the bill.

Routing

This is actually one thing that really hasn’t changed much over time if you’re building a front end app without libraries or frameworks.

Sure, you could just build your own Single Page App framework to handle routing and hotswapping contents out if you wanted (maybe I’ll see if I can do a folder on this down the line!?), but the easier and more common thing to do is to have a separate file for each path that you’re supporting.

For example - Fast Follow (That’s the name of the app that we’re building in The Folders Project) has three main routes:

  • home
  • post view
  • archive

In order to allow a route of FoldersJS/archive I literally have to have a file in my folder named archive.html. In that HTML file I have to include all of the dependencies needed on this page - that means that for every route that I have I need to create an html file that includes:

  • All the JS that’s used on that page
  • All the styling that’s used on that page
  • Everything that should exist in the <Head> tag (including the above, and things like a title)
  • And a body tag for all of the content to actually go into

You can see what these look like on the github repo for the FoldersJS Folder.

There’s not really a lot to say about this: other than it’s old, tired, and a pain in the butt.

butt.gif

Styling

This is another aspect that honestly hasn’t ended up changing too much. Sure, in the years since this project started, styling has changed a bit - flexbox and grid were introduced, SVGs became more powerful, and variables are a thing! But CSS is still CSS.

css.gif

However, since we’re going with an old school, just JS sort of approach there were some things that needed to be handled slightly differently. The main struggle back in the day was Do I use Sass or Scss - not that many people (myself included now) could call out the differences. Sass and SCSS were, and super still are ways to write a lot of CSS with ways to reduce duplication both of your style definitions, as well as your selectors. Here’s a chunk of scss from my file project:

.post-title {
font-size: 150%;
font-weight: 700;
margin: 0;
img {
width: 50px;
height: 50px;
border-radius: 50%;
}

If I were to write this in vanilla css I’d have to unnest the img tag and make a new rule that uses the selector of .post-title img. This style of CSS is still super relevant today - lots of projects still use these libraries, and most current libraries still heavily leverage these syntaxes.

One thing to note is that because this isn’t plain old CSS, we have to bring in a build tool to process this code and change it into CSS that the browser understands. I’ll talk a bit more about this in the Build System section of this post.

Models

zoo.gif

The Fast Follow app that we’re building has two main types of data that we represent: Posts and Comments

I wanted to have a model for each, which was pretty common - and still is, just differently - that handled all the interactions that a user might have for each of these Models.

The models were responsible for keeping track of the data of each type, as well as controlled the API interactions for each by interacting with the API handler outlined above. The Posts Model looks like this:

//The Post object class

function Post() {
this.posts = [];
}

Post.prototype.setPosts = function (data) {
this.posts = data;
};

Post.prototype.getPosts = function () {
return this.posts;
};

Post.prototype.findAll = function (callback) {
var context = this;
API.fetch("posts", function (data) {
context.setPosts(data, callback(data));
});
};

.....

I won’t talk too much about this, since I think that it’s mostly self explanatory - but one thing that’s really fun about it is that this is how we pretended to have classes using object protoyping! Classes actually exist these days, so I could really have cleaned this code up - but I kept it for the historical value (lol).

So using the above code, I could get a newly refreshed version of posts from my API by calling(ish):

const post = Post()
post.findAll(posts => console.log(posts))

Again, these leverage callbacks instead of async/await - but these models allow for a pretty simple way to interact with an API and encapsulate desired behaviour when it comes to one of these entities.

Templates

This was kinda fun as well! Even as far back as when I started developing there were templating libraries that would help developers pass values to a method or library that would then take that data and render it as the developer wants. My first introduction to this concept was with handlebars.js.

But of course, I wanted to implement this folder with no js libraries to support me as much as I could (you’ll notice I brought in some js assets to support a css library I included - but I don’t even know that that’s used). In practice this actually wasn’t too tough!

Here’s an example of my Comment template:

function commentTemplate(comment, index) {
var template;

template =
"<article class ='post comment" + (index % 2 === 0 ? " odd" : "") + "'>";
template += "<div class='post-title'>"
template += "<img src='" + comment.avatar + "'/>";
template += "<div>";
template += "<p><strong>" + comment.name + "</strong></p>";
template += "<p class='post-meta'>" + comment.createdAt + </p></div></div>"

template += "<p class='post-content'>" + comment.content + "</p>";

template += "</article>";

return template;
}

As you can see, all it really does is take a whole bunch of HTML and manually concatenate it as a string with the values that I want interspersed among the markup for the comment. We could then take that string and shove it into the DOM using something like:

//Find the desired location on screen and fill it with the markdown
var target = document.querySelector(".comments-container");
target.innerHTML = elements.join("");

This works really well! It means that as long as you have a Comment data object you can get the template to render just by calling commentTemplate(data).

Of course, these days it’d be a lot simpler to use template literals and string interpolation; but the general code would actually look pretty similar to the above!

Build System!

Nowadays there are a ton of different build/bundling systems for JavaScript out there. Of course there’s Webpack, but there’s parcel, rollup, and a slew of others that help devs package up all their code for various use cases. In 2015 there were basically three options people were using most often: Grunt, Gulp, and hand rolled solutions.

This project was bundled with Grunt. I could understand if people think this is cheating; it let’s me escape from having to worry about including all my js files individually on each html page, instead it bundles them all into one .js to include. It also lets me leverage scss by getting Grunt to process my scss files into a .css that I can also include on each page.

I decided to leverage gulp just because I felt like it didn’t take away from this experiment and it would help me stay sane.

gulp.task("concat", function () {
return gulp.src([
'src/constants.js',
'src/api.js',
'src/post.js',
'src/user.js',
'src/*.js'
])
.pipe(concat('bundle.js'))
.pipe(gulp.dest('./dist/'));
});

This gulpfile task will take all of the files listed in the order that they’re specific and concat them all together, following that they output a bundle.js to the dist folder.

dassit.gif

And that’s the end of the writeup for FoldersJS. As you can see, there’s actually a lot that had to happen to create this super simple app! And, if I’m being honest, it was super fun to go down history lane and see the approaches that I began to build this app with.

Future Folders likely won’t follow this historical format, instead I’ll use whatever tooling, frameworks, and libraries I feel like experimenting with (or just plain gets the job done).