Compare commits

...

92 Commits

Author SHA1 Message Date
Emily Xiong d99164a6ab fix(core): change to use init generator during import (#30029)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->
- call init generator using implementationFactory, causing issue because
schema.json file isnt respected, and then NX_INTERACTIVE is never set to
true

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
- change back to run init command

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
2025-02-13 22:50:14 -05:00
Benjamin Cabanes 67255189df docs(nx-dev): remove webinar notifier & event link (#29737)
Commented out the `WebinarNotifier` in `_app.tsx` and the live event link section in `hero.tsx`.

(cherry picked from commit ae9aa5ac76)
2025-01-23 15:55:56 -05:00
Leosvel Pérez Espinosa d02b30664f fix(react): ensure project name is escaped in spec matcher when generating an application (#29732)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit 4bbbea2def)
2025-01-23 15:55:56 -05:00
Leosvel Pérez Espinosa eb5c1d429c fix(nx-plugin): fix plugin generation in ts solution setup (#29730)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit 9d1c55b80e)
2025-01-23 15:55:55 -05:00
Jiří Prokop f921c189c6 fix(vite): do not stop the test process of failure in watch mode (#29260)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior

When you run `nx run <lib>:test --watch` it only works correctly if
there are no failing tests. In case you have some failing test, the
process finishes immediately after all tests are finished.

## Expected Behavior

Watch mode should work the same as with Jest or when you use `vitest` on
its own.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

The logic seems to be broken with introduction of
https://github.com/nrwl/nx/pull/27722

Fixes #28050

(cherry picked from commit bd35ab2892)
2025-01-23 15:55:54 -05:00
Jack Hsu 6270a4b46f fix(node): set correct compilerOptions for Nest applications (#29725)
This PR fixes and issue where generating Nest app in the new TS setup
results in a build error due to missing `experimentalDecorators` option
in tsconfig. Decorators are required for Nest to work, but we do not set
it anymore in `tsconfig.base.json` by default.

## Current Behavior
Nest apps are broken

## Expected Behavior
Nest apps work

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit a0cfe88f5f)
2025-01-23 15:55:53 -05:00
Isaac Mann 2b5d4f1989 docs(core): project linking concept and recipe (#29652)
Adds two pages:
- Concept page describing two options for [TypeScript project
linking](https://nx-dev-git-docs-workspaces-project-linking-nrwl.vercel.app/concepts/typescript-project-linking)
(workspaces and path aliases).
- Also describes performance benefits of TS Project References that are
possible with workspaces
- Recipe describing how to manually [switch from path aliases to
workspaces project
linking](https://nx-dev-git-docs-workspaces-project-linking-nrwl.vercel.app/recipes/tips-n-tricks/switch-to-workspaces-project-references)

(cherry picked from commit 8357a2270a)
2025-01-23 15:55:53 -05:00
James Henry bf0f9fda4e chore(repo): latest powerpack 1.2.0 (#29724)
(cherry picked from commit 123602c0d6)
2025-01-23 15:55:43 -05:00
Jonathan Cammisuli c97d54b8e1 docs(core): add local cache information for powerpack (#29630)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Also includes update ENV variables

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit cad265dad6)
2025-01-22 16:33:26 -05:00
Jonathan Cammisuli e1fbe37b59 fix(core): ensure that nx is backwards compatible with older versions of Nx Cloud (#29703)
(cherry picked from commit a9f6ba553a)
2025-01-22 16:33:26 -05:00
Juri Strumpflohner 37b022f00d fix(nx-dev): update request a trial link on pricing page (#29711)
(cherry picked from commit a055f1be36)
2025-01-22 16:33:25 -05:00
Zach Tindall d3553867e0 fix(core): update yarn-parser to handle yarn v4 syntax for root workspace package (#29452)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
The root workspace package is not generated correctly when using Yarn v4

## Expected Behavior
yarn.lock should be created correctly

## Related Issue(s)

Fixes #29451

(cherry picked from commit 3c98a1ca56)
2025-01-22 16:33:24 -05:00
Nicholas Cunningham 985e094a6d docs(nx-dev): remove unnecessary directory flag from host & remote generation commands (#29704)
### Changes
Remove `--directory` flag if the arg is provided as a positional. If
provided it will throw errors.

(cherry picked from commit 7f3ca1f094)
2025-01-22 16:33:24 -05:00
Craigory Coppola 2e6bb3ef78 fix(core): do not warn about custom tasks runners when explicitly usi… (#29669)
…ng default<!-- Please make sure you have read the submission guidelines
before posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit 104f06ccb7)
2025-01-22 16:33:23 -05:00
Colum Ferry fcb1a3b662 fix(testing): e2e config generators should prompt for missing serve data (#29660)
## Current Behavior
When running the `configuration` generator from `@nx/playwright` and
`@nx/cypress` for existing appliactions - they currently generate a
config that is likely to be invalid becaue there is not enough
information to correctly assume the port, target and baseUrl for the
application.
This data is provided by the application generators that call the
`configuration` generator - but that means that users running it
manually must remember to pass the information via flags.

## Expected Behavior
If the serve data is missing, prompt the user to input the correct
information to ensure the config generation is as accurate as possible.

(cherry picked from commit bc0566f4c3)
2025-01-22 16:33:23 -05:00
MaxKless efbf3a3caf fix(graph): copy command text directly from PDV (#29645)
(cherry picked from commit 37f994ad75)
2025-01-22 16:33:22 -05:00
Louie Weng 7dd2b3493e docs(nx-cloud): use assignment rules with self provisioned agents (#29490)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

The initial version of the docs only allow the use of assignment rules
with Nx Agents.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

The updated docs include an overview and example of how to configure
assignment rules to work with self provisioned agents (and DTE in
'manual' mode).

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

---------

Co-authored-by: Isaac Mann <isaacplmann@users.noreply.github.com>
(cherry picked from commit bb03ed7d82)
2025-01-22 16:33:22 -05:00
Isaac Mann 0fbfabfa91 docs(core): update turborepo docs (#29656)
Update the turborepo concept page and migration guide

(cherry picked from commit cba25da87e)
2025-01-22 16:33:21 -05:00
Benjamin Cabanes b05ef8cc0d docs(nx-dev): update "ebook" references to "guide" in button texts (#29655)
Revised all button texts and titles to consistently use "guide" instead of "ebook" across multiple components.

(cherry picked from commit 4d0ebe04c9)
2025-01-22 16:33:21 -05:00
Thimo Sietsma bcf2d5f4a1 docs(migration): update turborepo migration guide (#29522)
I came across the TurboRepo migration guide and noticed some outdated
TurboRepo configurations.

I’ve updated the migration guide for TurboRepo. However, the
documentation still lacks some global configurations:

- [ui](https://turbo.build/repo/docs/reference/configuration#ui)
- cacheDir
- [deamon](https://turbo.build/repo/docs/reference/configuration#daemon)
-
[envMode](https://turbo.build/repo/docs/reference/configuration#envmode)
-
[remoteCaching](https://turbo.build/repo/docs/core-concepts/remote-caching)

I'm not entirely sure if these should be included in the migration guide
or what their equivalent would be in nx, as I'm not yet very familiar
with nx.

(cherry picked from commit dd9db3603c)
2025-01-22 16:33:20 -05:00
Leosvel Pérez Espinosa b6d69301ef fix(js): ignore bundler config files correctly in eslint config when using vitest in js library generator (#29649)
## Current Behavior

Generating a js library with esbuild or rollup as bundlers and vitest as
the unit test runner, results in an eslint configuration where the
bundler config file is not ignored from the `@nx/dependency-checks`
rule.

## Expected Behavior

Generating a js library with esbuild or rollup as bundlers and vitest as
the unit test runner, should result in an eslint configuration where the
bundler config file is ignored from the `@nx/dependency-checks` rule.

## Related Issue(s)

Fixes #

(cherry picked from commit 8a6e44b788)
2025-01-17 11:13:40 -05:00
Leosvel Pérez Espinosa a963fa9b57 fix(js): do not generate package.json file for non-buildable js libraries in non-ts solution setup (#29646)
## Current Behavior

When generating a non-buildable js library in a workspace using the
integrated setup, a `package.json` file is generated.

## Expected Behavior

When generating a non-buildable js library in a workspace using the
integrated setup, a `package.json` file should not be generated.

## Related Issue(s)

Fixes #

(cherry picked from commit ad96cc17c9)
2025-01-17 11:13:39 -05:00
Leosvel Pérez Espinosa 00b0b38b55 docs(expo): fix typo in plugin overview (#29634)
## Current Behavior

## Expected Behavior

## Related Issue(s)

Fixes #

(cherry picked from commit ca1c3ea6a8)
2025-01-17 11:13:38 -05:00
Leosvel Pérez Espinosa 117f756ee3 fix(js): fix typo so exports field in package.json is properly sorted (#29643)
## Current Behavior

It tries to sort `exported` which is an invalid field.

## Expected Behavior

It should sort `exports`.

## Related Issue(s)

Fixes #

(cherry picked from commit ed6b220214)
2025-01-17 11:13:37 -05:00
Laney a899385731 docs(release): fix typo in version.generatorOptions.updateDependen… (#29640)
…ts option

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior

The version generator option `updateDependents` is misspelled as
`updatedDependents` in one of the Nx release docs pages.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->
n/a

Fixes #

(cherry picked from commit d0078d050e)
2025-01-17 11:13:36 -05:00
Jack Hsu 1d8508e37b fix(js): sort package.json fields by idiomatic order (#29635)
This PR updates our app/lib generators such that `package.json` files
generated have fields in idiomatic order.

e.g.

```json
{
  "name": "...",
  "version": "...",
  "private": true,
  "type": "module",
  "main": "...",
  ...
  "dependencies": { ... }
}
```

The import fields such as name, version, private, and type are at the
top. Dep fields that could be noisy are at the bottom.

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit cc441a6dc7)
2025-01-17 11:13:18 -05:00
Emily Xiong d887446657 fix(gradle): check if java is installed (#29572)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
throw an error when `./gradlew wrapper` or `java -version` failed to
run:
<img width="949" alt="Screenshot 2025-01-09 at 5 33 38 PM"
src="https://github.com/user-attachments/assets/f0b99adc-ff80-4962-8dfe-c1ad11944cac"
/>
<img width="933" alt="Screenshot 2025-01-09 at 5 32 20 PM"
src="https://github.com/user-attachments/assets/11d2286a-cc04-48a0-9839-b67cc93d5cfc"
/>

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit f9c306af28)
2025-01-17 11:13:18 -05:00
Jason Jean 7bc8269e2d fix(core): check only for watcher connections during inactivity shutdown (#29621)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

We currently second guess our inactivity timer by checking if there are
any open connections. However, there's also a strong chance that plugin
workers will remain open as long as the daemon is open. This means the
daemon stays alive forever and the daemon never shuts down even though
it is inactive.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Instead of checking for open connections in general, the daemon server
will only check for open file watchers. Most Daemon client requests will
restart the server when sending messages so we can safely shut the
server down in most cases. The only case where shutting down the daemon
would cause a disruption is if a file watcher is registered. In those
cases, the daemon will not shutdown due to inactivity.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit 32a2ca8eaa)
2025-01-15 11:07:29 -05:00
Colum Ferry dca604846b fix(rspack): make subresourceIntegrity usage configurable (#29629)
## Current Behavior
We currently set Subresource Integrity (SRI) on all scripts injected via
`HtmlRspackPlugin`.
This should be configurable.

## Expected Behavior
Expose an option to set SRI - mark false by default to match Rspack's
`HtmlRspackPlugin` behaviour

(cherry picked from commit 0d5e53d60e)
2025-01-15 11:07:20 -05:00
Leosvel Pérez Espinosa 5039ad4e5d fix(angular): restore esm2022 bundle and drop fesm2022 in ng-packagr-lite executor (#29615)
## Current Behavior

In Nx 20.2.0, the `ng-packagr-lite` executor stopped producing the
ESM2022 outputs and started producing the FESM2022 outputs. This was due
to the Angular Package Format (APF) dropping the ESM2022 outputs, which
was reflected in the upstream `ng-packagr` implementation. Due to this
change, the libraries' build time and memory increased compared to the
previous versions.

## Expected Behavior

The `ng-packagr-lite` executor should only produce ESM2022 outputs and
avoid running an extra step to bundle the outputs to produce the
FESM2022.

Given the `ng-packagr-lite` executor is not meant to produce publishable
artifacts, its output doesn't need to strictly comply with the APF and
can focus more on build performance.

## Related Issue(s)

Fixes #29519

(cherry picked from commit f24a869b67)
2025-01-15 11:07:19 -05:00
Jack Hsu 70e10dd797 fix(js): non-buildable js libs specify type=module (#29620)
In the new TS solution setup, non-buildable libraries should still`type:
module`. This can lead to problem since ESM is used but the type will
default to CJS.

This PR also updates `nx sync` for TS references such that transitive
deps are not sycned by default, unless
`NX_ENABLE_TS_SYNC_TRANSITIVE_DEPENDENCIES=true` env var is setup.
Previously, the transitive deps are synced unless the env var disables
it. There isn't a good reason to enable it by default, and it is much
cleaner to not sync by default. This means that if we have libs `a`,
`b`, and `c`, where `a -> b` and `b -> c` dependency edges are formed,
then running:

```
nx sync
```

Will update `a/tsconfig.json` to contain refs to `b` but not `c`.
Whereas:

```
NX_ENABLE_TS_SYNC_TRANSITIVE_DEPENDENCIES=true nx sync
```

Will update `a/tsconfig.json` to contain refs to both `b` and `c`.

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
`type` is missing

## Expected Behavior
`type: module` is set in `package.json`

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
2025-01-15 11:06:46 -05:00
Craigory Coppola 311204a8b4 fix(core): show better project graph errors (#29525)
## Current Behavior
Sub-errors are hidden when any project graph error is encountered. This
is detrimental, as things like "missing comma in JSON" get hidden and
make people think that Nx is broken, when in fact their config files are
invalid.

## Expected Behavior
Sub errors are shown regardless of verbose logging (but including their
stack trace if verbose logging is enabled)

### Without Verbose

![image](https://github.com/user-attachments/assets/3a96d07e-3f0a-4eb7-8629-0c02c6912746)

### With Verbose

![image](https://github.com/user-attachments/assets/41b83e19-e6b1-471c-80ca-004b8f56d8f2)

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit c060b3ae7f)
2025-01-15 11:06:45 -05:00
Colum Ferry bd35bfe4a5 fix(core): update package script logic to handle cli tool name as command (#29617)
## Current Behavior
When we have an inferred target command that matches the entry point of
the cli tool, there is a chance we do not replace package scripts
correctly

e.g.

```
{
  "dev": "vite",
  "build": "tsc -b && vite build",
  "preview": "vite preview"
}
```

this could result in package scripts being updated to

```
{
  "dev": "nx dev",
  "build": "tsc -b && nx vite:build",
  "preview": "nx dev preview"
}
```

## Expected Behavior
We should update the package scripts correctly to match the desired
inferred target

```
{
  "preview": "nx preview"
}
```

(cherry picked from commit c2fa9a03fd)
2025-01-15 11:06:44 -05:00
James Garbutt ed3c5cba6e cleanup(core): move esbuild to use tinyglobby (#29453)
(cherry picked from commit c6e9565973)
2025-01-15 11:06:43 -05:00
Alex H 099ee419fa chore(core): nx plugin submission @klerick/nx-angular-mf (#29548)
<!--
_[Please make sure you have read the submission guidelines before
posting an
PR](https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#submit-pr)_

# Community Plugin Submission

Thanks for submitting your Nx Plugin to our community plugins list. Make
sure to follow these steps to ensure that your PR is approved in a
timely manner.

## Plugin Requirements

Before you submit your plugin to be listed in our registry, it needs to
meet the following requirements:
- Run some kind of automated e2e tests in your repository
- Include `@nx/devkit` as a `dependency` in the plugin's `package.json`
- List a `repository.url` in the plugin's `package.json`

i.e.

```
{
  "repository": {
    "type": "git",
    "url": "https://github.com/nrwl/nx.git",
    "directory": "packages/web"
  }
}
```

Note: We reserve the right to remove unmaintained plugins from the
registry. If the plugins become maintained again, they can be
resubmitted to the registry.

## Steps to Submit Your Plugin
- Use the following commit message template: `chore(core): nx plugin
submission [PLUGIN_NAME]`
- Update the `community/approved-plugins.json` file with a new entry for
your plugin that includes `name`, `url`, `description`:

Example:

```json
// community/approved-plugins.json

[{
    "name": "@community/plugin",
    "url": "https://github.com/community/plugin",
    "description": "This plugin provides the following capabilities."
}]
```

Once merged, your plugin will be available when running the `nx list`
command, and will also be available in the Plugin Registry on
[nx.dev](https://nx.dev/plugin-registry)
-->

# Community Plugin Submission

## @klerick/nx-angular-mf

Custom builder for Angular projects designed to simplify the development
and production of microfrontend applications using native esm module.
The builder integrates with NX to provide seamless support for
development, testing, and deployment of Angular microfrontends.

## Features

- **Microfrontend Support**: Built-in support of native esm module with
dynamic imports them.
- **Server-Side Rendering (SSR)**: Improved SSR compatibility, including
custom module loaders and import maps.
- **Customizable Build Process**: Flexible options for managing
dependencies and extending build configurations.
- **Dev Server Enhancements**:
  - Incremental hydration support.
  - Dynamic `importmap` generation.
  - Automatic dependency resolution and rebuilds.
- **Seamless NX Integration**: Fully compatible with NX workspace for
streamlined project management.

(cherry picked from commit 1a85efca48)
2025-01-15 11:06:42 -05:00
Craigory Coppola 4aa1412099 chore(core): bump fs4 (#29611)
The version we relied on was yanked from cargo for some reason 🤷

(cherry picked from commit facb6dbb95)
2025-01-15 11:06:41 -05:00
Thomas Dekiere 3737d8014f fix(release): ensure git push option is always applied (#29596)
(cherry picked from commit bde8a217f7)
2025-01-15 11:06:41 -05:00
Nicholas Cunningham 4667cd6c54 fix(js): improve error handling during SWC compilation (#29605)
Improves our error handling for swc when using `@nx/js:swc` executor

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->
The executor fails to build if the workspace has a newer versions of
`@swc/cli` e.g.(`0.6.0`) is installed since it now uses stderr instead
of message to log errors.
RE: https://github.com/swc-project/pkgs/pull/53

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
The executor should pass in this scenario.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #29599

(cherry picked from commit 61815929d7)
2025-01-15 11:06:40 -05:00
Leosvel Pérez Espinosa 55fd3bf27d fix(js): do not generate explicit vitest task config for a js library unless adding plugin is disabled (#29606)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

Generating a js library with any bundler other than `vite` and with the
`vitest` test runner results in an explicit `test` task in the project
configuration.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Generating a js library with any bundler other than `vite` and with the
`vitest` test runner should not generate an explicit `test` task in the
project configuration. The `test` task should be inferred.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit a352c81876)
2025-01-15 11:06:29 -05:00
Benjamin Cabanes 537099a658 docs(nx-dev): fix inconsistent styling in SectionHeading components (#29597)
Removed the redundant "text-white" class from SectionHeading components to standardize styles.

(cherry picked from commit dc2c9dae24)
2025-01-15 11:06:28 -05:00
Benjamin Cabanes 1bee6c7ffc docs(nx-dev): Add analytics events & improve CTAs across components (#29592)
Introduced custom event tracking for ebook downloads and sales contact buttons using `sendCustomEvent`. Enhanced call-to-action designs by replacing links with `ButtonLink` components and adjusted styling and text for clarity. Updated webinar links and refined headings for consistency.

(cherry picked from commit f57d88a624)
2025-01-15 11:06:27 -05:00
Benjamin Cabanes 721d580a7a docs(nx-dev): enable WebinarNotifier and update webinar details (#29591)
Re-enabled the `WebinarNotifier` component in the app layout and updated the webinar date and localStorage key to reflect the new event on January 22, 2025.

(cherry picked from commit bbbfd9f43b)
2025-01-15 11:06:26 -05:00
Leosvel Pérez Espinosa bb363d6eaa fix(misc): ensure exports are generated for several lib generators in ts solution setup (#29588)
- Update React Native, React, Remix and Vue library generators to
produce `exports` in the `package.json` for the TS solution setup
- Fix an issue in `@nx/rollup/with-nx` where an unhandled `undefined`
plugin was causing an error to be thrown
- Fix output path of the build task for React Native libraries in the TS
solution setup

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit 9dbebbee20)
2025-01-15 11:06:26 -05:00
Nicholas Cunningham 8d7505b063 fix(nx-dev): Update Webinar link (#29590)
(cherry picked from commit cbea0623df)
2025-01-15 11:06:25 -05:00
Robb Traister 0fd1e3601f fix(core): support subpath exports when constructing the project graph (#29577)
Sibling dependencies that rely exclusively on subpath exports are
excluded from the dependency graph because there is no exact match.

This adds a fallback to look for subpath exports if the exact match is
not found.

This also adds logic to respect conditional exports independent from
subpath exports.

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior

Importing a workspace dependency via subpath export fails to match the
package name, and so is not included in the dependency graph.

### Example

```apps/api/package.json```
```json
  "name": "@my-org/api",
  "dependencies": {
    "@my-org/services": "workspace:*"
  }
```

```libs/services/package.json```
```json
  "name": "@my-org/services",
  "exports": {
    "./email": "./dist/email.js"
  }
```

The `@my-org/api` app should be able to import the email service with
`import { EmailService } from "@my-org/services/email"`.

However, the `getPackageEntryPointsToProjectMap` implementation results
in an object with a key of `@my-org/services/email`, but not
`@my-org/services`. This is not specifically a problem, except that
`findDependencyInWorkspaceProjects` only considers exact matches within
those object keys.

## Expected Behavior

Importing a workspace dependency via subpath export should be included
in the dependency graph.

I also addressed a related issue where the following resulted in keys of
`@my-org/services/default` and `@my-org/services/types`, which is
incorrect according to the subpath/conditional export rules.
```json
  "exports": {
    "default": "./dist/index.js",
    "types": "./dist/index.d.ts"
  }
```

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #29486

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
(cherry picked from commit d08ad7504f)
2025-01-15 11:06:22 -05:00
Leosvel Pérez Espinosa ba48f0a54e fix(misc): ensure all project generators add project to workspaces config (#29582)
- Update project generators to add the project to the workspaces setup
in the new TS solution setup
- Update some library generators that were not running package
installation

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit 0d5bfe3700)
2025-01-15 11:06:20 -05:00
Nicholas Cunningham 28de4454e7 feat(nx-dev): add trial pages for Powerpack and Enterprise, update contact sales team page (#29554)
(cherry picked from commit d30a84f49c)
2025-01-15 11:06:18 -05:00
Colum Ferry 7133996d41 fix(react): setup mf env var as input for rspack (#29584)
## Current Behavior
The Module Federation `NxRuntimeLibraryControlPlugin` relies on an
environment variable that is set during the build/serve process.
This could potentially lead to issues with cache restoration.

The impact should be minimal as the runtime control plugin should only
be added to the module federation config when the env var is set.
It should only be set by the `module-federation-dev-server` executor
which is invoked during serve - a non-cacheable task already.

## Expected Behavior
Ensure the env var is set as an input to ensure maximum accuracy with
module federation builds via rspack executor

(cherry picked from commit dbdb72aee2)
2025-01-15 11:06:17 -05:00
Rares Matei 4c359b1567 chore(repo): use new recommended agents cache folders (#29435)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit e89053c3b6)
2025-01-15 11:06:15 -05:00
Leosvel Pérez Espinosa fa7968d1d1 fix(js): generate js libs with exports in package.json and ensure esm output when using rollup bundler (#29565)
- Ensure libs are generated with `exports` in `package.json`
- Generate `types` instead of `typings` in package.json
- Update js lib with rollup to only output esm
- Update `tsconfig.spec.json` for js libraries with rollup to set
`module: esnext` and `moduleResolution: bundler` (they use `@swc/jest`)
- Fix `@nx/js/typescript` issue with absolute paths when normalizing
inputs/outputs
- Fix `@nx/js/typescript` issue identifying buildable libs
- Fix express app generator not installing `@types/express`

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

---------

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
(cherry picked from commit dd9b09f917)
2025-01-15 11:06:15 -05:00
Jack Hsu f6f8536064 fix(js): update detection of ts solution setup (#29576)
Since we simplified `tsconfig.base.json`'s `compilerOptions` to not
include values that match defaults (as per Jake's feedback), the logic
to detect TS solution setup should check that `declaration` is
explicitly set to `false`, rather than that it is falsy.

Clean up PR: https://github.com/nrwl/nx/pull/29550

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->
We're not detecting TS solution setup correctly

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Detection works

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit cbfc6fe97f)
2025-01-15 11:06:11 -05:00
Juri Strumpflohner 1c3c90aa1a feat(nx-dev): customer videos on customer page (#29380)
Co-authored-by: Nicholas Cunningham <ndcunningham@gmail.com>
(cherry picked from commit 9c176d8a44)
2025-01-15 11:06:10 -05:00
Zachary DeRose de3060bb80 docs(misc): bundler blogpost (#29569)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit c09e3690b1)
2025-01-15 11:06:09 -05:00
Rares Matei ca1988d059 docs(nx-cloud): use new cache recommendations on custom launch template docs (#29434)
Now that we home folder level caching has been unblocked, we can update
the package manager cache recommendations.

(cherry picked from commit 62057e99e0)
2025-01-15 11:06:08 -05:00
Nicholas Cunningham dc41bfe2ec fix(js): Update typescript plugin check for buildable projects (#29431)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->
Currently, we use `rootDir` to check if the project is buildable. This
might not be correct in the case where the transpiled files are inside
source.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
It should work the for projects as long as the main / exports files are
not source files.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit a77e3ef083)
2025-01-15 11:05:53 -05:00
Rares Matei a24e16f4ef docs(nx-cloud): update release notes (#29351)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit 325b9f6471)
2025-01-15 11:05:52 -05:00
Phillip Barta 3c928f34a7 cleanup(testing): migrate jest to picocolors (#29561)
migrates `@nx/jest` from `chalk` to `picocolors`

Part of https://github.com/es-tooling/ecosystem-cleanup/issues/117

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit b491489cb2)
2025-01-15 11:05:51 -05:00
Aidan Temple 27444bdf05 feat(web): support custom cors headers (#29382)
## Current Behavior

It is not possible to pass custom cors headers to the
`@nx/web:file-server` executor despite `http-server` supporting it.

## Expected Behavior

`@nx/web:file-server` should pass-through a string of custom cors
headers to `http-server`.

## Related Issue(s)

(cherry picked from commit f98ae78734)
2025-01-15 11:05:50 -05:00
Phillip Barta 06e7bb8a12 cleanup(angular): migrate angular to picocolors (#29444)
migrates `@nx/angular` from `chalk` to `picocolors`

Part of https://github.com/es-tooling/ecosystem-cleanup/issues/117

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit bc7c80908b)
2025-01-15 11:05:49 -05:00
Tine Kondo 064bc422a2 feat(testing): add option ciGroupName to @nx/jest/plugin (#29365)
Add option `ciGroupName` to the `@nx/jest/plugin` to allow customizing
the `Jest` atomized taks group on CI.

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

When using Atomizer on Jest for **unit tests** (via the `"ciTargetName":
"test-ci"`), the atomized tasks will be grouped under the misleading
name **"E2E (CI)"**.

Worst, if Atomizer is enabled for both **unit** and **e2e** tests, it
will result on E2E atomized tasks being overwritten by the one from unit
tests... when run on Nx Cloud.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

Allow customizing the name of the atomized tasks group. The group name
can be derived from the `ciTargetName` , when not explicitly provided.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #28066

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
(cherry picked from commit addf107471)
2025-01-15 11:05:40 -05:00
Craigory Coppola 843c06f404 fix(core): avoid launching default plugins twice (#29539)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
Default plugins are launched twice when loading plugins in a workspace
that has local plugins:
- Once to resolve the local plugin
- Once to be used as an actual plugin

## Expected Behavior
Default plugins are launched once and reused

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

---------

Co-authored-by: FrozenPandaz <jasonjean1993@gmail.com>
(cherry picked from commit 0edd1102f7)
2025-01-15 11:04:44 -05:00
Jack Hsu 206a47e8ff fix(js): avoid nested paths in workspaces because they can lead to future issues (#29553)
For the new TS setup, we currently use nested glob patterns: `apps/**`,
`libs/**`, and `packages/**`.

Nested paths can result into too many projects being matched. For
example, if `libs/mylib/src/__fixtures__/package.json` is there for
testing, it will be matched as a project and likely result in an error.

Other tools like turborepo also caution against this:
https://turbo.build/repo/docs/crafting-your-repository/structuring-a-repository#declaring-directories-for-packages

If users want to, they could change to nested `**` paths, but we should
not use it by default.

Note: For CNW, we only use `apps/*` by default since that is where the
project lives. When users do `nx g lib packages/foo` then `packages/*`
will be added automatically.

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->
Use nested `**` paths.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Don't use nested `**` paths.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit fb318005f2)
2025-01-15 11:04:42 -05:00
Jonathan Cammisuli abfe5d9804 fix(core): update nx cloud bundle install directory logic (#29555) 2025-01-15 11:04:42 -05:00
Leosvel Pérez Espinosa 3ccec47072 fix(js): ensure js libraries' build produce esm output in ts solution setup (#29546)
- Update js libraries for bundlers `esbuild`, `swc`, and `tsc` to
produce ESM output when using the TS solution setup.
- Fix `esbuild` and `swc` executors so they generate declaration files
even when skipping type-checking.
- Add `cjs` and `cts` to the `ignoredFiles` pattern for the rollup
config file in the eslint config.
- Ensure running an install after a js library is generated when using
the TS solution setup.

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
2025-01-15 11:04:41 -05:00
Leosvel Pérez Espinosa 7fa59941df fix(testing): infer correct outputs when absolute paths are provided in playwright config (#29549)
Update `@nx/playwright/plugin` to properly handle absolute paths set in
the playwright config to infer outputs correctly.

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit 6b8ba9778e)
2025-01-15 11:04:38 -05:00
Leosvel Pérez Espinosa ef63f29275 fix(js): do not set project references to non-existing tsconfig files in sync generator (#29536)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit 160800e66f)
2025-01-15 11:04:35 -05:00
Mike Hartington ed40a514c8 fix(nx-dev): fix heroicons for safari (#29544)
(cherry picked from commit 97e1e3bc50)
2025-01-15 11:04:33 -05:00
Colum Ferry b8752db9f1 feat(module-federation): upgrade to latest version of @module-federation/enhanced (#29535)
## Current Behavior
We currently use version `0.7.6` of `@module-federation/enhanced`.
This version does not contain the `externalRuntime` experiment to reduce
the remoteEntry bundle size.

## Expected Behavior
Upgrade Nx dependency of `@module-federation/enhanced` to version
`0.8.8`.

(cherry picked from commit 5157a0daf9)
2025-01-15 11:04:31 -05:00
Benjamin Cabanes 1b736ac50b docs(nx-dev): set year to 2025 in LICENSE and footer (#29524)
The copyright year was updated from 2024 to 2025 in both the LICENSE file and the footer component.

(cherry picked from commit 7f2693a048)
2025-01-15 11:04:30 -05:00
Jack Hsu e74dee0086 fix(react): transpile SVGR into React 19 compatible component (#29543)
This PR fixes an issue with React 19 and our `@nx/react/plugins/jest`
transform. The current transform uses an unsupported `$$typeof` symbol,
and also uses the deprecated `forwardRef` API.

The updated transform will use new API for React 19 and older, while
maintaining the previous API for React 18 and earlier. The backwards
compatibility may be needed if the test is using `ref`, which requires
`forwardRef` older versions.

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
SVGR fails in Jest tests with React 19

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
SVGR works

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit 90c0c8ebf6)
2025-01-15 11:04:29 -05:00
Mike Hartington c57ff37dc4 docs(misc): update nx 20.3 blog (#29542)
(cherry picked from commit 8dc100a1af)
2025-01-15 11:04:28 -05:00
Zachary DeRose fae2455f22 docs(misc): nx 20.3 blogpost (#29512)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit 3f3c8747c6)
2025-01-07 13:27:10 -05:00
Jack Hsu 5c51d92f30 fix(js): infer outputs correctly when both rootDir and outDir are set for tsconfig (#29531)
When the tsconfig has `rootDir` and `outDir` both defined, then the
`*.tsbuildinfo` file is not cached. This makes incremental tsc not work
through distribution (e.g. agents).

For example, given this `tsconfig.lib.json` file:

```json
{
  "compilerOptions": {
    "outDir": "out-tsc/lib-1",
    "rootDir": "src"
  }
}
```

The outputs (e.g. `*.d.ts` files) are under
`{projectRoot}/out-tsc/lib-1`, but the tsbuild info file is under
`{projectRoot}/out-tsc/tsconfig.lib.tsbuildinfo`.

## Current Behavior
tsbuildinfo file is not cached

## Expected Behavior
tsbuildinfo file is cached

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
(cherry picked from commit df27a97c7e)
2025-01-07 12:03:13 -05:00
Isaac Mann 08f385720b docs(core): create conformance rule recipe (#29406)
- [Create a Conformance
Rule](https://nx-dev-git-docs-conformance-rule-recipe-nrwl.vercel.app/nx-api/powerpack-conformance/documents/create-conformance-rule)
recipe

Blocked until the `create-rule` generator is merged and released

(cherry picked from commit 82751a1446)
2025-01-07 12:03:12 -05:00
Matt Lewis c9b14a2a3f fix(vite): tsconfig paths plugin should not partially match paths (#29501)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

When there is a path mapping like:
```
"match-lib-deep/": ["libs/lib1/src/*"],
"match-lib-top-level": ["libs/lib2/src/*"],
"match-lib/*": ["libs/lib3/src/*"],
```

Imports to `match-lib-deep` or `match-lib-top-level` will try and use
the last `match-lib` path mapping as the trailing `/` is not accounted
for in the `startsWith` check.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

The correct path mapping is matched.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

N/A

(cherry picked from commit 6948249ac7)
2025-01-07 12:03:11 -05:00
Daniel Karski 083809533d docs(storybook): update path in library generator command (#29483)
library path corrected for storybook-host generator

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit f7712f6321)
2025-01-07 12:03:10 -05:00
Jack Stevenson 84617b0ccb fix(js): only add typescript project references for explicit dependencies in sync generator (#28998)
This change omits references to implicit dependency tsconfigs for
typescript projects in the sync generator, since given that they are not
referenced directly in code there is no need for project references.

## Current Behavior
TypeScript sync generator adds references to any dependency project
which has a tsconfig (where composite is true), including implicit
dependencies where these references are unnecessary and can potentially
cause build failures.

See [example
repo](https://github.com/cogwirrel/nx-sync-generator-implicit-deps-example).

## Expected Behavior
Only explicit dependencies should be referenced in tsconfigs.

## Related Issue(s)
Fixes #28997

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
(cherry picked from commit 9e78142185)
2025-01-07 12:03:09 -05:00
Juri 6f9f461c66 docs(nx-dev): update weird dashes in article
(cherry picked from commit 68b293f6be)
2025-01-07 12:03:08 -05:00
Philip Fulcher 615fd172a5 fix(nx-dev): add playsInline to video loop component
(cherry picked from commit aceebca1aa)
2025-01-07 12:03:07 -05:00
Nicholas Cunningham 707b732860 fix(nx-dev): Quote typo (#29513)
(cherry picked from commit cb4a93e872)
2025-01-07 12:03:06 -05:00
Slava 33e350b5c2 docs(react): add spaces in 2023-08-10-create-your-own-create-react-app-cli.md (#29510)
Spaces in some places between word and backquote has been missed.

## Current Behavior
No spaces between formatted strings in some places.

## Expected Behavior
Spaces should appear between formatted string.

## Related Issue(s)
Not found any related issues. I have decided just create PR.

(cherry picked from commit 21d5bd8d66)
2025-01-07 12:03:05 -05:00
Benjamin Cabanes 8d383cef8f docs(nx-dev): update Nx Cloud CTA links to include UTM parameters (#29489)
Replaced internal Nx Cloud links with full URLs containing UTM parameters for better tracking of user interactions across various components. Additionally, minor improvements were made to React type definitions for clarity and consistency.

(cherry picked from commit 8a841cd754)
2025-01-07 12:03:04 -05:00
Juri 039c9640a1 docs(nx-dev): update Nx Console blog post to include animations
(cherry picked from commit fbd3db84f8)
2025-01-07 12:03:03 -05:00
Juri 6bed247fff docs(nx-dev): remove duplicated paragraph in blog post
(cherry picked from commit 2b479da159)
2025-01-07 12:03:02 -05:00
Benjamin Cabanes 14e8dccbce docs(nx-dev): replace graph image with light/dark neuron variants (#29461)
Replaced the old `graphs.jpg` image with two new `.avif` images to support light and dark mode. Updated the component to switch between the light and dark neuron visuals based on theme.

(cherry picked from commit 69a13dacd5)
2025-01-07 12:03:00 -05:00
Juri fcab3c8e6a docs(nx-dev): updates to EOY blog post
(cherry picked from commit a607df6168)
2025-01-07 12:02:58 -05:00
Juri f89d6b309e docs(nx-dev): year 2025 review post
(cherry picked from commit 89cb91cd76)
2025-01-07 12:02:56 -05:00
Juri d98e6e4e84 feat(nx-dev): add TOC markdoc component for blog posts
(cherry picked from commit 3e564864fd)
2025-01-07 12:02:55 -05:00
Bartosz Adamczyk f7e796a3d6 fix(release): invalid config path in hint for using skipLockFileUpdate (#29425)
(cherry picked from commit 90e12a77af)
2025-01-07 12:02:54 -05:00
Isaac Mann 51bebd9745 docs(nx-dev): render keywords meta tag (#29450)
Renders `keywords` property from frontmatter as a `<meta>` tag.

(cherry picked from commit c7e2782e78)
2025-01-07 12:02:53 -05:00
Craigory Coppola fe17c23333 fix(core): daemon spinner should show text (#29448)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
Daemon spinner doesn't show up

## Expected Behavior
Daemon spinner shows properly

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit d7ffba8f76)
2025-01-07 12:02:52 -05:00
Emily Xiong 59b30ef094 fix(js): not generate tsconfig if already exists (#29317)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->
- in serve target, it uses executor `@nx/webpack:dev-server`
- in `packages/webpack/src/executors/dev-server/dev-server.impl.ts`,
when buildLibsFromSource is false, it calls createTmpTsConfig to create
a temp config
- in webpack.config.js, it has `module.exports =
composePlugins(withNx()`. in withNx, it calls
NxTsconfigPathsWebpackPlugin.
- when buildLibsFromSource is false, it called createTmpTsConfig again
based on the temp config. it created an infinite loop because it creates
a tsconfig that extends itself.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
- do not create a temp config if it is a generated ts config

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes https://github.com/nrwl/nx/issues/28006

(cherry picked from commit 81c66eca73)
2025-01-07 12:02:51 -05:00
320 changed files with 61502 additions and 3342 deletions
+8 -16
View File
@@ -12,17 +12,13 @@ launch-templates:
NX_NATIVE_LOGGING: 'nx::native::db'
init-steps:
- name: Checkout
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/checkout/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
- name: Cache restore
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/cache/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
inputs:
key: 'pnpm-lock.yaml'
paths: |
node_modules
~/.cache/Cypress
~/.cache/ms-playwright
~/.pnpm-store
base_branch: 'master'
paths: .pnpm-store
base-branch: 'master'
- name: Install e2e deps
script: |
sudo apt-get update
@@ -69,17 +65,13 @@ launch-templates:
NX_NATIVE_LOGGING: 'nx::native::db'
init-steps:
- name: Checkout
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/checkout/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
- name: Cache restore
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/cache/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
inputs:
key: 'pnpm-lock.yaml'
paths: |
node_modules
~/.cache/Cypress
~/.cache/ms-playwright
~/.pnpm-store
base_branch: 'master'
paths: .pnpm-store
base-branch: 'master'
- name: Install e2e deps
script: |
sudo apt-get update
Generated
+2 -2
View File
@@ -547,9 +547,9 @@ dependencies = [
[[package]]
name = "fs4"
version = "0.10.0"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec6fcfb3c0c1d71612528825042261419d5dade9678c39a781e05b63677d9b32"
checksum = "c29c30684418547d476f0b48e84f4821639119c483b1eccd566c8cd0cd05f521"
dependencies = [
"rustix",
"windows-sys 0.52.0",
+1 -1
View File
@@ -1,6 +1,6 @@
(The MIT License)
Copyright (c) 2017-2024 Narwhal Technologies Inc.
Copyright (c) 2017-2025 Narwhal Technologies Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
+5
View File
@@ -4,6 +4,11 @@
"description": "Nx plugin add vitepress project to your workspace",
"url": "https://github.com/Ahryman40k/nx-vitepress/tree/main/packages/nx-vitepress"
},
{
"name": "@klerick/nx-angular-mf",
"description": "Custom Angular Builder for Microfrontend Architecture",
"url": "https://github.com/klerick/nx-angular-mf"
},
{
"name": "@nightwatch/nx",
"description": "The NightwatchJS plugin allows your workspace to use the power of NightwatchJS for E2E and Component Testing on Desktop and Mobile",
+8
View File
@@ -216,6 +216,14 @@ You can have a more dynamic visualization of a terminal output by using the foll
{% terminal-video src="/documentation/shared/images/caching/cache-terminal-animation.mp4" /%}
```
#### Table of Contents
You can add a table of contents to your document by using the following component. This is mostly useful for blog posts.
```markdown
{% toc /%}
```
#### Custom iframes
We can display a special iframe and setting its width inside the document.
@@ -180,9 +180,9 @@ export default presetGenerator;
The preset generator does 2 things:
- Create an Nx project using the`addProjectConfiguration` function. This creates a `project.json` file which allows Nx to run commands on it.
- Generates files in the project using the`generateFiles` function. This uses the templates under `src/generators/preset/files` which are interpolated to become the files that are generated for the user.
- Format the generated files with `prettier` with the`formatFiles` function
- Create an Nx project using the `addProjectConfiguration` function. This creates a `project.json` file which allows Nx to run commands on it.
- Generates files in the project using the `generateFiles` function. This uses the templates under `src/generators/preset/files` which are interpolated to become the files that are generated for the user.
- Format the generated files with `prettier` with the `formatFiles` function
![](/blog/images/2023-08-10/38RvkLIwUAvVDDrEp5sFPQ.avif)
_preset generator_
@@ -588,7 +588,7 @@ You can modify this e2e test to test your CLI. Then, run it using the command `n
The default test works like this:
1. Creates a test workspace at `tmp/`using the `create-my-own-react-app` CLI
1. Creates a test workspace at `tmp/` using the `create-my-own-react-app` CLI
2. Runs `npm ls my-own-react` to validate that the plugin is installed in the test workspace
3. Cleans up the test workspace
-1
View File
@@ -5,7 +5,6 @@ authors: [Mike Hartington]
tags: [nx, release]
cover_image: /blog/images/2024-10-03/nx-20-header.png
youtubeUrl: https://youtu.be/5-QwtlhaJK8
pinned: true
---
I know it's hard to believe but Nx 20 is here! There's a lot of great updates in this release, but look back at some of the major features from Nx 19:
@@ -3,7 +3,7 @@ title: Nx Cloud Pipelines Come To Nx Console
slug: nx-cloud-pipelines-come-to-nx-console
authors: [Zack DeRose]
tags: [nx, nx-cloud, nx-console, enterprise]
cover_image: '/blog/images/2024-11-25/thumbnail.png'
cover_image: /blog/images/2024-11-25/thumbnail.png
---
## Your CI Pipelines, Now At-A-Glance In Your IDE
@@ -12,7 +12,7 @@ We're in the process of adding a new integration between [Nx Cloud](/nx-cloud),
Now, once you've [connected your Nx Console to Nx Cloud](https://blog.nrwl.io/nx-console-meets-nx-cloud-d45dc099dc5d), you will have access to a new panel in the console that shows all of your recent CI Pipelines, including those in progress now.
![Nx Cloud Pipeline Panel](/blog/images/2024-11-25/pipeline-panel.png)
{% video-player src="/documentation/blog/media/nx-console-pipeline-running.mp4" alt="Nx Console CI Pipeline Execution" /%}
This way, you can keep an eye on the status of the pipeline of your latest PR, and always just 1 click away from seeing detailed your results on Nx Cloud.
@@ -20,7 +20,7 @@ This way, you can keep an eye on the status of the pipeline of your latest PR, a
In addition to a panel where you can see all of your recent pipelines, you can also receive pop-up notifications when a pipeline completes
![Pipeline Result Notification](/blog/images/2024-11-25/result-notification.png)
{% video-player src="/documentation/blog/media/nxconsole-ci-completion.mp4" alt="Nx Console CI Completion" /%}
Head to the Nx Console settings to adjust controls on these notifications. This will allow you to adjust notifications to only show for failed runs if you prefer, or to turn off the notifications altogether.
@@ -30,9 +30,7 @@ Head to the Nx Console settings to adjust controls on these notifications. This
We're in the process of landing this on Nx Console for VSCode now - and we're already dog-fooding it on the `nx` and `nx-console` repos. It will be landing in the next few week for all Nx Cloud projects, with the feature landing on Nx Console for JetBrains IDEs to follow soon!
For more on Nx Cloud, check out the Solutions tab above! Nx Cloud is free to get started, so you can [create your free account today](https://cloud.nx.app)!
[![Learn More about Nx Cloud](/blog/images/2024-11-25/learn-more-about-nx-cloud.gif)](/nx-cloud)
For more on Nx Cloud go to [nx.dev/nx-cloud](/nx-cloud)! Nx Cloud is free to get started, so you can [create your free account today](https://nx.app)!
And if you're not using Nx Console yet, you can get started now with Nx Console available for VSCode and JetBrains IDEs:
+279
View File
@@ -0,0 +1,279 @@
---
title: 'Nx Highlights 2024'
slug: nx-highlights-2024
authors: ['Juri Strumpflohner', 'Victor Savkin']
tags: ['nx']
cover_image: /blog/images/articles/nx-highlights-2024-bg.jpg
pinned: true,
youtubeUrl: https://youtu.be/n4MBETdLBVg
---
Thank you for being part of the Nx community. Your support and contributions make Nx what it is today, driving it forward as the go-to solution for delivering the best developer experience in monorepos. Nx and Nx Cloud integrate to provide a **complete solution for managing monorepos** at every stage of the development cycle, both locally and in CI.
In 2024, we focused on making Nx **more adaptable**, seamlessly fitting into OSS projects and large enterprise codebases. Our goal was to balance **flexibility and power**, ensuring Nx scales with your needs while remaining easy to adopt in **existing setups**. This progress is the result of **working with the community, collaborating with other tooling teams, and engaging directly with enterprises**.
{% github-repository title="Star Nx on GitHub" url="https://github.com/nrwl/nx" /%}
As we wrap up the year, were excited to share the highlights and give you a look at whats coming in 2025.
{% toc /%}
## Top 10 Highlights
Here are our picks for the top 10 highlights for 2024. There's no particular ordering here in terms of more or less relevance.
### Project Crystal
Nx has been solving monorepos long before package managers introduced features like workspaces. Early on, we used **TypeScript path mappings** to manage project linking, resulting in **integrated monorepos** powered by [Nx plugins](/concepts/nx-plugins#what-are-nx-plugins) to automate setup and tool integration.
When **npm**, **Yarn**, and **PNPM** introduced "workspaces," another option emerged: **package-based monorepos**, where Nx primarily acted as a task runner with caching and parallelization.
Integrated monorepos offer automation but are opinionated. Package-based monorepos provide flexibility but require more effort to manage. Combining the two wasnt easy, largely because of how Nx plugins were initially designed.
We wanted to make sure you didnt have to choose. This led to **Project Crystal**, an effort to make Nx plugins more adaptable. These "crystalized" plugins:
- **Rely on your existing config files** (e.g., `@nx/vite` enhances `vite.config.ts` rather than replacing it).
- **Enhance without interfering**, allowing for a better experience without locking you into the plugin.
Over the past year, most of our plugins have been "crystalized," making it easier to mix and match both monorepo styles.
![project-crystal-plugins.avif](/blog/images/articles/project-crystal-plugins.avif)
This approach gives you flexibility while keeping the automation and developer experience that make Nx essential for scaling monorepos.
Want to dive deeper? Check out [our announcement blog post](/blog/what-if-nx-plugins-were-more-like-vscode-extensions) and [documentation](/concepts/inferred-tasks).
### Nx Agents, Atomizer, and Flakiness Detection
![agents-atomizer-flaky-viz.avif](/blog/images/articles/agents-atomizer-flaky-viz.avif)
Nx isnt just about managing monorepos locally. A big part of the workflow happens on CI. If your monorepo doesnt run reliably in CI, its not working. Thats why Nx Cloud has been a major focus, especially for scaling monorepos in CI environments. This year, we introduced some of the most impactful features yet:
- [Nx Agents](/ci/features/distribute-task-execution)
- [Atomizer](/ci/features/split-e2e-tasks)
- [Flakiness detection](/ci/features/flaky-tasks)
With remote caching as the foundation, these features take CI performance to the next level. At scale, **parallelizing tasks across machines becomes necessary**. We've done this manually for clients in the past, scripting complex CI setups. A lot of that experience shaped Nx Agents, making distribution seamless and efficient.
Manually configuring parallelization is time-consuming and fragile. Its a static optimization, while your monorepo keeps changing. We wrote a [blog post](/blog/reliable-ci-a-new-execution-model-fixing-both-flakiness-and-slowness) that explains the difference between the traditional **push-based model** and Nxs **pull-based approach** to CI.
![nx-agents-run-viz.avif](/blog/images/articles/nx-agents-run-viz.avif)
If you havent tried Nx Agents yet, enabling them takes a single line in your CI setup:
```yaml
npx nx-cloud start-ci-run --distribute-on="3 linux-medium-js"
```
Check out [the docs](/ci/features/distribute-task-execution) or watch our [free video course](/courses/pnpm-nx-next/lessons-11-nx-agents) where we update an existing CI pipeline to use Nx Agents.
Even with distribution in place, **long-running tasks like e2e tests** can still slow things down. **Atomizer automatically breaks these into smaller pieces** that can run in parallel, making task distribution much more efficient.
![](/courses/pnpm-nx-next/images/e2e-splitting-anim.gif)
Finally, we introduced **flakiness detection** across all CI task runs. Flaky tasks (usually tests) waste a lot of time. Instead of forcing you to re-run CI manually, Nx Cloud retries flaky tasks automatically. If the task passes on the second run, the pipeline continues without interruption.
![flaky-task-retry.avif](/blog/images/articles/flaky-task-retry.avif)
### Nx Release
A big use case for Nx isnt just managing application monorepos but also developing and publishing packages to NPM. One missing piece was a built-in way to handle versioning, changelog generation, and publishing. While tools like [Lerna](https://lerna.js.org) or [Changesets](https://github.com/changesets/changesets) could be integrated, many wanted something more tightly connected to Nx itself.
Thats why we released [**Nx Release**](/features/manage-releases). It handles the entire process:
- Bumping versions
- Generating changelogs
- Publishing to NPM or other registries
Nx Release is designed to be flexible. It comes with a [programmatic API](/features/manage-releases#using-the-programmatic-api-for-nx-release) and is implemented in a tech-agnostic way. Nx provides the foundation, and plugins like `@nx/js` extend it to support JavaScript and TypeScript packages. The same system can be extended for Go, Rust, Java, and more.
In the future, Nx Release could grow to handle other release processes, like Docker containers or application deployments.
Take a look at [our docs](/features/manage-releases) or browse [Nx Release recipes](/recipes/nx-release) to see how you can adapt it to fit your workflow.
### Gradle Support
2024 was a big step forward with the release of the **@nx/gradle plugin**. This plugin lets you manage Gradle projects within an Nx workspace, bringing features like task caching, parallel execution, and dependency-aware task orchestration to Java and Kotlin projects.
Gradle projects were traditionally tricky to manage alongside JavaScript libraries in monorepos. Few tools could handle mixed tech stacks smoothly. With **@nx/gradle**, that process is much simpler. Gradle projects now work seamlessly inside Nx, allowing you to:
- **Run Gradle tasks directly with Nx commands** (e.g., `nx build myproject`)
- **Visualize dependencies across projects**, including composite builds, with the Nx Graph
- **Only execute tasks that are affected by code changes**, speeding up builds and CI pipelines
**Composite Build Support** takes this further by pulling in dependencies from composite builds and reflecting them in the task graph. This release reflects our larger goal of breaking down barriers between ecosystems. Nx aims to enable efficient workflows across different languages and technologies, moving closer to a seamless polyglot monorepo experience.
For more details, check out the blog post ["Manage Your Gradle Project using Nx"](/blog/manage-your-gradle-project-using-nx) and our [Gradle tutorial](/getting-started/tutorials/gradle-tutorial).
### Nx Import
Migrating projects into a monorepo is often seen as complicated and error-prone. With **`nx import`**, introduced in 2024, we've simplified the process, preserving **Git history** and minimizing disruptions along the way.
`nx import` builds on the work done in **Project Crystal**, making migrations smoother. For example, when importing a Gradle-based app, Nx detects the Gradle configuration, suggests installing the `@nx/gradle` plugin, and sets everything up for you. It reads your Gradle files, identifies runnable tasks, configures caching, and integrates the project into the workspace.
The experience is the same whether youre importing a JavaScript app, a Gradle project, or another tech stack.
With `nx import`, you can:
- Map existing repositories into an Nx workspace (while preserving Git history)
- Retain existing configurations and workflows without losing functionality
- Get consistent orchestration, caching, and dependency graphing across projects
This significantly reduces the effort involved in **polyrepo-to-monorepo migrations**, allowing teams to consolidate projects without downtime or loss of productivity. What used to be a hassle is now a streamlined process that works across different technologies.
Check out the [docs](/recipes/adopting-nx/import-project) for more details.
### GitHub Managed Orgs in Nx Cloud
![github-org-settings.avif](/blog/images/articles/github-org-settings.avif)
One of our goals with Nx Cloud is to make onboarding as simple as possible. We want to improve CI performance without adding unnecessary configuration or complexity. This year, we introduced **GitHub-powered organizations** to streamline team management and onboarding.
By connecting your GitHub organization, you can select repositories directly. Nx Cloud will automatically submit a PR to configure your workspace and handle GitHub integration.
![nx-cloud-connect-gh-repo.avif](/blog/images/articles/nx-cloud-connect-gh-repo.avif)
A major benefit is that user management syncs directly with GitHub. When someone links their GitHub account to Nx Cloud, theyre automatically added to the correct organization. Membership changes in GitHub are reflected in Nx Cloud without manual intervention.
Learn more about how it works [here](/ci/intro/connect-to-nx-cloud).
### Module Federation
In 2024, we continued expanding Nx's **Module Federation** support, improving functionality and making it easier to use based on feedback from the community.
One major update was the new pattern for the **module-federation-dev-server**. It improves compatibility, reduces resource usage, and provides a smoother local development experience. This approach makes working with Module Federation in Nx easier to set up and scale across larger workspaces.
We also adopted **Module Federation 2.0**, adding runtime plugins and key enhancements. On top of that, we introduced support for **Rspack Module Federation**, allowing Nx users to take advantage of newer tools in the ecosystem.
To simplify setup, we launched **@nx/module-federation**, a package that streamlines configuration and management of federated apps in Nx workspaces. Nxs approach to Module Federation has been highlighted by the community and is now featured on [module-federation.io](https://module-federation.io/practice/monorepos/nx-for-module-federation.html).
For more details on how Module Federation works in Nx, check out the [technical overview](/concepts/module-federation/nx-module-federation-technical-overview) or catch one of our [live streams on Rspack and Module Federation](https://www.youtube.com/watch?v=_c4zjYm0pYE).
### Nx Console
Nx Console has become a key part of the "Nx experience." In 2024, we introduced several updates to make it even more useful.
One standout feature is the **Project Detail View**. With Project Crystal, Nx can dynamically infer targets from your configuration. You can see these [inferred tasks](/concepts/inferred-tasks) by running `nx show project my-project --web`, but now theyre directly available inside Nx Console. This gives you quick access to project details, command options, caching configurations, and more, right in your editor.
{% video-player src="/documentation/blog/media/nxconsole-project-view.mp4" alt="Nx Console Project Detail View" /%}
Another big addition is **CI Pipeline Visualization** for Nx Cloud.
{% video-player src="/documentation/blog/media/nx-console-pipeline-running.mp4" alt="Nx Console CI Pipeline Execution" /%}
Nx Console notifies you inside your IDE when pipelines succeed or fail. This removes the need to monitor CI logs or constantly switch between tools.
{% video-player src="/documentation/blog/media/nxconsole-ci-completion.mp4" alt="Nx Console CI Completion" /%}
These updates make CI more accessible and help you stay focused without leaving your development environment.
If you havent tried it yet, grab Nx Console for [VSCode](https://marketplace.visualstudio.com/items?itemName=nrwl.angular-console) or [JetBrains IDEs](https://plugins.jetbrains.com/plugin/21060-nx-console).
### Affected Project Graph in Nx Cloud
Understanding how changes impact your workspace is key to optimizing and debugging CI pipelines. This year, we introduced the **Affected Project Graph** in Nx Cloud to make this easier.
![affected-project-graph-nxcloud.avif](/blog/images/articles/affected-project-graph-nxcloud.avif)
The Affected Project Graph builds on existing tools like [cache miss troubleshooting](/troubleshooting/troubleshoot-cache-misses#check-3-use-the-nx-cloud-troubleshooting-tools), helping you track down what triggered a cache reset. Now, you can visually map which projects are affected by changes, providing clearer insights into your pipeline.
This feature lets you:
- **Debug pipelines faster** by seeing why tasks were triggered
- **Spot bottlenecks** in dependency chains
- Use insights to optimize your workspace structure
For a deeper look at this feature, check out our blog post: [Understand the CI Affected Graph](/blog/ci-affected-graph). Combined with other Nx Cloud tools, the Affected Project Graph makes it easier to fine-tune CI performance and manage complex workspaces.
### Local Caching Moves to DB Storage
Speed is always a priority at Nx. This year, we transitioned **local caching** from a file-based system to a **database-backed approach**. This shift reduces I/O overhead, improving performance and laying the groundwork for smarter cache management.
With database-backed caching, we can introduce features like:
- Retaining only the most relevant cache entries based on usage
- Setting cache size limits
- Prioritizing failed tasks earlier in the queue
This change not only boosts performance but also opens up opportunities for more efficient task orchestration. The move to database storage is part of a broader effort to rewrite critical parts of Nx in **Rust**, pushing for better performance and scalability.
## Coming up in 2025
We have already a lot of exciting features that we want to ship next year. Here are some of them we're looking forward to.
### Local Agents
Nx Cloud already helps balance **speed and cost** by dynamically scaling agents based on PR size and workload. This ensures you only use the resources you need, keeping CI fast without unnecessary expense.
But theres still untapped potential. **Local Agents** will let you connect your developer machine to Nx Cloud, allowing it to handle tasks when its underutilized. This reduces the need for extra CI agents while making better use of the machines you already have, without disrupting your workflow.
We have a proof-of-concept in place, and we're working to turn this into a full feature.
### Polygraph
Many teams manage **multiple monorepos or polyrepos** instead of consolidating everything into a single large repository. This often happens for practical reasons or as part of a gradual transition.
**Polygraph** gives teams some of the benefits of a larger monorepo like consistency and visibility **without needing to merge everything at once**. Even if a monorepo is the end goal, the goal of Polygraph is to help teams make progress early, rather than waiting until everything is in one place.
This is especially useful for **platform teams** responsible for maintaining consistency, security, and best practices across many repositories. Polygraph provides better control by allowing you to:
- Run **conformance rules** across all repositories in your Nx Cloud organization
- Visualize **dependencies** between projects in different repositories using a multi-repo graph
Stay tuned as we keep working on this and releasing it in 2025.
### Rewriting Nx Core in Rust
Weve already rewritten performance-critical parts of Nx in **Rust**, and in 2025 we plan to extend this to more of the core. One of the main goals is to ensure that Nx adds as little overhead as possible to your monorepo, keeping things fast and efficient at scale.
This rewrite aligns with Nxs goal of being **tech agnostic**, supporting polyglot monorepos and workflows beyond JavaScript. By reducing reliance on Node.js for the core, Nx can fit into a wider range of environments, while plugins will continue to be written in **TypeScript** to keep development familiar and extensible.
By moving core parts to Rust, were focusing on performance where it matters most, while maintaining the flexibility that makes Nx useful across different tech stacks.
### Support for Long-Running Tasks
Nx is built around tasks that start and finish, but that doesnt always fit workflows involving **dev servers, watch-mode builds, or background services**. These tasks run indefinitely, which can be tricky to manage, especially when other processes depend on them, like e2e tests that require a server to stay up.
Were working on adding support for **long-running tasks** that can run alongside regular build and test processes. This will make workflows smoother and help avoid the need for manual orchestration. The upcoming **Nx terminal UI rewrite** will reflect this, making it easier to track and visualize long-running processes alongside other tasks (more about that later in the article).
If youre curious about the direction were heading, take a look at the ongoing [RFC](https://github.com/nrwl/nx/discussions/29025).
### Unified Monorepo Support
Nx already works well with both **integrated monorepos** driven by Nx plugins and **package-based monorepos** using npm, Yarn, or PNPM workspaces. Where things get trickier is mixing the two approaches since integrated plugins didnt always align smoothly with workspace-based setups.
With **Nx Crystal Plugins**, were making it easier to blend these approaches. You get the automation and guardrails of Nx plugins while retaining the flexibility of workspace-based monorepos. This lets you enhance a PNPM, npm, or Yarn workspace with Nxs powerful task orchestration, caching, and dependency management, without fully committing to an integrated setup.
A great example of this is our [Next.js + Nx + PNPM course](/courses/pnpm-nx-next), where we show how to enhance a PNPM workspace with Nx. But this is just the beginning. Our goal is to make the experience even better, reducing friction and making it seamless to mix and match both models.
Also note: existing workspaces wont be affected. Integrated monorepos will continue to work as they always have, but new projects will default to this more flexible model.
You can read more about this direction in the [RFC](https://github.com/nrwl/nx/discussions/29099).
### Nx Terminal Redesign
The terminal is one of the main ways developers interact with Nx, and were working on a complete redesign to make it nicer, clearer, and easier to use.
The goal is to reduce noise and surface the most important information for each task. Regardless whether you're running multiple dev servers, long-running tasks, or parallel builds.
This redesign also ties into our work on **long-running tasks**. Processes like dev servers or background services will be easier to manage directly from the terminal, letting you see their status alongside regular build and test processes.
We want the terminal to feel more intuitive and stay out of your way while giving you the details you need when you need them.
### Improved Node.js Experience
The goal is to bring the same level of polish to Node development that Nx already provides for frontend frameworks. This includes **better tools for managing microservices**, **streamlining Docker** builds, and improving backend workflows in monorepos.
We want Nx to feel just as natural for scaling Node applications as it does for frontend projects.
### Expanding Polyglot Support
Nx has grown beyond JavaScript, with support for tools across different ecosystems. In 2024, we introduced **Gradle support** to simplify Java app management in monorepos.
Next, were expanding to **Maven** and **.NET**, continuing to break down barriers for teams managing projects in multiple languages. The goal is to make Nx a natural fit for polyglot monorepos, keeping workflows fast and consistent across tech stacks.
## Excited for 2025?
We are too. As we wrap up 2024, we want to thank you for being part of the Nx community. Your feedback and contributions continue to shape Nx and push it forward.
We hope you enjoy the holidays and, if you're celebrating, Merry Christmas! Looking forward to seeing what we build in 2025.
+236
View File
@@ -0,0 +1,236 @@
---
title: 'Nx Update: 20.3!'
slug: nx-update-20-3
authors: [Zack DeRose]
tags: [nx]
cover_image: /blog/images/2025-01-06/nx-20-3.png
---
It's been a few months now since our last major update with [Nx 20](), let's check in with the latest updates since 20 came out, as we've now dropped 3 minor releases since them. Here's a rundown of everything new:
- [Typescript Project References And Workspaces Support](#typescript-project-references-and-workspaces-support)
- [Rspack updates](#rspack-updates)
- [New Nx Console Feature: CI Pipeline Status in Your IDE!](#new-nx-console-feature-ci-pipeline-status-in-your-ide)
- [Nx Cloud Enhancements](#nx-cloud-enhancements)
- [Angular 19 Support](#angular-19-support)
- [Core Performance Improvements](#core-performance-improvements)
- [Powerpack Updates](#powerpack-updates)
- [RFC for Infinite Tasks](#rfc-for-infinite-tasks)
You can also catch most of these updates direct from the team from our livestream:
{% youtube
src="https://www.youtube.com/embed/GRiXj4tmqKA"
title="Nx Live: Nx 20.3" /%}
## Typescript Project References And Workspaces Support
Our new support for Typescript project references has been launched!
Prior this enhancement, by default, Nx workspaces were treated as a single unit from the perspective of your package manager, and at the Typescript level, we used path aliases (using the `path` compiler option in your `tsconfig.base.json` file) in order for your different projects to know where to import from in import statements like:
```typescript
import { foo } from '@my-workspace/my-project;
```
With the new enhancement, when you run our generators, we'll instead manage creating each project as a new project from the perspective of your package manager (whether that's `npm`, `yarn`, `pnpm`, or `bun`), and setting up Typescript to know about this project as a ["project reference"](https://www.typescriptlang.org/docs/handbook/project-references.html) using the `references` compiler option in a `tsconfig.json` file at the root of your workspace.
You can see this now by creating a new nx workspace with:
```shell
npx create-nx-workspace@latest my-workspace --preset=ts
```
After creation, you'll notice that there's now a `workspaces` field set up in your root `package.json`:
```json
{
"name": "@my-workspace/source",
"version": "0.0.0",
"scripts": {},
"dependencies": {},
"devDependencies": {},
"workspaces": ["libs/**", "packages/**"]
}
```
This is how you inform your package manager as to where to find packages in your workspace. Note that because we used `npx` to create this workspace, Nx set up the workspace for Npm's workspaces feature.
If we had set up this workspace to use Pnpm as our package manager (which you can do either by using pnpx:
```shell
pnpx create-nx-workspace@latest
```
or providing a `pm` option:
```shell
npx create-nx-workspace@latest --pm=pnpm
```
Then a `pnpm-workspace.yaml` file would have been created to support pnpm's workspaces feature. Similar support and considerations are given for [Yarn workspaces](https://yarnpkg.com/features/workspaces).
You should now also see in your `tsconfig.json` file:
```json
{
"extends": "./tsconfig.base.json",
"compileOnSave": false,
"files": [],
"references": []
}
```
A new `references` field here that is currently empty. If we use an nx generator to create a new lib:
```shell
nx g lib packages/my-package
```
We'll see that this gets updated now to:
```json
{
"extends": "./tsconfig.base.json",
"compileOnSave": false,
"files": [],
"references": [
{
"path": "./packages/my-package"
}
]
}
```
Nx will continue to update this file as you add packages.
Note that dependending on which package manager you use, you may need to run an install from your package manager (for example `npm install`) after adding a new package for your package manager to set things up correctly!
This new approach is currently what you'll get using the `ts` preset by default:
```shell
npx create-nx-workspaces@latest --preset=ts
```
You can opt-in to the experimental support now for our react, vue, and node presets using the `--workspaces` flag:
```shell
npx create-nx-workspace@latest --preset=react --workspaces
```
And we will continue to add this as the default to all our official presets soon. You can follow along with [the discussion on the RFC here](https://github.com/nrwl/nx/discussions/29099) for more!
## Rspack updates
Our [`@nx/rspack`](/nx-api/rspack) plugin has moved from labs into our main repo now, and we now have [a dedicated plugin](/nx-api/rsbuild) for [Rsbuild](https://rsbuild.dev/) (a vite-like build tool with streamlined config built on top of Rspack) as well.
With the latest improvements, our Rspack plugin is now at feature parity with our [`@nx/webpack`](/nx-api/webpack) plugin, which should make it easier for teams to migrate from Webpack to Rspack now and take advantage of the significant performance gains.
Our new [Rsbuild plugin](/nx-api/rsbuild) will bring support for React and Vue applications, and we have measured a massive performance increase here over webpack. Running the command:
```shell
nx g @nx/rsbuild:configuration
```
Will create the necessary configuration for an existing targetted React or Vue application to work with Rsbuild.
When using the `@nx/react` and `@nx/vue` application generators, we'll also now include `rsbuild` as an option for the bundler to use when setting up the application.
For more on our Rspack support, be sure to check out previous livestreams with Colum, including this one for setting up Module Federation with Rspack:
{% youtube
src="https://www.youtube.com/embed/_c4zjYm0pYE"
title="Nx Live: Module Federation w/ Rspack" /%}
And Colum's package for setting up Angular with Rspack:
{% youtube
src="https://www.youtube.com/embed/raDY8RzdFI0"
title="Nx Live: Rspack for Angular Projects" /%}
## New Nx Console Feature: CI Pipeline Status in Your IDE!
We launched a [new feature](/blog/nx-cloud-pipelines-come-to-nx-console) for [Nx Console](/getting-started/editor-setup#download), our IDE plugin that works for Visual Studio Code and JetBrains IDEs (like IntelliJ and WebStorm)!
This feature allows you to have access to the status of your pending pipelines - including the ability to get notifications when one of your Nx Cloud pipelines completes - right from your IDE!
{% video-player src="/documentation/blog/media/nxconsole-ci-completion.mp4" alt="Nx Console CI Completion" /%}
You have access to this feature today if you're using the VsCode version of the plugin, and we plan to bring this to the JetBrains version soon.
## Nx Cloud Enhancements
Available now on Nx Cloud - you can see the affected project graph for each individual PR, using the new composite graph view! Check out this video for more details:
{% youtube
src="https://www.youtube.com/embed/TS-Fp2iSlVM"
title="At-A-Glance Affected Repo Architecture On Every Pull Request! Now on Nx Cloud." /%}
We also now have support for [Assignment Rules](/ci/reference/assignment-rules). Assignment Rules allow you to specify specific machines for various tasks when running your Nx Cloud pipelines with a fleet of different machines. For example, if you have a very computationally intensive `build` task, you can specify that this task should be picked up only by your largest sized machine.
## Angular 19 Support
Angular 19 is here, and Nx now supports migrating your Angular 18 projects to Angular 19 via [`nx migrate`](/features/automate-updating-dependencies).
```shell
nx migrate latest --interactive
```
By using the `--interactive` flag (like above) you can opt into migrating specific dependencies (for example if you want to upgrade to the latest version of Nx, but not Angular just yet).
Keep in mind as well that as Angular 16 has now [fallen out of Long-Term Support (LTS)](https://angular.dev/reference/releases#actively-supported-versions), Nx will no longer support Angular 16 going forward.
## Core Performance Improvements
Over the past many months, we've addressed most of the glaring issues regarding the new ['inferred tasks plugins'](/concepts/inferred-tasks) that were first introduced in Nx v18. Now, in the last recent months, we've started to address some of the more fine-grained issues that we has seen in supporting this new functionality - including performance.
One place we've improved performance is in the loading of a local custom plugin, written in Typescript. Prior to this enhancement, loading of these plugins was fairly costly in terms of time and memory, and we've now reduced both of those costs dramatically. If you had been using a custom inferred task plugin, you should see a noticeable performance improvement now.
We've also introduced spinners into the terminal ui for instances where a task is delayed due to Nx calculating your workspace's graph. This will give some visual feedback to the user whenever Nx is still calculating your graph - whereas prior to this, it might seem as if nothing is happening.
![](/blog/images/2025-01-06/project-graph-spinner.gif)
## Powerpack Updates
[Nx Powerpack](/nx-enterprise/powerpack) is a suite of paid extensions for the Nx CLI, that enables some features like [allowing for third-party storage services to be used for your remoted and shared caching](/nx-enterprise/powerpack/custom-caching), [specifying specific developers as owners of specific projects in your repo](/nx-enterprise/powerpack/owners), and [running language-agnostic conformance rules](/nx-enterprise/powerpack/conformance):
{% cards cols="2" lgCols="3" mdCols="3" smCols="2" %}
{% link-card title="Conformance" type="Powerpack Feature" url="/nx-enterprise/powerpack/conformance" icon="CheckBadgeIcon" /%}
{% link-card title="Owners" type="Powerpack Feature" url="/nx-enterprise/powerpack/owners" icon="UserGroupIcon" /%}
{% link-card title="Self-Hosted Remote Cache" type="Powerpack Feature" url="/nx-enterprise/powerpack/custom-caching" icon="ServerIcon" /%}
{% /cards %}
Recently, we've added support for [Azure](/nx-api/powerpack-azure-cache) and [Google Cloud Storage](/nx-api/powerpack-gcs-cache) as supported storage providers (in addition to [S3](/nx-api/powerpack-s3-cache) or [simply using a shared file system](/nx-api/powerpack-shared-fs-cache)).
We've also [added support for S3 compatible providers](/nx-api/powerpack-s3-cache#s3-compatible-providers) such as:
- [MinIO](https://min.io/product/s3-compatibility)
- [LocalStack](https://www.localstack.cloud)
- [DigitalOcean Spaces](https://www.digitalocean.com/products/spaces)
- [Cloudflare](https://www.cloudflare.com/developer-platform/solutions/s3-compatible-object-storage)
We've also added the capability to allow folks to authenticate their Powerpack license via Nx Cloud (rather than requiring that the license be committed to the repository). This should enable oss library authors use Powerpack - without exposing their private license via their repo.
We are offering free Nx Powerpack licenses to all open source libraries. We also offer free licenses to smaller businesses. If you are interested, you may [request a license now using Nx Cloud](https://cloud.nx.app/powerpack/purchase).
## RFC for Infinite Tasks
Last up, we have an [RFC for the concept of "Infinite Tasks"](https://github.com/nrwl/nx/discussions/29025) on GitHub now. This is a new feature that we'll be adding soon to support non-discrete tasks in terms of the task dependencies. It should come in handy for use-cases like:
- starting a local backend application whenever you start a frontend web server that depends on that backend running (while developing)
- starting a local database whenever you start a backend application that depends on that database istance (while developing)
- making sure you publish to a local registry (like verdaccio) when you are testing a package before publishing to npm
We're very excited to implement this soon and greatly appreciate feedback as we know this is something that many of our users have been asking about!
## Learn more
- [Nx Docs](/getting-started/intro)
- [X/Twitter](https://twitter.com/nxdevtools)
- [LinkedIn](https://www.linkedin.com/company/nrwl/)
- [Nx GitHub](https://github.com/nrwl/nx)
- [Nx Official Discord Server](https://go.nx.dev/community)
- [Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Speed up your CI](/nx-cloud)
@@ -0,0 +1,201 @@
---
title: 'Who Gave JavaScript a Build Step?!?'
slug: who-gave-js-a-build-step
authors: [Zack DeRose]
tags: []
cover_image: /blog/images/2025-01-09/thumbnail.png
---
JavaScript is awesome for many reasons. Not the least of these is as an interpreted language, we can actually send our JavaScript as-is over HTTP just as plain text right to a browser.
So how did we take something so simple and straightforward and mess it up to the point where we actually gave our JavaScript code a build step? Why are we web-packing? What is a Vite? And why do we hate ourselves?
I sat down with Zack Jackson - maintainer of the [Webpack](https://webpack.js.org/) and [Rspack](https://rspack.dev/) bundlers, and creator of Module Federation to get the answers to these burning questions. Part 1 is here where we talk a good bit about the history of bundlers (I'll throw part 2 a little further down):
{% youtube
src="https://www.youtube.com/watch?v=ma_c6UNHddI"
title="Zack Jackson: Everything You Ever Wanted To Know About Web Bundlers (and Rspack!)"
width="100%"
/%}
![The History of Bundlers](/blog/images/2025-01-09/bundler-gen-chart.png)
## Why A Build Step
Now that you're here and past the first few paragraphs, we can drop the clickbait facade.
We all _kinda_ know why we have a build step for our JavaScript. An entire over-simplification, but this is essentially what we're going for:
!["The build step"](/blog/images/2025-01-09/the-build-step.png)
We have an "Input format" that represents a format that we want to work with while developing. This should be human-readable, logically organized, and generally conducive to the process of development.
Then we have an "Output format" that represents what we'd like to ship, and the priorities here are very much efficiency-focused. We want to ship code that is functionally equivalent to the code from our "Input format", but we want to ship it in a way that has as few network requests as possible, with files that are as small as possible, and ideally we are always only sending code that is needed for the application to function properly for the current page or state - no more (or else we wasted sending code to the user's browser that is just not getting used) and no less (or else the application won't function properly).
The representation of this "build step" as a "black box" in the image above is very much on purpose. In most cases, I think an appropriately pragmatically-minded engineer (read this as a "good engineer") should probably not over-obsess with what this build process looks like. Preferably, you'd use the many available tools to leverage the work done by other engineers and the wider ecosystem to leverage work done by engineers focused on this problem.
## Inhale and Exhale: The Core Dimension
The "core dimension" as I like to think of it, comes down to "bundling" and "code-splitting". We'll hit the other dimensions later, but for the most part, those dimensions of the problem are either splintering of this core dimension, or somewhat ancillary to this core dimension.
"Bundling" refers to bundling up all the javascript files or "modules" of your application (and yes, that includes the black hole on your hard drive that is your `node_modules`) and bundling it all up into 1 file.
We'll flesh that process just a bit more because that's all very hand-wavey.
The first step of bundling is creating a graph of those "modules" mentioned. This graph will represent how each module depends on the others. From there, we _could_ collapse that entire graph into the 1 massive monolithic file, by replacing `import` or `require` statements with the contents of the code being imported. The reality is we often don't immediately, the graph itself is a good enough representation of that one file that we don't have to actually create the file, but you could think of it the same, because functionally, they're pretty much equivalent.
I like to think of bundling as an "inhale", where we gather up all your code into the module graph (or the 1 file).
From here we move into the "exhale", or the "code-splitting." The motivation here is without such a step, we could send over all our javascript in one shot with a single `script` tag:
```html {% filename="index.html" %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Webapp</title>
</head>
<body>
<div id="app">
<!-- Content will be injected by the JavaScript application -->
</div>
<!-- Reference to the bundled JavaScript -->
<script src="main.js"></script>
</body>
</html>
```
This is good: after the html comes in, we only need to make 1 request for all the javascript we need.
But this is also very very bad: if that 1 shot of javascript is massive, we end up waiting a long time for it all to arrive before our users can interact with the site.
When we utilize "code-splitting", we're "chunking" that 1 massive javascript file into smaller pieces, so that our `main.js` file can be small - just enough to "bootstrap" the application so the user can interact with it as soon as possible. When we use this approach, our `index.html` actually remains the same, but the `main.js` file will include code to dynamically load other chunks of javascript as we need them.
Our bundler is capable of automating some of this code-splitting for us, but by using [dynamic `import()` statements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import), we can signal to most bundlers to create dynamic chunks around those imports. This can be particularly effective when using a router on your application - to ensure that the code for each route is dynamically loaded when the route is activated.
Lets break down code-splitting with an actual example. Imagine youre building a single-page application (SPA) with React and `react-router` that dynamically loads components for each route:
```tsx {% filename="app.tsx" %}
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router';
const Bar = React.lazy(() => import('./bar'));
const Foo = React.lazy(() => import('./foo'));
function App() {
return (
<Router>
<nav>
<Link to="/">Foo</Link>
<Link to="/bar">Bar</Link>
</nav>
<Routes>
<Route path="/" element={<Foo />} />
<Route path="/bar" element={<Bar />} />
</Routes>
</Router>
);
}
export default App;
```
When building this (we'll use vite for this example), the bundler creates separate files for each chunk:
```shell
> vite build
vite v5.4.11 building for production...
✓ 42 modules transformed.
../../dist/apps/my-webapp/index.html 0.48 kB │ gzip: 0.30 kB
../../dist/apps/my-webapp/assets/foo-DjRQIFuQ.js 0.16 kB │ gzip: 0.15 kB
../../dist/apps/my-webapp/assets/bar-oew334y7.js 0.22 kB │ gzip: 0.19 kB
../../dist/apps/my-webapp/assets/index-3-BhaWR_.js 177.96 kB │ gzip: 58.71 kB
✓ built in 589ms
```
This way, our bundler creates a separate "chunk" per route, and the chunk can be dynamically loaded when it is needed.
This code-splitting then operates as the "exhale". Essentially, we move from a series of files we are working with as we develop, "inhale" them into "the graph", then "exhale", splitting them into their respective chunks - a different set of files optimized for your built artifact.
## The Other Dimensions
I view the rest of these as somewhat secondary to the core dimension above, but they're still worth mentioning!
### Non-JS Assets
Similar bundling is required for non-js assets, the most significant for front-end projects is usually css (where similar bundling/splitting strategies come into play), but other assets like images and fonts also need to end up in the final artifact, and things need to work in terms of where these assets are located in the subdirectories and where your javascript and html reference these!
Bundlers handle these as well.
### Transpilation / Polyfilling
Transpilation mainly refers to the process of transforming your Typescript files from Typescript (which a browser can't understand) to JavaScript (which a browser can understand!).
Typescript serves as a way of placing typing assertions on our code to make sure we don't have errors in our code that violate our typing instructions. We can think of type-checking our code as a "lint step" - something that we should run before committing code into our codebase via [Continuous Integration](/ci), but this type-check step we can safely view as separate from our "build step." From the perspective of our "build step" we're usually looking at simply stripping out the types from your code to create valid JavaScript.
Transpilation can also refer to adjusting the code we write in to code that browsers support. In prior days, tools like [Babel](https://babeljs.io/) were required to "transpile" down from ES6 javascript to ES5. Tools like Babel are still widely used, to support [esnext](https://developer.mozilla.org/en-US/docs/Web/JavaScript/JavaScript_technologies_overview#standardization_process) features that browsers don't support yet. This is also referred to as polyfilling sometimes - as in polyfilling a JS feature that is not supported yet by browsers, or sometimes for features that can be optionally loaded by specific browsers that are missing various features.
### "Last Mile" Optimizations
There's a series of other optimizations that bundlers perform as part of the build step, the main ones that come to mind here are:
- **Minification** - reduces file size by reducing whitespace to minimum, removing any superfluous text, and shortening all variable names
- **Tree Shaking** - Analyzes the Abstract Syntax Tree (AST) of your bundled graph for unreferenced branches of the overall tree. Those unreferenced branches are then "shaken off" so this code does not end up in your end artifact.
- **Cache Busting** - Appends hashes to filenames (e.g., `main-[hash].js`) to ensure browsers load updated files after a deployment.
Some may consider code splitting a "last mile" optimization as well, and some other items like creating source maps for a development build or asset optimization could be seen as a last-mile optimization as well.
### Module Formats
EcmaScript Modules (or ESM or `"type": "module"` or `.mjs`) vs. CommonJS modules (or `require` or `"type": "common"` or `.cjs`) is another terrible dimension of this whole discussion.
Quoting from [an article I read on this topic that rang especially true](https://redfin.engineering/node-modules-at-war-why-commonjs-and-es-modules-cant-get-along-9617135eeca1):
> Superficially, ESM looks very similar to CJS, but their implementations couldnt be more different. One of them is a honey bee, and the other is a murder hornet. But I can never remember which one is which.
The ESM module format uses `import` statements to bring in other modules, and `export` statements to mark public/consumable pieces of a module.
CommonJS module format uses `require` statements to bring in other modules, and `module.exports = ...` statements to mark public/consumable pieces of a module.
But it's unfortunately a bit more complicated than that, but that's beyond the scope of this article. There's other formats too, like AMD (Asynchronous module definition, popular in legacy browser projects) and UMD (a universal format that works in both Node.js and the browser)
Bundlers are great, cuz they pave over much of this headache - allowing you to write your code in either module format or even in a bit of both, and exporting to what makes most sense. Typically you'd target esm, as that's the current consensus for front-end applications.
### Building for Other Purposes
Another interesting dimension is building for other purposes than simply front-end apps.
One interesting alternative here is building a package to publish to npm or a private registry. There's a parallel set of concerns here, you still have a desired input format that probably looks very similar! But you have entirely different priorities for your output format! Size is largely unimportant, as `node_modules` are already an endless black hole of bytes, there's no sense fretting over adding a few more megs on that heap.
That's mainly a joke - but the idea is your end consumer would figure out minification and etcetera when running their own build step.
You also don't really need to "bundle" in your dependencies, as you can simply reference other dependencies in your exported `package.json` for your consumer to bring in. You do typically need to worry about types - typically building to `.js` files, but providing `d.ts` files to inform the typing of your package.
Another alternative is building for backend node applications. Different priorities here too as bundle size isn't all that important - but some interesting folds can come in around Module Federation on the backend.
## Wrapping it up
Here's the part 2 of my discussion with Zack Jackson - where we go a bit deeper, laying out the rough map of bundler lifecycle hooks and diving into webpack source code a bit to see it in action:
{% youtube
src="https://www.youtube.com/watch?v=RE1AzJIcbdk"
title="Everything You Need To Know About Bundlers! Part 2 w/ Zack Jackson (RsPack creator)"
width="100%" /%}
![The General Bundler Path](/blog/images/2025-01-09/bundler-flow-chart.png)
Jump into [our discord](https://go.nx.dev/community) if you have more questions, but I think the gist of it is summarized by this image:
!["The build step"](/blog/images/2025-01-09/the-build-step.png)
We have an input format we want to work with - and an output format that we want to export our artifact in. Generally, your build step should be a black-box of getting you from that input format to your output format. This article hopefully helped you flesh out that black box just a bit - at least enough to point you in the right direction if you want to dig deeper!
## Learn More
- 🧠 [Nx Docs](/getting-started/intro)
- 👩‍💻 [Nx GitHub](https://github.com/nrwl/nx)
- 💬 [Nx Official Discord Server](https://go.nx.dev/community)
- 📹 [Nx Youtube Channel](https://www.youtube.com/nrwl_io)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
+23 -12
View File
@@ -35,6 +35,17 @@
"path": "powerpack-conformance/documents/overview",
"tags": [],
"originalFilePath": "shared/packages/powerpack-conformance/powerpack-conformance-plugin"
},
{
"id": "create-conformance-rule",
"name": "Create a Conformance Rule",
"description": "A Nx Powerpack plugin which allows users to write and apply rules for your entire workspace that help with consistency, maintainability, reliability and security.",
"file": "external-generated/packages/powerpack-conformance/documents/create-conformance-rule",
"itemList": [],
"isExternal": false,
"path": "powerpack-conformance/documents/create-conformance-rule",
"tags": [],
"originalFilePath": "shared/packages/powerpack-conformance/create-conformance-rule"
}
],
"executors": [
@@ -48,7 +59,17 @@
"type": "executor"
}
],
"generators": [],
"generators": [
{
"description": "Create a new conformance rule",
"file": "external-generated/packages/powerpack-conformance/generators/create-rule.json",
"hidden": false,
"name": "create-rule",
"originalFilePath": "/libs/nx-packages/powerpack-conformance/src/generators/create-rule/schema.json",
"path": "powerpack-conformance/generators/create-rule",
"type": "generator"
}
],
"githubRoot": "https://github.com/nrwl/nx/blob/master",
"name": "powerpack-conformance",
"packageName": "@nx/powerpack-conformance",
@@ -168,17 +189,7 @@
}
],
"executors": [],
"generators": [
{
"description": "Initialize the S3 Cache",
"file": "external-generated/packages/powerpack-s3-cache/generators/init.json",
"hidden": false,
"name": "init",
"originalFilePath": "/libs/nx-packages/powerpack-s3-cache/src/generators/init/schema.json",
"path": "powerpack-s3-cache/generators/init",
"type": "generator"
}
],
"generators": [],
"githubRoot": "https://github.com/nrwl/nx/blob/master",
"name": "powerpack-s3-cache",
"packageName": "@nx/powerpack-s3-cache",
@@ -81,3 +81,29 @@ Finally, you need to configure your Nx cache in the `nx.json` file. The `contain
| --------------- | -------------------------------- |
| **container** | The name of the container to use |
| **accountName** | The name of blob storage account |
# Cache Modes
By default, Nx will try to write and read from the remote cache while running locally. This means that permissions must be set for users who are expected to access the remote cache.
Nx will only show warnings when the remote cache is not writable. You can disable these warnings by setting `localMode` to `read-only` or `no-cache` in the `nx.json` file.
```jsonc {% fileName="nx.json" %}
{
"azure": {
// ...
"localMode": "read-only"
}
}
```
The cache mode in CI can also be configured by setting `ciMode` to `read-only` or `no-cache` in the `nx.json` file. Or setting `NX_POWERPACK_CACHE_MODE` to `read-only` or `no-cache` in the CI environment.
```jsonc {% fileName="nx.json" %}
{
"azure": {
// ...
"ciMode": "read-only"
}
}
```
@@ -0,0 +1,308 @@
# Create a Conformance Rule
For local conformance rules, the resolution utilities from `@nx/js` are used in the same way they are for all other JavaScript/TypeScript files in Nx. Therefore, you can simply reference an adhoc JavaScript file or TypeScript file in your `"rule"` property (as long as the path is resolvable based on your package manager and/or tsconfig setup), and the rule will be loaded/transpiled as needed. The rule implementation file should also have a `schema.json` file next to it that defines the available rule options, if any.
Therefore, in practice, writing your local conformance rules in an Nx generated library is the easiest way to organize them and ensure that they are easily resolvable via TypeScript. The library in question could also be an Nx plugin, but it does not have to be.
To write your own conformance rule, run the `@nx/powerpack-conformance:create-rule` generator and answer the prompts.
```text {% command="nx g @nx/powerpack-conformance:create-rule" %}
NX Generating @nx/powerpack-conformance:create-rule
✔ What is the name of the rule? · local-conformance-rule-example
✔ Which directory do you want to create the rule directory in? · packages/my-plugin/local-conformance-rule
✔ What category does this rule belong to? · security
✔ What reporter do you want to use for this rule? · project-reporter
✔ What is the description of the rule? · an example of a conformance rule
CREATE packages/my-plugin/local-conformance-rule/local-conformance-rule-example/index.ts
CREATE packages/my-plugin/local-conformance-rule/local-conformance-rule-example/schema.json
```
The generated rule definition file should look like this:
```ts {% fileName="packages/my-plugin/local-conformance-rule/index.ts" %}
import {
createConformanceRule,
ProjectViolation,
} from '@nx/powerpack-conformance';
export default createConformanceRule({
name: 'local-conformance-rule-example',
category: 'security',
description: 'an example of a conformance rule',
reporter: 'project-reporter',
implementation: async (context) => {
const violations: ProjectViolation[] = [];
return {
severity: 'low',
details: {
violations,
},
};
},
});
```
To enable the rule, you need to register it in the `nx.json` file.
```json {% fileName="nx.json" %}
{
"conformance": {
"rules": [
{
"rule": "./packages/my-plugin/local-conformance-rule/index.ts"
}
]
}
}
```
Note that the severity of the error is defined by the rule author and can be adjusted based on the specific violations that are found.
## Conformance Rule Examples
There are three types of reporters that a rule can use.
- `project-reporter` - The rule evaluates an entire project at a time.
- `project-files-reporter` - The rule evaluates a single project file at a time.
- `non-project-files-reporter` - The rule evaluates files that don't belong to any project.
{% tabs %}
{% tab label="project-reporter" %}
The `@nx/powerpack-conformance:ensure-owners` rule provides us an example of how to write a `project-reporter` rule. The `@nx/powerpack-owners` plugin adds an `owners` metadata property to every project node that has an owner in the project graph. This rule checks each project node metadata to make sure that each project has some owner defined.
```ts
import { ProjectGraphProjectNode } from '@nx/devkit';
import {
createConformanceRule,
ProjectViolation,
} from '@nx/powerpack-conformance';
export default createConformanceRule({
name: 'ensure-owners',
category: 'consistency',
description: 'Ensure that all projects have owners defined via Nx Owners.',
reporter: 'project-reporter',
implementation: async (context) => {
const violations: ProjectViolation[] = [];
for (const node of Object.values(
context.projectGraph.nodes
) as ProjectGraphProjectNode[]) {
const metadata = node.data.metadata;
if (!metadata?.owners || Object.keys(metadata.owners).length === 0) {
violations.push({
sourceProject: node.name,
message: `This project currently has no owners defined via Nx Owners.`,
});
}
}
return {
severity: 'medium',
details: {
violations,
},
};
},
});
```
{% /tab %}
{% tab label="project-files-reporter" %}
This rule uses TypeScript AST processing to ensure that `index.ts` files use a client-side style of export syntax and `server.ts` files use a server-side style of export syntax.
```ts
import {
createConformanceRule,
ProjectFilesViolation,
} from '@nx/powerpack-conformance';
import { existsSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
import {
createSourceFile,
isExportDeclaration,
isStringLiteral,
isToken,
ScriptKind,
ScriptTarget,
} from 'typescript';
export default createConformanceRule({
name: 'server-client-public-api',
category: 'consistency',
description: 'Ensure server-only and client-only public APIs are not mixed',
reporter: 'project-files-reporter',
implementation: async ({ projectGraph }) => {
const violations: ProjectFilesViolation[] = [];
for (const nodeId in projectGraph.nodes) {
const node = projectGraph.nodes[nodeId];
const sourceRoot = node.data.root;
const indexPath = join(sourceRoot, 'src/index.ts');
const serverPath = join(sourceRoot, 'src/server.ts');
if (existsSync(indexPath)) {
const fileContent = readFileSync(indexPath, 'utf8');
violations.push(
...processEntryPoint(fileContent, indexPath, nodeId, 'client')
);
}
if (existsSync(serverPath)) {
const fileContent = readFileSync(serverPath, 'utf8');
violations.push(
...processEntryPoint(fileContent, serverPath, nodeId, 'server')
);
}
}
return {
severity: 'medium',
details: { violations },
};
},
});
export function processEntryPoint(
fileContent: string,
entryPoint: string,
project: string,
style: 'server' | 'client'
) {
const violations: ProjectFilesViolation[] = [];
const sf = createSourceFile(
entryPoint,
fileContent,
ScriptTarget.Latest,
true,
ScriptKind.TS
);
let hasNotOnlyExports = false;
sf.forEachChild((node) => {
if (isExportDeclaration(node)) {
const moduleSpecifier =
node.moduleSpecifier && isStringLiteral(node.moduleSpecifier)
? node.moduleSpecifier.getText()
: '';
if (isModuleSpecifierViolated(moduleSpecifier, style)) {
if (
violations.find(
(v) => v.file === entryPoint && v.sourceProject === project
)
) {
// we already have a violation for this file and project, so we don't need to add another one
return;
}
violations.push({
message:
style === 'client'
? 'Client-side only entry point cannot export from server-side modules'
: 'Server-side only entry point can only export server-side modules ',
file: entryPoint,
sourceProject: project,
});
}
} else if (isToken(node) && node === sf.endOfFileToken) {
// do nothing
} else {
hasNotOnlyExports = true;
}
});
if (hasNotOnlyExports) {
violations.push({
message: `Entry point should only contain exported APIs`,
file: entryPoint,
sourceProject: project,
});
}
return violations;
}
function isModuleSpecifierViolated(
moduleSpecifier: string,
style: 'server' | 'client'
) {
// should not get here. if this is the case, it's a grammar error in the source code.
if (!moduleSpecifier) return false;
if (style === 'server' && !moduleSpecifier.includes('.server')) {
return true;
}
if (style === 'client' && moduleSpecifier.includes('.server')) {
return true;
}
return false;
}
```
{% /tab %}
{% tab label="non-project-files-reporter" %}
This rule checks the root `package.json` file and ensures that if the `tmp` package is included as a dependency, it has a minimum version of 0.2.3.
```ts
import { readJsonFile, workspaceRoot } from '@nx/devkit';
import {
createConformanceRule,
NonProjectFilesViolation,
} from '@nx/powerpack-conformance';
import { join } from 'node:path';
import { satisfies } from 'semver';
export default createConformanceRule<object>({
name: 'package-tmp-0.2.3',
category: 'maintainability',
description: 'The tmp dependency should be a minimum version of 0.2.3',
reporter: 'non-project-files-reporter',
implementation: async () => {
const violations: NonProjectFilesViolation[] = [];
const applyViolationIfApplicable = (version: string | undefined) => {
if (version && !satisfies(version, '>=0.2.3')) {
violations.push({
message: 'The "tmp" package must be version "0.2.3" or higher',
file: 'package.json',
});
}
};
const workspaceRootPackageJson = await readJsonFile(
join(workspaceRoot, 'package.json')
);
applyViolationIfApplicable(workspaceRootPackageJson.dependencies?.['tmp']);
applyViolationIfApplicable(
workspaceRootPackageJson.devDependencies?.['tmp']
);
return {
severity: 'low',
details: {
violations,
},
};
},
});
```
{% /tab %}
{% /tabs %}
## Share Conformance Rules Across Workspaces
If you have an Enterprise Nx Cloud contract, you can share your conformance rules across every repository in your organization. Read more in these articles:
- [Publish Conformance Rules to Nx Cloud](/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud)
- [Configure Conformance Rules in Nx Cloud](/ci/recipes/enterprise/conformance/configure-conformance-rules-in-nx-cloud)
@@ -166,51 +166,10 @@ Set the `rule` property to: `@nx/powerpack-conformance/ensure-owners`
}
```
## Custom Conformance Rules
## Next Steps
To write your own conformance rule, specify a relative path to a TypeScript or JavaScript file as the rule name:
For more information about the conformance plugin, consult the following articles:
```json {% fileName="nx.json" %}
{
"conformance": {
"rules": [
{
"rule": "./tools/local-conformance-rule.ts"
}
]
}
}
```
The rule definition file should look like this:
```ts {% fileName="tools/local-conformance-rule.ts" %}
import { createConformanceRule } from '@nx/powerpack-conformance';
const rule = createConformanceRule({
name: 'local-conformance-rule-example',
description: 'The description of the rule',
category: 'security', // `consistency`, `maintainability`, `reliability` or `security`
reporter: 'project-reporter', // `project-reporter` or `project-files-reporter`
implementation: async (context) => {
const { projectGraph, ruleOptions } = context;
// Your rule logic goes here
return {
severity: 'low', // 'high', 'medium' or 'low'
details: {
violations: [
// Return an empty array if the rule passes
{
sourceProject: 'my-project',
message: 'This is an informative error message.',
},
],
},
};
},
});
export default rule;
```
Note that the severity of the error is defined by the rule author and can be adjusted based on the specific violations that are found.
- [Create a Conformance Rule](/nx-api/powerpack-conformance/documents/create-conformance-rule)
- [Publish Conformance Rules to Nx Cloud](/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud)
- [Configure Conformance Rules in Nx Cloud](/ci/recipes/enterprise/conformance/configure-conformance-rules-in-nx-cloud)
@@ -0,0 +1,59 @@
{
"name": "create-rule",
"factory": "./src/generators/create-rule/create-rule",
"schema": {
"$schema": "http://json-schema.org/schema",
"id": "NxPowerpackConformanceCreateRule",
"title": "Create a new conformance rule",
"type": "object",
"cli": "nx",
"properties": {
"name": {
"type": "string",
"description": "The name of the rule.",
"$default": { "$source": "argv", "index": 0 },
"x-prompt": "What is the name of the rule?",
"x-priority": "important"
},
"directory": {
"type": "string",
"description": "A directory where the rule directory is created.",
"x-prompt": "Which directory do you want to create the rule directory in?",
"x-priority": "important"
},
"category": {
"type": "string",
"enum": ["consistency", "maintainability", "reliability", "security"],
"description": "The category of the rule.",
"x-prompt": "What category does this rule belong to?",
"x-priority": "important"
},
"reporter": {
"type": "string",
"enum": [
"project-reporter",
"project-files-reporter",
"non-project-files-reporter"
],
"description": "The reporter of the rule.",
"x-prompt": "What reporter do you want to use for this rule?",
"x-priority": "important"
},
"description": {
"type": "string",
"description": "The description of the rule.",
"x-prompt": "What is the description of the rule?",
"x-priority": "important"
}
},
"additionalProperties": false,
"required": ["name", "directory", "category", "reporter"],
"presets": []
},
"description": "Create a new conformance rule",
"implementation": "/libs/nx-packages/powerpack-conformance/src/generators/create-rule/create-rule.ts",
"aliases": [],
"hidden": false,
"path": "/libs/nx-packages/powerpack-conformance/src/generators/create-rule/schema.json",
"type": "generator"
}
@@ -80,3 +80,29 @@ Finally, you need to configure your Nx cache in the `nx.json` file. The `bucket`
| **Property** | **Description** |
| ------------ | ----------------------------- |
| **bucket** | The name of the bucket to use |
# Cache Modes
By default, Nx will try to write and read from the remote cache while running locally. This means that permissions must be set for users who are expected to access the remote cache.
Nx will only show warnings when the remote cache is not writable. You can disable these warnings by setting `localMode` to `read-only` or `no-cache` in the `nx.json` file.
```jsonc {% fileName="nx.json" %}
{
"gcs": {
// ...
"localMode": "read-only"
}
}
```
The cache mode in CI can also be configured by setting `ciMode` to `read-only` or `no-cache` in the `nx.json` file. Or setting `NX_POWERPACK_CACHE_MODE` to `read-only` or `no-cache` in the CI environment.
```jsonc {% fileName="nx.json" %}
{
"gcs": {
// ...
"ciMode": "read-only"
}
}
```
@@ -152,3 +152,31 @@ Below is an example on how to connect to MinIO:
| **endpoint** | The custom endpoint to upload artifacts to. If endpoint is not defined, the default AWS endpoint is used |
| **accessKeyId** | AWS Access Key ID (optional if `AWS_ACCESS_KEY_ID` is set in the environment) |
| **secretAccessKey** | AWS secret access key (optional if `AWS_SECRET_ACCESS_KEY` is set in the environment) |
# Cache Modes
By default, Nx will try to write and read from the remote cache while running locally. This means that permissions must be set for users who are expected to access the remote cache.
Nx will only show warnings when the remote cache is not writable. You can disable these warnings by setting `localMode` to `read-only` or `no-cache` in the `nx.json` file.
```jsonc {% fileName="nx.json" %}
{
"s3": {
"region": "us-east-1",
"bucket": "my-bucket",
"localMode": "read-only"
}
}
```
The cache mode in CI can also be configured by setting `ciMode` to `read-only` or `no-cache` in the `nx.json` file. Or setting `NX_POWERPACK_CACHE_MODE` to `read-only` or `no-cache` in the CI environment.
```jsonc {% fileName="nx.json" %}
{
"s3": {
"region": "us-east-1",
"bucket": "my-bucket",
"ciMode": "read-only"
}
}
```
+65 -25
View File
@@ -630,6 +630,14 @@
"children": [],
"disableCollapsible": false
},
{
"name": "TypeScript Project Linking",
"path": "/concepts/typescript-project-linking",
"id": "typescript-project-linking",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Nx and Turborepo",
"path": "/concepts/turbo-and-nx",
@@ -843,6 +851,14 @@
"children": [],
"disableCollapsible": false
},
{
"name": "TypeScript Project Linking",
"path": "/concepts/typescript-project-linking",
"id": "typescript-project-linking",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Nx and Turborepo",
"path": "/concepts/turbo-and-nx",
@@ -1954,6 +1970,14 @@
"children": [],
"disableCollapsible": false
},
{
"name": "Switch to Workspaces and TS Project References",
"path": "/recipes/tips-n-tricks/switch-to-workspaces-project-references",
"id": "switch-to-workspaces-project-references",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Enable Typescript Batch Mode",
"path": "/recipes/tips-n-tricks/enable-tsc-batch-mode",
@@ -3680,6 +3704,14 @@
"children": [],
"disableCollapsible": false
},
{
"name": "Switch to Workspaces and TS Project References",
"path": "/recipes/tips-n-tricks/switch-to-workspaces-project-references",
"id": "switch-to-workspaces-project-references",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Enable Typescript Batch Mode",
"path": "/recipes/tips-n-tricks/enable-tsc-batch-mode",
@@ -3811,6 +3843,14 @@
"children": [],
"disableCollapsible": false
},
{
"name": "Switch to Workspaces and TS Project References",
"path": "/recipes/tips-n-tricks/switch-to-workspaces-project-references",
"id": "switch-to-workspaces-project-references",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Enable Typescript Batch Mode",
"path": "/recipes/tips-n-tricks/enable-tsc-batch-mode",
@@ -8235,14 +8275,6 @@
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Configure TypeScript Project References in an Nx Workspace",
"path": "/nx-api/js/documents/typescript-project-references",
"id": "typescript-project-references",
"isExternal": false,
"children": [],
"disableCollapsible": false
}
],
"isExternal": false,
@@ -10797,6 +10829,14 @@
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Create a Conformance Rule",
"path": "/nx-api/powerpack-conformance/documents/create-conformance-rule",
"id": "create-conformance-rule",
"isExternal": false,
"children": [],
"disableCollapsible": false
}
],
"isExternal": false,
@@ -10818,6 +10858,23 @@
],
"isExternal": false,
"disableCollapsible": false
},
{
"id": "generators",
"path": "/nx-api/powerpack-conformance/generators",
"name": "generators",
"children": [
{
"id": "create-rule",
"path": "/nx-api/powerpack-conformance/generators/create-rule",
"name": "create-rule",
"children": [],
"isExternal": false,
"disableCollapsible": false
}
],
"isExternal": false,
"disableCollapsible": false
}
],
"isExternal": false,
@@ -10955,23 +11012,6 @@
],
"isExternal": false,
"disableCollapsible": false
},
{
"id": "generators",
"path": "/nx-api/powerpack-s3-cache/generators",
"name": "generators",
"children": [
{
"id": "init",
"path": "/nx-api/powerpack-s3-cache/generators/init",
"name": "init",
"children": [],
"isExternal": false,
"disableCollapsible": false
}
],
"isExternal": false,
"disableCollapsible": false
}
],
"isExternal": false,
+23 -23
View File
@@ -1168,17 +1168,6 @@
"path": "/nx-api/js/documents/overview",
"tags": [],
"originalFilePath": "shared/packages/js/js-plugin"
},
"/nx-api/js/documents/typescript-project-references": {
"id": "typescript-project-references",
"name": "Configure TypeScript Project References in an Nx Workspace",
"description": "The JS plugin for Nx contains executors and generators that provide the best experience for developing JavaScript and TypeScript projects. ",
"file": "generated/packages/js/documents/typescript-project-references",
"itemList": [],
"isExternal": false,
"path": "/nx-api/js/documents/typescript-project-references",
"tags": [],
"originalFilePath": "shared/packages/js/typescript-project-references"
}
},
"root": "/packages/js",
@@ -3707,6 +3696,17 @@
"path": "/nx-api/powerpack-conformance/documents/overview",
"tags": [],
"originalFilePath": "shared/packages/powerpack-conformance/powerpack-conformance-plugin"
},
"/nx-api/powerpack-conformance/documents/create-conformance-rule": {
"id": "create-conformance-rule",
"name": "Create a Conformance Rule",
"description": "A Nx Powerpack plugin which allows users to write and apply rules for your entire workspace that help with consistency, maintainability, reliability and security.",
"file": "external-generated/packages/powerpack-conformance/documents/create-conformance-rule",
"itemList": [],
"isExternal": false,
"path": "/nx-api/powerpack-conformance/documents/create-conformance-rule",
"tags": [],
"originalFilePath": "shared/packages/powerpack-conformance/create-conformance-rule"
}
},
"root": "/libs/nx-packages/powerpack-conformance",
@@ -3722,7 +3722,17 @@
"type": "executor"
}
},
"generators": {},
"generators": {
"/nx-api/powerpack-conformance/generators/create-rule": {
"description": "Create a new conformance rule",
"file": "external-generated/packages/powerpack-conformance/generators/create-rule.json",
"hidden": false,
"name": "create-rule",
"originalFilePath": "/libs/nx-packages/powerpack-conformance/src/generators/create-rule/schema.json",
"path": "/nx-api/powerpack-conformance/generators/create-rule",
"type": "generator"
}
},
"path": "/nx-api/powerpack-conformance"
},
"powerpack-enterprise-cloud": {
@@ -3847,17 +3857,7 @@
"root": "/libs/nx-packages/powerpack-s3-cache",
"source": "/libs/nx-packages/powerpack-s3-cache/src",
"executors": {},
"generators": {
"/nx-api/powerpack-s3-cache/generators/init": {
"description": "Initialize the S3 Cache",
"file": "external-generated/packages/powerpack-s3-cache/generators/init.json",
"hidden": false,
"name": "init",
"originalFilePath": "/libs/nx-packages/powerpack-s3-cache/src/generators/init/schema.json",
"path": "/nx-api/powerpack-s3-cache/generators/init",
"type": "generator"
}
},
"generators": {},
"path": "/nx-api/powerpack-s3-cache"
},
"powerpack-shared-fs-cache": {
+55
View File
@@ -864,6 +864,17 @@
"path": "/concepts/sync-generators",
"tags": ["sync"]
},
{
"id": "typescript-project-linking",
"name": "TypeScript Project Linking",
"description": "",
"mediaImage": "",
"file": "shared/concepts/typescript-project-linking",
"itemList": [],
"isExternal": false,
"path": "/concepts/typescript-project-linking",
"tags": ["project-linking"]
},
{
"id": "turbo-and-nx",
"name": "Nx and Turborepo",
@@ -1157,6 +1168,17 @@
"path": "/concepts/sync-generators",
"tags": ["sync"]
},
"/concepts/typescript-project-linking": {
"id": "typescript-project-linking",
"name": "TypeScript Project Linking",
"description": "",
"mediaImage": "",
"file": "shared/concepts/typescript-project-linking",
"itemList": [],
"isExternal": false,
"path": "/concepts/typescript-project-linking",
"tags": ["project-linking"]
},
"/concepts/turbo-and-nx": {
"id": "turbo-and-nx",
"name": "Nx and Turborepo",
@@ -2675,6 +2697,17 @@
"path": "/recipes/tips-n-tricks/eslint",
"tags": []
},
{
"id": "switch-to-workspaces-project-references",
"name": "Switch to Workspaces and TS Project References",
"description": "",
"mediaImage": "",
"file": "shared/recipes/tips-n-tricks/switch-to-workspaces-project-references",
"itemList": [],
"isExternal": false,
"path": "/recipes/tips-n-tricks/switch-to-workspaces-project-references",
"tags": ["project-linking"]
},
{
"id": "enable-tsc-batch-mode",
"name": "Enable Typescript Batch Mode",
@@ -5042,6 +5075,17 @@
"path": "/recipes/tips-n-tricks/eslint",
"tags": []
},
{
"id": "switch-to-workspaces-project-references",
"name": "Switch to Workspaces and TS Project References",
"description": "",
"mediaImage": "",
"file": "shared/recipes/tips-n-tricks/switch-to-workspaces-project-references",
"itemList": [],
"isExternal": false,
"path": "/recipes/tips-n-tricks/switch-to-workspaces-project-references",
"tags": ["project-linking"]
},
{
"id": "enable-tsc-batch-mode",
"name": "Enable Typescript Batch Mode",
@@ -5223,6 +5267,17 @@
"path": "/recipes/tips-n-tricks/eslint",
"tags": []
},
"/recipes/tips-n-tricks/switch-to-workspaces-project-references": {
"id": "switch-to-workspaces-project-references",
"name": "Switch to Workspaces and TS Project References",
"description": "",
"mediaImage": "",
"file": "shared/recipes/tips-n-tricks/switch-to-workspaces-project-references",
"itemList": [],
"isExternal": false,
"path": "/recipes/tips-n-tricks/switch-to-workspaces-project-references",
"tags": ["project-linking"]
},
"/recipes/tips-n-tricks/enable-tsc-batch-mode": {
"id": "enable-tsc-batch-mode",
"name": "Enable Typescript Batch Mode",
+16
View File
@@ -769,6 +769,22 @@
"path": "/nx-api/nx/documents/sync-check"
}
],
"project-linking": [
{
"description": "",
"file": "shared/concepts/typescript-project-linking",
"id": "typescript-project-linking",
"name": "TypeScript Project Linking",
"path": "/concepts/typescript-project-linking"
},
{
"description": "",
"file": "shared/recipes/tips-n-tricks/switch-to-workspaces-project-references",
"id": "switch-to-workspaces-project-references",
"name": "Switch to Workspaces and TS Project References",
"path": "/recipes/tips-n-tricks/switch-to-workspaces-project-references"
}
],
"module-federation": [
{
"description": "",
-11
View File
@@ -1152,17 +1152,6 @@
"path": "js/documents/overview",
"tags": [],
"originalFilePath": "shared/packages/js/js-plugin"
},
{
"id": "typescript-project-references",
"name": "Configure TypeScript Project References in an Nx Workspace",
"description": "The JS plugin for Nx contains executors and generators that provide the best experience for developing JavaScript and TypeScript projects. ",
"file": "generated/packages/js/documents/typescript-project-references",
"itemList": [],
"isExternal": false,
"path": "js/documents/typescript-project-references",
"tags": [],
"originalFilePath": "shared/packages/js/typescript-project-references"
}
],
"executors": [
@@ -1,4 +1,4 @@
/nameExpo is an open-source framework for apps that run natively on Android, iOS, and the web. Expo brings together the best of mobile and the web and enables many important features for building and scaling an app.
Expo is an open-source framework for apps that run natively on Android, iOS, and the web. Expo brings together the best of mobile and the web and enables many important features for building and scaling an app.
Expo is a set of tools built on top of React Native. The Nx Plugin for Expo contains generators for managing Expo applications and libraries within an Nx workspace.
@@ -91,6 +91,27 @@ target with that name which can be used in CI to run the tests for each file in
}
```
### Customizing atomized unit/e2e tasks group name
By default, the atomized tasks group name is derived from the `ciTargetName`. For example, atomized tasks for the `e2e-ci` target will be grouped under the name "E2E (CI)" when displayed in Nx Cloud or `nx show project <project> --web` UI.
You can customize that name by explicitly providing the optional `ciGroupName` plugin option as such:
```json {% fileName="nx.json" %}
{
"plugins": [
{
"plugin": "@nx/jest/plugin",
"include": ["e2e/**/*"],
"options": {
"targetName": "e2e-local",
"ciTargetName": "e2e-ci",
"ciGroupname": "My E2E tests (CI)"
}
}
]
}
```
### How @nx/jest Infers Tasks
{% callout type="note" title="Inferred Tasks" %}
@@ -1,141 +0,0 @@
# Configure TypeScript Project References in an Nx Workspace
In Nx 20, the `@nx/js` plugin provides the ability to incrementally build projects in a monorepo using [TypeScript Project References](https://www.typescriptlang.org/docs/handbook/project-references.html). Nx also provides a `ts` preset for `create-nx-workspace` that configures project references and uses `workspaces` to link projects instead of [TypeScript compilerOptions Paths](https://www.typescriptlang.org/docs/handbook/modules/reference.html#paths).
The TypeScript team recommends using project references when working in a monorepo, but until now the configuration settings were difficult to maintain. Each project is required to list its own project dependencies in the `references` property of the `tsconfig.json` file so that TypeScript can incrementally compile projects in the correct order. In a large monorepo, maintaining those settings manually is cost prohibitive. To solve this problem, the `@nx/js` plugin registers a [sync generator](/concepts/sync-generators) to automatically update the references based on Nx's project graph before any TypeScript `build` task is executed.
## Create a New Nx Workspace Using Project References
We anticipate that this style of compiling projects will eventually become the default, but currently it will only be enabled for repositories configured in a specific way. Existing workspaces will continue to function as usual and there is no migration path yet. You can generate a new repository with these settings by using the `--preset=ts` flag of the `create-nx-workspace` command.
```shell
npx create-nx-workspace --preset=ts
```
{% callout type="note" title="Empty Workspace with Paths" %}
To generate an empty Nx workspace that links projects with the `compilerOptions.paths` property and does not use project references, use `create-nx-workspace --preset=apps`
{% /callout %}
This will generate an empty repository that is configured to use TypeScript project references. To see the new functionality in action, create some TypeScript projects and make sure to use the `tsc` bundler option.
```shell
nx g @nx/js:lib packages/cart --bundler=tsc
nx g @nx/js:lib packages/utils --bundler=tsc
```
These generators will detect that your repository is configured to use project references and update the configuration accordingly. If these generators were executed in an Nx repository that used `compilerOptions.paths`, they would update that setting instead.
To make `cart` depend on `utils`, update `packages/cart/package.json` like this:
```jsonc {% fileName="packages/cart/package.json" %}
{
"dependencies": {
"utils": "*"
}
}
```
Now if you run `nx build cart` or directly run `nx sync`, the `packages/cart/tsconfig.json` file will have its references updated for you.
## Project Reference Configuration Files
Nx expects the following configuration settings to be in place in order to use TypeScript project references to build projects. Most of this configuration is set up and maintained for you automatically by Nx.
Identify projects in the `workspaces` property in the root `package.json` file.
```json {% fileName="package.json" %}
{
"workspaces": ["packages/*"]
}
```
The root `tsconfig.base.json` should contain a `compilerOptions` property and no other properties. `compilerOptions.composite` and `compilerOptions.declaration` should be set to `true`. `compilerOptions.paths` should not be set.
```jsonc {% fileName="tsconfig.base.json" %}
{
"compilerOptions": {
// Required compiler options
"composite": true,
"declaration": true
// Other options...
}
}
```
The root `tsconfig.json` file should extend `tsconfig.base.json` and not include any files. It needs to have `references` for every project in the repository so that editor tooling works correctly.
```jsonc {% fileName="tsconfig.json" %}
{
"extends": "./tsconfig.base.json",
"files": [], // intentionally empty
"references": [
// UPDATED BY PROJECT GENERATORS
// All projects in the repository
]
}
```
Each project's `tsconfig.json` file should extend the `tsconfig.base.json` file and list `references` to the project's dependencies.
```jsonc {% fileName="packages/cart/tsconfig.json" %}
{
"extends": "../../tsconfig.base.json",
"files": [], // intentionally empty
"references": [
// UPDATED BY NX SYNC
// All project dependencies
{
"path": "../utils"
},
// This project's other tsconfig.*.json files
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}
```
Each project's `tsconfig.lib.json` file extends the project's `tsconfig.json` file and adds `references` to the `tsconfig.lib.json` files of project dependencies.
```jsonc {% fileName="packages/cart/tsconfig.lib.json" %}
{
"extends": "./tsconfig.json",
"compilerOptions": {
// Any overrides
},
"include": ["src/**/*.ts"],
"exclude": [
// exclude config and test files
],
"references": [
// UPDATED BY NX SYNC
// tsconfig.lib.json files for project dependencies
{
"path": "../utils/tsconfig.lib.json"
}
]
}
```
The project's `tsconfig.spec.json` does not need to reference project dependencies.
```jsonc {% fileName="packages/cart/tsconfig.spec.json" %}
{
"extends": "./tsconfig.json",
"compilerOptions": {
// Any overrides
},
"include": [
// test files
],
"references": [
// tsconfig.lib.json for this project
{
"path": "./tsconfig.lib.json"
}
]
}
```
@@ -72,7 +72,7 @@
"description": "Path where the build artifacts are located. If not provided then it will be infered from the buildTarget executor options as outputPath"
},
"cors": {
"type": "boolean",
"oneOf": [{ "type": "boolean" }, { "type": "string" }],
"description": "Enable CORS",
"default": true
},
+18 -6
View File
@@ -254,6 +254,12 @@
"tags": ["sync"],
"file": "shared/concepts/sync-generators"
},
{
"name": "TypeScript Project Linking",
"id": "typescript-project-linking",
"tags": ["project-linking"],
"file": "shared/concepts/typescript-project-linking"
},
{
"name": "Nx and Turborepo",
"id": "turbo-and-nx",
@@ -1012,6 +1018,12 @@
"id": "eslint",
"file": "shared/eslint"
},
{
"name": "Switch to Workspaces and TS Project References",
"id": "switch-to-workspaces-project-references",
"tags": ["project-linking"],
"file": "shared/recipes/tips-n-tricks/switch-to-workspaces-project-references"
},
{
"name": "Enable Typescript Batch Mode",
"id": "enable-tsc-batch-mode",
@@ -2303,12 +2315,6 @@
"id": "overview",
"path": "/nx-api/js",
"file": "shared/packages/js/js-plugin"
},
{
"name": "Configure TypeScript Project References in an Nx Workspace",
"id": "typescript-project-references",
"path": "/nx-api/js/typescript-project-references",
"file": "shared/packages/js/typescript-project-references"
}
]
},
@@ -2680,6 +2686,12 @@
"id": "overview",
"path": "/nx-api/powerpack-conformance",
"file": "shared/packages/powerpack-conformance/powerpack-conformance-plugin"
},
{
"name": "Create a Conformance Rule",
"id": "create-conformance-rule",
"path": "/nx-api/powerpack-conformance",
"file": "shared/packages/powerpack-conformance/create-conformance-rule"
}
]
},
@@ -8,48 +8,10 @@ Let's create a custom rule which we can then publish to Nx Cloud. We will first
nx generate @nx/js:library cloud-conformance-rules
```
The Nx Cloud distribution mechanism expects each rule to be created in a named subdirectory in the `src/` directory of our new project, and each rule directory to contain an `index.ts` and a `schema.json` file.
The Nx Cloud distribution mechanism expects each rule to be created in a named subdirectory in the `src/` directory of our new project, and each rule directory to contain an `index.ts` and a `schema.json` file. You can read more about [creating a conformance rule](/nx-api/powerpack-conformance/documents/create-conformance-rule) in the dedicated guide. For this recipe, we'll generate a default rule to use in the publishing process.
E.g.
```
cloud-conformance-rules/
├── src/
│ ├── test-cloud-rule/
│ │ ├── index.ts // Our rule implementation
│ │ └── schema.json // The schema definition for the options supported by our rule
```
Our simple rule implementation in `test-cloud-rule/index.ts`, that will currently not report any violations, might look like this:
```ts
import { createConformanceRule } from '@nx/powerpack-conformance';
export default createConformanceRule<object>({
name: 'test-cloud-rule',
category: 'reliability',
description: 'A test cloud rule',
reporter: 'non-project-files-reporter',
implementation: async () => {
return {
severity: 'low',
details: {
violations: [],
},
};
},
});
```
And because we do not yet have any options that we want to support for our rule, our `schema.json` file will looks like this (using the [JSON Schema](https://json-schema.org/) format):
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {},
"additionalProperties": false
}
```shell
nx g @nx/powerpack-conformance:create-rule --name=test-cloud-rule --directory=cloud-conformance-rules/src/test-cloud-rule --category=reliability --description="A test cloud rule" --reporter=non-project-files-reporter
```
We now have a valid implementation of a rule and we are ready to build it and publish it to Nx Cloud. The [`@nx/powerpack-conformance` plugin](/nx-api/powerpack-conformance) provides a [dedicated executor called `bundle-rules`](/nx-api/powerpack-conformance/executors/bundle-rules) for creating appropriate build artifacts for this purpose, so we will wire that executor up to a new build target in our `cloud-conformance-rules` project's `project.json` file:
+2 -2
View File
@@ -10,7 +10,7 @@ By default, when you set up [Nx Agents](/ci/features/distribute-task-execution)
...
jobs:
- job: main
displayName: Main Job
name: Main Job
...
steps:
...
@@ -68,7 +68,7 @@ You can then reference your distribution configuration in your CI pipeline confi
...
jobs:
- job: main
displayName: Main Job
name: Main Job
...
steps:
...
@@ -1,3 +1,7 @@
---
keywords: [split tasks, atomizer]
---
# Automatically Split E2E Tasks by File (Atomizer)
{% youtube
+169 -64
View File
@@ -1,24 +1,21 @@
# Assignment Rules (beta)
Assignment rules allow you to control which tasks can run on which agents. Save on agent costs by provisioning different sizes of agents all with the confidence that your tasks will be run on the agents that are best suited for them. You can ensure resource intensive targets like `e2e-ci` and `build` have what they need by using larger agents. Lighter tasks like `lint` and `test` can run on smaller agents.
Assignment rules allow you to control which tasks can run on which agents. Save on agent costs by provisioning different sizes of agents to suite the individual needs of your tasks. You can ensure resource intensive targets like `e2e-ci` and `build` have what they need by using larger agents. Lighter tasks like `lint` and `test` can run on smaller agents.
Assignment rules are defined in your workspaces `distribution-config.yaml` file. This file should be created in the `.nx/workflows` directory of your repository. Note that this means that you must have [dynamic agents](/ci/features/dynamic-agents) also configured in your `distribution-config.yaml` file.
Assignment rules are defined in `yaml` files within your workspace's `.nx/workflows` directory. You can use assignment rules with self-hosted agents or with [dynamic Nx agents](/ci/features/dynamic-agents). Note that additional configuration is required when using self-hosted agents.
## How to Define an Assignment Rule
Each assignment rule has one of the following properties that it matches against tasks: `project`, `target`, and/or `configuration`. It also has a list of possible [agent types](/ci/reference/launch-templates) that tasks with the matching properties can run on. Rules are defined in yaml like the following:
```yaml {% fileName=".nx/workflows/distribution-config.yaml" %}
distribute-on:
default: 3 linux-small-js, 2 linux-medium-js, 1 linux-large-js
```yaml {% fileName=".nx/workflows/assignment-rules.yaml" %}
assignment-rules:
- project: app1
target: build
configuration: production
runs-on:
- linux-large-js
- linux-medium-js
- linux-large-js
```
The above rule will match any task that has a project named `app1`, a target named `build`, and a configuration named `production`. Any tasks that match this rule will only be allowed to run on agents with the `linux-large-js` and `linux-medium-js` launch templates.
@@ -26,58 +23,13 @@ The above rule will match any task that has a project named `app1`, a target nam
You can mix and match any of the criteria in an assignment rule provided that you follow the constraints:
- At least one of the following properties is defined: `project`, `target`, `configuration`.
- There is at least one [agent type](/ci/reference/launch-templates) specified in the `run-on` field.
- Every changeset in your `distribute-on` field must include at **least one agent** that matches each agent type specified in the run-on field across all assignment rules. For example, if your rules distribute tasks on `linux-small-js`, `linux-medium-js`, and `linux-large-js`, then at least one agent of each type must be available; otherwise, tasks associated with those rules cannot be executed.
- There is at least one [agent type](/ci/reference/launch-templates) specified in the `runs-on` field.
- Every changeset in your `distribute-on` field must include at **least one agent** that matches each agent type specified in the `runs-on` field across all assignment rules. For example, if your rules distribute tasks on `linux-small-js`, `linux-medium-js`, and `linux-large-js`, then at least one agent of each type must be available; otherwise, tasks associated with those rules cannot be executed.
### Invalid Assignment Rules Example
```yaml {% fileName=".nx/workflows/distribution-config.yaml" %}
distribute-on:
# Invalid changeset that is missing `linux-large-js`. Tasks assigned to large agents won't be able to execute.
small-changeset: 1 linux-small-js, 2 linux-medium-js
medium-changeset: 2 linux-small-js, 2 linux-medium-js, 3 linux-large-js
large-changeset: 3 linux-small-js, 3 linux-medium-js, 4 linux-large-js
assignment-rules:
# Missing one of `project`, `target`, `configuration`
- runs-on:
- linux-medium-js
- linux-large-js
# Missing `runs-on`
- target: lint
configuration: production
# Agent type not found in any of the `distribute-on` changesets
- project: lib1
target: test
runs-on:
- linux-extra-large-js
```
### Valid Assignment Rules Example
```yaml {% fileName=".nx/workflows/distribution-config.yaml" %}
distribute-on:
default: 3 linux-small-js, 2 linux-medium-js, 1 linux-large-js
# All rules below are valid assignment rules
assignment-rules:
- project: app1
runs-on:
- linux-medium-js
- linux-large-js
- target: lint
configuration: production
runs-on:
- linux-large-js
- project: lib1
target: test
runs-on:
- linux-medium-js
```
{% callout type="note" title="If you are using self-hosted agents, you must define your own agent types" %}
You must define your own agent types and attach them to your self-hosted agents using the `NX_AGENT_LAUNCH_TEMPLATE` environment variable. Ensure that for each `runs-on` field in your assignment rules, you have corresponding agents in your agent pool that have the same agent type.
See below for an [example](#using-assignment-rules-with-selfhosted-agents) of how to define your own agent types when using self-hosted agents.
{% /callout %}
## Assignment Rule Precedence
@@ -95,7 +47,7 @@ Having multiple assignment rules means that often rules may overlap or apply to
### Rule Precedence Example
In this example, the task defined below can match multiple assignment rules. However, since the second rule specifies all three properties (`project`, `target`, and `configuration`) rather than just two (`project` and `target`), it takes precedence, and we apply the second rule when distributing the task.
In this example, the task defined below can match multiple assignment rules. However, since the second rule specifies all three properties (`project`, `target`, and `configuration`) rather than just two (`project` and `target`), it takes precedence, and we automatically apply the second rule when distributing the task.
```json {% fileName="A task from your workspace" %}
{
@@ -106,10 +58,8 @@ In this example, the task defined below can match multiple assignment rules. How
```
```yaml {% fileName=".nx/workflows/distribution-config.yaml" %}
distribute-on:
default: 10 linux-medium-js, 8 linux-large-js
assignment-rules:
# A task for app1:build:production will use this rule because it is more specific (matches all three properties instead of just two)
- project: app1
target: build
configuration: production
@@ -122,7 +72,110 @@ assignment-rules:
- linux-large-js
```
## Using Assignment Rules in your CI Pipeline
## Using Assignment Rules with Self-Hosted Agents
A typical `assignment-rules.yaml` file might look like this:
```yaml {% fileName=".nx/workflows/assignment-rules.yaml" %}
assignment-rules:
- project: app1
target: build
configuration: production
runs-on:
- linux-medium
- linux-large
- target: lint
runs-on:
- linux-medium
- configuration: development
runs-on:
- linux-medium
- linux-large
```
Note that the agent types supplied in the `runs-on` property will be used to determine which agents will have rules applied to them.
You can choose to name your agent types anything you want, but they must be set on your agents via the `NX_AGENT_LAUNCH_TEMPLATE` environment variable.
You can then reference your assignment rules file within your `start-ci-run` command:
```shell
npx nx-cloud start-ci-run --distribute-on="manual" --assignment-rules=".nx/workflows/assignment-rules.yaml"
```
The following is an example of what this looks like within a Github Actions pipeline:
```yaml {% fileName=".github/workflows/ci.yaml" %}
---
jobs:
main:
name: Main Job
runs-on: ubuntu-latest
steps:
- ... # setup steps for your main job
- run: npx nx-cloud start-ci-run --distribute-on="manual" --assignment-rules=".nx/workflows/assignment-rules.yaml" --stop-agents-after="e2e-ci"
- ... # Nx commands you want to distribute
medium-agents:
name: Agents ${{ matrix.agent }}
runs-on:
group: medium-agents
strategy:
matrix:
agent: [1, 2, 3]
steps:
- name: Checkout
uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- ... # other setup steps you may need
- name: Install dependencies
run: npm ci --legacy-peer-deps
- name: Start Agent ${{ matrix.agent }}
run: npx nx-cloud start-agent
env:
NX_AGENT_NAME: ${{ matrix.agent }}
NX_AGENT_LAUNCH_TEMPLATE: 'linux-medium' # This value needs to match one of the 'runs-on' values defined in the assignment rules
large-agents:
name: Agents ${{ matrix.agent }}
runs-on:
group: large-agents
strategy:
matrix:
agent: [1, 2, 3]
steps:
- name: Checkout
uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- ... # other setup steps you may need
- name: Install dependencies
run: npm ci --legacy-peer-deps
- name: Start Agent ${{ matrix.agent }}
run: npx nx-cloud start-agent
env:
NX_AGENT_NAME: ${{ matrix.agent }}
NX_AGENT_LAUNCH_TEMPLATE: 'linux-large' # This value needs to match one of the 'runs-on' values defined in the assignment rules
```
## Using Assignment Rules with Dynamic Nx Agents
A typical `distribution-config.yaml` file might look like this:
@@ -155,10 +208,62 @@ You can then reference your distribution configuration in your CI pipeline confi
...
jobs:
- job: main
displayName: Main Job
name: Main Job
...
steps:
...
- run: npx nx-cloud start-ci-run --distribute-on=".nx/workflows/distribution-config.yaml" --stop-agents-after="e2e-ci"
- ..
```
### More Examples of Assignment Rules with Dynamic Agents
#### Invalid Assignment Rules Example
```yaml {% fileName=".nx/workflows/distribution-config.yaml" %}
distribute-on:
# Invalid changeset that is missing `linux-large-js`. Tasks assigned to large agents won't be able to execute.
small-changeset: 1 linux-small-js, 2 linux-medium-js
medium-changeset: 2 linux-small-js, 2 linux-medium-js, 3 linux-large-js
large-changeset: 3 linux-small-js, 3 linux-medium-js, 4 linux-large-js
assignment-rules:
# Missing one of `project`, `target`, `configuration`
- runs-on:
- linux-medium-js
- linux-large-js
# Missing `runs-on`
- target: lint
configuration: production
# Agent type not found in any of the `distribute-on` changesets
- project: lib1
target: test
runs-on:
- linux-extra-large-js
```
#### Valid Assignment Rules Example
```yaml {% fileName=".nx/workflows/distribution-config.yaml" %}
distribute-on:
default: 3 linux-small-js, 2 linux-medium-js, 1 linux-large-js
# All rules below are valid assignment rules
assignment-rules:
- project: app1
runs-on:
- linux-medium-js
- linux-large-js
- target: lint
configuration: production
runs-on:
- linux-large-js
- project: lib1
target: test
runs-on:
- linux-medium-js
```
+38 -28
View File
@@ -141,9 +141,9 @@ You can find the [list of Nx Cloud reusable steps here](https://github.com/nrwl/
launch-templates:
template-one:
init-steps:
- uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/checkout/main.yaml'
- uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
- name: 'Install Node Modules'
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/install-node-modules/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node-modules/main.yaml'
```
### `launch-templates.<template-name>.init-steps[*].script`
@@ -186,10 +186,13 @@ launch-templates:
template-one:
init-steps:
- name: Restore Node Modules Cache
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/cache/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
inputs:
key: 'package-lock.json|yarn.lock|pnpm-lock.yaml'
paths: 'node_modules'
paths: |
~/.npm
# or ~/.cache/yarn
# or .pnpm-store
base-branch: 'main'
```
@@ -215,27 +218,29 @@ launch-templates:
- name: Checkout
# using a reusable step in an external GitHub repo,
# this step is provided by Nx Cloud: https://github.com/nrwl/nx-cloud-workflows/tree/main/workflow-steps
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/checkout/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
- name: Restore Node Modules Cache
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/cache/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
# the cache step requires configuration via env vars
# https://github.com/nrwl/nx-cloud-workflows/tree/main/workflow-steps/cache#options
inputs:
key: 'package-lock.json|yarn.lock|pnpm-lock.yaml'
paths: 'node_modules'
paths: |
~/.npm
# or ~/.cache/yarn
# or .pnpm-store
base-branch: 'main'
- name: Restore Browser Binary Cache
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/cache/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
inputs:
key: 'package-lock.json|yarn.lock|pnpm-lock.yaml|"browsers"'
paths: |
'~/.cache/Cypress'
'~/.cache/ms-playwright'
base-branch: 'main'
- name: Install Node Modules
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/install-node-modules/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node-modules/main.yaml'
- name: Install Browsers (if needed)
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/install-browsers/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-browsers/main.yaml'
# You can also run a custom script to configure various things on the agent machine
- name: Run a custom script
script: |
@@ -268,25 +273,27 @@ launch-templates:
MY_ENV_VAR: shared
init-steps:
- name: Checkout
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/checkout/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
- name: Restore Node Modules Cache
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/cache/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
inputs:
key: 'package-lock.json|yarn.lock|pnpm-lock.yaml'
paths: 'node_modules'
paths: |
~/.npm
# or ~/.cache/yarn
# or .pnpm-store
base-branch: 'main'
- name: Restore Browser Binary Cache
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/cache/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
inputs:
key: 'package-lock.json|yarn.lock|pnpm-lock.yaml|"browsers"'
paths: |
'~/.cache/Cypress'
'~/.cache/ms-playwright'
base-branch: 'main'
- name: Install Node Modules
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/install-node-modules/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node-modules/main.yaml'
- name: Install Browsers (if needed)
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/install-browsers/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-browsers/main.yaml'
- name: Run a custom script
script: |
git config --global user.email test@test.com
@@ -306,15 +313,18 @@ launch-templates:
image: 'ubuntu22.04-node20.11-v9'
init-steps:
- name: Checkout
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/checkout/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
- name: Restore Node Modules Cache
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/cache/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'
inputs:
key: 'package-lock.json|yarn.lock|pnpm-lock.yaml'
paths: 'node_modules'
paths: |
~/.npm
# or ~/.cache/yarn
# or .pnpm-store
base-branch: 'main'
- name: Install Node Modules
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/install-node-modules/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node-modules/main.yaml'
- name: Install Rust
script: |
curl --proto '=https' --tlsv1.3 https://sh.rustup.rs -sSf | sh -s -- -y
@@ -391,14 +401,14 @@ launch-templates:
image: 'ubuntu22.04-node20.11-v9'
init-steps:
- name: Checkout
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/checkout/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
- name: Auth to Registry
script: |
# create .npmrc with @myorg scoped packages pointing to GH npm registry
echo "@myorg:registry=https://npm.pkg.github.com" >> .npmrc
echo "//npm.pkg.github.com/:_authToken=${SOME_AUTH_TOKEN}" >> .npmrc
- name: Install Node Modules
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/install-node-modules/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node-modules/main.yaml'
```
Pass `SOME_AUTH_TOKEN` via `--with-env-vars`
@@ -426,10 +436,10 @@ launch-templates:
image: 'ubuntu22.04-node20.11-v9'
init-steps:
- name: Checkout
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/checkout/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
- name: Install Node
# note the step is only released as of v4 of the workflow steps
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/install-node/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node/main.yaml'
inputs:
# can omit value if a '.nvmrc' file is within the root of the repo
node_version: '21'
@@ -453,7 +463,7 @@ launch-templates:
image: 'ubuntu22.04-node20.11-v9'
init-steps:
- name: Checkout
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/checkout/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'
- name: Install nvm
script: |
# run nvm install script
@@ -468,7 +478,7 @@ launch-templates:
# confirm that the node version has changed
script: node -v
- name: Install Node Modules
uses: 'nrwl/nx-cloud-workflows/v4/workflow-steps/install-node-modules/main.yaml'
uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node-modules/main.yaml'
# Continue setup steps as needed
```
+8
View File
@@ -1,5 +1,13 @@
# Enterprise Release Notes
### 2024.10.2
- Fix: AWS S3 bucket connections when using STS role-based authentication
### 2024.10.1
- Fix: GitHub and external bucket connection issues when using a proxy
### 2024.10
This is a big release so let's go through the highlights first. There is also an important "Breaking changes" section at the end.
+4
View File
@@ -1,3 +1,7 @@
---
keywords: [build, serve, test, lint]
---
# Common Tasks
The tasks that are [inferred by plugins](/concepts/inferred-tasks) or that you define in your [project configuration](/reference/project-configuration) can have any name that you want, but it is helpful for developers if you keep your task naming convention consistent across the projects in your repository. This way, if a developer moves from one project to another, they already know how to launch tasks for the new project. Here are some common task names that you can define for your projects.
+3 -6
View File
@@ -8,7 +8,7 @@ Note that the relationship between Nx and Turborepo isnt the same as with Nx
We do our best to be unbiased, but, of course you should do your own research. Read the docs, try things out and build your own opinion.
We clearly separate Nx (the open source tool) and [Nx Cloud](https://nx.app) (the SAAS product). Turborepo doesnt have such a separation. Hence, in this guide we compare Turborepo with Nx+Nx Cloud (so its apples to apples). That said, you dont have to use Nx Cloud to get features such as remote caching and distributed task execution. We provide public APIs so you can build your own, if you'd prefer not to use Nx Cloud.
We clearly separate Nx (the open source tool) and [Nx Cloud](https://nx.app) (the SAAS product). Turborepo doesnt have such a separation. Hence, in this guide we compare Turborepo with Nx+Nx Cloud (so its apples to apples).
We are going to compare the tools in three different ways: **features**, **tech and performance**, and **community**.
@@ -80,7 +80,6 @@ A crucial feature in Nx is the ability to not only parallelize your tasks on a s
- **Turborepo doesnt support it.** The best thing you can do when using Turborepo is binning/sharding, and that doesnt work for non-trivial workspaces.
- **Distributed task execution has a significantly higher impact on the ability to scale the repo than the computation cache.** You can scale without the cache, you cannot scale without the distribution.
- This is the biggest feature related to performance and scaling that Turborepo is missing. And its by far the hardest one to build.
- As with the rest of Nx, you can build your own version of the distributed task execution given the provided public API. If you choose not to implement your own version of the remote cache, you can use Nx Cloud. There is an [on-prem version of Nx Cloud](https://nx.app/private-cloud), so you have full control over where the artifacts are stored.
If you want to learn more, check out our article on [Distributing CI - Binning and Distributed Task Execution](https://blog.nrwl.io/distributing-ci-binning-and-distributed-task-execution-632fe31a8953)
@@ -147,7 +146,7 @@ Benchmarking is hard because a lot depends on what you are trying to run, in wha
This is the result:
![nx and turbo benchmark](/shared/concepts/turbo-nx-perf.gif)
Nx is 9.4 times faster on the latest MBP. We have made several changes to [the benchmark](https://github.com/vsavkin/large-monorepo/) since it was released (removed the usage `npx` and addressed other concerns folks had), but the result remained roughly the same. Please check out the benchmark.
Nx is 4 times faster on the latest MBP. We have made several changes to [the benchmark](https://github.com/vsavkin/large-monorepo/) since it was released (removed the usage `npx` and addressed other concerns folks had), but the result remained roughly the same. Please check out the benchmark.
Why is it faster? Nx is in many ways akin to React in that it's doing tree diffing when restoring files from the cache. If the right files are in the right place, Nx won't touch them. Turbo blows everything away every time. Nx's version isn't just faster, it's also more useful (again similarly to tree diffing in React). Blowing everything away on every restoration means that if any tools watch the folders (which is common when you build large apps or build microfrontends), they are going to get confused or triggered for no reason. This is similar to how recreating the DOM from scratch isn't just slower, but results in worse UX. But even if you disable tree-diffing and make Nx do what Turbo does, it is still 1.7 times faster.
@@ -163,7 +162,7 @@ The one advantage Turbo's Go implementation has, is that any time you run an Nx
**The reason why we stuck with TypeScript is that our focus was always on extensibility.** If the rise of VSCode taught us anything, it is that its easier to extend things when they are written in JavaScript/TypeScript. Also, 5 years of **working with Fortune 500 companies** clearly showed us that **extensibility is key**!
Its also worth noting that the backend of Nx Cloud is written in Kotlin. This is because the only contributors to our API, work at Nrwl, and we decided it was the best technology for the job.
Its also worth noting that the backend of Nx Cloud is written in Kotlin. This is because the only contributors to our API work at Nx, and we decided it was the best technology for the job.
## Community
@@ -173,8 +172,6 @@ Nx was released in 2016. Turborepo was open sourced in December of 2021. Turbore
- There are about 1 million+ unique [Nx Console](https://marketplace.visualstudio.com/items?itemName=nrwl.angular-console) (a plugin for VSCode) installations.
- There is a rich ecosystem of [third-party plugins](/plugin-registry).
From day 1 Nx has always been an **MIT-licensed open source project**, and we did everything to make sure companies using Nx wont end up in the vendor lock-in. We clearly separated Nx the open source project and Nx Cloud the SAAS product. For instance, Nx Cloud is built using the public APIs Nx provides (you can build your own and some companies do). Nx Cloud docs are on a separate domain etc.
## Switch to Nx
If you're ready to switch from Turborepo to Nx, the [migration process is fully documented](/recipes/adopting-nx/from-turborepo).
@@ -0,0 +1,302 @@
# Typescript Project Linking
The naive way to reference code in a separate project is to use a relative path in the `import` statement.
```ts
import { someFunction } from '../../teamA/otherProject';
const result = someFunction();
```
The problem with this approach is that all your import statements become tied to your folder structure. Developers need to know the full path to any project from which they want to import code. Also, if `otherProject` ever moves locations, there will be superfluous code changes across the entire repository.
A more ergonomic solution is to reference your local projects as if they were external npm packages and then use a project linking mechanism to automatically resolve the project file path behind the scenes.
```ts
import { someFunction } from '@myorg/otherProject';
const result = someFunction();
```
There are two different methods that Nx supports for linking TypeScript projects: package manager workspaces and TypeScript path aliases. Project linking with TS path aliases was available with Nx before package managers offered a workspaces project linking approach. The Nx Team has since added full support for workspaces because (1) it has become more common across the TypeScript ecosystem and (2) packages will be resolved using native node module resolution instead of relying on TypeScript. Nx provides a cohesive experience for repositories using TypeScript path aliases without project references or repositories using package manager workspaces with TypeScript project references enabled.
## Project Linking with Workspaces
To create a new Nx workspace that links projects with package manager workspaces, use the `--workspaces` flag.
```shell
npx create-nx-workspace --workspaces
```
### Set Up Package Manager Workspaces
The configuration for package manager workspaces varies based on which package manager you're using.
{% tabs %}
{% tab label="npm" %}
```json {% fileName="package.json" %}
{
"workspaces": ["apps/**", "packages/**"]
}
```
Defining the `workspaces` property in the root `package.json` file lets npm know to look for other `package.json` files in the specified folders. With this configuration in place, all the dependencies for the individual projects will be installed in the root `node_modules` folder when `npm install` is run in the root folder. Also, the projects themselves will be linked in the root `node_modules` folder to be accessed as if they were npm packages.
If you want to reference a local library project with its own `build` task, you should include the library in the `devDependencies` of the application's `package.json` with `*` specified as the library's version. `*` tells npm to use whatever version of the project is available.
```json {% fileName="/apps/my-app/package.json" %}
{
"devDependencies": {
"@my-org/some-project": "*"
}
}
```
{% /tab %}
{% tab label="yarn" %}
```json {% fileName="package.json" %}
{
"workspaces": ["apps/**", "packages/**"]
}
```
Defining the `workspaces` property in the root `package.json` file lets yarn know to look for other `package.json` files in the specified folders. With this configuration in place, all the dependencies for the individual projects will be installed in the root `node_modules` folder when `yarn` is run in the root folder. Also, the projects themselves will be linked in the root `node_modules` folder to be accessed as if they were npm packages.
If you want to reference a local library project with its own `build` task, you should include the library in the `devDependencies` of the application's `package.json` with `workspace:*` specified as the library's version. [`workspace:*` tells yarn that the project is in the same repository](https://yarnpkg.com/features/workspaces) and not an npm package. You want to specify local projects as `devDependencies` instead of `dependencies` so that the library is not included twice in the production bundle of the application.
```json {% fileName="/apps/my-app/package.json" %}
{
"devDependencies": {
"@my-org/some-project": "*"
}
}
```
{% /tab %}
{% tab label="bun" %}
```json {% fileName="package.json" %}
{
"workspaces": ["apps/**", "packages/**"]
}
```
Defining the `workspaces` property in the root `package.json` file lets bun know to look for other `package.json` files in the specified folders. With this configuration in place, all the dependencies for the individual projects will be installed in the root `node_modules` folder when `bun install` is run in the root folder. Also, the projects themselves will be linked in the root `node_modules` folder to be accessed as if they were npm packages.
If you want to reference a local library project with its own `build` task, you should include the library in the `devDependencies` of the application's `package.json` with `workspace:*` specified as the library's version. [`workspace:*` tells bun that the project is in the same repository](https://bun.sh/docs/install/workspaces) and not an npm package. You want to specify local projects as `devDependencies` instead of `dependencies` so that the library is not included twice in the production bundle of the application.
```json {% fileName="/apps/my-app/package.json" %}
{
"devDependencies": {
"@my-org/some-project": "workspace:*"
}
}
```
{% /tab %}
{% tab label="pnpm" %}
```yaml {% fileName="pnpm-workspace.yaml" %}
packages:
- 'apps/**'
- 'packages/**'
```
Defining the `packages` property in the root `pnpm-workspaces.yaml` file lets pnpm know to look for project `package.json` files in the specified folders. With this configuration in place, all the dependencies for the individual projects will be installed in the root `node_modules` folder when `pnpm install` is run in the root folder.
If you want to reference a local library project from an application, you need to include the library in the `devDependencies` of the application's `package.json` with `workspace:*` specified as the library's version. [`workspace:*` tells pnpm that the project is in the same repository](https://pnpm.io/workspaces#workspace-protocol-workspace) and not an npm package. You want to specify local projects as `devDependencies` instead of `dependencies` so that the library is not included twice in the production bundle of the application.
```json {% fileName="/apps/my-app/package.json" %}
{
"devDependencies": {
"@my-org/some-project": "workspace:*"
}
}
```
{% /tab %}
{% /tabs %}
### Set Up TypeScript Project References
With workspaces enabled, you can also configure TypeScript project references to speed up your build and typecheck tasks.
The root `tsconfig.base.json` should contain a `compilerOptions` property and no other properties. `compilerOptions.composite` and `compilerOptions.declaration` should be set to `true`. `compilerOptions.paths` should not be set.
```jsonc {% fileName="tsconfig.base.json" %}
{
"compilerOptions": {
// Required compiler options
"composite": true,
"declaration": true,
"declarationMaps": true
// Other options...
}
}
```
The root `tsconfig.json` file should extend `tsconfig.base.json` and not include any files. It needs to have `references` for every project in the repository so that editor tooling works correctly.
```jsonc {% fileName="tsconfig.json" %}
{
"extends": "./tsconfig.base.json",
"files": [], // intentionally empty
"references": [
// UPDATED BY PROJECT GENERATORS
// All projects in the repository
]
}
```
#### Individual Project TypeScript Configuration
Each project's `tsconfig.json` file should extend the `tsconfig.base.json` file and list `references` to the project's dependencies.
```jsonc {% fileName="packages/cart/tsconfig.json" %}
{
"extends": "../../tsconfig.base.json",
"files": [], // intentionally empty
"references": [
// UPDATED BY NX SYNC
// All project dependencies
{
"path": "../utils"
},
// This project's other tsconfig.*.json files
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}
```
Each project's `tsconfig.lib.json` file extends the project's `tsconfig.json` file and adds `references` to the `tsconfig.lib.json` files of project dependencies.
```jsonc {% fileName="packages/cart/tsconfig.lib.json" %}
{
"extends": "./tsconfig.json",
"compilerOptions": {
// Any overrides
},
"include": ["src/**/*.ts"],
"exclude": [
// exclude config and test files
],
"references": [
// UPDATED BY NX SYNC
// tsconfig.lib.json files for project dependencies
{
"path": "../utils/tsconfig.lib.json"
}
]
}
```
The project's `tsconfig.spec.json` does not need to reference project dependencies.
```jsonc {% fileName="packages/cart/tsconfig.spec.json" %}
{
"extends": "./tsconfig.json",
"compilerOptions": {
// Any overrides
},
"include": [
// test files
],
"references": [
// tsconfig.lib.json for this project
{
"path": "./tsconfig.lib.json"
}
]
}
```
### TypeScript Project References Performance Benefits
Using TypeScript project references improves both the speed and memory usage of build and typecheck tasks. The repository below contains benchmarks showing the difference between running typecheck with and without using TypeScript project references.
{% github-repository title="TypeScript Project References Benchmark" url="https://github.com/jaysoo/typecheck-timings" /%}
Here are the baseline typecheck task performance results.
```text
Typecheck without using project references: 186 seconds, max memory 6.14 GB
```
Using project references allows the TypeScript compiler to individually check the types for each project and store the results of that calculation in a `.tsbuildinfo` file for later use. Because of this, the TypeScript compiler does not need to load the entire codebase into memory at the same time, which you can see from the decreased memory usage on the first run with project references enabled.
```text
Typecheck with project references first run: 175 seconds, max memory 945 MB
```
Once the `.tsbuildinfo` files have been created, subsequent runs will be much faster.
```text
Typecheck with all `.tsbuildinfo` files created: 25 seconds, max memory 429 MB
```
Even if some projects have been updated and individual projects need to be type checked again, the TypeScript compiler can still use the cached `.tsbuildinfo` files for any projects that were not affected. This is very similar to the way Nx's caching and affected features work.
```text
Typecheck (1 pkg updated): 36.33 seconds, max memory 655.14 MB
Typecheck (5 pkg updated): 48.21 seconds, max memory 702.96 MB
Typecheck (25 pkg updated): 65.25 seconds, max memory 666.78 MB
Typecheck (100 pkg updated): 80.69 seconds, max memory 664.58 MB
Typecheck (1 nested leaf pkg updated): 26.66 seconds, max memory 407.54 MB
Typecheck (2 nested leaf pkg updated): 31.17 seconds, max memory 889.86 MB
Typecheck (1 nested root pkg updated): 26.67 seconds, max memory 393.78 MB
```
These performance benefits will be more noticeable for larger repositories, but even small code bases will see some benefits.
### Local TypeScript Path Aliases
If you define TS path aliases in an individual project's tsconfig files, you should not define them also in the root `tsconfig.base.json` file because TypeScript does not merge the paths. The paths defined in the root file would be completely overwritten by the ones defined in the project tsconfig. For instance, you could define paths like this in an application's tsconfig file.
```jsonc {% fileName="/apps/my-remix-app/tsconfig.app.json" %}
{
"compilerOptions": {
"paths": {
"#app/*": ["./app/*"],
"#tests/*": ["./tests/*"],
"@/icon-name": [
"./app/components/ui/icons/name.d.ts",
"./types/icon-name.d.ts"
]
}
}
}
```
## Project Linking with TypeScript Path Aliases
{% callout type="warning" title="Path Aliases Overwrite Extended Configuration Files" %}
If you define path aliases in a project's specific `tsconfig.*.json` file, those path aliases will overwrite the path aliases defined in the root `tsconfig.base.json`. You can't use both project-level path aliases and root path aliases.
{% /callout %}
Linking projects with TypeScript path aliases is configured entirely in the tsconfig files. You can still use package manager workspaces to enable you to define separate third-party dependencies for individual projects, but the local project linking is done by TypeScript instead of the package manager.
The paths for each library are defined in the root `tsconfig.base.json` and each project's `tsconfig.json` should extend that file. Note that application projects do not need to have a path defined because no projects will import code from a top-level application.
```jsonc {% fileName="/tsconfig.base.json" %}
{
"compilerOptions": {
// common compiler option defaults for all projects
// ...
// These compiler options must be false or undefined
"composite": false,
"declaration": false,
"paths": {
// These paths are automatically added by Nx library generators
"@myorg/shared-ui": ["packages/shared-ui/src/index.ts"]
// ...
}
}
}
```
@@ -1,3 +1,7 @@
---
keywords: [update]
---
# Automate Updating Dependencies
{% youtube
@@ -1,3 +1,7 @@
---
keywords: [distributed tasks]
---
# Distribute Task Execution (Nx Agents)
{% youtube
+57 -54
View File
@@ -16,7 +16,7 @@ See the [Adding Nx to NPM/Yarn/PNPM Workspace](/recipes/adopting-nx/adding-to-mo
## Convert turbo.json into Nx Configuration
Most of the settings in your `turbo.json` file can be converted directly into `nx.json` equivalents. The key configuration properties of `dependsOn`, `inputs` and `outputs` have a very similar syntax and can probably be copied over directly from the `turbo.json` `pipeline` into the `nx.json` `targetDefaults`.
Most of the settings in your `turbo.json` file can be converted directly into `nx.json` equivalents. The key configuration properties of `dependsOn`, `inputs` and `outputs` have a very similar syntax and can probably be copied over directly from the `turbo.json` `tasks` into the `nx.json` `targetDefaults`.
If you have project-specific tasks defined in the root `turbo.json` (i.e. `myreactapp#build`) or in project-level `turbo.json` files (i.e. `/packages/myreactapp/turbo.json`), those settings should go in the `nx` property of the project's `package.json` (i.e. `/packages/myreactapp/package.json`).
@@ -29,7 +29,7 @@ Let's say you start with the following `turbo.json` file:
```json {% fileName="/turbo.json" %}
{
"$schema": "https://turbo.build/schema.json",
"pipeline": {
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
@@ -100,58 +100,61 @@ Creating the equivalent configuration with Nx yields the following files:
For each `turbo.json` configuration property, the equivalent Nx property is listed.
| **Global Configuration:** | |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `globalDependencies` | add to the [`sharedGlobals` `namedInput`](/recipes/running-tasks/configure-inputs) |
| `globalEnv` | add to the [`sharedGlobals` `namedInput`](/recipes/running-tasks/configure-inputs) as an [`env` input](/reference/inputs#environment-variables) |
| `globalPassThroughEnv` | N/A. See [Defining Environment Variables](/recipes/tips-n-tricks/define-environment-variables) |
| `globalDotEnv` | add to the [`sharedGlobals` `namedInput`](/recipes/running-tasks/configure-inputs) |
| **Task Configuration:** | |
| ------------------------------- | ---------------------------------------------------------------------------------------------- |
| `extends` | N/A. The project configurations will always extend the `targetDefaults` defined in `nx.json`. |
| `pipeline[task].dependsOn` | [Same syntax](/reference/project-configuration#dependson). |
| `pipeline[task].dotEnv` | Define [file `inputs`](/reference/inputs#source-files) |
| `pipeline[task].env` | Define [env `inputs`](/reference/inputs#environment-variables) |
| `pipeline[task].passThroughEnv` | N/A. See [Defining Environment Variables](/recipes/tips-n-tricks/define-environment-variables) |
| `pipeline[task].outputs` | [Same syntax](/reference/project-configuration#outputs). |
| `pipeline[task].cache` | [Same syntax](/reference/project-configuration#cache) |
| `pipeline[task].inputs` | [Same syntax](/reference/inputs#source-files). |
| `pipeline[task].outputMode` | Use the [`--output-style` command line flag](/nx-api/nx/documents/run-many#output-style) |
| `pipeline[task].persistent` | N/A. |
| **Global Configuration:** | |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `cacheDir` | Set in [`cacheDirectory`](/reference/nx-json#task-options) |
| `deamon` | Use [`NX_DAEMON=false` or set `useDaemonProcess: false`](/concepts/nx-daemon#turning-it-off) in `nx.json` |
| `envMode` | Nx core does not block any environment variables. There are [React](/recipes/react/use-environment-variables-in-react) and [Angular](/recipes/angular/use-environment-variables-in-angular) build executors that handle environment variables in a customized way. |
| `globalDependencies` | add to the [`sharedGlobals` `namedInput`](/recipes/running-tasks/configure-inputs) |
| `globalEnv` | add to the [`sharedGlobals` `namedInput`](/recipes/running-tasks/configure-inputs) as an [`env` input](/reference/inputs#environment-variables) |
| `globalPassThroughEnv` | N/A. See [Defining Environment Variables](/recipes/tips-n-tricks/define-environment-variables) |
| `remoteCache` | See [Nx Replay](/ci/features/remote-cache) |
| `ui` | Use [`--output-style`](/nx-api/nx/documents/run-many#output-style) |
| **Task Configuration:** | |
| ---------------------------- | ---------------------------------------------------------------------------------------------- |
| `extends` | N/A. The project configurations will always extend the `targetDefaults` defined in `nx.json`. |
| `tasks[task].dependsOn` | [Same syntax](/reference/project-configuration#dependson). |
| `tasks[task].env` | Define [env `inputs`](/reference/inputs#environment-variables) |
| `tasks[task].passThroughEnv` | N/A. See [Defining Environment Variables](/recipes/tips-n-tricks/define-environment-variables) |
| `tasks[task].outputs` | [Same syntax](/reference/project-configuration#outputs). |
| `tasks[task].cache` | [Same syntax](/reference/project-configuration#cache) |
| `tasks[task].inputs` | [Same syntax](/reference/inputs#source-files). |
| `tasks[task].outputLogs` | Use the [`--output-style` command line flag](/nx-api/nx/documents/run-many#output-style) |
| `tasks[task].persistent` | N/A. |
| `tasks[task].interactive` | N/A. |
## Command Equivalents
| | |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `turbo run test lint build` | [`nx run-many -t test lint build`](/nx-api/nx/documents/run-many) |
| `--cache-dir` | Set in [`nx.json` under `cacheDirectory`](/reference/nx-json#task-options) |
| `--concurrency` | [`--parallel`](/nx-api/nx/documents/run-many#parallel) |
| `--continue` | [Use `--nx-bail`](/nx-api/nx/documents/run-many#nx-bail) with the inverse value |
| `--cwd` | Available when using the [`run-commands` executor](/nx-api/nx/executors/run-commands#cwd) |
| `--dry-run` | N/A. Nx has `--dry-run` for `nx generate` but not for running tasks. |
| `--env-mode` | N/A |
| `--filter` | Use [`-p admin-*` or `-p tag:api-*`](/nx-api/nx/documents/run-many#projects). Also see [`nx affected`](/nx-api/nx/documents/affected). |
| `--graph` | [Same syntax](/nx-api/nx/documents/run-many#graph) or [`nx graph`](/nx-api/nx/documents/dep-graph) for the entire graph |
| `--force` | [`nx reset`](/nx-api/nx/documents/reset) and then run the command again |
| `--global-deps` | Use [`inputs` in the `nx.json`](/recipes/running-tasks/configure-inputs) or project configuration |
| `--framework-inference` | Nx knows if you're using a particular framework if you use an executor for that framework. |
| `--ignore` | Use an [`.nxignore` file](/reference/nxignore) (or `.gitignore`) |
| `--log-order` | Use [`--output-style`](/nx-api/nx/documents/run-many#output-style) |
| `--no-cache` | Use [`--skip-nx-cache`](/nx-api/nx/documents/run-many#skip-nx-cache) |
| `--no-daemon` | Use [`NX_DAEMON=false` or set `useDaemonProcess: false`](/concepts/nx-daemon#turning-it-off) in `nx.json` |
| `--output-logs` | Use [`--output-style`](/nx-api/nx/documents/run-many#output-style) |
| `--only` | N/A |
| `--parallel` | N/A |
| `--remote-only` | N/A. Can [ignore the remote cache](/ci/features/remote-cache#skipping-cloud-cache) with `--no-cloud`. |
| `--summarize` | N/A |
| `--token` | Set the [Nx Cloud CI Access Token](/ci/recipes/security/access-tokens#setting-ci-access-tokens) or as an environment variable (`NX_CLOUD_ACCESS_TOKEN`) |
| `--team` | See `--token` for choosing a different Nx Cloud workspace. You can [use `--runner`](/nx-api/nx/documents/run-many#runner) to choose a different runner defined in the `nx.json` file. |
| `--preflight` | N/A |
| `--trace` | N/A. [`--verbose`](/nx-api/nx/documents/run-many#verbose) for more logging. |
| `--heap` | N/A. [`--verbose`](/nx-api/nx/documents/run-many#verbose) for more logging. |
| `--cpuprofile` | Use [`NX_PROFILE=profile.json`](/troubleshooting/performance-profiling). |
| `--verbosity` | Use [`--verbose`](/nx-api/nx/documents/run-many#verbose) |
| `turbo gen` | [Use `nx generate`](/nx-api/nx/documents/generate) |
| `turbo login` | No need. [Create an Nx Cloud account](/nx-api/nx/documents/connect-to-nx-cloud) once to set up Nx Cloud. |
| `turbo link` | [Create an Nx Cloud account](/nx-api/nx/documents/connect-to-nx-cloud) |
| | |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `turbo run test lint build` | [`nx run-many -t test lint build`](/nx-api/nx/documents/run-many) |
| `--cache-dir` | Set in [`nx.json` under `cacheDirectory`](/reference/nx-json#task-options) |
| `--concurrency` | [`--parallel`](/nx-api/nx/documents/run-many#parallel) |
| `--continue` | [Use `--nx-bail`](/nx-api/nx/documents/run-many#nx-bail) with the inverse value |
| `--cpuprofile` | Use [`NX_PROFILE=profile.json`](/troubleshooting/performance-profiling). |
| `--cwd` | Available when using the [`run-commands` executor](/nx-api/nx/executors/run-commands#cwd) |
| `--deamon` | Use [`NX_DAEMON=false` or set `useDaemonProcess: false`](/concepts/nx-daemon#turning-it-off) in `nx.json` |
| `--dry-run` | N/A. Nx has `--dry-run` for `nx generate` but not for running tasks. |
| `--env-mode` | Nx core does not block any environment variables. There are [React](/recipes/react/use-environment-variables-in-react) and [Angular](/recipes/angular/use-environment-variables-in-angular) build executors that handle environment variables in a customized way. |
| `--filter` | Use [`-p admin-*` or `-p tag:api-*`](/nx-api/nx/documents/run-many#projects). Also see [`nx affected`](/nx-api/nx/documents/affected). |
| `--force` | [`nx reset`](/nx-api/nx/documents/reset) and then run the command again |
| `--framework-inference` | Nx knows if you're using a particular framework if you use an executor for that framework. |
| `--global-deps` | Use [`inputs` in the `nx.json`](/recipes/running-tasks/configure-inputs) or project configuration |
| `--graph` | [Same syntax](/nx-api/nx/documents/run-many#graph) or [`nx graph`](/nx-api/nx/documents/dep-graph) for the entire graph |
| `--heap` | N/A. [`--verbose`](/nx-api/nx/documents/run-many#verbose) for more logging. |
| `--ignore` | Use an [`.nxignore` file](/reference/nxignore) (or `.gitignore`) |
| `--log-order` | Use [`--output-style`](/nx-api/nx/documents/run-many#output-style) |
| `--no-cache` | Use [`--skip-nx-cache`](/nx-api/nx/documents/run-many#skip-nx-cache) |
| `--output-logs` | Use [`--output-style`](/nx-api/nx/documents/run-many#output-style) |
| `--only` | N/A |
| `--parallel` | N/A |
| `--preflight` | N/A |
| `--remote-only` | N/A. Can [ignore the remote cache](/ci/features/remote-cache#skipping-cloud-cache) with `--no-cloud`. |
| `--summarize` | N/A |
| `--token` | Set the [Nx Cloud CI Access Token](/ci/recipes/security/access-tokens#setting-ci-access-tokens) or as an environment variable (`NX_CLOUD_ACCESS_TOKEN`) |
| `--team` | See `--token` for choosing a different Nx Cloud workspace. You can [use `--runner`](/nx-api/nx/documents/run-many#runner) to choose a different runner defined in the `nx.json` file. |
| `--trace` | N/A. [`--verbose`](/nx-api/nx/documents/run-many#verbose) for more logging. |
| `--verbosity` | Use [`--verbose`](/nx-api/nx/documents/run-many#verbose) |
| `turbo gen` | [Use `nx generate`](/nx-api/nx/documents/generate) |
| `turbo login` | No need. [Create an Nx Cloud account](/nx-api/nx/documents/connect-to-nx-cloud) once to set up Nx Cloud. |
| `turbo link` | [Create an Nx Cloud account](/nx-api/nx/documents/connect-to-nx-cloud) |
+1 -1
View File
@@ -1,4 +1,4 @@
/nameExpo is an open-source framework for apps that run natively on Android, iOS, and the web. Expo brings together the best of mobile and the web and enables many important features for building and scaling an app.
Expo is an open-source framework for apps that run natively on Android, iOS, and the web. Expo brings together the best of mobile and the web and enables many important features for building and scaling an app.
Expo is a set of tools built on top of React Native. The Nx Plugin for Expo contains generators for managing Expo applications and libraries within an Nx workspace.
+21
View File
@@ -91,6 +91,27 @@ target with that name which can be used in CI to run the tests for each file in
}
```
### Customizing atomized unit/e2e tasks group name
By default, the atomized tasks group name is derived from the `ciTargetName`. For example, atomized tasks for the `e2e-ci` target will be grouped under the name "E2E (CI)" when displayed in Nx Cloud or `nx show project <project> --web` UI.
You can customize that name by explicitly providing the optional `ciGroupName` plugin option as such:
```json {% fileName="nx.json" %}
{
"plugins": [
{
"plugin": "@nx/jest/plugin",
"include": ["e2e/**/*"],
"options": {
"targetName": "e2e-local",
"ciTargetName": "e2e-ci",
"ciGroupname": "My E2E tests (CI)"
}
}
]
}
```
### How @nx/jest Infers Tasks
{% callout type="note" title="Inferred Tasks" %}
@@ -1,141 +0,0 @@
# Configure TypeScript Project References in an Nx Workspace
In Nx 20, the `@nx/js` plugin provides the ability to incrementally build projects in a monorepo using [TypeScript Project References](https://www.typescriptlang.org/docs/handbook/project-references.html). Nx also provides a `ts` preset for `create-nx-workspace` that configures project references and uses `workspaces` to link projects instead of [TypeScript compilerOptions Paths](https://www.typescriptlang.org/docs/handbook/modules/reference.html#paths).
The TypeScript team recommends using project references when working in a monorepo, but until now the configuration settings were difficult to maintain. Each project is required to list its own project dependencies in the `references` property of the `tsconfig.json` file so that TypeScript can incrementally compile projects in the correct order. In a large monorepo, maintaining those settings manually is cost prohibitive. To solve this problem, the `@nx/js` plugin registers a [sync generator](/concepts/sync-generators) to automatically update the references based on Nx's project graph before any TypeScript `build` task is executed.
## Create a New Nx Workspace Using Project References
We anticipate that this style of compiling projects will eventually become the default, but currently it will only be enabled for repositories configured in a specific way. Existing workspaces will continue to function as usual and there is no migration path yet. You can generate a new repository with these settings by using the `--preset=ts` flag of the `create-nx-workspace` command.
```shell
npx create-nx-workspace --preset=ts
```
{% callout type="note" title="Empty Workspace with Paths" %}
To generate an empty Nx workspace that links projects with the `compilerOptions.paths` property and does not use project references, use `create-nx-workspace --preset=apps`
{% /callout %}
This will generate an empty repository that is configured to use TypeScript project references. To see the new functionality in action, create some TypeScript projects and make sure to use the `tsc` bundler option.
```shell
nx g @nx/js:lib packages/cart --bundler=tsc
nx g @nx/js:lib packages/utils --bundler=tsc
```
These generators will detect that your repository is configured to use project references and update the configuration accordingly. If these generators were executed in an Nx repository that used `compilerOptions.paths`, they would update that setting instead.
To make `cart` depend on `utils`, update `packages/cart/package.json` like this:
```jsonc {% fileName="packages/cart/package.json" %}
{
"dependencies": {
"utils": "*"
}
}
```
Now if you run `nx build cart` or directly run `nx sync`, the `packages/cart/tsconfig.json` file will have its references updated for you.
## Project Reference Configuration Files
Nx expects the following configuration settings to be in place in order to use TypeScript project references to build projects. Most of this configuration is set up and maintained for you automatically by Nx.
Identify projects in the `workspaces` property in the root `package.json` file.
```json {% fileName="package.json" %}
{
"workspaces": ["packages/*"]
}
```
The root `tsconfig.base.json` should contain a `compilerOptions` property and no other properties. `compilerOptions.composite` and `compilerOptions.declaration` should be set to `true`. `compilerOptions.paths` should not be set.
```jsonc {% fileName="tsconfig.base.json" %}
{
"compilerOptions": {
// Required compiler options
"composite": true,
"declaration": true
// Other options...
}
}
```
The root `tsconfig.json` file should extend `tsconfig.base.json` and not include any files. It needs to have `references` for every project in the repository so that editor tooling works correctly.
```jsonc {% fileName="tsconfig.json" %}
{
"extends": "./tsconfig.base.json",
"files": [], // intentionally empty
"references": [
// UPDATED BY PROJECT GENERATORS
// All projects in the repository
]
}
```
Each project's `tsconfig.json` file should extend the `tsconfig.base.json` file and list `references` to the project's dependencies.
```jsonc {% fileName="packages/cart/tsconfig.json" %}
{
"extends": "../../tsconfig.base.json",
"files": [], // intentionally empty
"references": [
// UPDATED BY NX SYNC
// All project dependencies
{
"path": "../utils"
},
// This project's other tsconfig.*.json files
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}
```
Each project's `tsconfig.lib.json` file extends the project's `tsconfig.json` file and adds `references` to the `tsconfig.lib.json` files of project dependencies.
```jsonc {% fileName="packages/cart/tsconfig.lib.json" %}
{
"extends": "./tsconfig.json",
"compilerOptions": {
// Any overrides
},
"include": ["src/**/*.ts"],
"exclude": [
// exclude config and test files
],
"references": [
// UPDATED BY NX SYNC
// tsconfig.lib.json files for project dependencies
{
"path": "../utils/tsconfig.lib.json"
}
]
}
```
The project's `tsconfig.spec.json` does not need to reference project dependencies.
```jsonc {% fileName="packages/cart/tsconfig.spec.json" %}
{
"extends": "./tsconfig.json",
"compilerOptions": {
// Any overrides
},
"include": [
// test files
],
"references": [
// tsconfig.lib.json for this project
{
"path": "./tsconfig.lib.json"
}
]
}
```
@@ -81,3 +81,29 @@ Finally, you need to configure your Nx cache in the `nx.json` file. The `contain
| --------------- | -------------------------------- |
| **container** | The name of the container to use |
| **accountName** | The name of blob storage account |
# Cache Modes
By default, Nx will try to write and read from the remote cache while running locally. This means that permissions must be set for users who are expected to access the remote cache.
Nx will only show warnings when the remote cache is not writable. You can disable these warnings by setting `localMode` to `read-only` or `no-cache` in the `nx.json` file.
```jsonc {% fileName="nx.json" %}
{
"azure": {
// ...
"localMode": "read-only"
}
}
```
The cache mode in CI can also be configured by setting `ciMode` to `read-only` or `no-cache` in the `nx.json` file. Or setting `NX_POWERPACK_CACHE_MODE` to `read-only` or `no-cache` in the CI environment.
```jsonc {% fileName="nx.json" %}
{
"azure": {
// ...
"ciMode": "read-only"
}
}
```
@@ -0,0 +1,308 @@
# Create a Conformance Rule
For local conformance rules, the resolution utilities from `@nx/js` are used in the same way they are for all other JavaScript/TypeScript files in Nx. Therefore, you can simply reference an adhoc JavaScript file or TypeScript file in your `"rule"` property (as long as the path is resolvable based on your package manager and/or tsconfig setup), and the rule will be loaded/transpiled as needed. The rule implementation file should also have a `schema.json` file next to it that defines the available rule options, if any.
Therefore, in practice, writing your local conformance rules in an Nx generated library is the easiest way to organize them and ensure that they are easily resolvable via TypeScript. The library in question could also be an Nx plugin, but it does not have to be.
To write your own conformance rule, run the `@nx/powerpack-conformance:create-rule` generator and answer the prompts.
```text {% command="nx g @nx/powerpack-conformance:create-rule" %}
NX Generating @nx/powerpack-conformance:create-rule
✔ What is the name of the rule? · local-conformance-rule-example
✔ Which directory do you want to create the rule directory in? · packages/my-plugin/local-conformance-rule
✔ What category does this rule belong to? · security
✔ What reporter do you want to use for this rule? · project-reporter
✔ What is the description of the rule? · an example of a conformance rule
CREATE packages/my-plugin/local-conformance-rule/local-conformance-rule-example/index.ts
CREATE packages/my-plugin/local-conformance-rule/local-conformance-rule-example/schema.json
```
The generated rule definition file should look like this:
```ts {% fileName="packages/my-plugin/local-conformance-rule/index.ts" %}
import {
createConformanceRule,
ProjectViolation,
} from '@nx/powerpack-conformance';
export default createConformanceRule({
name: 'local-conformance-rule-example',
category: 'security',
description: 'an example of a conformance rule',
reporter: 'project-reporter',
implementation: async (context) => {
const violations: ProjectViolation[] = [];
return {
severity: 'low',
details: {
violations,
},
};
},
});
```
To enable the rule, you need to register it in the `nx.json` file.
```json {% fileName="nx.json" %}
{
"conformance": {
"rules": [
{
"rule": "./packages/my-plugin/local-conformance-rule/index.ts"
}
]
}
}
```
Note that the severity of the error is defined by the rule author and can be adjusted based on the specific violations that are found.
## Conformance Rule Examples
There are three types of reporters that a rule can use.
- `project-reporter` - The rule evaluates an entire project at a time.
- `project-files-reporter` - The rule evaluates a single project file at a time.
- `non-project-files-reporter` - The rule evaluates files that don't belong to any project.
{% tabs %}
{% tab label="project-reporter" %}
The `@nx/powerpack-conformance:ensure-owners` rule provides us an example of how to write a `project-reporter` rule. The `@nx/powerpack-owners` plugin adds an `owners` metadata property to every project node that has an owner in the project graph. This rule checks each project node metadata to make sure that each project has some owner defined.
```ts
import { ProjectGraphProjectNode } from '@nx/devkit';
import {
createConformanceRule,
ProjectViolation,
} from '@nx/powerpack-conformance';
export default createConformanceRule({
name: 'ensure-owners',
category: 'consistency',
description: 'Ensure that all projects have owners defined via Nx Owners.',
reporter: 'project-reporter',
implementation: async (context) => {
const violations: ProjectViolation[] = [];
for (const node of Object.values(
context.projectGraph.nodes
) as ProjectGraphProjectNode[]) {
const metadata = node.data.metadata;
if (!metadata?.owners || Object.keys(metadata.owners).length === 0) {
violations.push({
sourceProject: node.name,
message: `This project currently has no owners defined via Nx Owners.`,
});
}
}
return {
severity: 'medium',
details: {
violations,
},
};
},
});
```
{% /tab %}
{% tab label="project-files-reporter" %}
This rule uses TypeScript AST processing to ensure that `index.ts` files use a client-side style of export syntax and `server.ts` files use a server-side style of export syntax.
```ts
import {
createConformanceRule,
ProjectFilesViolation,
} from '@nx/powerpack-conformance';
import { existsSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
import {
createSourceFile,
isExportDeclaration,
isStringLiteral,
isToken,
ScriptKind,
ScriptTarget,
} from 'typescript';
export default createConformanceRule({
name: 'server-client-public-api',
category: 'consistency',
description: 'Ensure server-only and client-only public APIs are not mixed',
reporter: 'project-files-reporter',
implementation: async ({ projectGraph }) => {
const violations: ProjectFilesViolation[] = [];
for (const nodeId in projectGraph.nodes) {
const node = projectGraph.nodes[nodeId];
const sourceRoot = node.data.root;
const indexPath = join(sourceRoot, 'src/index.ts');
const serverPath = join(sourceRoot, 'src/server.ts');
if (existsSync(indexPath)) {
const fileContent = readFileSync(indexPath, 'utf8');
violations.push(
...processEntryPoint(fileContent, indexPath, nodeId, 'client')
);
}
if (existsSync(serverPath)) {
const fileContent = readFileSync(serverPath, 'utf8');
violations.push(
...processEntryPoint(fileContent, serverPath, nodeId, 'server')
);
}
}
return {
severity: 'medium',
details: { violations },
};
},
});
export function processEntryPoint(
fileContent: string,
entryPoint: string,
project: string,
style: 'server' | 'client'
) {
const violations: ProjectFilesViolation[] = [];
const sf = createSourceFile(
entryPoint,
fileContent,
ScriptTarget.Latest,
true,
ScriptKind.TS
);
let hasNotOnlyExports = false;
sf.forEachChild((node) => {
if (isExportDeclaration(node)) {
const moduleSpecifier =
node.moduleSpecifier && isStringLiteral(node.moduleSpecifier)
? node.moduleSpecifier.getText()
: '';
if (isModuleSpecifierViolated(moduleSpecifier, style)) {
if (
violations.find(
(v) => v.file === entryPoint && v.sourceProject === project
)
) {
// we already have a violation for this file and project, so we don't need to add another one
return;
}
violations.push({
message:
style === 'client'
? 'Client-side only entry point cannot export from server-side modules'
: 'Server-side only entry point can only export server-side modules ',
file: entryPoint,
sourceProject: project,
});
}
} else if (isToken(node) && node === sf.endOfFileToken) {
// do nothing
} else {
hasNotOnlyExports = true;
}
});
if (hasNotOnlyExports) {
violations.push({
message: `Entry point should only contain exported APIs`,
file: entryPoint,
sourceProject: project,
});
}
return violations;
}
function isModuleSpecifierViolated(
moduleSpecifier: string,
style: 'server' | 'client'
) {
// should not get here. if this is the case, it's a grammar error in the source code.
if (!moduleSpecifier) return false;
if (style === 'server' && !moduleSpecifier.includes('.server')) {
return true;
}
if (style === 'client' && moduleSpecifier.includes('.server')) {
return true;
}
return false;
}
```
{% /tab %}
{% tab label="non-project-files-reporter" %}
This rule checks the root `package.json` file and ensures that if the `tmp` package is included as a dependency, it has a minimum version of 0.2.3.
```ts
import { readJsonFile, workspaceRoot } from '@nx/devkit';
import {
createConformanceRule,
NonProjectFilesViolation,
} from '@nx/powerpack-conformance';
import { join } from 'node:path';
import { satisfies } from 'semver';
export default createConformanceRule<object>({
name: 'package-tmp-0.2.3',
category: 'maintainability',
description: 'The tmp dependency should be a minimum version of 0.2.3',
reporter: 'non-project-files-reporter',
implementation: async () => {
const violations: NonProjectFilesViolation[] = [];
const applyViolationIfApplicable = (version: string | undefined) => {
if (version && !satisfies(version, '>=0.2.3')) {
violations.push({
message: 'The "tmp" package must be version "0.2.3" or higher',
file: 'package.json',
});
}
};
const workspaceRootPackageJson = await readJsonFile(
join(workspaceRoot, 'package.json')
);
applyViolationIfApplicable(workspaceRootPackageJson.dependencies?.['tmp']);
applyViolationIfApplicable(
workspaceRootPackageJson.devDependencies?.['tmp']
);
return {
severity: 'low',
details: {
violations,
},
};
},
});
```
{% /tab %}
{% /tabs %}
## Share Conformance Rules Across Workspaces
If you have an Enterprise Nx Cloud contract, you can share your conformance rules across every repository in your organization. Read more in these articles:
- [Publish Conformance Rules to Nx Cloud](/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud)
- [Configure Conformance Rules in Nx Cloud](/ci/recipes/enterprise/conformance/configure-conformance-rules-in-nx-cloud)
@@ -166,51 +166,10 @@ Set the `rule` property to: `@nx/powerpack-conformance/ensure-owners`
}
```
## Custom Conformance Rules
## Next Steps
To write your own conformance rule, specify a relative path to a TypeScript or JavaScript file as the rule name:
For more information about the conformance plugin, consult the following articles:
```json {% fileName="nx.json" %}
{
"conformance": {
"rules": [
{
"rule": "./tools/local-conformance-rule.ts"
}
]
}
}
```
The rule definition file should look like this:
```ts {% fileName="tools/local-conformance-rule.ts" %}
import { createConformanceRule } from '@nx/powerpack-conformance';
const rule = createConformanceRule({
name: 'local-conformance-rule-example',
description: 'The description of the rule',
category: 'security', // `consistency`, `maintainability`, `reliability` or `security`
reporter: 'project-reporter', // `project-reporter` or `project-files-reporter`
implementation: async (context) => {
const { projectGraph, ruleOptions } = context;
// Your rule logic goes here
return {
severity: 'low', // 'high', 'medium' or 'low'
details: {
violations: [
// Return an empty array if the rule passes
{
sourceProject: 'my-project',
message: 'This is an informative error message.',
},
],
},
};
},
});
export default rule;
```
Note that the severity of the error is defined by the rule author and can be adjusted based on the specific violations that are found.
- [Create a Conformance Rule](/nx-api/powerpack-conformance/documents/create-conformance-rule)
- [Publish Conformance Rules to Nx Cloud](/ci/recipes/enterprise/conformance/publish-conformance-rules-to-nx-cloud)
- [Configure Conformance Rules in Nx Cloud](/ci/recipes/enterprise/conformance/configure-conformance-rules-in-nx-cloud)
@@ -80,3 +80,29 @@ Finally, you need to configure your Nx cache in the `nx.json` file. The `bucket`
| **Property** | **Description** |
| ------------ | ----------------------------- |
| **bucket** | The name of the bucket to use |
# Cache Modes
By default, Nx will try to write and read from the remote cache while running locally. This means that permissions must be set for users who are expected to access the remote cache.
Nx will only show warnings when the remote cache is not writable. You can disable these warnings by setting `localMode` to `read-only` or `no-cache` in the `nx.json` file.
```jsonc {% fileName="nx.json" %}
{
"gcs": {
// ...
"localMode": "read-only"
}
}
```
The cache mode in CI can also be configured by setting `ciMode` to `read-only` or `no-cache` in the `nx.json` file. Or setting `NX_POWERPACK_CACHE_MODE` to `read-only` or `no-cache` in the CI environment.
```jsonc {% fileName="nx.json" %}
{
"gcs": {
// ...
"ciMode": "read-only"
}
}
```
@@ -152,3 +152,31 @@ Below is an example on how to connect to MinIO:
| **endpoint** | The custom endpoint to upload artifacts to. If endpoint is not defined, the default AWS endpoint is used |
| **accessKeyId** | AWS Access Key ID (optional if `AWS_ACCESS_KEY_ID` is set in the environment) |
| **secretAccessKey** | AWS secret access key (optional if `AWS_SECRET_ACCESS_KEY` is set in the environment) |
# Cache Modes
By default, Nx will try to write and read from the remote cache while running locally. This means that permissions must be set for users who are expected to access the remote cache.
Nx will only show warnings when the remote cache is not writable. You can disable these warnings by setting `localMode` to `read-only` or `no-cache` in the `nx.json` file.
```jsonc {% fileName="nx.json" %}
{
"s3": {
"region": "us-east-1",
"bucket": "my-bucket",
"localMode": "read-only"
}
}
```
The cache mode in CI can also be configured by setting `ciMode` to `read-only` or `no-cache` in the `nx.json` file. Or setting `NX_POWERPACK_CACHE_MODE` to `read-only` or `no-cache` in the CI environment.
```jsonc {% fileName="nx.json" %}
{
"s3": {
"region": "us-east-1",
"bucket": "my-bucket",
"ciMode": "read-only"
}
}
```
@@ -18,7 +18,7 @@ To generate only a host application in your workspace, run the following command
{% tabs %}
{% tab label="React" %}
```{% command="nx g @nx/react:host apps/shell --directory=apps/react/shell" %}
```{% command="nx g @nx/react:host apps/react/shell" %}
NX Generating @nx/react:host
CREATE apps/react/shell/src/app/app.spec.tsx
@@ -48,7 +48,7 @@ CREATE apps/react/shell/webpack.config.prod.ts
{% /tab %}
{% tab label="Angular" %}
```{% command="nx g @nx/angular:host apps/shell --directory=apps/angular/shell" %}
```{% command="nx g @nx/angular:host apps/angular/shell" %}
NX Generating @nx/angular:host
CREATE apps/angular/shell/project.json
@@ -118,7 +118,7 @@ Attempting to keep track of this manually as a part of pull request reviews can
nx release plan:check
```
Running this command will analyze the changed files (supporting the same options you may be familiar with from `nx affected`, such as `--base`, `--head`, `--files`, `--uncommitted`, etc) and then determine which projects have been "touched" as a result. Note that it is specifically touched projects, and not affected in this case, because only directly changed projects are relevant for versioning. The side-effects of versioning independently released dependents are handled by the release process itself (controllable via the `version.generatorOptions.updatedDependents` option).
Running this command will analyze the changed files (supporting the same options you may be familiar with from `nx affected`, such as `--base`, `--head`, `--files`, `--uncommitted`, etc) and then determine which projects have been "touched" as a result. Note that it is specifically touched projects, and not affected in this case, because only directly changed projects are relevant for versioning. The side-effects of versioning independently released dependents are handled by the release process itself (controllable via the `version.generatorOptions.updateDependents` option).
<!-- Prettier will mess up the end tag of the callout causing it to capture all content that follows it -->
<!-- prettier-ignore-start -->
@@ -21,7 +21,7 @@ Lets see how we can implement this solution:
According to the framework you are using, use the corresponding generator to generate a new library. Lets suppose that you are using React and all your stories are using the `@storybook/react-vite` framework:
```shell
nx g @nx/react:library lib/storybook-host --bundler=none --unitTestRunner=none
nx g @nx/react:library libs/storybook-host --bundler=none --unitTestRunner=none
```
Now, you have a new library, which will act as a shell/host for all your stories.
@@ -0,0 +1,257 @@
# Switch to Workspaces and Project References
If you want to take advantage of the [performance benefits](/concepts/typescript-project-linking#typescript-project-references-performance-benefits) of TypeScript project references, it is recommended to use package manager workspaces for local [project linking](/concepts/typescript-project-linking). If you are currently using TypeScript path aliases for project linking, follow the steps in this guide to switch to workspaces project linking and enable TypeScript project references.
## Enable Package Manager Workspaces
Follow the specific instructions for your package manager to enable workspaces project linking.
{% tabs %}
{% tab label="npm" %}
```json {% fileName="package.json" %}
{
"workspaces": ["apps/**", "libs/**"]
}
```
Defining the `workspaces` property in the root `package.json` file lets npm know to look for other `package.json` files in the specified folders. With this configuration in place, all the dependencies for the individual projects will be installed in the root `node_modules` folder when `npm install` is run in the root folder. Also, the projects themselves will be linked in the root `node_modules` folder to be accessed as if they were npm packages.
If you reference a local library project with its own `build` task, you should include the library in the `devDependencies` of the application's `package.json` with `*` specified as the library's version. `*` tells npm to use whatever version of the project is available.
```json {% fileName="/apps/my-app/package.json" %}
{
"devDependencies": {
"@my-org/some-project": "*"
}
}
```
{% /tab %}
{% tab label="yarn" %}
```json {% fileName="package.json" %}
{
"workspaces": ["apps/**", "libs/**"]
}
```
Defining the `workspaces` property in the root `package.json` file lets yarn know to look for other `package.json` files in the specified folders. With this configuration in place, all the dependencies for the individual projects will be installed in the root `node_modules` folder when `yarn` is run in the root folder. Also, the projects themselves will be linked in the root `node_modules` folder to be accessed as if they were npm packages.
If you reference a local library project with its own `build` task, you should include the library in the `devDependencies` of the application's `package.json` with `workspace:*` specified as the library's version. [`workspace:*` tells yarn that the project is in the same repository](https://yarnpkg.com/features/workspaces) and not an npm package. You want to specify local projects as `devDependencies` instead of `dependencies` so that the library is not included twice in the production bundle of the application.
```json {% fileName="/apps/my-app/package.json" %}
{
"devDependencies": {
"@my-org/some-project": "*"
}
}
```
{% /tab %}
{% tab label="bun" %}
```json {% fileName="package.json" %}
{
"workspaces": ["apps/**", "libs/**"]
}
```
Defining the `workspaces` property in the root `package.json` file lets bun know to look for other `package.json` files in the specified folders. With this configuration in place, all the dependencies for the individual projects will be installed in the root `node_modules` folder when `bun install` is run in the root folder. Also, the projects themselves will be linked in the root `node_modules` folder to be accessed as if they were npm packages.
If you reference a local library project with its own `build` task, you should include the library in the `devDependencies` of the application's `package.json` with `workspace:*` specified as the library's version. [`workspace:*` tells bun that the project is in the same repository](https://bun.sh/docs/install/workspaces) and not an npm package. You want to specify local projects as `devDependencies` instead of `dependencies` so that the library is not included twice in the production bundle of the application.
```json {% fileName="/apps/my-app/package.json" %}
{
"devDependencies": {
"@my-org/some-project": "workspace:*"
}
}
```
{% /tab %}
{% tab label="pnpm" %}
```yaml {% fileName="pnpm-workspace.yaml" %}
packages:
- 'apps/**'
- 'libs/**'
```
Defining the `packages` property in the root `pnpm-workspaces.yaml` file lets pnpm know to look for project `package.json` files in the specified folders. With this configuration in place, all the dependencies for the individual projects will be installed in the root `node_modules` folder when `pnpm install` is run in the root folder.
If you reference a local library project from an application, you need to include the library in the `devDependencies` of the application's `package.json` with `workspace:*` specified as the library's version. [`workspace:*` tells pnpm that the project is in the same repository](https://pnpm.io/workspaces#workspace-protocol-workspace) and not an npm package. You want to specify local projects as `devDependencies` instead of `dependencies` so that the library is not included twice in the production bundle of the application.
```json {% fileName="/apps/my-app/package.json" %}
{
"devDependencies": {
"@my-org/some-project": "workspace:*"
}
}
```
{% /tab %}
{% /tabs %}
## Update Root TypeScript Configuration
The root `tsconfig.base.json` should contain a `compilerOptions` property and no other properties. `compilerOptions.composite` and `compilerOptions.declaration` should be set to `true`. `compilerOptions.paths` and `compilerOptions.rootDir` should not be set.
Note: Before you delete the `paths` property, copy the project paths for use as `references` in the `tsconfig.json` file.
{% tabs %}
{% tab label="Before" %}
```jsonc {% fileName="tsconfig.base.json" %}
{
"compilerOptions": {
"allowJs": false,
"allowSyntheticDefaultImports": true,
// ...
"paths": {
"@myorg/utils": ["libs/utils/src/index.ts"],
"@myorg/ui": ["libs/ui/src/index.ts"]
}
}
}
```
{% /tab %}
{% tab label="After" %}
```jsonc {% fileName="tsconfig.base.json" %}
{
"compilerOptions": {
// Required compiler options
"composite": true,
"declaration": true, // defaults to true when composite is true
// Delete the paths property
// Other options...
"allowJs": false,
"allowSyntheticDefaultImports": true
}
}
```
{% /tab %}
{% /tabs %}
The root `tsconfig.json` file should extend `tsconfig.base.json` and not include any files. It needs to have `references` for every project in the repository so that editor tooling works correctly.
{% tabs %}
{% tab label="Before" %}
```jsonc {% fileName="tsconfig.json" %}
{
"extends": "./tsconfig.base.json",
"files": [] // intentionally empty
}
```
{% /tab %}
{% tab label="After" %}
```jsonc {% fileName="tsconfig.json" %}
{
"extends": "./tsconfig.base.json",
"files": [], // intentionally empty
"references": [
// All projects in the repository
{
"path": "./libs/utils"
},
{
"path": "./libs/ui"
}
// Future generated projects will automatically be added here by the generator
]
}
```
{% /tab %}
{% /tabs %}
## Create Individual Project package.json files
When using package manager project linking, every project needs to have a `package.json` file. You can leave all the task configuration in the existing `project.json` file. For application projects, you only need to specify the `name` property. For library projects, you should add an `exports` property that accounts for any TypeScript path aliases that referenced the project. A typical configuration is shown below:
```json {% fileName="libs/ui/package.json" %}
{
"name": "@myorg/ui",
"exports": {
".": "./src/index.js"
}
}
```
{% callout type="warning" title="Package Names with Multiple Slashes" %}
The `package.json` name can only have one `/` character in it. This is more restrictive than the TypeScript path aliases. So if you have a project that you have been referencing with `@myorg/shared/ui`, you'll need to make the `package.json` name be something like `@myorg/shared-ui` and update all the import statements in your codebase to reference the new name.
{% /callout %}
## Update Individual Project TypeScript Configuration
Each project's `tsconfig.json` file should extend the `tsconfig.base.json` file and list `references` to the project's dependencies.
```jsonc {% fileName="libs/ui/tsconfig.json" %}
{
"extends": "../../tsconfig.base.json",
"files": [], // intentionally empty
"references": [
// All project dependencies
// UPDATED BY NX SYNC
// This project's other tsconfig.*.json files
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}
```
Each project's `tsconfig.lib.json` file extends the project's `tsconfig.json` file and adds `references` to the `tsconfig.lib.json` files of project dependencies.
```jsonc {% fileName="libs/ui/tsconfig.lib.json" %}
{
"extends": "./tsconfig.json",
"compilerOptions": {
// Any overrides
},
"include": ["src/**/*.ts"],
"exclude": [
// exclude config and test files
],
"references": [
// tsconfig.lib.json files for project dependencies
// UPDATED BY NX SYNC
]
}
```
The project's `tsconfig.spec.json` does not need to reference project dependencies.
```jsonc {% fileName="libs/ui/tsconfig.spec.json" %}
{
"extends": "./tsconfig.json",
"compilerOptions": {
// Any overrides
},
"include": [
// test files
],
"references": [
// tsconfig.lib.json for this project
{
"path": "./tsconfig.lib.json"
}
]
}
```
After creating these `tsconfig.*.json` files, run `nx sync` to have Nx automatically add the correct references for each project.
## Future Plans
We realize that this manual migration process is tedious. We are investigating automating parts of this process with generators.
@@ -17,7 +17,10 @@ The following environment variables are ones that you can set to change the beha
| NX_WORKSPACE_DATA_DIRECTORY | string | The project graph cache and some other internal nx caches are stored in `.nx/workspace-data` by default. Set this variable to use a different directory. |
| NX_PARALLEL | number | The number of tasks Nx should run in parallel. Overrides any configured value inside nx.json |
| NX_RUNNER | string | The name of task runner from the config to use. Can be overridden on the command line with `--runner`. Not read if `NX_TASKS_RUNNER` is set. |
| NX_SKIP_NX_CACHE | boolean | Rerun the tasks even when the results are available in the cache |
| NX_SKIP_NX_CACHE | boolean | Rerun the tasks even when the results are available in the cache. |
| NX_DISABLE_NX_CACHE | boolean | Rerun the tasks even when the results are available in the cache. |
| NX_SKIP_REMOTE_CACHE | boolean | Disable all remote caching features. This means that the remote cache will not be read from or written to. Includes Nx Cloud and Powerpack Caches. |
| NX_DISABLE_REMOTE_CACHE | boolean | Disable all remote caching features. This means that the remote cache will not be read from or written to. Includes Nx Cloud and Powerpack Caches. |
| NX_TASKS_RUNNER | string | The name of task runner from the config to use. Can be overridden on the command line with `--runner`. Preferred over `NX_RUNNER`. |
| NX_TASKS_RUNNER_DYNAMIC_OUTPUT | boolean | If set to `false`, will use non-dynamic terminal output strategy (what you see in CI), even when you terminal can support the dynamic version |
| NX_VERBOSE_LOGGING | boolean | If set to `true`, will print debug information useful for troubleshooting |
@@ -1,3 +1,7 @@
---
keywords: [project.json]
---
# Project Configuration
A project's configuration is constructed by Nx from three sources:
+5 -3
View File
@@ -33,6 +33,7 @@
- [Common Tasks](/concepts/common-tasks)
- [Nx Daemon](/concepts/nx-daemon)
- [Sync Generators](/concepts/sync-generators)
- [TypeScript Project Linking](/concepts/typescript-project-linking)
- [Nx and Turborepo](/concepts/turbo-and-nx)
- [Buildable and Publishable Libraries](/concepts/buildable-and-publishable-libraries)
- [Module Federation](/concepts/module-federation)
@@ -158,6 +159,7 @@
- [Tips and tricks](/recipes/tips-n-tricks)
- [Convert from a Standalone Repository to a Monorepo](/recipes/tips-n-tricks/standalone-to-monorepo)
- [Configuring ESLint with Typescript](/recipes/tips-n-tricks/eslint)
- [Switch to Workspaces and TS Project References](/recipes/tips-n-tricks/switch-to-workspaces-project-references)
- [Enable Typescript Batch Mode](/recipes/tips-n-tricks/enable-tsc-batch-mode)
- [Define Secondary Entrypoints for Typescript Packages](/recipes/tips-n-tricks/define-secondary-entrypoints)
- [Compile Typescript Packages to Multiple Formats](/recipes/tips-n-tricks/compile-multiple-formats)
@@ -482,7 +484,6 @@
- [js](/nx-api/js)
- [documents](/nx-api/js/documents)
- [Overview](/nx-api/js/documents/overview)
- [Configure TypeScript Project References in an Nx Workspace](/nx-api/js/documents/typescript-project-references)
- [executors](/nx-api/js/executors)
- [tsc](/nx-api/js/executors/tsc)
- [swc](/nx-api/js/executors/swc)
@@ -793,8 +794,11 @@
- [powerpack-conformance](/nx-api/powerpack-conformance)
- [documents](/nx-api/powerpack-conformance/documents)
- [Overview](/nx-api/powerpack-conformance/documents/overview)
- [Create a Conformance Rule](/nx-api/powerpack-conformance/documents/create-conformance-rule)
- [executors](/nx-api/powerpack-conformance/executors)
- [bundle-rules](/nx-api/powerpack-conformance/executors/bundle-rules)
- [generators](/nx-api/powerpack-conformance/generators)
- [create-rule](/nx-api/powerpack-conformance/generators/create-rule)
- [powerpack-enterprise-cloud](/nx-api/powerpack-enterprise-cloud)
- [generators](/nx-api/powerpack-enterprise-cloud/generators)
- [init](/nx-api/powerpack-enterprise-cloud/generators/init)
@@ -811,8 +815,6 @@
- [powerpack-s3-cache](/nx-api/powerpack-s3-cache)
- [documents](/nx-api/powerpack-s3-cache/documents)
- [Overview](/nx-api/powerpack-s3-cache/documents/overview)
- [generators](/nx-api/powerpack-s3-cache/generators)
- [init](/nx-api/powerpack-s3-cache/generators/init)
- [powerpack-shared-fs-cache](/nx-api/powerpack-shared-fs-cache)
- [documents](/nx-api/powerpack-shared-fs-cache/documents)
- [Overview](/nx-api/powerpack-shared-fs-cache/documents/overview)
+25 -3
View File
@@ -153,10 +153,32 @@ function runNgNew(projectName: string, cwd: string): void {
const pmc = getPackageManagerCommand({ packageManager });
const command = `${pmc.runUninstalledPackage} @angular/cli@${angularCliVersion} new ${projectName} --package-manager=${packageManager}`;
cwd = join(tmpProjPath(), cwd);
ensureDirSync(cwd);
const fullCwd = join(tmpProjPath(), cwd);
ensureDirSync(fullCwd);
execSync(command, {
cwd,
cwd: fullCwd,
stdio: isVerbose() ? 'inherit' : 'pipe',
env: process.env,
encoding: 'utf-8',
});
// ensure angular packages are installed with ~ instead of ^ to prevent
// potential failures when new minor versions are released
function updateAngularDependencies(dependencies: any): void {
Object.keys(dependencies).forEach((key) => {
if (key.startsWith('@angular/') || key.startsWith('@angular-devkit/')) {
dependencies[key] = dependencies[key].replace(/^\^/, '~');
}
});
}
updateJson(join(cwd, projectName, 'package.json'), (json) => {
updateAngularDependencies(json.dependencies ?? {});
updateAngularDependencies(json.devDependencies ?? {});
return json;
});
execSync(pmc.install, {
cwd: join(fullCwd, projectName),
stdio: isVerbose() ? 'inherit' : 'pipe',
env: process.env,
encoding: 'utf-8',
+15 -6
View File
@@ -174,10 +174,13 @@ describe('Tailwind support', () => {
const assertLibComponentStyles = (
lib: string,
libSpacing: (typeof spacing)['root']
libSpacing: (typeof spacing)['root'],
isPublishable: boolean = true
) => {
const builtComponentContent = readFile(
`dist/${lib}/fesm2022/${project}-${lib}.mjs`
isPublishable
? `dist/${lib}/fesm2022/${project}-${lib}.mjs`
: `dist/${lib}/esm2022/lib/foo.component.mjs`
);
let expectedStylesRegex = new RegExp(
`styles: \\[\\"\\.custom\\-btn(\\[_ngcontent\\-%COMP%\\])?{margin:${libSpacing.md};padding:${libSpacing.sm}}(\\\\n)?\\"\\]`
@@ -203,7 +206,8 @@ describe('Tailwind support', () => {
assertLibComponentStyles(
buildLibWithTailwind.name,
spacing.projectVariant1
spacing.projectVariant1,
false
);
});
@@ -223,7 +227,11 @@ describe('Tailwind support', () => {
runCLI(`build ${buildLibSetupTailwind}`);
assertLibComponentStyles(buildLibSetupTailwind, spacing.projectVariant2);
assertLibComponentStyles(
buildLibSetupTailwind,
spacing.projectVariant2,
false
);
});
it('should correctly build a buildable library with a tailwind.config.js file in the project root or workspace root', () => {
@@ -241,7 +249,8 @@ describe('Tailwind support', () => {
assertLibComponentStyles(
buildLibNoProjectConfig,
spacing.projectVariant3
spacing.projectVariant3,
false
);
// remove tailwind.config.js file from the project root to test the one in the workspace root
@@ -249,7 +258,7 @@ describe('Tailwind support', () => {
runCLI(`build ${buildLibNoProjectConfig}`);
assertLibComponentStyles(buildLibNoProjectConfig, spacing.root);
assertLibComponentStyles(buildLibNoProjectConfig, spacing.root, false);
});
it('should generate a publishable library with tailwind and build correctly', () => {
+1 -1
View File
@@ -48,7 +48,7 @@ describe('EsBuild Plugin', () => {
private: true,
type: 'commonjs',
main: './index.cjs',
typings: './index.d.ts',
types: './index.d.ts',
dependencies: {},
});
+1 -1
View File
@@ -567,7 +567,7 @@ describe('Linter', () => {
name: `@proj/${mylib}`,
private: true,
type: 'commonjs',
typings: './src/index.d.ts',
types: './src/index.d.ts',
version: '0.0.1',
});
+183
View File
@@ -0,0 +1,183 @@
import {
cleanupProject,
getPackageManagerCommand,
getSelectedPackageManager,
newProject,
runCLI,
runCommand,
uniq,
updateFile,
updateJson,
} from '@nx/e2e/utils';
describe('JS - TS solution setup', () => {
beforeAll(() => {
newProject({
packages: ['@nx/js'],
preset: 'ts',
});
});
afterAll(() => {
cleanupProject();
});
it('should generate libraries with different bundlers and link them successfully', () => {
const esbuildParentLib = uniq('esbuild-parent-lib');
const esbuildChildLib = uniq('esbuild-child-lib');
const rollupParentLib = uniq('rollup-parent-lib');
const rollupChildLib = uniq('rollup-child-lib');
const swcParentLib = uniq('swc-parent-lib');
const swcChildLib = uniq('swc-child-lib');
const tscParentLib = uniq('tsc-parent-lib');
const tscChildLib = uniq('tsc-child-lib');
const viteParentLib = uniq('vite-parent-lib');
const viteChildLib = uniq('vite-child-lib');
runCLI(
`generate @nx/js:lib packages/${esbuildParentLib} --bundler=esbuild --linter=eslint --unitTestRunner=jest`
);
runCLI(
`generate @nx/js:lib packages/${esbuildChildLib} --bundler=esbuild --linter=eslint --unitTestRunner=jest`
);
runCLI(
`generate @nx/js:lib packages/${rollupParentLib} --bundler=rollup --linter=eslint --unitTestRunner=jest`
);
runCLI(
`generate @nx/js:lib packages/${rollupChildLib} --bundler=rollup --linter=eslint --unitTestRunner=jest`
);
runCLI(
`generate @nx/js:lib packages/${swcParentLib} --bundler=swc --linter=eslint --unitTestRunner=jest`
);
runCLI(
`generate @nx/js:lib packages/${swcChildLib} --bundler=swc --linter=eslint --unitTestRunner=jest`
);
runCLI(
`generate @nx/js:lib packages/${tscParentLib} --bundler=tsc --linter=eslint --unitTestRunner=jest`
);
runCLI(
`generate @nx/js:lib packages/${tscChildLib} --bundler=tsc --linter=eslint --unitTestRunner=jest`
);
runCLI(
`generate @nx/js:lib packages/${viteParentLib} --bundler=vite --linter=eslint --unitTestRunner=jest`
);
runCLI(
`generate @nx/js:lib packages/${viteChildLib} --bundler=vite --linter=eslint --unitTestRunner=jest`
);
// add deps, each parent lib imports all child libs
const addImports = (parentLib: string) => {
updateFile(
`packages/${parentLib}/src/index.ts`,
(content) => `export * from '@proj/${esbuildChildLib}';
export * from '@proj/${rollupChildLib}';
export * from '@proj/${swcChildLib}';
export * from '@proj/${tscChildLib}';
export * from '@proj/${viteChildLib}';
${content}`
);
};
addImports(esbuildParentLib);
addImports(rollupParentLib);
addImports(swcParentLib);
addImports(tscParentLib);
addImports(viteParentLib);
const pm = getSelectedPackageManager();
if (pm === 'pnpm') {
// for pnpm we need to add the local packages as dependencies to each consumer package.json
const addDeps = (parentLib: string) => {
updateJson(`packages/${parentLib}/package.json`, (json) => {
json.dependencies ??= {};
json.dependencies[`@proj/${esbuildChildLib}`] = 'workspace:*';
json.dependencies[`@proj/${rollupChildLib}`] = 'workspace:*';
json.dependencies[`@proj/${swcChildLib}`] = 'workspace:*';
json.dependencies[`@proj/${tscChildLib}`] = 'workspace:*';
json.dependencies[`@proj/${viteChildLib}`] = 'workspace:*';
return json;
});
};
addDeps(esbuildParentLib);
addDeps(rollupParentLib);
addDeps(swcParentLib);
addDeps(tscParentLib);
addDeps(viteParentLib);
const pmc = getPackageManagerCommand({ packageManager: pm });
runCommand(pmc.install);
}
// sync to ensure the TS project references are updated
runCLI(`sync`);
// check build
expect(runCLI(`build ${esbuildParentLib}`)).toContain(
`Successfully ran target build for project ${esbuildParentLib} and 5 tasks it depends on`
);
expect(runCLI(`build ${rollupParentLib}`)).toContain(
`Successfully ran target build for project ${rollupParentLib} and 5 tasks it depends on`
);
expect(runCLI(`build ${swcParentLib}`)).toContain(
`Successfully ran target build for project ${swcParentLib} and 5 tasks it depends on`
);
expect(runCLI(`build ${tscParentLib}`)).toContain(
`Successfully ran target build for project ${tscParentLib} and 5 tasks it depends on`
);
expect(runCLI(`build ${viteParentLib}`)).toContain(
`Successfully ran target build for project ${viteParentLib} and 5 tasks it depends on`
);
// check typecheck
expect(runCLI(`typecheck ${esbuildParentLib}`)).toContain(
`Successfully ran target typecheck for project ${esbuildParentLib} and 5 tasks it depends on`
);
expect(runCLI(`typecheck ${rollupParentLib}`)).toContain(
`Successfully ran target typecheck for project ${rollupParentLib} and 5 tasks it depends on`
);
expect(runCLI(`typecheck ${swcParentLib}`)).toContain(
`Successfully ran target typecheck for project ${swcParentLib} and 5 tasks it depends on`
);
expect(runCLI(`typecheck ${tscParentLib}`)).toContain(
`Successfully ran target typecheck for project ${tscParentLib} and 5 tasks it depends on`
);
expect(runCLI(`typecheck ${viteParentLib}`)).toContain(
`Successfully ran target typecheck for project ${viteParentLib} and 5 tasks it depends on`
);
// check lint
expect(runCLI(`lint ${esbuildParentLib}`)).toContain(
`Successfully ran target lint for project ${esbuildParentLib}`
);
expect(runCLI(`lint ${rollupParentLib}`)).toContain(
`Successfully ran target lint for project ${rollupParentLib}`
);
expect(runCLI(`lint ${swcParentLib}`)).toContain(
`Successfully ran target lint for project ${swcParentLib}`
);
expect(runCLI(`lint ${tscParentLib}`)).toContain(
`Successfully ran target lint for project ${tscParentLib}`
);
expect(runCLI(`lint ${viteParentLib}`)).toContain(
`Successfully ran target lint for project ${viteParentLib}`
);
// check test
expect(runCLI(`test ${esbuildParentLib}`)).toContain(
`Successfully ran target test for project ${esbuildParentLib}`
);
expect(runCLI(`test ${rollupParentLib}`)).toContain(
`Successfully ran target test for project ${rollupParentLib}`
);
expect(runCLI(`test ${swcParentLib}`)).toContain(
`Successfully ran target test for project ${swcParentLib}`
);
expect(runCLI(`test ${tscParentLib}`)).toContain(
`Successfully ran target test for project ${tscParentLib}`
);
expect(runCLI(`test ${viteParentLib}`)).toContain(
`Successfully ran target test for project ${viteParentLib}`
);
}, 300_000);
});
+41 -15
View File
@@ -28,21 +28,6 @@ describe('Node Applications', () => {
packages: ['@nx/node', '@nx/express', '@nx/nest', '@nx/webpack'],
preset: 'ts',
});
if (pm === 'pnpm') {
updateFile(
'pnpm-workspace.yaml',
`
packages:
- 'apps/**'
- 'packages/**'
`
);
} else {
updateJson('package.json', (json) => {
json.workspaces = ['apps/**', 'packages/**'];
return json;
});
}
});
afterAll(() => {
@@ -116,9 +101,11 @@ packages:
expect(() => runCLI(`lint ${nodeapp}`)).not.toThrow();
expect(() => runCLI(`test ${nodeapp}`)).not.toThrow();
expect(() => runCLI(`build ${nodeapp}`)).not.toThrow();
expect(() => runCLI(`typecheck ${nodeapp}`)).not.toThrow();
expect(() => runCLI(`lint ${nodelib}`)).not.toThrow();
expect(() => runCLI(`test ${nodelib}`)).not.toThrow();
expect(() => runCLI(`build ${nodelib}`)).not.toThrow();
expect(() => runCLI(`typecheck ${nodelib}`)).not.toThrow();
const p = await runCommandUntil(
`serve ${nodeapp}`,
@@ -144,6 +131,45 @@ packages:
expect(err).toBeFalsy();
}
}, 300_000);
it('should be able to generate a nest application', async () => {
const nestapp = uniq('nodeapp');
const port = getRandomPort();
process.env.PORT = `${port}`;
runCLI(
`generate @nx/nest:app apps/${nestapp} --linter=eslint --unitTestRunner=jest`
);
expect(() => runCLI(`lint ${nestapp}`)).not.toThrow();
expect(() => runCLI(`test ${nestapp}`)).not.toThrow();
runCLI(`build ${nestapp}`);
checkFilesExist(`dist/apps/${nestapp}/main.js`);
const p = await runCommandUntil(
`serve ${nestapp}`,
(output) =>
output.includes(
`Application is running on: http://localhost:${port}/api`
),
{
env: {
NX_DAEMON: 'true',
},
}
);
const result = await getData(port, '/api');
expect(result.message).toMatch('Hello');
try {
await promisifiedTreeKill(p.pid, 'SIGKILL');
expect(await killPorts(port)).toBeTruthy();
} catch (err) {
expect(err).toBeFalsy();
}
}, 300_000);
});
function getRandomPort() {
+14 -6
View File
@@ -31,8 +31,8 @@ describe('Nx Affected and Graph Tests', () => {
const mylib = uniq('mylib');
const mylib2 = uniq('mylib2');
const mypublishablelib = uniq('mypublishablelib');
runCLI(`generate @nx/web:app apps/${myapp}`);
runCLI(`generate @nx/web:app apps/${myapp2}`);
runCLI(`generate @nx/web:app apps/${myapp} --unitTestRunner=vitest`);
runCLI(`generate @nx/web:app apps/${myapp2} --unitTestRunner=vitest`);
runCLI(`generate @nx/js:lib libs/${mylib}`);
runCLI(`generate @nx/js:lib libs/${mylib2}`);
runCLI(
@@ -193,8 +193,12 @@ describe('Nx Affected and Graph Tests', () => {
});
function generateAll() {
runCLI(`generate @nx/web:app apps/${myapp}`);
runCLI(`generate @nx/web:app apps/${myapp2}`);
runCLI(
`generate @nx/web:app apps/${myapp} --bundler=webpack --unitTestRunner=vitest`
);
runCLI(
`generate @nx/web:app apps/${myapp2} --bundler=webpack --unitTestRunner=vitest`
);
runCLI(`generate @nx/js:lib libs/${mylib}`);
runCommand(`git add . && git commit -am "add all"`);
}
@@ -536,8 +540,12 @@ describe('show projects --affected', () => {
const mylib2 = uniq('mylib2');
const mypublishablelib = uniq('mypublishablelib');
runCLI(`generate @nx/web:app ${myapp} --directory=apps/${myapp}`);
runCLI(`generate @nx/web:app ${myapp2} --directory=apps/${myapp2}`);
runCLI(
`generate @nx/web:app ${myapp} --directory=apps/${myapp} --unitTestRunner=vitest`
);
runCLI(
`generate @nx/web:app ${myapp2} --directory=apps/${myapp2} --unitTestRunner=vitest`
);
runCLI(`generate @nx/js:lib ${mylib} --directory=libs/${mylib}`);
runCLI(`generate @nx/js:lib ${mylib2} --directory=libs/${mylib2}`);
runCLI(
+4 -2
View File
@@ -68,9 +68,11 @@ describe('Nx Commands', () => {
it('should show detailed project info', () => {
const app = uniq('myapp');
runCLI(`generate @nx/web:app apps/${app}`);
runCLI(
`generate @nx/web:app apps/${app} --bundler=webpack --unitTestRunner=vitest --linter=eslint`
);
const project: ProjectConfiguration = JSON.parse(
runCLI(`show project ${app}`)
runCLI(`show project ${app} --json`)
);
expect(project.targets.build).toBeDefined();
expect(project.targets.lint).toBeDefined();
+6 -2
View File
@@ -695,8 +695,12 @@ describe('Nx Running Tests', () => {
it('should run multiple targets', () => {
const myapp1 = uniq('myapp');
const myapp2 = uniq('myapp');
runCLI(`generate @nx/web:app ${myapp1} --directory=apps/${myapp1}`);
runCLI(`generate @nx/web:app ${myapp2} --directory=apps/${myapp2}`);
runCLI(
`generate @nx/web:app ${myapp1} --directory=apps/${myapp1} --unitTestRunner=vitest`
);
runCLI(
`generate @nx/web:app ${myapp2} --directory=apps/${myapp2} --unitTestRunner=vitest`
);
let outputs = runCLI(
// Options with lists can be specified using multiple args or with a delimiter (comma or space).
@@ -23,6 +23,62 @@ describe('Nx Plugin (TS solution)', () => {
afterAll(() => cleanupProject());
it('should be able to generate a Nx Plugin with generators, executors and migrations', async () => {
const plugin = uniq('plugin');
const generator = uniq('generator');
const executor = uniq('executor');
const migrationVersion = '1.0.0';
runCLI(
`generate @nx/plugin:plugin packages/${plugin} --linter=eslint --unitTestRunner=jest --e2eTestRunner=jest --publishable`
);
runCLI(
`generate @nx/plugin:generator packages/${plugin}/src/generators/${generator}/generator --name ${generator}`
);
runCLI(
`generate @nx/plugin:executor packages/${plugin}/src/executors/${executor}/executor --name ${executor} --includeHasher`
);
runCLI(
`generate @nx/plugin:migration packages/${plugin}/src/migrations/update-${migrationVersion}/update-${migrationVersion} --packageVersion=${migrationVersion} --packageJsonUpdates=false`
);
expect(runCLI(`lint ${plugin}`)).toContain(
`Successfully ran target lint for project ${plugin}`
);
expect(runCLI(`typecheck ${plugin}`)).toContain(
`Successfully ran target typecheck for project ${plugin}`
);
expect(runCLI(`build ${plugin}`)).toContain(
`Successfully ran target build for project ${plugin}`
);
checkFilesExist(
// entry point
`packages/${plugin}/dist/index.js`,
`packages/${plugin}/dist/index.d.ts`,
// generator
`packages/${plugin}/dist/generators/${generator}/schema.json`,
`packages/${plugin}/dist/generators/${generator}/schema.d.ts`,
`packages/${plugin}/dist/generators/${generator}/generator.js`,
`packages/${plugin}/dist/generators/${generator}/generator.d.ts`,
// executor
`packages/${plugin}/dist/executors/${executor}/schema.json`,
`packages/${plugin}/dist/executors/${executor}/schema.d.ts`,
`packages/${plugin}/dist/executors/${executor}/executor.js`,
`packages/${plugin}/dist/executors/${executor}/executor.d.ts`,
`packages/${plugin}/dist/executors/${executor}/hasher.js`,
`packages/${plugin}/dist/executors/${executor}/hasher.d.ts`,
// migration
`packages/${plugin}/dist/migrations/update-${migrationVersion}/update-${migrationVersion}.js`,
`packages/${plugin}/dist/migrations/update-${migrationVersion}/update-${migrationVersion}.d.ts`
);
expect(runCLI(`test ${plugin}`)).toContain(
`Successfully ran target test for project ${plugin}`
);
expect(runCLI(`e2e ${plugin}-e2e`)).toContain(
`Successfully ran target e2e for project ${plugin}-e2e`
);
}, 90000);
it('should be able to infer projects and targets', async () => {
const plugin = uniq('plugin');
runCLI(`generate @nx/plugin:plugin packages/${plugin}`);
+23
View File
@@ -486,6 +486,29 @@ export function runNgNew(
env: process.env,
encoding: 'utf-8',
});
// ensure angular packages are installed with ~ instead of ^ to prevent
// potential failures when new minor versions are released
function updateAngularDependencies(dependencies: any): void {
Object.keys(dependencies).forEach((key) => {
if (key.startsWith('@angular/') || key.startsWith('@angular-devkit/')) {
dependencies[key] = dependencies[key].replace(/^\^/, '~');
}
});
}
updateJson('package.json', (json) => {
updateAngularDependencies(json.dependencies ?? {});
updateAngularDependencies(json.devDependencies ?? {});
return json;
});
execSync(pmc.install, {
cwd: join(e2eCwd, projName),
stdio: isVerbose() ? 'inherit' : 'pipe',
env: process.env,
encoding: 'utf-8',
});
copySync(tmpProjPath(), tmpBackupNgCliProjPath());
if (isVerboseE2ERun()) {
+98
View File
@@ -0,0 +1,98 @@
import { names } from '@nx/devkit';
import {
cleanupProject,
getPackageManagerCommand,
getSelectedPackageManager,
newProject,
runCLI,
runCommand,
uniq,
updateFile,
updateJson,
} from '@nx/e2e/utils';
describe('Vite - TS solution setup', () => {
beforeAll(() => {
newProject({
packages: ['@nx/react', '@nx/js'],
preset: 'ts',
});
});
afterAll(() => {
cleanupProject();
});
it('should generate app and consume libraries with different bundlers', () => {
const reactApp = uniq('react-app');
const esbuildLib = uniq('esbuild-lib');
const rollupLib = uniq('rollup-lib');
const swcLib = uniq('swc-lib');
const tscLib = uniq('tsc-lib');
const viteLib = uniq('vite-lib');
const noBundlerLib = uniq('no-bundler-lib');
runCLI(`generate @nx/react:app apps/${reactApp} --bundler=vite`);
runCLI(`generate @nx/js:lib packages/${esbuildLib} --bundler=esbuild`);
runCLI(`generate @nx/js:lib packages/${rollupLib} --bundler=rollup`);
runCLI(`generate @nx/js:lib packages/${swcLib} --bundler=swc`);
runCLI(`generate @nx/js:lib packages/${tscLib} --bundler=tsc`);
runCLI(`generate @nx/js:lib packages/${viteLib} --bundler=vite`);
runCLI(`generate @nx/js:lib packages/${noBundlerLib} --bundler=none`);
// import all libs from the app
updateFile(
`apps/${reactApp}/src/app/app.tsx`,
(content) => `import { ${
names(esbuildLib).propertyName
} } from '@proj/${esbuildLib}';
import { ${names(rollupLib).propertyName} } from '@proj/${rollupLib}';
import { ${names(swcLib).propertyName} } from '@proj/${swcLib}';
import { ${names(tscLib).propertyName} } from '@proj/${tscLib}';
import { ${names(viteLib).propertyName} } from '@proj/${viteLib}';
import { ${names(noBundlerLib).propertyName} } from '@proj/${noBundlerLib}';
console.log(
${names(esbuildLib).propertyName}(),
${names(rollupLib).propertyName}(),
${names(swcLib).propertyName}(),
${names(tscLib).propertyName}(),
${names(viteLib).propertyName}(),
${names(noBundlerLib).propertyName}()
);
${content}`
);
const pm = getSelectedPackageManager();
if (pm === 'pnpm') {
// for pnpm we need to add the local packages as dependencies to each consumer package.json
updateJson(`apps/${reactApp}/package.json`, (json) => {
json.dependencies ??= {};
json.dependencies[`@proj/${esbuildLib}`] = 'workspace:*';
json.dependencies[`@proj/${rollupLib}`] = 'workspace:*';
json.dependencies[`@proj/${swcLib}`] = 'workspace:*';
json.dependencies[`@proj/${tscLib}`] = 'workspace:*';
json.dependencies[`@proj/${viteLib}`] = 'workspace:*';
json.dependencies[`@proj/${noBundlerLib}`] = 'workspace:*';
return json;
});
const pmc = getPackageManagerCommand({ packageManager: pm });
runCommand(pmc.install);
}
// sync to ensure the TS project references are updated
runCLI(`sync`);
// check build
expect(runCLI(`build ${reactApp}`)).toContain(
`Successfully ran target build for project ${reactApp} and 5 tasks it depends on`
);
// check typecheck
expect(runCLI(`typecheck ${reactApp}`)).toContain(
`Successfully ran target typecheck for project ${reactApp} and 6 tasks it depends on`
);
}, 300_000);
});
+41
View File
@@ -206,6 +206,47 @@ describe('@nx/vite/plugin', () => {
expect(() => runCLI(`test ${mylib}`)).not.toThrow();
});
it('should not partially match a path mapping', () => {
const lib1 = uniq('lib1');
const lib2 = uniq('lib2');
const lib3 = uniq('lib3');
runCLI(
`generate @nx/react:library libs/${lib1} --bundler=none --unitTestRunner=vitest`
);
runCLI(
`generate @nx/react:library libs/${lib2} --bundler=none --unitTestRunner=vitest`
);
runCLI(
`generate @nx/react:library libs/${lib3} --bundler=none --unitTestRunner=vitest`
);
updateFile(`libs/${lib1}/src/foo.enum.ts`, `export const foo = 'foo';`);
updateFile(`libs/${lib2}/src/bar.enum.ts`, `export const bar = 'bar';`);
updateFile(`libs/${lib3}/src/bam.enum.ts`, `export const bam = 'bam';`);
updateFile(
`libs/${lib1}/src/foo.spec.ts`,
`
import { foo } from 'match-lib-deep/foo.enum';
import { bar } from 'match-lib-top-level';
import { bam } from 'match-lib/bam.enum';
test('should work', () => {
expect(foo).toBeDefined();
expect(bar).toBeDefined();
expect(bam).toBeDefined();
});
`
);
updateJson('tsconfig.base.json', (json) => {
json.compilerOptions.paths['match-lib-deep/*'] = [`libs/${lib1}/src/*`];
json.compilerOptions.paths['match-lib-top-level'] = [
`libs/${lib2}/src/bar.enum.ts`,
];
json.compilerOptions.paths['match-lib/*'] = [`libs/${lib3}/src/*`];
return json;
});
expect(() => runCLI(`test ${lib1}`)).not.toThrow();
});
});
describe('react with vitest only', () => {
-15
View File
@@ -18,21 +18,6 @@ describe('Vue Plugin', () => {
packages: ['@nx/vue'],
preset: 'ts',
});
if (pm === 'pnpm') {
updateFile(
'pnpm-workspace.yaml',
`
packages:
- 'apps/**'
- 'packages/**'
`
);
} else {
updateJson('package.json', (json) => {
json.workspaces = ['apps/**', 'packages/**'];
return json;
});
}
});
afterAll(() => cleanupProject());
@@ -85,6 +85,9 @@ exports[`Webpack Plugin (legacy) ConvertConfigToWebpackPlugin, should convert wi
}
}
},
"lint": {
"executor": "@nx/eslint:lint"
},
"test": {
"executor": "@nx/vite:test",
"outputs": ["{options.reportsDirectory}"],
@@ -92,9 +95,6 @@ exports[`Webpack Plugin (legacy) ConvertConfigToWebpackPlugin, should convert wi
"reportsDirectory": "../coverage/app3224373"
}
},
"lint": {
"executor": "@nx/eslint:lint"
},
"serve-static": {
"executor": "@nx/web:file-server",
"dependsOn": ["build"],
@@ -31,10 +31,7 @@ export function TargetExecutorTitle({
<span className="font-medium">
Command
<span className="mb-1 ml-2 hidden group-hover:inline">
<CopyToClipboardButton
text={`"command": "${command}"`}
tooltipText="Copy Command"
/>
<CopyToClipboardButton text={command} tooltipText="Copy Command" />
</span>
</span>
);
@@ -96,6 +96,16 @@ export function DocViewer({
siteName: 'Nx',
type: 'website',
}}
additionalMetaTags={
metadata.keywords
? [
{
name: 'keywords',
content: metadata.keywords,
},
]
: []
}
/>
<div className="mx-auto w-full grow items-stretch px-4 sm:px-6 lg:px-8 2xl:max-w-6xl">
+9 -10
View File
@@ -1,21 +1,20 @@
import {
Hero,
TrustedBy,
FasterAndCheaper,
UnderstandWorkspace,
EnhancedWithAi,
AutomatedAgentsManagement,
AgentNumberOverTime,
AutomatedAgentsManagement,
EnhancedWithAi,
FasterAndCheaper,
Hero,
Statistics,
TrustedBy,
UnderstandWorkspace,
} from '@nx/nx-dev/ui-cloud';
import {
ButtonLinkProps,
CallToAction,
DefaultLayout,
} from '@nx/nx-dev/ui-common';
import type { Metadata } from 'next';
import { ReactElement } from 'react';
export const metadata: Metadata = {
title: 'Nx Cloud',
@@ -40,10 +39,10 @@ export const metadata: Metadata = {
},
};
export default function NxCloudPage(): JSX.Element {
export default function NxCloudPage(): ReactElement {
const headerCTAConfig: ButtonLinkProps[] = [
{
href: '/pricing',
href: 'https://cloud.nx.app/get-started?utm_source=nx-dev&utm_medium=nx-cloud-header&utm_campaign=get-started',
variant: 'primary',
size: 'small',
title: 'Get started for free',
+3 -3
View File
@@ -5,9 +5,9 @@ import {
Hero,
PowerpackFeatures,
} from '@nx/nx-dev/ui-powerpack';
import { contactButton } from '../../lib/components/headerCtaConfigs';
import type { Metadata } from 'next';
import { type ReactElement } from 'react';
export const metadata: Metadata = {
title: 'Nx Powerpack',
@@ -32,10 +32,10 @@ export const metadata: Metadata = {
},
};
export default function NxPowerPackPage(): JSX.Element {
export default function NxPowerPackPage(): ReactElement {
const headerCTAConfig: ButtonLinkProps[] = [
{
href: 'https://cloud.nx.app/powerpack/purchase?licenseBusinessType=small&utm_source=nx.dev&utm_medium=referral&utm_campaign=nx-powerpackurl',
href: '/powerpack/trial',
variant: 'primary',
size: 'small',
title: 'Request a free trial',
@@ -2,7 +2,7 @@ import { ButtonLinkProps } from '@nx/nx-dev/ui-common';
import { NxCloudAnimatedIcon } from '@nx/nx-dev/ui-icons';
export const requestFreeTrial: ButtonLinkProps = {
href: '/contact/sales',
href: '/enterprise/trial',
variant: 'primary',
size: 'small',
title: 'Request a free trial',
+8 -7
View File
@@ -1,21 +1,22 @@
import { useRouter } from 'next/router';
import { NextSeo } from 'next-seo';
import { Footer, Header } from '@nx/nx-dev/ui-common';
import { TalkToOurSalesTeam } from '@nx/nx-dev/ui-contact';
import { TalkToOurTeam } from '@nx/nx-dev/ui-contact';
import { type ReactElement } from 'react';
export function ContactSales(): JSX.Element {
export function ContactSales(): ReactElement {
const router = useRouter();
return (
<>
<NextSeo
title="Talk to our Sales team"
description="Were here to help you find the right plan and pricing for your needs and discuss how Nx Cloud Enterprise can drive better business outcomes for your organization."
title="Contact Nx Sales Discover the Best Solution for Your Team"
description="Get in touch with Nx experts to learn how we can optimize your development workflow. Whether you're scaling up or seeking enhanced CI performance, our team is here to help."
openGraph={{
url: 'https://nx.dev' + router.asPath,
title: 'Talk to our Sales team',
title: 'Contact Nx Sales Discover the Best Solution for Your Team',
description:
'Were here to help you find the right plan and pricing for your needs and discuss how Nx Cloud Enterprise can drive better business outcomes for your organization.',
"Get in touch with Nx experts to learn how we can optimize your development workflow. Whether you're scaling up or seeking enhanced CI performance, our team is here to help.",
images: [
{
url: 'https://nx.dev/socials/nx-media.png',
@@ -32,7 +33,7 @@ export function ContactSales(): JSX.Element {
<Header />
<main id="main" role="main" className="py-24 lg:py-32">
<div>
<TalkToOurSalesTeam />
<TalkToOurTeam />
</div>
</main>
<Footer />
+2 -2
View File
@@ -6,7 +6,7 @@ import {
Hero,
OssProjects,
} from '@nx/nx-dev/ui-customers';
import { tryNxCloudForFree } from '../lib/components/headerCtaConfigs';
import { contactButton } from '../lib/components/headerCtaConfigs';
export function Customers(): JSX.Element {
const router = useRouter();
@@ -34,7 +34,7 @@ export function Customers(): JSX.Element {
type: 'website',
}}
/>
<DefaultLayout headerCTAConfig={[tryNxCloudForFree]}>
<DefaultLayout headerCTAConfig={[contactButton]}>
<div>
<Hero />
</div>
@@ -14,7 +14,7 @@ import {
TestimonialCarousel,
VmwareTestimonial,
} from '@nx/nx-dev/ui-enterprise';
import { requestFreeTrial } from '../lib/components/headerCtaConfigs';
import { requestFreeTrial } from '../../lib/components/headerCtaConfigs';
import { ReactElement } from 'react';
export function Enterprise(): ReactElement {

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