Skip to content

Commit

Permalink
fix: store sourcemap and minify information along with cache identifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
wessberg committed Oct 22, 2020
1 parent 75dba0e commit e70a5be
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 59 deletions.
12 changes: 6 additions & 6 deletions src/bl/polyfill/polyfill-bl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class PolyfillBl implements IPolyfillBl {
*/
async getPolyfills(request: IPolyfillRequest): Promise<IGetPolyfillsResult> {
// Check if a polyfill set exists within the cache for the request features and the user agent of the request
let featureSet = await this.cacheRegistry.getPolyfillFeatureSet(request.features, request.userAgent, request.context);
let featureSet = await this.cacheRegistry.getPolyfillFeatureSet(request.features, request);

// If not, resolve and order the required polyfills
if (featureSet == null) {
Expand All @@ -37,15 +37,15 @@ export class PolyfillBl implements IPolyfillBl {
);

// Store them within the cache
await this.cacheRegistry.setPolyfillFeatureSet(request.features, featureSet, request.userAgent, request.context);
await this.cacheRegistry.setPolyfillFeatureSet(request.features, featureSet, request);
} else {
this.logger.debug("Matched Polyfill Set in cache!");
}

this.logger.debug(featureSet);

// Check if a Set has already been registered for this combination
const existingSet = await this.cacheRegistry.get(featureSet, request.context, request.encoding);
const existingSet = await this.cacheRegistry.get(featureSet, request);
if (existingSet != null) {
this.logger.debug("Matched Polyfills in cache!");
// If it has, just return that one
Expand All @@ -57,9 +57,9 @@ export class PolyfillBl implements IPolyfillBl {

// Add the polyfills to the registry
const [minifiedResult, brotliResult, zlibResult] = await Promise.all([
this.cacheRegistry.set(featureSet, minified, request.context),
this.cacheRegistry.set(featureSet, brotli, request.context, ContentEncodingKind.BROTLI),
this.cacheRegistry.set(featureSet, zlib, request.context, ContentEncodingKind.GZIP)
this.cacheRegistry.set(featureSet, minified, {...request, encoding: undefined}),
this.cacheRegistry.set(featureSet, brotli, {...request, encoding: ContentEncodingKind.BROTLI}),
this.cacheRegistry.set(featureSet, zlib, {...request, encoding: ContentEncodingKind.GZIP})
]);

// Return the joined Buffer
Expand Down
48 changes: 23 additions & 25 deletions src/service/registry/cache-registry/cache-registry-service.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import {ICacheRegistryService} from "./i-cache-registry-service";
import {IFileSaver} from "@wessberg/filesaver";
import {IPolyfillFeature, IPolyfillFeatureInput} from "../../../polyfill/i-polyfill-feature";
import {ContentEncodingKind} from "../../../encoding/content-encoding-kind";
import {getPolyfillIdentifier, getPolyfillSetIdentifier} from "../../../util/polyfill/polyfill-util";
import {join} from "path";
import {constant} from "../../../constant/constant";
import {IFileLoader} from "@wessberg/fileloader";
import {IMemoryRegistryService} from "../polyfill-registry/i-memory-registry-service";
import {IMemoryRegistryService, PolyfillCachingContext} from "../polyfill-registry/i-memory-registry-service";
import {PolyfillName} from "../../../polyfill/polyfill-name";
import {coerce, gt} from "semver";
import {IConfig} from "../../../config/i-config";
import {IRegistryGetResult} from "../polyfill-registry/i-registry-get-result";
import {ILoggerService} from "../../logger/i-logger-service";
import {PolyfillDictEntry} from "../../../polyfill/polyfill-dict";
import {PolyfillContext} from "../../../polyfill/polyfill-context";

/**
* A class that can cache generated Polyfills on disk
Expand Down Expand Up @@ -42,67 +40,67 @@ export class CacheRegistryService implements ICacheRegistryService {
/**
* Gets the contents for the polyfill with the given name and with the given encoding
*/
async get(name: IPolyfillFeature | Set<IPolyfillFeature>, context: PolyfillContext, encoding?: ContentEncodingKind): Promise<IRegistryGetResult | undefined> {
async get(name: IPolyfillFeature | Set<IPolyfillFeature>, context: PolyfillCachingContext): Promise<IRegistryGetResult | undefined> {
// Attempt to fetch it from the in-memory registry
const memoryHit = await this.memoryRegistry.get(name, context, encoding);
const memoryHit = await this.memoryRegistry.get(name, context);
if (memoryHit != null) return memoryHit;

// Otherwise, attempt to get it from cache
const buffer = await this.getFromCache(this.getCachePath(name, context, encoding));
const buffer = await this.getFromCache(this.getCachePath(name, context));
// If not possible, return undefined
if (buffer == null) return undefined;

// Otherwise, store it in the memory registry and return the Buffer
return await this.memoryRegistry.set(name, buffer, context, encoding);
return await this.memoryRegistry.set(name, buffer, context);
}

/**
* Gets the Set of Polyfill feature inputs that matches the given input
*/
async getPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, userAgent: string, context: PolyfillContext): Promise<Set<IPolyfillFeature> | undefined> {
async getPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, context: PolyfillCachingContext): Promise<Set<IPolyfillFeature> | undefined> {
// Attempt to fetch it from the in-memory registry
const memoryHit = await this.memoryRegistry.getPolyfillFeatureSet(input, userAgent, context);
const memoryHit = await this.memoryRegistry.getPolyfillFeatureSet(input, context);
if (memoryHit != null) return memoryHit;

// Otherwise, attempt to get it from cache
const buffer = await this.getFromCache(this.getCachePathForPolyfillSet(input, userAgent, context));
const buffer = await this.getFromCache(this.getCachePathForPolyfillSet(input, context));
// If not possible, return undefined
if (buffer == null) return undefined;

// Otherwise, store it in the memory registry and return the Buffer
return await this.memoryRegistry.setPolyfillFeatureSet(input, new Set(JSON.parse(buffer.toString())), userAgent, context);
return await this.memoryRegistry.setPolyfillFeatureSet(input, new Set(JSON.parse(buffer.toString())), context);
}

/**
* Returns true if a polyfill wil the given name exists
*/
async has(name: IPolyfillFeature | Set<IPolyfillFeature>, context: PolyfillContext, encoding?: ContentEncodingKind): Promise<boolean> {
return (await this.get(name, context, encoding)) != null;
async has(name: IPolyfillFeature | Set<IPolyfillFeature>, context: PolyfillCachingContext): Promise<boolean> {
return (await this.get(name, context)) != null;
}

/**
* Returns true if there is a PolyfillFeature Set in the cache that matches the given input Set
*/
async hasPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, userAgent: string, context: PolyfillContext): Promise<boolean> {
return (await this.getPolyfillFeatureSet(input, userAgent, context)) != null;
async hasPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, context: PolyfillCachingContext): Promise<boolean> {
return (await this.getPolyfillFeatureSet(input, context)) != null;
}

/**
* Sets the contents for the polyfill with the given name and of the given encoding
*/
async set(name: IPolyfillFeature | Set<IPolyfillFeature>, contents: Buffer, context: PolyfillContext, encoding?: ContentEncodingKind): Promise<IRegistryGetResult> {
async set(name: IPolyfillFeature | Set<IPolyfillFeature>, contents: Buffer, context: PolyfillCachingContext): Promise<IRegistryGetResult> {
// Add it to the memory cache as well as the disk cache
await this.writeToCache(this.getCachePath(name, context, encoding), contents);
return await this.memoryRegistry.set(name, contents, context, encoding);
await this.writeToCache(this.getCachePath(name, context), contents);
return await this.memoryRegistry.set(name, contents, context);
}

/**
* Sets the given PolyfillFeature Set for the given Set of PolyfillFeature inputs
*/
async setPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, polyfillSet: Set<IPolyfillFeature>, userAgent: string, context: PolyfillContext): Promise<Set<IPolyfillFeature>> {
async setPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, polyfillSet: Set<IPolyfillFeature>, context: PolyfillCachingContext): Promise<Set<IPolyfillFeature>> {
// Add it to the memory cache as well as the disk cache
await this.writeToCache(this.getCachePathForPolyfillSet(input, userAgent, context), Buffer.from(JSON.stringify([...polyfillSet])));
return await this.memoryRegistry.setPolyfillFeatureSet(input, polyfillSet, userAgent, context);
await this.writeToCache(this.getCachePathForPolyfillSet(input, context), Buffer.from(JSON.stringify([...polyfillSet])));
return await this.memoryRegistry.setPolyfillFeatureSet(input, polyfillSet, context);
}

/**
Expand Down Expand Up @@ -225,14 +223,14 @@ export class CacheRegistryService implements ICacheRegistryService {
/**
* Gets the cache path to the given name and encoding
*/
private getCachePath(name: IPolyfillFeature | Set<IPolyfillFeature>, context: PolyfillContext, encoding?: ContentEncodingKind): string {
return join(constant.path.cacheRoot, getPolyfillIdentifier(name, context, encoding));
private getCachePath(name: IPolyfillFeature | Set<IPolyfillFeature>, context: PolyfillCachingContext): string {
return join(constant.path.cacheRoot, getPolyfillIdentifier(name, context));
}

/**
* Gets the cache path to the given Polyfill Feature Set
*/
private getCachePathForPolyfillSet(input: Set<IPolyfillFeatureInput>, userAgent: string, context: PolyfillContext): string {
return join(constant.path.cacheRoot, getPolyfillSetIdentifier(input, userAgent, context));
private getCachePathForPolyfillSet(input: Set<IPolyfillFeatureInput>, context: PolyfillCachingContext): string {
return join(constant.path.cacheRoot, getPolyfillSetIdentifier(input, context));
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {ContentEncodingKind} from "../../../encoding/content-encoding-kind";
import {IPolyfillFeature, IPolyfillFeatureInput} from "../../../polyfill/i-polyfill-feature";
import {IRegistryGetResult} from "./i-registry-get-result";
import {PolyfillContext} from "../../../polyfill/polyfill-context";
import {IPolyfillRequest} from "../../../polyfill/i-polyfill-request";

export interface PolyfillCachingContext extends Omit<IPolyfillRequest, "features"> {}

export interface IMemoryRegistryService {
get(name: IPolyfillFeature | Set<IPolyfillFeature>, context: PolyfillContext, encoding?: ContentEncodingKind): Promise<IRegistryGetResult | undefined>;
getPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, userAgent: string, context: PolyfillContext): Promise<Set<IPolyfillFeature> | undefined>;
set(name: IPolyfillFeature | Set<IPolyfillFeature>, contents: Buffer, context: PolyfillContext, encoding?: ContentEncodingKind): Promise<IRegistryGetResult>;
setPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, polyfillSet: Set<IPolyfillFeature>, userAgent: string, context: PolyfillContext): Promise<Set<IPolyfillFeature>>;
has(name: IPolyfillFeature | Set<IPolyfillFeature>, context: PolyfillContext, encoding?: ContentEncodingKind): Promise<boolean>;
hasPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, userAgent: string, context: PolyfillContext): Promise<boolean>;
get(name: IPolyfillFeature | Set<IPolyfillFeature>, context: PolyfillCachingContext): Promise<IRegistryGetResult | undefined>;
getPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, context: PolyfillCachingContext): Promise<Set<IPolyfillFeature> | undefined>;
set(name: IPolyfillFeature | Set<IPolyfillFeature>, contents: Buffer, context: PolyfillCachingContext): Promise<IRegistryGetResult>;
setPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, polyfillSet: Set<IPolyfillFeature>, context: PolyfillCachingContext): Promise<Set<IPolyfillFeature>>;
has(name: IPolyfillFeature | Set<IPolyfillFeature>, context: PolyfillCachingContext): Promise<boolean>;
hasPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, context: PolyfillCachingContext): Promise<boolean>;
}
28 changes: 13 additions & 15 deletions src/service/registry/polyfill-registry/memory-registry-service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import {IMemoryRegistryService} from "./i-memory-registry-service";
import {ContentEncodingKind} from "../../../encoding/content-encoding-kind";
import {IMemoryRegistryService, PolyfillCachingContext} from "./i-memory-registry-service";
import {IPolyfillFeature, IPolyfillFeatureInput} from "../../../polyfill/i-polyfill-feature";
import {getPolyfillIdentifier, getPolyfillSetIdentifier} from "../../../util/polyfill/polyfill-util";
import {IRegistryGetResult} from "./i-registry-get-result";
import {PolyfillContext} from "../../../polyfill/polyfill-context";

/**
* A Registry of polyfills living in-memory
Expand All @@ -24,8 +22,8 @@ export class MemoryRegistryService implements IMemoryRegistryService {
/**
* Gets the contents for the polyfill with the given name and with the given encoding
*/
async get(name: IPolyfillFeature | Set<IPolyfillFeature>, context: PolyfillContext, encoding?: ContentEncodingKind): Promise<IRegistryGetResult | undefined> {
const checksum = getPolyfillIdentifier(name, context, encoding);
async get(name: IPolyfillFeature | Set<IPolyfillFeature>, context: PolyfillCachingContext): Promise<IRegistryGetResult | undefined> {
const checksum = getPolyfillIdentifier(name, context);
const buffer = this.registeredPolyfills.get(checksum);

return buffer == null ? undefined : {buffer, checksum};
Expand All @@ -34,30 +32,30 @@ export class MemoryRegistryService implements IMemoryRegistryService {
/**
* Gets the Set of Polyfill feature inputs that matches the given input
*/
async getPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, userAgent: string, context: PolyfillContext): Promise<Set<IPolyfillFeature> | undefined> {
const checksum = getPolyfillSetIdentifier(input, userAgent, context);
async getPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, context: PolyfillCachingContext): Promise<Set<IPolyfillFeature> | undefined> {
const checksum = getPolyfillSetIdentifier(input, context);
return this.registeredPolyfillSets.get(checksum);
}

/**
* Returns true if a polyfill wil the given name exists
*/
async has(name: IPolyfillFeature | Set<IPolyfillFeature>, context: PolyfillContext, encoding?: ContentEncodingKind): Promise<boolean> {
return this.registeredPolyfills.has(getPolyfillIdentifier(name, context, encoding));
async has(name: IPolyfillFeature | Set<IPolyfillFeature>, context: PolyfillCachingContext): Promise<boolean> {
return this.registeredPolyfills.has(getPolyfillIdentifier(name, context));
}

/**
* Returns true if a Set of PolyfillFeatures exist in cache for the given PolyfillFeature input Set
*/
async hasPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, userAgent: string, context: PolyfillContext): Promise<boolean> {
return this.registeredPolyfillSets.has(getPolyfillSetIdentifier(input, userAgent, context));
async hasPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, context: PolyfillCachingContext): Promise<boolean> {
return this.registeredPolyfillSets.has(getPolyfillSetIdentifier(input, context));
}

/**
* Sets the contents for the polyfill with the given name and of the given encoding
*/
async set(name: IPolyfillFeature | Set<IPolyfillFeature>, buffer: Buffer, context: PolyfillContext, encoding?: ContentEncodingKind): Promise<IRegistryGetResult> {
const checksum = getPolyfillIdentifier(name, context, encoding);
async set(name: IPolyfillFeature | Set<IPolyfillFeature>, buffer: Buffer, context: PolyfillCachingContext): Promise<IRegistryGetResult> {
const checksum = getPolyfillIdentifier(name, context);

this.registeredPolyfills.set(checksum, buffer);
return {buffer, checksum};
Expand All @@ -66,8 +64,8 @@ export class MemoryRegistryService implements IMemoryRegistryService {
/**
* Sets the given PolyfillFeature Set for the given Set of PolyfillFeature inputs
*/
async setPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, polyfillSet: Set<IPolyfillFeature>, userAgent: string, context: PolyfillContext): Promise<Set<IPolyfillFeature>> {
const checksum = getPolyfillSetIdentifier(input, userAgent, context);
async setPolyfillFeatureSet(input: Set<IPolyfillFeatureInput>, polyfillSet: Set<IPolyfillFeature>, context: PolyfillCachingContext): Promise<Set<IPolyfillFeature>> {
const checksum = getPolyfillSetIdentifier(input, context);

this.registeredPolyfillSets.set(checksum, polyfillSet);
return polyfillSet;
Expand Down
10 changes: 5 additions & 5 deletions src/util/polyfill/polyfill-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {IPolyfillLibraryDictEntry, IPolyfillLocalDictEntry} from "../../polyfill
// @ts-ignore
import toposort from "toposort";
import {POLYFILL_CONTEXTS, PolyfillContext} from "../../polyfill/polyfill-context";
import {PolyfillCachingContext} from "../../service/registry/polyfill-registry/i-memory-registry-service";

/**
* Traces all polyfill names that matches the given name. It may be an alias, and it may refer to additional aliases
Expand Down Expand Up @@ -48,25 +49,24 @@ export function traceAllPolyfillNamesForPolyfillName(name: PolyfillName): Set<Po
*/
export function getPolyfillIdentifier(
name: IPolyfillFeature | IPolyfillFeatureInput | Set<IPolyfillFeature> | Set<IPolyfillFeatureInput>,
context: PolyfillContext,
encoding?: string
context: PolyfillCachingContext
): string {
const shasum = createHash("sha1");
const normalizedName = name instanceof Set ? name : new Set([name]);
const sortedName = [...normalizedName].sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
const namePart = sortedName.map(part => `${part.name}${JSON.stringify(part.meta)}${context}`).join(",");
shasum.update(`[${namePart}].${encoding == null ? "" : encoding}`);
shasum.update(`[${namePart}].${context.sourcemap}.${context.minify}.${context.encoding || "none"}`);
return shasum.digest("hex");
}

/**
* Returns a stringified key as a function of the given Set of polyfill feature inputs
*/
export function getPolyfillSetIdentifier(polyfills: Set<IPolyfillFeatureInput>, userAgent: string, context: PolyfillContext): string {
export function getPolyfillSetIdentifier(polyfills: Set<IPolyfillFeatureInput>, context: PolyfillCachingContext): string {
const shasum = createHash("sha1");
const sortedName = [...polyfills].sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
const namePart = sortedName.map(part => `${part.name}${JSON.stringify(part.meta)}${JSON.stringify(part.force)}${JSON.stringify(context)}`).join(",");
shasum.update(`[${namePart}].${userAgent}`);
shasum.update(`[${namePart}].${context.userAgent}.${context.context}`);
return shasum.digest("hex");
}

Expand Down

0 comments on commit e70a5be

Please sign in to comment.