Skip to content

Commit

Permalink
refactor: add module metadata
Browse files Browse the repository at this point in the history
- replace cache hash to module meta.hash
  • Loading branch information
leegeunhyeok committed Oct 27, 2023
1 parent 3cbb7b1 commit a960c14
Show file tree
Hide file tree
Showing 14 changed files with 105 additions and 117 deletions.
5 changes: 0 additions & 5 deletions packages/core/lib/bundler/cache/CacheController.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import fs from 'node:fs';
import path from 'node:path';
import md5 from 'md5';
import type { Cache } from '../../types';

const OPTIONS = { encoding: 'utf-8' } as const;
Expand All @@ -16,10 +15,6 @@ export class CacheController {
}
}

public getCacheHash(message: string): string {
return md5(message);
}

public readFromMemory(key: string): Cache | undefined {
return this.cache[key];
}
Expand Down
3 changes: 1 addition & 2 deletions packages/core/lib/bundler/cache/__tests__/cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ describe('CacheController', () => {
let data: string;

beforeEach(async () => {
const hashParam = faker.string.alphanumeric(10);
hash = manager.getCacheHash(hashParam);
hash = faker.string.alphanumeric(10);
data = faker.string.alphanumeric(10);
await manager.writeToFileSystem(hash, data);
});
Expand Down
10 changes: 9 additions & 1 deletion packages/core/lib/bundler/helpers/internal.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { BuildOptions } from 'esbuild';
import { getPreludeScript } from '@react-native-esbuild/internal';
import type { TransformerContext } from '@react-native-esbuild/transformer';
import {
stripFlowWithSucrase,
minifyWithSwc,
Expand All @@ -11,7 +12,14 @@ export const getTransformedPreludeScript = async (
bundleOptions: BundleOptions,
root: string,
): Promise<string> => {
const context = { root, path: '' };
// Dummy context
const context: TransformerContext = {
root,
path: '',
id: 0,
dev: bundleOptions.dev,
entry: bundleOptions.entry,
};
const preludeScript = await getPreludeScript(bundleOptions, root);

/**
Expand Down
4 changes: 1 addition & 3 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
"deepmerge": "^4.3.1",
"esbuild": "^0.19.5",
"invariant": "^2.2.4",
"md5": "^2.3.0",
"ora": "^5.4.1"
},
"peerDependencies": {
Expand All @@ -57,7 +56,6 @@
"devDependencies": {
"@babel/core": "^7.23.2",
"@faker-js/faker": "^8.1.0",
"@swc/core": "^1.3.95",
"@types/md5": "^2.3.2"
"@swc/core": "^1.3.95"
}
}
15 changes: 10 additions & 5 deletions packages/jest/lib/transformer/createTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,21 @@ import {
SyncTransformPipeline,
AsyncTransformPipeline,
swcPresets,
type TransformerContext,
} from '@react-native-esbuild/transformer';
import { getReactNativeInitializeCore } from '@react-native-esbuild/internal';
import type { TransformerConfig } from '../types';
import pkg from '../../package.json';

const DUMMY_ENTRY = '';
const DUMMY_ESBUILD_VALUE = '';
const ROOT = process.cwd();
const TRANSFORMER_CONTEXT: TransformerContext = {
root: ROOT,
id: 0,
dev: true,
entry: '',
path: '',
};

ReactNativeEsbuildBundler.bootstrap();

Expand All @@ -32,8 +39,7 @@ export const createTransformer = (config: TransformerConfig): Transformer => {
: undefined;

const syncTransformPipeline = new SyncTransformPipeline.builder(
ROOT,
DUMMY_ENTRY,
TRANSFORMER_CONTEXT,
)
.setSwcPreset(
swcPresets.getJestPreset({
Expand All @@ -53,8 +59,7 @@ export const createTransformer = (config: TransformerConfig): Transformer => {
.build();

const asyncTransformPipeline = new AsyncTransformPipeline.builder(
ROOT,
DUMMY_ENTRY,
TRANSFORMER_CONTEXT,
)
.setSwcPreset(
// Async transform is always ESM.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,6 @@
import fs from 'node:fs/promises';
import type { Stats } from 'node:fs';
import type { OnLoadArgs } from 'esbuild';
import type {
CacheController,
PluginContext,
} from '@react-native-esbuild/core';
import type { CacheController } from '@react-native-esbuild/core';
import type { CacheConfig } from '../../types';

/**
* Generate hash that contains the file path, modification time, and bundle options.
*
* `id` is combined(platform, dev, minify) bundle options value in `@react-native-esbuild`.
*
* hash = md5(id + modified time + file path)
* number + number + string
*/
export const makeCacheConfig = async (
controller: CacheController,
args: OnLoadArgs,
context: PluginContext,
stats?: Stats,
): Promise<CacheConfig> => {
const mtimeMs = (stats ?? (await fs.stat(args.path))).mtimeMs;
return {
hash: controller.getCacheHash(context.id + mtimeMs + args.path),
mtimeMs,
};
};

export const getTransformedCodeFromInMemoryCache = (
controller: CacheController,
cacheConfig: CacheConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
import { logger } from '../shared';
import type { ReactNativeRuntimeTransformPluginConfig } from '../types';
import {
makeCacheConfig,
getTransformedCodeFromInMemoryCache,
getTransformedCodeFromFileSystemCache,
writeTransformedCodeToInMemoryCache,
Expand Down Expand Up @@ -46,18 +45,13 @@ export const createReactNativeRuntimeTransformPlugin: ReactNativeEsbuildPluginCr
const onBeforeTransform: AsyncTransformStep = async (
code,
args,
sharedData,
moduleMeta,
) => {
const isChangedFile = bundlerSharedData.watcher.changed === args.path;
const cacheConfig = await makeCacheConfig(
cacheController,
args,
context,
isChangedFile ? bundlerSharedData.watcher.stats : undefined,
);

sharedData.hash = cacheConfig.hash;
sharedData.mtimeMs = cacheConfig.mtimeMs;
const cacheConfig = {
hash: moduleMeta.hash,
mtimeMs: moduleMeta.stats.mtimeMs,
};

// 1. Force re-transform when file is changed.
if (isChangedFile) {
Expand Down Expand Up @@ -95,15 +89,12 @@ export const createReactNativeRuntimeTransformPlugin: ReactNativeEsbuildPluginCr
const onAfterTransform: AsyncTransformStep = async (
code,
_args,
shared,
moduleMeta,
) => {
if (!(shared.hash && shared.mtimeMs)) {
logger.warn('unexpected cache config');
return { code, done: true };
}

const cacheConfig = { hash: shared.hash, mtimeMs: shared.mtimeMs };

const cacheConfig = {
hash: moduleMeta.hash,
mtimeMs: moduleMeta.stats.mtimeMs,
};
writeTransformedCodeToInMemoryCache(cacheController, code, cacheConfig);

if (cacheEnabled) {
Expand All @@ -118,10 +109,7 @@ export const createReactNativeRuntimeTransformPlugin: ReactNativeEsbuildPluginCr
};

let transformPipeline: AsyncTransformPipeline;
const transformPipelineBuilder = new AsyncTransformPipeline.builder(
context.root,
context.entry,
)
const transformPipelineBuilder = new AsyncTransformPipeline.builder(context)
.setSwcPreset(swcPresets.getReactNativeRuntimePreset())
.setInjectScripts(injectScriptPaths)
.setFullyTransformPackages(fullyTransformPackageNames)
Expand Down
33 changes: 19 additions & 14 deletions packages/transformer/lib/pipelines/AsyncTransformPipeline.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import path from 'node:path';
import fs from 'node:fs/promises';
import type { OnLoadArgs } from 'esbuild';
import {
transformWithBabel,
transformWithSwc,
stripFlowWithSucrase,
} from '../transformer';
import { transformByBabelRule, transformBySwcRule } from '../helpers';
import type { AsyncTransformStep, TransformResult, SharedData } from '../types';
import type { AsyncTransformStep, ModuleMeta, TransformResult } from '../types';
import { TransformPipeline } from './pipeline';
import { TransformPipelineBuilder } from './builder';

Expand All @@ -15,14 +16,14 @@ export class AsyncTransformPipelineBuilder extends TransformPipelineBuilder<
AsyncTransformPipeline
> {
build(): AsyncTransformPipeline {
const pipeline = new AsyncTransformPipeline();
const pipeline = new AsyncTransformPipeline(this.context);

this.onBefore && pipeline.beforeTransform(this.onBefore);
this.onAfter && pipeline.afterTransform(this.onAfter);

// 1. Inject initializeCore and specified scripts to entry file.
if (this.injectScriptPaths.length) {
const entryFile = path.resolve(this.root, this.entry);
const entryFile = path.resolve(this.context.root, this.context.entry);
pipeline.addStep((code, args) => {
return Promise.resolve({
code:
Expand All @@ -44,7 +45,7 @@ export class AsyncTransformPipelineBuilder extends TransformPipelineBuilder<
return {
code: await transformWithBabel(
code,
this.getTransformContext(args),
this.getContext(args),
this.presets.babelFullyTransform,
),
// skip other transformations when fully transformed
Expand All @@ -66,7 +67,7 @@ export class AsyncTransformPipelineBuilder extends TransformPipelineBuilder<
this.isFlow(code, args.path)
) {
// eslint-disable-next-line no-param-reassign -- Allow reassign.
code = stripFlowWithSucrase(code, this.getTransformContext(args));
code = stripFlowWithSucrase(code, this.getContext(args));
}

return Promise.resolve({ code, done: false });
Expand All @@ -76,7 +77,7 @@ export class AsyncTransformPipelineBuilder extends TransformPipelineBuilder<
// 4. Apply additional babel rules.
if (this.additionalBabelRules.length) {
pipeline.addStep(async (code, args) => {
const context = this.getTransformContext(args);
const context = this.getContext(args);
for await (const rule of this.additionalBabelRules) {
// eslint-disable-next-line no-param-reassign -- Allow reassign.
code = (await transformByBabelRule(rule, code, context)) ?? code;
Expand All @@ -88,7 +89,7 @@ export class AsyncTransformPipelineBuilder extends TransformPipelineBuilder<
// 5. Apply additional swc rules.
if (this.additionalSwcRules.length) {
pipeline.addStep(async (code, args) => {
const context = this.getTransformContext(args);
const context = this.getContext(args);
for await (const rule of this.additionalSwcRules) {
// eslint-disable-next-line no-param-reassign -- Allow reassign.
code = (await transformBySwcRule(rule, code, context)) ?? code;
Expand All @@ -102,7 +103,7 @@ export class AsyncTransformPipelineBuilder extends TransformPipelineBuilder<
return {
code: await transformWithSwc(
code,
this.getTransformContext(args),
this.getContext(args),
this.swcPreset,
),
done: true,
Expand All @@ -120,17 +121,21 @@ export class AsyncTransformPipeline extends TransformPipeline<AsyncTransformStep
protected onAfterTransform?: AsyncTransformStep;

async transform(code: string, args: OnLoadArgs): Promise<TransformResult> {
const sharedData = {} as SharedData;
const fileStat = await fs.stat(args.path);
const moduleMeta: ModuleMeta = {
stats: fileStat,
hash: this.getHash(this.context.id, args.path, fileStat.mtimeMs),
};

const before: AsyncTransformStep = (code, args) => {
return this.onBeforeTransform
? this.onBeforeTransform(code, args, sharedData)
? this.onBeforeTransform(code, args, moduleMeta)
: Promise.resolve({ code, done: false });
};

const after: AsyncTransformStep = (code, args) => {
return this.onAfterTransform
? this.onAfterTransform(code, args, sharedData)
? this.onAfterTransform(code, args, moduleMeta)
: Promise.resolve({ code, done: true });
};

Expand All @@ -139,12 +144,12 @@ export class AsyncTransformPipeline extends TransformPipeline<AsyncTransformStep
return Promise.resolve(prev).then((prevResult) =>
prevResult.done
? Promise.resolve({ code: prevResult.code, done: true })
: curr(prevResult.code, args, sharedData),
: curr(prevResult.code, args, moduleMeta),
);
},
before(code, args, sharedData),
before(code, args, moduleMeta),
);

return after(result.code, args, sharedData);
return after(result.code, args, moduleMeta);
}
}
Loading

2 comments on commit a960c14

@vercel
Copy link

@vercel vercel bot commented on a960c14 Oct 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage report

St.
Category Percentage Covered / Total
🔴 Statements 16.22% 327/2016
🔴 Branches 16.3% 82/503
🔴 Functions 10.85% 65/599
🔴 Lines 15.49% 297/1917

Test suite run success

83 tests passing in 10 suites.

Report generated by 🧪jest coverage report action from a960c14

Please sign in to comment.