pagespeed-quest
Version:
A framework for efficient web front-end speed improvement
96 lines • 8.34 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9odHRwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sTUFBTSxNQUFNLFFBQVEsQ0FBQTtBQUMzQixPQUFPLElBQUksTUFBTSxNQUFNLENBQUE7QUFFdkIsTUFBTSxjQUFjLEdBQUcsWUFBWSxDQUFBO0FBQ25DLE1BQU0saUJBQWlCLEdBQUcsR0FBRyxDQUFBO0FBQzdCLE1BQU0sVUFBVSxHQUFHLENBQUMsQ0FBQTtBQUNwQixNQUFNLFlBQVksR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLGFBQWEsSUFBSSxJQUFJLENBQUE7QUFDdEQsTUFBTSxpQkFBaUIsR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxNQUFNLENBQUMsV0FBVyxDQUFDLFNBQVMsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFBO0FBSTFHOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLFlBQVksQ0FBQyxHQUFpQjtJQUM1QyxNQUFNLE1BQU0sR0FBRyxPQUFPLEdBQUcsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUE7SUFFM0Qsd0JBQXdCO0lBQ3hCLElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxFQUFFLEVBQUUsQ0FBQztRQUN6QixNQUFNLENBQUMsTUFBTSxHQUFHLGlCQUFpQixDQUFDLE1BQU0sQ0FBUyxDQUFDLE1BQU0sRUFBRSxFQUFFLEVBQUUsRUFBRTtZQUM5RCxPQUFPLE1BQU0sQ0FBQyxPQUFPLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFBO1FBQy9CLENBQUMsRUFBRSxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDbkIsQ0FBQztJQUVELE9BQU8sTUFBTSxDQUFBO0FBQ2YsQ0FBQztBQUVEOzs7Ozs7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