-
Notifications
You must be signed in to change notification settings - Fork 204
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: ios example app has duplicated symbols due to codegen (#757)
### Summary Fixed #755 There is an effort towards shipping React Native in a prebuilt format on iOS. As a result, some of the codegen-related custom code have to be generated at the build time. However, these changes also affected the codegen generated native code for libraries. This PR patches that behavior on bob level. Related PRs: - facebook/react-native#47518 - facebook/react-native#47650 - facebook/react-native#47517 ### Test plan This adds 3 unit test cases to make sure we're able to parse the codegen paths and delete the necessary files. #### To test it locally: 1. Build bob 1. Create a new library using `npx create-react-native-library`, and pick turbo modules 1. Link the local bob by calling `yarn link path/to/bob --all` in the new library 1. Call `yarn bob build --target codegen` 1. Make sure there is no `.podspec` file or mm files in `android/generated` 1. Make sure there is no `.podspec` file or any of the following files in `ios/generated`: ``` 'RCTAppDependencyProvider.h', 'RCTAppDependencyProvider.mm', 'RCTModulesConformingToProtocolsProvider.h', 'RCTModulesConformingToProtocolsProvider.mm', 'RCTThirdPartyComponentsProvider.h', 'RCTThirdPartyComponentsProvider.mm', 'ReactAppDependencyProvider.podspec', ```
- Loading branch information
Showing
5 changed files
with
178 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 2 additions & 2 deletions
4
...ests__/patchCodegenAndroidPackage.test.ts → ...atches/patchCodegenAndroidPackage.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 3 additions & 3 deletions
6
...b/src/utils/patchCodegenAndroidPackage.ts → ...gen/patches/patchCodegenAndroidPackage.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
...es/react-native-builder-bob/src/targets/codegen/patches/removeCodegenAppLevelCode.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { expect, it, describe, beforeEach, afterEach } from '@jest/globals'; | ||
import fs from 'fs-extra'; | ||
import path from 'node:path'; | ||
import { removeCodegenAppLevelCode } from './removeCodegenAppLevelCode'; | ||
import mockfs from 'mock-fs'; | ||
|
||
const mockPackageJson = { | ||
codegenConfig: { | ||
outputDir: { | ||
android: 'android/generated', | ||
ios: 'ios/generated', | ||
}, | ||
}, | ||
}; | ||
|
||
const mockProjectPath = path.resolve(__dirname, 'mockProject'); | ||
|
||
describe('patchCodegenAndroidPackage', () => { | ||
beforeEach(() => { | ||
mockfs({ | ||
[mockProjectPath]: { | ||
'package.json': JSON.stringify(mockPackageJson), | ||
'ios': { | ||
generated: { | ||
'RCTAppDependencyProvider.h': '', | ||
'RCTAppDependencyProvider.mm': '', | ||
'RCTModulesConformingToProtocolsProvider.h': '', | ||
'RCTModulesConformingToProtocolsProvider.mm': '', | ||
'RCTThirdPartyComponentsProvider.h': '', | ||
'RCTThirdPartyComponentsProvider.mm': '', | ||
'ReactAppDependencyProvider.podspec': '', | ||
}, | ||
}, | ||
'android': { | ||
generated: { | ||
'RCTAppDependencyProvider.h': '', | ||
'RCTAppDependencyProvider.mm': '', | ||
'RCTModulesConformingToProtocolsProvider.h': '', | ||
'RCTModulesConformingToProtocolsProvider.mm': '', | ||
'RCTThirdPartyComponentsProvider.h': '', | ||
'RCTThirdPartyComponentsProvider.mm': '', | ||
'ReactAppDependencyProvider.podspec': '', | ||
}, | ||
}, | ||
}, | ||
}); | ||
}); | ||
|
||
afterEach(() => { | ||
mockfs.restore(); | ||
}); | ||
|
||
it('removes the duplicate iOS files', async () => { | ||
await removeCodegenAppLevelCode(mockProjectPath, mockPackageJson); | ||
|
||
expect( | ||
( | ||
await fs.promises.readdir( | ||
path.join(mockProjectPath, 'ios', 'generated') | ||
) | ||
).length | ||
).toBe(0); | ||
}); | ||
|
||
it('removes the unnecessary Android files', async () => { | ||
await removeCodegenAppLevelCode(mockProjectPath, mockPackageJson); | ||
|
||
expect( | ||
( | ||
await fs.promises.readdir( | ||
path.join(mockProjectPath, 'android', 'generated') | ||
) | ||
).length | ||
).toBe(0); | ||
}); | ||
|
||
it("doesn't crash the process when there are no files to remove", async () => { | ||
mockfs({ | ||
[mockProjectPath]: { | ||
'package.json': JSON.stringify(mockPackageJson), | ||
'ios': { | ||
generated: { | ||
someRandomFile: '', | ||
}, | ||
}, | ||
'android': { | ||
generated: { | ||
someRandomFile: '', | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
await expect( | ||
removeCodegenAppLevelCode(mockProjectPath, mockPackageJson) | ||
).resolves.not.toThrow(); | ||
}); | ||
}); |
70 changes: 70 additions & 0 deletions
70
packages/react-native-builder-bob/src/targets/codegen/patches/removeCodegenAppLevelCode.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import fs from 'fs-extra'; | ||
import path from 'path'; | ||
import { CODEGEN_DOCS } from './patchCodegenAndroidPackage'; | ||
|
||
const FILES_TO_REMOVE = [ | ||
'RCTAppDependencyProvider.h', | ||
'RCTAppDependencyProvider.mm', | ||
'RCTModulesConformingToProtocolsProvider.h', | ||
'RCTModulesConformingToProtocolsProvider.mm', | ||
'RCTThirdPartyComponentsProvider.h', | ||
'RCTThirdPartyComponentsProvider.mm', | ||
'ReactAppDependencyProvider.podspec', | ||
]; | ||
|
||
/** | ||
* With React Native 0.77, calling `@react-native-community/cli codegen` generates | ||
* some app level source files such as `RCTAppDependencyProvider.mm`. | ||
* These files are supposed to be only generated for apps | ||
* but the cli misbehaves and generates them for all sorts of projects. | ||
* You can find the relevant PR here: https://github.com/facebook/react-native/pull/47650 | ||
* This patch can be removed when this gets fixed in React Native. | ||
*/ | ||
export async function removeCodegenAppLevelCode( | ||
projectPath: string, | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
packageJson: any | ||
) { | ||
const codegenAndroidPathSetting: string | undefined = | ||
packageJson.codegenConfig?.outputDir?.android; | ||
if (!codegenAndroidPathSetting) { | ||
throw new Error( | ||
`Your package.json doesn't contain codegenConfig.outputDir.android. Please see ${CODEGEN_DOCS}` | ||
); | ||
} | ||
const codegenAndroidPath = path.resolve( | ||
projectPath, | ||
codegenAndroidPathSetting | ||
); | ||
|
||
if (!(await fs.pathExists(codegenAndroidPath))) { | ||
throw new Error( | ||
`The codegen android path defined in your package.json: ${codegenAndroidPath} doesnt' exist.` | ||
); | ||
} | ||
|
||
const codegenIosPathSetting: string | undefined = | ||
packageJson.codegenConfig?.outputDir?.ios; | ||
if (!codegenIosPathSetting) { | ||
throw new Error( | ||
`Your package.json doesn't contain codegenConfig.outputDir.ios. Please see ${CODEGEN_DOCS}` | ||
); | ||
} | ||
const codegenIosPath = path.resolve(projectPath, codegenIosPathSetting); | ||
|
||
if (!(await fs.pathExists(codegenAndroidPath))) { | ||
throw new Error( | ||
`The codegen iOS path defined in your package.json: ${codegenIosPathSetting} doesnt' exist.` | ||
); | ||
} | ||
|
||
const androidPromises = FILES_TO_REMOVE.map((fileName) => | ||
fs.rm(path.join(codegenAndroidPath, fileName)) | ||
); | ||
|
||
const iosPromises = FILES_TO_REMOVE.map((fileName) => | ||
fs.rm(path.join(codegenIosPath, fileName)) | ||
); | ||
|
||
await Promise.allSettled([...androidPromises, ...iosPromises]); | ||
} |