diff --git a/docs/generated/manifests/menus.json b/docs/generated/manifests/menus.json index 59331a8ef38c06..39e1e01bd2fdb6 100644 --- a/docs/generated/manifests/menus.json +++ b/docs/generated/manifests/menus.json @@ -685,6 +685,14 @@ "id": "decisions", "isExternal": false, "children": [ + { + "name": "Overview", + "path": "/concepts/decisions/overview", + "id": "overview", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Monorepos", "path": "/concepts/decisions/why-monorepos", @@ -702,41 +710,33 @@ "disableCollapsible": false }, { - "name": "Code Sharing", - "path": "/concepts/decisions/code-sharing", - "id": "code-sharing", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "Applications and Libraries", - "path": "/concepts/decisions/applications-and-libraries", - "id": "applications-and-libraries", + "name": "Code Ownership", + "path": "/concepts/decisions/code-ownership", + "id": "code-ownership", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "When to Create a New Library", - "path": "/concepts/decisions/creating-libraries", - "id": "creating-libraries", + "name": "Project Size", + "path": "/concepts/decisions/project-size", + "id": "project-size", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Library Types", - "path": "/concepts/decisions/library-types", - "id": "library-types", + "name": "Project Dependency Rules", + "path": "/concepts/decisions/project-dependency-rules", + "id": "project-dependency-rules", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Grouping Libraries", - "path": "/concepts/decisions/grouping-libraries", - "id": "grouping-libraries", + "name": "Folder Structure", + "path": "/concepts/decisions/folder-structure", + "id": "folder-structure", "isExternal": false, "children": [], "disableCollapsible": false @@ -923,6 +923,14 @@ "id": "decisions", "isExternal": false, "children": [ + { + "name": "Overview", + "path": "/concepts/decisions/overview", + "id": "overview", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Monorepos", "path": "/concepts/decisions/why-monorepos", @@ -940,41 +948,33 @@ "disableCollapsible": false }, { - "name": "Code Sharing", - "path": "/concepts/decisions/code-sharing", - "id": "code-sharing", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "Applications and Libraries", - "path": "/concepts/decisions/applications-and-libraries", - "id": "applications-and-libraries", + "name": "Code Ownership", + "path": "/concepts/decisions/code-ownership", + "id": "code-ownership", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "When to Create a New Library", - "path": "/concepts/decisions/creating-libraries", - "id": "creating-libraries", + "name": "Project Size", + "path": "/concepts/decisions/project-size", + "id": "project-size", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Library Types", - "path": "/concepts/decisions/library-types", - "id": "library-types", + "name": "Project Dependency Rules", + "path": "/concepts/decisions/project-dependency-rules", + "id": "project-dependency-rules", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Grouping Libraries", - "path": "/concepts/decisions/grouping-libraries", - "id": "grouping-libraries", + "name": "Folder Structure", + "path": "/concepts/decisions/folder-structure", + "id": "folder-structure", "isExternal": false, "children": [], "disableCollapsible": false @@ -982,6 +982,14 @@ ], "disableCollapsible": false }, + { + "name": "Overview", + "path": "/concepts/decisions/overview", + "id": "overview", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Monorepos", "path": "/concepts/decisions/why-monorepos", @@ -999,41 +1007,33 @@ "disableCollapsible": false }, { - "name": "Code Sharing", - "path": "/concepts/decisions/code-sharing", - "id": "code-sharing", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "Applications and Libraries", - "path": "/concepts/decisions/applications-and-libraries", - "id": "applications-and-libraries", + "name": "Code Ownership", + "path": "/concepts/decisions/code-ownership", + "id": "code-ownership", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "When to Create a New Library", - "path": "/concepts/decisions/creating-libraries", - "id": "creating-libraries", + "name": "Project Size", + "path": "/concepts/decisions/project-size", + "id": "project-size", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Library Types", - "path": "/concepts/decisions/library-types", - "id": "library-types", + "name": "Project Dependency Rules", + "path": "/concepts/decisions/project-dependency-rules", + "id": "project-dependency-rules", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Grouping Libraries", - "path": "/concepts/decisions/grouping-libraries", - "id": "grouping-libraries", + "name": "Folder Structure", + "path": "/concepts/decisions/folder-structure", + "id": "folder-structure", "isExternal": false, "children": [], "disableCollapsible": false diff --git a/docs/generated/manifests/nx.json b/docs/generated/manifests/nx.json index 704fd240a2f91a..1a2bbe648ef4e1 100644 --- a/docs/generated/manifests/nx.json +++ b/docs/generated/manifests/nx.json @@ -933,6 +933,17 @@ "mediaImage": "", "file": "", "itemList": [ + { + "id": "overview", + "name": "Overview", + "description": "", + "mediaImage": "", + "file": "shared/concepts/decisions/monorepo-polyrepo", + "itemList": [], + "isExternal": false, + "path": "/concepts/decisions/overview", + "tags": [] + }, { "id": "why-monorepos", "name": "Monorepos", @@ -956,58 +967,47 @@ "tags": [] }, { - "id": "code-sharing", - "name": "Code Sharing", + "id": "code-ownership", + "name": "Code Ownership", "description": "", "mediaImage": "", - "file": "shared/concepts/decisions/code-sharing", + "file": "shared/concepts/decisions/code-ownership", "itemList": [], "isExternal": false, - "path": "/concepts/decisions/code-sharing", + "path": "/concepts/decisions/code-ownership", "tags": [] }, { - "id": "applications-and-libraries", - "name": "Applications and Libraries", - "description": "", - "mediaImage": "", - "file": "shared/concepts/decisions/applications-and-libraries", - "itemList": [], - "isExternal": false, - "path": "/concepts/decisions/applications-and-libraries", - "tags": ["enforce-module-boundaries"] - }, - { - "id": "creating-libraries", - "name": "When to Create a New Library", + "id": "project-size", + "name": "Project Size", "description": "", "mediaImage": "", - "file": "shared/concepts/decisions/creating-libraries", + "file": "shared/concepts/decisions/project-size", "itemList": [], "isExternal": false, - "path": "/concepts/decisions/creating-libraries", + "path": "/concepts/decisions/project-size", "tags": ["enforce-module-boundaries"] }, { - "id": "library-types", - "name": "Library Types", + "id": "project-dependency-rules", + "name": "Project Dependency Rules", "description": "", "mediaImage": "", - "file": "shared/concepts/decisions/library-types", + "file": "shared/concepts/decisions/project-dependency-rules", "itemList": [], "isExternal": false, - "path": "/concepts/decisions/library-types", + "path": "/concepts/decisions/project-dependency-rules", "tags": ["enforce-module-boundaries"] }, { - "id": "grouping-libraries", - "name": "Grouping Libraries", + "id": "folder-structure", + "name": "Folder Structure", "description": "", "mediaImage": "", - "file": "shared/concepts/decisions/grouping-libraries", + "file": "shared/concepts/decisions/folder-structure", "itemList": [], "isExternal": false, - "path": "/concepts/decisions/grouping-libraries", + "path": "/concepts/decisions/folder-structure", "tags": ["enforce-module-boundaries"] } ], @@ -1260,6 +1260,17 @@ "mediaImage": "", "file": "", "itemList": [ + { + "id": "overview", + "name": "Overview", + "description": "", + "mediaImage": "", + "file": "shared/concepts/decisions/monorepo-polyrepo", + "itemList": [], + "isExternal": false, + "path": "/concepts/decisions/overview", + "tags": [] + }, { "id": "why-monorepos", "name": "Monorepos", @@ -1283,58 +1294,47 @@ "tags": [] }, { - "id": "code-sharing", - "name": "Code Sharing", + "id": "code-ownership", + "name": "Code Ownership", "description": "", "mediaImage": "", - "file": "shared/concepts/decisions/code-sharing", + "file": "shared/concepts/decisions/code-ownership", "itemList": [], "isExternal": false, - "path": "/concepts/decisions/code-sharing", + "path": "/concepts/decisions/code-ownership", "tags": [] }, { - "id": "applications-and-libraries", - "name": "Applications and Libraries", - "description": "", - "mediaImage": "", - "file": "shared/concepts/decisions/applications-and-libraries", - "itemList": [], - "isExternal": false, - "path": "/concepts/decisions/applications-and-libraries", - "tags": ["enforce-module-boundaries"] - }, - { - "id": "creating-libraries", - "name": "When to Create a New Library", + "id": "project-size", + "name": "Project Size", "description": "", "mediaImage": "", - "file": "shared/concepts/decisions/creating-libraries", + "file": "shared/concepts/decisions/project-size", "itemList": [], "isExternal": false, - "path": "/concepts/decisions/creating-libraries", + "path": "/concepts/decisions/project-size", "tags": ["enforce-module-boundaries"] }, { - "id": "library-types", - "name": "Library Types", + "id": "project-dependency-rules", + "name": "Project Dependency Rules", "description": "", "mediaImage": "", - "file": "shared/concepts/decisions/library-types", + "file": "shared/concepts/decisions/project-dependency-rules", "itemList": [], "isExternal": false, - "path": "/concepts/decisions/library-types", + "path": "/concepts/decisions/project-dependency-rules", "tags": ["enforce-module-boundaries"] }, { - "id": "grouping-libraries", - "name": "Grouping Libraries", + "id": "folder-structure", + "name": "Folder Structure", "description": "", "mediaImage": "", - "file": "shared/concepts/decisions/grouping-libraries", + "file": "shared/concepts/decisions/folder-structure", "itemList": [], "isExternal": false, - "path": "/concepts/decisions/grouping-libraries", + "path": "/concepts/decisions/folder-structure", "tags": ["enforce-module-boundaries"] } ], @@ -1342,6 +1342,17 @@ "path": "/concepts/decisions", "tags": [] }, + "/concepts/decisions/overview": { + "id": "overview", + "name": "Overview", + "description": "", + "mediaImage": "", + "file": "shared/concepts/decisions/monorepo-polyrepo", + "itemList": [], + "isExternal": false, + "path": "/concepts/decisions/overview", + "tags": [] + }, "/concepts/decisions/why-monorepos": { "id": "why-monorepos", "name": "Monorepos", @@ -1364,59 +1375,48 @@ "path": "/concepts/decisions/dependency-management", "tags": [] }, - "/concepts/decisions/code-sharing": { - "id": "code-sharing", - "name": "Code Sharing", + "/concepts/decisions/code-ownership": { + "id": "code-ownership", + "name": "Code Ownership", "description": "", "mediaImage": "", - "file": "shared/concepts/decisions/code-sharing", + "file": "shared/concepts/decisions/code-ownership", "itemList": [], "isExternal": false, - "path": "/concepts/decisions/code-sharing", + "path": "/concepts/decisions/code-ownership", "tags": [] }, - "/concepts/decisions/applications-and-libraries": { - "id": "applications-and-libraries", - "name": "Applications and Libraries", - "description": "", - "mediaImage": "", - "file": "shared/concepts/decisions/applications-and-libraries", - "itemList": [], - "isExternal": false, - "path": "/concepts/decisions/applications-and-libraries", - "tags": ["enforce-module-boundaries"] - }, - "/concepts/decisions/creating-libraries": { - "id": "creating-libraries", - "name": "When to Create a New Library", + "/concepts/decisions/project-size": { + "id": "project-size", + "name": "Project Size", "description": "", "mediaImage": "", - "file": "shared/concepts/decisions/creating-libraries", + "file": "shared/concepts/decisions/project-size", "itemList": [], "isExternal": false, - "path": "/concepts/decisions/creating-libraries", + "path": "/concepts/decisions/project-size", "tags": ["enforce-module-boundaries"] }, - "/concepts/decisions/library-types": { - "id": "library-types", - "name": "Library Types", + "/concepts/decisions/project-dependency-rules": { + "id": "project-dependency-rules", + "name": "Project Dependency Rules", "description": "", "mediaImage": "", - "file": "shared/concepts/decisions/library-types", + "file": "shared/concepts/decisions/project-dependency-rules", "itemList": [], "isExternal": false, - "path": "/concepts/decisions/library-types", + "path": "/concepts/decisions/project-dependency-rules", "tags": ["enforce-module-boundaries"] }, - "/concepts/decisions/grouping-libraries": { - "id": "grouping-libraries", - "name": "Grouping Libraries", + "/concepts/decisions/folder-structure": { + "id": "folder-structure", + "name": "Folder Structure", "description": "", "mediaImage": "", - "file": "shared/concepts/decisions/grouping-libraries", + "file": "shared/concepts/decisions/folder-structure", "itemList": [], "isExternal": false, - "path": "/concepts/decisions/grouping-libraries", + "path": "/concepts/decisions/folder-structure", "tags": ["enforce-module-boundaries"] }, "/concepts/more-concepts": { diff --git a/docs/generated/manifests/tags.json b/docs/generated/manifests/tags.json index 781cae8c493e9e..ceee1750ba861e 100644 --- a/docs/generated/manifests/tags.json +++ b/docs/generated/manifests/tags.json @@ -392,31 +392,24 @@ }, { "description": "", - "file": "shared/concepts/decisions/applications-and-libraries", - "id": "applications-and-libraries", - "name": "Applications and Libraries", - "path": "/concepts/decisions/applications-and-libraries" + "file": "shared/concepts/decisions/project-size", + "id": "project-size", + "name": "Project Size", + "path": "/concepts/decisions/project-size" }, { "description": "", - "file": "shared/concepts/decisions/creating-libraries", - "id": "creating-libraries", - "name": "When to Create a New Library", - "path": "/concepts/decisions/creating-libraries" + "file": "shared/concepts/decisions/project-dependency-rules", + "id": "project-dependency-rules", + "name": "Project Dependency Rules", + "path": "/concepts/decisions/project-dependency-rules" }, { "description": "", - "file": "shared/concepts/decisions/library-types", - "id": "library-types", - "name": "Library Types", - "path": "/concepts/decisions/library-types" - }, - { - "description": "", - "file": "shared/concepts/decisions/grouping-libraries", - "id": "grouping-libraries", - "name": "Grouping Libraries", - "path": "/concepts/decisions/grouping-libraries" + "file": "shared/concepts/decisions/folder-structure", + "id": "folder-structure", + "name": "Folder Structure", + "path": "/concepts/decisions/folder-structure" }, { "description": "", diff --git a/docs/generated/packages/angular/documents/overview.md b/docs/generated/packages/angular/documents/overview.md index 88354b1493bfa6..a331d4ab9d1fb7 100644 --- a/docs/generated/packages/angular/documents/overview.md +++ b/docs/generated/packages/angular/documents/overview.md @@ -111,8 +111,8 @@ nx lint libName Read more about: -- [Creating Libraries](/concepts/decisions/creating-libraries) -- [Library Types](/concepts/decisions/library-types) +- [Creating Libraries](/concepts/decisions/project-size) +- [Library Types](/concepts/decisions/project-dependency-rules) - [Buildable and Publishable Libraries](/concepts/more-concepts/buildable-and-publishable-libraries) ### Fallback to `@schematics/angular` diff --git a/docs/generated/packages/next/documents/overview.md b/docs/generated/packages/next/documents/overview.md index 4bab33d9cfd82a..61b85b540aef76 100644 --- a/docs/generated/packages/next/documents/overview.md +++ b/docs/generated/packages/next/documents/overview.md @@ -108,9 +108,6 @@ Nx allows you to create libraries with just one command. Some reasons you might - Publish a package to be used outside the monorepo - Better visualize the architecture using `nx graph` -For more information on Nx libraries, see our documentation on [Creating Libraries](/concepts/decisions/creating-libraries) -and [Library Types](/concepts/decisions/library-types). - To generate a new library run: ```shell diff --git a/docs/generated/packages/storybook/documents/best-practices.md b/docs/generated/packages/storybook/documents/best-practices.md index 54bf7d4d5a9b82..976893d7d5d405 100644 --- a/docs/generated/packages/storybook/documents/best-practices.md +++ b/docs/generated/packages/storybook/documents/best-practices.md @@ -87,7 +87,7 @@ In the following section, we are going to see how to set up Storybook in these c ### Philosophy -Setting up Storybook on Nx reflects - and takes advantage of - the [mental model](/concepts/mental-model) of Nx, and especially the architecture of [Applications and Libraries](/concepts/decisions/applications-and-libraries). What that means, in essence, is that you still maintain the individual Storybook instances (per project) which you use for testing and local development, but you also keep one extra “container” for publishing, that serves as a single entry point. Let’s see this in more detail. +Setting up Storybook on Nx reflects - and takes advantage of - the [mental model](/concepts/mental-model) of Nx. What that means, in essence, is that you still maintain the individual Storybook instances (per project) which you use for testing and local development, but you also keep one extra “container” for publishing, that serves as a single entry point. Let’s see this in more detail. #### Local development and testing @@ -119,7 +119,7 @@ Since each Storybook, in this case, is attached to a project, so is the serving #### Publishing -When you are publishing your Storybook, you can follow the same principles described in the [Applications and Libraries Mental Model](/concepts/decisions/applications-and-libraries#mental-model) documentation page. The general idea is to have one central Storybook container, into which you are going to gather your stories from multiple libraries. +When you are publishing your Storybook, you can follow the same principles described in the [Applications and Libraries Mental Model](/concepts/decisions/project-size#mental-model) documentation page. The general idea is to have one central Storybook container, into which you are going to gather your stories from multiple libraries. You can think of the central Storybook container as a grouping of similar-concept or same-scope UI parts of your workspace. In the same way you are scoping libraries, you can group your stories as well. @@ -129,7 +129,7 @@ Then, according to your use-case, you can have one central Storybook for your wh In order to achieve some things mentioned above, you may use [Storybook Composition](/recipes/storybook/storybook-composition-setup). However, in this case, you would still need to build each project’s Storybook individually, and also deploy it individually. So in the cases where you have multiple projects, Storybook Composition would not be very efficient. {% /callout %} -Before moving on to the examples section, it could be useful to read the [Library Types](/concepts/decisions/library-types) documentation page and the [Grouping libraries](/concepts/decisions/grouping-libraries) documentation page. These could help you decide which way fits your use case better. +Before moving on to the examples section, it could be useful to read the [Library Types](/concepts/decisions/project-dependency-rules) documentation page and the [Grouping libraries](/concepts/decisions/folder-structure) documentation page. These could help you decide which way fits your use case better. ## Examples / Use cases diff --git a/docs/map.json b/docs/map.json index 108c8a6c1f7312..a71dfc68cf6e4a 100644 --- a/docs/map.json +++ b/docs/map.json @@ -283,6 +283,11 @@ "id": "decisions", "description": "Topics that need to be considered when structuring your repository", "itemList": [ + { + "name": "Overview", + "id": "overview", + "file": "shared/concepts/decisions/monorepo-polyrepo" + }, { "name": "Monorepos", "id": "why-monorepos", @@ -294,33 +299,27 @@ "file": "shared/concepts/decisions/dependency-management" }, { - "name": "Code Sharing", - "id": "code-sharing", - "file": "shared/concepts/decisions/code-sharing" - }, - { - "name": "Applications and Libraries", - "id": "applications-and-libraries", - "tags": ["enforce-module-boundaries"], - "file": "shared/concepts/decisions/applications-and-libraries" + "name": "Code Ownership", + "id": "code-ownership", + "file": "shared/concepts/decisions/code-ownership" }, { - "name": "When to Create a New Library", - "id": "creating-libraries", + "name": "Project Size", + "id": "project-size", "tags": ["enforce-module-boundaries"], - "file": "shared/concepts/decisions/creating-libraries" + "file": "shared/concepts/decisions/project-size" }, { - "name": "Library Types", - "id": "library-types", + "name": "Project Dependency Rules", + "id": "project-dependency-rules", "tags": ["enforce-module-boundaries"], - "file": "shared/concepts/decisions/library-types" + "file": "shared/concepts/decisions/project-dependency-rules" }, { - "name": "Grouping Libraries", - "id": "grouping-libraries", + "name": "Folder Structure", + "id": "folder-structure", "tags": ["enforce-module-boundaries"], - "file": "shared/concepts/decisions/grouping-libraries" + "file": "shared/concepts/decisions/folder-structure" } ] }, diff --git a/docs/shared/concepts/decisions/applications-and-libraries.md b/docs/shared/concepts/decisions/applications-and-libraries.md deleted file mode 100644 index c9963f3e8a561f..00000000000000 --- a/docs/shared/concepts/decisions/applications-and-libraries.md +++ /dev/null @@ -1,50 +0,0 @@ -# Applications and libraries - -A typical Nx workspace is structured into _"apps"_ and _"libs"_. This distinction allows us to have a more modular architecture by following a separation of concerns methodology, incentivizing the organization of our source code and logic into smaller, more focused and highly cohesive units. - -Nx automatically creates TypeScript path mappings in the `tsconfig.base.json` file, such that they can be easily consumed by other apps or libs. - -```typescript -// example of importing from another workspace library -import { Button } from '@my-organization/ui'; -... -``` - -Therefore, consuming libraries is very straightforward, and similar to what you might already be accustomed to in previous projects. - -Having a dedicated library project is a much stronger boundary compared to just separating code into folders, though. Each Nx library has a so-called _"public API"_, represented by an `index.ts` barrel file. This forces developers into an _"API thinking"_ of what should be exposed and thus be made available for others to consume, and what on the others side should remain private within the library itself. - -{% callout type="caution" title="Library !== published artifact" %} -[This is a common misconception, moving code into libraries can be done from a pure code organization perspective](#misconception). -{% /callout %} - -## Mental model - -A common mental model is to **see the application as "containers"** that link, bundle and compile functionality implemented in libraries for being deployed. -As such, if we follow a _80/20 approach_: - -- place 80% of your logic into the `libs/` folder -- and 20% into `apps/` - -Note, these libraries don’t necessarily need to be built separately, but are rather consumed and built by the application itself directly. Hence, nothing changes from a pure deployment point of view. - -That said, it is totally possible to create so-called _"[buildable libraries](/concepts/more-concepts/buildable-and-publishable-libraries#buildable-libraries)"_ for enabling incremental builds as -well as _"[publishable libraries](/concepts/more-concepts/buildable-and-publishable-libraries#publishable-libraries)"_ for those scenarios where not only you want to -use a specific library within the current Nx workspace, but also to publish it -to some package repository (e.g. NPM). - -### Misconception - -> Developers new to Nx are initially often hesitant to move their logic into libraries, because they assume it implies that those libraries need to be general purpose and shareable across applications. - -**This is a common misconception, moving code into libraries can be done from a pure code organization perspective.** - -Ease of re-use might emerge as a positive side effect of refactoring code into libraries by applying an _"API thinking"_ approach. It is not the main driver though. - -In fact when organizing libraries you should think about your business domains. - -Most often teams are aligned with those domains and thus a similar organization of the libraries in the `libs/` folder might be most appropriate. Nx allows to nest libraries into sub-folders which makes it easy to reflect such structuring. - -- [Learn more about when you need to create a new library or using an existing one](/concepts/decisions/creating-libraries) -- [Learn more about the different types of libraries we think you should follow](/concepts/decisions/library-types) -- [Learn more about how to group libraries between each other](/concepts/decisions/grouping-libraries) diff --git a/docs/shared/concepts/decisions/code-sharing.md b/docs/shared/concepts/decisions/code-ownership.md similarity index 98% rename from docs/shared/concepts/decisions/code-sharing.md rename to docs/shared/concepts/decisions/code-ownership.md index 77540bcb7373c9..4bbafeda2ed2fb 100644 --- a/docs/shared/concepts/decisions/code-sharing.md +++ b/docs/shared/concepts/decisions/code-ownership.md @@ -1,4 +1,4 @@ -# Code Sharing +# Code Ownership One of the most obvious benefits of having a monorepo is that you can easily share code across projects. This enables you to apply the Don't Repeat Yourself principle across the whole codebase. Code sharing could mean using a function or a component in multiple projects. Or code sharing could mean using a typescript interface to define the network API interface for both the front end and back end applications. @@ -20,7 +20,7 @@ Another team can use a piece of code that is intended to be internal to your pro Libraries with presentational components can accidentally use code from a library that holds a data store. Projects with Angular code can accidentally use code from a React project. Projects from team A could accidentally use code in projects that are intended to be only for team B. These kinds of rules will vary based on the organisation, but they can all be enforced automatically using tags and the `enforce-module-boundaries` lint rule. -## Code Ownership +## Defining Code Ownership As more teams are contributing to the same repository, it becomes crucial to establish clear code ownership. diff --git a/docs/shared/concepts/decisions/creating-libraries.md b/docs/shared/concepts/decisions/creating-libraries.md deleted file mode 100644 index d6c2ebbddf8407..00000000000000 --- a/docs/shared/concepts/decisions/creating-libraries.md +++ /dev/null @@ -1,33 +0,0 @@ -# Creating Libraries - -Like a lot of decisions in programming, deciding to make a new Nx library or not is all about trade-offs. Each organization will decide on their own conventions, but here are some trade-offs to bear in mind as you have the conversation. - -## Should I Make a New Library? - -There are three main benefits to breaking your code up into more libraries. - -### 1. Faster Commands - -The more granular your libraries are, the more effective `nx affected` and Nx's computation cache will be. For example, if `libraryA` contains 10 tests, but only 5 of them were affected by a particular code change, all 10 tests will be run by `nx affected -t test`. If you can predict which 5 tests are usually run together, you can split all the related code into a separate library to allow the two groups of 5 tests to be executed independently. - -### 2. Visualizing Architecture - -The `nx graph` command generates a graph of how apps and libraries depend on each other. If most of your code lives in a few giant libraries, this visualization doesn't provide much value. Adding the `--watch` flag to the command will update the visualization in-browser as you make changes. - -### 3. Enforcing Constraints - -You can enforce constraints on how different types of libraries depend on each other [using tags](/features/enforce-module-boundaries). Following pre-determined conventions on what kind of code can go in different types of libraries allows your tagging system to enforce good architectural patterns. - -Also, each library defines its own API, which allows for encapsulating logic that other parts of codebase can not access. You can even use a [CODEOWNERS file](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners) to assign ownership of a certain library to a user or team. - -## Should I Add to an Existing Library? - -Limiting the number of libraries by keeping code in an existing library also has benefits. - -### 1. Consolidating Code - -Related code should be close together. If a developer can accomplish a task without moving between multiple different folders, it helps them work faster and make less mistakes. Every new library adds some folders and configuration files that are not directly contributing to business value. Nx helps reduce the cost of adding a new library, but it isn't zero. - -### 2. Removing Constraints - -Especially for rapidly evolving code, the standard architectural constraints may just get in the way of experimentation and exploration. It may be worthwhile to develop for a while in a single library in order to allow a real architecture to emerge and then refactoring into multiple libraries once the pace of change has slowed down. diff --git a/docs/shared/concepts/decisions/folder-structure.md b/docs/shared/concepts/decisions/folder-structure.md new file mode 100644 index 00000000000000..475f6d1dfc11eb --- /dev/null +++ b/docs/shared/concepts/decisions/folder-structure.md @@ -0,0 +1,67 @@ +# Folder Structure + +Nx can work with any folder structure you choose, but it is good to have a plan in place for the folder structure of your monorepo. + +Projects are often grouped by _scope_. A project's scope is either the application to which it belongs or (for larger applications) a section within that application. + +## Move Generator + +Don't be too anxious about choosing the exact right folder structure from the beginning. Projects can be moved or renamed using the [`@nx/workspace:move` generator](/nx-api/workspace/generators/move). + +For instance, if a project under the `booking` folder is now being shared by multiple apps, you can move it to the shared folder like this: + +```shell +nx g move --project booking-some-project shared/some-project +``` + +## Remove Generator + +Similarly, if you no longer need a project, you can remove it with the [`@nx/workspace:remove` generator](/nx-api/workspace/generators/remove). + +```shell +nx g remove booking-some-project +``` + +## Example Workspace + +Let's use Nrwl Airlines as an example organization. This organization has two apps, `booking` and `check-in`. In the Nx workspace, projects related to `booking` are grouped under a `libs/booking` folder, projects related to `check-in` are grouped under a `libs/check-in` folder and projects used in both applications are placed in `libs/shared`. You can also have nested grouping folders, (i.e. `libs/shared/seatmap`). + +The purpose of these folders is to help with organizing by scope. We recommend grouping projects together which are (usually) updated together. It helps minimize the amount of time a developer spends navigating the folder tree to find the right file. + +```text +apps/ + booking/ + check-in/ +libs/ + booking/ <---- grouping folder + feature-shell/ <---- project + + check-in/ + feature-shell/ + + shared/ <---- grouping folder + data-access/ <---- project + + seatmap/ <---- grouping folder + data-access/ <---- project + feature-seatmap/ <---- project +``` + +## Sharing Projects + +One of the main advantages of using a monorepo is that there is more visibility into code that can be reused across many different applications. Shared projects are a great way to save developers time and effort by reusing a solution to a common problem. + +Let’s consider our reference monorepo. The `shared-data-access` project contains the code needed to communicate with the back-end (for example, the URL prefix). We know that this would be the same for all libs; therefore, we should place this in the shared lib and properly document it so that all projects can use it instead of writing their own versions. + +```text + libs/ + booking/ + data-access/ <---- app-specific project + + shared/ + data-access/ <---- shared project + + seatmap/ + data-access/ <---- shared project + feature-seatmap/ <---- shared project +``` diff --git a/docs/shared/concepts/decisions/grouping-libraries.md b/docs/shared/concepts/decisions/grouping-libraries.md deleted file mode 100644 index 0a15d7b0e3e898..00000000000000 --- a/docs/shared/concepts/decisions/grouping-libraries.md +++ /dev/null @@ -1,65 +0,0 @@ -# Grouping Libraries - -Libraries are often grouped by _scope_. A library's scope is either the application to which it belongs or (for larger applications) a section within that application. - -## Move Generator - -Don't be too anxious about choosing the exact right folder structure from the beginning. Libraries can be moved or renamed using the [`@nx/workspace:move` generator](/nx-api/workspace/generators/move). - -For instance, if a library under the `booking` folder is now being shared by multiple apps, you can move it to the shared folder like this: - -```shell -nx g move --project booking-some-library shared/some-library -``` - -## Remove Generator - -Similarly, if you no longer need a library, you can remove it with the [`@nx/workspace:remove` generator](/nx-api/workspace/generators/remove). - -```shell -nx g remove booking-some-library -``` - -## Example Workspace - -Let's use Nrwl Airlines as an example organization. This organization has two apps, `booking` and `check-in`. In the Nx workspace, libraries related to `booking` are grouped under a `libs/booking` folder, libraries related to `check-in` are grouped under a `libs/check-in` folder and libraries used in both applications are placed in `libs/shared`. You can also have nested grouping folders, (i.e. `libs/shared/seatmap`). - -The purpose of these folders is to help with organizing by scope. We recommend grouping libraries together which are (usually) updated together. It helps minimize the amount of time a developer spends navigating the folder tree to find the right file. - -```text -apps/ - booking/ - check-in/ -libs/ - booking/ <---- grouping folder - feature-shell/ <---- library - - check-in/ - feature-shell/ - - shared/ <---- grouping folder - data-access/ <---- library - - seatmap/ <---- grouping folder - data-access/ <---- library - feature-seatmap/ <---- library -``` - -## Sharing Libraries - -One of the main advantages of using a monorepo is that there is more visibility into code that can be reused across many different applications. Shared libraries are a great way to save developers time and effort by reusing a solution to a common problem. - -Let’s consider our reference monorepo. The `shared-data-access` library contains the code needed to communicate with the back-end (for example, the URL prefix). We know that this would be the same for all libs; therefore, we should place this in the shared lib and properly document it so that all projects can use it instead of writing their own versions. - -```text - libs/ - booking/ - data-access/ <---- app-specific library - - shared/ - data-access/ <---- shared library - - seatmap/ - data-access/ <---- shared library - feature-seatmap/ <---- shared library -``` diff --git a/docs/shared/concepts/decisions/monorepo-polyrepo.md b/docs/shared/concepts/decisions/monorepo-polyrepo.md new file mode 100644 index 00000000000000..6c4fb0ee33fbe0 --- /dev/null +++ b/docs/shared/concepts/decisions/monorepo-polyrepo.md @@ -0,0 +1,38 @@ +# Monorepo or Polyrepo + +Monorepos have a lot of benefits, but there are also some costs involved. We feel strongly that the [technical challenges](/concepts/decisions/why-monorepos) involved in maintaining large monorepos are fully addressed through the efficient use of Nx and Nx Cloud. Rather, the limiting factors in how large your monorepo grows are interpersonal. + +In order for teams to work together in a monorepo, they need to agree on how that repository is going to be managed. These questions can be answered in many different ways, but if the developers in the repository can't agree on the answers, then they'll need to work in separate repositories. + +**Organizational Decisions:** + +- [Dependency Management](/concepts/decisions/dependency-management) - Should there be an enforced single version policy or should each project maintain their own dependency versions independently? +- [Code Ownership](/concepts/decisions/code-ownership) - What is the code review process? Who is responsible for reviewing changes to each portion of the repository? +- [Project Dependency Rules](/concepts/decisions/project-dependency-rules) - What are the restrictions on dependencies between projects? Which projects can depend on which other projects? +- [Folder Structure](/concepts/decisions/folder-structure) - What is the folder structure and naming convention for projects in the repository? +- [Project Size](/concepts/decisions/project-size) - What size should projects be before they need to be split into separate projects? +- Git Workflow - What Git workflow should be used? Will you use trunk-based development or long running feature branches? +- CI Pipeline - How is the CI pipeline managed? Who is responsible for maintaining it? +- Deployment - How are deployments managed? Does each project deploy independently or do they all deploy at once? + +## How Many Repositories? + +Once you have a good understanding of where people stand on these questions, you'll need to choose between one of the following setups: + +### One Monorepo to Rule Them All + +If everyone can agree on how to run the repository, having [a single monorepo will provide a lot of benefits](/concepts/decisions/why-monorepos). Every project can share code and maintenance tasks can be performed in one PR for the entire organization. Any task that involves coordination becomes much easier. + +Once the repository scales to hundreds of developers, you need to take proactive steps to ensure that your decisions about [code review](/concepts/decisions/code-ownership) and [project dependency restrictions](/features/enforce-module-boundaries) do not inhibit the velocity of your teams. Also, any shared code and tooling (like the CI pipeline or a shared component library) need to be maintained by a dedicated team to help everyone in the monorepo. + +### Polyrepos - A Repository for Each Project + +If every project is placed in its own repository, each team can make their own organizational decisions without the need to consult with other teams. Unfortunately, this also means that each team has to make their own organizational decisions instead of focusing on feature work that provides business value. Sharing code is difficult with this set up and every maintenance task needs to be repeated across all the repositories in the organization. + +Nx can still be useful with this organizational structure. Tooling and maintenance tasks can be centralized through shared [Nx plugins](/concepts/nx-plugins) that each repository can opt-in to using. Since creating repositories is a frequent occurrence in this scenario, Nx [generators](/features/generate-code) can be used to quickly scaffold out the repository with reasonable tooling defaults. + +### Multiple Monorepos + +Somewhere between the single monorepo and the full polyrepo solutions exists the multiple monorepo setup. Typically when there are disagreements about organizational decisions, there are two or three factions that form. These factions can naturally be allocated to separate monorepos that have been configured in a way that best suits the teams that will be working in them. + +Compared to the single monorepo setup, this setup requires some extra overhead cost - maintaining multiple CI pipelines and performing the same tooling maintenance tasks on multiple repositories, but this cost could be offset by the extra productivity boost provided by the fact that each team can work in a repository that is optimized for the way that they work. diff --git a/docs/shared/concepts/decisions/monorepos.md b/docs/shared/concepts/decisions/monorepos.md index 2e3ba9768753dd..6b1c79da07d7bf 100644 --- a/docs/shared/concepts/decisions/monorepos.md +++ b/docs/shared/concepts/decisions/monorepos.md @@ -4,7 +4,7 @@ A monorepo is a single git repository that holds the source code for multiple ap ## What are the benefits of a monorepo? -- **Shared code and visibility** - [Keeps your code DRY across your entire organization.](/concepts/decisions/code-sharing) Reuse validation code, UI components, and types across the codebase. Reuse code between the backend, the frontend, and utility libraries. +- **Shared code and visibility** - [Keeps your code DRY across your entire organization.](/concepts/decisions/code-ownership) Reuse validation code, UI components, and types across the codebase. Reuse code between the backend, the frontend, and utility libraries. - **Atomic changes** - Change a server API and modify the downstream applications that consume that API in the same commit. You can change a button component in a shared library and the applications that use that component in the same commit. A monorepo saves the pain of trying to coordinate commits across multiple repositories. diff --git a/docs/shared/concepts/decisions/library-types.md b/docs/shared/concepts/decisions/project-dependency-rules.md similarity index 70% rename from docs/shared/concepts/decisions/library-types.md rename to docs/shared/concepts/decisions/project-dependency-rules.md index bde76fb9db0506..ae4c8b311b48cf 100644 --- a/docs/shared/concepts/decisions/library-types.md +++ b/docs/shared/concepts/decisions/project-dependency-rules.md @@ -1,6 +1,6 @@ -# Library Types +# Project Dependency Rules -There are many types of libraries in a workspace. You can identify the type of a library through a naming convention and/or by using the project tagging system. This article explains one possible way to organize your repository projects by type. Every repository is different and yours may need a different set of types. +There are many types of libraries in a workspace. You can identify the type of a library through a naming convention and/or by using the project tagging system. With explicitly defined types, you can also use Nx to enforce project dependency rules based on the types of each project. This article explains one possible way to organize your repository projects by type. Every repository is different and yours may need a different set of types. In order to maintain a certain sense of order, we recommend having a small number of types, such as the below four (4) types of libraries. @@ -104,6 +104,49 @@ export { formatDate, formatTime } from './src/format-date-fns'; export { formatCurrency } from './src/format-currency'; ``` +## Enforce Project Dependency Rules + +In order to enforce the dependency constraints that were listed for each type, you can add the following rule in the root `.eslintrc.json` file: + +```json {% fileName="/.eslintrc.json" %} +{ + "root": true, + "ignorePatterns": ["**/*"], + "plugins": ["@nx"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": { + "@nx/enforce-module-boundaries": [ + "error", + { + "allow": [], + "depConstraints": [ + { + "sourceTag": "type:feature", + "onlyDependOnLibsWithTags": [ + "type:feature", + "type:ui", + "type:util" + ] + }, + { + "sourceTag": "type:ui", + "onlyDependOnLibsWithTags": ["type:ui", "type:util"] + }, + { + "sourceTag": "type:util", + "onlyDependOnLibsWithTags": ["type:util"] + } + ] + } + ] + } + } + ] +} +``` + ## Other Types You will probably come up with other library types that make sense for your organization. That's fine. Just keep a few things in mind: diff --git a/docs/shared/concepts/decisions/project-size.md b/docs/shared/concepts/decisions/project-size.md new file mode 100644 index 00000000000000..5595ddb3da3c3b --- /dev/null +++ b/docs/shared/concepts/decisions/project-size.md @@ -0,0 +1,43 @@ +# Project Size + +Like a lot of decisions in programming, deciding to make a new Nx project or not is all about trade-offs. Each organization will decide on their own conventions, but here are some trade-offs to bear in mind as you have the conversation. + +## What is a Project For? + +> Developers new to Nx can be initially hesitant to move their logic into separate projects, because they assume it implies that those projects need to be general purpose and shareable across applications. + +**This is a common misconception, moving code into projects can be done from a pure code organization perspective.** + +Ease of re-use might emerge as a positive side effect of refactoring code into projects by applying an _"API thinking"_ approach. It is not the main driver though. + +In fact when organizing projects you should think about your business domains. + +## Should I Make a New Project? + +There are three main benefits to breaking your code up into more projects. + +### 1. Faster Commands + +The more granular your projects are, the more effective `nx affected` and Nx's computation cache will be. For example, if `projectA` contains 10 tests, but only 5 of them were affected by a particular code change, all 10 tests will be run by `nx affected -t test`. If you can predict which 5 tests are usually run together, you can split all the related code into a separate project to allow the two groups of 5 tests to be executed independently. + +### 2. Visualizing Architecture + +The `nx graph` command generates a graph of how apps and projects depend on each other. If most of your code lives in a few giant projects, this visualization doesn't provide much value. Adding the `--watch` flag to the command will update the visualization in-browser as you make changes. + +### 3. Enforcing Constraints + +You can enforce constraints on how different types of projects depend on each other [using tags](/features/enforce-module-boundaries). Following pre-determined conventions on what kind of code can go in different types of projects allows your tagging system to enforce good architectural patterns. + +Also, each project defines its own API, which allows for encapsulating logic that other parts of codebase can not access. You can even use a [CODEOWNERS file](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners) to assign ownership of a certain project to a user or team. + +## Should I Add to an Existing Project? + +Limiting the number of projects by keeping code in an existing project also has benefits. + +### 1. Consolidating Code + +Related code should be close together. If a developer can accomplish a task without moving between multiple different folders, it helps them work faster and make less mistakes. Every new project adds some folders and configuration files that are not directly contributing to business value. Nx helps reduce the cost of adding a new project, but it isn't zero. + +### 2. Removing Constraints + +Especially for rapidly evolving code, the standard architectural constraints may just get in the way of experimentation and exploration. It may be worthwhile to develop for a while in a single project in order to allow a real architecture to emerge and then refactoring into multiple projects once the pace of change has slowed down. diff --git a/docs/shared/guides/react-native.md b/docs/shared/guides/react-native.md index 4848cf7b9e36fb..272d7f24c29512 100644 --- a/docs/shared/guides/react-native.md +++ b/docs/shared/guides/react-native.md @@ -182,9 +182,6 @@ Nx allows you to create libraries with just one command. Some reasons you might - Publish a package to be used outside the monorepo - Better visualize the architecture using `npx nx graph` -For more information on Nx libraries, see our documentation on [Creating Libraries](/concepts/decisions/creating-libraries) -and [Library Types](/concepts/decisions/library-types). - To generate a new library run: ```shell diff --git a/docs/shared/packages/angular/angular-plugin.md b/docs/shared/packages/angular/angular-plugin.md index 88354b1493bfa6..a331d4ab9d1fb7 100644 --- a/docs/shared/packages/angular/angular-plugin.md +++ b/docs/shared/packages/angular/angular-plugin.md @@ -111,8 +111,8 @@ nx lint libName Read more about: -- [Creating Libraries](/concepts/decisions/creating-libraries) -- [Library Types](/concepts/decisions/library-types) +- [Creating Libraries](/concepts/decisions/project-size) +- [Library Types](/concepts/decisions/project-dependency-rules) - [Buildable and Publishable Libraries](/concepts/more-concepts/buildable-and-publishable-libraries) ### Fallback to `@schematics/angular` diff --git a/docs/shared/packages/next/plugin-overview.md b/docs/shared/packages/next/plugin-overview.md index 4bab33d9cfd82a..61b85b540aef76 100644 --- a/docs/shared/packages/next/plugin-overview.md +++ b/docs/shared/packages/next/plugin-overview.md @@ -108,9 +108,6 @@ Nx allows you to create libraries with just one command. Some reasons you might - Publish a package to be used outside the monorepo - Better visualize the architecture using `nx graph` -For more information on Nx libraries, see our documentation on [Creating Libraries](/concepts/decisions/creating-libraries) -and [Library Types](/concepts/decisions/library-types). - To generate a new library run: ```shell diff --git a/docs/shared/packages/storybook/best-practices.md b/docs/shared/packages/storybook/best-practices.md index 54bf7d4d5a9b82..976893d7d5d405 100644 --- a/docs/shared/packages/storybook/best-practices.md +++ b/docs/shared/packages/storybook/best-practices.md @@ -87,7 +87,7 @@ In the following section, we are going to see how to set up Storybook in these c ### Philosophy -Setting up Storybook on Nx reflects - and takes advantage of - the [mental model](/concepts/mental-model) of Nx, and especially the architecture of [Applications and Libraries](/concepts/decisions/applications-and-libraries). What that means, in essence, is that you still maintain the individual Storybook instances (per project) which you use for testing and local development, but you also keep one extra “container” for publishing, that serves as a single entry point. Let’s see this in more detail. +Setting up Storybook on Nx reflects - and takes advantage of - the [mental model](/concepts/mental-model) of Nx. What that means, in essence, is that you still maintain the individual Storybook instances (per project) which you use for testing and local development, but you also keep one extra “container” for publishing, that serves as a single entry point. Let’s see this in more detail. #### Local development and testing @@ -119,7 +119,7 @@ Since each Storybook, in this case, is attached to a project, so is the serving #### Publishing -When you are publishing your Storybook, you can follow the same principles described in the [Applications and Libraries Mental Model](/concepts/decisions/applications-and-libraries#mental-model) documentation page. The general idea is to have one central Storybook container, into which you are going to gather your stories from multiple libraries. +When you are publishing your Storybook, you can follow the same principles described in the [Applications and Libraries Mental Model](/concepts/decisions/project-size#mental-model) documentation page. The general idea is to have one central Storybook container, into which you are going to gather your stories from multiple libraries. You can think of the central Storybook container as a grouping of similar-concept or same-scope UI parts of your workspace. In the same way you are scoping libraries, you can group your stories as well. @@ -129,7 +129,7 @@ Then, according to your use-case, you can have one central Storybook for your wh In order to achieve some things mentioned above, you may use [Storybook Composition](/recipes/storybook/storybook-composition-setup). However, in this case, you would still need to build each project’s Storybook individually, and also deploy it individually. So in the cases where you have multiple projects, Storybook Composition would not be very efficient. {% /callout %} -Before moving on to the examples section, it could be useful to read the [Library Types](/concepts/decisions/library-types) documentation page and the [Grouping libraries](/concepts/decisions/grouping-libraries) documentation page. These could help you decide which way fits your use case better. +Before moving on to the examples section, it could be useful to read the [Library Types](/concepts/decisions/project-dependency-rules) documentation page and the [Grouping libraries](/concepts/decisions/folder-structure) documentation page. These could help you decide which way fits your use case better. ## Examples / Use cases diff --git a/docs/shared/recipes/storybook/one-storybook-per-scope.md b/docs/shared/recipes/storybook/one-storybook-per-scope.md index 2fa8b33e47a90d..ce14e8330495c5 100644 --- a/docs/shared/recipes/storybook/one-storybook-per-scope.md +++ b/docs/shared/recipes/storybook/one-storybook-per-scope.md @@ -8,7 +8,7 @@ description: Learn how to set up individual Storybook instances for each scope w This guide extends the [Using Storybook in a Nx workspace - Best practices](/nx-api/storybook/documents/best-practices) guide. In that guide, we discussed the best practices of using Storybook in a Nx workspace. We explained the main concepts and the mental model of how to best set up Storybook. In this guide, we are going to see how to put that into practice, by looking at a real-world example. We are going to see how you can publish one Storybook per scope (eg. theme, app, framework) for your workspace. -Sometimes, you have multiple apps and libraries, and each of these is associated with a specific scope. You can read more about grouping libraries and scoping them in the [Library Types](/concepts/decisions/library-types) documentation page. +Sometimes, you have multiple apps and libraries, and each of these is associated with a specific scope. You can read more about grouping libraries and scoping them in the [Library Types](/concepts/decisions/project-dependency-rules) documentation page. In this case, you can have one Storybook instance per scope. If you follow the folder organization convention described above, it is easy to configure Storybook to import all the stories under a specific folder, for example, which are associated with a specific app or scope. diff --git a/docs/shared/reference/glossary.md b/docs/shared/reference/glossary.md index 6bd202cd6d45a3..fcfc7b5bd7750a 100644 --- a/docs/shared/reference/glossary.md +++ b/docs/shared/reference/glossary.md @@ -8,8 +8,6 @@ This is a short list of Nx-specific terms that will help you understand the rest A [project](#project) that can run on its own. Generally uses [libraries](#library). -> See: [Applications and Libraries](/concepts/decisions/applications-and-libraries) - ### Atomizer The Atomizer is an Nx Cloud feature that automatically splits tasks so that they can be executed in parallel. @@ -120,14 +118,10 @@ Launch Templates are used to set up an agent machine. They specify a resource cl A [project](#project) that is used by [applications](#application) or other [libraries](#library). -> See: [Applications and Libraries](/concepts/decisions/applications-and-libraries) - ### Monolith A large [application](#application) that is difficult to separate into smaller pieces. -> See: [Applications and Libraries](/concepts/decisions/applications-and-libraries) - ### Monorepo A repository with multiple [projects](#project). @@ -180,8 +174,6 @@ Related [projects](#project) spread across multiple repositories. The unit of code on which a [task](#task) can be run. A project can be an [application](#application) or a [library](#library). -> See: [Applications and Libraries](/concepts/decisions/applications-and-libraries) - ### Publishable Library A [library](#library) that has a `publish` [target](#target). Some libraries can be generated with a `publish` target using the `--publishable` flag. diff --git a/docs/shared/reference/sitemap.md b/docs/shared/reference/sitemap.md index 41ade60b5b4fe0..b64eb6a5e00d8c 100644 --- a/docs/shared/reference/sitemap.md +++ b/docs/shared/reference/sitemap.md @@ -37,13 +37,13 @@ - [Micro Frontend Architecture](/concepts/module-federation/micro-frontend-architecture) - [Manage Library Versions with Module Federation](/concepts/module-federation/manage-library-versions-with-module-federation) - [Organizational Decisions](/concepts/decisions) + - [Overview](/concepts/decisions/overview) - [Monorepos](/concepts/decisions/why-monorepos) - [Dependency Management](/concepts/decisions/dependency-management) - - [Code Sharing](/concepts/decisions/code-sharing) - - [Applications and Libraries](/concepts/decisions/applications-and-libraries) - - [When to Create a New Library](/concepts/decisions/creating-libraries) - - [Library Types](/concepts/decisions/library-types) - - [Grouping Libraries](/concepts/decisions/grouping-libraries) + - [Code Ownership](/concepts/decisions/code-ownership) + - [Project Size](/concepts/decisions/project-size) + - [Project Dependency Rules](/concepts/decisions/project-dependency-rules) + - [Folder Structure](/concepts/decisions/folder-structure) - [More Concepts](/concepts/more-concepts) - [Nx Daemon](/concepts/more-concepts/nx-daemon) - [Nx and Turborepo](/concepts/more-concepts/turbo-and-nx) diff --git a/docs/shared/tutorials/angular-monorepo.md b/docs/shared/tutorials/angular-monorepo.md index da548e523629a8..da717bc47a8220 100644 --- a/docs/shared/tutorials/angular-monorepo.md +++ b/docs/shared/tutorials/angular-monorepo.md @@ -106,7 +106,7 @@ The setup includes: - ESLint preconfigured - Jest preconfigured -Typically, an integrated Nx workspace places application projects in the `apps` folder and library projects in the `libs` folder. [Applications are encouraged to be as light-weight as possible](/concepts/decisions/applications-and-libraries) so that more code is pushed into libraries and can be reused in other projects. This folder structure is just a suggestion and can be modified to suit your organization's needs. +Typically, an integrated Nx workspace places application projects in the `apps` folder and library projects in the `libs` folder. Applications are encouraged to be as light-weight as possible so that more code is pushed into libraries and can be reused in other projects. This folder structure is just a suggestion and can be modified to suit your organization's needs. The [`nx.json` file](/reference/nx-json) contains configuration settings for Nx itself and global default settings that individual projects inherit. The `apps/angular-store/project.json` file contains [settings that are specific to the `angular-store` project](/reference/project-configuration). We'll examine that file more in the next section. diff --git a/docs/shared/tutorials/angular-standalone.md b/docs/shared/tutorials/angular-standalone.md index 1d76d53e71077e..f2ba2c8b9ffe0b 100644 --- a/docs/shared/tutorials/angular-standalone.md +++ b/docs/shared/tutorials/angular-standalone.md @@ -886,7 +886,7 @@ Once you modularize your codebase you want to make sure that the modules are not When building these kinds of constraints you usually have two dimensions: -- **type of project:** what is the type of your library. Example: "feature" library, "utility" library, "data-access" library, "ui" library (see [library types](/concepts/decisions/library-types)) +- **type of project:** what is the type of your library. Example: "feature" library, "utility" library, "data-access" library, "ui" library (see [library types](/concepts/decisions/project-dependency-rules)) - **scope (domain) of the project:** what domain area is covered by the project. Example: "orders", "products", "shared" ... this really depends on the type of product you're developing Nx comes with a generic mechanism that allows you to assign "tags" to projects. "tags" are arbitrary strings you can assign to a project that can be used later when defining boundaries between projects. For example, go to the `project.json` of your `orders` library and assign the tags `type:feature` and `scope:orders` to it. diff --git a/docs/shared/tutorials/react-monorepo.md b/docs/shared/tutorials/react-monorepo.md index 45aa577030c847..bea07224c6ecf4 100644 --- a/docs/shared/tutorials/react-monorepo.md +++ b/docs/shared/tutorials/react-monorepo.md @@ -103,7 +103,7 @@ The setup includes.. - ESLint preconfigured - Jest preconfigured -Typically, an integrated Nx workspace places application projects in the `apps` folder and library projects in the `libs` folder. [Applications are encouraged to be as light-weight as possible](/concepts/decisions/applications-and-libraries) so that more code is pushed into libraries and can be reused in other projects. This folder structure is just a suggestion and can be modified to suit your organization's needs. +Typically, an integrated Nx workspace places application projects in the `apps` folder and library projects in the `libs` folder. Applications are encouraged to be as light-weight as possible so that more code is pushed into libraries and can be reused in other projects. This folder structure is just a suggestion and can be modified to suit your organization's needs. The [`nx.json` file](/reference/nx-json) contains configuration settings for Nx itself and global default settings that individual projects inherit. The `apps/react-store/project.json` file contains [settings that are specific to the `react-store` project](/reference/project-configuration). We'll examine that file more in the next section. diff --git a/docs/shared/tutorials/vue-standalone.md b/docs/shared/tutorials/vue-standalone.md index 9619c26f2bdf75..4fc001c179108c 100644 --- a/docs/shared/tutorials/vue-standalone.md +++ b/docs/shared/tutorials/vue-standalone.md @@ -714,7 +714,7 @@ Once you modularize your codebase you want to make sure that the modules are not When building these kinds of constraints you usually have two dimensions: -- **type of project:** what is the type of your library. Example: "feature" library, "utility" library, "data-access" library, "ui" library (see [library types](/concepts/decisions/library-types)) +- **type of project:** what is the type of your library. Example: "feature" library, "utility" library, "data-access" library, "ui" library (see [library types](/concepts/decisions/project-dependency-rules)) - **scope (domain) of the project:** what domain area is covered by the project. Example: "orders", "products", "shared" ... this really depends on the type of product you're developing Nx comes with a generic mechanism that allows you to assign "tags" to projects. "tags" are arbitrary strings you can assign to a project that can be used later when defining boundaries between projects. For example, go to the `project.json` of your `orders` library and assign the tags `type:feature` and `scope:orders` to it. diff --git a/nx-dev/nx-dev/redirect-rules.js b/nx-dev/nx-dev/redirect-rules.js index 4141f35e9bbd28..b5a9f59cee70d4 100644 --- a/nx-dev/nx-dev/redirect-rules.js +++ b/nx-dev/nx-dev/redirect-rules.js @@ -1064,14 +1064,15 @@ const decisionsSection = { '/concepts/more-concepts/why-monorepos': '/concepts/decisions/why-monorepos', '/concepts/more-concepts/dependency-management': '/concepts/decisions/dependency-management', - '/concepts/more-concepts/code-sharing': '/concepts/decisions/code-sharing', + '/concepts/more-concepts/code-sharing': '/concepts/decisions/code-ownership', '/concepts/more-concepts/applications-and-libraries': - '/concepts/decisions/applications-and-libraries', + '/concepts/decisions/project-size', '/concepts/more-concepts/creating-libraries': - '/concepts/decisions/creating-libraries', - '/concepts/more-concepts/library-types': '/concepts/decisions/library-types', + '/concepts/decisions/project-size', + '/concepts/more-concepts/library-types': + '/concepts/decisions/project-dependency-rules', '/concepts/more-concepts/grouping-libraries': - '/concepts/decisions/grouping-libraries', + '/concepts/decisions/folder-structure', }; // Blog post redirects const blogPosts = {