docs(nxdev): remove flavors and versions

This commit is contained in:
ben 2022-01-05 15:32:39 -05:00 committed by Victor Savkin
parent 6dae831e55
commit 9827b5258c
192 changed files with 593 additions and 3931 deletions

View File

@ -9,7 +9,7 @@ Compiles an application into an output directory named dist/ at the given output
## Usage
The `build` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `build` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Builds and serves an app, then runs end-to-end tests using the configured E2E te
## Usage
The `e2e` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `e2e` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Runs linting tools on application code in a given project folder using the confi
## Usage
The `lint` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `lint` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Builds and serves an application, rebuilding on file changes.
## Usage
The `serve` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `serve` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Runs unit tests in a project using the configured unit test runner.
## Usage
The `test` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `test` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Compiles an application into an output directory named dist/ at the given output
## Usage
The `build` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `build` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Builds and serves an app, then runs end-to-end tests using the configured E2E te
## Usage
The `e2e` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `e2e` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Runs linting tools on application code in a given project folder using the confi
## Usage
The `lint` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `lint` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Builds and serves an application, rebuilding on file changes.
## Usage
The `serve` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `serve` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Runs unit tests in a project using the configured unit test runner.
## Usage
The `test` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `test` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Compiles an application into an output directory named dist/ at the given output
## Usage
The `build` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `build` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Builds and serves an app, then runs end-to-end tests using the configured E2E te
## Usage
The `e2e` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `e2e` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Runs linting tools on application code in a given project folder using the confi
## Usage
The `lint` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `lint` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Builds and serves an application, rebuilding on file changes.
## Usage
The `serve` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `serve` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Runs unit tests in a project using the configured unit test runner.
## Usage
The `test` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `test` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Compiles an application into an output directory named dist/ at the given output
## Usage
The `build` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `build` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Builds and serves an app, then runs end-to-end tests using the configured E2E te
## Usage
The `e2e` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `e2e` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Runs linting tools on application code in a given project folder using the confi
## Usage
The `lint` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `lint` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Builds and serves an application, rebuilding on file changes.
## Usage
The `serve` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `serve` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Runs unit tests in a project using the configured unit test runner.
## Usage
The `test` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `test` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -101,34 +101,34 @@ myorg/
## See Also
- [Using DataPersistence](/{{version}}/angular/guides/misc-data-persistence)
- [Using NgRx](/{{version}}/angular/guides/misc-ngrx)
- [Upgrading an AngularJS application to Angular](/{{version}}/angular/guides/misc-upgrade)
- [Using DataPersistence](/guides/misc-data-persistence)
- [Using NgRx](/guides/misc-ngrx)
- [Upgrading an AngularJS application to Angular](/guides/misc-upgrade)
## Executors / Builders
- [delegate-build](/{{framework}}/angular/delegate-build) - Delegates the build to a different target while supporting incremental builds.
- [ng-packagr-lite](/{{framework}}/angular/ng-packagr-lite) - Builds a library with support for incremental builds.
- [package](/{{framework}}/angular/package) - Builds and packages an Angular library to be distributed as an NPM package. It supports incremental builds.
- [webpack-browser](/{{framework}}/angular/webpack-browser) - Builds a browser application with support for incremental builds and custom webpack configuration.
- [delegate-build](/angular/delegate-build) - Delegates the build to a different target while supporting incremental builds.
- [ng-packagr-lite](/angular/ng-packagr-lite) - Builds a library with support for incremental builds.
- [package](/angular/package) - Builds and packages an Angular library to be distributed as an NPM package. It supports incremental builds.
- [webpack-browser](/angular/webpack-browser) - Builds a browser application with support for incremental builds and custom webpack configuration.
## Generators
- [application](/{{framework}}/angular/application) - Creates an Angular application.
- [convert-tslint-to-eslint](/{{framework}}/angular/convert-tslint-to-eslint) - Converts a project from TSLint to ESLint.
- [downgrade-module](/{{framework}}/angular/downgrade-module) - Sets up a Downgrade Module.
- [karma](/{{framework}}/angular/karma) - Adds Karma configuration to a workspace.
- [karma-project](/{{framework}}/angular/karma-project) - Adds Karma configuration to a project.
- [library](/{{framework}}/angular/library) - Creates an Angular library.
- [move](/{{framework}}/angular/move) - Moves an Angular application or library to another folder within the workspace and updates the project configuration.
- [ngrx](/{{framework}}/angular/ngrx) - Adds NgRx support to an application or library.
- [setup-mfe](/{{framework}}/angular/setup-mfe) - Generate a Module Federation configuration for a given Angular application.
- [stories](/{{framework}}/angular/stories) - Creates stories/specs for all components declared in a project.
- [storybook-configuration](/{{framework}}/angular/storybook-configuration) - Adds Storybook configuration to a project.
- [storybook-migrate-defaults-5-to-6](/{{framework}}/angular/storybook-migrate-defaults-5-to-6) - Generates default Storybook configuration files using Storybook version >=6.x specs, for projects that already have Storybook instances and configurations of versions <6.x.
- [storybook-migrate-stories-to-6-2](/{{framework}}/angular/storybook-migrate-stories-to-6-2) - Migrates stories to match the new syntax in v6.2 where the component declaration should be in the default export.
- [upgrade-module](/{{framework}}/angular/upgrade-module) - Sets up an Upgrade Module.
- [web-worker](/{{framework}}/angular/web-worker) - Creates a Web Worker.
- [application](/angular/application) - Creates an Angular application.
- [convert-tslint-to-eslint](/angular/convert-tslint-to-eslint) - Converts a project from TSLint to ESLint.
- [downgrade-module](/angular/downgrade-module) - Sets up a Downgrade Module.
- [karma](/angular/karma) - Adds Karma configuration to a workspace.
- [karma-project](/angular/karma-project) - Adds Karma configuration to a project.
- [library](/angular/library) - Creates an Angular library.
- [move](/angular/move) - Moves an Angular application or library to another folder within the workspace and updates the project configuration.
- [ngrx](/angular/ngrx) - Adds NgRx support to an application or library.
- [setup-mfe](/angular/setup-mfe) - Generate a Module Federation configuration for a given Angular application.
- [stories](/angular/stories) - Creates stories/specs for all components declared in a project.
- [storybook-configuration](/angular/storybook-configuration) - Adds Storybook configuration to a project.
- [storybook-migrate-defaults-5-to-6](/angular/storybook-migrate-defaults-5-to-6) - Generates default Storybook configuration files using Storybook version >=6.x specs, for projects that already have Storybook instances and configurations of versions <6.x.
- [storybook-migrate-stories-to-6-2](/angular/storybook-migrate-stories-to-6-2) - Migrates stories to match the new syntax in v6.2 where the component declaration should be in the default export.
- [upgrade-module](/angular/upgrade-module) - Sets up an Upgrade Module.
- [web-worker](/angular/web-worker) - Creates a Web Worker.
## Public API

View File

@ -4,7 +4,7 @@
In this tutorial you use Nx to build a full-stack application out of common libraries using modern technologies like Cypress and Nest.
> This tutorial uses several Nx plugins to provide a rich dev experience. **All the plugins are optional.** [Read about using Nx Core without plugins](/{{framework}}/getting-started/nx-core).
> This tutorial uses several Nx plugins to provide a rich dev experience. **All the plugins are optional.** [Read about using Nx Core without plugins](/getting-started/nx-core).
## Create a new workspace
@ -130,7 +130,7 @@ Internally, the Nx CLI delegates to the Angular CLI when running commands or gen
produces the same result as `ng serve`, and `nx build` produces the same results as `ng build`. However, the Nx CLI
supports advanced capabilities that aren't supported by the Angular CLI. For instance, Nx's computation cache only
works when using the Nx CLI. In other words, using `nx` instead `ng` results in the same output, but often performs
a lot better. [Read more about Nx CLI and Angular CLI.](/{{framework}}/using-nx/nx-cli)
a lot better. [Read more about Nx CLI and Angular CLI.](/using-nx/nx-cli)
## What's Next

View File

@ -2,7 +2,7 @@
<iframe width="560" height="315" src="https://www.youtube.com/embed/owRAO75DIR4" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture; fullscreen"></iframe>
By default, Nx uses [Cypress](/{{framework}}/cypress/overview) to run E2E tests.
By default, Nx uses [Cypress](/cypress/overview) to run E2E tests.
**Open `apps/todos-e2e/src/support/app.po.ts`.** It's a page object file that contains helpers for querying the page.

View File

@ -126,7 +126,7 @@ import { AppService } from './app.service';
export class AppModule {}
```
We recommend using the [Nest](/{{framework}}/nest/overview) framework when creating node applications. Nest is a powerful framework which helps develop robust node applications. You can also use Express or any node libraries with Nx.
We recommend using the [Nest](/nest/overview) framework when creating node applications. Nest is a powerful framework which helps develop robust node applications. You can also use Express or any node libraries with Nx.
In this case you have an application that registers a service and a controller. Services in Nest are responsible for the business logic, and controllers are responsible for implementing Http endpoints.

View File

@ -63,7 +63,7 @@ And notice the output:
Nx read the output from cache instead of running the command for 1 out of 2 projects.
```
Nx built `api` and retrieved `todos` from its computation cache. Read more about the cache here [here](/{{framework}}/using-nx/caching).
Nx built `api` and retrieved `todos` from its computation cache. Read more about the cache here [here](/using-nx/caching).
> Add --parallel to any command, and Nx does most of the work in parallel.

View File

@ -13,6 +13,6 @@ In this tutorial you:
**Dive Deep:**
- [Nx CLI](/{{framework}}/using-nx/nx-cli)
- [Computation Caching](/{{framework}}/using-nx/caching)
- [Rebuilding What is Affected](/{{framework}}/using-nx/affected)
- [Nx CLI](/using-nx/nx-cli)
- [Computation Caching](/using-nx/caching)
- [Rebuilding What is Affected](/using-nx/affected)

View File

@ -9,7 +9,7 @@ Compiles an application into an output directory named dist/ at the given output
## Usage
The `build` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `build` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Builds and serves an app, then runs end-to-end tests using the configured E2E te
## Usage
The `e2e` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `e2e` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Runs linting tools on application code in a given project folder using the confi
## Usage
The `lint` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `lint` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Builds and serves an application, rebuilding on file changes.
## Usage
The `serve` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `serve` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -9,7 +9,7 @@ Runs unit tests in a project using the configured unit test runner.
## Usage
The `test` command is a built-in alias to the [run command](/{{framework}}/cli/run).
The `test` command is a built-in alias to the [run command](/cli/run).
These two commands are equivalent:

View File

@ -42,7 +42,7 @@ All of the core plugins are written using Nx Devkit, and you can use the same ut
executors.
The Nx team maintains a core set of plugins for many application and tooling frameworks. You can also extend an Nx
workspace by writing your own plugins. The [Nx Plugin](/{{framework}}/nx-plugin/overview) plugin provides guidance on
workspace by writing your own plugins. The [Nx Plugin](/nx-plugin/overview) plugin provides guidance on
how you can build your own custom plugins.
### Listing Nx plugins
@ -63,15 +63,15 @@ Trees(ASTs), and more.
### Pay as you go
As with most things in Nx, the core of Nx Devkit is very simple. It only uses language primitives and immutable
objects (the tree being the only exception). See [Simplest Generator](/{{framework}}/generators/creating-files)
and [Simplest Executor](/{{framework}}/executors/using-builders#simplest-executor) for examples on creating generators
and executors. The [Using Executors](/{{framework}}/executors/using-builders)
and [Using Generators](/{{framework}}/generators/using-schematics) guides also have additional information on executors
objects (the tree being the only exception). See [Simplest Generator](/generators/creating-files)
and [Simplest Executor](/executors/using-builders#simplest-executor) for examples on creating generators
and executors. The [Using Executors](/executors/using-builders)
and [Using Generators](/generators/using-schematics) guides also have additional information on executors
and generators.
## Learn more
- [Using Nx Core Without Plugins](/{{framework}}/getting-started/nx-core)
- [Workspace generators](/{{framework}}/generators/workspace-generators)
- [Workspace executors](/{{framework}}/executors/creating-custom-builders)
- [Using Nx Core Without Plugins](/getting-started/nx-core)
- [Workspace generators](/generators/workspace-generators)
- [Workspace executors](/executors/creating-custom-builders)
- [Nx Community Plugins](/community)

View File

@ -66,11 +66,11 @@ myorg/
## Executors / Builders
- [build](/{{framework}}/gatsby/build) - Builds a Gatsby application
- [server](/{{framework}}/gatsby/server) - Builds and serves a Gatsby application
- [build](/gatsby/build) - Builds a Gatsby application
- [server](/gatsby/server) - Builds and serves a Gatsby application
## Generators
- [application](/{{framework}}/gatsby/application) - Create a Gatsby application
- [component](/{{framework}}/gatsby/component) - Create a Gatsby component
- [page](/{{framework}}/gatsby/page) - Create a Gatsby page
- [application](/gatsby/application) - Create a Gatsby application
- [component](/gatsby/component) - Create a Gatsby component
- [page](/gatsby/page) - Create a Gatsby page

View File

@ -4,19 +4,19 @@
Generators provide a way to automate many tasks you regularly perform as part of your development workflow. Whether it is scaffolding out components, features, ensuring libraries are generated and structured in a certain way, or updating your configuration files, generators help you standardize these tasks in a consistent, and predictable manner.
The [Workspace Generators](/{{framework}}/generators/workspace-generators) guide shows you how to create, run, and customize workspace generators within your Nx workspace.
The [Workspace Generators](/generators/workspace-generators) guide shows you how to create, run, and customize workspace generators within your Nx workspace.
## Types of Generators
There are three main types of generators:
1. **Plugin Generators** are available when an Nx plugin has been installed in your workspace.
2. **Workspace Generators** are generators that you can create for your own workspace. [Workspace generators](/{{framework}}/generators/workspace-generators) allow you to codify the processes that are unique to your own organization.
3. **Update Generators** are invoked by Nx plugins when you [update Nx](/{{framework}}/using-nx/updating-nx) to keep your config files in sync with the latest versions of third party tools.
2. **Workspace Generators** are generators that you can create for your own workspace. [Workspace generators](/generators/workspace-generators) allow you to codify the processes that are unique to your own organization.
3. **Update Generators** are invoked by Nx plugins when you [update Nx](/using-nx/updating-nx) to keep your config files in sync with the latest versions of third party tools.
## Invoking Plugin Generators
Generators allow you to create or modify your codebase in a simple and repeatable way. Generators are invoked using the [`nx generate`](/{{framework}}/cli/generate) command.
Generators allow you to create or modify your codebase in a simple and repeatable way. Generators are invoked using the [`nx generate`](/cli/generate) command.
```bash
nx generate [plugin]:[generator-name] [options]

View File

@ -18,10 +18,10 @@ the boilerplate. The vast majority of the features though will work the same way
These guides will help you get started:
- [Installing Nx CLI & creating a new Nx Workspace](/{{framework}}/getting-started/nx-setup)
- [Adding Nx to an existing monorepo](/{{framework}}/migration/adding-to-monorepo)
- [Using Nx without plugins](/{{framework}}/getting-started/nx-core)
- [Nx and TypeScript](/{{framework}}/getting-started/nx-and-typescript)
- [Installing Nx CLI & creating a new Nx Workspace](/getting-started/nx-setup)
- [Adding Nx to an existing monorepo](/migration/adding-to-monorepo)
- [Using Nx without plugins](/getting-started/nx-core)
- [Nx and TypeScript](/getting-started/nx-and-typescript)
- [Nx and React](/default/getting-started/nx-and-react)
- [Nx and Angular](/default/getting-started/nx-and-angular)
@ -29,27 +29,27 @@ These guides will help you get started:
**Best-in-Class Support for Monorepos**
- [Smart rebuilds of affected projects](/{{framework}}/using-nx/affected)
- [Computation caching](/{{framework}}/using-nx/caching)
- [Distributed task execution](/{{framework}}/using-nx/dte)
- [Code sharing and ownership management](/{{framework}}/structure/monorepo-tags)
- [Smart rebuilds of affected projects](/using-nx/affected)
- [Computation caching](/using-nx/caching)
- [Distributed task execution](/using-nx/dte)
- [Code sharing and ownership management](/structure/monorepo-tags)
**Integrated Development Experience**
- [High-quality editor plugins](/{{framework}}/using-nx/console) & [GitHub apps](https://github.com/apps/nx-cloud)
- [Powerful code generators](/{{framework}}/generators/using-schematics)
- [Workspace visualizations](/{{framework}}/structure/dependency-graph)
- [High-quality editor plugins](/using-nx/console) & [GitHub apps](https://github.com/apps/nx-cloud)
- [Powerful code generators](/generators/using-schematics)
- [Workspace visualizations](/structure/dependency-graph)
**Supports Your Ecosystem**
- [Rich plugin ecosystem](/{{framework}}/getting-started/nx-devkit) from Nrwl and the [community](/community)
- [Rich plugin ecosystem](/getting-started/nx-devkit) from Nrwl and the [community](/community)
- Consistent dev experience for any framework
- [Automatic upgrade to the latest versions of all frameworks and tools](/{{framework}}/using-nx/updating-nx)
- [Automatic upgrade to the latest versions of all frameworks and tools](/using-nx/updating-nx)
## Learn While Doing
- [Using Nx without plugins](/{{framework}}/getting-started/nx-core)
- [Nx and TypeScript](/{{framework}}/getting-started/nx-and-typescript)
- [Using Nx without plugins](/getting-started/nx-core)
- [Nx and TypeScript](/getting-started/nx-and-typescript)
- [React: Interactive Nx Tutorial (with videos)](/default/react-tutorial/01-create-application)
- [Node: Interactive Nx Tutorial (with videos)](/default/node-tutorial/01-create-application)
- [Angular: Interactive Nx Tutorial (with videos)](/default/angular-tutorial/01-create-application)

View File

@ -73,7 +73,7 @@ myorg/
`/libs/` contains the library projects. There are many kinds of libraries, and each library defines its own external API so that boundaries between libraries remain clear.
`/tools/` contains scripts that act on your code base. This could be database scripts, [custom executors](/{{framework}}/executors/creating-custom-builders), or [workspace generators](/{{framework}}/generators/workspace-generators).
`/tools/` contains scripts that act on your code base. This could be database scripts, [custom executors](/executors/creating-custom-builders), or [workspace generators](/generators/workspace-generators).
`/workspace.json` lists every project in your workspace. (this file optional)

View File

@ -61,14 +61,14 @@ For example:
2. `workspaceRoot/apps/my-app/.env` contains `AUTH_URL=https://prod-url.com/auth`
3. Nx will first load the variables from `apps/my-app/.env.local` into the process. When it tries to load the variables from `apps/my-app/.env`, it will notice that `AUTH_URL` already exists, so it will ignore it.
We recommend nesting your **app** specific `env` files in `apps/your-app`, and creating workspace/root level `env` files for workspace-specific settings (like the [Nx Cloud token](/{{framework}}/using-nx/caching#distributed-computation-caching)).
We recommend nesting your **app** specific `env` files in `apps/your-app`, and creating workspace/root level `env` files for workspace-specific settings (like the [Nx Cloud token](/using-nx/caching#distributed-computation-caching)).
### Pointing to custom env files
If you want to load variables from `env` files other than the ones listed above:
1. Use the [env-cmd](https://www.npmjs.com/package/env-cmd) package: `env-cmd -f .qa.env nx serve`
2. Use the `envFile` option of the [run-commands](/{{framework}}/workspace/run-commands-executor#envfile) builder and execute your command inside of the builder
2. Use the `envFile` option of the [run-commands](/workspace/run-commands-executor#envfile) builder and execute your command inside of the builder
## Using Environment Variables in index.html

View File

@ -3,9 +3,9 @@
> In our teams we see a shift away from Lerna and a strong preference to use Nx for managing JavaScript-based monorepos.
> [Thoughtworks Technology Radar 2021](https://www.thoughtworks.com/en-ca/radar/tools/nx)
- Want to know how to create a **new** Nx workspace and use Lerna/Yarn with it, check out [Using Nx Core Without Plugins](/{{framework}}/getting-started/nx-core).
- Want to add Nx to an existing Lerna/Yarn/PNPM mononorepo, check out [Adding Nx to Lerna/Yarn/PNPM/NPM Workspace](/{{framework}}/migration/adding-to-monorepo).
- Want to build a publishable TS/JS library, checkout [Nx and TypeScript](/{{framework}}/getting-started/nx-and-typescript).
- Want to know how to create a **new** Nx workspace and use Lerna/Yarn with it, check out [Using Nx Core Without Plugins](/getting-started/nx-core).
- Want to add Nx to an existing Lerna/Yarn/PNPM mononorepo, check out [Adding Nx to Lerna/Yarn/PNPM/NPM Workspace](/migration/adding-to-monorepo).
- Want to build a publishable TS/JS library, checkout [Nx and TypeScript](/getting-started/nx-and-typescript).
This guide clarifies some misconceptions about how Nx and Lerna/Yarn relate.
@ -60,7 +60,7 @@ published to NPM.
### Misconception: Nx is "all-in"
While Nx does have many plugins, each of them is optional. If you check out [Using Nx Core Without Plugins](/{{framework}}/getting-started/nx-core), you will see that Nx at its core is very minimal. Much like VS Code, Nx is very minimal but can easily be extended by adding plugins. Saying this is akin to saying that VS Code is "all in". The fullness and richness of the experience depends on how many plugins you choose to use. You could install a lot of Nx Plugins that will do a lot of the heavy lifting in, for instance, connecting your Next.js, Storybook and Cypress. You could but you don't have to.
While Nx does have many plugins, each of them is optional. If you check out [Using Nx Core Without Plugins](/getting-started/nx-core), you will see that Nx at its core is very minimal. Much like VS Code, Nx is very minimal but can easily be extended by adding plugins. Saying this is akin to saying that VS Code is "all in". The fullness and richness of the experience depends on how many plugins you choose to use. You could install a lot of Nx Plugins that will do a lot of the heavy lifting in, for instance, connecting your Next.js, Storybook and Cypress. You could but you don't have to.
### Misconception: Nx is configuration over convention

View File

@ -35,7 +35,7 @@ The most common additional options are:
- `syntax` - NgRx introduced new creator functions for actions, reducers, and effects that provide the same type-safety with less code than action classes.
- `facade` - Optional. If you prefer to further encapsulate NgRx from your components, add an injectable facade. See the blog [Better State Management with Facades](https://blog.nrwl.io/nrwl-nx-6-2-angular-6-1-and-better-state-management-e139da2cd074#cb93) for details.
See the [API Docs](/{{framework}}/angular/ngrx) for detailed descriptions of all the available options. Also visit the [NgRx](https://ngrx.io) website for more guides and documentation about the libraries.
See the [API Docs](/angular/ngrx) for detailed descriptions of all the available options. Also visit the [NgRx](https://ngrx.io) website for more guides and documentation about the libraries.
---

View File

@ -2,7 +2,7 @@
![](/shared/nextjs-logo.png)
Nx provides a holistic dev experience powered by an advanced CLI and editor plugins. It provides rich support for common tools like [Cypress](/{{version}}/{{framework}}/cypress/overview), Storybook, Jest, and more.
Nx provides a holistic dev experience powered by an advanced CLI and editor plugins. It provides rich support for common tools like [Cypress](/cypress/overview), Storybook, Jest, and more.
In this guide we will show you how to develop [Next.js](https://nextjs.org/) applications with Nx.
@ -105,8 +105,8 @@ 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 dep-graph`
For more information on Nx libraries, see our documentation on [Creating Libraries](/{{version}}/{{framework}}/structure/creating-libraries)
and [Library Types](/{{version}}/{{framework}}/structure/library-types).
For more information on Nx libraries, see our documentation on [Creating Libraries](/structure/creating-libraries)
and [Library Types](/structure/library-types).
To generate a new library run:

View File

@ -147,7 +147,7 @@ Nx is still able to pick those up natively, so you can still run `nx build mylib
Nx doesnt provide an out of the box process for the publishing itself and leaves it to the developer to invoke the final command. The reason is that the actual publishing process can be very specific to your project and target you deploy to and might have a lot of custom pre-deployment setup (e.g. generating changelogs, determining semver etc.). Make sure to check out our [community page](/community) as there are a lot of community provided packages integrating into the publishing process.
However, integrating your custom publishing process with Nx can be pretty straightforward, especially with the help of Nx [run-commands](/{{framework}}/executors/run-commands-builder) and [“Target Dependencies”](/{{framework}}/configuration/projectjson#dependson).
However, integrating your custom publishing process with Nx can be pretty straightforward, especially with the help of Nx [run-commands](/executors/run-commands-builder) and [“Target Dependencies”](/configuration/projectjson#dependson).
To add a new run-command to our project, we can leverage the `run-command` generator:
@ -204,4 +204,4 @@ We can however even automate this further by leveraging the `targetDependencies`
}
```
Now, just running `nx publish hello-tsc` will automatically run the `nx build hello-tsc` command first. And of course, if `build` has already run, it won't execute again, thanks to [Nx computation caching](/{{framework}}/using-nx/caching).
Now, just running `nx publish hello-tsc` will automatically run the `nx build hello-tsc` command first. And of course, if `build` has already run, it won't execute again, thanks to [Nx computation caching](/using-nx/caching).

View File

@ -1,6 +1,6 @@
# Nx Devkit and Angular Devkit
> Note: this document covers the difference between Nx Devkit and Angular Devkit. See the [Nx Devkit](/{{framework}}/getting-started/nx-devkit) guide for more in-depth details about Nx Devkit.
> Note: this document covers the difference between Nx Devkit and Angular Devkit. See the [Nx Devkit](/getting-started/nx-devkit) guide for more in-depth details about Nx Devkit.
Nx comes with a devkit to write generators and executors, but you can also use Angular devkit (schematics and builders). In other words, you can use an Angular schematic to implement a generator, and you can use an Angular builder to implement an executor.
@ -183,7 +183,7 @@ export default createBuilder<NextBuildBuilderOptions>(run);
### Notable Differences
- Nx Devkit executors return a Promise (or async iterable). If you want, you can always convert an observable to a promise or an async iterable. See [Using Rxjs Observables](/{{framework}}/executors/using-builders#using-rxjs-observables)
- Nx Devkit executors return a Promise (or async iterable). If you want, you can always convert an observable to a promise or an async iterable. See [Using Rxjs Observables](/executors/using-builders#using-rxjs-observables)
- Nx Devkit executors do not have to be wrapped using `createBuilder`.
The schema files for both Nx Devkit executors and Angular Builders are the same. Nx can run both of them in the same way.

View File

@ -77,7 +77,7 @@ If you want to learn more, check out our article on [Distributing CI - Binning a
All the available Nx commands can be executed via the command line. But as your monorepo grows, with multiple teams and hundreds of projects, even just finding the project to run a command against can sometimes be difficult. Having a high quality IDE integration can be a time saver there.
- Nx has [VSCode](https://nx.dev/l/r/using-nx/console) and WebStorm/Intellij plugins.
- Nx has [VSCode](https://nx.dev/using-nx/console) and WebStorm/Intellij plugins.
- Turborepo doesnt have any plugins, and the maintainer has indicated there's no intention to provide editor support.
Learn more [by watching this Egghead lesson](https://egghead.io/lessons/javascript-generate-new-projects-for-nx-with-nx-console).
@ -125,7 +125,7 @@ At this point, Turborepo doesnt do any of that. So for a monorepo of any non-
Nx is like the **VSCode of build tools**. In VSCode you can get started with the plain, core VSCode setup and it would be fine. But if you want to enhance your experience, there's the option to add extensions for managing Git, Docker, Mongo etc. Similarly, **you dont have to use all the Nx plugins or, say, the Nx Cloud GitHub integration.**
Nx doesnt replace any of your tools, and its not “all in”. You can start without any Nx plugins and Nx Cloud affordances, as with Turborepo. Or you can add them in as you go, both natively supported plugins by Nx as well as our growing [set of community plugins](https://nx.dev/community). **Turborepo isnt pluggable**, so if you use the same analogy, you would have to use different tools (GitTower, DataGrip, Mongo Compass) to meet the same needs.
Read [this guide](https://nx.dev/l/r/getting-started/nx-core) to learn more about how to only use Nx Core.
Read [this guide](https://nx.dev/getting-started/nx-core) to learn more about how to only use Nx Core.
## Tech and Performance

View File

@ -2,7 +2,7 @@
A monorepo is a single git repository that holds the source code for multiple applications and libraries, along with the tooling for them.
> If you are familiar with Lerna or Yarn workspaces, check out [this guide](/{{framework}}/guides/lerna-and-nx) (with a quick video) showing how to add Nx to a Lerna/Yarn workspace, what the difference is, when to use both and when to use just Nx.
> If you are familiar with Lerna or Yarn workspaces, check out [this guide](/guides/lerna-and-nx) (with a quick video) showing how to add Nx to a Lerna/Yarn workspace, what the difference is, when to use both and when to use just Nx.
## What are the benefits of a monorepo?
@ -36,7 +36,7 @@ Nx provides tools to give you the benefits of a monorepo without the drawbacks o
- **Consistent Code Generation** - Generators allow you to customize and standardize organizational conventions and structure, removing the need to perform the same manual setup tasks repetitively.
- **Affected Commands** - [Nxs affected commands](/{{framework}}/cli/affected) analyze your source code, the context of the changes, and only runs tasks on the affected projects impacted by the source code changes.
- **Affected Commands** - [Nxs affected commands](/cli/affected) analyze your source code, the context of the changes, and only runs tasks on the affected projects impacted by the source code changes.
- **Distributed Caching** - Nx provides local caching and support for distributed caching of command executions. With distributed caching, when someone on your team runs a command, everyone else gets access to those artifacts to speed up their command executions, bringing them down from minutes to seconds. Nx helps you scale your development to massive applications and libraries even more with distributed task execution and incremental builds.

View File

@ -27,7 +27,7 @@ On the other hand, the executor of a **buildable library**, performs a subset of
nx g @nrwl/react:lib mylib --buildable
```
Read more about [Publishable and Buildable Nx Libraries here.](/{{framework}}/structure/buildable-and-publishable-libraries)
Read more about [Publishable and Buildable Nx Libraries here.](/structure/buildable-and-publishable-libraries)
## Nx computation cache and Nx Cloud

View File

@ -21,7 +21,7 @@ Watch this 3-min video to see how the command works and what next steps are:
3. Set up a `tsconfig` file mapping if needed.
4. Set up Nx Cloud (if you chose "yes").
> If you are familiar with Turborepo, check out [this guide](/{{framework}}/guides/turbo-and-nx). At this point, Nx can do anything Turbo can, and much more.
> If you are familiar with Turborepo, check out [this guide](/guides/turbo-and-nx). At this point, Nx can do anything Turbo can, and much more.
## What You Get Right Away
@ -58,7 +58,7 @@ commands you run. They don't preserve animations and colors. We instrument Node.
as is. When running, say, an npm script via Nx, the output will not be modified. The same is true when Nx restores the
output from cache.
[Learn about computation caching.](/{{framework}}/using-nx/caching)
[Learn about computation caching.](/using-nx/caching)
### Distributed Task Execution
@ -79,7 +79,7 @@ outputs as if it ran it locally.
**Using Distributed Task Execution you can keep your CI fast, with practically no effort, regardless of the size of your
workspace.**
[Learn more distributed task execution.](/{{framework}}/using-nx/dte)
[Learn more distributed task execution.](/using-nx/dte)
### Affected Commands
@ -87,7 +87,7 @@ Nx automatically analyzes your workspace to know what projects are affected by y
run: `nx affected --target=test` to see it in action. Often, Nx is able to do a better job detecting affected than other
tools because it looks not just at the changed files but also at the nature of the changes.
[Learn more "affected".](/{{framework}}/using-nx/affected)
[Learn more "affected".](/using-nx/affected)
### Workspace Visualization
@ -153,7 +153,7 @@ Nx + Lerna:
}
```
[Learn more about Nx CLI.](/{{framework}}/using-nx/nx-cli)
[Learn more about Nx CLI.](/using-nx/nx-cli)
## Next Steps

View File

@ -25,7 +25,7 @@ Select `empty` when prompted:
## Exploring your workspace
Take a tour of your [Nx workspace](/{{framework}}/getting-started/nx-setup). There are some important areas to know about as you migrate.
Take a tour of your [Nx workspace](/getting-started/nx-setup). There are some important areas to know about as you migrate.
### apps
@ -57,10 +57,10 @@ nx generate @nrwl/react:application my-application
There are a lot of options when creating your application. If you want to follow Nx recommendations, you can accept the defaults. If you have a well-established codebase, you can configure those options at the time of application generation. You can find documentation for these options for the different frameworks here:
- [Angular](/{{framework}}/angular/application)
- [React](/{{framework}}/react/application)
- [Angular](/angular/application)
- [React](/react/application)
You may also find it useful to use the [Nx Console](/{{framework}}/using-nx/console) in Visual Studio Code. This will give you a visual way to generate your application with all of the options laid out in front of you.
You may also find it useful to use the [Nx Console](/using-nx/console) in Visual Studio Code. This will give you a visual way to generate your application with all of the options laid out in front of you.
### Configuration files
@ -72,11 +72,11 @@ In general, you should not replace the configuration files provided for you. You
In addition to configuration files for external libraries, your Nx workspace will have configuration files for Nx itself. This will be `angular.json` for workspaces using the Angular CLI and `workspace.json` for workspaces using the Nx CLI. This file will define all of the individual projects in your workspace (of which your application is one) and the tasks available for them.
For example, your generated application should have four [tasks available](/{{framework}}/executors/using-builders) for it: `build`, `serve`, `lint`, and `test`. Each of these comes with its own configuration. If you find you need to adjust the configuration of a task for your codebase, this is the place to begin looking.
For example, your generated application should have four [tasks available](/executors/using-builders) for it: `build`, `serve`, `lint`, and `test`. Each of these comes with its own configuration. If you find you need to adjust the configuration of a task for your codebase, this is the place to begin looking.
These workspace configuration files can seem a little long and intimidating. The Nx Console can help you navigate it more easily with its Workspace JSON panel. By clicking on a project in your workspace, it will navigate you to the right place in the workspace file to begin making edits.
Additionally, there is an `nx.json` file that contains metadata about your projects. [This metadata includes tags](/{{framework}}/structure/monorepo-tags) that can help you impose constraints on your applications and library dependencies.
Additionally, there is an `nx.json` file that contains metadata about your projects. [This metadata includes tags](/structure/monorepo-tags) that can help you impose constraints on your applications and library dependencies.
## Migrating your code
@ -106,7 +106,7 @@ nx serve my-application
If this doesnt work for you, you may need to add or modify some configuration on the `build` task in your workspace configuration file.
[Learn more about local serving](/{{framework}}/cli/serve)
[Learn more about local serving](/cli/serve)
### Unit tests
@ -120,7 +120,7 @@ It is recommended that unit tests live next to the code they exercise and code s
Testing configuration files can be found in the root of your application as well as the workspace configuration file.
[Learn more about unit testing](/{{framework}}/cli/test)
[Learn more about unit testing](/cli/test)
### End to End Tests
@ -132,7 +132,7 @@ nx e2e my-application-e2e
All of the configuration for your e2e tests should be in this directory.
[Learn more about end-to-end testing](/{{framework}}/cli/e2e)
[Learn more about end-to-end testing](/cli/e2e)
### Linting
@ -152,7 +152,7 @@ nx lint my-application
Global configuration files for linting will be at the root of your workspace. Each application and library will extend those configuration files. Global configuration changes should be made in the root, while application-or-library-specific changes should occur in the application or library configuration files.
[Learn more about linting](/{{framework}}/cli/lint)
[Learn more about linting](/cli/lint)
### Formatting
@ -162,19 +162,19 @@ Nx uses Prettier to ensure standard formatting across your codebase. Prettier co
nx format:write
```
[Learn more about formatting](/{{framework}}/cli/format-write)
[Learn more about formatting](/cli/format-write)
### Adding tasks
Nx offers built-in tasks for the most common needs: `serve`, `build`, `test`, `e2e`, and `lint`. You likely have additional tasks that are needed to manage or deploy your codebase. These tasks might include deployment, i18n workflows, or uploading assets to CDNs. These tasks can be set up as scripts that you run manually with node, ts-node, or npm scripts. You can migrate those tasks over as-is, to begin with.
You should consider implementing them as Nx tasks which should be a quick transition with the `run-commands` builder. [The `run-commands` builder](/{{framework}}/executors/run-commands-builder) will allow you to run any custom commands you need as an Nx task. By implementing these commands in an Nx task, they are able to take advantage of the dependency graph in Nx and only run when necessary. They are also able to be cached and only be re-run when necessary.
You should consider implementing them as Nx tasks which should be a quick transition with the `run-commands` builder. [The `run-commands` builder](/executors/run-commands-builder) will allow you to run any custom commands you need as an Nx task. By implementing these commands in an Nx task, they are able to take advantage of the dependency graph in Nx and only run when necessary. They are also able to be cached and only be re-run when necessary.
Your use-case may also be covered by one of our community plugins. Plugin authors are able to extend the functionality of Nx through our plugin API.
[Learn more about the `run-commands` builder](/{{framework}}/workspace/run-commands-executor)
[Learn more about the `run-commands` builder](/workspace/run-commands-executor)
[Learn more about caching](/{{framework}}/using-nx/caching)
[Learn more about caching](/using-nx/caching)
[Learn more about community plugins](/community)
@ -200,4 +200,4 @@ Its important to remember: dont just drop your code anywhere! Always gener
If youre consolidating multiple repositories or libraries into a single Nx workspace, you may have concerns about code boundaries. Previously, you may have had well-established boundaries by separating code into different repositories or having a public API for a library. Nx features a tagging system that allows you to enforce these code boundaries in a granular way. Each project can be tagged, and you can constrain dependencies based on these tags.
[Learn more about tags and dependency constraints](/{{framework}}/structure/monorepo-tags)
[Learn more about tags and dependency constraints](/structure/monorepo-tags)

View File

@ -90,10 +90,10 @@ Your workspace is now powered by Nx! You can verify out that your application st
Learn more about the advantages of Nx in the following guides:
- [Using Cypress for e2e tests](/{{framework}}/cypress/overview)
- [Using Jest for unit tests](/{{framework}}/jest/overview)
- [Computation Caching](/{{framework}}/using-nx/caching)
- [Rebuilding and Retesting What is Affected](/{{framework}}/using-nx/affected)
- [Using Cypress for e2e tests](/cypress/overview)
- [Using Jest for unit tests](/jest/overview)
- [Computation Caching](/using-nx/caching)
- [Rebuilding and Retesting What is Affected](/using-nx/affected)
## Transitioning Manually
@ -374,6 +374,6 @@ yarn lint
Learn more about the advantages of Nx in the following guides:
[Using Cypress for e2e tests](/{{framework}}/cypress/overview) \
[Using Jest for unit tests](/{{framework}}/jest/overview) \
[Rebuilding and Retesting What is Affected](/{{framework}}/using-nx/affected)
[Using Cypress for e2e tests](/cypress/overview) \
[Using Jest for unit tests](/jest/overview) \
[Rebuilding and Retesting What is Affected](/using-nx/affected)

View File

@ -371,7 +371,7 @@ But migrating AngularJS code means we need to switch some of our tools to a more
npm install -D @nrwl/web babel-plugin-angularjs-annotate
```
Nx already has most of what you need for webpack added as a dependency. `@nrwl/web` contains the [executors](/{{version}}/{{framework}}/executors/using-builders) we need to use to build and serve the application with webpack and
Nx already has most of what you need for webpack added as a dependency. `@nrwl/web` contains the [executors](/executors/using-builders) we need to use to build and serve the application with webpack and
`babel-plugin-angularjs-annotate` is going to accomplish the same thing that `browserify-ngannotate` previously did in gulp: add dependency injection annotations.
Start with a `webpack.config.js` file in your applications root directory:

View File

@ -6,7 +6,7 @@ You can either use a CLI tool to migrate your app automatically, or you can foll
**Note:** This guide has been updated for Nx 13 and may not work for earlier versions of Nx.
If you have a monorepo (more than one project in the same repo), follow the [Adding Nx to Lerna/Yarn/PNPM/NPM Workspace](https://nx.dev/l/r/migration/adding-to-monorepo) guide instead.
If you have a monorepo (more than one project in the same repo), follow the [Adding Nx to Lerna/Yarn/PNPM/NPM Workspace](https://nx.dev/migration/adding-to-monorepo) guide instead.
## Using a tool that will do it for you
@ -18,8 +18,8 @@ Just `cd` into your Create-React-App (CRA) project and run the following command
npx cra-to-nx
```
Then just sit back and wait. After a while, take advantage of the [full magic of Nx](https://nx.dev/l/r/getting-started/intro).
Start from [the commands mentioned in this article](https://nx.dev/l/r/migration/migration-cra#try-nx).
Then just sit back and wait. After a while, take advantage of the [full magic of Nx](https://nx.dev/getting-started/intro).
Start from [the commands mentioned in this article](https://nx.dev/migration/migration-cra#try-nx).
**Note:** The command will fail if you try execute it and you have uncommitted changes in your repository. Commit any local changes, and then try to run the command.

View File

@ -36,4 +36,4 @@ Note that for these files, the file history of the standalone project will be no
## Using `git mv`
If your standalone project was not an Nx workspace, it's likely that your migration work will also entail moving directories to match a typical Nx Workspace structure. You can find more information in the [Manual migration](/{{framework}}/migration/manual) page, but when migrating an existing project, you'll want to ensure that you use [`git mv`](https://git-scm.com/docs/git-mv) when moving a file or directory to ensure that file history from the old standalone repo is not lost!
If your standalone project was not an Nx workspace, it's likely that your migration work will also entail moving directories to match a typical Nx Workspace structure. You can find more information in the [Manual migration](/migration/manual) page, but when migrating an existing project, you'll want to ensure that you use [`git mv`](https://git-scm.com/docs/git-mv) when moving a file or directory to ensure that file history from the old standalone repo is not lost!

View File

@ -136,7 +136,7 @@ For a large organization it's crucial to establish how projects can depend on ea
- Libraries with a broader scope (e.g., `shared/ui`) should not depend on the libraries with narrower scope (e.g., `happynrwlapp/search/utils-testing`).
- Component libraries should only depend on other component libraries and utility libraries, but should not depend feature libraries.
Nx provides a feature called tags that can be used to codify and statically-enforce these rules. Read more about tags [here](/{{framework}}/structure/monorepo-tags).
Nx provides a feature called tags that can be used to codify and statically-enforce these rules. Read more about tags [here](/structure/monorepo-tags).
## Code Ownership
@ -188,7 +188,7 @@ Note `all the projects affected by a PR/commit`. This is very important. Monorep
- The performance of CI checks will degrade over time. The time it takes to run the CI checks should be proportional to the impact of the change, not the size of the repo.
- We will be affected by the code your change didnt touch
We should utilize `affected:*` commands to build and test projects. Read more about them [here](/{{framework}}/cli/affected).
We should utilize `affected:*` commands to build and test projects. Read more about them [here](/cli/affected).
### Trunk-based development

View File

@ -6,4 +6,4 @@ The Nx Plugin for Next.js contains executors and generators for managing Next.js
- Integration with building, serving, and exporting a Next.js application.
- Integration with React libraries within the workspace.
See the [Next.js guide](/{{version}}/react/guides/nextjs) for information about using Next.js and Nx.
See the [Next.js guide](/guides/nextjs) for information about using Next.js and Nx.

View File

@ -4,7 +4,7 @@
In this tutorial you use Nx to build a server application out of common libraries using modern technologies.
> This tutorial uses several Nx plugins to provide a rich dev experience. **All the plugins are optional.** [Read about using Nx Core without plugins](/{{framework}}/getting-started/nx-core).
> This tutorial uses several Nx plugins to provide a rich dev experience. **All the plugins are optional.** [Read about using Nx Core without plugins](/getting-started/nx-core).
## Create a New Workspace

View File

@ -13,6 +13,6 @@ In this tutorial you:
**Dive Deep:**
- [Nx CLI](/{{framework}}/using-nx/nx-cli)
- [Computation Caching](/{{framework}}/using-nx/caching)
- [Rebuilding What is Affected](/{{framework}}/using-nx/affected)
- [Nx CLI](/using-nx/nx-cli)
- [Computation Caching](/using-nx/caching)
- [Rebuilding What is Affected](/using-nx/affected)

View File

@ -156,7 +156,7 @@ Finally, run `yarn`.
The example uses Yarn to connect the two packages. Most of the time, however, there are better ways to do it. The React,
Node, Angular plugins for Nx allow different projects in your workspace to import each other without having to maintain
cumbersome `package.json` files. Instead, they use Webpack, Rollup and Jest plugins to enable this use case in a more
elegant way. [Read about the relationship between Nx and Yarn/Lerna/PNPM](/{{framework}}/guides/lerna-and-nx).
elegant way. [Read about the relationship between Nx and Yarn/Lerna/PNPM](/guides/lerna-and-nx).
## What Nx Core Provides

View File

@ -4,7 +4,7 @@ Nx plugins are npm packages that contain generators and executors to extend a Nx
> A list of plugins that is maintained by Nrwl is found in the [Nrwl/nx repo](https://github.com/nrwl/nx/tree/master/packages). \
> A list of custom plugins created by the community is found in the [Community](/community) section.
> Plugins are written using Nx Devkit. **Read [Nx Devkit](/{{framework}}/getting-started/nx-devkit) for more information.**
> Plugins are written using Nx Devkit. **Read [Nx Devkit](/getting-started/nx-devkit) for more information.**
<iframe width="560" height="315" src="https://www.youtube.com/embed/fC1-4fAZDP4" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture; fullscreen"></iframe>

View File

@ -69,22 +69,22 @@ myorg/
## See Also
- [Using Cypress](/{{framework}}/cypress/overview)
- [Using Jest](/{{framework}}/jest/overview)
- [Using Cypress](/cypress/overview)
- [Using Jest](/jest/overview)
- [Using Storybook](/default/storybook/overview-react)
## Executors / Builders
React applications are built using the executors from the `@nrwl/web` plugin.
- [build](/{{framework}}/web/build) - Builds a web components application
- [dev-server](/{{framework}}/web/package) - Builds and serves a web application
- [package](/{{framework}}/web/package) - Bundles artifacts for a buildable library that can be distributed as an NPM package.
- [build](/web/build) - Builds a web components application
- [dev-server](/web/package) - Builds and serves a web application
- [package](/web/package) - Bundles artifacts for a buildable library that can be distributed as an NPM package.
## Generators
- [application](/{{framework}}/react/application) - Create an React application
- [component](/{{framework}}/react/component) - Create an React component
- [library](/{{framework}}/react/library) - Create an React library
- [redux](/{{framework}}/react/redux) - Generate a Redux slice for a project
- [storybook-configuration](/{{framework}}/react/storybook-configuration) - Set up Storybook for a react library
- [application](/react/application) - Create an React application
- [component](/react/component) - Create an React component
- [library](/react/library) - Create an React library
- [redux](/react/redux) - Generate a Redux slice for a project
- [storybook-configuration](/react/storybook-configuration) - Set up Storybook for a react library

View File

@ -4,9 +4,9 @@
In this tutorial you use Nx to build a full-stack application out of common libraries using modern technologies.
> Next.js: Nx also has first-class Next.js support. Read more about it [here](/{{framework}}/next/overview)
> Next.js: Nx also has first-class Next.js support. Read more about it [here](/next/overview)
> This tutorial uses several Nx plugins to provide a rich dev experience. **All the plugins are optional.** [Read about using Nx Core without plugins](/{{framework}}/getting-started/nx-core).
> This tutorial uses several Nx plugins to provide a rich dev experience. **All the plugins are optional.** [Read about using Nx Core without plugins](/getting-started/nx-core).
## Create a new workspace

View File

@ -71,6 +71,6 @@ Options:
--help Show available options for project target.
```
It helps with good editor integration (see [VSCode Support](/{{framework}}/using-nx/console#nx-console-for-vscode)).
It helps with good editor integration (see [VSCode Support](/using-nx/console#nx-console-for-vscode)).
But, most importantly, it provides a holistic dev experience regardless of the tools used, and enables advanced build features like distributed computation caching and distributed builds.

View File

@ -52,6 +52,6 @@ Based on the state of the source code and the environment, Nx figured out that i
Nx read the output from cache instead of running the command for 1 out of 2 projects.
```
Nx built `api` and retrieved `todos` from its computation cache. Read more about the cache [here](/{{framework}}/using-nx/caching).
Nx built `api` and retrieved `todos` from its computation cache. Read more about the cache [here](/using-nx/caching).
> Add --parallel to any command, and Nx does most of the work in parallel.

View File

@ -13,6 +13,6 @@ In this tutorial you:
**Dive Deep:**
- [Nx CLI](/{{framework}}/using-nx/nx-cli)
- [Computation Caching](/{{framework}}/using-nx/caching)
- [Rebuilding What is Affected](/{{framework}}/using-nx/affected)
- [Nx CLI](/using-nx/nx-cli)
- [Computation Caching](/using-nx/caching)
- [Rebuilding What is Affected](/using-nx/affected)

View File

@ -42,7 +42,7 @@ For each project for which you want to enable `make`, add a target in `workspace
}
```
For more information, see the [run-commands api doc](/{{framework}}/workspace/run-commands-executor).
For more information, see the [run-commands api doc](/workspace/run-commands-executor).
##### 3. Trigger the executor from the terminal
@ -58,4 +58,4 @@ To run the executor for all affected projects:
nx affected --target=make
```
For more information, see the [nx affected](/{{framework}}/cli/affected).
For more information, see the [nx affected](/cli/affected).

View File

@ -59,7 +59,7 @@ Each executor definition has an `executor` property and, optionally, an `options
## Running executors
The [`nx run`](/{{framework}}/cli/run) cli command (or the shorthand versions) can be used to run executors.
The [`nx run`](/cli/run) cli command (or the shorthand versions) can be used to run executors.
```bash
nx run [project]:[command]
@ -245,7 +245,7 @@ The `runExecutor` utility will find the target in the configuration, find the ex
- `readTargetOptions` -- Reads and combines options for a given target.
- `runExecutor` -- Constructs options and invokes an executor.
See more helper functions in the [Devkit API Docs](/{{framework}}/nx-devkit/index#functions)
See more helper functions in the [Devkit API Docs](/nx-devkit/index#functions)
## Using RxJS observables
@ -274,5 +274,5 @@ export default async function (opts) {
## See Also
- [`nx affected`](/{{framework}}/cli/affected)
- [`nx run-many`](/{{framework}}/cli/run-many)
- [`nx affected`](/cli/affected)
- [`nx run-many`](/cli/run-many)

View File

@ -1,6 +1,6 @@
# Affected
> Before reading this guide, check out the [mental model guide](/{{framework}}/using-nx/mental-model). It will help you understand how computation caching fits into the rest of Nx.
> Before reading this guide, check out the [mental model guide](/using-nx/mental-model). It will help you understand how computation caching fits into the rest of Nx.
## Overview

View File

@ -1,6 +1,6 @@
# Computation Caching
> Before reading this guide, check out the [mental model guide](/{{framework}}/using-nx/mental-model). It will help you understand how computation caching fits into the rest of Nx.
> Before reading this guide, check out the [mental model guide](/using-nx/mental-model). It will help you understand how computation caching fits into the rest of Nx.
## Overview

View File

@ -1,6 +1,6 @@
# Distributed Task Execution
> Before reading this guide, check out the [mental model guide](/{{framework}}/using-nx/mental-model). It will help you understand how computation caching fits into the rest of Nx.
> Before reading this guide, check out the [mental model guide](/using-nx/mental-model). It will help you understand how computation caching fits into the rest of Nx.
## Overview

View File

@ -16,7 +16,7 @@ Run the `nx help` command to see a full list of commands in the Nx CLI.
## Acting on Code
The [`nx run` command](/{{framework}}/cli/run) executes a target on a single project. For convenience, you can also
The [`nx run` command](/cli/run) executes a target on a single project. For convenience, you can also
run `nx [target] [project]` which is an alias to `nx run [project]:[target]`.
```bash
@ -28,21 +28,21 @@ nx build my-js-app
However, `nx build` is only an abstraction over what it means to "build" projects rather than tied to a certain
implementation. For instance, if you have a `project.json` file defining `build` using
a **[executor](/{{framework}}/executors/using-builders)**, that executor will be invoked. If you don't specify an
a **[executor](/executors/using-builders)**, that executor will be invoked. If you don't specify an
executor for the build target, `nx build my-react-app` will invoke the `build` npm script in the project's folder. Every
argument you pass into `run` will be forwarded to the executor or the npm script.
Along with running a target on a single project, Nx provides some commands to run the same target across multiple
projects.
The [`nx run-many` command](/{{framework}}/cli/run-many) runs the same target name across a list of projects.
The [`nx run-many` command](/cli/run-many) runs the same target name across a list of projects.
```bash
nx run-many --target=build --projects=app1,app2
nx run-many --target=test --all # Runs all projects that have a test target, use this sparingly.
```
The [`nx affected` command](/{{framework}}/cli/affected) isolates set projects that may have changed in behavior and
The [`nx affected` command](/cli/affected) isolates set projects that may have changed in behavior and
runs a target across them. This is more efficient than running all projects every time.
```bash
@ -51,7 +51,7 @@ nx affected --target=build
## Modifying Code
The [`nx generate` command](/{{framework}}/cli/generate) generates and modifies code.
The [`nx generate` command](/cli/generate) generates and modifies code.
```bash
nx generate @nrwl/js:lib my-lib
@ -60,12 +60,12 @@ nx generate @nrwl/react:storybook-configuration shared-button # Configures story
```
Again, like `nx run`, `nx generate` is only an abstraction over generating code. `nx generate` can generate anything you
want via **generators**. **[Generators](/{{framework}}/generators/using-schematics)** can be installed as part of a
want via **generators**. **[Generators](/generators/using-schematics)** can be installed as part of a
plugin or developed locally within an Nx workspace to fit the needs of your organization.
A [Workspace Generator](/{{framework}}/generators/workspace-generators) is custom generator for your
A [Workspace Generator](/generators/workspace-generators) is custom generator for your
workspace. `nx generate workspace-generator my-generator` generates a workspace generator which can be run with
the [`nx workspace-generator` command](/{{framework}}/cli/workspace-generator). This can be useful to allow your
the [`nx workspace-generator` command](/cli/workspace-generator). This can be useful to allow your
organization to consistently generate projects according to your own standards.
```bash
@ -73,9 +73,9 @@ nx workspace-generator my-generator
```
Upgrading a package is not always as simple as bumping the version in `package.json`.
The [`nx migrate` command](/{{framework}}/cli/migrate) facilitates not only managing package versions but also runs
The [`nx migrate` command](/cli/migrate) facilitates not only managing package versions but also runs
migrations specified by package maintainers. See
the [full guide to updating Nx](/{{framework}}/using-nx/updating-nx).
the [full guide to updating Nx](/using-nx/updating-nx).
```bash
nx migrate latest # Updates the version of Nx in `package.json` and schedules migrations to be run
@ -85,11 +85,11 @@ nx migrate --run-migrations # Runs the migrations scheduled by the previous comm
## Understanding the codebase
Nx creates and maintains a dependency graph between projects based on import statements in your code and uses that
information to run executors only on the [affected](/{{framework}}/cli/affected) projects in a codebase. A visual
version of the [dependency graph](/{{framework}}/structure/dependency-graph) is also available to help developers
information to run executors only on the [affected](/cli/affected) projects in a codebase. A visual
version of the [dependency graph](/structure/dependency-graph) is also available to help developers
understand the architecture of the codebase.
The [`nx dep-graph` command](/{{framework}}/cli/dep-graph) displays this dependency graph in a web browser for you to
The [`nx dep-graph` command](/cli/dep-graph) displays this dependency graph in a web browser for you to
explore.
```bash
@ -98,7 +98,7 @@ nx dep-graph --watch # Updates the browser as code is changed
nx affected:dep-graph # Highlights projects which may have changed in behavior
```
The [`nx list` command](/{{framework}}/cli/list) lists the currently installed Nx plugins and other available plugins.
The [`nx list` command](/cli/list) lists the currently installed Nx plugins and other available plugins.
The `nx list` command can list the generators and executors that are available for a plugin.
**List installed plugins:**

View File

@ -68,15 +68,15 @@ myorg/
## See Also
- [Using Cypress](/{{framework}}/cypress/overview)
- [Using Jest](/{{framework}}/cypress/overview)
- [Using Cypress](/cypress/overview)
- [Using Jest](/cypress/overview)
## Executors / Builders
- [build](/{{framework}}/web/build) - Builds a web components application
- [dev-server](/{{framework}}/web/dev-server) - Builds and serves a web application
- [package](/{{framework}}/web/package) - Bundles artifacts for a buildable library that can be distributed as an NPM package.
- [build](/web/build) - Builds a web components application
- [dev-server](/web/dev-server) - Builds and serves a web application
- [package](/web/package) - Bundles artifacts for a buildable library that can be distributed as an NPM package.
## Generators
- [application](/{{framework}}/web/application) - Create an Web Components application
- [application](/web/application) - Create an Web Components application

View File

@ -4,12 +4,12 @@ The workspace plugin contains executors and generators that are useful for any N
## Generators
- [library](/{{framework}}/workspace/library) - Create a plain typescript library
- [move](/{{framework}}/workspace/move) - Move a project to another directory and update all references
- [remove](/{{framework}}/workspace/remove) - Remove a project from the workspace
- [run-commands](/{{framework}}/workspace/run-commands-executor) - Add a target to a project that uses the run-commands executor
- [workspace-generator](/{{framework}}/workspace/workspace-generator) - Scaffold a custom generator for use within your workspace
- [library](/workspace/library) - Create a plain typescript library
- [move](/workspace/move) - Move a project to another directory and update all references
- [remove](/workspace/remove) - Remove a project from the workspace
- [run-commands](/workspace/run-commands-executor) - Add a target to a project that uses the run-commands executor
- [workspace-generator](/workspace/workspace-generator) - Scaffold a custom generator for use within your workspace
## Executors / Builders
- [run-commands](/{{framework}}/workspace/run-commands-executor) - Execute an arbitrary command line script
- [run-commands](/workspace/run-commands-executor) - Execute an arbitrary command line script

View File

@ -17,7 +17,7 @@ One typical scenario for this may be that you use Nx to develop your organizatio
A normal Nx library - lets call it "workspace library" - is not made for building or publishing. Rather it only includes common lint and test targets in its `angular.json` or `workspace.json`. These libraries are directly referenced from one of the monorepos applications and built together with them.
Keep in mind that the `--publishable` flag does not enable automatic publishing. Rather it adds to your Nx workspace library a builder target that **compiles** and **bundles** your app. The resulting artifact will be ready to be published to some registry (e.g. [npm](https://npmjs.com/)). By having that builder, you can invoke the build via a command like: `nx build mylib` (where "mylib" is the name of the lib) which will then produce an optimized bundle in the `dist/mylib` folder. Nx [also analyzes](/{{framework}}/angular/package#updatebuildableprojectdepsinpackagejson) the librarys dependencies and automatically compiles the dependencies in the resulting `package.json` file.
Keep in mind that the `--publishable` flag does not enable automatic publishing. Rather it adds to your Nx workspace library a builder target that **compiles** and **bundles** your app. The resulting artifact will be ready to be published to some registry (e.g. [npm](https://npmjs.com/)). By having that builder, you can invoke the build via a command like: `nx build mylib` (where "mylib" is the name of the lib) which will then produce an optimized bundle in the `dist/mylib` folder. Nx [also analyzes](/angular/package#updatebuildableprojectdepsinpackagejson) the librarys dependencies and automatically compiles the dependencies in the resulting `package.json` file.
One particularity when generating a library with `--publishable` is that it requires you to also provide an `--importPath`. Your import path is the actual scope of your distributable package (e.g.: `@myorg/mylib`) - which needs to be a [valid npm package name](https://docs.npmjs.com/files/package.json#name).
@ -29,6 +29,6 @@ For more details on the mechanics, remember that Nx is an open source project, s
Buildable libraries are similar to "publishable libraries" described above. Their scope however is not to distribute or publish them to some external registry. Thus they might not be optimized for bundling and distribution.
Buildable libraries are mostly used for producing some pre-compiled output that can be directly referenced from an Nx workspace application without the need to again compile it. A typical scenario is to leverage Nxs [incremental building](/{{framework}}/ci/incremental-builds) capabilities.
Buildable libraries are mostly used for producing some pre-compiled output that can be directly referenced from an Nx workspace application without the need to again compile it. A typical scenario is to leverage Nxs [incremental building](/ci/incremental-builds) capabilities.
For more details on the mechanics, remember that Nx is an open source project, so you can see the actual impact of the generator by looking at the source code (the best starting point is probably `packages/<framework>/src/generators/library/library.ts`).

View File

@ -16,7 +16,7 @@ The `nx dep-graph` command generates a graph of how apps and libraries depend on
### 3. Enforcing Constraints
You can enforce constraints on how different types of libraries depend on each other [using tags](/{{framework}}/structure/monorepo-tags). 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.
You can enforce constraints on how different types of libraries depend on each other [using tags](/structure/monorepo-tags). 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.

View File

@ -4,7 +4,7 @@ Libraries should be grouped by _scope_. A library's scope is either 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 [`@nrwl/workspace:move` generator](/{{framework}}/workspace/move).
Don't be too anxious about choosing the exact right folder structure from the beginning. Libraries can be moved or renamed using the [`@nrwl/workspace:move` generator](/workspace/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:
@ -14,7 +14,7 @@ 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 [`@nrwl/workspace:remove` generator](/{{framework}}/workspace/remove).
Similarly, if you no longer need a library, you can remove it with the [`@nrwl/workspace:remove` generator](/workspace/remove).
```bash
nx g remove booking-some-library

View File

@ -115,7 +115,7 @@ If a file hasn't changed since the last invocation, it doesn't need to be reanal
## Visualizing the Project Graph
You can then visualize the project graph as described [here](/{{framework}}/structure/dependency-graph). However, there is a cache that Nx uses to avoid recalculating the project graph as much as possible. As you develop your project graph plugin, it might be a good idea to set the following environment variable to disable the project graph cache: `NX_CACHE_PROJECT_GRAPH=false`.
You can then visualize the project graph as described [here](/structure/dependency-graph). However, there is a cache that Nx uses to avoid recalculating the project graph as much as possible. As you develop your project graph plugin, it might be a good idea to set the following environment variable to disable the project graph cache: `NX_CACHE_PROJECT_GRAPH=false`.
## Example Project Graph Plugin

View File

@ -6,82 +6,21 @@ describe('DocumentsApi', () => {
describe('getDocument', () => {
it('should retrieve documents that exist', () => {
const result = api.getDocument(
api.getDefaultVersion(),
api.getDefaultFlavor(),
['getting-started', 'intro']
);
const result = api.getDocument(['getting-started', 'intro']);
expect(result.filePath).toBeTruthy();
});
it('should throw error if segments do not match a file', () => {
expect(() =>
api.getDocument(
api.getDefaultVersion(),
{ id: 'vue', alias: 'v', name: 'Vue', path: 'does not exist' },
['does', 'not', 'exist']
)
).toThrow();
expect(() => api.getDocument(['does', 'not', 'exist'])).toThrow();
});
});
describe('getDocumentsRoot', () => {
it('should support latest', () => {
expect(api.getDocumentsRoot('latest')).toMatch(
/nx-dev\/nx-dev\/public\/documentation\/latest/
);
});
it('should support previous', () => {
expect(api.getDocumentsRoot('previous')).toMatch(
/nx-dev\/nx-dev\/public\/documentation\/previous/
);
});
});
describe('getVersions', () => {
it('should return versions data', () => {
expect(api.getVersions()).toEqual([
expect.objectContaining({ id: 'latest' }),
expect.objectContaining({ id: 'previous' }),
]);
});
});
describe('getFlavors', () => {
it('should return versions data', () => {
expect(api.getFlavors()).toEqual([
expect.objectContaining({ id: 'angular' }),
expect.objectContaining({ id: 'react' }),
expect.objectContaining({ id: 'node' }),
]);
});
});
describe('getStaticDocumentPaths', () => {
const paths = api
.getVersions()
.flatMap((v) =>
api.getFlavors().flatMap((f) => api.getStaticDocumentPaths(v, f))
);
const urls = paths.map((p) => p.params.segments.join('/'));
it.each`
version | flavor
${'l'} | ${'r'}
${'l'} | ${'a'}
${'l'} | ${'n'}
${'p'} | ${'r'}
${'p'} | ${'a'}
${'p'} | ${'n'}
`('should return paths for all flavors', ({ version, flavor }) =>
expect(urls).toContainEqual(
expect.stringMatching(`${version}/${flavor}/getting-started`)
)
);
it('should return generic paths for the latest version', () =>
expect(urls).toContainEqual(expect.stringMatching(/^getting-started\//)));
});
// describe('getStaticDocumentPaths', () => {
// const paths = api.getStaticDocumentPaths();
// const urls = paths.map((p) => p.params.segments.join('/'));
//
// it('should return paths', () =>
// expect(urls).toContainEqual(expect.stringMatching('/getting-started')));
// });
});

View File

@ -2,12 +2,7 @@ import { readFileSync } from 'fs';
import { join } from 'path';
import matter from 'gray-matter';
import { extractTitle } from './documents.utils';
import {
DocumentData,
DocumentMetadata,
FlavorMetadata,
VersionMetadata,
} from './documents.models';
import { DocumentData, DocumentMetadata } from './documents.models';
export interface StaticDocumentPaths {
params: { segments: string[] };
@ -17,9 +12,7 @@ export class DocumentsApi {
constructor(
private readonly options: {
publicDocsRoot: string;
versions: VersionMetadata[];
flavors: FlavorMetadata[];
documentsMap: Map<string, DocumentMetadata[]>;
documents: DocumentMetadata;
}
) {
if (!options.publicDocsRoot) {
@ -27,32 +20,9 @@ export class DocumentsApi {
}
}
getDefaultVersion(): VersionMetadata {
const found = this.options.versions.find((v) => v.default);
if (found) return found;
throw new Error('Cannot find default version');
}
getDocument(path: string[]): DocumentData {
const docPath = this.getFilePath(path);
getDefaultFlavor(): FlavorMetadata {
const found = this.options.flavors.find((f) => f.default);
if (found) return found;
throw new Error('Cannot find default flavor');
}
getVersions(): VersionMetadata[] {
return this.options.versions;
}
getFlavors(): FlavorMetadata[] {
return this.options.flavors;
}
getDocument(
version: VersionMetadata,
flavor: FlavorMetadata,
path: string[]
): DocumentData {
const docPath = this.getFilePath(version.id, flavor.id, path);
const originalContent = readFileSync(docPath, 'utf8');
const file = matter(originalContent);
@ -70,21 +40,14 @@ export class DocumentsApi {
};
}
getDocuments(version: string) {
const docs = this.options.documentsMap.get(version);
if (docs) {
return docs;
} else {
throw new Error(`Cannot find documents for ${version}`);
}
getDocuments() {
const docs = this.options.documents;
if (docs) return docs;
throw new Error(`Cannot find any documents`);
}
getStaticDocumentPaths(
version: VersionMetadata,
flavor: FlavorMetadata
): StaticDocumentPaths[] {
getStaticDocumentPaths(): StaticDocumentPaths[] {
const paths: StaticDocumentPaths[] = [];
const defaultVersion = this.getDefaultVersion();
function recur(curr, acc) {
if (curr.itemList) {
@ -92,17 +55,6 @@ export class DocumentsApi {
recur(ii, [...acc, curr.id]);
});
} else {
paths.push({
params: {
segments: [version.alias, flavor.alias, ...acc, curr.id],
},
});
/**
* Generic path generation
* For generic paths such as `/getting-started/intro`, use the default version and react flavor.
*/
if (version.id === defaultVersion.id && flavor.id === 'react')
paths.push({
params: {
segments: [...acc, curr.id],
@ -111,36 +63,17 @@ export class DocumentsApi {
}
}
const item = this.getDocuments(version.id).find(
(item) => item.id === flavor.id
);
if (!item || !item.itemList)
throw new Error(
`Can't find items for version:${version.id} and flavor:${flavor.id}`
);
item.itemList.forEach((item) => {
if (!this.options.documents || !this.options.documents.itemList)
throw new Error(`Can't find any items`);
this.options.documents.itemList.forEach((item) => {
recur(item, []);
});
return paths;
}
getDocumentsRoot(version: string): string {
const versionPath = this.options.versions.find(
(x) => x.id === version
)?.path;
if (versionPath) {
return join(this.options.publicDocsRoot, versionPath);
}
throw new Error(`Cannot find root for ${version}`);
}
private getFilePath(versionId, flavorId, path): string {
let items = this.getDocuments(versionId).find(
(item) => item.id === flavorId
)?.itemList;
private getFilePath(path: string[]): string {
let items = this.options.documents?.itemList;
if (!items) {
throw new Error(`Document not found`);
@ -155,7 +88,7 @@ export class DocumentsApi {
throw new Error(`Document not found`);
}
}
const file = found.file ?? [flavorId, ...path].join('/');
return join(this.getDocumentsRoot(versionId), `${file}.md`);
const file = found.file ?? ['default', ...path].join('/');
return join(this.options.publicDocsRoot, 'latest', `${file}.md`);
}
}

View File

@ -8,14 +8,9 @@ describe('MenuApi', () => {
describe('getMenu', () => {
it('should group by section', () => {
const menu = api.getMenu(
docsApi.getDefaultVersion(),
docsApi.getDefaultFlavor()
);
const menu = api.getMenu();
expect(menu).toEqual({
version: docsApi.getDefaultVersion(),
flavor: docsApi.getDefaultFlavor(),
sections: expect.arrayContaining([
expect.objectContaining({ id: 'basic', itemList: expect.any(Array) }),
expect.objectContaining({ id: 'api', itemList: expect.any(Array) }),
@ -26,21 +21,5 @@ describe('MenuApi', () => {
]),
});
});
it('should add path to menu items', () => {
const menu = api.getMenu(
docsApi.getDefaultVersion(),
docsApi.getDefaultFlavor()
);
// first basic section item should have prefix by version and flavor
// e.g. "latest/react/getting-started/intro"
expect(menu?.sections?.[0]?.itemList?.[0]?.itemList?.[0].url).toMatch(
/l\/r/
);
expect(menu?.sections?.[0]?.itemList?.[0]?.itemList?.[0].path).toMatch(
/latest\/react/
);
});
});
});

View File

@ -6,24 +6,19 @@ import {
getBasicSection,
getDeepDiveSection,
} from './menu.utils';
import { FlavorMetadata, VersionMetadata } from './documents.models';
export class MenuApi {
private readonly menuCache = new Map<string, Menu>();
private menuCache: Menu | null = null;
constructor(private readonly documentsApi: DocumentsApi) {}
getMenu(version: VersionMetadata, flavor: FlavorMetadata): Menu {
const key = `${version.id}-${flavor.id}`;
let menu = this.menuCache.get(key);
getMenu(): Menu {
let menu = this.menuCache;
if (!menu) {
const root = this.documentsApi.getDocuments(version.id);
const items = createMenuItems(version, flavor, root);
const items = createMenuItems(this.documentsApi.getDocuments());
if (items) {
menu = {
version: version,
flavor: flavor,
sections: [
getBasicSection(items),
getDeepDiveSection(items),
@ -31,9 +26,9 @@ export class MenuApi {
],
};
} else {
throw new Error(`Cannot find documents for flavor id: "${flavor.id}"`);
throw new Error(`Cannot find any documents`);
}
this.menuCache.set(key, menu);
this.menuCache = menu;
}
return menu;

View File

@ -1,12 +1,6 @@
import {
DocumentMetadata,
FlavorMetadata,
VersionMetadata,
} from './documents.models';
import { DocumentMetadata, VersionMetadata } from './documents.models';
export interface Menu {
version: VersionMetadata;
flavor: FlavorMetadata;
sections: MenuSection[];
}

View File

@ -1,22 +1,14 @@
import {
DocumentMetadata,
FlavorMetadata,
VersionMetadata,
} from '@nrwl/nx-dev/data-access-documents';
import { DocumentMetadata } from '@nrwl/nx-dev/data-access-documents';
import { MenuItem, MenuSection } from './menu.models';
export function createMenuItems(
version: VersionMetadata,
flavor: FlavorMetadata,
root: DocumentMetadata[]
): MenuItem[] {
const items = root.find((x) => x.id === flavor.id)?.itemList;
export function createMenuItems(root: DocumentMetadata): MenuItem[] {
const items = root?.itemList;
const createPathMetadata = (g: DocumentMetadata, parentId = ''): MenuItem => {
const pathData = {
...g,
path: `/${version.id}/${flavor.id}/${parentId}/${g.id}`,
url: `/${version.alias}/${flavor.alias}/${parentId}/${g.id}`,
path: `/${parentId}/${g.id}`,
url: `/${parentId}/${g.id}`,
};
if (Array.isArray(g.itemList)) {

View File

@ -8,40 +8,13 @@ function readJsonFile(f) {
export function createDocumentApiOptions() {
return {
versions: readJsonFile(
join(
join(__dirname, '../../../nx-dev/public/documentation'),
'versions.json'
)
),
flavors: readJsonFile(
join(
join(__dirname, '../../../nx-dev/public/documentation'),
'flavors.json'
)
),
documentsMap: new Map<string, DocumentMetadata[]>([
[
'latest',
readJsonFile(
documents: readJsonFile(
join(
join(__dirname, '../../../nx-dev/public/documentation'),
'latest',
'map.json'
)
),
],
[
'previous',
readJsonFile(
join(
join(__dirname, '../../../nx-dev/public/documentation'),
'previous',
'map.json'
)
),
],
]),
).find((x) => x.id === 'default') as DocumentMetadata,
publicDocsRoot: join(__dirname, '../../../nx-dev/public/documentation'),
};
}

View File

@ -3,23 +3,14 @@ import ReactMarkdown from 'react-markdown';
import autolinkHeadings from 'rehype-autolink-headings';
import gfm from 'remark-gfm';
import slug from 'rehype-slug';
import {
DocumentData,
FlavorMetadata,
VersionMetadata,
} from '@nrwl/nx-dev/data-access-documents';
import { DocumentData } from '@nrwl/nx-dev/data-access-documents';
import { sendCustomEvent } from '@nrwl/nx-dev/feature-analytics';
import { transformLinkPath } from './renderers/transform-link-path';
import { transformImagePath } from './renderers/transform-image-path';
import { renderIframes } from './renderers/render-iframe';
import { CodeBlock } from './code-block';
export interface ContentProps {
document: DocumentData;
flavor: FlavorMetadata;
flavorList: FlavorMetadata[];
version: VersionMetadata;
versionList: VersionMetadata[];
}
interface ComponentsConfig {
@ -52,7 +43,7 @@ const components: any = (config: ComponentsConfig) => ({
export function Content(props: ContentProps) {
return (
<div className="min-w-0 flex-auto px-4 sm:px-6 xl:px-8 pt-10 pb-24 lg:pb-16">
<div className="min-w-0 flex-auto px-4 sm:px-6 xl:px-8 pt-8 pb-24 lg:pb-16">
<ReactMarkdown
remarkPlugins={[gfm]}
rehypePlugins={[
@ -67,14 +58,7 @@ export function Content(props: ContentProps) {
renderIframes,
]}
children={props.document.content}
transformLinkUri={transformLinkPath({
framework: props.flavor,
frameworkList: props.flavorList,
version: props.version,
versionList: props.versionList,
})}
transformImageUri={transformImagePath({
version: props.version,
document: props.document,
})}
className="prose max-w-none"
@ -93,7 +77,7 @@ export function Content(props: ContentProps) {
);
}
function createAnchorContent(node) {
function createAnchorContent(node: any) {
node.properties.className = ['group'];
return {
type: 'element',

View File

@ -1,22 +1,12 @@
import React from 'react';
import cx from 'classnames';
import { useRouter } from 'next/router';
import { BreadcrumbJsonLd, NextSeo } from 'next-seo';
import {
DocumentData,
FlavorMetadata,
Menu,
MenuItem,
VersionMetadata,
} from '@nrwl/nx-dev/data-access-documents';
import { NextSeo } from 'next-seo';
import { DocumentData, Menu } from '@nrwl/nx-dev/data-access-documents';
import Content from './content';
import Sidebar from './sidebar';
export interface DocumentationFeatureDocViewerProps {
version: VersionMetadata;
flavor: FlavorMetadata;
flavorList: FlavorMetadata[];
versionList: VersionMetadata[];
menu: Menu;
document: DocumentData;
toc: any;
@ -25,11 +15,7 @@ export interface DocumentationFeatureDocViewerProps {
export function DocViewer({
document,
version,
versionList,
menu,
flavor,
flavorList,
navIsOpen,
}: DocumentationFeatureDocViewerProps) {
const router = useRouter();
@ -37,7 +23,6 @@ export function DocViewer({
return (
<>
<NextSeo
noindex={version.id === 'previous'}
title={document.data.title + ' | Nx'}
openGraph={{
url: 'https://nx.dev' + router.asPath,
@ -69,13 +54,7 @@ export function DocViewer({
navIsOpen && 'overflow-hidden max-h-screen fixed'
)}
>
<Content
document={document}
flavor={flavor}
flavorList={flavorList}
version={version}
versionList={versionList}
/>
<Content document={document} />
</div>
</div>
</div>

View File

@ -3,29 +3,21 @@ import { transformImagePath } from './transform-image-path';
describe('transformImagePath', () => {
it('should transform relative paths', () => {
const opts = {
version: {
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
document: {
content: '',
excerpt: '',
filePath:
'nx-dev/nx-dev/public/documentation/latest/angular/migration/migration-angularjs.md',
'nx-dev/nx-dev/public/documentation/latest/shared/using-nx/dte.md',
data: {},
},
};
const transform = transformImagePath(opts);
expect(transform('./test.png')).toEqual(
'/documentation/latest/angular/migration/test.png'
'/documentation/latest/shared/using-nx/test.png'
);
expect(transform('../test.png')).toEqual(
'/documentation/latest/angular/test.png'
'/documentation/latest/shared/test.png'
);
expect(transform('../../test.png')).toEqual(
'/documentation/latest/test.png'
@ -53,7 +45,7 @@ describe('transformImagePath', () => {
const transform = transformImagePath(opts);
expect(transform('/shared/test.png')).toEqual(
'/documentation/latest/shared/test.png'
'/documentation/shared/test.png'
);
});
});

View File

@ -6,10 +6,8 @@ import {
import { join } from 'path';
export function transformImagePath({
version,
document,
}: {
version: VersionMetadata;
document: DocumentData;
}): (src: string) => string {
return (src) => {
@ -25,6 +23,6 @@ export function transformImagePath({
);
}
return uriTransformer(`/documentation/${version.id}`.concat(src));
return uriTransformer(`/documentation`.concat(src));
};
}

View File

@ -1,374 +0,0 @@
import { transformLinkPath } from './transform-link-path';
describe('transformLinkPath', () => {
it('should transform path containing version and flavour', () => {
const transform = transformLinkPath({
framework: {
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
frameworkList: [
{ id: 'angular', name: 'Angular', alias: 'a', path: 'angular' },
{
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
{ id: 'node', name: 'Node', alias: 'n', path: 'node' },
],
version: {
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
versionList: [
{
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
{
name: 'Previous',
id: 'previous',
alias: 'p',
release: '11.3.0',
path: 'previous',
default: false,
},
],
});
expect(
transform('/%7B%7Bversion%7D%7D/%7B%7Bframework%7D%7D/node/overview')
).toEqual('/l/r/node/overview');
});
it('should transform path containing flavour only', () => {
const transform = transformLinkPath({
framework: {
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
frameworkList: [
{ id: 'angular', name: 'Angular', alias: 'a', path: 'angular' },
{
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
{ id: 'node', name: 'Node', alias: 'n', path: 'node' },
],
version: {
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
versionList: [
{
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
{
name: 'Previous',
id: 'previous',
alias: 'p',
release: '11.3.0',
path: 'previous',
default: false,
},
],
});
expect(transform('/l/%7B%7Bframework%7D%7D/node/overview')).toEqual(
'/l/r/node/overview'
);
});
it('should transform path containing version only', () => {
const transform = transformLinkPath({
framework: {
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
frameworkList: [
{ id: 'angular', name: 'Angular', alias: 'a', path: 'angular' },
{
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
{ id: 'node', name: 'Node', alias: 'n', path: 'node' },
],
version: {
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
versionList: [
{
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
{
name: 'Previous',
id: 'previous',
alias: 'p',
release: '11.3.0',
path: 'previous',
default: false,
},
],
});
expect(transform('/%7B%7Bversion%7D%7D/r/node/overview')).toEqual(
'/l/r/node/overview'
);
});
it('should always prepend version if framework detected', () => {
const transform = transformLinkPath({
framework: {
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
frameworkList: [
{ id: 'angular', name: 'Angular', alias: 'a', path: 'angular' },
{
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
{ id: 'node', name: 'Node', alias: 'n', path: 'node' },
],
version: {
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
versionList: [
{
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
{
name: 'Previous',
id: 'previous',
alias: 'p',
release: '11.3.0',
path: 'previous',
default: false,
},
],
});
expect(transform('/a/node/overview')).toEqual('/l/a/node/overview');
expect(transform('/r/node/overview')).toEqual('/l/r/node/overview');
});
it('should always use version & framework aliasing', () => {
const transform = transformLinkPath({
framework: {
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
frameworkList: [
{ id: 'angular', name: 'Angular', alias: 'a', path: 'angular' },
{
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
{ id: 'node', name: 'Node', alias: 'n', path: 'node' },
],
version: {
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
versionList: [
{
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
{
name: 'Previous',
id: 'previous',
alias: 'p',
release: '11.3.0',
path: 'previous',
default: false,
},
],
});
expect(transform('/latest/angular/node/overview')).toEqual(
'/l/a/node/overview'
);
expect(transform('/latest/a/node/overview')).toEqual('/l/a/node/overview');
expect(transform('/previous/react/node/overview')).toEqual(
'/p/r/node/overview'
);
expect(transform('/p/react/node/overview')).toEqual('/p/r/node/overview');
});
it('should do nothing if unrecognized path', () => {
const transform = transformLinkPath({
framework: {
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
frameworkList: [
{ id: 'angular', name: 'Angular', alias: 'a', path: 'angular' },
{
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
{ id: 'node', name: 'Node', alias: 'n', path: 'node' },
],
version: {
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
versionList: [
{
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
{
name: 'Previous',
id: 'previous',
alias: 'p',
release: '11.3.0',
path: 'previous',
default: false,
},
],
});
expect(transform('/%7B%7Bxxx%7D%7D/%7B%7Byyy%7D%7D/node/overview')).toEqual(
'/%7B%7Bxxx%7D%7D/%7B%7Byyy%7D%7D/node/overview'
);
});
it('should not transform path when internal or anchor links', () => {
const transform = transformLinkPath({
framework: {
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
frameworkList: [
{ id: 'angular', name: 'Angular', alias: 'a', path: 'angular' },
{
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
{ id: 'node', name: 'Node', alias: 'n', path: 'node' },
],
version: {
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
versionList: [
{
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
{
name: 'Previous',
id: 'previous',
alias: 'p',
release: '11.3.0',
path: 'previous',
default: false,
},
],
});
expect(transform('#something-path')).toEqual('#something-path');
expect(transform('https://somewhere.path')).toEqual(
'https://somewhere.path'
);
});
});

View File

@ -1,123 +0,0 @@
import { uriTransformer } from 'react-markdown';
import {
FlavorMetadata,
VersionMetadata,
} from '@nrwl/nx-dev/data-access-documents';
export function transformLinkPath(options: {
framework: FlavorMetadata;
frameworkList: FlavorMetadata[];
version: VersionMetadata;
versionList: VersionMetadata[];
}): (href: string) => string {
return (href) =>
uriTransformer(
href
? interpolation(href, {
framework: {
marker: '%7B%7Bframework%7D%7D',
value: options.framework.alias,
},
frameworkList: options.frameworkList.map((f) => f.alias),
version: {
marker: '%7B%7Bversion%7D%7D',
value: options.version.alias,
},
versionList: options.versionList.map((v) => v.alias),
})
: href
);
}
function interpolation(
path: string,
config: {
framework: { marker: string; value: string };
frameworkList: string[];
version: { marker: string; value: string };
versionList: string[];
}
): string {
// Skip external and anchor links
if (path.startsWith('#') || path.startsWith('http')) return path;
// -> /{{version}}/{{framework}}/path/to/document
if (path.includes([config.version.marker, config.framework.marker].join('/')))
path = path.replace(
[config.version.marker, config.framework.marker].join('/'),
`${config.version.value}/${config.framework.value}`
);
// -> /version/{{framework}}/path/to/document
if (path.includes(config.framework.marker))
path = path.replace(
[config.framework.marker].join('/'),
config.framework.value
);
// -> /{{version}}/framework/path/to/document
if (path.includes(config.version.marker))
path = path.replace(
[config.version.marker].join('/'),
config.version.value
);
const isPrependedWithVersion = (
value: string,
versionList: string[]
): boolean => versionList.includes(value.split('/').filter(Boolean)[0]);
const isSupportedFramework = (
value: string,
frameworkList: string[]
): boolean => frameworkList.includes(value.split('/').filter(Boolean)[0]);
/**
* Always prepend the link with a version if not already present only
* if the path contains a known framework
*/
if (
!isPrependedWithVersion(path, config.versionList) &&
isSupportedFramework(path, config.frameworkList)
) {
path =
'/' + config.version.value + (path.startsWith('/') ? path : '/' + path);
}
/**
* Version aliasing if not done already on supported versions only
* /latest/react/gatsby/overview => /l/react/gatsby/overview
*/
const aliasVersion = (path: string): string => {
const explodedPath = path.split('/').filter(Boolean);
if (
!!explodedPath[0] &&
explodedPath[0].length > 1 &&
config.versionList.includes(explodedPath[0].charAt(0))
)
return (path =
'/' +
[explodedPath[0].charAt(0), explodedPath.slice(1).join('/')].join('/'));
return path;
};
/**
* Framework aliasing if not done already on supported framework only
* /l/react/gatsby/overview => /l/r/gatsby/overview
*/
const aliasFramework = (path: string): string => {
const explodedPath = path.split('/').filter(Boolean);
if (
!!explodedPath[1] &&
explodedPath[1].length > 1 &&
config.frameworkList.includes(explodedPath[1].charAt(0))
)
return (path =
'/' +
[
explodedPath[0],
explodedPath[1].charAt(0),
explodedPath.slice(2).join('/'),
].join('/'));
return path;
};
return aliasFramework(aliasVersion(path));
}

View File

@ -2,80 +2,14 @@ import React from 'react';
import { screen } from '@testing-library/dom';
import { render } from '@testing-library/react';
import Sidebar, { createNextPath } from './sidebar';
import { VersionsAndFlavorsProvider } from '@nrwl/nx-dev/feature-versions-and-flavors';
import Sidebar from './sidebar';
describe('Sidebar', () => {
it('should render sections', () => {
render(
<VersionsAndFlavorsProvider
value={{
activeFlavor: {
id: 'angular',
name: 'Angular',
alias: 'a',
path: 'angular',
},
activeVersion: {
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
flavors: [
{
id: 'angular',
name: 'Angular',
alias: 'a',
path: 'angular',
},
{
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
],
versions: [
{
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
{
name: 'Previous (v10.4.13)',
id: 'previous',
alias: 'p',
release: '10.4.13',
path: '10.4.13',
default: false,
},
],
}}
>
<Sidebar
navIsOpen={false}
menu={{
version: {
name: 'Latest',
id: 'latest',
alias: 'l',
release: '12.9.0',
path: 'latest',
default: true,
},
flavor: {
id: 'angular',
name: 'Angular',
alias: 'a',
path: 'angular',
},
sections: [
{
id: 'basic',
@ -110,7 +44,6 @@ describe('Sidebar', () => {
],
}}
/>
</VersionsAndFlavorsProvider>
);
// TODO: figure out the type errors and fix
@ -122,15 +55,3 @@ describe('Sidebar', () => {
expect(screen.getByTestId('section-h4:api')).toBeTruthy();
});
});
describe('createNextPath', () => {
it('should replace version and flavor in the current path', () => {
expect(
createNextPath('latest', 'react', '/previous/react/guides/eslint')
).toEqual('/latest/react/guides/eslint');
expect(
createNextPath('previous', 'angular', '/previous/react/guides/eslint')
).toEqual('/previous/angular/guides/eslint');
});
});

View File

@ -7,37 +7,13 @@ import {
MenuSection,
} from '@nrwl/nx-dev/data-access-documents';
import { useRouter } from 'next/router';
import { Selector } from '@nrwl/nx-dev/ui-common';
import { useSelectedFlavor } from '@nrwl/nx-dev/feature-flavor-selection';
import {
useActiveFlavor,
useActiveVersion,
useFlavors,
useVersions,
} from '@nrwl/nx-dev/feature-versions-and-flavors';
export interface SidebarProps {
menu: Menu;
navIsOpen?: boolean;
}
// Exported for testing
export function createNextPath(
version: string,
flavor: string,
currentPath: string
): string {
const genericPath = currentPath.split('/').slice(3).join('/');
return `/${version}/${flavor}/${genericPath}`;
}
export function Sidebar({ menu, navIsOpen }: SidebarProps) {
const version = useActiveVersion();
const flavor = useActiveFlavor();
const { setSelectedFlavor } = useSelectedFlavor();
const flavorList = useFlavors();
const versionList = useVersions();
const router = useRouter();
return (
<div
data-testid="sidebar"
@ -52,42 +28,11 @@ export function Sidebar({ menu, navIsOpen }: SidebarProps) {
className="h-full overflow-y-auto scrolling-touch lg:h-auto lg:block lg:relative lg:sticky lg:bg-transparent overflow-auto lg:top-18 bg-white mr-24 lg:mr-0 px-2 sm:pr-4 xl:pr-6"
>
<div className="hidden lg:block h-12 pointer-events-none absolute inset-x-0 z-10 bg-gradient-to-b from-white" />
<div className="px-1 pt-6 sm:px-3 xl:px-5 lg:pt-10">
<Selector
items={versionList.map((version) => ({
label: version.name,
value: version.alias,
}))}
selected={{ label: version.name, value: version.alias }}
onChange={(item) =>
router.push(
createNextPath(item.value, flavor.alias, router.asPath)
)
}
/>
</div>
<div className="px-1 pt-3 sm:px-3 xl:px-5">
<Selector
items={flavorList.map((flavor) => ({
label: flavor.name,
value: flavor.alias,
data: flavor,
}))}
selected={{ label: flavor.name, value: flavor.alias }}
onChange={(item) =>
!!router.push(
createNextPath(version.alias, item.value, router.asPath)
) &&
item.data &&
setSelectedFlavor(item.data)
}
/>
</div>
<div className="px-1 py-6 sm:px-3 xl:px-5 h-1 w-full border-b border-gray-50" />
<nav
id="nav"
data-testid="navigation"
className="px-1 pt-1 font-medium text-base sm:px-3 xl:px-5 lg:text-sm pb-10 lg:pb-14 sticky?lg:h-(screen-18)"
className="px-1 pt-16 font-medium text-base sm:px-3 xl:px-5 lg:text-sm pb-10 lg:pb-14 sticky?lg:h-(screen-18)"
>
{menu.sections.map((section, index) => (
<SidebarSection key={section.id + '-' + index} section={section} />

View File

@ -1,18 +0,0 @@
{
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}

View File

@ -1,9 +0,0 @@
module.exports = {
displayName: 'nx-dev-feature-flavor-selection',
preset: '../../jest.preset.js',
transform: {
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/next/babel'] }],
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage//nx-dev/feature-flavor-selection',
};

View File

@ -1,25 +0,0 @@
{
"root": "nx-dev/feature-flavor-selection",
"sourceRoot": "nx-dev/feature-flavor-selection/src",
"projectType": "library",
"tags": ["scope:nx-dev", "type:feature"],
"targets": {
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": [
"nx-dev/feature-flavor-selection/**/*.{ts,tsx,js,jsx}"
]
}
},
"test": {
"executor": "@nrwl/jest:jest",
"outputs": ["coverage/nx-dev/feature-flavor-selection"],
"options": {
"jestConfig": "nx-dev/feature-flavor-selection/jest.config.js",
"passWithNoTests": true
}
}
}
}

View File

@ -1,3 +0,0 @@
export * from './lib/use-selected-flavor/use-selected-flavor';
export * from './lib/flavors-banner';
export * from './lib/utils';

View File

@ -1,107 +0,0 @@
import Link from 'next/link';
import { Dialog } from '@headlessui/react';
import { useRouter } from 'next/router';
import {
FlavorMetadata,
VersionMetadata,
} from '@nrwl/nx-dev/data-access-documents';
import {
useFlavors,
useVersions,
} from '@nrwl/nx-dev/feature-versions-and-flavors';
import { pathCleaner } from '../utils';
export interface FlavorSelectionDialogProps {
version: VersionMetadata;
open: boolean;
onSelect: (f: FlavorMetadata) => void;
}
export function FlavorSelectionDialog(props: FlavorSelectionDialogProps) {
const router = useRouter();
const flavors = useFlavors();
const versions = useVersions();
const cleanPath = pathCleaner(versions, flavors);
const angularFlavor = flavors.find((f) => f.alias === 'a') as FlavorMetadata;
const reactFlavor = flavors.find((f) => f.alias === 'r') as FlavorMetadata;
const nodeFlavor = flavors.find((f) => f.alias === 'n') as FlavorMetadata;
return (
<Dialog
as="div"
className="fixed z-50 inset-0 overflow-y-auto"
open={props.open}
onClose={() => {}}
>
<div className="flex items-center justify-center min-h-screen">
<Dialog.Overlay className="fixed inset-0 backdrop-filter backdrop-blur" />
<div className="z-50 bg-white rounded-md w-11/12 max-w-xl filter drop-shadow-2xl">
<Dialog.Title
as="h3"
className="text-xl sm:text-2xl lg:text-2xl leading-6 m-5"
>
Before You Continue...
</Dialog.Title>
<Dialog.Description className="m-5">
Nx is a smart, fast and extensible build system that has first-class
support for many frontend and backend technologies.
</Dialog.Description>
<Dialog.Description className="m-5">
Please select the flavor you want to learn more about.
</Dialog.Description>
<div className="p-5 w-full grid grid-cols-3 gap-5 justify-items-center">
<Link
href={`${props.version.alias}/r${cleanPath(router.asPath)}`}
replace
>
<a
onClick={() => props.onSelect(reactFlavor)}
className="w-full bg-white border border-gray-100 shadow-sm hover:shadow-md transition-all ease-out duration-180 rounded-md py-4 px-3 space-x-1 text-base tracking-tight font-bold leading-tight text-center flex flex-col justify-center items-center px-2 py-4 space-y-4"
>
<svg viewBox="0 0 24 24" className="w-1/2" fill="#52C1DE">
<path d="M14.23 12.004a2.236 2.236 0 0 1-2.235 2.236 2.236 2.236 0 0 1-2.236-2.236 2.236 2.236 0 0 1 2.235-2.236 2.236 2.236 0 0 1 2.236 2.236zm2.648-10.69c-1.346 0-3.107.96-4.888 2.622-1.78-1.653-3.542-2.602-4.887-2.602-.41 0-.783.093-1.106.278-1.375.793-1.683 3.264-.973 6.365C1.98 8.917 0 10.42 0 12.004c0 1.59 1.99 3.097 5.043 4.03-.704 3.113-.39 5.588.988 6.38.32.187.69.275 1.102.275 1.345 0 3.107-.96 4.888-2.624 1.78 1.654 3.542 2.603 4.887 2.603.41 0 .783-.09 1.106-.275 1.374-.792 1.683-3.263.973-6.365C22.02 15.096 24 13.59 24 12.004c0-1.59-1.99-3.097-5.043-4.032.704-3.11.39-5.587-.988-6.38-.318-.184-.688-.277-1.092-.278zm-.005 1.09v.006c.225 0 .406.044.558.127.666.382.955 1.835.73 3.704-.054.46-.142.945-.25 1.44-.96-.236-2.006-.417-3.107-.534-.66-.905-1.345-1.727-2.035-2.447 1.592-1.48 3.087-2.292 4.105-2.295zm-9.77.02c1.012 0 2.514.808 4.11 2.28-.686.72-1.37 1.537-2.02 2.442-1.107.117-2.154.298-3.113.538-.112-.49-.195-.964-.254-1.42-.23-1.868.054-3.32.714-3.707.19-.09.4-.127.563-.132zm4.882 3.05c.455.468.91.992 1.36 1.564-.44-.02-.89-.034-1.345-.034-.46 0-.915.01-1.36.034.44-.572.895-1.096 1.345-1.565zM12 8.1c.74 0 1.477.034 2.202.093.406.582.802 1.203 1.183 1.86.372.64.71 1.29 1.018 1.946-.308.655-.646 1.31-1.013 1.95-.38.66-.773 1.288-1.18 1.87-.728.063-1.466.098-2.21.098-.74 0-1.477-.035-2.202-.093-.406-.582-.802-1.204-1.183-1.86-.372-.64-.71-1.29-1.018-1.946.303-.657.646-1.313 1.013-1.954.38-.66.773-1.286 1.18-1.868.728-.064 1.466-.098 2.21-.098zm-3.635.254c-.24.377-.48.763-.704 1.16-.225.39-.435.782-.635 1.174-.265-.656-.49-1.31-.676-1.947.64-.15 1.315-.283 2.015-.386zm7.26 0c.695.103 1.365.23 2.006.387-.18.632-.405 1.282-.66 1.933-.2-.39-.41-.783-.64-1.174-.225-.392-.465-.774-.705-1.146zm3.063.675c.484.15.944.317 1.375.498 1.732.74 2.852 1.708 2.852 2.476-.005.768-1.125 1.74-2.857 2.475-.42.18-.88.342-1.355.493-.28-.958-.646-1.956-1.1-2.98.45-1.017.81-2.01 1.085-2.964zm-13.395.004c.278.96.645 1.957 1.1 2.98-.45 1.017-.812 2.01-1.086 2.964-.484-.15-.944-.318-1.37-.5-1.732-.737-2.852-1.706-2.852-2.474 0-.768 1.12-1.742 2.852-2.476.42-.18.88-.342 1.356-.494zm11.678 4.28c.265.657.49 1.312.676 1.948-.64.157-1.316.29-2.016.39.24-.375.48-.762.705-1.158.225-.39.435-.788.636-1.18zm-9.945.02c.2.392.41.783.64 1.175.23.39.465.772.705 1.143-.695-.102-1.365-.23-2.006-.386.18-.63.406-1.282.66-1.933zM17.92 16.32c.112.493.2.968.254 1.423.23 1.868-.054 3.32-.714 3.708-.147.09-.338.128-.563.128-1.012 0-2.514-.807-4.11-2.28.686-.72 1.37-1.536 2.02-2.44 1.107-.118 2.154-.3 3.113-.54zm-11.83.01c.96.234 2.006.415 3.107.532.66.905 1.345 1.727 2.035 2.446-1.595 1.483-3.092 2.295-4.11 2.295-.22-.005-.406-.05-.553-.132-.666-.38-.955-1.834-.73-3.703.054-.46.142-.944.25-1.438zm4.56.64c.44.02.89.034 1.345.034.46 0 .915-.01 1.36-.034-.44.572-.895 1.095-1.345 1.565-.455-.47-.91-.993-1.36-1.565z" />
</svg>
<div className="sm:text-base md:text-sm lg:text-base">
React
</div>
</a>
</Link>
<Link
href={`${props.version.alias}/a${cleanPath(router.asPath)}`}
replace
>
<a
onClick={() => props.onSelect(angularFlavor)}
className="w-full bg-white border border-gray-100 shadow-sm hover:shadow-md transition-all ease-out duration-180 rounded-md py-4 px-3 space-x-1 text-base tracking-tight font-bold leading-tight text-center flex flex-col justify-center items-center px-2 py-4 space-y-4"
>
<svg viewBox="0 0 24 24" className="w-1/2" fill="#E23236">
<path d="M9.931 12.645h4.138l-2.07-4.908m0-7.737L.68 3.982l1.726 14.771L12 24l9.596-5.242L23.32 3.984 11.999.001zm7.064 18.31h-2.638l-1.422-3.503H8.996l-1.422 3.504h-2.64L12 2.65z" />
</svg>
<div className="sm:text-base md:text-sm lg:text-base">
Angular
</div>
</a>
</Link>
<Link
href={`${props.version.alias}/n${cleanPath(router.asPath)}`}
replace
>
<a
onClick={() => props.onSelect(nodeFlavor)}
className="w-full bg-white border border-gray-100 shadow-sm hover:shadow-md transition-all ease-out duration-180 rounded-md py-4 px-3 space-x-1 text-base tracking-tight font-bold leading-tight text-center flex flex-col justify-center items-center px-2 py-4 space-y-4"
>
<svg viewBox="0 0 24 24" className="w-1/2" fill="#77AE64">
<path d="M11.998,24c-0.321,0-0.641-0.084-0.922-0.247l-2.936-1.737c-0.438-0.245-0.224-0.332-0.08-0.383 c0.585-0.203,0.703-0.25,1.328-0.604c0.065-0.037,0.151-0.023,0.218,0.017l2.256,1.339c0.082,0.045,0.197,0.045,0.272,0l8.795-5.076 c0.082-0.047,0.134-0.141,0.134-0.238V6.921c0-0.099-0.053-0.192-0.137-0.242l-8.791-5.072c-0.081-0.047-0.189-0.047-0.271,0 L3.075,6.68C2.99,6.729,2.936,6.825,2.936,6.921v10.15c0,0.097,0.054,0.189,0.139,0.235l2.409,1.392 c1.307,0.654,2.108-0.116,2.108-0.89V7.787c0-0.142,0.114-0.253,0.256-0.253h1.115c0.139,0,0.255,0.112,0.255,0.253v10.021 c0,1.745-0.95,2.745-2.604,2.745c-0.508,0-0.909,0-2.026-0.551L2.28,18.675c-0.57-0.329-0.922-0.945-0.922-1.604V6.921 c0-0.659,0.353-1.275,0.922-1.603l8.795-5.082c0.557-0.315,1.296-0.315,1.848,0l8.794,5.082c0.57,0.329,0.924,0.944,0.924,1.603 v10.15c0,0.659-0.354,1.273-0.924,1.604l-8.794,5.078C12.643,23.916,12.324,24,11.998,24z M19.099,13.993 c0-1.9-1.284-2.406-3.987-2.763c-2.731-0.361-3.009-0.548-3.009-1.187c0-0.528,0.235-1.233,2.258-1.233 c1.807,0,2.473,0.389,2.747,1.607c0.024,0.115,0.129,0.199,0.247,0.199h1.141c0.071,0,0.138-0.031,0.186-0.081 c0.048-0.054,0.074-0.123,0.067-0.196c-0.177-2.098-1.571-3.076-4.388-3.076c-2.508,0-4.004,1.058-4.004,2.833 c0,1.925,1.488,2.457,3.895,2.695c2.88,0.282,3.103,0.703,3.103,1.269c0,0.983-0.789,1.402-2.642,1.402 c-2.327,0-2.839-0.584-3.011-1.742c-0.02-0.124-0.126-0.215-0.253-0.215h-1.137c-0.141,0-0.254,0.112-0.254,0.253 c0,1.482,0.806,3.248,4.655,3.248C17.501,17.007,19.099,15.91,19.099,13.993z" />
</svg>
<div className="sm:text-base md:text-sm lg:text-base">Node</div>
</a>
</Link>
</div>
</div>
</div>
</Dialog>
);
}
export default FlavorSelectionDialog;

View File

@ -1,167 +0,0 @@
import {
FlavorMetadata,
VersionMetadata,
} from '@nrwl/nx-dev/data-access-documents';
import { useRouter } from 'next/router';
import { motion, useAnimation } from 'framer-motion';
import {
useFlavors,
useVersions,
} from '@nrwl/nx-dev/feature-versions-and-flavors';
import { pathCleaner } from './utils';
import Link from 'next/link';
export interface FlavorSelectionDialogProps {
version: VersionMetadata;
isSelected: boolean;
onSelect: (f: FlavorMetadata) => void;
}
export function FlavorsBanner(props: FlavorSelectionDialogProps) {
const router = useRouter();
const flavors = useFlavors();
const versions = useVersions();
const cleanPath = pathCleaner(versions, flavors);
const angularFlavor = flavors.find((f) => f.alias === 'a') as FlavorMetadata;
const reactFlavor = flavors.find((f) => f.alias === 'r') as FlavorMetadata;
const nodeFlavor = flavors.find((f) => f.alias === 'n') as FlavorMetadata;
const defaultFlavor = flavors.find((f) => f.default) as FlavorMetadata;
const controls = useAnimation();
if (props.isSelected) controls.start('hidden');
else controls.start('visible');
return (
<div className="relative w-full max-w-screen-lg mx-auto">
<motion.div
key={'angular'}
initial="hidden"
variants={{
hidden: { y: -20, opacity: 0 },
visible: { y: 0, opacity: 1 },
}}
animate={controls}
transition={{
when: 'beforeChildren',
staggerChildren: 0.12,
ease: 'linear',
duration: 0.88,
type: 'tween',
}}
exit="hidden"
className="absolute left-0 top-0 w-full py-3 px-3 sm:px-6 lg:px-8 bg-white z-40 rounded-md shadow-md"
>
<div className="flex items-center justify-between flex-wrap">
<div className="flex-1 flex items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<p className="ml-3 font-medium text-gray-500">
Nx comes with dedicated documentation for each framework:
</p>
</div>
<div className="order-3 mt-2 flex-shrink-0 flex w-full sm:order-2 sm:mt-0 sm:w-auto">
<div className="relative z-0 flex flex-grow w-full shadow-sm rounded-md">
<Link
href={`${props.version.alias}/r${cleanPath(router.asPath)}`}
replace
>
<a
onClick={() => props.onSelect(reactFlavor)}
className="flex flex-grow items-center justify-center px-4 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-600 bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-blue-nx-base"
>
<svg
className="w-4 h-4 mr-2"
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
>
<path d="M14.23 12.004a2.236 2.236 0 0 1-2.235 2.236 2.236 2.236 0 0 1-2.236-2.236 2.236 2.236 0 0 1 2.235-2.236 2.236 2.236 0 0 1 2.236 2.236zm2.648-10.69c-1.346 0-3.107.96-4.888 2.622-1.78-1.653-3.542-2.602-4.887-2.602-.41 0-.783.093-1.106.278-1.375.793-1.683 3.264-.973 6.365C1.98 8.917 0 10.42 0 12.004c0 1.59 1.99 3.097 5.043 4.03-.704 3.113-.39 5.588.988 6.38.32.187.69.275 1.102.275 1.345 0 3.107-.96 4.888-2.624 1.78 1.654 3.542 2.603 4.887 2.603.41 0 .783-.09 1.106-.275 1.374-.792 1.683-3.263.973-6.365C22.02 15.096 24 13.59 24 12.004c0-1.59-1.99-3.097-5.043-4.032.704-3.11.39-5.587-.988-6.38-.318-.184-.688-.277-1.092-.278zm-.005 1.09v.006c.225 0 .406.044.558.127.666.382.955 1.835.73 3.704-.054.46-.142.945-.25 1.44-.96-.236-2.006-.417-3.107-.534-.66-.905-1.345-1.727-2.035-2.447 1.592-1.48 3.087-2.292 4.105-2.295zm-9.77.02c1.012 0 2.514.808 4.11 2.28-.686.72-1.37 1.537-2.02 2.442-1.107.117-2.154.298-3.113.538-.112-.49-.195-.964-.254-1.42-.23-1.868.054-3.32.714-3.707.19-.09.4-.127.563-.132zm4.882 3.05c.455.468.91.992 1.36 1.564-.44-.02-.89-.034-1.345-.034-.46 0-.915.01-1.36.034.44-.572.895-1.096 1.345-1.565zM12 8.1c.74 0 1.477.034 2.202.093.406.582.802 1.203 1.183 1.86.372.64.71 1.29 1.018 1.946-.308.655-.646 1.31-1.013 1.95-.38.66-.773 1.288-1.18 1.87-.728.063-1.466.098-2.21.098-.74 0-1.477-.035-2.202-.093-.406-.582-.802-1.204-1.183-1.86-.372-.64-.71-1.29-1.018-1.946.303-.657.646-1.313 1.013-1.954.38-.66.773-1.286 1.18-1.868.728-.064 1.466-.098 2.21-.098zm-3.635.254c-.24.377-.48.763-.704 1.16-.225.39-.435.782-.635 1.174-.265-.656-.49-1.31-.676-1.947.64-.15 1.315-.283 2.015-.386zm7.26 0c.695.103 1.365.23 2.006.387-.18.632-.405 1.282-.66 1.933-.2-.39-.41-.783-.64-1.174-.225-.392-.465-.774-.705-1.146zm3.063.675c.484.15.944.317 1.375.498 1.732.74 2.852 1.708 2.852 2.476-.005.768-1.125 1.74-2.857 2.475-.42.18-.88.342-1.355.493-.28-.958-.646-1.956-1.1-2.98.45-1.017.81-2.01 1.085-2.964zm-13.395.004c.278.96.645 1.957 1.1 2.98-.45 1.017-.812 2.01-1.086 2.964-.484-.15-.944-.318-1.37-.5-1.732-.737-2.852-1.706-2.852-2.474 0-.768 1.12-1.742 2.852-2.476.42-.18.88-.342 1.356-.494zm11.678 4.28c.265.657.49 1.312.676 1.948-.64.157-1.316.29-2.016.39.24-.375.48-.762.705-1.158.225-.39.435-.788.636-1.18zm-9.945.02c.2.392.41.783.64 1.175.23.39.465.772.705 1.143-.695-.102-1.365-.23-2.006-.386.18-.63.406-1.282.66-1.933zM17.92 16.32c.112.493.2.968.254 1.423.23 1.868-.054 3.32-.714 3.708-.147.09-.338.128-.563.128-1.012 0-2.514-.807-4.11-2.28.686-.72 1.37-1.536 2.02-2.44 1.107-.118 2.154-.3 3.113-.54zm-11.83.01c.96.234 2.006.415 3.107.532.66.905 1.345 1.727 2.035 2.446-1.595 1.483-3.092 2.295-4.11 2.295-.22-.005-.406-.05-.553-.132-.666-.38-.955-1.834-.73-3.703.054-.46.142-.944.25-1.438zm4.56.64c.44.02.89.034 1.345.034.46 0 .915-.01 1.36-.034-.44.572-.895 1.095-1.345 1.565-.455-.47-.91-.993-1.36-1.565z" />
</svg>
React
</a>
</Link>
<Link
href={`${props.version.alias}/a${cleanPath(router.asPath)}`}
replace
>
<a
onClick={() => props.onSelect(angularFlavor)}
className="-ml-px flex flex-grow items-center justify-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-600 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-blue-nx-base"
>
<svg
className="w-4 h-4 mr-2"
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
>
<path d="M9.931 12.645h4.138l-2.07-4.908m0-7.737L.68 3.982l1.726 14.771L12 24l9.596-5.242L23.32 3.984 11.999.001zm7.064 18.31h-2.638l-1.422-3.503H8.996l-1.422 3.504h-2.64L12 2.65z" />
</svg>{' '}
Angular
</a>
</Link>
<Link
href={`${props.version.alias}/n${cleanPath(router.asPath)}`}
replace
>
<a
onClick={() => props.onSelect(nodeFlavor)}
className="-ml-px flex flex-grow items-center justify-center px-4 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-600 hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-1 focus:ring-blue-nx-base"
>
<svg
viewBox="0 0 24 24"
role="img"
className="w-4 h-4 mr-2"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
>
<path d="M11.998,24c-0.321,0-0.641-0.084-0.922-0.247l-2.936-1.737c-0.438-0.245-0.224-0.332-0.08-0.383 c0.585-0.203,0.703-0.25,1.328-0.604c0.065-0.037,0.151-0.023,0.218,0.017l2.256,1.339c0.082,0.045,0.197,0.045,0.272,0l8.795-5.076 c0.082-0.047,0.134-0.141,0.134-0.238V6.921c0-0.099-0.053-0.192-0.137-0.242l-8.791-5.072c-0.081-0.047-0.189-0.047-0.271,0 L3.075,6.68C2.99,6.729,2.936,6.825,2.936,6.921v10.15c0,0.097,0.054,0.189,0.139,0.235l2.409,1.392 c1.307,0.654,2.108-0.116,2.108-0.89V7.787c0-0.142,0.114-0.253,0.256-0.253h1.115c0.139,0,0.255,0.112,0.255,0.253v10.021 c0,1.745-0.95,2.745-2.604,2.745c-0.508,0-0.909,0-2.026-0.551L2.28,18.675c-0.57-0.329-0.922-0.945-0.922-1.604V6.921 c0-0.659,0.353-1.275,0.922-1.603l8.795-5.082c0.557-0.315,1.296-0.315,1.848,0l8.794,5.082c0.57,0.329,0.924,0.944,0.924,1.603 v10.15c0,0.659-0.354,1.273-0.924,1.604l-8.794,5.078C12.643,23.916,12.324,24,11.998,24z M19.099,13.993 c0-1.9-1.284-2.406-3.987-2.763c-2.731-0.361-3.009-0.548-3.009-1.187c0-0.528,0.235-1.233,2.258-1.233 c1.807,0,2.473,0.389,2.747,1.607c0.024,0.115,0.129,0.199,0.247,0.199h1.141c0.071,0,0.138-0.031,0.186-0.081 c0.048-0.054,0.074-0.123,0.067-0.196c-0.177-2.098-1.571-3.076-4.388-3.076c-2.508,0-4.004,1.058-4.004,2.833 c0,1.925,1.488,2.457,3.895,2.695c2.88,0.282,3.103,0.703,3.103,1.269c0,0.983-0.789,1.402-2.642,1.402 c-2.327,0-2.839-0.584-3.011-1.742c-0.02-0.124-0.126-0.215-0.253-0.215h-1.137c-0.141,0-0.254,0.112-0.254,0.253 c0,1.482,0.806,3.248,4.655,3.248C17.501,17.007,19.099,15.91,19.099,13.993z" />
</svg>
Node
</a>
</Link>
</div>
</div>
<div className="order-2 flex-shrink-0 sm:order-3 sm:ml-3">
<button
type="button"
onClick={() => props.onSelect(defaultFlavor)}
className="-mr-1 flex p-2 rounded-md text-gray-500 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-nx-base sm:-mr-2"
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span className="sr-only">Dismiss</span>
</button>
</div>
</div>
</motion.div>
</div>
);
}
export default FlavorsBanner;

View File

@ -1,163 +0,0 @@
import { act, renderHook } from '@testing-library/react-hooks';
import { VersionsAndFlavorsProvider } from '@nrwl/nx-dev/feature-versions-and-flavors';
import { useSelectedFlavor } from './use-selected-flavor';
import { FlavorMetadata } from '@nrwl/nx-dev/data-access-documents';
import { NextRouter, useRouter } from 'next/router';
jest.mock('next/router', () => {
const router = {
asPath: '/getting-started/intro',
replace: () => null,
};
return { useRouter: () => router };
});
class MockStorage {
private cache: Record<string, string> = {};
getItem(key: string) {
return this.cache[key];
}
setItem(key: string, value: string) {
this.cache[key] = value;
}
clear() {
this.cache = {};
}
}
const mockFlavors: FlavorMetadata[] = [
{ id: 'angular', name: 'Angular', alias: 'a', path: 'angular' },
{
id: 'react',
name: 'React',
alias: 'r',
path: 'react',
default: true,
},
{ id: 'node', name: 'Node', alias: 'n', path: 'node' },
];
const latestVersion = {
name: 'Latest',
id: 'latest',
alias: 'l',
release: 'master',
path: 'latest',
default: true,
};
function createWrapper(opts: { activeAlias: string; isFallback: boolean }) {
return function Wrapper(props: any) {
return (
<VersionsAndFlavorsProvider
value={{
flavors: mockFlavors,
versions: [latestVersion],
activeFlavor: getFlavor(opts),
activeVersion: latestVersion,
isFallbackActiveFlavor: opts.isFallback,
}}
>
{props.children}
</VersionsAndFlavorsProvider>
);
};
}
function getFlavor(opts: { activeAlias: string }) {
return mockFlavors.find(
(f) => f.alias === opts.activeAlias
) as FlavorMetadata;
}
describe('useSelectedFlavor', () => {
let router: NextRouter;
let replaceSpy: jest.SpyInstance;
let mockStorage: MockStorage;
beforeAll(() => {
router = useRouter();
replaceSpy = jest.spyOn(router, 'replace');
mockStorage = new MockStorage();
Object.defineProperty(window, 'localStorage', { value: mockStorage });
});
afterEach(() => {
replaceSpy.mockReset();
mockStorage.clear();
});
it('should store flavor in storage when `setSelectedFlavor` is called', () => {
router.asPath = '/getting-started/intro';
const { result } = renderHook(() => useSelectedFlavor(), {
wrapper: createWrapper({ activeAlias: 'a', isFallback: true }),
});
act(() =>
result.current.setSelectedFlavor(getFlavor({ activeAlias: 'r' }))
);
expect(mockStorage.getItem('flavor')).toEqual('r');
act(() =>
result.current.setSelectedFlavor(getFlavor({ activeAlias: 'n' }))
);
expect(mockStorage.getItem('flavor')).toEqual('n');
});
it('should redirect when active and selected flavors are different', () => {
router.asPath = '/l/a/getting-started/intro';
const { result } = renderHook(() => useSelectedFlavor(), {
wrapper: createWrapper({ activeAlias: 'a', isFallback: true }),
});
act(() =>
result.current.setSelectedFlavor(getFlavor({ activeAlias: 'r' }))
);
expect(router.replace).toHaveBeenCalledWith('/l/r/getting-started/intro');
});
it('should not redirect when selected and active flavors are the same', () => {
router.asPath = '/l/r/getting-started/intro';
const { result } = renderHook(() => useSelectedFlavor(), {
wrapper: createWrapper({ activeAlias: 'r', isFallback: true }),
});
act(() =>
result.current.setSelectedFlavor(getFlavor({ activeAlias: 'r' }))
);
expect(router.replace).not.toHaveBeenCalled();
});
it('should redirect when URL is a fallback URL', () => {
router.asPath = '/getting-started/intro';
const { result } = renderHook(() => useSelectedFlavor(), {
wrapper: createWrapper({ activeAlias: 'a', isFallback: true }),
});
act(() =>
result.current.setSelectedFlavor(getFlavor({ activeAlias: 'a' }))
);
expect(router.replace).toHaveBeenCalledWith('/l/a/getting-started/intro');
});
it('should not redirect when URL is not fallback URL', () => {
router.asPath = '/l/r/getting-started/intro';
const { result } = renderHook(() => useSelectedFlavor(), {
wrapper: createWrapper({ activeAlias: 'r', isFallback: false }),
});
act(() =>
result.current.setSelectedFlavor(getFlavor({ activeAlias: 'r' }))
);
expect(router.replace).not.toHaveBeenCalled();
});
});

View File

@ -1,50 +0,0 @@
import {
useActiveFlavor,
useActiveVersion,
useFlavors,
useVersions,
} from '@nrwl/nx-dev/feature-versions-and-flavors';
import { pathCleaner } from '@nrwl/nx-dev/feature-flavor-selection';
import { useStorage } from '@nrwl/nx-dev/feature-storage';
import { useRouter } from 'next/router';
import { useEffect, useMemo } from 'react';
import { FlavorMetadata } from '@nrwl/nx-dev/data-access-documents';
export function useSelectedFlavor() {
const versions = useVersions();
const flavors = useFlavors();
const activeFlavor = useActiveFlavor();
const activeVersion = useActiveVersion();
const cleanPath = pathCleaner(versions, flavors);
const { value: selectedFlavor, setValue: setSelectedFlavor } =
useStorage('flavor');
const router = useRouter();
const handleSetFlavor = (f: FlavorMetadata) => setSelectedFlavor(f.alias);
const flavorSelected = useMemo(
() => !(activeFlavor.isFallback && !selectedFlavor) && !!selectedFlavor,
[activeFlavor.isFallback, selectedFlavor]
);
useEffect(() => {
if (!activeFlavor.isFallback || !selectedFlavor) return;
// If the selected flavor is different then, navigate away.
// Otherwise, replace current URL _if_ it is missing version+flavor.
if (activeFlavor.alias !== selectedFlavor) {
router.replace(
`/${activeVersion.alias}/${selectedFlavor}${cleanPath(router.asPath)}`
);
} else if (!router.asPath.startsWith(`/${activeVersion.alias}`)) {
router.replace(
`/${activeVersion.alias}/${selectedFlavor}${cleanPath(router.asPath)}`
);
}
}, [router, activeVersion, activeFlavor, selectedFlavor]);
return {
selectedFlavor,
setSelectedFlavor: handleSetFlavor,
flavorSelected,
};
}

View File

@ -1,24 +0,0 @@
import {
FlavorMetadata,
VersionMetadata,
} from '@nrwl/nx-dev/data-access-documents';
export function pathCleaner(
versions: VersionMetadata[],
flavors: FlavorMetadata[]
) {
return (path: string): string => {
const [first, second, ...others] = path.split('/').filter(Boolean);
const cleanPath = [];
if (!versions.find((v) => [v.alias, v.id].includes(first))) {
cleanPath.push(first);
}
if (!flavors.find((f) => [f.alias, f.id].includes(second))) {
cleanPath.push(second);
}
return '/' + (others ? cleanPath.concat(...others) : cleanPath).join('/');
};
}

View File

@ -1,24 +0,0 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react-jsx",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"lib": ["dom"]
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}

View File

@ -1,13 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": ["node"]
},
"files": [
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
"../../node_modules/@nrwl/next/typings/image.d.ts"
],
"exclude": ["**/*.spec.ts", "**/*.test.ts", "**/*.spec.tsx", "**/*.test.tsx"],
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
}

Some files were not shown because too many files have changed in this diff Show More