React Native
Check out the React Native Aspect on Bit.dev
The built-in React Native Component Development Environment is a concrete composition of the Env Aspect. Use it when getting started with React Native components with Bit and later as a base for any future customization of your ReactNative-based workflow.
React Native environment is composed out of the base React Environment with some specific overrides for dependency management.
#
Use React Native environmentTo use this environment for your components, add it to any of the variants
in your workspace.jsonc
file as follows:
{ "teambit.workspace/variants": { "some/path": { "teambit.react/react-native": {} } }}
#
Create React Native componentsReact Native implements several component templates:
react-native-env
boilerplate for customizing configuration.
Use any of these templates with the bit create
command:
bit create <template name> [components...]
#
Default Configuration and ServicesReact Native, like all over Environments must implement a set of Service Handlers. For each service, React Native compose a different tool and config by default.
React Native is a composition of the React environment with some specific modifications. Most of the links here direct to the actual configs in React environment.
Service | Aspect | Base Configuration |
---|---|---|
Compilation | TypeScript | tsconfig.json |
Testing | Jest | jest.config.js |
Linting | ESLint | eslintrc.ts |
DevServer | Webpack | webpack.config.preview.dev.ts |
Preview (simulation) | Webpack | webpack.config.preview.ts |
Package | PKG | Base package.json props from TypeScript Aspect |
Bundling | Webpack | webpack.config.preview.ts |
Documentation | Core implementation | Docs template |
Build pipeline | Builder | Build pipeline |
Dependencies | Core implementation | Env-dependencies |
Component Generator | Generator | example template |
#
Customize environmentAll environments are extendible. You can take any pre-existing environment, and create a component to extend it. That component can then use APIs to:
- Override default configurations.
- Replace composed tools with others (for example - use Babel instead of TypeScript).
- Add new services and capabilities.
#
Create an extensionThe first step is to create a component that extends React Native. Use the react-native-env
template from React Native env.
bit create react-native-env extensions/custom-react-native
As with any component, environments must themselves have an environment which compiles, builds, transpiles, etc, them. Bit has a special environment that knows how to create other environments - teambit.harmony/aspect
. So for any component that is meant to be a Bit environment, you must set teambit.harmony/aspect
as the environment for that component.
{ //... "teambit.workspace/variants": { //... "extensions/custom-react-native": { "teambit.harmony/aspect": {} } //... }}
Validate the above by running bit env
and see that the extension-component has teambit.harmony/aspect
set as an environment.
Now that you have a basic customized extension to start from, you can go ahead and configure it for your components in workspace.json
:
{ //... "teambit.workspace/variants": { //... "[some]/[variant]": { "[yourscope]/extensions/custom-react-native": {} } //... }}
#
Customize configurationReact Native implements a set of APIs you can use to merge your preferred configuration with its defaults. These APIs are called transformers and they all start with the override
pre-fix. Find Available transformers here.
In case of a conflict, your config will override the default.
import { EnvsMain, EnvsAspect } from '@teambit/envs';import { ReactNativeAspect, ReactNativeMain } from '@teambit/react-native';
const tsconfig = require('./typescript/tsconfig.json');
export class CustomReactNativeExtension { constructor(private reactNative: ReactNativeMain) {}
static dependencies: any = [EnvsAspect, ReactNativeAspect];
static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) { const customReactNativeEnv = reactNative.compose([reactNative.overrideTsConfig(tsconfig)]);
envs.registerEnv(customreactNativeEnv);
return new CustomReactNativeExtension(reactNative); }}
To override any specific configuration it's recommended to create a separate config file with your customized configuration and import it into the main
.extension.ts
file where you can supply it to the relevant transformers. See the tsconfig example in the above snippet.
#
Composing tools and servicesEnvironments use Environment Services by implementing a special class of methods called Service Handlers.
The supplied transformers allow overriding of these services - for instance the overrideCompiler
transformer allows overriding the environment's getCompiler()
method.
The below example uses the overrideCompiler
transformer to override the getCompiler()
Service Handler to change the compilation service.
- Add a Babel config file to your custom environment and import/require it in your
.extension
file - Create a new Babel compiler using the Babel aspect, and initialize it with the above babelConfig
- Use the
compose
Env API to apply the compiler override transformer and add Babel as a transpiler in the environment
import { EnvsMain, EnvsAspect } from '@teambit/envs';import { ReactNativeAspect, ReactNativeMain } from '@teambit/react-native';import { BabelAspect, BabelMain } from '@teambit/babel';
const babelConfig = require('./babel/babel.config');
export class CustomReactNativeExtension { constructor(private reactNative: ReactNativeMain) {}
static dependencies: any = [EnvsAspect, reactNative, BabelAspect];
static async provider([envs, reactNative, babel]: [EnvsMain, ReactNativeMain, BabelMain]) { const babelCompiler = babel.createCompiler({ babelTransformOptions: babelConfig, });
const customReactNativeEnv = reactNative.compose([ reactNative.overrideCompiler(babelCompiler), reactNative.overrideCompilerTasks([babelCompiler.createTask()]), ]);
envs.registerEnv(customReactNativeEnv); return new CustomReactNativeExtension(reactNative); }}
#
Transformers API docsUse these APIs to customize the base React Native environment default configuration with your extension. Read more here.
overrideTsConfig(tsconfig: TsConfigSourceFile): EnvTransformer
#
Merges the environment's default TypeScript configuration with the contents of your typescript configuration file.
This config affects the transpilation carried out when rendering components on the local dev UI. To override the config used when building components, use overrideBuildTsConfig
below.
// ...const tsconfig = require('./typescript/tsconfig.json');export class ReactNativeExtension {// ...
static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) { const newReactNativeEnv = reactNative.compose([ reactNative.overrideTsConfig(tsconfig) ]);}// ...
overrideBuildTsConfig(tsconfig: TsConfigSourceFile): EnvTransformer
#
Merges the environment's default TypeScript configuration with the contents of your typescript configuration file.
This config affects transpilation of component code during the build process, i.e. in preparation for packaging and exporting the component. To override the local ts config used when rendering components in the local UI, please use overrideTsConfig
above.
// ...const tsconfig = require('./typescript/tsconfig.json');export class ReactNativeExtension {// ...
static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) { const newReactNativeEnv = reactNative.compose([ reactNative.overrideTsConfig(tsconfig) ]);}// ...
overridePreviewConfig(config: Configuration): EnvTransformer
#
Merges the Webpack configuration for the 'Preview' environment service, with the contents of your webpack configuration file. This webpack configuration is used for building and rendering your components on the local dev server.
// ...const webpackConfig = require('./webpack/webpack.config');export class ReactNativeExtension {// ... static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) { const newReactNativeEnv = reactNative.compose([ reactNative.overridePreviewConfig(webpackConfig) ]);}// ...
overrideDevServerConfig(config: Configuration): EnvTransformer
#
Merges the Webpack configuration for the 'DevServer' environment service, with the contents of your webpack configuration file. This configuration is used for building and rendering the dev server UI (but not your components, which use the PreviewConfig)
// ...const webpackConfig = require('./webpack/webpack.config');export class ReactNativeExtension {// ... static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) { const newReactNativeEnv = reactNative.compose([ reactNative.overrideDevServerConfig(webpackConfig) ]);}// ...
overrideJestConfig(jestConfigPath: string): EnvTransformer
#
Merges the default configuration for the Jest test runner with the contents of your (jest.config configuration file).
// ...export class ReactNativeExtension {// ... static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) { const newReactNativeEnv = reactNative.compose([ reactNative.overrideJestConfig(require.resolve('./jest/jest.config')) ]);}// ...
overrideBuildPipe(tasks: BuildTask[]): EnvTransformer
#
This method receives an array of build tasks. It merges the provided tasks with the environment's default build pipeline (initiated either on a bit tag
or bit build
command).
// ...// Import the taskimport { CustomTask } from './custom.task'export class CustomReactNative { // ... static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) { // Get the environment's default build pipeline using the 'getBuildPipe' service handler const reactNativePipe = reactNative.env.getBuildPipe() // Add the custom task to the end of the build tasks sequence. const tasks = [...reactNativePipe, new CustomTask()] const newReactNativeEnv = reactNative.compose([reactNative.overrideBuildPipe(tasks)]) // ... }}
overrideDependencies(dependencyPolicy: DependenciesPolicy): EnvTransformer
#
This method receives a dependency-policy object and merges it with the environment's default dependency policy for components using this environment.
Each key-value pair in a dependency-policy object signifies the package and the version to be used. Use also the -
and +
notation to signify a module should moved between dependency types (dev, peer or standard).
// ...const newDependencies = { devDependencies: { '@types/jest': '~26.0.9' }}
export class CustomReactNative { // ... static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) { const newReactNativeEnv = reactNative.compose([ reactNative.overrideDependencies(newDependencies) ]) // ... }}
overridePackageJsonProps(props: PackageJsonProps): EnvTransformer
#
Merges the provide props with the default properties added to the package.json
file of every package generated from components using this environment.
// ...const newPackageProps = { main: 'dist/{main}.js', types: '{main}.ts'}
export class CustomReactNative { // ... static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) { const newReactNativeEnv = reactNative.compose([ reactNative.overridePackageJsonProps(newPackageProps) ]) // ... }}
The built-in React Native Component Development Environment is a concrete composition of the Env Aspect. It compose different tools and configs that fit practices implemented in Create React Native App. Use it when getting started with React Native components with Bit and later as a base for any future customization of your React-Native-based workflow.
React Native environment is composed out of the base React Environment with some specific configuration overrides.
#
Use React Native environmentTo use this environment for your components, add it to any of the variants
in your workspace.jsonc
file as follows:
{ "teambit.workspace/variants": { "[some]/[path]": { "teambit.react/react-native": {} } }}
#
Create React Native componentsReact implements several component templates:
reactnative-env
boilerplate for customizing configuration.
Use any of these templates with the bit create
command:
bit create <template name> [components...]
#
Runtime (framework) dependenciesSimilar to many Frontend frameworks React Native must have a singleton instance in your app's runtime. When building reuseable components we need to adhere to that and have react
and react-native
set as peerDependencies
, thus allowing the consuming app to determine runtime version. React environment implements this via the Dependencies service which is used to override dependency-resolver and set your prefered dependencies.
It is recommended to for you to extend the base React environment and define a semantic version rule to fit your current tech stack and guidelines for reuseable React components.
#
Default Configuration and ServicesReact Native, like all over Environments must implement a set of Service Handlers. For each service, React Native compose a different tool and config by default.
React Native is a composition of the React environment with some specific modifications. Most of the links here direct to the actual configs in React environment.
Service | Aspect | Base Configuration |
---|---|---|
Compilation | TypeScript | tsconfig.json |
Testing | Jest | jest.config.js |
Linting | ESLint | eslintrc.ts |
DevServer | Webpack | webpack.config.preview.dev.ts |
Preview (simulation) | Webpack | webpack.config.preview.ts |
Package | PKG | Base package.json props from TypeScript Aspect |
Bundling | Webpack | webpack.config.preview.ts |
Documentation | Core implementation | Docs template |
Build pipeline | Builder | Build pipeline |
Dependencies | Core implementation | Env-dependencies |
Component Generator | Generator | example template |
#
Customize environmentAll environments are extendible. You can take any pre-existing environment, and create a component to extend it. That component can then use APIs to:
- Override default configurations.
- Replace composed tools with others (for example - use Babel instead of TypeScript).
- Add new services and capabilities.
#
Create an extensionThe first step is to create a component that extends React Native. Use the react-native-env
template from React env.
bit create react-native-env extensions/custom-react-native
After you created your extension you need configure it to be a Bit Aspect. This is because environments are actually aspects that extends Bit's core functionality to support your development workflow. To do this edit your workspace.jsonc and set teambit.harmony/aspect
as the environment applied on the extension you created:
{ //... "teambit.workspace/variants": { //... "extensions/custom-react-native": { "teambit.harmony/aspect": {} } //... }}
Validate it by running bit env
and see that the extension-component has teambit.harmony/aspect
set as an environment.
Now that you have a base extension to start from, you can already go ahead and configure it for your components in workspace.json
:
{ //... "teambit.workspace/variants": { //... "[some]/[variant]": { "[yourscope]/extensions/custom-react-native": {} } //... }}
#
Customize configurationReact implements a set of APIs you can use to merge you preferred configuration with its defaults. These APIs are called transformers and they all start with the override
pre-fix. Find all Available transformers here.
In case of a conflict, your config will override the default.
import { EnvsMain, EnvsAspect } from '@teambit/envs';import { ReactNativeAspect, ReactNativeMain } from '@teambit/react-native';
const tsconfig = require('./typescript/tsconfig.json');
export class CustomReactNativeExtension { constructor(private reactNative: ReactNativeMain) {}
static dependencies: any = [EnvsAspect, ReactNativeAspect];
static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) { const customReactNativeExtension = reactNative.compose([reactNative.overrideTsConfig(tsconfig)]);
envs.registerEnv(customReactNativeExtension);
return new CustomReactNativeExtension(reactNative); }}
To override any specific configuration it's recommended to create a config file for the specific tool and import it to any of the transformers.
#
Composing tools and servicesEnvironments use Environment Services by implementing a special class of methods called Service Handlers.
You can override an environment's compiler replacing its Compiler Service Handler with the method getCompiler()
.
Find all service handlers here.
The below example uses a Service Handler to change compilation service.
- Import the Babel extension component to configure it and set it as the new compiler
- Import your Babel config
- Set the necessary dependencies to be injected (by Bit) into the following 'provider' function
- Instantiate a new Babel compiler with the 'babelConfig' configurations
- use the
compose
Env API to register a new Service Hanlder
import { EnvsMain, EnvsAspect } from '@teambit/envs';import { ReactNativeAspect, ReactNativeMain } from '@teambit/react-native';import { BabelAspect, BabelMain } from '@teambit/babel';
const babelConfig = require('./babel/babel.config');
export class CustomReactNativeExtension { constructor(private reactNative: ReactNativeMain) {}
static dependencies: any = [EnvsAspect, ReactNativeAspect, BabelAspect];
static async provider([envs, reactNative, babel]: [EnvsMain, ReactNativeMain, BabelMain]) { const babelCompiler = babel.createCompiler({ babelTransformOptions: babelConfig, });
const customReactNativeExtension = reactNative.compose([ reactNative.overrideCompiler(babelCompiler), reactNative.overrideCompilerTasks([babelCompiler.createTask()]), ]);
envs.registerEnv(customReactNativeExtension); return new CustomReactNativeExtension(reactNative); }}
#
Transformers API docsUse these APIs to customize React environment default configuration with your extension. React more here.
overrideTsConfig(tsconfig: TsConfigSourceFile): EnvTransformer
#
Merge the environment's default TypeScript configurations with a new (tsconfig.json) configuration file.
// ...const tsconfig = require('./typescript/tsconfig.json');export class ReactNativeExtension {// ...
static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) { const newReactNativeEnv = reactNative.compose([ reactNative.overrideTsConfig(tsconfig) ]);}// ...
overridePreviewConfig(config: Configuration): EnvTransformer
#
Merge the Webpack configurations for the 'Preview' environment service, with a new (webpack.config.js) configuration file.
// ...const webpackConfig = require('./webpack/webpack.config');export class ReactNativeExtension {// ... static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) { const newReactNativeEnv = reactNative.compose([ reactNative.overridePreviewConfig(webpackConfig) ]);}// ...
overrideDevServerConfig(config: Configuration): EnvTransformer
#
Merge the Webpack configurations for the 'DevServer' environment service, with a new (webpack.config.js) configuration file.
// ...const webpackConfig = require('./webpack/webpack.config');export class ReactNativeExtension {// ... static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) { const newReactNativeEnv = reactNative.compose([ reactNative.overrideDevServerConfig(webpackConfig) ]);}// ...
overrideJestConfig(jestConfigPath: string): EnvTransformer
#
This method receives a path (as a string) to a configuration file . Overrides the default configurations for the Jest test runner with a new (jest.config) configuration file. This is done by passing the path to the file as an argument.
// ...export class ReactNativeExtension {// ... static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) { const newReactNativeEnv = reactNative.compose([ reactNative.overrideJestConfig(require.resolve('./jest/jest.config')) ]);}// ...
overrideBuildPipe(tasks: BuildTask[]): EnvTransformer
#
This method receives an array of Bit tasks. It overrides the build pipeline of a component (initiated either on a bit tag
or bit build
command).
// ...// Import the taskimport { CustomTask } from './custom.task';export class ReactNative { // ... static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) { // Get the environment's default build pipeline using the 'getBuildPipe' service handler const reactNativePipe = reactNative.env.getBuildPipe(); // Add the custom task to the end of the build tasks sequence. const tasks = [...reactNativePipe, new CustomTask()]; const newReactNativeEnv = reactNative.compose([reactNative.overrideBuildPipe(tasks)]); // ... }}
overrideDependencies(dependencyPolicy: DependenciesPolicy): EnvTransformer
#
This method receives a Bit dependency-policy object. It overrides the default dependency policy for components using this environment.
Each key-value pair in a dependency-policy object signifies the package and the version to be used. It also uses the -
notation to signify a module should not be defined as a dependency of a certain type (dev, peer or standard).
// ...const newDependencies = { devDependencies: { '@types/jest': '~26.0.9', },};
export class CustomReactNative { // ... static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) { const newReactNativeEnv = reactNative.compose([reactNative.overrideDependencies(newDependencies)]); // ... }}
The above example shows the 'React Native' library being removed as a (runtime) dependency and added as a peer dependency.
overridePackageJsonProps(props: PackageJsonProps): EnvTransformer
#
Overrides the default properties added to the package.json
file of every package generated from components using this environment.
// ...const newPackageProps = { main: 'dist/{main}.js', types: '{main}.ts',};
export class CustomReactNative { // ... static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) { const newReactNativeEnv = reactNative.compose([reactNative.overridePackageJsonProps(newPackageProps)]); // ... }}
#
Service providers API docsUse these APIs to customize React environment default configuration with your extension. Read more here.
getTester(...args : any[]): Tester
#
Returns a test runner to be used by the Tester service.
export class ReactNativeEnv implements Environment { constructor( // ...
// The Jest Aspect private jestAspect: JestMain ) {} // ... getTester(jestConfigPath: string, jestModule = jest): Tester { const jestConfig = require.resolve('./jest/jest.config'); return this.jestAspect.createTester(jestConfig); }}
getCompiler(...args : any[]): Compiler
#
Returns a compiler to be used by the Compiler service.
export class ReactNativeEnv implements Environment {constructor( // ... // The TypeScript aspect private tsAspect: TypescriptMain){}// ...getCompiler() { const tsConfig = require.resolve('./typescript/tsconfig.json') return this.tsAspect.createCompiler(tsConfig);}
getLinter(...args : any[]): Linter
#
Returns a linter to be used by the Linter service.
export class ReactNativeEnv implements Environment { constructor(){ // ... // The ESLint aspect private eslint: ESLintMain } // ... getLinter() { const eslintConfig = require.resolve('./eslint/eslintrc') return this.eslint.createLinter({ config: eslintConfig, // resolve all plugins from the react environment pluginPath: __dirname, }); }}
getDevServer(...args : any[]): DevServer
#
Returns a DevServer to be used by the DevServer service. (A DevServer is essentially the combination of the bundler configurations, together with a specified 'listen' port number)
export class ReactNativeEnv implements Environment { constructor( // ... // The Webpack aspect private webpack: WebpackMain ) {} // ... getDevServer(): DevServer { const withDocs = Object.assign(context, { entry: context.entry.concat([require.resolve('./docs')]), }); return this.webpack.createDevServer(withDocs, webpackConfig); }}
The above example runs the dev server with the environment's documentation template.
getDocsTemplate(...args : any[]): string
#
Returns the path to the documentation template files, to be used by the Documentation service.
For example (see docs files here):
export class ReactNativeEnv implements Environment { // ... getDocsTemplate() { return require.resolve('./docs'); }}
getPackageJsonProps(...args : any[]): object
#
Returns an object that defines the package.json
properties of the packages generated for components handled by this environment. This configuration is used by the Packager service.
export class ReactNativeEnv implements Environment { // ... getPackageJsonProps() { return { main: 'dist/{main}.js', types: '{main}.ts', }; }}
As with any other 'merging' process, the properties defined in the above returned object will be added to configurations set by Bit. Conflicting properties will be overridden by the properties that are set here. Configurations that are set here may also be overridden, either by the 'pkg aspect' or by workspace configurations set using the 'variants API'.
getDependencies(component: any): Promise<DependencyList>
#
Returns an object that defines the default dependencies for components handled by this environment. The returned object is used by the Dependencies service.
export class ReactNativeEnv implements Environment { // ... async getDependencies() { return { dependencies: { react: '-', }, devDependencies: { '@types/react': '16.9.43', '@types/jest': '~26.0.9', }, peerDependencies: { react: '^16.13.1', 'react-dom': '^16.13.1', }, }; }}
As with any other 'merging' process, the properties defined in the above returned object will be added to configurations set by Bit. Conflicting properties will be overridden by the properties that are set here. Configurations that are set here may also be overridden, either by the 'Dependency Resolver aspect' or by workspace configurations set using the 'variants API'.
getBuildPipe(...args : any[]): BuildTask[]
#
Returns an array of build tasks to be used by the Builder service. Tasks will be added after and before Bit's pre-configured build tasks.
export class ReactNativeEnv implements Environment { constructor( // ... // The Compiler aspect private compiler: CompilerMain, // The Tester aspect private tester: TesterMain ) {} getBuildPipe(): BuildTask[] { return [this.compiler.createTask('StencilCompiler', this.getCompiler()), this.tester.task]; }}
#
FAQ#
Compositions issuesYou may need an appropriate loader to handle this file type...
This error can show up for multiple reason, and one of the most popular is because we use a library in a React Native component that uses Native API's. As the local Bit Dev Server runs on the Web it can't work properly with API's that are meant to be run on a mobile device. So components that are using a library that use Native API's cannot be rendered on the web, because the Native API's are unavailable.
One way to solve it is to see if the library has support for Web and update your code to also be Web compatible. If not, the second way to solve this is to search for a parallel library with Web support and make a Webpack aliases in a Bit React Native extension inside your project, and then configure the extension to make a Webpack alises.
If for some reason a library doesn't have a parallel library for the web and doesn't have built in Websupport, you can't make the composition work on the local Bit dev server.
For example, react-native-svg
library has a parallel library called react-native-svg-web
.
Let's create a React Native extension and add a webpack-transformers.ts
file in the extension under webpack
folder, the file looks like this:
import { WebpackConfigTransformer, WebpackConfigMutator, WebpackConfigTransformContext } from '@teambit/webpack';
/** * Transformation to apply for both preview and dev server * @param config * @param _context */// eslint-disable-next-line @typescript-eslint/no-unused-varsfunction commonTransformation(config: WebpackConfigMutator, _context: WebpackConfigTransformContext) { // Merge config with the webpack.config.js file - adding handlebars support // config.merge([webpackConfig]); config.addAliases({ 'react-native-svg': require.resolve('react-native-svg-web'), 'react-native-web': require.resolve('react-native-web'), }); return config;}
/** * Transformation for the preview only * @param config * @param context * @returns */export const previewConfigTransformer: WebpackConfigTransformer = ( config: WebpackConfigMutator, context: WebpackConfigTransformContext) => { const newConfig = commonTransformation(config, context); return newConfig;};
/** * Transformation for the dev server only * @param config * @param context * @returns */export const devServerConfigTransformer: WebpackConfigTransformer = ( config: WebpackConfigMutator, context: WebpackConfigTransformContext) => { const newConfig = commonTransformation(config, context); return newConfig;};
And then in the main file of the extension we created, let's add the import of the Webpack transformers:
import { EnvsMain, EnvsAspect } from '@teambit/envs';import { ReactNativeAspect, ReactNativeMain } from '@teambit/react-native';import { previewConfigTransformer, devServerConfigTransformer } from './webpack/webpack-transformers';
export class CustomReactNativeExtension { constructor(private reactNative: ReactNativeMain) {}
static dependencies: any = [EnvsAspect, ReactNativeAspect];
static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) { const CustomReactNativeEnv = reactNative.compose([ /* Use any of the "reactNative.override..." transformers to */ reactNative.useWebpack({ previewConfig: [previewConfigTransformer], devServerConfig: [devServerConfigTransformer], }), ]);
envs.registerEnv(CustomReactNativeEnv);
return new CustomReactNativeExtension(reactNative); }}
This will add the Webpack aliases to the Webpack configurations and solve the issue.
One last thing we need to do, is to add the peer dependencies of the parallel library we use to the dependency resolver of the extension in the variants section in workspace.jsonc
file:
{ "teambit.workspace/variants": { // ... "[some]/[variant]": { "[yourscope]/extensions/custom-react-native": {} }, "extensions/custom-react-native": { "teambit.harmony/aspect": {}, "teambit.dependencies/dependency-resolver": { "policy": { "dependencies": { "react-native-svg-web": "1.0.9", "react-native-web": "0.16.2", "prop-types": "15.7.2" } } } } // ... }}
In this case react-native-svg-web
has these dependencies in the peer dependencies:
"peerDependencies": { "prop-types": "*", "react": "*", "react-native-web": ">= 0.10.1"},
So we need to add them as the dependencies of the extension so it will work properly.
Now every component that will use the react-native-svg
library will work fine with the compositions, and this solution can be used for every other library that use Native API's.