patternjavascriptModerate
Non-generalized Site Generator
Viewed 0 times
generalizedgeneratorsitenon
Problem
For my CS class, I need to, by the end, have written an entire website. The idea for my site is to supply information about Uromastyces. Because of this, most of each page will be nearly identical. The only part that changes will be the main body that contains unique information (this seems to be common on most large sites. The header and navbar are always the same, but the body can differ).
I first manually wrote up the first 3 pages, then realized there was a good number of changes I wanted to make to the layout, which required my to comb through each page of code, making identical changes everywhere.
Then I learned about DOM manipulation, and I came up with the idea of generating the page from a central template, and filling in a section (the "unique body") with the part of the page that changes.
This is the JS code that I came up with to fill this need. It's in 2 main parts, each represented as an object literal:
To change the overall structure,
What I'd like advice on:
I first manually wrote up the first 3 pages, then realized there was a good number of changes I wanted to make to the layout, which required my to comb through each page of code, making identical changes everywhere.
Then I learned about DOM manipulation, and I came up with the idea of generating the page from a central template, and filling in a section (the "unique body") with the part of the page that changes.
This is the JS code that I came up with to fill this need. It's in 2 main parts, each represented as an object literal:
SitePieces: "Generator" functions that create the individual parts of the site (the header, the nav bar, the footer...). Any piece of changeable information is fed in.
SiteFactory: The section that holds all the otherwise "magic" constants that may change, or at least should be easy to change or lookup (class names, and things like the image path for the sidebar image), and puts all the pieces together.
To change the overall structure,
SiteFactory is updated. To change an individual part, the relevant function in SitePieces is updated.What I'd like advice on:
- Right now, all my constants are just grouped together at the top of
SiteFactoryin a semi-arbitrary ordering. Is there a neater way to organize the data?
- General thoughts on the setup of
SitePiecesandSiteFactory.
- Are my comments good? I'm coming from Java, and tried to use a Javadoc-like notation, but there doesn't seem to be any way to access the comments besides manually checking the source.
- Should I be doing type checks? Say, for the function `generateUniqu
Solution
Let's start on a few of the things you explicitly asked questions on before moving over to the code itself.
Are my comments good? I'm coming from Java, and tried to use a Javadoc-like notation, but there doesn't seem to be any way to access the comments besides manually checking the source.
There are a few ways of using comments but most of them stem from some version of JSDoc. JSDoc compliant comments can have a command line tool run over them that parses the comments and generates a web page for those comments. That might be a bit overkill for this scenario, but it does exist and is used widely - most notably by AngularJS (note that that code is in TypeScript, which is a dialect of JavaScript, so don't expect to understand all of it at face value. The comments are what are important).
This documentation becomes this website. Again, this is slightly overkill for a simple project like you have, but it's worth knowing nonetheless.
Should I be doing type checks? Say, for the function
You probably shouldn't be checking types per se, and even if you were, I would recommend an alternative dialect of JavaScript which will cover that purpose much more thoroughly (this is what TypeScript/FlowJS et al try to solve). You should be checking whether or not the thing you are accessing has the properties you need. This is how we implement backwards compatible functionality in JavaScript too (some browsers may not support the functions we're using, so they will be undefined).
That said, in the scenario you have (
JavaScript will throw its own error if you try and append a non-DOM element to the DOM, so there's not much point in you doing that as well.
Let's talk jQuery
I'm glad you said you don't want to learn jQuery just now. I'm a bit bias (currently dealing with a lot of hoo-hah at work due to jQuery and its silliness in work at the moment) but I just want to say to you (and to anyone else reading this) that you might not need jQuery and jQuery is very dangerous when inter-operating between different DOM frameworks (for example - Angular and jQuery) due to the way it internally works by caching elements.
Browsers can make great optimisations on stuff like
Don't get me wrong, developer productivity is definitely better than speed, but jQuery is in a bit of a strange place at the moment where it doesn't make sense to use jQuery on small sites (because the modern API is pretty concise already) and it doesn't make sense to use it on large sites (because frameworks like Angular and React are really good at that). It's basically in a place where it works either as a compatibility layer or as a productivity aid for mid-level sites. Unless you're sure you're going to be making a mid-level site, you should probably just stick to vanilla or framework.
And you should definitely know vanilla before learning jQuery or a framework. As the site says, though, you should know what jQuery is doing for you - and what it isn't.
And should I be using Hungarian-style notation (-"DOM")? I know it's generally frowned upon, but I need to communicate type information somehow.
No. This is a widely reached consensus in the programming community in nearly every language. [citation needed] /thread
Name your functions.
You've got a lot of anonymous functions in your code that are assigned to an object. While in future versions of JavaScript the engine may be able to infer the name of the function based on the key it is assigned to (Babel already does this!), it is a good idea to assign names to your functions. The main benefit of this is that they will show up in the debugger with those names instead of
Example:
On to the code.
I'm going to second what was said in @JosephTheDreamer's answer and suggest that you use a templating library - it'll make it harder for you to lose your sanity later on in the development when you keep having to change things.
Are my comments good? I'm coming from Java, and tried to use a Javadoc-like notation, but there doesn't seem to be any way to access the comments besides manually checking the source.
There are a few ways of using comments but most of them stem from some version of JSDoc. JSDoc compliant comments can have a command line tool run over them that parses the comments and generates a web page for those comments. That might be a bit overkill for this scenario, but it does exist and is used widely - most notably by AngularJS (note that that code is in TypeScript, which is a dialect of JavaScript, so don't expect to understand all of it at face value. The comments are what are important).
This documentation becomes this website. Again, this is slightly overkill for a simple project like you have, but it's worth knowing nonetheless.
Should I be doing type checks? Say, for the function
generateUniqueBody, should I be checking that uniqueBodyDOM is in fact a DOM object?You probably shouldn't be checking types per se, and even if you were, I would recommend an alternative dialect of JavaScript which will cover that purpose much more thoroughly (this is what TypeScript/FlowJS et al try to solve). You should be checking whether or not the thing you are accessing has the properties you need. This is how we implement backwards compatible functionality in JavaScript too (some browsers may not support the functions we're using, so they will be undefined).
That said, in the scenario you have (
generateUniqueBodyWrapper), it is not really feasible to be checking whether or not uniqueBodyDOM is an element or not, so I would recommend simply just making sure that it is not falsey (which is null or undefined). That is something as simple as this:function(uniqueBodyDOM, wrapperClasses) {
if (!uniqueBodyDOM) {
// If uniqueBodyDOM does not exist, nothing will happen.
// You could alternatively throw an error here if you so wished.
return;
}
var uniqueBodyWrapper = document.createElement('section');
uniqueBodyWrapper.className = 'wrapperClasses';
uniqueBodyWrapper.appendChild(uniqueBodyDOM);
return uniqueBodyWrapper;
}JavaScript will throw its own error if you try and append a non-DOM element to the DOM, so there's not much point in you doing that as well.
Let's talk jQuery
I'm glad you said you don't want to learn jQuery just now. I'm a bit bias (currently dealing with a lot of hoo-hah at work due to jQuery and its silliness in work at the moment) but I just want to say to you (and to anyone else reading this) that you might not need jQuery and jQuery is very dangerous when inter-operating between different DOM frameworks (for example - Angular and jQuery) due to the way it internally works by caching elements.
Browsers can make great optimisations on stuff like
document.getElementByXXX such as caching the element so it is O(1) after first access. There's almost never a reason to use jQuery unless you're using a framework that requires it - such as Backbone - or laziness, these days. Or unless you're supporting dinosaur-age browsers.Don't get me wrong, developer productivity is definitely better than speed, but jQuery is in a bit of a strange place at the moment where it doesn't make sense to use jQuery on small sites (because the modern API is pretty concise already) and it doesn't make sense to use it on large sites (because frameworks like Angular and React are really good at that). It's basically in a place where it works either as a compatibility layer or as a productivity aid for mid-level sites. Unless you're sure you're going to be making a mid-level site, you should probably just stick to vanilla or framework.
And you should definitely know vanilla before learning jQuery or a framework. As the site says, though, you should know what jQuery is doing for you - and what it isn't.
And should I be using Hungarian-style notation (-"DOM")? I know it's generally frowned upon, but I need to communicate type information somehow.
No. This is a widely reached consensus in the programming community in nearly every language. [citation needed] /thread
Name your functions.
You've got a lot of anonymous functions in your code that are assigned to an object. While in future versions of JavaScript the engine may be able to infer the name of the function based on the key it is assigned to (Babel already does this!), it is a good idea to assign names to your functions. The main benefit of this is that they will show up in the debugger with those names instead of
(anonymous), making debugging significantly easier.Example:
On to the code.
I'm going to second what was said in @JosephTheDreamer's answer and suggest that you use a templating library - it'll make it harder for you to lose your sanity later on in the development when you keep having to change things.
Code Snippets
function(uniqueBodyDOM, wrapperClasses) {
if (!uniqueBodyDOM) {
// If uniqueBodyDOM does not exist, nothing will happen.
// You could alternatively throw an error here if you so wished.
return;
}
var uniqueBodyWrapper = document.createElement('section');
uniqueBodyWrapper.className = 'wrapperClasses';
uniqueBodyWrapper.appendChild(uniqueBodyDOM);
return uniqueBodyWrapper;
}<template id='template'>
<header class='header'><%= title %></header>
<section class='contents'><%= page %></section>
</template>var data = {
title: 'Hello, world',
page: 'Some random text'
}
var template = document.getElementById('template')
var linkFn = _.template(template.innerHTML)
// This is the node which is actually rendered.
var node = template.cloneNode()
node.innerHTML = linkFn(data)
document.body.appendChild(node)
// You could of course do what Joseph did and just set the innerHTML of an already existing Node instead of cloning & so forth./*
Generates the page header
headerClass: The classes to assign to the header
*/
generateHeader: function(headerClasses) {
var header = document.createElement('header');
var h1 = document.createElement('h1');
h1.innerHTML = "Brendon's Uromastyces Fact Site";
header.appendChild(h1);
return header;
}<template id='header'>
</template>
// Note that I've removed the class aspect because generateHeader wasn't using headerClasses anyway!
/**
* Generates the DOM layout for the page header.
* @param {String} title The title of the page.
*/
function generateHeader(title) {
// This could be separated even *further* if you wanted.
// Note that getElementById is already cached by the browser.
var template = document.getElementById('header').innerHTML
return _.template(template)({ title: title })
}
document.appendChild(generateHeader('Brendon\'s Uromastyces Fact Site'))Context
StackExchange Code Review Q#113855, answer score: 10
Revisions (0)
No revisions yet.