|
|
@ -0,0 +1,159 @@ |
|
|
|
|
|
|
|
|
|
|
|
## Results |
|
|
|
|
|
|
|
|
|
|
|
## Optimize Images |
|
|
|
|
|
|
|
Since images are the largest portion of a website's size, optimizing and reducing the |
|
|
|
size of images will greatly decrease load time. In a perfect web development world, everyone would |
|
|
|
use SVG images which are extremely small and don't need compression. However, since most of us |
|
|
|
use PNG and JPEG images I wrote a script to automatically optimize images for the web. |
|
|
|
|
|
|
|
``` |
|
|
|
#!/bin/bash |
|
|
|
|
|
|
|
# Simple script for optimizing all images for a website |
|
|
|
# |
|
|
|
# @author Jeffery Russell 7-19-18 |
|
|
|
|
|
|
|
WIDTH="690>" # the ">" tag specifies that images will not get scaled up |
|
|
|
|
|
|
|
folders=("./entries" "./img") |
|
|
|
|
|
|
|
for folder in "${folders[@]}"; do |
|
|
|
|
|
|
|
for f in $(find $folder -name '*.jpg' -or -name '*.JPG'); do |
|
|
|
convert "$f" -resize $WIDTH "$f" |
|
|
|
jpegoptim --max=80 --strip-all --preserve --totals --all-progressive "$f" |
|
|
|
done |
|
|
|
|
|
|
|
|
|
|
|
for f in $(find $folder -name '*.png' -or -name '*.PNG'); do |
|
|
|
convert "$f" -resize $WIDTH "$f" |
|
|
|
optipng -o7 -preserve "$f" |
|
|
|
done |
|
|
|
done |
|
|
|
``` |
|
|
|
|
|
|
|
When ran, this script will go through the img, and entries folder recursively and optimize all |
|
|
|
the images in there. If an image is more than 690px wide, it will scale it down to save size. In |
|
|
|
most cases, it is useless to have images with a width greater than 690 because it will just get |
|
|
|
scaled by the client's web browser. |
|
|
|
|
|
|
|
|
|
|
|
If you are running a Debian based linux distro, you can download the dependencies for this script with |
|
|
|
the following commands: |
|
|
|
``` |
|
|
|
apt-get install jpegoptim |
|
|
|
apt-get install optipng |
|
|
|
``` |
|
|
|
|
|
|
|
The goal of this script is to make most of the images under 100kb for the web. It is ok to have |
|
|
|
a few images above 100k, however, you should really avoid having images above 200kb. |
|
|
|
|
|
|
|
|
|
|
|
## Take advantage of Async calls |
|
|
|
|
|
|
|
One of the largest benefits of node is its async abilities where code is executed in a |
|
|
|
multi-threaded fashion. This can become a callback hell if not handled correctly, but, with |
|
|
|
good code structure it can become very easy. When code is executed in parallel, you can greatly |
|
|
|
decrease run time by doing other stuff while waiting on costly file IO or database calls. |
|
|
|
|
|
|
|
The problem with async code is that it is hard to coordinate. Node has a lot of ways to handel |
|
|
|
synchronization, but, I prefer to use [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) |
|
|
|
. Here is a simple example where async code can become inefficient. |
|
|
|
|
|
|
|
Good Code Async: |
|
|
|
``` |
|
|
|
Promise.all([includes.printHeader(), |
|
|
|
require(file).main(filename, request), |
|
|
|
includes.printFooter()]).then(function(content) |
|
|
|
{ |
|
|
|
res.write(content.join('')); |
|
|
|
res.end(); |
|
|
|
}).catch(function(err) |
|
|
|
{ |
|
|
|
console.log(err); |
|
|
|
}); |
|
|
|
``` |
|
|
|
|
|
|
|
Bad Async Code: |
|
|
|
``` |
|
|
|
includes.printHeader(res).then(function() |
|
|
|
{ |
|
|
|
return require(file).main(res, filename, request); |
|
|
|
}).then(function() |
|
|
|
{ |
|
|
|
return includes.printFooter(res); |
|
|
|
}).catch(function(err) |
|
|
|
{ |
|
|
|
console.log(err); |
|
|
|
}) |
|
|
|
``` |
|
|
|
|
|
|
|
In the first example three blocks of async code are executed in parallel and in the second example |
|
|
|
three blocks of async code are executed one after another. Many people may initially do the second |
|
|
|
option because it may seem like you have to create and render the footer after you render the header |
|
|
|
and body of the page. |
|
|
|
|
|
|
|
A great way to handel async calls is by having most of your methods returning promises which resolve to |
|
|
|
the HTML or DB information that they produce. When you run Promise.all, it returns an array of the |
|
|
|
objects which enables you to preserve the order ie header, body, footer. After you do this for all of |
|
|
|
your code, it creates a "perfect" async tree which actually runs very fast. |
|
|
|
|
|
|
|
Another Good Async Example: |
|
|
|
``` |
|
|
|
/** |
|
|
|
* Calls posts and sidebar modules to render blog contents in order |
|
|
|
* |
|
|
|
* @param requestURL |
|
|
|
* @returns {Promise|*} |
|
|
|
*/ |
|
|
|
main: function(requestURL) |
|
|
|
{ |
|
|
|
return new Promise(function(resolve, reject) |
|
|
|
{ |
|
|
|
Promise.all([renderPost(requestURL), |
|
|
|
require("../sidebar/sidebar.js").main()]).then(function(content) |
|
|
|
{ |
|
|
|
resolve(content.join('')); |
|
|
|
}).catch(function(error) |
|
|
|
{ |
|
|
|
reject(error); |
|
|
|
}) |
|
|
|
}); |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
## Client Side Caching |
|
|
|
|
|
|
|
|
|
|
|
``` |
|
|
|
var eTag = crypto.createHash('md5').update(content).digest('hex'); |
|
|
|
result.writeHead(200, {'Content-Type': 'text/css', 'Cache-Control': |
|
|
|
'public, max-age=2678400', 'ETag': '"' + eTag + '"', |
|
|
|
'Vary': 'Accept-Encoding'}); |
|
|
|
result.write(content); |
|
|
|
result.end(); |
|
|
|
cache.put(path, content); |
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
## Server Side Caching |
|
|
|
|
|
|
|
|
|
|
|
## Enable Compression (GZIP) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Purge Unused CSS Definitions |
|
|
|
|
|
|
|
|
|
|
|
## Minify CSS and Javascript |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|