You have successfully created a flat filesystem Content Management System (CMS) using Go. The next step is to take the same ideal and make a web server using Node.js. I will show you how to load the libraries, create the server, and run the server.
This CMS will use the site data structure as laid out in the first tutorial, Building a CMS: Structure and Styling. Therefore, download and install this basic structure in a fresh directory.
The easiest way to install Node.js on a Mac is with Homebrew. If you haven’t installed Homebrew yet, the tutorial Homebrew Demystified: OS X’s Ultimate Package Manager will show you how.
To install Node.js with Homebrew, type this instruction into a terminal:
brew install node
When done, you will have node and npm commands fully installed on your Mac. For all other platforms, follow the instructions on the Node.js website.
Be careful: Many package managers are currently installing Node.js version 0.10. This tutorial is assuming that you have version 5.3 or newer. You can check your version by typing:
node --version
The node command runs the JavaScript interpreter. The npm command is a package manager for Node.js to install new libraries, create new projects, and run scripts for a project. There are many great tutorials and courses on Node.js and NPM at Envato Tuts+.
To install the libraries for the web server, you have to run these commands in the Terminal.app or iTerm.app program:
npm install express --save npm install handlebars --save npm install moment --save npm install marked --save npm install jade --save npm install morgan --save
Express is a web application development platform. It is similar to the goWeb library in Go. Handlebars is the templating engine for creating the pages. Moment is a library for working with dates. Marked is a great Markdown to HTML converter in JavaScript. Jade is an HTML shorthand language for easily creating HTML. Morgan is a middleware library for Express that generates the Apache Standard Log Files.
An alternative way to install the libraries is to download the source files for this tutorial. Once downloaded and unzipped, type this in the main directory:
npm --install
That will install everything needed to create this project.
Now you can get started creating the server. In the top directory of the project, create a file called nodePress.js, open it in your editor of choice, and start adding the following code. I am going to explain the code as it is placed into the file.
//
// Load the libraries used.
//
var fs = require('fs');
var path = require("path");
var child_process = require('child_process');
var process = require('process');
var express = require('express'); // http://expressjs.com/en/
var morgan = require('morgan'); // https://github.com/expressjs/morgan
var Handlebars = require("handlebars"); // http://handlebarsjs.com/
var moment = require("moment"); // http://momentjs.com/
var marked = require('marked'); // https://github.com/chjj/marked
var jade = require('jade'); // http://jade-lang.com/
The server code starts with the initialization of all the libraries used to make the server. Libraries that do not have a comment with a web address are internal Node.js libraries.
//
// Setup Global Variables.
//
var parts = JSON.parse(fs.readFileSync('./server.json', 'utf8'));
var styleDir = process.cwd() + '/themes/styling/' + parts['CurrentStyling'];
var layoutDir = process.cwd() + '/themes/layouts/' + parts['CurrentLayout'];
var siteCSS = null;
var siteScripts = null;
var mainPage = null;
Next, I set up all the global variables and library configurations. The use of global variables is not the best software design practice, but it does work and makes for quick development.
The parts variable is a hash array containing all the parts of a web page. Every page references the contents of this variable. It begins with the contents of the server.json file found at the top of the server directory.
I then use the information from the server.json file to create the complete paths to the styles and layouts directories used for this site.
Three variables are then set to null values: siteCSS, siteScripts, and mainPage. These global variables will contain all the CSS, JavaScripts, and main index page contents. These three items are the most requested items on any web server. Therefore, keeping them in memory saves time. If the Cache variable in the server.json file is false, these items get re-read with every request.
marked.setOptions({
renderer: new marked.Renderer(),
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: false,
smartLists: true,
smartypants: false
});
This block of code is for configuring the Marked library for generating HTML from Markdown. Mostly, I am turning on table and smartLists support.
parts["layout"] = fs.readFileSync(layoutDir + '/template.html', 'utf8');
parts["404"] = fs.readFileSync(styleDir + '/404.html', 'utf8');
parts["footer"] = fs.readFileSync(styleDir + '/footer.html', 'utf8');
parts["header"] = fs.readFileSync(styleDir + '/header.html', 'utf8');
parts["sidebar"] = fs.readFileSync(styleDir + '/sidebar.html', 'utf8');
//
// Read in the page parts.
//
var partFiles = fs.readdirSync(parts['Sitebase'] + "parts/");
partFiles.forEach(function(ele, index, array) {
parts[path.basename(ele, path.extname(ele))] = figurePage(parts['Sitebase'] + "parts/" + path.basename(ele, path.extname(ele)));
});
The parts variable is further loaded with the parts from the styles and layout directories. Every file in the parts directory inside the site directory is also loaded into the parts global variable. The name of the file without the extension is the name used to store the contents of the file. These names get expanded in the Handlebars macro.
//
// Setup Handlebar's Helpers.
//
//
// HandleBars Helper: save
//
// Description: This helper expects a
// "<name>" "<value>" where the name
// is saved with the value for future
// expansions. It also returns the
// value directly.
//
Handlebars.registerHelper("save", function(name, text) {
//
// Local Variables.
//
var newName = "", newText = "";
//
// See if the name and text is in the first argument
// with a |. If so, extract them properly. Otherwise,
// use the name and text arguments as given.
//
if(name.indexOf("|") > 0) {
var parts = name.split("|");
newName = parts[0];
newText = parts[1];
} else {
newName = name;
newText = text;
}
//
// Register the new helper.
//
Handlebars.registerHelper(newName, function() {
return newText;
});
//
// Return the text.
//
return newText;
});
//
// HandleBars Helper: date
//
// Description: This helper returns the date
// based on the format given.
//
Handlebars.registerHelper("date", function(dFormat) {
return moment().format(dFormat);
});
//
// HandleBars Helper: cdate
//
// Description: This helper returns the date given
// in to a format based on the format
// given.
//
Handlebars.registerHelper("cdate", function(cTime, dFormat) {
return moment(cTime).format(dFormat);
});
The next section of code defines the Handlebars helpers that I defined for use in the web server: save, date, and cdate. The save helper allows for the creation of variables inside a page. This version supports the goPress version where the parameter has the name and value together separated by a “|”. You can also specify a save using two parameters. For example:
{{save "name|Richard Guay"}}
{{save "newName" "Richard Guay"}}
Name is: {{name}}
newName is: {{newName}}
This will produce the same results. I prefer the second approach, but the Handlebars library in Go doesn’t allow for more than one parameter.
The date and cdate helpers format the current date (date) or a given date (cdate) according to the moment.js library formatting rules. The cdate helper expects the date to render to be the first parameter and have the ISO 8601 format.
//
// Create and configure the server.
//
var nodePress = express();
//
// Configure middleware.
//
nodePress.use(morgan('combined'))
Now, the code creates an Express instance for configuring the actual server engine. The nodePress.use() function sets up the middleware software. Middleware is any code that gets served on every call to the server. Here, I set up the Morgan.js library to create the proper server log output.
//
// Define the routes.
//
nodePress.get('/', function(request, response) {
setBasicHeader(response);
if((parts["Cache"] == true) && (mainPage != null)) {
response.send(mainPage);
} else {
mainPage = page("main");
response.send(mainPage);
}
});
nodePress.get('/favicon.ico', function(request, response) {
var options = {
root: parts['Sitebase'] + 'images/',
dotfiles: 'deny',
headers: {
'x-timestamp': Date.now(),
'x-sent': true
}
};
response.set("Content-Type", "image/ico");
setBasicHeader(response);
response.sendFile('favicon.ico', options, function(err) {
if (err) {
console.log(err);
response.status(err.status).end();
} else {
console.log('Favicon was sent:', 'favicon.ico');
}
});
});
nodePress.get('/stylesheets.css', function(request, response) {
response.set("Content-Type", "text/css");
setBasicHeader(response);
response.type("css");
if((parts["Cache"] == true) && (siteCSS != null)) {
response.send(siteCSS);
} else {
siteCSS = fs.readFileSync(parts['Sitebase'] + 'css/final/final.css');
response.send(siteCSS);
}
});
nodePress.get('/scripts.js', function(request, response) {
response.set("Content-Type", "text/javascript");
setBasicHeader(response);
if((parts["Cache"] == true) && (siteScripts != null)) {
response.send(siteScripts);
} else {
siteScripts = fs.readFileSync(parts['Sitebase'] + 'js/final/final.js', 'utf8');
response.send(siteScripts);
}
});
nodePress.get('/images/:image', function(request, response) {
var options = {
root: parts['Sitebase'] + 'images/',
dotfiles: 'deny',
headers: {
'x-timestamp': Date.now(),
'x-sent': true
}
};
response.set("Content-Type", "image/" + path.extname(request.params.image).substr(1));
setBasicHeader(response);
response.sendFile(request.params.image, options, function(err) {
if (err) {
console.log(err);
response.status(err.status).end();
} else {
console.log('Image was sent:', request.params.image);
}
});
});
nodePress.get('/posts/blogs/:blog', function(request, response) {
setBasicHeader(response);
response.send(post("blogs", request.params.blog, "index"));
});
nodePress.get('/posts/blogs/:blog/:post', function(request, response) {
setBasicHeader(response);
response.send(post("blogs", request.params.blog, request.params.post));
});
nodePress.get('/posts/news/:news', function(request, response) {
setBasicHeader(response);
response.send(post("news", request.params.news, "index"));
});
nodePress.get('/posts/news/:news/:post', function(request, response) {
setBasicHeader(response);
response.send(post("news", request.params.news, request.params.post));
});
nodePress.get('/:page', function(request, response) {
setBasicHeader(response);
response.send(page(request.params.page));
});
This section of code defines all the routes needed to implement the web server. All routes run the setBasicHeader() function to set the proper header values. All requests for a page type will evoke the page() function, while all requests for post type page will evoke the posts() function.
The default for Content-Type is HTML. Therefore, for CSS, JavaScript, and images, the Content-Type is explicitly set to its appropriate value.
You can also define routes with the put, delete, and post REST verbs. This simple server only makes use of the get verb.
//
// Start the server.
//
var addressItems = parts['ServerAddress'].split(':');
var server = nodePress.listen(addressItems[2], function() {
var host = server.address().address;
var port = server.address().port;
console.log('nodePress is listening at http://%s:%s', host, port);
});
The last thing to do before defining the different functions used is to start the server. The server.json file contains the DNS name (here, it is localhost) and the port for the server. Once parsed, the server’s listen() function uses the port number to start the server. Once the server port is open, the script logs the address and port for the server.
//
// Function: setBasicHeader
//
// Description: This function will set the basic header information
// needed.
//
// Inputs:
// response The response object
//
function setBasicHeader(response) {
response.append("Cache-Control", "max-age=2592000, cache");
response.append("Server", "nodePress - a CMS written in node from Custom Computer Tools: http://customct.com.");
}
The first function defined is the setBasicHeader() function. This function sets the response header to tell the browser to cache the page for one month. It also tells the browser that the server is a nodePress server. If there are any other standard header values you want, you would add them here with the response.append() function.
//
// Function: page
//
// Description: This function processes a page request
//
// Inputs:
// page The requested page
//
function page(page) {
//
// Process the given page using the standard layout.
//
return (processPage(parts["layout"], parts['Sitebase'] + "pages/" + page));
}
The page() function sends the layout template for a page and the location of the page on the server to the processPage() function.
//
// Function: post
//
// Description: This function processes a post request
//
// Inputs:
// type The type of post.
// cat The category of the post.
// post The requested post
//
function post(type, cat, post) {
//
// Process the post given the type and the post name.
//
return (processPage(parts["layout"], parts['Sitebase'] + "posts/" + type + "/" + cat + "/" + post));
}
The post() function is just like the page() function, except that posts have more items to define each post. In this series of servers, a post contains a type, category, and the actual post. The type is either blogs or news. The category is flatcms. Since these represent directory names, you can make them whatever you want. Just match the naming to what is in your file system.
//
// Function: processPage
//
// Description: This function processes a page for the CMS.
//
// Inputs:
// layout The layout to use for the page.
// page Path to the page to render.
//
function processPage(layout, page) {
//
// Get the pages contents and add to the layout.
//
var context = {};
context = MergeRecursive(context, parts);
context['content'] = figurePage(page);
context['PageName'] = path.basename(page, path.extname(page));
//
// Load page data.
//
if(fileExists(page + ".json")) {
//
// Load the page's data file and add it to the data structure.
//
context = MergeRecursive(context, JSON.parse(fs.readFileSync(page + '.json', 'utf8')));
}
//
// Process Handlebars codes.
//
var template = Handlebars.compile(layout);
var html = template(context);
//
// Process all shortcodes.
//
html = processShortCodes(html);
//
// Run through Handlebars again.
//
template = Handlebars.compile(html);
html = template(context);
//
// Return results.
//
return (html);
}
The processPage() function gets the layout and the path to the page contents to render. The function starts by making a local copy of the parts global variable and adding the “contents” hashtag with the results of calling figurePage() function. It then sets the PageName hash value to the name of the page.
This function then compiles the page contents to the layout template using Handlebars. After that, the processShortCodes() function will expand all of the shortcodes defined on the page. Then, the Handlebars template engine goes over the code once more. The browser then receives the results.
//
// Function: processShortCodes
//
// Description: This function takes a string and
// processes all of the shortcodes in
// the string.
//
// Inputs:
// content String to process
//
function processShortCodes(content) {
//
// Create the results variable.
//
var results = "";
//
// Find the first match.
//
var scregFind = /\-\[([^\]]*)\]\-/i;
var match = scregFind.exec(content);
if (match != null) {
results += content.substr(0,match.index);
var scregNameArg = /(\w+)(.*)*/i;
var parts = scregNameArg.exec(match[1]);
if (parts != null) {
//
// Find the closing tag.
//
var scregClose = new RegExp("\\-\\[\\/" + parts[1] + "\\]\\-");
var left = content.substr(match.index + 4 + parts[1].length);
var match2 = scregClose.exec(left);
if (match2 != null) {
//
// Process the enclosed shortcode text.
//
var enclosed = processShortCodes(content.substr(match.index + 4 + parts[1].length, match2.index));
//
// Figure out if there were any arguments.
//
var args = "";
if (parts.length == 2) {
args = parts[2];
}
//
// Execute the shortcode.
//
results += shortcodes[parts[1]](args, enclosed);
//
// Process the rest of the code for shortcodes.
//
results += processShortCodes(left.substr(match2.index + 5 + parts[1].length));
} else {
//
// Invalid shortcode. Return full string.
//
results = content;
}
} else {
//
// Invalid shortcode. Return full string.
//
results = content;
}
} else {
//
// No shortcodes found. Return the string.
//
results = content;
}
return (results);
}
The processShortCodes() function takes the web page contents as a string and searches for all shortcodes. A shortcode is a block of code similar to HTML tags. An example would be:
-[box]-
<p>This is inside a box</p>
-[/box]-
This code has a shortcode for box around an HTML paragraph. Where HTML uses < and >, shortcodes use -[ and ]-. After the name, a string containing arguments to the shortcode can or cannot be there.
The processShortCodes() function finds a shortcode, gets its name and arguments, finds the end to get the contents, processes the contents for shortcodes, executes the shortcode with the arguments and contents, adds the results to the finished page, and searches for the next shortcode in the rest of the page. The looping is performed by recursively calling the function.
//
// Define the shortcodes function array.
//
var shortcodes = {
'box': function(args, inside) {
return ("<div class='box'>" + inside + "</div>");
},
'Column1': function(args, inside) {
return ("<div class='col1'>" + inside + "</div>");
},
'Column2': function(args, inside) {
return ("<div class='col2'>" + inside + "</div>");
},
'Column1of3': function(args, inside) {
return ("<div class='col1of3'>" + inside + "</div>");
},
'Column2of3': function(args, inside) {
return ("<div class='col2of3'>" + inside + "</div>");
},
'Column3of3': function(args, inside) {
return ("<div class='col3of3'>" + inside + "</div>");
},
'php': function(args, inside) {
return ("<div class='showcode'><pre type='syntaxhighlighter' class='brush: php'>" + inside + "</pre></div>");
},
'js': function(args, inside) {
return ("<div class='showcode'><pre type='syntaxhighlighter' class='brush: javascript'>" + inside + "</pre></div>");
},
'html': function(args, inside) {
return ("<div class='showcode'><pre type='syntaxhighlighter' class='brush: html'>" + inside + "</pre></div>");
},
'css': function(args, inside) {
return ("<div class='showcode'><pre type='syntaxhighlighter' class='brush: css'>" + inside + "</pre></div>");
}
};
This next section defines the shortcodes json structure that defines the name of a shortcode associated to its function. All shortcode functions accept two parameters: args and inside. The args is everything after the name and space and before the closing of the tag. The inside is everything contained by the opening and closing shortcode tags. These functions are basic, but you can create a shortcode to perform anything you can think of in JavaScript.
//
// Function: figurePage
//
// Description: This function figures the page type
// and loads the contents appropriately
// returning the HTML contents for the page.
//
// Inputs:
// page The page to load contents.
//
function figurePage(page) {
var result = "";
if (fileExists(page + ".html")) {
//
// It's an HTML file. Read it in and send it on.
//
result = fs.readFileSync(page + ".html");
} else if (fileExists(page + ".amber")) {
//
// It's a jade file. Convert to HTML and send it on. I
// am still using the amber extension for compatibility
// to goPress.
//
var jadeFun = jade.compileFile(page + ".amber", {});
// Render the function
var result = jadeFun({});
} else if (fileExists(page + ".md")) {
//
// It's a markdown file. Convert to HTML and send
// it on.
//
result = marked(fs.readFileSync(page + ".md").toString());
//
// This undo marked's URI encoding of quote marks.
//
result = result.replace(/\"\;/g,"\"");
}
return (result);
}
The figurePage() function receives the full path to a page on the server. This function then tests for it to be an HTML, Markdown, or Jade page based on the extension. I am still using .amber for Jade since that was the library I used with the goPress server. All Markdown and Jade contents get translated into HTML before passing it on to the calling routine. Since the Markdown processor translates all quotes to ", I translate them back before passing it back.
//
// Function: fileExists
//
// Description: This function returns a boolean true if
// the file exists. Otherwise, false.
//
// Inputs:
// filePath Path to a file in a string.
//
function fileExists(filePath) {
try {
return fs.statSync(filePath).isFile();
} catch (err) {
return false;
}
}
The fileExists() function is a replacement for the fs.exists() function that used to be a part of the fs library of Node.js. It uses the fs.statSync() function to try to get the status of the file. If an error happens, a false is returned. Otherwise, it returns true.
//
// Function: MergeRecursive
//
// Description: Recursively merge properties of two objects
//
// Inputs:
// obj1 The first object to merge
// obj2 The second object to merge
//
function MergeRecursive(obj1, obj2) {
for (var p in obj2) {
try {
// Property in destination object set; update its value.
if (obj2[p].constructor == Object) {
obj1[p] = MergeRecursive(obj1[p], obj2[p]);
} else {
obj1[p] = obj2[p];
}
} catch (e) {
// Property in destination object not set; create it and set its value.
obj1[p] = obj2[p];
}
}
return obj1;
}
The last function is the MergeRecursive() function. It copies the second pass object into the first passed object. I make use of this to copy the main parts global variable into a local copy before adding page-specific parts.
After saving the file, you can run the server with:
node nodePress.js
Alternatively, you can use the npm script that is in the package.json file. You run npm scripts like this:
npm start
This will run the start script that is inside the package.json file.

Point your web browser to http://localhost:8080 and you will see the page above. You might have noticed that I added more test code to the main page. All the changes to the pages are in the download for this tutorial. They're mostly just some minor tweaks to more completely test the functionality and to fit any differences from using different libraries. The most notable difference is that the Jade library doesn't use $ to name variables while Amber does.
Now you have exactly the same flat filesystem CMS in Go and Node.js. This only scratches the surface of what you can build with this platform. Experiment and try something new. That is the best part of creating your own web server.
Create Modern Vue Apps Using Create-Vue and Vite
/
5Pros and Cons of Using WordPress
/
-4How to Fix the “There Has Been a Critical Error in Your Website” Error in WordPress
/
1How To Fix The “There Has Been A Critical Error in Your Website” Error in WordPress
How to Create a Privacy Policy Page in WordPress
/
7WordPress Website Maintenance Guide For Beginners
/
6How Long Does It Take to Learn JavaScript?
/
-1How Long Does it Take to Learn JavaScript
/
1The Best Way to Deep Copy an Object in JavaScript
/
-2
4
-6Adding and Removing Elements From Arrays in JavaScript
/
-1Create a JavaScript AJAX Post Request: With and Without jQuery
/
85 Real-Life Uses for the JavaScript reduce() Method
/
-10How to Enable or Disable a Button With [removed] jQuery vs. Vanilla
/
2How to Enable or Disable a Button With [removed] jQuery vs Vanilla
/
-3Confirm Yes or No With JavaScript
/
-2How to Change the URL in [removed] Redirecting
/
-415+ Best WordPress Twitter Widgets
/
-227 Best Tab and Accordion Widget Plugins for WordPress (Free & Premium)
/
1121 Best Tab and Accordion Widget Plugins for WordPress (Free & Premium)
/
-1130 HTML Best Practices for Beginners
/
-731 Best WordPress Calendar Plugins and Widgets (With 5 Free Plugins)
/
625 Ridiculously Impressive HTML5 Canvas Experiments
/
-5
1How to Implement Email Verification for New Members
/
2How to Create a Simple Web-Based Chat Application
/
530 Popular WordPress User Interface Elements
/
-4Top 18 Best Practices for Writing Super Readable Code
/
3Best Affiliate WooCommerce Plugins Compared
/
-1018 Best WordPress Star Rating Plugins
/
1410+ Best WordPress Twitter Widgets
/
420+ Best WordPress Booking and Reservation Plugins
/
5Working With Tables in React: Part Two
/
-4Best CSS Animations and Effects on CodeCanyon
/
-1630 CSS Best Practices for Beginners
/
4How to Create a Custom WordPress Plugin From Scratch
/
510 Best Responsive HTML5 Sliders for Images and Text… and 3 Free Options
/
-516 Best Tab and Accordion Widget Plugins for WordPress
/
-518 Best WordPress Membership Plugins and 5 Free Plugins
/
325 Best WooCommerce Plugins for Products, Pricing, Payments and More
/
210 Best WordPress Twitter Widgets
1 /
1512 Best Contact Form PHP Scripts for 2020
/
-420 Popular WordPress User Interface Elements
/
-210 Best WordPress Star Rating Plugins
/
-412 Best CSS Animations on CodeCanyon
/
112 Best WordPress Booking and Reservation Plugins
/
120 Best WordPress Calendar Plugins and Widgets
/
-212 Elegant CSS Pricing Tables for Your Latest Web Project
/
724 Best WordPress Form Plugins for 2020
/
-214 Best PHP Event Calendar and Booking Scripts
/
-2Create a Blog for Each Category or Department in Your WooCommerce Store
/
28 Best WordPress Booking and Reservation Plugins
/
-18Best Exit Popups for WordPress Compared
/
20Best Exit Popups for WordPress Compared
/
-611 Best Tab & Accordion WordPress Widgets & Plugins
/
-1012 Best Tab & Accordion WordPress Widgets & Plugins
1New Course: Practical React Fundamentals
/
3Short Course: Better Angular App Architecture With Modules
/
3Preview Our New Course on Angular Material
/
4Object-Oriented PHP With Classes and Objects
/
3Best Practices for ARIA Implementation
/
-3Accessible Apps: Barriers to Access and Getting Started With Accessibility
/
-4Dramatically Speed Up Your React Front-End App Using Lazy Loading
/
1915 Best Modern JavaScript Admin Templates for React, Angular, and Vue.js
/
-1515 Best Modern JavaScript Admin Templates for React, Angular and Vue.js
/
219 Best JavaScript Admin Templates for React, Angular, and Vue.js
/
3New Course: Build an App With JavaScript and the MEAN Stack
/
12Hands-on With ARIA: Accessibility Recipes for Web Apps
/
910 Best WordPress Facebook Widgets
13 /
-5Hands-on With ARIA: Accessibility for eCommerce
/
6New eBooks Available for Subscribers
/
-6Hands-on With ARIA: Homepage Elements and Standard Navigation
/
10
-8Site Accessibility: Getting Started With ARIA
/
4How Secure Are Your JavaScript Open-Source Dependencies?
/
-1New Course: Secure Your WordPress Site With SSL
/
-3Testing Components in React Using Jest and Enzyme
/
-9Testing Components in React Using Jest: The Basics
/
-515 Best PHP Event Calendar and Booking Scripts
/
-1Create Interactive Gradient Animations Using Granim.js
/
10How to Build Complex, Large-Scale Vue.js Apps With Vuex
1Examples of Dependency Injection in PHP With Symfony Components
/
-6Set Up Routing in PHP Applications Using the Symfony Routing Component
1 /
11A Beginner’s Guide to Regular Expressions in JavaScript
/
13Introduction to Popmotion: Custom Animation Scrubber
/
-6Introduction to Popmotion: Pointers and Physics
/
-10New Course: Connect to a Database With Laravel’s Eloquent ORM
/
-5How to Create a Custom Settings Panel in WooCommerce
/
-12Building the DOM faster: speculative parsing, async, defer and preload
120 Useful PHP Scripts Available on CodeCanyon
3 /
51How to Find and Fix Poor Page Load Times With Raygun
/
1Introduction to the Stimulus Framework
/
-12Single-Page React Applications With the React-Router and React-Transition-Group Modules
/
2
812 Best Contact Form PHP Scripts
1 /
-5Getting Started With the Mojs Animation Library: The ShapeSwirl and Stagger Modules
/
1Getting Started With the Mojs Animation Library: The Shape Module
/
-4Getting Started With the Mojs Animation Library: The HTML Module
/
4Project Management Considerations for Your WordPress Project
/
-88 Things That Make Jest the Best React Testing Framework
/
3Creating an Image Editor Using CamanJS: Layers, Blend Modes, and Events
/
-2New Short Course: Code a Front-End App With GraphQL and React
/
1Creating an Image Editor Using CamanJS: Applying Basic Filters
/
-14Creating an Image Editor Using CamanJS: Creating Custom Filters and Blend Modes
/
-3Challenge: Create a To-Do List in React
1 /
1Deploy PHP Web Applications Using Laravel Forge
/
-2Getting Started With the Mojs Animation Library: The Burst Module
/
6
-1010 Things Men Can Do to Support Women in Tech
/
1A Gentle Introduction to Higher-Order Components in React: Best Practices
/
-4Challenge: Build a React Component
/
-4A Gentle Introduction to HOC in React: Learn by Example
/
5A Gentle Introduction to Higher-Order Components in React
/
-6Creating Pretty Popup Messages Using SweetAlert2
/
5Creating Stylish and Responsive Progress Bars Using ProgressBar.js
/
1818 Best Contact Form PHP Scripts for 2022
/
-3How to Make a Real-Time Sports Application Using Node.js
/
-1Creating a Blogging App Using Angular & MongoDB: Delete Post
/
-16Set Up an OAuth2 Server Using Passport in Laravel
/
1Creating a Blogging App Using Angular & MongoDB: Edit Post
/
-2Creating a Blogging App Using Angular & MongoDB: Add Post
/
-1Introduction to Mocking in Python
/
-1Creating a Blogging App Using Angular & MongoDB: Show Post
/
9Creating a Blogging App Using Angular & MongoDB: Home
/
8
3Creating a Blogging App Using Angular & MongoDB: Login
/
13Creating Your First Angular App: Implement Routing
/
12Persisted WordPress Admin Notices: Part 4
/
-4Creating Your First Angular App: Components, Part 2
/
4Persisted WordPress Admin Notices: Part 3
/
4
8Persisted WordPress Admin Notices: Part 2
/
-3Create Your First Angular App: Storing and Accessing Data
/
3Persisted WordPress Admin Notices: Part 1
/
-3Error and Performance Monitoring for Web & Mobile Apps Using Raygun
/
6Using Luxon for Date and Time in JavaScript
7 /
-6How to Create an Audio Oscillator With the Web Audio API
/
-4How to Cache Using Redis in Django Applications
/
220 Essential WordPress Utilities to Manage Your Site
/
-6Introduction to API Calls With React and Axios
/
18Beginner’s Guide to Angular 4: HTTP
/
11Rapid Web Deployment for Laravel With GitHub, Linode, and RunCloud.io
/
9Beginners Guide to Angular 4: Routing
/
-9Beginner’s Guide to Angular 4: Components
/
1Creating a Drop-Down Menu for Mobile Pages
/
5Introduction to Forms in Angular 4: Writing Custom Form Validators
/
5Getting Started With Redux: Connecting Redux With React
/
15Getting Started With Redux: Learn by Example
/
16Getting Started With Redux: Why Redux?
/
9Understanding Recursion With JavaScript
/
-3How to Auto Update WordPress Salts
/
-7How to Download Files in Python
/
-3
-22Eloquent Mutators and Accessors in Laravel
1 /
18
-11
1310 Best HTML5 Sliders for Images and Text
/
6Site Authentication in Node.js: User Signup
/
-5Creating a Task Manager App Using Ionic: Part 2
/
1Creating a Task Manager App Using Ionic: Part 1
/
1
4Introduction to Forms in Angular 4: Template-Driven Forms
/
-224 Essential WordPress Utilities to Manage Your Site
/
-225 Essential WordPress Utilities to Manage Your Site
/
-11Get Rid of Bugs Quickly Using BugReplay
1 /
-16Manipulating HTML5 Canvas Using Konva: Part 1, Getting Started
/
610 Must-See Easy Digital Downloads Extensions for Your WordPress Site
/
-122 Best WordPress Booking and Reservation Plugins
/
-6Understanding ExpressJS Routing
/
-715 Best WordPress Star Rating Plugins
/
12Inheritance and Extending Objects With JavaScript
/
-9Introduction to the CSS Grid Layout With Examples
1 /
1
8Performant Animations Using KUTE.js: Part 5, Easing Functions and Attributes
/
-9Performant Animations Using KUTE.js: Part 4, Animating Text
/
-14Performant Animations Using KUTE.js: Part 3, Animating SVG
/
-9New Course: Code a Quiz App With Vue.js
/
-1Performant Animations Using KUTE.js: Part 2, Animating CSS Properties
/
3
8Performant Animations Using KUTE.js: Part 1, Getting Started
/
110 Best Responsive HTML5 Sliders for Images and Text (Plus 3 Free Options)
/
-3Single-Page Applications With ngRoute and ngAnimate in AngularJS
/
-13Deferring Tasks in Laravel Using Queues
/
-5
4Site Authentication in Node.js: User Signup and Login
/
12Working With Tables in React, Part Two
/
-16Working With Tables in React, Part One
/
6How to Set Up a Scalable, E-Commerce-Ready WordPress Site Using ClusterCS
/
-4New Course on WordPress Conditional Tags
/
2TypeScript for Beginners, Part 5: Generics
/
1
-12Building With Vue.js 2 and Firebase
6 /
11
-8Best Unique Bootstrap JavaScript Plugins
/
-9
-4Essential JavaScript Libraries and Frameworks You Should Know About
/
7
2Vue.js Crash Course: Create a Simple Blog Using Vue.js
/
-13Build a React App With a Laravel RESTful Back End: Part 1, Laravel 5.5 API
/
4API Authentication With Node.js
/
-4Beginner’s Guide to Angular: HTTP
/
7Beginner’s Guide to Angular: Routing
/
-4Beginners Guide to Angular: Routing
/
-6Beginner’s Guide to Angular: Services
/
4How to Create a Custom Authentication Guard in Laravel
/
6Learn Computer Science With [removed] Part 3, Loops
/
-4Build Web Applications Using Node.js
/
1Learn Computer Science With [removed] Part 4, Functions
/
4Learn Computer Science With [removed] Part 2, Conditionals
/
14Learn Computer Science With [removed] Part 1, The Basics
/
-4Create Interactive Charts Using Plotly.js, Part 5: Pie and Gauge Charts
/
-9Create Interactive Charts Using Plotly.js, Part 4: Bubble and Dot Charts
/
18Create Interactive Charts Using Plotly.js, Part 3: Bar Charts
/
-13Awesome JavaScript Libraries and Frameworks You Should Know About
/
-4Create Interactive Charts Using Plotly.js, Part 2: Line Charts
/
-8Bulk Import a CSV File Into MongoDB Using Mongoose With Node.js
/
-5Build a To-Do API With Node, Express, and MongoDB
/
-7Getting Started With End-to-End Testing in Angular Using Protractor
/
9TypeScript for Beginners, Part 4: Classes
/
-10Object-Oriented Programming With JavaScript
/
610 Best Affiliate WooCommerce Plugins Compared
/
8Stateful vs. Stateless Functional Components in React
/
10Make Your JavaScript Code Robust With Flow
/
-5Build a To-Do API With Node and Restify
/
7Testing Components in Angular Using Jasmine: Part 2, Services
/
2Testing Components in Angular Using Jasmine: Part 1
/
-2Creating a Blogging App Using React, Part 6: Tags
/
-11React Crash Course for Beginners, Part 3
/
2React Crash Course for Beginners, Part 2
/
10React Crash Course for Beginners, Part 1
/
2Set Up a React Environment, Part 4
1 /
8Set Up a React Environment, Part 3
/
-12New Course: Get Started With Phoenix
/
-10Set Up a React Environment, Part 2
/
2Set Up a React Environment, Part 1
/
1Command Line Basics and Useful Tricks With the Terminal
/
5How to Create a Real-Time Feed Using Phoenix and React
/
-7Build a React App With a Laravel Back End: Part 2, React
/
2Build a React App With a Laravel RESTful Back End: Part 1, Laravel 9 API
/
-6Creating a Blogging App Using React, Part 5: Profile Page
/
-5Pagination in CodeIgniter: The Complete Guide
/
23JavaScript-Based Animations Using Anime.js, Part 4: Callbacks, Easings, and SVG
JavaScript-Based Animations Using Anime.js, Part 3: Values, Timeline, and Playback
Learn to Code With [removed] Part 1, The Basics
/
510 Elegant CSS Pricing Tables for Your Latest Web Project
/
-8Getting Started With the Flux Architecture in React
/
-3Getting Started With Matter.js: The Composites and Composite Modules
/
4Getting Started With Matter.js: The Engine and World Modules
/
1410 More Popular HTML5 Projects for You to Use and Study
/
-24Understand the Basics of Laravel Middleware
/
-6Iterating Fast With Django & Heroku
/
8Creating a Blogging App Using React, Part 4: Update & Delete Posts
/
4Creating a jQuery Plugin for Long Shadow Design
/
-10How to Register & Use Laravel Service Providers
2 /
-13Unit Testing in React: Shallow vs. Static Testing
/
5Creating a Blogging App Using React, Part 3: Add & Display Post
/
16Creating a Blogging App Using React, Part 2: User Sign-Up
20 /
-6Creating a Blogging App Using React, Part 1: User Sign-In
/
99 More Popular HTML5 Projects for You to Use and Study
/
18Creating a Grocery List Manager Using Angular, Part 2: Managing Items
/
8Dynamic Page Templates in WordPress, Part 3
/
-1Angular vs. React: 7 Key Features Compared
/
5Creating a Grocery List Manager Using Angular, Part 1: Add & Display Items
/
3New eBooks Available for Subscribers in June 2017
/
7Create Interactive Charts Using Plotly.js, Part 1: Getting Started
/
11The 5 Best IDEs for WordPress Development (And Why)
/
133 Popular WordPress User Interface Elements
/
2New Course: How to Hack Your Own App
/
-10How to Install Yii on Windows or a Mac
/
5What Is a JavaScript Operator?
/
-5How to Register and Use Laravel Service Providers
/
8
waly Good blog post. I absolutely love this…