You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.1 KiB
124 lines
3.1 KiB
2 years ago
|
"use strict";
|
||
|
|
||
|
var etag = require("etag");
|
||
|
var fresh = require("fresh");
|
||
|
var fs = require("fs");
|
||
|
var path = require("path");
|
||
|
var zlib = require("zlib");
|
||
|
|
||
|
var minifiedScript = path.join(__dirname, "dist", "index.js");
|
||
|
var unminifiedScript = path.join(__dirname, "dist", "index.js");
|
||
|
|
||
|
/**
|
||
|
* Does the current request support compressed encoding?
|
||
|
* @param {Object} req
|
||
|
* @returns {boolean}
|
||
|
*/
|
||
|
function supportsGzip(req) {
|
||
|
var accept = req.headers["accept-encoding"];
|
||
|
return accept && accept.indexOf("gzip") > -1;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set headers on the response
|
||
|
* @param {Object} res
|
||
|
* @param {String} body
|
||
|
*/
|
||
|
function setHeaders(res, body) {
|
||
|
res.setHeader("Cache-Control", "public, max-age=0");
|
||
|
res.setHeader("Content-Type", "text/javascript");
|
||
|
res.setHeader("ETag", etag(body));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {Object} req
|
||
|
* @returns {String}
|
||
|
*/
|
||
|
function isConditionalGet(req) {
|
||
|
return req.headers["if-none-match"] || req.headers["if-modified-since"];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return a not-modified response
|
||
|
* @param {Object} res
|
||
|
*/
|
||
|
function notModified(res) {
|
||
|
res.removeHeader("Content-Type");
|
||
|
res.statusCode = 304;
|
||
|
res.end();
|
||
|
}
|
||
|
|
||
|
function processItems(items) {
|
||
|
return [].concat(items)
|
||
|
.filter(Boolean)
|
||
|
.reduce((stringOutput, item) => {
|
||
|
if (typeof item === 'string') {
|
||
|
return stringOutput + item;
|
||
|
}
|
||
|
if (typeof item === 'function') {
|
||
|
return stringOutput + item();
|
||
|
}
|
||
|
return stringOutput;
|
||
|
}, "");
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Public method for returning either a middleware fn
|
||
|
* or the content as a string
|
||
|
* @param {Object} options
|
||
|
* @param requestBody
|
||
|
* @param {String} type - either `file` or `middleware`
|
||
|
* @returns {*}
|
||
|
*/
|
||
|
function init(options, requestBody, type) {
|
||
|
/**
|
||
|
* If the user asked for a file, simply return the string.
|
||
|
*/
|
||
|
if (type && type === "file") {
|
||
|
return processItems(requestBody);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Otherwise return a function to be used a middleware
|
||
|
*/
|
||
|
return function(req, res) {
|
||
|
/**
|
||
|
* default to using the uncompressed string
|
||
|
* @type {String}
|
||
|
*/
|
||
|
var output = processItems(requestBody);
|
||
|
|
||
|
/**
|
||
|
* Set the appropriate headers for caching
|
||
|
*/
|
||
|
setHeaders(res, output);
|
||
|
var resHeaders = res.getHeaders ? res.getHeaders() : res._headers;
|
||
|
if (isConditionalGet(req) && fresh(req.headers, resHeaders)) {
|
||
|
return notModified(res);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If gzip is supported, compress the string once
|
||
|
* and save for future requests
|
||
|
*/
|
||
|
if (supportsGzip(req)) {
|
||
|
res.setHeader("Content-Encoding", "gzip");
|
||
|
var buf = Buffer.from(output, "utf-8");
|
||
|
zlib.gzip(buf, function(_, result) {
|
||
|
res.end(result);
|
||
|
});
|
||
|
} else {
|
||
|
res.end(output);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
module.exports.middleware = init;
|
||
|
module.exports.plugin = init;
|
||
|
module.exports.minified = function() {
|
||
|
return fs.readFileSync(minifiedScript, "utf8");
|
||
|
};
|
||
|
module.exports.unminified = function() {
|
||
|
return fs.readFileSync(unminifiedScript, "utf8");
|
||
|
};
|