diff --git a/docs/map.json b/docs/map.json index 3396d253ac..3971807dd2 100644 --- a/docs/map.json +++ b/docs/map.json @@ -15,9 +15,14 @@ "file": "shared/getting-started/intro" }, { - "name": "Core Tutorial", - "id": "core-tutorial", - "file": "shared/core-tutorial/01-create-blog" + "name": "Package-Based Repo Tutorial", + "id": "package-based-repo-tutorial", + "file": "shared/npm-tutorial/package-based" + }, + { + "name": "Integrated Repo Tutorial", + "id": "integrated-repo-tutorial", + "file": "shared/npm-tutorial/integrated" }, { "name": "React Tutorial", diff --git a/docs/shared/angular-tutorial/01-create-application.md b/docs/shared/angular-tutorial/01-create-application.md index b15da4b81e..4f2e4a73b2 100644 --- a/docs/shared/angular-tutorial/01-create-application.md +++ b/docs/shared/angular-tutorial/01-create-application.md @@ -8,7 +8,7 @@ width="100%" /%} In this tutorial you use Nx to build a full-stack application out of common libraries using modern technologies like Cypress and Nest. {% callout type="check" title="Integrated Repo" %} -This tutorial sets up an [integrated repo](/concepts/integrated-vs-package-based). If you prefer a [package-based repo](/concepts/integrated-vs-package-based), check out the [Core Tutorial](/getting-started/core-tutorial). +This tutorial sets up an [integrated repo](/concepts/integrated-vs-package-based). If you prefer a [package-based repo](/concepts/integrated-vs-package-based), check out the [Package-Based Repo Tutorial](/getting-started/package-based-repo-tutorial). {% /callout %} ## Contents diff --git a/docs/shared/concepts/more-concepts.md b/docs/shared/concepts/more-concepts.md index 6cc913b38f..1021ba0a8c 100644 --- a/docs/shared/concepts/more-concepts.md +++ b/docs/shared/concepts/more-concepts.md @@ -2,6 +2,7 @@ - [Incremental Builds](/more-concepts/incremental-builds) - [Nx and Turborepo](/more-concepts/turbo-and-nx) +- [Nx and the Angular CLI](/more-concepts/nx-and-angular) - [Monorepos](/more-concepts/why-monorepos) - [Using Nx at Enterprises](/more-concepts/monorepo-nx-enterprise) - [Nx Daemon](/more-concepts/nx-daemon) diff --git a/docs/shared/getting-started/intro.md b/docs/shared/getting-started/intro.md index 04c8c40765..74325a918a 100644 --- a/docs/shared/getting-started/intro.md +++ b/docs/shared/getting-started/intro.md @@ -2,28 +2,57 @@ Nx is a smart, fast and extensible build system with first class monorepo support and powerful integrations. -## Philosophy +{% personas %} +{% persona type="javascript" title="New Package-Based Repo" url="/getting-started/package-based-repo-tutorial" %} +Create a monorepo with Yarn, NPM or PNPM. Nx makes it fast, but lets you run things your way. -Nx has a similar design philosophy to Visual Studio Code. VSCode is a powerful text editor, and you can be very productive -with it even if you don't install any extensions. The ecosystem of VSCode's extensions though is what can really level -up your productivity. +- [Get started with your package-based repo](/getting-started/package-based-repo-tutorial) -Nx is similar. The core of Nx is generic, simple, and unobtrusive. Nx plugins, although very useful for many projects, -are completely optional. +{% /persona %} -Most examples on this site use Nx plugins (integrated repo style). It's just easier to demonstrate many features Nx offers when Nx generates all -the boilerplate. However, the vast majority of the features will work the same way in a workspace with no plugins (package-based repo). +{% persona type="integrated" title="New Integrated Repo" url="/getting-started/integrated-repo-tutorial" %} -Here's a deep dive on [Integrated Repos vs. Package-Based Repos](/concepts/integrated-vs-package-based) +Get a pre-configured setup. Nx configures your favorite frameworks and lets you focus on shipping features. -## Getting Started +- [Get started with your integrated repo](/getting-started/integrated-repo-tutorial) -- [Nx core tutorial](/core-tutorial/01-create-blog) will help you understand the core of Nx. -- [Adding Nx to an existing monorepo](/recipes/adopting-nx/adding-to-monorepo) shows several paths to adopting Nx in your organization. -- [Mental model](/concepts/mental-model) is a good starting point for those who like to understand things theoretically first. +{% /persona %} -If you want to use Nx plugins to really level up your productivity, pick one of the following tutorials: +{% persona type="lerna" title="Add to an Existing Monorepo" url="/recipe/adding-to-monorepo" %} -- [Nx and Node](/node-tutorial/01-create-application) -- [Nx and React](/react-tutorial/01-create-application) -- [Nx and Angular](/angular-tutorial/01-create-application) +Incrementally add Nx to your repo and enjoy faster CI runs and local development. All without modifying your existing setup. + +- [Add Nx to an Existing Monorepo](/recipe/adding-to-monorepo) + +{% /persona %} + +{% persona type="angular" title="Enter Modern Angular" url="/recipe/migration-angular" %} +Enhance your Angular development experience by leveraging its advanced generators and integrations with modern tooling. + +- [Switch from the Angular CLI to Nx](/recipe/migration-angular) + +{% /persona %} +{% /personas %} + +If you know other tools in the monorepo space, here is how Nx compares: + +- [Monorepo.tools](https://monorepo.tools) +- [Nx and Turborepo](/more-concepts/turbo-and-nx) + +## Nx Has Two Goals + +**Speed up your existing workflow with minimum effort.** + +- Never rebuild the same code twice by [caching task results](/core-features/cache-task-results). +- Only [run tasks affected by the current PR](/core-features/run-tasks#run-tasks-affected-by-a-pr). +- [Distribute your task execution](/core-features/distribute-task-execution) across multiple agents in CI. + +These features can be enabled without touching your existing workflows if you use Nx with a [package-based repo](/concepts/integrated-vs-package-based). + +**Provide a first-rate developer experience no matter the size of the repo:** + +- Encode common coding tasks in [code generators](/plugin-features/use-code-generators) to make them easily repeatable. +- Offload the maintenance burden of [updating dependencies and configuration files](/core-features/automate-updating-dependencies) to the Nrwl team. +- [Enforce project boundaries](/core-features/enforce-project-boundaries) based on your own organization structure. + +These features and the [integrated repository](/concepts/integrated-vs-package-based) mindset allow large teams to collaborate in a single monorepo without getting in each other's way. diff --git a/docs/shared/migration/adding-to-monorepo.md b/docs/shared/migration/adding-to-monorepo.md index 66b9d5312a..22b8cad6b6 100644 --- a/docs/shared/migration/adding-to-monorepo.md +++ b/docs/shared/migration/adding-to-monorepo.md @@ -81,7 +81,7 @@ third_party # nx will ignore everything in the third-party dir ### Enabling JS Analysis -After running `add-nx-to-monorepo` Nx will only analyze `package.json` files like Lerna or Turborepo. +After running `add-nx-to-monorepo` Nx will only analyze `package.json` files in the same way Lerna or Turborepo do. ```json { diff --git a/docs/shared/migration/lerna-and-nx.md b/docs/shared/migration/lerna-and-nx.md index 0948531516..b99aa81288 100644 --- a/docs/shared/migration/lerna-and-nx.md +++ b/docs/shared/migration/lerna-and-nx.md @@ -18,7 +18,7 @@ For a discussion on #2, see [dependency management](#dependency-management) belo ## Speed up Lerna with Nx's powerful task scheduler -Nx comes with a powerful task scheduler that intelligenty runs operations and makes sure they are quick. This happens in a variety of ways: +Nx comes with a powerful task scheduler that intelligently runs operations and makes sure they are quick. This happens in a variety of ways: - **Parallelization and task dependencies -** Nx automatically [knows how your projects relate to each other](/more-concepts/how-project-graph-is-built). As a result, if `project-a` depends on `project-b` and you run the build command for `project-a`, Nx first runs the builds for all of `project-a`'s dependencies and then the invoked project itself. Nx sorts these tasks to maximize parallelism. - **Only run what changed -** Using [Nx affected commands](/concepts/affected) you only really execute tasks on the projects that changed, compared to a given baseline (usually the main branch). diff --git a/docs/shared/node-tutorial/01-create-application.md b/docs/shared/node-tutorial/01-create-application.md index 715a3bb2c4..99d9f4e2b5 100644 --- a/docs/shared/node-tutorial/01-create-application.md +++ b/docs/shared/node-tutorial/01-create-application.md @@ -8,7 +8,7 @@ width="100%" /%} In this tutorial you use Nx to build a server application out of common libraries using modern technologies. {% callout type="check" title="Integrated Repo" %} -This tutorial sets up an [integrated repo](/concepts/integrated-vs-package-based). If you prefer a [package-based repo](/concepts/integrated-vs-package-based), check out the [Core Tutorial](/getting-started/core-tutorial). +This tutorial sets up an [integrated repo](/concepts/integrated-vs-package-based). If you prefer a [package-based repo](/concepts/integrated-vs-package-based), check out the [Package-Based Repo Tutorial](/getting-started/package-based-repo-tutorial). {% /callout %} ## Contents diff --git a/docs/shared/npm-tutorial/integrated.md b/docs/shared/npm-tutorial/integrated.md new file mode 100644 index 0000000000..84af431a8c --- /dev/null +++ b/docs/shared/npm-tutorial/integrated.md @@ -0,0 +1,219 @@ +# Getting Started with Integrated Repos + +## Create a New Workspace + +Start by creating a new workspace. We can use the following command that will help us set it up. + +```bash +npx create-nx-workspace@latest myorg --preset=ts +``` + +The file structure should look like this: + +```treeview +myorg/ +├── packages/ +├── tools/ +├── nx.json +├── package.json +├── README.md +└── tsconfig.base.json +``` + +## Create a Package + +Nx comes with generators that can help with scaffolding applications. Run this generator to make a new library named `is-even`: + +```bash +npx nx generate @nrwl/js:library is-even --publishable --importPath @myorg/is-even +``` + +This command: + +- Uses the `@nrwl/js` plugin's `library` generator to scaffold a new library named `is-even`. +- The `--publishable` flag makes sure we also get a `package.json` generated and a `publish` target we can invoke to publish to NPM. +- The `--importPath` allows us to define the name of the NPM package. + +You should now have the following structure: + +```treeview +packages/ +└── is-even/ + ├── src/ + | └── lib/ + | | ├── is-even.spec.ts + | | ├── is-even.ts + | └── index.ts + ├── project.json + ├── package.json + ├── ... + └── tsconfig.json +``` + +Update `is-even.ts` with this content: + +```ts {% fileName="packages/is-even/src/lib/is-even.ts" %} +export function isEven(x: number): boolean { + return x % 2 === 0; +} +``` + +The Nx plugins use a project-level `project.json` to manage the metadata around the available targets that can be run for a given project. The generated `project.json` for `is-even` contains `build`, `publish`, `lint` and `test` targets: + +```jsonc {% fileName="packages/is-even/project.json" %} +{ + "name": "is-even", + "targets": { + "build": { + /* ... */ + }, + "publish": { + /* ... */ + }, + "lint": { + /* ... */ + }, + "test": { + /* ... */ + } + } +} +``` + +You can dive into the various settings to fine-tune the options used for building, publishing, linting or testing the package. The low-level details are being taken care of by the plugin. + +Running + +- `npx nx build is-even` builds the src files and places a ready-to-be-published package in `dist/packages/is-even` at the root of your workspace +- `npx nx publish is-even` runs a publish script from `dist/packages/is-even` to push your package to NPM +- `npx nx test is-even` runs the pre-configured Jest tests for the package +- `npx nx lint is-even` runs the pre-configured ESLint checks for the package + +## Local Linking of Packages + +The local linking of packages in an integrated monorepo style is handled by Nx automatically by leveraging TypeScript path mappings in the `tsconfig.base.json` file. + +To illustrate that, let's create another package `is-odd`. We can again run the generator for that: + +```bash +npx nx generate @nrwl/js:library is-odd --publishable --importPath @myorg/is-odd +``` + +Note how the `tsconfig.base.json` now has two entries: + +```json {% fileName="tsconfig.base.json" %} +{ + "compileOnSave": false, + "compilerOptions": { + ... + "paths": { + "@myorg/is-even": ["packages/is-even/src/index.ts"], + "@myorg/is-odd": ["packages/is-odd/src/index.ts"] + } + } +} +``` + +Update the `is-odd.ts` implemention in the `is-odd` package to import `isEven` from the `@myorg/is-even` package: + +```ts {% fileName="packages/is-odd/src/lib/is-odd.ts" %} +import { isEven } from '@myorg/is-even'; + +export function isOdd(x: number): boolean { + return !isEven(x); +} +``` + +This is all that needs to be done. + +## Task Dependencies + +In a monorepo there are not just dependencies among packages, but also among their tasks. + +For example, whenever we build `is-odd` we need to ensure that `is-even` is built beforehand. Nx can define such task dependencies by adding a `targetDefaults` property to nx.json. + +In an integrated monorepo style this is already being dealt with by the generators. The current `nx.json` file already comes with defaults that work out of the box: + +```json {% fileName="nx.json" %} +{ + ... + "targetDefaults": { + "build": { + "dependsOn": ["^build"], + ... + }, + ... + }, + ... +} +``` + +This tells Nx to run the `build` target of all the dependent projects first, before the `build` target of the package itself is being run. + +Remove any existing `dist` folder at the root of the workspace and run: + +```bash +npx nx build is-odd +``` + +It will automatically first run `npx nx build is-even`, so you should end up with both packages in your dist folder. Note that if `is-even` has been built before, it would just be restored out of the cache. + +## Cache Build Results + +To build the `is-even` package run: + +```bash +npx nx build is-even +``` + +Run the same command a second time and you'll see the build cache is being used: + +```bash +> nx build is-even + +> nx run is-even:build + +Compiling TypeScript files for project "is-even"... +Done compiling TypeScript files for project "is-even". + + ————————————————————————————————————————————————————————————————————— + + > NX Successfully ran target build for project is-even (713ms) +``` + +## Running Multiple Tasks + +To run the `build` target for all the packages in the workspace, use: + +```bash +npx nx run-many --target=build +``` + +What you would get is the following: + +```bash +> npx nx run-many --target=build + + ✔ nx run is-even:build [existing outputs match the cache, left as is] + ✔ nx run is-odd:build (906ms) + + ————————————————————————————————————————————————————————————————— + + > NX Successfully ran target build for 2 projects (914ms) + + Nx read the output from the cache instead of running the command for 1 out of 2 tasks. +``` + +Note how on the `is-even:build` it didn't run the build but rather pulled it out of the cache because the build has ran before. If you re-run the `run-many` command all of the builds would be cached. + +You can also only run tasks on packages that got changed by using + +```bash +npx nx affected --target=build +``` + +## Learn More + +- Read about the [core features](/core-features) and [plugin features](/plugin-features) of Nx +- Get a deeper understanding of the [mental model](/concepts/mental-model) behind Nx. +- [Adopt Nx](/recipes/adopting-nx) in your existing repo diff --git a/docs/shared/npm-tutorial/package-based.md b/docs/shared/npm-tutorial/package-based.md new file mode 100644 index 0000000000..e6061de9a1 --- /dev/null +++ b/docs/shared/npm-tutorial/package-based.md @@ -0,0 +1,216 @@ +# Getting Started with Package-Based Repos + +## Create a New Workspace + +Start by creating a new workspace. We can use the following command that will help us set it up. + +```bash +npx create-nx-workspace@latest package-based --preset=npm +``` + +The file structure should look like this: + +```treeview +myorg/ +├── packages/ +├── nx.json +└── package.json +``` + +## Create a Package + +The `packages` folder is where we host our monorepo libraries. Create a new `is-even` folder with the following structure: + +```treeview +packages/ +└── is-even/ + ├── index.ts + └── package.json +``` + +Before proceeding, make sure you install TypeScript as we're going to use it to build our package. While we could install TypeScript at the package-level, it is more convenient to have it globally for the entire monorepo. Run the following command at the root of your workspace. + +```bash +npm i typescript -D -W +``` + +Now update the content of the files to match the following: + +{% tabs %} +{% tab label="index.ts" %} + +```ts {% fileName="packages/is-even/index.ts" %} +export const isEven = (x: number) => x % 2 === 0; +``` + +{% /tab %} +{% tab label="package.json" %} + +```json {% fileName="packages/is-even/package.json" %} +{ + "name": "@package-based/is-even", + "version": "0.0.0", + "main": "dist/index.js", + "devDependencies": {}, + "scripts": { + "build": "tsc index.ts --outDir dist" + } +} +``` + +{% /tab %} +{% /tabs %} + +Update the `.gitignore` file to make sure you have a `dist` entry (without a leading slash) to ignore the `dist` folder inside the `is-even` package. + +Note, the `build` uses TypeScript to compile the `index.ts` file into a project-level `./dist` folder. To run it use: + +```bash +npx nx build is-even +``` + +## Local Linking of Packages + +Linking packages locally in a package-based monorepo style is done with NPM/Yarn/PNPM workspaces. In this specific setup we use NPM workspaces (see `package.json` at the root of this monorepo). + +To illustrate how packages can be linked locally, let's create another package `is-odd`. You can copy the existing `is-even` package: + +```treeview +packages/ +└── is-even/ + ├── ... +└── is-odd/ + ├── index.ts + └── package.json +``` + +Here's what the content of the files should look like: + +{% tabs %} +{% tab label="index.ts" %} + +```ts {% fileName="packages/is-odd/index.ts" %} +import { isEven } from '@package-based/is-even'; + +export const isOdd = (x: number) => !isEven(x); +``` + +{% /tab %} +{% tab label="package.json" %} + +```json {% fileName="packages/is-odd/package.json" %} +{ + "name": "@package-based/is-odd", + "version": "0.0.0", + "main": "dist/index.js", + "devDependencies": {}, + "scripts": { + "build": "tsc index.ts --outDir dist" + }, + "dependencies": { + "@package-based/is-even": "*" + } +} +``` + +{% /tab %} +{% /tabs %} + +`is-odd` imports the `isEven` function from `@package-based/is-even`. Therefore its `package.json` file should list the `is-even` package in its `package.json` file as a dependency. + +The `workspaces` property in the root-level `package.json` tells NPM (and it similar for Yarn or PNPM workspaces) to locally-link the two packages, without the need to publish them first to a NPM registry. + +At the root of your workspace run + +```bash +npm install +``` + +This allows the NPM workspace to properly link the new `is-odd` package. + +## Task Dependencies + +Most monorepos have dependencies not only among different packages, but also among their tasks. + +For example, whenever we build `is-odd` we need to ensure that `is-even` is built beforehand. Nx can define such task dependencies by adding a `targetDefaults` property to `nx.json`. + +```json {% fileName="nx.json" %} +{ + ... + "targetDefaults": { + "build": { + "dependsOn": ["^build"] + } + } +} +``` + +This tells Nx to run the `build` target of all the dependent projects first, before the `build` target of the package itself is being run. + +Remove any existing `dist` folder and run: + +```bash +npx nx build is-odd +``` + +It will automatically first run `npx nx build is-even` and then the build for `is-odd`. Note that if `is-even` has been built before, it would just be restored out of the cache. + +## Cache Build Results + +To build the `is-even` package run: + +```bash +npx nx build is-even +``` + +Run the same command a second time and you'll see the build cache is being used: + +```bash +> nx build is-even + +> nx run is-even:build + +> @package-based/is-even@0.0.0 build +> tsc index.ts --outDir dist + + ————————————————————————————————————————————————————————————————— + + > NX Successfully ran target build for project is-even (1s) +``` + +## Running Multiple Tasks + +To run the `build` target for all the packages in the workspace, use: + +```bash +npx nx run-many --target=build +``` + +What you would get is the following: + +```bash +> npx nx run-many --target=build + + ✔ nx run is-even:build [existing outputs match the cache, left as is] + ✔ nx run is-odd:build (906ms) + + ————————————————————————————————————————————————————————————————— + + > NX Successfully ran target build for 2 projects (914ms) + + Nx read the output from the cache instead of running the command for 1 out of 2 tasks. +``` + +Note how on the `is-even:build` it didn't run the build but rather pulled it out of the cache because the build has ran before. If you re-run the `run-many` command all of the builds would be cached. + +You can also only run tasks on packages that got changed by using + +```bash +npx nx affected --target=build +``` + +## Learn More + +- Read about the [core features of Nx](/core-features) +- Get a deeper understanding of the [mental model](/concepts/mental-model) behind Nx. +- [Adopt Nx](/recipes/adopting-nx) in your existing repo diff --git a/docs/shared/react-tutorial/01-create-application.md b/docs/shared/react-tutorial/01-create-application.md index 2f6c18e3ec..cf4da17815 100644 --- a/docs/shared/react-tutorial/01-create-application.md +++ b/docs/shared/react-tutorial/01-create-application.md @@ -12,7 +12,7 @@ Nx has first-class Next.js support, if you are looking to use it for your projec {% /callout %} {% callout type="check" title="Integrated Repo" %} -This tutorial sets up an [integrated](/concepts/integrated-vs-package-based) repo. If you prefer a [package-based repo](/concepts/integrated-vs-package-based), check out the [Core Tutorial](/getting-started/core-tutorial). +This tutorial sets up an [integrated](/concepts/integrated-vs-package-based) repo. If you prefer a [package-based repo](/concepts/integrated-vs-package-based), check out the [Package-Based Repo Tutorial](/getting-started/package-based-repo-tutorial). {% /callout %} ## Contents diff --git a/nx-dev/ui-markdoc/src/index.ts b/nx-dev/ui-markdoc/src/index.ts index 7dbb68605e..109af1f73e 100644 --- a/nx-dev/ui-markdoc/src/index.ts +++ b/nx-dev/ui-markdoc/src/index.ts @@ -20,6 +20,8 @@ import { NxCloudSection } from './lib/tags/nx-cloud-section.component'; import { nxCloudSection } from './lib/tags/nx-cloud-section.schema'; import { InstallNxConsole } from './lib/tags/install-nx-console.component'; import { installNxConsole } from './lib/tags/install-nx-console.schema'; +import { Persona, Personas } from './lib/tags/personas.component'; +import { persona, personas } from './lib/tags/personas.schema'; import { SideBySide } from './lib/tags/side-by-side.component'; import { sideBySide } from './lib/tags/side-by-side.schema'; import { Tab, Tabs } from './lib/tags/tabs.component'; @@ -45,6 +47,8 @@ export const getMarkdocCustomConfig = ( iframe, 'install-nx-console': installNxConsole, 'nx-cloud-section': nxCloudSection, + persona, + personas, 'side-by-side': sideBySide, tab, tabs, @@ -62,6 +66,8 @@ export const getMarkdocCustomConfig = ( Iframe, InstallNxConsole, NxCloudSection, + Persona, + Personas, SideBySide, Tab, Tabs, diff --git a/nx-dev/ui-markdoc/src/lib/tags/personas.component.tsx b/nx-dev/ui-markdoc/src/lib/tags/personas.component.tsx new file mode 100644 index 0000000000..fe1a93bd42 --- /dev/null +++ b/nx-dev/ui-markdoc/src/lib/tags/personas.component.tsx @@ -0,0 +1,134 @@ +import Link from 'next/link'; +import { ReactNode } from 'react'; + +export function Personas({ children }: { children: ReactNode }): JSX.Element { + return ( +
{children}
+ ); +} + +type PersonaType = 'javascript' | 'lerna' | 'angular' | 'integrated'; +const typeMap: Record< + PersonaType, + { + image: JSX.Element; + } +> = { + javascript: { + image: ( + + {/*JAVASCRIPT*/} + + + ), + }, + integrated: { + image: ( +
+ + {/*NODEJS*/} + + + + React + + +
+ ), + }, + lerna: { + image: ( +
+ + {/*YARN*/} + + + + {/*LERNA*/} + + + + {/*PNPM*/} + + +
+ ), + }, + angular: { + image: ( + + {/*ANGULAR*/} + + + ), + }, +}; + +export function Persona({ + title, + type, + url, + children, +}: { + title: string; + type: PersonaType; + url: string; + children: ReactNode; +}): JSX.Element { + const ui = typeMap[type]; + + return ( +