Skip to content

Commit

Permalink
fix(metro): Use env for default Babel transformer path (#4298)
Browse files Browse the repository at this point in the history
  • Loading branch information
krystofwoldrich authored Nov 21, 2024
1 parent e8464db commit 7fd512a
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 94 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
> make sure you follow our [migration guide](https://docs.sentry.io/platforms/react-native/migration/) first.
<!-- prettier-ignore-end -->

## Unreleased

### Fixes

- Remove `.sentry` tmp directory and use environmental variables instead to save default Babel transformer path ([#4298](https://github.com/getsentry/sentry-react-native/pull/4298))
- This resolves concurrency issues when running multiple bundle processes

## 6.3.0-beta.1

### Features
Expand Down
7 changes: 2 additions & 5 deletions packages/core/src/js/tools/metroconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as process from 'process';
import { env } from 'process';

import { enableLogger } from './enableLogger';
import { cleanDefaultBabelTransformerPath, saveDefaultBabelTransformerPath } from './sentryBabelTransformerUtils';
import { setSentryDefaultBabelTransformerPathEnv } from './sentryBabelTransformerUtils';
import { createSentryMetroSerializer, unstable_beforeAssetSerializationPlugin } from './sentryMetroSerializer';
import type { DefaultConfigOptions } from './vendor/expo/expoconfig';
export * from './sentryMetroSerializer';
Expand Down Expand Up @@ -143,10 +143,7 @@ export function withSentryBabelTransformer(config: MetroConfig): MetroConfig {
}

if (defaultBabelTransformerPath) {
saveDefaultBabelTransformerPath(defaultBabelTransformerPath);
process.on('exit', () => {
cleanDefaultBabelTransformerPath();
});
setSentryDefaultBabelTransformerPathEnv(defaultBabelTransformerPath);
}

return {
Expand Down
52 changes: 12 additions & 40 deletions packages/core/src/js/tools/sentryBabelTransformerUtils.ts
Original file line number Diff line number Diff line change
@@ -1,62 +1,34 @@
import { logger } from '@sentry/utils';
import * as fs from 'fs';
import * as path from 'path';
import * as process from 'process';

import type { BabelTransformer } from './vendor/metro/metroBabelTransformer';

/**
* Saves default Babel transformer path to the project root.
*/
export function saveDefaultBabelTransformerPath(defaultBabelTransformerPath: string): void {
try {
fs.mkdirSync(path.join(process.cwd(), '.sentry'), { recursive: true });
fs.writeFileSync(getDefaultBabelTransformerPath(), defaultBabelTransformerPath);
logger.debug('Saved default Babel transformer path');
} catch (e) {
// eslint-disable-next-line no-console
console.error('[Sentry] Failed to save default Babel transformer path:', e);
}
}
export const SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH = 'SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH';

/**
* Reads default Babel transformer path from the project root.
* Sets default Babel transformer path to the environment variables.
*/
export function readDefaultBabelTransformerPath(): string | undefined {
try {
return fs.readFileSync(getDefaultBabelTransformerPath()).toString();
} catch (e) {
// eslint-disable-next-line no-console
console.error('[Sentry] Failed to read default Babel transformer path:', e);
}
return undefined;
export function setSentryDefaultBabelTransformerPathEnv(defaultBabelTransformerPath: string): void {
process.env[SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH] = defaultBabelTransformerPath;
logger.debug(`Saved default Babel transformer path ${defaultBabelTransformerPath}`);
}

/**
* Cleans default Babel transformer path from the project root.
* Reads default Babel transformer path from the environment variables.
*/
export function cleanDefaultBabelTransformerPath(): void {
try {
fs.unlinkSync(getDefaultBabelTransformerPath());
logger.debug('Cleaned default Babel transformer path');
} catch (e) {
// We don't want to fail the build if we can't clean the file
// eslint-disable-next-line no-console
console.error('[Sentry] Failed to clean default Babel transformer path:', e);
}
}

function getDefaultBabelTransformerPath(): string {
return path.join(process.cwd(), '.sentry/.defaultBabelTransformerPath');
export function getSentryDefaultBabelTransformerPathEnv(): string | undefined {
return process.env[SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH];
}

/**
* Loads default Babel transformer from `@react-native/metro-config` -> `@react-native/metro-babel-transformer`.
*/
export function loadDefaultBabelTransformer(): BabelTransformer {
const defaultBabelTransformerPath = readDefaultBabelTransformerPath();
const defaultBabelTransformerPath = getSentryDefaultBabelTransformerPathEnv();
if (!defaultBabelTransformerPath) {
throw new Error('Default Babel Transformer Path not found in `.sentry` directory.');
throw new Error(
`Default Babel transformer path environment variable ${SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH} is not set.`,
);
}

logger.debug(`Loading default Babel transformer from ${defaultBabelTransformerPath}`);
Expand Down
43 changes: 3 additions & 40 deletions packages/core/test/tools/metroconfig.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
jest.mock('fs', () => {
return {
readFile: jest.fn(),
mkdirSync: jest.fn(),
writeFileSync: jest.fn(),
unlinkSync: jest.fn(),
};
});

import type { getDefaultConfig } from 'expo/metro-config';
import * as fs from 'fs';
import type { MetroConfig } from 'metro';
import * as path from 'path';
import * as process from 'process';

import {
Expand All @@ -19,6 +8,7 @@ import {
withSentryFramesCollapsed,
withSentryResolver,
} from '../../src/js/tools/metroconfig';
import { SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH } from '../../src/js/tools/sentryBabelTransformerUtils';

type MetroFrame = Parameters<Required<Required<MetroConfig>['symbolicator']>['customizeFrame']>[0];

Expand Down Expand Up @@ -69,43 +59,16 @@ describe('metroconfig', () => {
},
);

test.each([
[{ transformer: { babelTransformerPath: 'babelTransformerPath' }, projectRoot: 'project/root' }],
[{ transformer: { babelTransformerPath: 'babelTransformerPath' } }],
])('save default babel transformer path to a file', () => {
test('save default babel transformer path to environment variable', () => {
const defaultBabelTransformerPath = '/default/babel/transformer';

withSentryBabelTransformer({
transformer: {
babelTransformerPath: defaultBabelTransformerPath,
},
projectRoot: 'project/root',
});

expect(fs.mkdirSync).toHaveBeenCalledWith(path.join(process.cwd(), '.sentry'), { recursive: true });
expect(fs.writeFileSync).toHaveBeenCalledWith(
path.join(process.cwd(), '.sentry/.defaultBabelTransformerPath'),
defaultBabelTransformerPath,
);
});

test('clean default babel transformer path file on exit', () => {
const processOnSpy: jest.SpyInstance = jest.spyOn(process, 'on');

const defaultBabelTransformerPath = 'defaultBabelTransformerPath';

withSentryBabelTransformer({
transformer: {
babelTransformerPath: defaultBabelTransformerPath,
},
projectRoot: 'project/root',
});

const actualExitHandler: () => void | undefined = processOnSpy.mock.calls[0][1];
actualExitHandler?.();

expect(processOnSpy).toHaveBeenCalledWith('exit', expect.any(Function));
expect(fs.unlinkSync).toHaveBeenCalledWith(path.join(process.cwd(), '.sentry/.defaultBabelTransformerPath'));
expect(process.env[SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH]).toBe(defaultBabelTransformerPath);
});

test('return config with sentry babel transformer path', () => {
Expand Down
12 changes: 3 additions & 9 deletions packages/core/test/tools/sentryBabelTransformer.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
jest.mock('fs', () => {
return {
readFileSync: jest.fn(),
};
});
import * as process from 'process';

import * as fs from 'fs';
import { SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH } from '../../src/js/tools/sentryBabelTransformerUtils';

// needs to be defined before sentryBabelTransformer is imported
// the transformer is created on import (side effect)
(fs.readFileSync as jest.Mock).mockReturnValue(require.resolve('./fixtures/mockBabelTransformer.js'));
process.env[SENTRY_DEFAULT_BABEL_TRANSFORMER_PATH] = require.resolve('./fixtures/mockBabelTransformer.js');

import * as SentryBabelTransformer from '../../src/js/tools/sentryBabelTransformer';
import type { BabelTransformerArgs } from '../../src/js/tools/vendor/metro/metroBabelTransformer';
Expand Down

0 comments on commit 7fd512a

Please sign in to comment.