Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/declare-babel-syntax-typescript.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@callstack/repack": patch
---

Fix `Cannot find module '@babel/plugin-syntax-typescript'` when bundling TypeScript with `babel-swc-loader` or the codegen rules. Re.Pack passed the plugin to Babel by name, so it only resolved when the project happened to have it installed. With pnpm, builds often worked only through the `NODE_PATH` set by script shims and failed when bundling from Xcode or Gradle.

- `@babel/plugin-syntax-typescript` is now a dependency of Re.Pack and is passed to Babel as a resolved path.
- `@babel/core` is now declared as a peer dependency, since Re.Pack's loaders import it.
1 change: 0 additions & 1 deletion apps/tester-federation-v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
},
"devDependencies": {
"@babel/core": "^7.29.7",
"@babel/plugin-syntax-typescript": "7.25.4",
"@react-native-community/cli": "catalog:testers",
"@react-native-community/cli-platform-android": "catalog:testers",
"@react-native-community/cli-platform-ios": "catalog:testers",
Expand Down
1 change: 1 addition & 0 deletions packages/repack-expo/test/public-environment.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ test('resolves Expo development and production dotenv precedence without exposin
const projectRoot = createEnvironmentProject({
'.env': [
'EXPO_PUBLIC_VALUE=base',
// biome-ignore lint/suspicious/noTemplateCurlyInString: literal dotenv variable expansion under test
'EXPO_PUBLIC_EXPANDED=${SHARED_SUFFIX}-base',
'PRIVATE_TEST_SECRET=private-value-that-must-not-escape',
].join('\n'),
Expand Down
2 changes: 2 additions & 0 deletions packages/repack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"clang-format:android": "find android/src/ -iname \"*.h\" -o -iname \"*.cpp\" | xargs clang-format -i"
},
"peerDependencies": {
"@babel/core": "^7.20.0",
"@module-federation/enhanced": ">=0.6.10",
"@rspack/core": ">=1",
"react-native": ">=0.74",
Expand All @@ -82,6 +83,7 @@
}
},
"dependencies": {
"@babel/plugin-syntax-typescript": "^7.25.4",
"@callstack/repack-dev-server": "workspace:*",
"@discoveryjs/json-ext": "^0.5.7",
"@rspack/plugin-react-refresh": "1.0.0",
Expand Down
23 changes: 23 additions & 0 deletions packages/repack/src/loaders/babelSwcLoader/__tests__/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { getExtraBabelPlugins } from '../utils.js';

const syntaxTypeScriptPlugin = require.resolve(
'@babel/plugin-syntax-typescript'
);

describe('getExtraBabelPlugins', () => {
it('adds the resolved TS syntax plugin for .ts files', () => {
expect(getExtraBabelPlugins('/virtual/file.ts')).toEqual([
[syntaxTypeScriptPlugin, { isTSX: false, allowNamespaces: true }],
]);
});

it('adds the resolved TSX syntax plugin for .tsx files', () => {
expect(getExtraBabelPlugins('/virtual/file.tsx')).toEqual([
[syntaxTypeScriptPlugin, { isTSX: true, allowNamespaces: true }],
]);
});

it('adds no plugins for other files', () => {
expect(getExtraBabelPlugins('/virtual/file.js')).toEqual([]);
});
});
8 changes: 6 additions & 2 deletions packages/repack/src/loaders/babelSwcLoader/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import { importDefaultESM } from '../../helpers/index.js';
type Swc = (typeof experiments)['swc'];
type Logger = ReturnType<LoaderContext['getLogger']>;

const syntaxTypeScriptPlugin = require.resolve(
'@babel/plugin-syntax-typescript'
);

export function isTypeScriptSource(fileName: string) {
return !!fileName && fileName.endsWith('.ts');
}
Expand All @@ -34,12 +38,12 @@ export function getExtraBabelPlugins(filename: string) {
// which includes the syntax-typescript plugin
if (isTypeScriptSource(filename)) {
extraBabelPlugins.push([
'@babel/plugin-syntax-typescript',
syntaxTypeScriptPlugin,
{ isTSX: false, allowNamespaces: true },
]);
} else if (isTSXSource(filename)) {
extraBabelPlugins.push([
'@babel/plugin-syntax-typescript',
syntaxTypeScriptPlugin,
{ isTSX: true, allowNamespaces: true },
]);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { getCodegenTransformRules } from '../getCodegenTransformRules.js';

const syntaxTypeScriptPlugin = require.resolve(
'@babel/plugin-syntax-typescript'
);

describe('getCodegenTransformRules', () => {
const [rule] = getCodegenTransformRules();
const { plugins, overrides } = rule.use.options;
const getOverridePlugins = (file: string) =>
overrides.find((override) => override.test.test(file))?.plugins;

it('references the resolved TS syntax plugin', () => {
expect(plugins).toContainEqual([syntaxTypeScriptPlugin, false]);
expect(getOverridePlugins('NativeFoo.ts')).toEqual([
[syntaxTypeScriptPlugin, { isTSX: false, allowNamespaces: true }],
]);
expect(getOverridePlugins('FooNativeComponent.tsx')).toEqual([
[syntaxTypeScriptPlugin, { isTSX: true, allowNamespaces: true }],
]);
});
});
10 changes: 7 additions & 3 deletions packages/repack/src/utils/getCodegenTransformRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
* @returns Array of module rules
*/
export function getCodegenTransformRules() {
const syntaxTypeScriptPlugin = require.resolve(
'@babel/plugin-syntax-typescript'
);

return [
{
type: 'javascript/auto',
Expand All @@ -21,7 +25,7 @@ export function getCodegenTransformRules() {
},
plugins: [
'@callstack/repack/babel-plugin-syntax-react-native',
['@babel/plugin-syntax-typescript', false],
[syntaxTypeScriptPlugin, false],
'@react-native/babel-plugin-codegen',
],
// config merging reference: https://babeljs.io/docs/options#pluginpreset-entries
Expand All @@ -30,7 +34,7 @@ export function getCodegenTransformRules() {
test: /\.ts$/,
plugins: [
[
'@babel/plugin-syntax-typescript',
syntaxTypeScriptPlugin,
{ isTSX: false, allowNamespaces: true },
],
],
Expand All @@ -39,7 +43,7 @@ export function getCodegenTransformRules() {
test: /\.tsx$/,
plugins: [
[
'@babel/plugin-syntax-typescript',
syntaxTypeScriptPlugin,
{ isTSX: true, allowNamespaces: true },
],
],
Expand Down
6 changes: 3 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions tests/integration/src/loaders/react-native-parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,13 @@ function createFixtureProject(

linkPackage(projectRoot, '@callstack/repack', repackRoot);
linkPackage(projectRoot, '@babel/runtime', babelRuntimeRoot);
for (const name of [
linkPackage(
projectRoot,
'@react-native/babel-plugin-codegen',
Comment thread
dannyhw marked this conversation as resolved.
'@babel/plugin-syntax-typescript',
]) {
linkPackage(projectRoot, name, resolvePresetPackage(name));
}
resolvePresetPackage('@react-native/babel-plugin-codegen')
);
// '@babel/plugin-syntax-typescript' is intentionally not linked: Re.Pack
// resolves it from its own dependencies, as with isolated (e.g. pnpm) installs.
// Webpack needs a resolvable SWC to exercise the SWC path instead of Babel.
linkPackage(projectRoot, '@swc/core', swcRoot);
}
Expand Down
Loading