Skip to content

Commit

Permalink
feat(babel): new cache system
Browse files Browse the repository at this point in the history
  • Loading branch information
Anber committed Aug 30, 2023
1 parent 49c36c1 commit b021c42
Show file tree
Hide file tree
Showing 42 changed files with 1,344 additions and 1,290 deletions.
3 changes: 2 additions & 1 deletion packages/babel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
"cosmiconfig": "^8.0.0",
"happy-dom": "10.8.0",
"source-map": "^0.7.3",
"stylis": "^3.5.4"
"stylis": "^3.5.4",
"ts-invariant": "^0.10.3"
},
"devDependencies": {
"@types/babel__core": "^7.1.19",
Expand Down
7 changes: 1 addition & 6 deletions packages/babel/src/HOW_IT_WORKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ This function identifies the names of all exports in the file. If the file conta

### transform

Prepares the file for execution: identifies the utilized Linaria processors, invokes eval-time substitutions for them, removes unnecessary code, and calls the `evaluator`. From the remaining code, surviving imports are extracted, wrapped in `resolveImports`, and queued. After imports are resolved, the `processImports` task is set to handle them. The final step is `addToCodeCache`, which stores all the gathered information in the cache for later utilization in `evalFile`.
Prepares the file for execution: identifies the utilized Linaria processors, invokes eval-time substitutions for them, removes unnecessary code, and calls the `evaluator`. From the remaining code, surviving imports are extracted, wrapped in `resolveImports`, and queued. After imports are resolved, the `processImports` task is set to handle them.


### resolveImports
Expand All @@ -67,11 +67,6 @@ This function exists in two variants: synchronous for strictly synchronous envir
Invokes `createEntrypoint` for each import. At this stage, it might return `"ignored"` if a loop is detected. In this case, the specific import is skipped. For the remaining imports, `processEntrypoint` will be enqueued without the parent's `AbortSignal`.


### addToCodeCache

Simply adds the result to the cache. While it could be done directly in `transform`, this approach provides clearer logging.


### evalFile

Executes the code prepared in previous steps within the current `Entrypoint`. Returns all exports that were requested in `only`.
Expand Down
78 changes: 20 additions & 58 deletions packages/babel/src/cache.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,24 @@
import { createHash } from 'crypto';

import type { File } from '@babel/types';

import { linariaLogger } from '@linaria/logger';

import type { IBaseEntrypoint, IModule, ITransformFileResult } from './types';
import type { Entrypoint } from './transform/Entrypoint';
import type { IEvaluatedEntrypoint } from './transform/Entrypoint.types';

function hashContent(content: string) {
return createHash('sha256').update(content).digest('hex');
}

interface ICaches {
entrypoints: Map<string, IBaseEntrypoint>;
ignored: Map<string, true>;
resolve: Map<string, string>;
resolveTask: Map<
string,
Promise<{
importedFile: string;
importsOnly: string[];
resolved: string | null;
}>
>;
code: Map<
string,
{
imports: Map<string, string[]> | null;
only: string[];
result: ITransformFileResult;
}
>;
eval: Map<string, IModule>;
originalAST: Map<string, File>;
contentHashes: Map<string, string>;
entrypoints: Map<string, Entrypoint | IEvaluatedEntrypoint>;
}

type MapValue<T> = T extends Map<string, infer V> ? V : never;

const cacheLogger = linariaLogger.extend('cache');

const cacheNames = [
'entrypoints',
'ignored',
'resolve',
'resolveTask',
'code',
'eval',
'originalAST',
] as const;
const cacheNames = ['entrypoints', 'contentHashes'] as const;
type CacheNames = (typeof cacheNames)[number];

const loggers = cacheNames.reduce(
Expand All @@ -60,35 +32,13 @@ const loggers = cacheNames.reduce(
export class TransformCacheCollection {
private contentHashes = new Map<string, string>();

protected readonly entrypoints: Map<string, IBaseEntrypoint>;

protected readonly ignored: Map<string, true>;

protected readonly resolve: Map<string, string>;

protected readonly resolveTask: Map<string, Promise<string>>;

protected readonly code: Map<
protected readonly entrypoints: Map<
string,
{
imports: Map<string, string[]> | null;
only: string[];
result: ITransformFileResult;
}
Entrypoint | IEvaluatedEntrypoint
>;

protected readonly eval: Map<string, IModule>;

protected readonly originalAST: Map<string, File>;

constructor(caches: Partial<ICaches> = {}) {
this.entrypoints = caches.entrypoints || new Map();
this.ignored = caches.ignored || new Map();
this.resolve = caches.resolve || new Map();
this.resolveTask = caches.resolveTask || new Map();
this.code = caches.code || new Map();
this.eval = caches.eval || new Map();
this.originalAST = caches.originalAST || new Map();
}

public invalidateForFile(filename: string) {
Expand Down Expand Up @@ -147,6 +97,10 @@ export class TransformCacheCollection {
return res;
}

public delete(cacheName: CacheNames, key: string): void {
this.invalidate(cacheName, key);
}

public invalidate(cacheName: CacheNames, key: string): void {
const cache = this[cacheName] as Map<string, unknown>;
if (!cache.has(key)) {
Expand All @@ -158,7 +112,15 @@ export class TransformCacheCollection {
cache.delete(key);
}

public clear(cacheName: CacheNames): void {
public clear(cacheName: CacheNames | 'all'): void {
if (cacheName === 'all') {
cacheNames.forEach((name) => {
this.clear(name);
});

return;
}

loggers[cacheName]('clear');
const cache = this[cacheName] as Map<string, unknown>;

Expand Down
18 changes: 4 additions & 14 deletions packages/babel/src/evaluators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,20 @@
* This file is an entry point for module evaluation for getting lazy dependencies.
*/

import type { StrictOptions } from '@linaria/utils';

import type { TransformCacheCollection } from '../cache';
import Module from '../module';
import type { Entrypoint } from '../transform/Entrypoint';

export default function evaluate(
cache: TransformCacheCollection,
code: string,
pluginOptions: StrictOptions,
filename: string
entrypoint: Entrypoint
) {
const m = new Module(
filename ?? 'unknown',
'__linariaPreval',
pluginOptions,
cache
);
const m = new Module(entrypoint, cache);

m.dependencies = [];
m.evaluate(code);
m.evaluate();

return {
value: m.exports,
dependencies: m.dependencies,
processors: m.tagProcessors,
};
}
1 change: 1 addition & 0 deletions packages/babel/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export {
syncResolveImports,
} from './transform/generators/resolveImports';
export { default as loadLinariaOptions } from './transform/helpers/loadLinariaOptions';
export { StackOfMaps } from './transform/helpers/StackOfMaps';
export { withDefaultServices } from './transform/helpers/withDefaultServices';
export { default as isNode } from './utils/isNode';
export { default as getTagProcessor } from './utils/getTagProcessor';
Expand Down
Loading

0 comments on commit b021c42

Please sign in to comment.