pagespeed-quest
Version:
A framework for efficient web front-end speed improvement
96 lines • 8.24 kB
JavaScript
import Crypto from 'crypto';
import Path from 'path';
const DirectoryIndex = 'index.html';
const BasenameMaxLength = 196;
const HashLength = 8;
const IgnoreParams = process.env.IGNORE_PARAMS || 'ts';
const IgnoreParamsRegex = IgnoreParams.split(/\s*,\s*/).map((p) => new RegExp(`(?<=[?&]${p}=)[^&]*`, 'g'));
/**
* Remove IgnoreParams from URL
* Default: ts (timestamp) assumed different for each request
* @param url
* @returns
*/
export function normalizeUrl(url) {
const urlObj = typeof url === 'string' ? new URL(url) : url;
// Remove dynamic params
if (urlObj.search !== '') {
urlObj.search = IgnoreParamsRegex.reduce((search, re) => {
return search.replace(re, '');
}, urlObj.search);
}
return urlObj;
}
/**
* Convert URL to content file path
* For example:
* https://example.com/foo/bar.html?hoge=123 -> example.com/foo/bar~hoge=123.html
* - Add directory index (index.html) if URL ends with slash
* - Shorten too long basename with short hash
* - Ignore dynamic params for example: ts=123
* @param url
* @returns
*/
export function requestContentFilePath(method, url) {
const urlObj = normalizeUrl(url);
const protocol = urlObj.protocol.replace(/:/g, '');
const host = urlObj.host.replace(/:/g, '~');
// Directory Index (index.html)
let pathname = urlObj.pathname;
if (pathname.endsWith('/')) {
pathname += DirectoryIndex;
}
else {
const ext = Path.extname(pathname);
if (ext === '') {
pathname = Path.join(pathname, DirectoryIndex);
}
}
const dir = Path.dirname(pathname);
const ext = Path.extname(pathname);
const base = Path.basename(pathname, ext);
let filename = base;
// Search params
if (urlObj.search !== '') {
// Remove dynamic params
const search = IgnoreParamsRegex.reduce((search, re) => {
return search.replace(re, '');
}, urlObj.search);
filename = [filename, search.slice(1)].join('~');
}
// Shorten too long basename
if (filename.length > BasenameMaxLength) {
const trunk = filename.slice(0, BasenameMaxLength);
const hash = Crypto.createHash('sha1');
hash.update(filename);
const digest = hash.digest('hex').slice(0, HashLength);
filename = [trunk, digest].join('_');
}
// Extension
filename += ext;
// Content file relative path
const relPath = Path.join(dir, filename);
return Path.join(method, protocol, host, relPath);
}
export function parseContentTypeHeader(contentType) {
const [mime, ...params] = contentType.split(/;/).map((s) => s.trim());
const charsetParam = params.find((p) => p.startsWith('charset='));
return {
mime,
charset: charsetParam ? charsetParam.slice('charset='.length) : undefined,
};
}
export function stringifyContentTypeHeader(mime, charset, original) {
const params = original ? original.split(/;/).map((s) => s.trim()) : [];
if (mime)
params[0] = mime;
if (charset) {
const charsetParamIndex = params.findIndex((p) => p.startsWith('charset='));
if (charsetParamIndex >= 0)
params.splice(charsetParamIndex, 1, `charset=${charset}`);
else
params.splice(1, 0, `charset=${charset}`);
}
return params.join('; ');
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9odHRwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sTUFBTSxNQUFNLFFBQVEsQ0FBQTtBQUMzQixPQUFPLElBQUksTUFBTSxNQUFNLENBQUE7QUFFdkIsTUFBTSxjQUFjLEdBQUcsWUFBWSxDQUFBO0FBQ25DLE1BQU0saUJBQWlCLEdBQUcsR0FBRyxDQUFBO0FBQzdCLE1BQU0sVUFBVSxHQUFHLENBQUMsQ0FBQTtBQUNwQixNQUFNLFlBQVksR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLGFBQWEsSUFBSSxJQUFJLENBQUE7QUFDdEQsTUFBTSxpQkFBaUIsR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxNQUFNLENBQUMsV0FBVyxDQUFDLFNBQVMsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFBO0FBSTFHOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLFlBQVksQ0FBQyxHQUFpQjtJQUM1QyxNQUFNLE1BQU0sR0FBRyxPQUFPLEdBQUcsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUE7SUFFM0Qsd0JBQXdCO0lBQ3hCLElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxFQUFFLEVBQUU7UUFDeEIsTUFBTSxDQUFDLE1BQU0sR0FBRyxpQkFBaUIsQ0FBQyxNQUFNLENBQVMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxFQUFFLEVBQUU7WUFDOUQsT0FBTyxNQUFNLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQTtRQUMvQixDQUFDLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFBO0tBQ2xCO0lBRUQsT0FBTyxNQUFNLENBQUE7QUFDZixDQUFDO0FBRUQ7Ozs7Ozs7OztHQVNHO0FB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