From 63e16d997633c13971184e07d6c93a2c2ebfac9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Thu, 22 Aug 2024 08:58:51 -0700 Subject: [PATCH 01/17] Add doc from previous work --- docs/recipes/MonorepoSetup.md | 681 ++++++++++++++++++++++++++++++++++ 1 file changed, 681 insertions(+) create mode 100644 docs/recipes/MonorepoSetup.md diff --git a/docs/recipes/MonorepoSetup.md b/docs/recipes/MonorepoSetup.md new file mode 100644 index 00000000..ca786d0a --- /dev/null +++ b/docs/recipes/MonorepoSetup.md @@ -0,0 +1,681 @@ +--- +title: Setting up a Yarn monorepo with Ignite +description: How to set up a Yarn monorepo using Ignite with two extra utilities +tags: + - Ignite + - Monorepo + - Yarn +last_update: + author: Felipe Peña +publish_date: 2024-08-22 +--- + +# Setting up a Yarn monorepo with Ignite + +In this guide, we'll lead you through the process of setting up a Yarn monorepo for your [React Native](https://reactnative.dev/) projects using the [Ignite](https://github.com/infinitered/ignite) framework. We'll start by setting up the monorepo structure, then create a React Native app using Ignite, add a shared form-validator utility, add a shared UI package and finally integrate these utilitoes into the mobile app. + +## Prerequisites + +Before you start, ensure you have the following installed on your machine: + +- [Node.js](https://nodejs.org/en) (version 18 or later) +- [Yarn](https://yarnpkg.com) (version 3.8 or later) + +## Use case + +In a monorepo setup, multiple applications, such as a mobile app (using React Native) and a web app (using React), can share common functionalities. This guide will walk you through the process of setting up and utilizing shared utilities within a monorepo. For instance, if you have several apps that need to share an ESLint configuration or UI components, you can create reusable packages that can be integrated across all your applications. + + +:::info + +More information on whether you want to setup your app within a monorepo can be found [here](https://github.com/infinitered/ignite/blob/monorepo-setup-doc/docs/Monorepos-Overview.md). + +::: + +By centralizing these utilities, you reduce code duplication and simplify maintenance, ensuring that any updates or bug fixes are immediately available to all your apps. + +In this setup, we’ll create a React Native app along with two shared packages: one for holding a common ESLint configuration and another for shared UI components. Finally, we’ll integrate these packages into the mobile app. + +## Step 1: Setting up the monorepo + +First, follow the [Expo documentation on setting up monorepos](https://docs.expo.dev/guides/monorepos/) to initialize your own monorepo. This will include setting up your `packages/` and `apps/` directories and configuring Yarn workspaces. + +Here's a quick recap: + +1. Initialize the monorepo: + +```shell +mkdir monorepo-example +cd monorepo-example +yarn init +``` + +2. Configure workspaces in `package.json`: + +```json +// success-line-start +{ + "private": true, + "workspaces": { + "packages": [ + "packages/*" + ], + "apps": [ + "apps/*" + ] + } +} +// success-line-end +``` + +:::info + +You can organize the folder structure of your Yarn monorepo however it best suits your project. While this guide suggests using `apps/` and `packages/`, you can rename or add directories like `services/` or `libs/` to fit your workflow. + +The key is to keep your monorepo clear and organized, ensuring that it’s easy to manage and navigate for your team. + +::: + +3. Create directory structure: + +```shell +mkdir apps packages +``` + +## Step 2: Create mobile app using Ignite + +Ignite is a powerful tool for scaffolding React Native projects. In this step, we'll create your first app within the monorepo using Ignite. + +1. Install the [Ignite CLI](https://www.npmjs.com/package/ignite-cli) (if you haven't already): + +```shell +npx ignite-cli@latest +``` + +2. Generate a new app: + Navigate to the apps/ directory and run the following command to create a new app: + +```shell +cd apps +ignite new mobile +``` + +We suggest the following answers to the prompts: + +``` +📝 Do you want to use Expo?: Expo - Recommended for almost all apps [Default] +📝 Which Expo workflow?: Expo Go - For simple apps that don't need custom native code [Default] +📝 Do you want to initialize a git repository?: No +📝 Remove demo code? We recommend leaving it in if it's your first time using Ignite: No +📝 Which package manager do you want to use?: yarn +📝 Do you want to install dependencies?: No +``` + +3. Open `metro.config.js` file + +```shell +touch mobile/metro.config.js +``` + +4. Replace the following lines in the Metro configuration file with the lines below + +```js +// Learn more https://docs.expo.io/guides/customizing-metro +const { getDefaultConfig } = require('expo/metro-config'); + +// success-line-start +// Get monorepo root folder +const monorepoRoot = path.resolve(projectRoot, '../..'); +// success-line-end + +/** @type {import('expo/metro-config').MetroConfig} */ +// error-line +const config = getDefaultConfig(__dirname); +// success-line +const config = getDefaultConfig(projectRoot); + +config.transformer.getTransformOptions = async () => ({ + transform: { + // Inline requires are very useful for deferring loading of large dependencies/components. + // For example, we use it in app.tsx to conditionally load Reactotron. + // However, this comes with some gotchas. + // Read more here: https://reactnative.dev/docs/optimizing-javascript-loading + // And here: https://github.com/expo/expo/issues/27279#issuecomment-1971610698 + inlineRequires: true, + }, +}); + +// success-line-start +// 1. Watch all files within the monorepo +config.watchFolders = [monorepoRoot]; +// 2. Let Metro know where to resolve packages and in what order +config.resolver.nodeModulesPaths = [ + path.resolve(projectRoot, 'node_modules'), + path.resolve(monorepoRoot, 'node_modules'), +]; +// success-line-end + +// This helps support certain popular third-party libraries +// such as Firebase that use the extension cjs. +config.resolver.sourceExts.push("cjs") + +module.exports = config; +``` + +## Step 3: Install dependencies + +Let's make sure all of our dependendencies are installed for both apps. + +1. Run `yarn` at the root of the project + +```shell +cd .. +cd .. +yarn +``` + +:::info + +When you run yarn at the top of the monorepo with Yarn 3.x, Yarn installs all dependencies and links the packages. It places a single node_modules folder in each package’s directory, but shared dependencies are typically stored in a .yarn/cache folder at the root. Yarn uses Plug’n’Play (PnP) to resolve dependencies without the traditional node_modules structure, creating a more efficient setup. Each package or app is linked to the dependencies it needs through Yarn’s PnP system. For more details, you can check out [Yarn's documentation on Plug'n'Play](https://yarnpkg.com/features/pnp). + +::: + +## Step 4: Add a shared ESLint configuration with TypeScript + +In a monorepo setup, maintaining consistent code quality across TypeScript projects is essential. Sharing a single ESLint configuration file between these apps ensures consistent coding standards and streamlines the development process. + +1. Create a shared ESLint configuration package: + +Inside your monorepo, create a new package for your shared ESLint configuration. + +```shell +mkdir packages/eslint-config +cd packages/eslint-config +``` + +2. Initialize the package: + +Initialize the package with a `package.json` file. + +```shell +yarn init -y +``` + +3. Install ESLint and TypeScript dependencies: + +Install ESLint, TypeScript, and any shared plugins or configurations that you want to use across the apps. + +```shell +yarn add eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react eslint-plugin-react-native eslint-plugin-reactotron eslint-config-standard eslint-config-prettier --dev +``` + +4. Create the `tsconfig.json` file: + +`packages/eslint-config/tsconfig.json` + +```json +// success-line-start +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "lib": ["es6", "dom"], + "jsx": "react", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true + } + } + // success-line-end + ``` + +5. Create the shared ESLint configuration file: + +Create an `index.ts` file in the root of your eslint-config package. We will reuse Ignite’s boilerplate ESLint configuration and then replace the original configuration with it. + +`packages/eslint-config/index.ts` + +```typescript +module.exports = { + root: true, + parser: "@typescript-eslint/parser", + extends: [ + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "plugin:react-native/all", + "standard", + "prettier", + ], + plugins: [ + "@typescript-eslint", + "react", + "react-native", + "reactotron", + ], + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + settings: { + react: { + pragma: "React", + version: "detect", + }, + }, + globals: { + __DEV__: false, + jasmine: false, + beforeAll: false, + afterAll: false, + beforeEach: false, + afterEach: false, + test: false, + expect: false, + describe: false, + jest: false, + it: false, + }, + rules: { + "@typescript-eslint/ban-ts-ignore": 0, + "@typescript-eslint/ban-ts-comment": 0, + "@typescript-eslint/explicit-function-return-type": 0, + "@typescript-eslint/explicit-member-accessibility": 0, + "@typescript-eslint/explicit-module-boundary-types": 0, + "@typescript-eslint/indent": 0, + "@typescript-eslint/member-delimiter-style": 0, + "@typescript-eslint/no-empty-interface": 0, + "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/no-object-literal-type-assertion": 0, + "@typescript-eslint/no-var-requires": 0, + "@typescript-eslint/no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + }, + ], + "comma-dangle": 0, + "multiline-ternary": 0, + "no-undef": 0, + "no-unused-vars": 0, + "no-use-before-define": 0, + "no-global-assign": 0, + "quotes": 0, + "react-native/no-raw-text": 0, + "react/no-unescaped-entities": 0, + "react/prop-types": 0, + "space-before-function-paren": 0, + "reactotron/no-tron-in-production": "error", + }, +} +// success-line-end +``` + +This configuration (originally sourced from [Ignite](https://github.com/infinitered/ignite)) provides a strong foundation for TypeScript, React, React Native, and import order rules. You can adjust the rules according to your project's specific needs. + +5. Compile the TypeScript configuration: + +```shell +npx tsc +``` + +This will generate a `index.js` file from your `index.ts` file. + +## Step 6: Use the shared ESLint configuration in your apps + +1. Navigate to the mobile app: + +```shell +cd .. +cd .. +cd apps/mobile +``` + +2. Add the ESLint shared package to the `package.json` file: + +`apps/mobile/package.json` + +```json +"eslint": "8.17.0", +// success-line + "eslint-config": "workspace:^", + "eslint-config-prettier": "8.5.0", +``` + +3. Replace the shared ESLint configuration in `package.json` + +`apps/mobile/package.json` + +```json +// error-line-start +"eslintConfig": { + "root": true, + "parser": "@typescript-eslint/parser", + "extends": [ + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "plugin:react-native/all", + "standard", + "prettier" + ], + "plugins": [ + "@typescript-eslint", + "react", + "react-native", + "reactotron" + ], + "parserOptions": { + "ecmaFeatures": { + "jsx": true + } + }, + "settings": { + "react": { + "pragma": "React", + "version": "detect" + } + }, + "globals": { + "__DEV__": false, + "jasmine": false, + "beforeAll": false, + "afterAll": false, + "beforeEach": false, + "afterEach": false, + "test": false, + "expect": false, + "describe": false, + "jest": false, + "it": false + }, + "rules": { + "@typescript-eslint/ban-ts-ignore": 0, + "@typescript-eslint/ban-ts-comment": 0, + "@typescript-eslint/explicit-function-return-type": 0, + "@typescript-eslint/explicit-member-accessibility": 0, + "@typescript-eslint/explicit-module-boundary-types": 0, + "@typescript-eslint/indent": 0, + "@typescript-eslint/member-delimiter-style": 0, + "@typescript-eslint/no-empty-interface": 0, + "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/no-object-literal-type-assertion": 0, + "@typescript-eslint/no-var-requires": 0, + "@typescript-eslint/no-unused-vars": [ + "error", + { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_" + } + ], + "comma-dangle": 0, + "multiline-ternary": 0, + "no-undef": 0, + "no-unused-vars": 0, + "no-use-before-define": 0, + "no-global-assign": 0, + "quotes": 0, + "react-native/no-raw-text": 0, + "react/no-unescaped-entities": 0, + "react/prop-types": 0, + "space-before-function-paren": 0, + "reactotron/no-tron-in-production": "error" + } + } +// error-line-end +// success-line-start +"eslintConfig": { + extends: ["@monorepo-example/eslint-config"], +} +// success-line-end +``` + +## Step 6: Create the shared UI components package: + +Let's create a Badge component as a shared UI component that can be used across the monorepo apps. The Badge component is a simple, versatile element often used to display small bits of information, such as notifications, statuses, or labels. + +1. Navigate to the packages folder: + +```shell +cd .. +cd .. +cd packages +``` + +2. Create the package directory: + +```shell +mkdir ui-components +cd ui-components +``` + +3. Initialize the package: + +Initialize the package with a `package.json` file. + +```shell +yarn init -y +``` + +4. Install dependencies: + +Install any necessary dependencies, such as React, React Native, and TypeScript, which will be used across both platforms. + +```shell +yarn add react react-native typescript --peer +yarn add @types/react @types/react-native --dev +``` + +4. Create the `tsconfig.json` file: + +`packages/ui-components/tsconfig.json` + +```json +// success-line-start +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "es2017"], + "module": "commonjs", + "jsx": "react", + "declaration": true, + "outDir": "dist", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true + }, + "include": ["src"], + "exclude": ["node_modules"] +} + // success-line-end + ``` + +5. Create the badge component: + +Inside the `packages/ui-components` directory, create a `src` folder and add your Badge component. + +```shell +mkdir src +touch src/Badge.tsx +``` + +6. Build the badge component: + +`packages/ui-component/src/Badge.tsx` + +```tsx +// success-line-start +import React, { FC } from "react" +import { View, Text, StyleSheet, ViewStyle, TextStyle } from "react-native" + +interface BadgeProps { + label: string + color?: string + backgroundColor?: string + style?: ViewStyle + textStyle?: TextStyle +} + +export const Badge: FC = ({ label, color = "white", backgroundColor = "red", style, textStyle }) => { + return ( + + {label} + + ) +} + +const styles = StyleSheet.create({ + badge: { + paddingHorizontal: 8, + paddingVertical: 4, + borderRadius: 12, + alignSelf: "flex-start", + } as ViewStyle, + text: { + fontSize: 12, + fontWeight: "bold", + } as TextStyle, +}) +// success-line-end +``` + +The Badge component is a simple UI element that can display a label with customizable colors, making it versatile for use in different parts of your application, such as notification counts, statuses, or category labels. + +7. Export the badge component: + +Ensure that your component is exported in the package's main entry file. + +`packages/ui-component/src/index.ts` + +```ts +// success-line-start +export * from "./Badge" +// success-line-end +``` + +8. Compile the package: + +Compile your TypeScript code to ensure it's ready for consumption by other packages. + +```shell +yarn tsc +``` + +## Step 7: Use the shared UI package in the mobile app + +1. Navigate to the mobile app: + +```shell +cd .. +cd .. +cd apps/mobile +``` + +2. Add the shared UI package to the `package.json` file: + +`apps/mobile/package.json` + +```json + "react-native-screens": "3.31.1", + "react-native-web": "~0.19.6", + // success-line + "ui-components": "workspace:^", + }, +``` + +3. Add the Badge component to the UI + +Now, decide where you'd like to display the Badge. For this example, let’s place in the login screen, below the heading and above the form fields to indicate the number of login attempts if they exceed a certain number. + +`apps/mobile/apps/screebs/LoginScreen.tsx` + +```tsx +import type { ThemedStyle } from "app/theme" +import { useAppTheme } from "app/utils/useAppTheme" +// success-line +import { Badge } from "@myworkspace/ui-components" + +... + + + +// success-line-start +{attemptsCount > 0 && ( + 2 ? "red" : "blue"} + style={themed($badge)} + textStyle={themed($badgeText)} + /> +)} +// success-line-end +``` + +## Step 8: Run mobile app to make sure logic was added + +1. Navigate to the root of the project: + +```shell +cd .. +cd .. +``` + +2. Make sure dependencies are installed: + +```shell +yarn +``` + +3. Run React Native app (make sure you have your [environment setup](https://reactnative.dev/docs/set-up-your-environment)): + +For iOS: + +```shell +cd apps/mobile +yarn ios +``` + +For Android: + +```shell +cd apps/mobile +yarn android +``` + +## Step 9: Add Yarn global scripts (optional) + +Yarn's workspaces feature allows you to define and run scripts globally across all packages in your monorepo. This simplifies your workflow by enabling you to execute tasks like testing, building, or linting from the root of your project, ensuring consistency across all packages. In this section, we’ll explore how to set up and use global scripts with Yarn in your monorepo. + +Let's add a global script for the mobile app to run iOS and Android projects. + +1. Navigate to the root of the project: + +```shell +cd .. +cd .. +``` + +2. Add a global script to the root `package.json` file: + +`package.json` + +```json + "version": "1.0.0", + // success-line-start + "scripts": { + "mobile:ios" : "yarn workspace mobile ios", + "mobile:android" : "yarn workspace mobile android" + }, + // success-line-end + "workspaces": [ + "apps/*", + "utilities/*" + ] +``` + + +For more information on Yarn's global scripts, check [this site](https://yarnpkg.com/features/workspaces#global-scripts). + +## Conclusion + +Congratulations on setting up your Yarn monorepo! By using the Ignite framework, and two shared packages, you've successfully integrated these together. This setup enables you to scale your projects efficiently by sharing code across multiple applications in a well-structured and organized manner. \ No newline at end of file From 0aab531e27711a83182b60150944de555f27e031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Thu, 22 Aug 2024 09:35:03 -0700 Subject: [PATCH 02/17] Add second doc and right link --- docs/MonoreposOverview.md | 106 ++++++++++++++++++ ...repoSetup.md => SettingsUpYarnMonorepo.md} | 4 +- 2 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 docs/MonoreposOverview.md rename docs/recipes/{MonorepoSetup.md => SettingsUpYarnMonorepo.md} (98%) diff --git a/docs/MonoreposOverview.md b/docs/MonoreposOverview.md new file mode 100644 index 00000000..880c5e49 --- /dev/null +++ b/docs/MonoreposOverview.md @@ -0,0 +1,106 @@ +--- +title: Choosing the right monorepo strategy for your project +description: Choosing the right monorepo strategy for your project +tags: + - Monorepo + - Yarn +last_update: + author: Felipe Peña +--- + +# Choosing the right monorepo strategy for your project + +## Introduction + +When embarking on a software development project, particularly in the context of React Native and using the Ignite framework, the decision to adopt a monorepo structure is critical. A monorepo can streamline development, foster better code sharing, and simplify dependency management. However, it's not a one-size-fits-all solution. This document explores when you should consider using a monorepo, when you might want to avoid it, the most common monorepo options available, and typical setups for software applications. + +## When to use a monorepo + +- **Code sharing across multiple projects**: If your project involves multiple apps or services that share a significant amount of code, a monorepo can help ensure that these shared components are consistent across all projects. This is particularly beneficial for UI components, utility functions, or custom logic. + +- **Unified CI/CD pipeline**: A monorepo allows you to manage a single CI/CD pipeline, simplifying the automation process. This is useful when you want to ensure that all parts of your application are tested and deployed together, reducing the risk of version mismatches. + +- **Simplified dependency management**: Managing dependencies across multiple repositories can be complex and error-prone. With a monorepo, you can centralize dependency management, making it easier to maintain consistency and avoid version conflicts. + +- **Synchronous release cycles**: If your apps or services need to be released together, a monorepo makes it easier to coordinate these releases. This is often the case in large-scale enterprise applications where different parts of the system are closely interconnected. + +- **Small to medium-sized teams**: Monorepos work well for small to medium-sized teams. With everyone working in the same repository, it’s easier to collaborate, share code, and stay aligned on changes. + +## When not to use a monorepo + +- **Large and unrelated projects**: If your projects are large and unrelated, a monorepo can become unwieldy. The repository size might grow excessively, and it can become difficult to manage unrelated codebases together, leading to longer CI/CD times and more complex build processes. + +- **Different lifecycles**: When different projects have significantly different release cycles or stability requirements, maintaining them in a monorepo can introduce unnecessary complexity. For example, if one service is in active development while another is in maintenance mode, separate repositories might be more appropriate. + +- **Security concerns**: If your projects require different access controls or have varying levels of security requirements, a monorepo might not be suitable. Ensuring that sensitive parts of the codebase are protected can be more challenging in a monorepo setup. + +- **Large, distributed teams**: For large, distributed teams, a monorepo can become hard to manage. With many contributors, the repository can grow quickly, leading to longer build times and more complicated merges. In these cases, using separate repositories might be better, allowing different teams to work independently without slowing each other down. + +## Common monorepo tools + +| Tool | Pro | Cons | +| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| Yarn Workspaces [Recommended] | Built-in support for monorepos.
Simplifies dependency management across packages.
Excellent community support and documentation. | Can be complex to configure initially.
Some issues with peer dependencies. | +| Nx | Focuses on improving performance with advanced caching and task scheduling.
Great for large-scale enterprise applications. | Steeper learning curve.
May be overkill for smaller projects. | +| Turborepo | High performance with built-in caching and parallel task execution.
Simplifies monorepo management with minimal configuration. | Less mature ecosystem compared to Yarn or Lerna.
Limited tooling support for some workflows. | +| Pnpm | Efficient disk space usage with unique package storage.
Fast installation times.
Built-in support for monorepos. | Less mainstream adoption, leading to potential issues with community support.
Some tooling might not fully support Pnpm yet. | + +## Common monorepo setups for software apps + +### Frontend and backend in a single monorepo + +Structure: + +- `/frontend`: Contains the React Native app and other frontend components. +- `/backend`: Contains the server-side code, typically a Node.js or Python backend. +- `/shared`: Contains shared utilities, types, or components used by both frontend and backend. + +Use case: Ideal for projects where the frontend and backend are tightly coupled and frequently share code, such as shared type definitions, utility functions, or API clients. + +### Multiple mobile apps in a single monorepo + +Structure: + +- `/app-ios`: Contains the iOS-specific code. +- `/app-android`: Contains the Android-specific code. +- `/shared`: Contains shared React Native components, utilities, and business logic. + +Use case: Best for projects with multiple mobile apps that need to share a significant amount of code, ensuring consistency across different platforms. + +### Monorepo with multiple microservices + +Structure: + +- `/service-auth`: Contains the authentication service. +- `/service-payment`: Contains the payment processing service. +- `/service-notifications`: Contains the notification service. +- `/shared`: Contains shared libraries, such as logging or database utilities. + +Use case: Suitable for large-scale applications with multiple microservices that need to share common libraries or configurations. + +### Hybrid monorepo (web, mobile, and backend) + +Structure: + +- `/web`: Contains the web application code, typically built with React or Next.js. +- `/mobile`: Contains the React Native mobile app code. +- `/backend`: Contains the backend services. +- `/shared`: Contains shared components, utilities, or API clients. + +Use case: Ideal for projects that need to maintain both web and mobile applications with a shared backend, ensuring that all parts of the system stay in sync. + +### Library and application in a single monorepo + +Structure: + +- `/library`: Contains the core library code, which could be published as an npm package. +- `/app`: Contains the application code that consumes the library. +- `/docs`: Contains documentation for the library and application. + +Use case: Best for projects where a core library is being developed alongside an application that consumes it, allowing for rapid iteration and testing. + +## Conclusion + +Choosing whether to use a monorepo and selecting the right setup and tool depends on your project's specific needs. Yarn Workspaces is generally the recommended choice due to its balance of simplicity, community support, and effectiveness in managing shared dependencies. However, other options like Lerna, Nx, Turborepo, and Pnpm offer unique advantages that might better suit your project depending on its scale, complexity, and specific requirements. + +By carefully considering the pros and cons of each option and common monorepo setups, you can select the best strategy to streamline your development process and ensure the long-term maintainability of your codebase. \ No newline at end of file diff --git a/docs/recipes/MonorepoSetup.md b/docs/recipes/SettingsUpYarnMonorepo.md similarity index 98% rename from docs/recipes/MonorepoSetup.md rename to docs/recipes/SettingsUpYarnMonorepo.md index ca786d0a..c696b4c6 100644 --- a/docs/recipes/MonorepoSetup.md +++ b/docs/recipes/SettingsUpYarnMonorepo.md @@ -1,6 +1,6 @@ --- title: Setting up a Yarn monorepo with Ignite -description: How to set up a Yarn monorepo using Ignite with two extra utilities +description: How to set up a Yarn monorepo using Ignite and two extra shared utilities tags: - Ignite - Monorepo @@ -28,7 +28,7 @@ In a monorepo setup, multiple applications, such as a mobile app (using React Na :::info -More information on whether you want to setup your app within a monorepo can be found [here](https://github.com/infinitered/ignite/blob/monorepo-setup-doc/docs/Monorepos-Overview.md). +More information on whether you want to setup your app within a monorepo can be found [here](/docs/MonoreposOverview.md). ::: From 629fbf80225e19a2743c8759c671d77e4929a05d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Thu, 22 Aug 2024 09:38:35 -0700 Subject: [PATCH 03/17] Add better description --- docs/MonoreposOverview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/MonoreposOverview.md b/docs/MonoreposOverview.md index 880c5e49..d242d837 100644 --- a/docs/MonoreposOverview.md +++ b/docs/MonoreposOverview.md @@ -1,6 +1,6 @@ --- title: Choosing the right monorepo strategy for your project -description: Choosing the right monorepo strategy for your project +description: This document outlines the advantages and challenges of adopting a monorepo strategy for software development projects, particularly in the context of React Native and the Ignite framework. It provides guidance on when to use or avoid a monorepo, explores common monorepo tools, and discusses typical setups to help teams select the most suitable approach for their needs. tags: - Monorepo - Yarn From 8aa2df887cf2f31590690524db4eede570e714a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Thu, 22 Aug 2024 09:49:29 -0700 Subject: [PATCH 04/17] Improve diff for init monorepo --- docs/recipes/SettingsUpYarnMonorepo.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/recipes/SettingsUpYarnMonorepo.md b/docs/recipes/SettingsUpYarnMonorepo.md index c696b4c6..7a2c0cbe 100644 --- a/docs/recipes/SettingsUpYarnMonorepo.md +++ b/docs/recipes/SettingsUpYarnMonorepo.md @@ -53,8 +53,10 @@ yarn init 2. Configure workspaces in `package.json`: ```json -// success-line-start { + "name": "monorepo-example", + "packageManager": "yarn@3.8.4", + // success-line-start "private": true, "workspaces": { "packages": [ @@ -64,8 +66,8 @@ yarn init "apps/*" ] } + // success-line-end } -// success-line-end ``` :::info From dc1b994e73e266694d40e12cf6fe4f8c2812c76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Thu, 22 Aug 2024 09:55:08 -0700 Subject: [PATCH 05/17] Few improvements to doc --- docs/recipes/SettingsUpYarnMonorepo.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/recipes/SettingsUpYarnMonorepo.md b/docs/recipes/SettingsUpYarnMonorepo.md index 7a2c0cbe..181e450f 100644 --- a/docs/recipes/SettingsUpYarnMonorepo.md +++ b/docs/recipes/SettingsUpYarnMonorepo.md @@ -166,7 +166,7 @@ module.exports = config; ## Step 3: Install dependencies -Let's make sure all of our dependendencies are installed for both apps. +Let's make sure all of our dependendencies are installed for the mobile app. 1. Run `yarn` at the root of the project @@ -178,7 +178,7 @@ yarn :::info -When you run yarn at the top of the monorepo with Yarn 3.x, Yarn installs all dependencies and links the packages. It places a single node_modules folder in each package’s directory, but shared dependencies are typically stored in a .yarn/cache folder at the root. Yarn uses Plug’n’Play (PnP) to resolve dependencies without the traditional node_modules structure, creating a more efficient setup. Each package or app is linked to the dependencies it needs through Yarn’s PnP system. For more details, you can check out [Yarn's documentation on Plug'n'Play](https://yarnpkg.com/features/pnp). +When you run yarn at the top of the monorepo with Yarn 3.x, Yarn installs all dependencies and links the packages. It places a single `node_modules` folder in each package’s directory, but shared dependencies are typically stored in a `.yarn/cache` folder at the root. Yarn uses Plug’n’Play (PnP) to resolve dependencies without the traditional `node_modules` structure, creating a more efficient setup. Each package or app is linked to the dependencies it needs through Yarn’s PnP system. For more details, you can check out [Yarn's documentation on Plug'n'Play](https://yarnpkg.com/features/pnp). ::: @@ -200,7 +200,7 @@ cd packages/eslint-config Initialize the package with a `package.json` file. ```shell -yarn init -y +yarn init ``` 3. Install ESLint and TypeScript dependencies: @@ -456,7 +456,7 @@ cd ui-components Initialize the package with a `package.json` file. ```shell -yarn init -y +yarn init ``` 4. Install dependencies: From 6df9d1b89012d448f897e90dd644d92143922eaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Thu, 22 Aug 2024 14:46:43 -0700 Subject: [PATCH 06/17] Fixes to doc --- docs/recipes/SettingsUpYarnMonorepo.md | 38 +++++++++++++------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/recipes/SettingsUpYarnMonorepo.md b/docs/recipes/SettingsUpYarnMonorepo.md index 181e450f..7e20af87 100644 --- a/docs/recipes/SettingsUpYarnMonorepo.md +++ b/docs/recipes/SettingsUpYarnMonorepo.md @@ -47,7 +47,7 @@ Here's a quick recap: ```shell mkdir monorepo-example cd monorepo-example -yarn init +yarn init -y ``` 2. Configure workspaces in `package.json`: @@ -55,17 +55,15 @@ yarn init ```json { "name": "monorepo-example", - "packageManager": "yarn@3.8.4", + // error-line + "packageManager": "yarn@3.8.4" // success-line-start + "packageManager": "yarn@3.8.4", "private": true, - "workspaces": { - "packages": [ - "packages/*" - ], - "apps": [ - "apps/*" - ] - } + "workspaces": [ + "apps/*", + "packages/*" + ] // success-line-end } ``` @@ -99,7 +97,7 @@ npx ignite-cli@latest ```shell cd apps -ignite new mobile +npx ignite-cli new mobile ``` We suggest the following answers to the prompts: @@ -172,8 +170,7 @@ Let's make sure all of our dependendencies are installed for the mobile app. ```shell cd .. -cd .. -yarn +yarn install ``` :::info @@ -200,7 +197,7 @@ cd packages/eslint-config Initialize the package with a `package.json` file. ```shell -yarn init +yarn init -y ``` 3. Install ESLint and TypeScript dependencies: @@ -456,7 +453,7 @@ cd ui-components Initialize the package with a `package.json` file. ```shell -yarn init +yarn init -y ``` 4. Install dependencies: @@ -560,7 +557,7 @@ export * from "./Badge" Compile your TypeScript code to ensure it's ready for consumption by other packages. ```shell -yarn tsc +npx tsc ``` ## Step 7: Use the shared UI package in the mobile app @@ -579,9 +576,12 @@ cd apps/mobile ```json "react-native-screens": "3.31.1", + // error-line + "react-native-web": "~0.19.6" + // success-line-start "react-native-web": "~0.19.6", - // success-line - "ui-components": "workspace:^", + "ui-components": "workspace:^" + // success-line-end }, ``` @@ -589,7 +589,7 @@ cd apps/mobile Now, decide where you'd like to display the Badge. For this example, let’s place in the login screen, below the heading and above the form fields to indicate the number of login attempts if they exceed a certain number. -`apps/mobile/apps/screebs/LoginScreen.tsx` +`apps/mobile/apps/screens/LoginScreen.tsx` ```tsx import type { ThemedStyle } from "app/theme" From 6a6ec6b31f26d347b5515c6aa239a16e2ca6d948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Mon, 26 Aug 2024 08:55:21 -0700 Subject: [PATCH 07/17] General cleanup --- docs/recipes/SettingsUpYarnMonorepo.md | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/docs/recipes/SettingsUpYarnMonorepo.md b/docs/recipes/SettingsUpYarnMonorepo.md index 7e20af87..bf8b576e 100644 --- a/docs/recipes/SettingsUpYarnMonorepo.md +++ b/docs/recipes/SettingsUpYarnMonorepo.md @@ -111,13 +111,13 @@ We suggest the following answers to the prompts: 📝 Do you want to install dependencies?: No ``` -3. Open `metro.config.js` file +3. Open the `metro.config.js` file: ```shell touch mobile/metro.config.js ``` -4. Replace the following lines in the Metro configuration file with the lines below +4. Replace the following lines in the Metro configuration file with the lines below: ```js // Learn more https://docs.expo.io/guides/customizing-metro @@ -166,7 +166,7 @@ module.exports = config; Let's make sure all of our dependendencies are installed for the mobile app. -1. Run `yarn` at the root of the project +1. Run `yarn` at the root of the project: ```shell cd .. @@ -342,7 +342,7 @@ cd apps/mobile "eslint-config-prettier": "8.5.0", ``` -3. Replace the shared ESLint configuration in `package.json` +3. Replace the shared ESLint configuration in `package.json`: `apps/mobile/package.json` @@ -429,7 +429,7 @@ cd apps/mobile // success-line-end ``` -## Step 6: Create the shared UI components package: +## Step 6: Create the shared UI components package Let's create a Badge component as a shared UI component that can be used across the monorepo apps. The Badge component is a simple, versatile element often used to display small bits of information, such as notifications, statuses, or labels. @@ -587,27 +587,24 @@ cd apps/mobile 3. Add the Badge component to the UI -Now, decide where you'd like to display the Badge. For this example, let’s place in the login screen, below the heading and above the form fields to indicate the number of login attempts if they exceed a certain number. +Now, let's use the Badge component. For this example, let’s place it in the login screen, below the heading and above the form fields to indicate the number of login attempts if they exceed a certain number. `apps/mobile/apps/screens/LoginScreen.tsx` ```tsx -import type { ThemedStyle } from "app/theme" -import { useAppTheme } from "app/utils/useAppTheme" +import { AppStackScreenProps } from "../navigators" +import { colors, spacing } from "../theme" // success-line -import { Badge } from "@myworkspace/ui-components" +import { Badge } from "ui-components" ... - // success-line-start {attemptsCount > 0 && ( 2 ? "red" : "blue"} - style={themed($badge)} - textStyle={themed($badgeText)} /> )} // success-line-end @@ -646,7 +643,7 @@ yarn android ## Step 9: Add Yarn global scripts (optional) -Yarn's workspaces feature allows you to define and run scripts globally across all packages in your monorepo. This simplifies your workflow by enabling you to execute tasks like testing, building, or linting from the root of your project, ensuring consistency across all packages. In this section, we’ll explore how to set up and use global scripts with Yarn in your monorepo. +Yarn's workspaces feature allows you to define and run scripts globally across all packages in your monorepo. This simplifies your workflow by enabling you to execute tasks like testing, building, or linting from the root of your project, ensuring consistency across all packages. In this optional section, we’ll explore how to set up and use global scripts with Yarn in your monorepo. Let's add a global script for the mobile app to run iOS and Android projects. From 0f72fa832b0c01334b4e9b7507964335c7010e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Thu, 26 Sep 2024 07:31:49 -0700 Subject: [PATCH 08/17] Better segmentation for tool --- docs/MonoreposOverview.md | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/docs/MonoreposOverview.md b/docs/MonoreposOverview.md index d242d837..8511ae07 100644 --- a/docs/MonoreposOverview.md +++ b/docs/MonoreposOverview.md @@ -38,12 +38,41 @@ When embarking on a software development project, particularly in the context of ## Common monorepo tools -| Tool | Pro | Cons | +Existing monorepo tools can be divided in two types: +* Dependency managers +* Build systems + +Let's talk about each of them. + +### Dependency managers + +A dependency manager is a tool that automates the installation and management of a project's required libraries, ensuring compatibility and consistency. + +| Tool | Pros | Cons | +| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| [Yarn Workspaces](https://yarnpkg.com/features/workspaces) | Built-in support for monorepos.
Simplifies dependency management across packages.
Excellent community support and documentation. | Can be complex to configure initially.
Some issues with peer dependencies. | +| [Pnpm](https://pnpm.io/) | Efficient disk space usage with unique package storage.
Fast installation times.
Built-in support for monorepos. | Less mainstream adoption, leading to potential issues with community support.
Some tooling might not fully support Pnpm yet. | +| [Lerna](https://lerna.js.org/) | Great for managing multi-package repositories.
Supports independent versioning of packages.
Integrates well with Yarn Workspaces. | Stagnant for years, although [maintained by Nx now](https://www.google.com/url?q=https://blog.nrwl.io/lerna-5-1-new-website-new-guides-new-lerna-example-repo-distributed-caching-support-and-speed-64d66410bec7&sa=D&source=docs&ust=1727362999686773&usg=AOvVaw2QrLSkc_AY7zOgk7Sz_YQM).
Slower for large codebases.
Requires additional configuration for CI/CD. | + +:::info + +Based on our experience, simplicity and community support, **we recommend Yarn as a dependency manager**. + +::: + + +### Build systems + +A build system automates tasks like compiling code, running tests, and bundling assets, optimizing the development process. + +| Tool | Pros | Cons | | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -| Yarn Workspaces [Recommended] | Built-in support for monorepos.
Simplifies dependency management across packages.
Excellent community support and documentation. | Can be complex to configure initially.
Some issues with peer dependencies. | -| Nx | Focuses on improving performance with advanced caching and task scheduling.
Great for large-scale enterprise applications. | Steeper learning curve.
May be overkill for smaller projects. | -| Turborepo | High performance with built-in caching and parallel task execution.
Simplifies monorepo management with minimal configuration. | Less mature ecosystem compared to Yarn or Lerna.
Limited tooling support for some workflows. | -| Pnpm | Efficient disk space usage with unique package storage.
Fast installation times.
Built-in support for monorepos. | Less mainstream adoption, leading to potential issues with community support.
Some tooling might not fully support Pnpm yet. | +| [Nx](https://nx.dev/) | Focuses on improving performance with advanced caching and task scheduling.
Great for large-scale enterprise applications. | Steeper learning curve.
May be overkill for smaller projects. | +| [Turborepo](https://turbo.build/repo/docs/guides/tools) | High performance with built-in caching and parallel task execution.
Simplifies monorepo management with minimal configuration. | Less mature ecosystem compared to Yarn or Lerna.
Limited tooling support for some workflows. | + +--- + + ## Common monorepo setups for software apps From ac4a86c141812508b14b5baf2caedfb898f4dfac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Thu, 26 Sep 2024 07:43:38 -0700 Subject: [PATCH 09/17] Add info text for public publishing and changesets --- docs/MonoreposOverview.md | 4 ---- docs/recipes/SettingsUpYarnMonorepo.md | 6 ++++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/MonoreposOverview.md b/docs/MonoreposOverview.md index 8511ae07..2153cbb4 100644 --- a/docs/MonoreposOverview.md +++ b/docs/MonoreposOverview.md @@ -70,10 +70,6 @@ A build system automates tasks like compiling code, running tests, and bundling | [Nx](https://nx.dev/) | Focuses on improving performance with advanced caching and task scheduling.
Great for large-scale enterprise applications. | Steeper learning curve.
May be overkill for smaller projects. | | [Turborepo](https://turbo.build/repo/docs/guides/tools) | High performance with built-in caching and parallel task execution.
Simplifies monorepo management with minimal configuration. | Less mature ecosystem compared to Yarn or Lerna.
Limited tooling support for some workflows. | ---- - - - ## Common monorepo setups for software apps ### Frontend and backend in a single monorepo diff --git a/docs/recipes/SettingsUpYarnMonorepo.md b/docs/recipes/SettingsUpYarnMonorepo.md index bf8b576e..93820fd6 100644 --- a/docs/recipes/SettingsUpYarnMonorepo.md +++ b/docs/recipes/SettingsUpYarnMonorepo.md @@ -342,6 +342,12 @@ cd apps/mobile "eslint-config-prettier": "8.5.0", ``` +:::info + +Although this guide focuses on private monorepos, it's important to address external publishing scenarios. For monorepos with some packages intended for public release, avoid using `workspace:^`. Instead, specify the exact version of each package to ensure proper consumption. To manage versioning and publishing of multiple packages within a monorepo, we recommend using the [changesets](https://github.com/changesets/changesets) tool. + +::: + 3. Replace the shared ESLint configuration in `package.json`: `apps/mobile/package.json` From f716f37db9e52b584af0cbaac2d3922b1ea71d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Thu, 26 Sep 2024 07:49:18 -0700 Subject: [PATCH 10/17] Remove case for two entry points --- docs/MonoreposOverview.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/docs/MonoreposOverview.md b/docs/MonoreposOverview.md index 2153cbb4..75c50e0d 100644 --- a/docs/MonoreposOverview.md +++ b/docs/MonoreposOverview.md @@ -82,16 +82,6 @@ Structure: Use case: Ideal for projects where the frontend and backend are tightly coupled and frequently share code, such as shared type definitions, utility functions, or API clients. -### Multiple mobile apps in a single monorepo - -Structure: - -- `/app-ios`: Contains the iOS-specific code. -- `/app-android`: Contains the Android-specific code. -- `/shared`: Contains shared React Native components, utilities, and business logic. - -Use case: Best for projects with multiple mobile apps that need to share a significant amount of code, ensuring consistency across different platforms. - ### Monorepo with multiple microservices Structure: From 5ce3f5888bdbe9eb8ae6dc47dc52c876cbfdbd09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Thu, 26 Sep 2024 19:42:36 -0700 Subject: [PATCH 11/17] Add case that's detailed in guide --- docs/MonoreposOverview.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/MonoreposOverview.md b/docs/MonoreposOverview.md index 75c50e0d..9e8cd618 100644 --- a/docs/MonoreposOverview.md +++ b/docs/MonoreposOverview.md @@ -72,6 +72,13 @@ A build system automates tasks like compiling code, running tests, and bundling ## Common monorepo setups for software apps +### Frontend apps and packages + +- `/apps`: Contains a set of frontend apps (e.g. React, Electron, React Native). +- `/packages`: Contains shared packages used by frontend apps. + +Use case: Ideal for projects that need to manage multiple frontend apps sharing a common set of utilities and packages. + ### Frontend and backend in a single monorepo Structure: From b364adaa091c9480faefdda5ca85728206440b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Fri, 27 Sep 2024 07:18:00 -0700 Subject: [PATCH 12/17] Remove plug and play as it is not recommneded by Yarn Stated here: https://yarnpkg.com/features/pnp --- docs/recipes/SettingsUpYarnMonorepo.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/recipes/SettingsUpYarnMonorepo.md b/docs/recipes/SettingsUpYarnMonorepo.md index 93820fd6..9e0d77ea 100644 --- a/docs/recipes/SettingsUpYarnMonorepo.md +++ b/docs/recipes/SettingsUpYarnMonorepo.md @@ -173,12 +173,6 @@ cd .. yarn install ``` -:::info - -When you run yarn at the top of the monorepo with Yarn 3.x, Yarn installs all dependencies and links the packages. It places a single `node_modules` folder in each package’s directory, but shared dependencies are typically stored in a `.yarn/cache` folder at the root. Yarn uses Plug’n’Play (PnP) to resolve dependencies without the traditional `node_modules` structure, creating a more efficient setup. Each package or app is linked to the dependencies it needs through Yarn’s PnP system. For more details, you can check out [Yarn's documentation on Plug'n'Play](https://yarnpkg.com/features/pnp). - -::: - ## Step 4: Add a shared ESLint configuration with TypeScript In a monorepo setup, maintaining consistent code quality across TypeScript projects is essential. Sharing a single ESLint configuration file between these apps ensures consistent coding standards and streamlines the development process. From 4a87b178fde531e856cdfbbf19ec9cae97ab9f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Fri, 27 Sep 2024 10:17:32 -0700 Subject: [PATCH 13/17] Improving and cleaning up content --- docs/recipes/SettingsUpYarnMonorepo.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/recipes/SettingsUpYarnMonorepo.md b/docs/recipes/SettingsUpYarnMonorepo.md index 9e0d77ea..f947da1f 100644 --- a/docs/recipes/SettingsUpYarnMonorepo.md +++ b/docs/recipes/SettingsUpYarnMonorepo.md @@ -12,27 +12,27 @@ publish_date: 2024-08-22 # Setting up a Yarn monorepo with Ignite -In this guide, we'll lead you through the process of setting up a Yarn monorepo for your [React Native](https://reactnative.dev/) projects using the [Ignite](https://github.com/infinitered/ignite) framework. We'll start by setting up the monorepo structure, then create a React Native app using Ignite, add a shared form-validator utility, add a shared UI package and finally integrate these utilitoes into the mobile app. +In this guide, we'll lead you through the process of setting up a Yarn monorepo for your [React Native](https://reactnative.dev/) projects using the [Ignite](https://github.com/infinitered/ignite) framework. We'll start by setting up the monorepo structure, then create a React Native app using the Ignite CLI, to end up creating two shared utilities (form-validator utility and UI library) that will be integrated into the app. ## Prerequisites -Before you start, ensure you have the following installed on your machine: +Before you start, we want to ensure you have the following tools installed on your machine: - [Node.js](https://nodejs.org/en) (version 18 or later) - [Yarn](https://yarnpkg.com) (version 3.8 or later) ## Use case -In a monorepo setup, multiple applications, such as a mobile app (using React Native) and a web app (using React), can share common functionalities. This guide will walk you through the process of setting up and utilizing shared utilities within a monorepo. For instance, if you have several apps that need to share an ESLint configuration or UI components, you can create reusable packages that can be integrated across all your applications. +In a monorepo setup, multiple applications, such as a mobile app (using React Native) and a web app (using React), can share common functionalities. This guide will walk you through the process of setting up and utilizing shared utilities within a monorepo. For instance, if you have several apps that need to share an ESLint configuration or UI components, you can create reusable packages that can be integrated across all your apps. :::info -More information on whether you want to setup your app within a monorepo can be found [here](/docs/MonoreposOverview.md). +More information on monorepo tools and whether you want to setup your apps within a monorepo, can be found [here](/docs/MonoreposOverview.md). ::: -By centralizing these utilities, you reduce code duplication and simplify maintenance, ensuring that any updates or bug fixes are immediately available to all your apps. +By centralizing these utilities, you can reduce code duplication and simplify maintenance, ensuring that any updates or bug fixes are immediately available to all your apps. In this setup, we’ll create a React Native app along with two shared packages: one for holding a common ESLint configuration and another for shared UI components. Finally, we’ll integrate these packages into the mobile app. @@ -40,8 +40,6 @@ In this setup, we’ll create a React Native app along with two shared packages: First, follow the [Expo documentation on setting up monorepos](https://docs.expo.dev/guides/monorepos/) to initialize your own monorepo. This will include setting up your `packages/` and `apps/` directories and configuring Yarn workspaces. -Here's a quick recap: - 1. Initialize the monorepo: ```shell From d5a3fa5298f6dc3f96a9a4e631b73b2874d45ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Fri, 27 Sep 2024 10:49:11 -0700 Subject: [PATCH 14/17] More revision and clean up --- docs/recipes/SettingsUpYarnMonorepo.md | 36 ++++++++++++++------------ 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/docs/recipes/SettingsUpYarnMonorepo.md b/docs/recipes/SettingsUpYarnMonorepo.md index f947da1f..742e51de 100644 --- a/docs/recipes/SettingsUpYarnMonorepo.md +++ b/docs/recipes/SettingsUpYarnMonorepo.md @@ -82,7 +82,7 @@ mkdir apps packages ## Step 2: Create mobile app using Ignite -Ignite is a powerful tool for scaffolding React Native projects. In this step, we'll create your first app within the monorepo using Ignite. +[Ignite](https://github.com/infinitered/ignite) is a battle-tested React Native boilerplate that Infinite Red uses every time we start a new project. In this step, we'll create a React Native app within the monorepo using Ignite's CLI. 1. Install the [Ignite CLI](https://www.npmjs.com/package/ignite-cli) (if you haven't already): @@ -115,7 +115,7 @@ We suggest the following answers to the prompts: touch mobile/metro.config.js ``` -4. Replace the following lines in the Metro configuration file with the lines below: +4. Replace the following lines in the Metro configuration file with the lines below (this is taken from the [Expo guide](https://docs.expo.dev/guides/monorepos/)): ```js // Learn more https://docs.expo.io/guides/customizing-metro @@ -173,7 +173,7 @@ yarn install ## Step 4: Add a shared ESLint configuration with TypeScript -In a monorepo setup, maintaining consistent code quality across TypeScript projects is essential. Sharing a single ESLint configuration file between these apps ensures consistent coding standards and streamlines the development process. +In our experience, maintaining consistent code quality across TypeScript projects within a monorepo is essential. Sharing a single ESLint configuration file between these apps ensures consistent coding standards and streamlines the development process. Let's go ahead and create an utility for that. 1. Create a shared ESLint configuration package: @@ -194,7 +194,7 @@ yarn init -y 3. Install ESLint and TypeScript dependencies: -Install ESLint, TypeScript, and any shared plugins or configurations that you want to use across the apps. +Install ESLint, TypeScript, and any shared plugins or configurations that you want to use across the apps. We recommend the follow: ```shell yarn add eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react eslint-plugin-react-native eslint-plugin-reactotron eslint-config-standard eslint-config-prettier --dev @@ -222,7 +222,7 @@ yarn add eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslin 5. Create the shared ESLint configuration file: -Create an `index.ts` file in the root of your eslint-config package. We will reuse Ignite’s boilerplate ESLint configuration and then replace the original configuration with it. +Create an `index.ts` file in the root of your `eslint-config` package. We will reuse Ignite’s boilerplate ESLint configuration and then replace the original configuration with it. `packages/eslint-config/index.ts` @@ -303,7 +303,7 @@ module.exports = { // success-line-end ``` -This configuration (originally sourced from [Ignite](https://github.com/infinitered/ignite)) provides a strong foundation for TypeScript, React, React Native, and import order rules. You can adjust the rules according to your project's specific needs. +This configuration (originally sourced from [Ignite](https://github.com/infinitered/ignite)) provides a strong foundation for TypeScript, React and React Native projects. You can also adjust the rules according to your project's specific needs. 5. Compile the TypeScript configuration: @@ -313,7 +313,7 @@ npx tsc This will generate a `index.js` file from your `index.ts` file. -## Step 6: Use the shared ESLint configuration in your apps +## Step 6: Use the shared ESLint configuration in the mobile app 1. Navigate to the mobile app: @@ -427,9 +427,11 @@ Although this guide focuses on private monorepos, it's important to address exte // success-line-end ``` -## Step 6: Create the shared UI components package +In this guide, we use `@monorepo-example` as the placeholder name for the monorepo. Be sure to replace it with your actual monorepo name if it’s different. -Let's create a Badge component as a shared UI component that can be used across the monorepo apps. The Badge component is a simple, versatile element often used to display small bits of information, such as notifications, statuses, or labels. +## Step 7: Create the shared UI components package + +Let's create a Badge component as a shared UI component that can be used within the mobile app. For context, a Badge component is a simple and versatile element often used to display small bits of information, such as notifications, statuses, or labels. 1. Navigate to the packages folder: @@ -536,7 +538,7 @@ const styles = StyleSheet.create({ // success-line-end ``` -The Badge component is a simple UI element that can display a label with customizable colors, making it versatile for use in different parts of your application, such as notification counts, statuses, or category labels. +The way it's been defined above, a Badge component should be a simple UI element that can display a label with customizable colors, making it versatile for use in different parts of your application, such as notification counts, statuses, or category labels. 7. Export the badge component: @@ -558,9 +560,9 @@ Compile your TypeScript code to ensure it's ready for consumption by other packa npx tsc ``` -## Step 7: Use the shared UI package in the mobile app +## Step 8: Use the shared UI package in the mobile app -1. Navigate to the mobile app: +1. Navigate now to the mobile app: ```shell cd .. @@ -585,7 +587,7 @@ cd apps/mobile 3. Add the Badge component to the UI -Now, let's use the Badge component. For this example, let’s place it in the login screen, below the heading and above the form fields to indicate the number of login attempts if they exceed a certain number. +Let's now use the Badge component within the app. For this example, let's place it in the login screen, below the heading and above the form fields to indicate the number of login attempts if they exceed a certain number. `apps/mobile/apps/screens/LoginScreen.tsx` @@ -608,7 +610,7 @@ import { Badge } from "ui-components" // success-line-end ``` -## Step 8: Run mobile app to make sure logic was added +## Step 9: Run mobile app to make sure logic was added 1. Navigate to the root of the project: @@ -623,7 +625,7 @@ cd .. yarn ``` -3. Run React Native app (make sure you have your [environment setup](https://reactnative.dev/docs/set-up-your-environment)): +3. Run the React Native app (make sure you have your [environment setup](https://reactnative.dev/docs/set-up-your-environment)): For iOS: @@ -639,7 +641,9 @@ cd apps/mobile yarn android ``` -## Step 9: Add Yarn global scripts (optional) +You should be able to view the login screen with an instance of a badge element added between the heading and the form fields. + +## Step 10: Add Yarn global scripts (optional) Yarn's workspaces feature allows you to define and run scripts globally across all packages in your monorepo. This simplifies your workflow by enabling you to execute tasks like testing, building, or linting from the root of your project, ensuring consistency across all packages. In this optional section, we’ll explore how to set up and use global scripts with Yarn in your monorepo. From 58a6a4afd5f7191d0f2fc314196c0f51fb609520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Fri, 27 Sep 2024 10:55:52 -0700 Subject: [PATCH 15/17] Add resources at the end --- docs/recipes/SettingsUpYarnMonorepo.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/recipes/SettingsUpYarnMonorepo.md b/docs/recipes/SettingsUpYarnMonorepo.md index 742e51de..4d0f7c09 100644 --- a/docs/recipes/SettingsUpYarnMonorepo.md +++ b/docs/recipes/SettingsUpYarnMonorepo.md @@ -679,4 +679,8 @@ For more information on Yarn's global scripts, check [this site](https://yarnpkg ## Conclusion -Congratulations on setting up your Yarn monorepo! By using the Ignite framework, and two shared packages, you've successfully integrated these together. This setup enables you to scale your projects efficiently by sharing code across multiple applications in a well-structured and organized manner. \ No newline at end of file +Congratulations on setting up your Yarn monorepo! By using the [Ignite](https://github.com/infinitered/ignite) framework, and two shared packages, you've successfully integrated these together. This setup enables you to scale your projects efficiently by sharing code across multiple applications in a well-structured and organized manner. + +For more information, you can check the following resources: +* [Choosing the right monorepo strategy for your project](/docs/MonoreposOverview.md) +* [Expo: Work with monorepos](https://docs.expo.dev/guides/monorepos/) \ No newline at end of file From d9fd7cfe095e339d6911691b20f6ee0e65047afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Fri, 27 Sep 2024 14:35:27 -0700 Subject: [PATCH 16/17] Add local global script instead --- docs/recipes/SettingsUpYarnMonorepo.md | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/docs/recipes/SettingsUpYarnMonorepo.md b/docs/recipes/SettingsUpYarnMonorepo.md index 4d0f7c09..1adae773 100644 --- a/docs/recipes/SettingsUpYarnMonorepo.md +++ b/docs/recipes/SettingsUpYarnMonorepo.md @@ -649,31 +649,26 @@ Yarn's workspaces feature allows you to define and run scripts globally across a Let's add a global script for the mobile app to run iOS and Android projects. -1. Navigate to the root of the project: - -```shell -cd .. -cd .. -``` -2. Add a global script to the root `package.json` file: +1. Add a global script to the mobile app `package.json` file: -`package.json` +`apps/mobile/package.json` ```json - "version": "1.0.0", - // success-line-start "scripts": { + ... + "serve:web": "npx server dist", + // error-line + "prebuild:clean": "npx expo prebuild --clean" + // success-line-start + "prebuild:clean": "npx expo prebuild --clean", "mobile:ios" : "yarn workspace mobile ios", "mobile:android" : "yarn workspace mobile android" + // success-line-end }, - // success-line-end - "workspaces": [ - "apps/*", - "utilities/*" - ] ``` +Even though this script is locally defined within the app's `package.json` file, it will available everywhere within the monorepo by running `yarn mobile:ios` or `yarn mobile:android`. For more information on Yarn's global scripts, check [this site](https://yarnpkg.com/features/workspaces#global-scripts). From 711a9418fc2579d87977908d3c0afbf38d490315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Pe=C3=B1a?= Date: Tue, 1 Oct 2024 10:00:45 -0700 Subject: [PATCH 17/17] Update docs/recipes/SettingsUpYarnMonorepo.md Co-authored-by: Joshua Yoes <37849890+joshuayoes@users.noreply.github.com> --- docs/recipes/SettingsUpYarnMonorepo.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/recipes/SettingsUpYarnMonorepo.md b/docs/recipes/SettingsUpYarnMonorepo.md index 1adae773..2c95dca0 100644 --- a/docs/recipes/SettingsUpYarnMonorepo.md +++ b/docs/recipes/SettingsUpYarnMonorepo.md @@ -529,11 +529,11 @@ const styles = StyleSheet.create({ paddingVertical: 4, borderRadius: 12, alignSelf: "flex-start", - } as ViewStyle, + } satisfies ViewStyle, text: { fontSize: 12, fontWeight: "bold", - } as TextStyle, + } satisfies TextStyle, }) // success-line-end ```