Compare commits

...

45 Commits

Author SHA1 Message Date
Katerina Skroumpelou 73f15ebcc8 feat(nx-cloud): unhide new onboarding flow
(cherry picked from commit 92be32c1a8)
2024-06-26 12:17:24 -04:00
Katerina Skroumpelou 75b7fa1553 feat(nx-cloud): updates to the new onboarding flow
(cherry picked from commit d928558bc4)
2024-06-26 12:17:23 -04:00
Emily Xiong ef3d1e227c fix(core): expand env variables on load and unload (#26459)
This pr is meant to replace https://github.com/nrwl/nx/pull/22585 and
https://github.com/nrwl/nx/pull/20524

Env variables using other variables were not unloaded from the
environment and further customizations were impossible in more specific
env files.

<!-- 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` -->

## 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 https://github.com/nrwl/nx/issues/23581

Co-authored-by: Mateo Tibaquira <nestormateo@gmail.com>
(cherry picked from commit 88fd03be3b)
2024-06-26 12:17:17 -04:00
Leosvel Pérez Espinosa 3abd3528f7 fix(linter): handle eslint flat config path correctly in lint executor (#26687)
<!-- 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 #26424
Fixes #26586
Fixes #26532

(cherry picked from commit 7ba49ffc41)
2024-06-26 12:17:17 -04:00
Colum Ferry 5818942d10 fix(module-federation): dynamic remotes external to workspace should be skipped correctly #26551 (#26692)
<!-- 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 -->
Module Federation utils were not checking if the remotes defined
dynamically in the `module-federation.manifest.json` were in the project
graph.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Check that the dynamic remotes exist in the project graph before trying
to do work with them

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

Fixes #26551

(cherry picked from commit ce3f7f4ed8)
2024-06-26 12:17:08 -04:00
Leosvel Pérez Espinosa a35dff8af2 fix(testing): accept a numeric value for the playwright executor's workers option (#26689)
<!-- 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 #26437

(cherry picked from commit d3383caad3)
2024-06-26 12:17:07 -04:00
Jack Hsu 8d3323eba5 fix(linter): ensure that @nx/eslint-plugin is installed when we add an extracted base eslintrc file (#26679)
The current eslint logic doesn't add the necessary `@nx/eslint-plugin`
package when we extract root config. This PR fixes the issue. This
applies to projects not generated using CNW but rather using something
like `npm create vite`, where the eslint setup isn't what we expect.

<!-- 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 c24c20e990)
2024-06-26 12:17:06 -04:00
Colum Ferry 0c7e6cd07c fix(angular): migration of browserTarget to buildTarget should handle empty config #26681 (#26690)
<!-- 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 migration from `browserTarget` to `buildTarget` assumed config would
not be undefined.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
The migration should check if config is undefined

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

Fixes #26681

(cherry picked from commit 81dced7252)
2024-06-26 12:16:55 -04:00
Leosvel Pérez Espinosa c7cb8da5fd fix(angular): allow usages of ecmascript decorators in ng-packagr executors (#26691)
<!-- 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 #26448

(cherry picked from commit a871643b37)
2024-06-26 12:16:55 -04:00
Josh Kim b027042f2f fix(module-federation): module-federation-dev-server hang caused by child process exiting too early (#26684) (#26685)
<!-- 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
See #26684

## Expected Behavior
See #26684

Fixes #26684

---

This fix is targeted at NX 19. For a backport to NX 18, a small, trivial
change is necessary. I will file another PR targeting NX 18.

---------

Co-authored-by: Colum Ferry <cferry09@gmail.com>
(cherry picked from commit 93b3e2142c)
2024-06-26 12:16:49 -04:00
James Henry 7dd5498797 feat(release): allow disabling GitHub username matching in default changelog renderer (#26672)
(cherry picked from commit 3a2e8d45f5)
2024-06-26 12:16:46 -04:00
Thomas Dekiere b2155119cc fix(remix): don't add @remix-run/eslint-config dependency to new remix apps (#26568)
<!-- 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 a new remix app is generated with @nx/remix, it can't be installed
due to peer dependencies that are introduced by
@remix-run/eslint-config. This dependency though is not used in the nx
workspace and has also been removed from the official create-remix
method.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Running `npm install` should not throw errors after a remix application
was added to the nx workspace.

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

Fixes #26540

(cherry picked from commit 1e41672e6a)
2024-06-26 12:16:43 -04:00
Colum Ferry 3a5f41252c fix(vite): incremental builds tmp tsconfig should have baseUrl set to workspace root (#26680)
<!-- 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 nxViteTsPaths resolves the tmp tsconfig we create for the buildable
libs, it uses the absoluteBaseUrl of the tsconfig to when creating the
ESM matcher for resolving files.
There is no baseUrl set, therefore the absoluteBaseUrl becomes the
directory of the tmp tsconfig
This means the paths to the built artifacts are incorrect

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Use the workspace root, which lines up with the output locations for
built artifacts, for the baseUrl for the tmp tsconfig

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

Fixes #

(cherry picked from commit b42b6f7dbe)
2024-06-26 12:16:39 -04:00
James Henry adbbaba497 fix(release): skip dependents of projects without changes in conventional commits (#26671)
(cherry picked from commit d356f61192)
2024-06-26 12:16:37 -04:00
Colum Ferry 82f7a5fe4e fix(vite): setup-paths-plugin should only register import once (#26678)
<!-- 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 `@nx/vite:setup-paths-plugin` generator is adding the import
multiple times

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
The `@nx/vite:setup-paths-plugin` should only add the import when it
does not exist

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

Fixes #

(cherry picked from commit e04b5761de)
2024-06-26 12:16:34 -04:00
Emily Xiong 7951ded7ea fix(graph): fix search params reload when back to graph (#26580)
<!-- 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 -->
- change useIntervalWhen
- when this function is used, it is mostly calling a fetch request,
change it to take an async function
- wait for the current fetch request to finish before firing the next
one
  - change the name to usePoll
- currently, when going back to graph, it needs to remove the search
params expand and sometimes need to add ?project= search params
- delete expand search params is called after adding the project search
params

```

 setSearchParams(
        (currentSearchParams) => {
          currentSearchParams.delete('expanded');
          return currentSearchParams;
        },
        { replace: true, preventScrollReset: true }
      );

```

this function does not contain the ?project= search param key, caused
the graph page to reload twice
- change the function useRouteConstructor to delete the search params
`expanded` there

## 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 6ebf676b5e)
2024-06-26 12:16:29 -04:00
Leosvel Pérez Espinosa 8157ecbaf3 fix(angular): fix chalk import and correctly skip invalid projects in ng-add generator (#26667)
<!-- 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 #26654

(cherry picked from commit 8872ca5c8f)
2024-06-26 12:16:12 -04:00
Jason Jean b91e26eef3 fix(bundling): use vite createNodes v2 for add plugin (#26662)
<!-- 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 -->

vite createNodesV1 is used during init

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

vite createNodesV2 is used during init

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

Fixes #

(cherry picked from commit a3322f76ef)
2024-06-26 12:15:25 -04:00
Craigory Coppola 38da3680cc fix(core): isolated plugins should provide cleanup function (#26657)
<!-- 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
- Isolated plugins return no-op cleanup function.

## Expected Behavior
- Isolated plugins cleanup fn shuts them down.

## Related Issue(s)
In #26625 we are starting to reload plugins when their configurations
change. This makes sense, but means we should actually shutdown + reload
workers.

Fixes #

(cherry picked from commit 3b2c42a8a5)
2024-06-26 12:15:19 -04:00
Jason Jean 3e59e9852c fix(core): pick up changes to plugins configuration in daemon (#26625)
<!-- 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 previous set of plugins are reused even when the plugins
configuration change (plugins are added/removed or have their options
changed).

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

Plugins are cleaned up and reloaded when the plugins configuration
change.

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

Fixes #

(cherry picked from commit cb4cff7251)
2024-06-26 12:15:16 -04:00
MaxKless c67339231d fix(core): repair sourcemaps that had file & plugin swapped (#26628)
(cherry picked from commit 8efe26c99a)
2024-06-26 12:14:48 -04:00
Leosvel Pérez Espinosa 3dfdc1884b fix(webpack): handle nullable plugin options (#26624)
<!-- 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 f66ac74b64)
2024-06-26 12:14:12 -04:00
Juri bcd1cff408 docs(nx-dev): update monorepo world links
(cherry picked from commit efd0994ee6)
2024-06-21 09:57:51 -04:00
Isaac Mann 7ba7b6ac3f docs(core): small tutorial updates (#26559)
Update the npm workspaces, react monorepo and angular monorepo tutorials

(cherry picked from commit 1d1c699c81)
2024-06-21 09:57:50 -04:00
Isaac Mann 2518e7e739 docs(core): remove tasksRunnerOptions (#26615)
Remove the tasksRunnerOptions section in the nx.json docs

(cherry picked from commit 5b44085c81)
2024-06-21 09:57:49 -04:00
James Henry 9e95a89ef3 chore(repo): allow e2e workflows to publish relative versions (#26609)
(cherry picked from commit 472459d9f5)
2024-06-21 09:57:48 -04:00
Caleb Ukle ad5d29e1b5 fix(nx-dev): allow linking to headers that are code wrapped (#26608)
before if a header that was using `code` in the title (i.e. launch
template) the header should so the link icon but would not link anywhere
because the rendered id tag would be an empty string

![empty id tag for
headers](https://github.com/nrwl/nx/assets/23272162/6ee2aa5f-7b1f-4a98-ad11-2e088dd5c36d)

after the id tag is correctly linked by checking the rendering children
contains a `code` tag and pulls the code children out.

added benefit includes the code headers being linked in the side nav
correct too

![side by side diff with
changes](https://github.com/nrwl/nx/assets/23272162/c4f7a166-44fa-4541-ae72-d095962bee5b)

Example showing working from preview:
https://nx-dev-git-docs-allow-linking-code-headers-nrwl.vercel.app/ci/reference/launch-templates#launchtemplatestemplatenameinitsteps

(cherry picked from commit 7699b33ea1)
2024-06-21 09:57:47 -04:00
Jack Hsu 6b8878e0c5 fix(misc): rename @nrwl/* to @nx/* in init generator descriptions (#26610)
We forgot to rename these in the init generator descriptions. This
affects tutorials since we've been including the terminal output with
the wrong scope.

## 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 86954ae96b)
2024-06-21 09:57:47 -04:00
Juri 4ac0a716a0 docs(misc): adjust blog urls
(cherry picked from commit bb3658a809)
2024-06-21 09:57:46 -04:00
Emily Xiong 516bfbdb1e feat(expo): add to project package.json for install command (#26500)
<!-- 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` -->

## 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 https://github.com/nrwl/nx/issues/22393

(cherry picked from commit 5646b38c99)
2024-06-21 09:56:43 -04:00
Emily Xiong 91ddd8874c fix(expo): fix expo start windows (#26493)
<!-- 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` -->

## Current Behavior
<!-- This is the behavior we have today -->
- interactive command does not work on windows, use executor instead

## 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 https://github.com/nrwl/nx/issues/24138

(cherry picked from commit fe30d02109)
2024-06-21 09:56:40 -04:00
Leosvel Pérez Espinosa 06cc155cbc feat(webpack): add createNodesV2 for plugin (#26588)
<!-- 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 -->

There is no implementation for `createNodesV2`.

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

There should be an implementation for `createNodesV2`.

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

Fixes #

(cherry picked from commit 95a6e6864d)
2024-06-21 09:56:37 -04:00
Tycho Bokdam f44ebbb142 chore(core): nx plugin submissions @nx-extend/docusaurus (#26578)
(cherry picked from commit e5d7805d4b)
2024-06-21 09:56:31 -04:00
Jack Hsu 46542f70d4 fix(graph): improve layout when target groups are empty or there are no groups (#26555)
This PR fixes empty target groups and adds consistency between grouped
and ungrouped targets.

## Before

Empty groups have bad empty state -- we should not show it. The
ungrouped targets being on their own without a group is also
inconsistent.

<img width="1153" alt="Screenshot 2024-06-14 at 9 46 11 AM"
src="https://github.com/nrwl/nx/assets/53559/b6e96187-fc6f-4c3f-9b45-39744d02b0ec">

## After

If group is empty, don't render it. Also, if there are no groups then
don't nest the ungrouped targets.

<img width="1190" alt="Screenshot 2024-06-14 at 9 46 29 AM"
src="https://github.com/nrwl/nx/assets/53559/76cd0b32-532b-470d-ad2f-85fc3aaf3997">

If there are groups, put the ungrouped targets into `Others`.

<img width="1152" alt="Screenshot 2024-06-14 at 9 45 55 AM"
src="https://github.com/nrwl/nx/assets/53559/465e64c7-e376-4555-b580-d6ecaafb61f5">

(cherry picked from commit 09a08c6cef)
2024-06-21 09:56:28 -04:00
Leosvel Pérez Espinosa 9389ab0d26 fix(core): merge args and options in nx:run-commands executor (#26573)
<!-- 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 a target using `nx:run-commands` has the `args` option set, the
rest of the options are completely ignored and not forwarded to the
command.

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

When a target using `nx:run-commands` has the `args` option set, the
rest of the options that don't match any of the options set in `args`
and are not specific to the executor should be forwarded to the command.

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

Fixes #

(cherry picked from commit 59ab43ab79)
2024-06-21 09:56:26 -04:00
Colum Ferry 04b959db98 fix(vite): nxViteTsPaths plugin should not run-many for vitest (#26574)
<!-- 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 -->
`nxViteTsPaths` does not check if the mode is test and only filters the
`run-many` command based on whether Vite's config.command === serve.

Vitest will set `config.command` to serve, even for `test` targets.
It does set `mode = test` however.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
When `mode === test`, we do not invoke `nx run-many`

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

Fixes #

(cherry picked from commit 44565262a6)
2024-06-21 09:56:25 -04:00
Nicholas Cunningham 59148637fb fix(nest): Add missing props (#26534)
Add missing props back to the schema so that they can be
defaulted/overwritten.

closes: #26384
(cherry picked from commit c467129758)
2024-06-21 09:56:22 -04:00
Pavlo Grosse b099cd750f feat(angular): add helper function to devkit to add viewProviders to a component (#26526)
## Current Behavior

Angular Nx utils have `addProviderToComponent` function to add a
provider to an Angular component, but are missing a function to add
viewProviders.

## Expected Behavior

There should be a function like `addProviderToComponent` to add view
providers to a component.

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
(cherry picked from commit 15b7e9f079)
2024-06-21 09:56:20 -04:00
Callum Silcock 42fc59731e docs(misc): add .nx/workspace-data to .gitignore in manual setup (#26520)
folder is created during install but is not required to be committed

feel free to close if not required

resolves #26519

---------

Co-authored-by: Isaac Mann <isaacplmann@gmail.com>
(cherry picked from commit df2ff2ded2)
2024-06-21 09:56:18 -04:00
Emily Xiong 7887accb07 feat(graph): add description and tags to details page (#26252)
<!-- 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` -->

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

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
<img width="1155" alt="Screenshot 2024-05-29 at 5 47 20 PM"
src="https://github.com/nrwl/nx/assets/16211801/025f08d5-52cf-4087-94a5-e3319c89f8b1">
<img width="1127" alt="Screenshot 2024-05-29 at 5 47 04 PM"
src="https://github.com/nrwl/nx/assets/16211801/ff19514d-2513-4b13-ac9c-4b124ac0ce4a">
<img width="387" alt="Screenshot 2024-06-04 at 11 56 54 PM"
src="https://github.com/nrwl/nx/assets/16211801/ea2f0c47-a444-4be8-9ccd-60fd2b534e12">

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

Fixes #

(cherry picked from commit e9b7439ce2)
2024-06-21 09:56:12 -04:00
James Henry 7ac7d7130b chore(repo): remove pnpm cache from data step, improve messages (#26552)
(cherry picked from commit b61546fc1a)
2024-06-21 09:56:10 -04:00
James Henry 9cd0c0d7e0 chore(repo): refactor publish.yml for PR releases (#26550)
Redo of #26509, with more guards for unexpected missing/relative values
within full releases in GitHub Actions.

---

Refactors our publish workflow to support PR releases, in addition to
our previous triggers.

**Tests:**

---

- Example of failure on non-PR release (comment skipped):
https://github.com/nrwl/nx/actions/runs/9480869812

---

- Example of failure on PR release (comment created on PR):
  - https://github.com/nrwl/nx/actions/runs/9480852880
  - https://github.com/nrwl/nx/pull/26515#issuecomment-2162646682

---

- Example of dry-run of full release (`workflow_dispatch` with no PR
number provided): https://github.com/nrwl/nx/actions/runs/9497871483

---

- Real PR release created here:

| Release details | 📑 |
  | ------------- | ------------- |
| **Published version** |
[0.0.0-pr-26515-856ef7f](https://www.npmjs.com/package/nx/v/0.0.0-pr-26515-856ef7f)
|
  | **Triggered by** | @JamesHenry |
| **Branch** |
[JamesHenry-patch-1](https://github.com/nrwl/nx/tree/JamesHenry-patch-1)
|
| **Commit** |
[856ef7f](https://github.com/nrwl/nx/commit/856ef7f353ec173d6e1dcdaa286147f4784d72ab)
|
| **Workflow run** |
[9497298216](https://github.com/nrwl/nx/actions/runs/9497298216) |

---------

Co-authored-by: Katerina Skroumpelou <sk.katherine@gmail.com>
(cherry picked from commit 42749b8225)
2024-06-21 09:56:07 -04:00
Leosvel Pérez Espinosa bedc48d1a2 feat(angular): update ngrx packages to v18 (#26549)
<!-- 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` -->

## 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 NXP-747 -->

Fixes #

(cherry picked from commit e22021da4e)
2024-06-21 09:56:06 -04:00
Jack Hsu 32aa8a1e81 fix(bundling): set project type correct for buildable vite projects (#26420)
<!-- 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` -->

This PR:

1. fixes `@nx/vite/plugin` so that it infers the correct `projectType`
2. changes the default `package-json-workspaces` plugin such that
`projectType` is not inferred is `appsDir` and `libsDir` are not set
3. Update PDV to look for the normalized `type` property on projects if
`projectType` is missing (due to no longer being inferred by any
plugin).

## 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 fbd7f80bc9)
2024-06-21 09:56:05 -04:00
Jason Jean b0c82e6de4 Revert publish (#26544)
<!-- 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 below commit caused the publish pipeline to publish a `minor`
version when it should have been a `next` version.

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

This reverts commit
https://github.com/nrwl/nx/commit/3750366ebc5a714912a85bfc0bae4724739847b2.

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

Fixes #

(cherry picked from commit 73c8c3343d)
2024-06-21 09:56:05 -04:00
161 changed files with 2148 additions and 983 deletions
+1 -1
View File
@@ -68,7 +68,6 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
registry-url: 'https://registry.npmjs.org'
check-latest: true
cache: 'pnpm'
# Ensure that the NPM_TOKEN secret is still valid before wasting any time deriving data or building projects
- name: Check NPM Credentials
@@ -414,6 +413,7 @@ jobs:
pnpm nx-release --local=false $VERSION $DRY_RUN
- name: (Stable Release Only) Trigger Docs Release
# Publish docs only on a full release
if: ${{ !github.event.release.prerelease && github.event_name == 'release' }}
run: npx ts-node ./scripts/release-docs.ts
+5
View File
@@ -299,6 +299,11 @@
"description": "Nx plugin for working with shadcn/ui",
"url": "https://github.com/tripss/nx-extend/tree/master/packages/shadcn-ui"
},
{
"name": "@nx-extend/docusaurus",
"description": "Nx plugin adding first class support for Docusaurus in your Nx workspace.",
"url": "https://github.com/tripss/nx-extend/tree/master/packages/docusaurus"
},
{
"name": "@nativescript/nx",
"description": "Nx Plugin adding first class support for NativeScript in your Nx workspace",
+1
View File
@@ -1,5 +1,6 @@
---
title: Nx Cloud 3.0 — Faster Cache, More Powerful DTE, Better Ergonomics
slug: 'nx-cloud-3-0-faster-more-efficient-modernized'
authors: [Juri Strumpflohner]
cover_image: '/blog/images/2023-04-19/featured_img.webp'
tags: [nx, nx-cloud]
@@ -1,5 +1,6 @@
---
title: Nx Console gets Lit
slug: 'nx-console-gets-lit'
authors: [Max Kless]
cover_image: '/blog/images/2023-06-29/featured_img.webp'
tags: [nx, nx-console]
+1
View File
@@ -1,5 +1,6 @@
---
title: Qwikify your Development with Nx
slug: 'qwikify-your-development-with-nx'
authors: ['Colum Ferry']
cover_image: '/blog/images/2023-08-15/featured_img.png'
tags: [nx, changelog, release]
+1
View File
@@ -1,5 +1,6 @@
---
title: Nx Raises $16M Series A
slug: 'nx-raises-16m-series-a'
authors: [Jeff Cross]
tags: [nx]
---
+2 -1
View File
@@ -1,5 +1,6 @@
---
title: Nx Conf 2023 — Recap
slug: 'nx-conf-2023-recap'
authors: [Juri Strumpflohner]
cover_image: '/blog/images/2023-10-13/featured_img.webp'
tags: [nx, nx-conf]
@@ -475,7 +476,7 @@ Jon and Max are the masterminds behind [Nx Console](/getting-started/editor-setu
They mention the release of the JetBrains IDE support earlier this year and give a big shoutout to [Issam](https://github.com/iguissouma) who was the original author of the Nx Console Webstorm community plugin and who helped a lot with the official Nx Console version for JetBrains IDE.
Jon and Max demo the new IntelliJ version of Nx console and how it properly integrates as well as how they wrote the new UI completely from the ground up [using Lit](/blog/2023-06-29-nx-console-gets-lit).
Jon and Max demo the new IntelliJ version of Nx console and how it properly integrates as well as how they wrote the new UI completely from the ground up [using Lit](/blog/nx-console-gets-lit).
Clearly they did not spare showing off the awesome new graph capabilities built into Nx Console that allow you to directly navigate to files.
+1
View File
@@ -1,5 +1,6 @@
---
title: 'Nx 17 has Landed'
slug: 'nx-17-release'
authors: ['Juri Strumpflohner', 'Zack DeRose']
cover_image: '/blog/images/2023-10-20/featured_img.png'
tags: [nx, design]
+1
View File
@@ -1,5 +1,6 @@
---
title: State Management Nx React Native/Expo Apps with TanStack Query and Redux
slug: 'state-management-nx-react-native-expo-apps-with-tanstack-query-and-redux'
authors: [Emily Xiong]
image: '/blog/images/2023-11-08/featured_img.webp'
tags: [nx, React Native]
+1
View File
@@ -1,5 +1,6 @@
---
title: Nx Docs AI Assistant
slug: 'nx-docs-ai-assistant'
authors: [Katerina Skroumpelou]
cover_image: '/blog/images/2023-11-21/featured_img.webp'
tags: [nx, docs, AI]
@@ -1,5 +1,6 @@
---
title: Unit Testing Expo Apps With Jest
slug: 'unit-testing-expo-apps-with-jest'
authors: [Emily Xiong]
cover_image: '/blog/images/2023-11-22/featured_img.webp'
tags: [nx, unit testing]
+2 -1
View File
@@ -1,11 +1,12 @@
---
title: Nx 17.2 Update
slug: 'nx-17-2-release'
authors: [Zack DeRose]
cover_image: '/blog/images/2023-12-20/featured_img.png'
tags: [nx, changelog, release]
---
Its been a bit since we launched [Nx 17](/blog/2023-10-20-nx-17-release)! In this article, well go over some of the new developments and improvements that have landed in Nx 17.2:
Its been a bit since we launched [Nx 17](/blog/nx-17-release)! In this article, well go over some of the new developments and improvements that have landed in Nx 17.2:
- [Nx Closes In On 4 Million Weekly NPM Downloads!!](#nx-closes-in-on-4-million-weekly-npm-downloads)
- [New Simplified Project Configuration On the Way](#new-simplified-project-configuration-on-the-way)
+1
View File
@@ -1,5 +1,6 @@
---
title: Nx — Highlights of 2023
slug: 'nx-highlights-of-2023'
authors: [Juri Strumpflohner, Victor Savkin, Zack DeRose]
cover_image: /blog/images/2023-12-28/featured_img.png
tags: [nx, nx-cloud]
@@ -1,5 +1,6 @@
---
title: What if Nx Plugins Were More Like VSCode Extensions
slug: 'what-if-nx-plugins-were-more-like-vscode-extensions'
authors: [Juri Strumpflohner]
cover_image: '/blog/images/2024-02-05/featured_img.png'
tags: [nx, releases]
@@ -1,5 +1,6 @@
---
title: Introducing @nx/nuxt Enhanced Nuxt.js Support in Nx
slug: 'introducing-nx-nuxt-enhanced-nuxt-js-support-in-nx'
cover_image: '/blog/images/2024-02-06/featured_img.png'
authors: ['Katerina Skroumpelou']
tags: [devtools, javascript, monorepos, nuxt]
+2 -1
View File
@@ -1,5 +1,6 @@
---
title: Fast, Effortless CI
slug: 'fast-effortless-ci'
authors: [Isaac Mann]
cover_image: '/blog/images/2024-02-07/featured_img.png'
tags: [nx, nx-cloud, release]
@@ -101,7 +102,7 @@ Nx understands that some CI pipelines need more resources than others. To accoun
## Automatically Split E2E Tasks by File
Typically, e2e tests are the tasks that take the longest in CI. In order to take advantage of parallelization and task distribution, these large tasks would need to be split into smaller tasks, but doing this manually would involve duplicating a lot of configuration code and making sure to keep that configuration synchronized. Nx 18s [Project Crystal](/blog/2024-02-05-nx-18-project-crystal) allows you to [automatically create separate Cypress and Playwright tasks](/ci/features/split-e2e-tasks) for each spec file in the e2e project. These individual tasks can all be triggered by running the `e2e-ci` task. What was once a tedious manual process can now be done for you automatically.
Typically, e2e tests are the tasks that take the longest in CI. In order to take advantage of parallelization and task distribution, these large tasks would need to be split into smaller tasks, but doing this manually would involve duplicating a lot of configuration code and making sure to keep that configuration synchronized. Nx 18s [Project Crystal](/blog/what-if-nx-plugins-were-more-like-vscode-extensions) allows you to [automatically create separate Cypress and Playwright tasks](/ci/features/split-e2e-tasks) for each spec file in the e2e project. These individual tasks can all be triggered by running the `e2e-ci` task. What was once a tedious manual process can now be done for you automatically.
![](/blog/images/2024-02-07/bodyimg3.webp)
@@ -1,5 +1,6 @@
---
title: Versioning and Releasing Packages in a Monorepo
slug: 'versioning-and-releasing-packages-in-a-monorepo'
authors: [Juri Strumpflohner]
cover_image: '/blog/images/2024-02-09/featured_img.png'
tags: [nx, nx-cloud, releases, changelog]
@@ -48,11 +49,11 @@ pnpm dlx nx@latest init
(use `npx nx@latest init` in a NPM workspace)
This brings up a couple of questions including whether to install [Project Crystal plugins](/blog/2024-02-05-nx-18-project-crystal).
This brings up a couple of questions including whether to install [Project Crystal plugins](/blog/what-if-nx-plugins-were-more-like-vscode-extensions).
![](/blog/images/2024-02-09/bodyimg2.webp)
It gives you some additional benefits ([you can read more here](/blog/2024-02-05-nx-18-project-crystal)), but you dont have to as it is not required for Nx Release.
It gives you some additional benefits ([you can read more here](/blog/what-if-nx-plugins-were-more-like-vscode-extensions)), but you dont have to as it is not required for Nx Release.
## Installing the JavaScript/TypeScript versioning Package
+4 -3
View File
@@ -1,5 +1,6 @@
---
title: Launch Nx Week Recap
slug: 'launch-nx-week-recap'
authors: [Zack DeRose]
cover_image: '/blog/images/2024-02-15/featured_img.png'
tags: [nx, nx-cloud, releases, changelog]
@@ -36,7 +37,7 @@ Juri announced launched Project Crystal with this video:
The short version is: Nx project crystal means Nx plugins make your codebases work more seemlessly with less config.
For the long version, checkout this blog post by Juri where he describes [how Nx plugins are now more like VsCode Extentions](/blog/2024-02-05-nx-18-project-crystal)!
For the long version, checkout this blog post by Juri where he describes [how Nx plugins are now more like VsCode Extentions](/blog/what-if-nx-plugins-were-more-like-vscode-extensions)!
And dont miss our two conference talks on this subject:
@@ -80,7 +81,7 @@ Were very excited about Nx Agents because we think that in its current state,
{% youtube src="https://www.youtube.com/embed/_FSHQIwITic?si=jDpwTVXLYFXiHEm0" title="Nx Agents" /%}
Be sure to also checkout the [blog post from Isaac on Nx Agents](/blog/2024-02-07-fast-effortless-ci), including explanations of exclusive features like auto-detection and retrying for flaky tasks and automatically splitting lengthy end-to-end tests!
Be sure to also checkout the [blog post from Isaac on Nx Agents](/blog/fast-effortless-ci), including explanations of exclusive features like auto-detection and retrying for flaky tasks and automatically splitting lengthy end-to-end tests!
You can [signup for Nx Agents NOW](https://nx.app/products/agents#content), and find out [more of the details in our docs](/ci/features/distribute-task-execution)!
@@ -120,7 +121,7 @@ For a long time, Nx has been purposefully versioning and publishing agnostic, bu
Therefore, weve been working on a new command to the Nx CLI: [nx release](/recipes/nx-release/get-started-with-nx-release#get-started-with-nx-release). We launched this on Friday of our Launch Nx week!
Juri goes into [full details in this blog post](/blog/2024-02-09-versioning-and-releasing-packages), and James Henry — our Director of Engineering and the primary engineer responsible for both maintaining Lerna and creating Nx Release — expands further in his conference talk:
Juri goes into [full details in this blog post](/blog/versioning-and-releasing-packages-in-a-monorepo), and James Henry — our Director of Engineering and the primary engineer responsible for both maintaining Lerna and creating Nx Release — expands further in his conference talk:
### Conference Talk: Releasing Nx Release
+2 -1
View File
@@ -1,6 +1,7 @@
---
title: Monorepos - Why Speed Matters
authors: ['Katerina Skroumpelou']
slug: 'monorepos-why-speed-matters'
authors: ['Katerina Skroumpelou', 'Jeff Cross']
tags: nx, nxdevtools, speed, ci
cover_image: '/blog/images/2024-03-20/featured_img.png'
---
+1
View File
@@ -1,5 +1,6 @@
---
title: Reliable CI. A new execution model fixing both flakiness and slowness
slug: 'reliable-ci-a-new-execution-model-fixing-both-flakiness-and-slowness'
authors: [Victor Savkin]
cover_image: '/blog/images/2024-03-21/featured_img.png'
tags: [nx, nx-cloud, releases]
@@ -1,5 +1,6 @@
---
title: Manage Your Gradle Project using Nx
slug: 'manage-your-gradle-project-using-nx'
authors: ['Emily Xiong']
cover_image: '/blog/images/2024-04-19/featured_img.png'
tags: [nx, gradle, how-to]
+8 -7
View File
@@ -1,5 +1,6 @@
---
title: Nx 19.0 Release!!
slug: 'nx-19-release'
authors: ['Zack DeRose']
cover_image: '/blog/images/2024-05-08/nx-19-thumbnail.png'
tags: [nx, release]
@@ -14,9 +15,9 @@ Hey folks!
It's been awhile since February, where in the midsts our big launch week, we launched Nx 18. Nx 18 introduced the biggest new enhancement to Nx to date: Project Crystal.
[![Project Crystal](/blog/images/2024-02-05/featured_img.png)](/blog/2024-02-05-nx-18-project-crystal)
[![Project Crystal](/blog/images/2024-02-05/featured_img.png)](/blog/what-if-nx-plugins-were-more-like-vscode-extensions)
You can read more on project crystal [here](/blog/2024-02-05-nx-18-project-crystal). The main thing to know though is that Project Crystal adjusts the idea of Nx plugins, so that the mere presence of the plugin in your Nx Workspace removes the need to maintain any configuration for most cases.
You can read more on project crystal [here](/blog/what-if-nx-plugins-were-more-like-vscode-extensions). The main thing to know though is that Project Crystal adjusts the idea of Nx plugins, so that the mere presence of the plugin in your Nx Workspace removes the need to maintain any configuration for most cases.
Nx 18 was a significant departure for us in several ways - maybe the most noteworthy was that we broke our years-long cadence of releasing a new major version every 6 months.
@@ -38,11 +39,11 @@ Here's the rundown of the major things we'll cover in this update:
## NEW PLUGIN: @nx/gradle
[![NEW PLUGIN: @nx/gradle](/blog/images/2024-04-19/featured_img.png)](/blog/2024-04-19-manage-your-gradle)
[![NEW PLUGIN: @nx/gradle](/blog/images/2024-04-19/featured_img.png)](/blog/manage-your-gradle-project-using-nx)
We've launched a new first-party plugin for Gradle!
Emily, the engineer that worked on this effort, posted an entire article where you can find the full details [here](/blog/2024-04-19-manage-your-gradle).
Emily, the engineer that worked on this effort, posted an entire article where you can find the full details [here](/blog/manage-your-gradle-project-using-nx).
Thanks to the benefits of Project Crystal - which allows us to determine information to create Nx Tasks based on the way your Gradle projects are setup - by adding this plugin, it makes it easy to add Gradle into an existing workspace without needing any Nx-specific configuration.
@@ -171,7 +172,7 @@ We've got some cool stats to share from our users regarding the benefits of [Nx
- **speed**: Reported 30% - 70% faster CI
- **cost**: Reported 40% - 75% reduction in CI costs
- **reliability**: Nx Cloud's automatic detection and retrying of flaky tests makes the issue of flaky tests largely go away entirely. You can read more on [our thoughts on reliability here](/blog/2024-03-21-reliable-ci).
- **reliability**: Nx Cloud's automatic detection and retrying of flaky tests makes the issue of flaky tests largely go away entirely. You can read more on [our thoughts on reliability here](/blog/reliable-ci-a-new-execution-model-fixing-both-flakiness-and-slowness).
In February, we launched two big enhancements to Nx Cloud: the [Atomizer](/ci/features/split-e2e-tasks) and [Nx Agents](https://nx.app/products/agents#content).
@@ -195,9 +196,9 @@ And! We've revamped our newsletter, written by our CTO, Victor Savkin. [Subscrib
## NEW CONFERENCE: Monorepo World 2024
[![NEW CONFERENCE: Monorepo World 2024](/blog/images/2024-05-08/welcome-to-monorepo-world-2024.webp)](https://monorepo.tools/conf)
[![NEW CONFERENCE: Monorepo World 2024](/blog/images/2024-05-08/welcome-to-monorepo-world-2024.webp)](https://monorepo.world)
We've got a new conference coming up: [Monorepo World 2024](https://monorepo.tools/conf)!
We've got a new conference coming up: [Monorepo World 2024](https://monorepo.world)!
This conference will cover all things dealing with monorepos, and we're excited to host it at the Computer History Museum in Mountain View, California this October 7th!
+10 -10
View File
@@ -2,7 +2,7 @@
Nx 19.0 has landed, and it's ALL about reinforcing 💎Project Crystal💎!!!
Catch the details in this [blog post](/blog/2024-05-08-nx-19-release) and watch the video below:
Catch the details in this [blog post](/blog/nx-19-release) and watch the video below:
{% youtube
src="https://youtu.be/U6eO8-w9DR0"
@@ -12,16 +12,16 @@ title="Nx 19.0 Has Landed!!"
## Features
{% cards cols="2" %}
{% card title="NEW PLUGIN: @nx/gradle" type="document" url="/blog/2024-05-08-nx-19-release#new-plugin-nxgradle" /%}
{% card title="Nx Atomizer Enhancements" type="document" url="/blog/2024-05-08-nx-19-release#nx-atomizer-enhancements" /%}
{% card title="Associated Technologies Added To Tasks" type="document" url="/blog/2024-05-08-nx-19-release##associated-technologies-added-to-tasks" /%}
{% card title="Generators to Migrate to Project Crystal" type="document" url="/blog/2024-05-08-nx-19-release#generators-to-migrate-to-project-crystal" /%}
{% card title="General Crystal Polishing" type="document" url="/blog/2024-05-08-nx-19-release#general-crystal-polishing" /%}
{% card title="Nx Cloud Updates!" type="document" url="/blog/2024-05-08-nx-19-release#nx-cloud-updates" /%}
{% card title="More Miscellaneous Updates!" type="document" url="/blog/2024-05-08-nx-19-release#more-miscellaneous-updates" /%}
{% card title="NEW CONFERENCE: Monorepo World 2024" type="document" url="/blog/2024-05-08-nx-19-release#new-conference-monorepo-world-2024" /%}
{% card title="NEW PLUGIN: @nx/gradle" type="document" url="/blog/nx-19-release#new-plugin-nxgradle" /%}
{% card title="Nx Atomizer Enhancements" type="document" url="/blog/nx-19-release#nx-atomizer-enhancements" /%}
{% card title="Associated Technologies Added To Tasks" type="document" url="/blog/nx-19-release##associated-technologies-added-to-tasks" /%}
{% card title="Generators to Migrate to Project Crystal" type="document" url="/blog/nx-19-release#generators-to-migrate-to-project-crystal" /%}
{% card title="General Crystal Polishing" type="document" url="/blog/nx-19-release#general-crystal-polishing" /%}
{% card title="Nx Cloud Updates!" type="document" url="/blog/nx-19-release#nx-cloud-updates" /%}
{% card title="More Miscellaneous Updates!" type="document" url="/blog/nx-19-release#more-miscellaneous-updates" /%}
{% card title="NEW CONFERENCE: Monorepo World 2024" type="document" url="/blog/nx-19-release#new-conference-monorepo-world-2024" /%}
{% /cards %}
## Breaking Changes
[Updating Bundled Environment Variables: `NX_` to `NX_PUBLIC_`](/blog/2024-05-08-nx-19-release#breaking-change-updating-bundled-environment-variables-to)
[Updating Bundled Environment Variables: `NX_` to `NX_PUBLIC_`](/blog/nx-19-release#breaking-change-updating-bundled-environment-variables-to)
+11 -11
View File
@@ -502,7 +502,7 @@
},
"generators": {
"/nx-api/cypress/generators/init": {
"description": "Initialize the `@nrwl/cypress` plugin.",
"description": "Initialize the `@nx/cypress` plugin.",
"file": "generated/packages/cypress/generators/init.json",
"hidden": true,
"name": "init",
@@ -591,7 +591,7 @@
},
"generators": {
"/nx-api/detox/generators/init": {
"description": "Initialize the `@nrwl/detox` plugin.",
"description": "Initialize the `@nx/detox` plugin.",
"file": "generated/packages/detox/generators/init.json",
"hidden": true,
"name": "init",
@@ -679,7 +679,7 @@
},
"generators": {
"/nx-api/esbuild/generators/init": {
"description": "Initialize the `@nrwl/esbuild` plugin.",
"description": "Initialize the `@nx/esbuild` plugin.",
"file": "generated/packages/esbuild/generators/init.json",
"hidden": true,
"name": "init",
@@ -1018,7 +1018,7 @@
"executors": {},
"generators": {
"/nx-api/express/generators/init": {
"description": "Initialize the `@nrwl/express` plugin.",
"description": "Initialize the `@nx/express` plugin.",
"file": "generated/packages/express/generators/init.json",
"hidden": true,
"name": "init",
@@ -1114,7 +1114,7 @@
},
"generators": {
"/nx-api/jest/generators/init": {
"description": "Initialize the `@nrwl/jest` plugin.",
"description": "Initialize the `@nx/jest` plugin.",
"file": "generated/packages/jest/generators/init.json",
"hidden": true,
"name": "init",
@@ -1300,7 +1300,7 @@
"type": "generator"
},
"/nx-api/nest/generators/init": {
"description": "Initialize the `@nrwl/nest` plugin.",
"description": "Initialize the `@nx/nest` plugin.",
"file": "generated/packages/nest/generators/init.json",
"hidden": true,
"name": "init",
@@ -1506,7 +1506,7 @@
},
"generators": {
"/nx-api/next/generators/init": {
"description": "Initialize the `@nrwl/next` plugin.",
"description": "Initialize the `@nx/next` plugin.",
"file": "generated/packages/next/generators/init.json",
"hidden": true,
"name": "init",
@@ -1594,7 +1594,7 @@
"executors": {},
"generators": {
"/nx-api/node/generators/init": {
"description": "Initialize the `@nrwl/node` plugin.",
"description": "Initialize the `@nx/node` plugin.",
"file": "generated/packages/node/generators/init.json",
"hidden": true,
"name": "init",
@@ -2178,7 +2178,7 @@
},
"generators": {
"/nx-api/react/generators/init": {
"description": "Initialize the `@nrwl/react` plugin.",
"description": "Initialize the `@nx/react` plugin.",
"file": "generated/packages/react/generators/init.json",
"hidden": true,
"name": "init",
@@ -2739,7 +2739,7 @@
},
"generators": {
"/nx-api/rollup/generators/init": {
"description": "Initialize the `@nrwl/rollup` plugin.",
"description": "Initialize the `@nx/rollup` plugin.",
"file": "generated/packages/rollup/generators/init.json",
"hidden": true,
"name": "init",
@@ -3172,7 +3172,7 @@
},
"generators": {
"/nx-api/webpack/generators/init": {
"description": "Initialize the `@nrwl/webpack` plugin.",
"description": "Initialize the `@nx/webpack` plugin.",
"file": "generated/packages/webpack/generators/init.json",
"hidden": true,
"name": "init",
+11 -11
View File
@@ -494,7 +494,7 @@
],
"generators": [
{
"description": "Initialize the `@nrwl/cypress` plugin.",
"description": "Initialize the `@nx/cypress` plugin.",
"file": "generated/packages/cypress/generators/init.json",
"hidden": true,
"name": "init",
@@ -582,7 +582,7 @@
],
"generators": [
{
"description": "Initialize the `@nrwl/detox` plugin.",
"description": "Initialize the `@nx/detox` plugin.",
"file": "generated/packages/detox/generators/init.json",
"hidden": true,
"name": "init",
@@ -668,7 +668,7 @@
],
"generators": [
{
"description": "Initialize the `@nrwl/esbuild` plugin.",
"description": "Initialize the `@nx/esbuild` plugin.",
"file": "generated/packages/esbuild/generators/init.json",
"hidden": true,
"name": "init",
@@ -1003,7 +1003,7 @@
"executors": [],
"generators": [
{
"description": "Initialize the `@nrwl/express` plugin.",
"description": "Initialize the `@nx/express` plugin.",
"file": "generated/packages/express/generators/init.json",
"hidden": true,
"name": "init",
@@ -1097,7 +1097,7 @@
],
"generators": [
{
"description": "Initialize the `@nrwl/jest` plugin.",
"description": "Initialize the `@nx/jest` plugin.",
"file": "generated/packages/jest/generators/init.json",
"hidden": true,
"name": "init",
@@ -1281,7 +1281,7 @@
"type": "generator"
},
{
"description": "Initialize the `@nrwl/nest` plugin.",
"description": "Initialize the `@nx/nest` plugin.",
"file": "generated/packages/nest/generators/init.json",
"hidden": true,
"name": "init",
@@ -1486,7 +1486,7 @@
],
"generators": [
{
"description": "Initialize the `@nrwl/next` plugin.",
"description": "Initialize the `@nx/next` plugin.",
"file": "generated/packages/next/generators/init.json",
"hidden": true,
"name": "init",
@@ -1573,7 +1573,7 @@
"executors": [],
"generators": [
{
"description": "Initialize the `@nrwl/node` plugin.",
"description": "Initialize the `@nx/node` plugin.",
"file": "generated/packages/node/generators/init.json",
"hidden": true,
"name": "init",
@@ -2152,7 +2152,7 @@
],
"generators": [
{
"description": "Initialize the `@nrwl/react` plugin.",
"description": "Initialize the `@nx/react` plugin.",
"file": "generated/packages/react/generators/init.json",
"hidden": true,
"name": "init",
@@ -2710,7 +2710,7 @@
],
"generators": [
{
"description": "Initialize the `@nrwl/rollup` plugin.",
"description": "Initialize the `@nx/rollup` plugin.",
"file": "generated/packages/rollup/generators/init.json",
"hidden": true,
"name": "init",
@@ -3137,7 +3137,7 @@
],
"generators": [
{
"description": "Initialize the `@nrwl/webpack` plugin.",
"description": "Initialize the `@nx/webpack` plugin.",
"file": "generated/packages/webpack/generators/init.json",
"hidden": true,
"name": "init",
@@ -36,7 +36,7 @@
},
"presets": []
},
"description": "Initialize the `@nrwl/cypress` plugin.",
"description": "Initialize the `@nx/cypress` plugin.",
"aliases": ["ng-add"],
"hidden": true,
"implementation": "/packages/cypress/src/generators/init/init#cypressInitGeneratorInternal.ts",
@@ -35,7 +35,7 @@
"required": [],
"presets": []
},
"description": "Initialize the `@nrwl/detox` plugin.",
"description": "Initialize the `@nx/detox` plugin.",
"hidden": true,
"implementation": "/packages/detox/src/generators/init/init#detoxInitGeneratorInternal.ts",
"aliases": [],
@@ -29,7 +29,7 @@
"required": [],
"presets": []
},
"description": "Initialize the `@nrwl/esbuild` plugin.",
"description": "Initialize the `@nx/esbuild` plugin.",
"aliases": ["ng-add"],
"hidden": true,
"implementation": "/packages/esbuild/src/generators/init/init#esbuildInitGenerator.ts",
@@ -29,7 +29,7 @@
"required": [],
"presets": []
},
"description": "Initialize the `@nrwl/express` plugin.",
"description": "Initialize the `@nx/express` plugin.",
"aliases": ["ng-add"],
"hidden": true,
"implementation": "/packages/express/src/generators/init/init#initGenerator.ts",
@@ -37,7 +37,7 @@
"required": [],
"presets": []
},
"description": "Initialize the `@nrwl/jest` plugin.",
"description": "Initialize the `@nx/jest` plugin.",
"aliases": ["ng-add"],
"hidden": true,
"implementation": "/packages/jest/src/generators/init/init#jestInitGeneratorInternal.ts",
@@ -30,7 +30,7 @@
"required": [],
"presets": []
},
"description": "Initialize the `@nrwl/nest` plugin.",
"description": "Initialize the `@nx/nest` plugin.",
"aliases": ["ng-add"],
"hidden": true,
"implementation": "/packages/nest/src/generators/init/init.ts",
@@ -22,6 +22,11 @@
"alias": "p",
"x-deprecated": "Provide The `directory` option instead and use the `as-provided` format. the project will be determined from the directory provided. It will be removed in Nx v20."
},
"nameAndDirectoryFormat": {
"description": "Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).",
"type": "string",
"enum": ["as-provided", "derived"]
},
"directory": {
"description": "Directory where the generated files are placed. when `--nameAndDirectoryFormat=as-provided`, it will be relative to the current working directory. otherwise, it will be relative to the workspace root.",
"type": "string",
@@ -22,6 +22,11 @@
"alias": "p",
"x-deprecated": "Provide The `directory` option instead and use the `as-provided` format. the project will be determined from the directory provided. It will be removed in Nx v20."
},
"nameAndDirectoryFormat": {
"description": "Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).",
"type": "string",
"enum": ["as-provided", "derived"]
},
"directory": {
"description": "Directory where the generated files are placed. when `--nameAndDirectoryFormat=as-provided`, it will be relative to the current working directory. otherwise, it will be relative to the workspace root.",
"type": "string",
@@ -36,7 +36,7 @@
"required": [],
"presets": []
},
"description": "Initialize the `@nrwl/next` plugin.",
"description": "Initialize the `@nx/next` plugin.",
"hidden": true,
"implementation": "/packages/next/src/generators/init/init#nextInitGeneratorInternal.ts",
"aliases": [],
@@ -29,7 +29,7 @@
"required": [],
"presets": []
},
"description": "Initialize the `@nrwl/node` plugin.",
"description": "Initialize the `@nx/node` plugin.",
"aliases": ["ng-add"],
"hidden": true,
"implementation": "/packages/node/src/generators/init/init.ts",
@@ -28,6 +28,11 @@
"type": "boolean",
"description": "If the user will be using GitHub as their git hosting provider",
"default": false
},
"directory": {
"type": "string",
"description": "The directory where the workspace is located",
"x-priority": "internal"
}
},
"additionalProperties": false,
@@ -63,7 +63,7 @@
},
"workers": {
"alias": "j",
"type": "string",
"oneOf": [{ "type": "number" }, { "type": "string" }],
"description": "Number of concurrent workers or percentage of logical CPU cores, use 1 to run in a single worker"
},
"list": {
@@ -29,7 +29,7 @@
"required": [],
"presets": []
},
"description": "Initialize the `@nrwl/react` plugin.",
"description": "Initialize the `@nx/react` plugin.",
"aliases": ["ng-add"],
"hidden": true,
"implementation": "/packages/react/src/generators/init/init#reactInitGenerator.ts",
@@ -35,7 +35,7 @@
"required": [],
"presets": []
},
"description": "Initialize the `@nrwl/rollup` plugin.",
"description": "Initialize the `@nx/rollup` plugin.",
"aliases": ["ng-add"],
"hidden": true,
"implementation": "/packages/rollup/src/generators/init/init#rollupInitGenerator.ts",
@@ -35,7 +35,7 @@
"required": [],
"presets": []
},
"description": "Initialize the `@nrwl/webpack` plugin.",
"description": "Initialize the `@nx/webpack` plugin.",
"aliases": ["ng-add"],
"hidden": true,
"implementation": "/packages/webpack/src/generators/init/init#webpackInitGeneratorInternal.ts",
+3 -2
View File
@@ -44,13 +44,14 @@ Next, we'll create a blank `nx.json` configuration file for Nx:
{}
```
## Add `.nx/cache` to `.gitignore`
## Add `.nx` directories to `.gitignore`
Next, we'll add [the Nx default cache directory](/features/cache-task-results#where-is-the-cache-stored) to the list of files to be ignored by Git. Update the `.gitignore` file adding the `.nx/cache` entry:
Next, we'll add [the Nx default task cache directory](/features/cache-task-results#where-is-the-cache-stored) and the project graph cache directory to the list of files to be ignored by Git. Update the `.gitignore` file adding the `.nx/cache` and `.nx/workspace-data` entry:
```text {% fileName=".gitignore" %}
...
.nx/cache
.nx/workspace-data
```
## Set Up Caching For a Task
@@ -18,7 +18,7 @@ The default changelog renderer for `nx release` generates a changelog entry for
## Include All Metadata
There are a few options available to modify the default changelog renderer output. They can be applied to both `workspaceChangelog` and `projectChangelogs` in exactly the same way. All three options are true by default:
There are a few options available to modify the default changelog renderer output. They can be applied to both `workspaceChangelog` and `projectChangelogs` in exactly the same way. All four options are true by default:
```json
{
@@ -27,6 +27,7 @@ There are a few options available to modify the default changelog renderer outpu
"projectChangelogs": {
"renderOptions": {
"authors": true,
"mapAuthorsToGitHubUsernames": true,
"commitReferences": true,
"versionTitleDate": true
}
@@ -40,6 +41,12 @@ There are a few options available to modify the default changelog renderer outpu
Whether the commit authors should be added to the bottom of the changelog in a "Thank You" section. Defaults to `true`.
#### `mapAuthorsToGitHubUsernames`
If authors is enabled, controls whether or not to try to map the authors to their GitHub usernames using https://ungh.cc (from https://github.com/unjs/ungh) and the email addresses found in the commits. Defaults to `true`.
You should disable this option if you don't want to make any external requests to https://ungh.cc
#### `commitReferences`
Whether the commit references (such as commit and/or PR links) should be included in the changelog. Defaults to `true`.
@@ -59,6 +66,7 @@ If you prefer a more minimalist changelog, you can set all the options to false,
"projectChangelogs": {
"renderOptions": {
"authors": false,
"mapAuthorsToGitHubUsernames": false,
"commitReferences": false,
"versionTitleDate": false
}
@@ -8,7 +8,6 @@ Problem: A task is being executed when you expect it to be replayed from the cac
- If you're using a version lower than Nx 17.2.0, check:
- the target configuration in the project's `project.json` file has `"cache": true` set, or
- the target configuration in `nx.json#targetDefaults` has `"cache": true` set, or
- the task is listed in `cacheableOperations` defined in `nx.json#tasksRunnerOptions`
1. Check if the output of your task is changing the inputs of your task
-25
View File
@@ -119,31 +119,6 @@ The following properties affect the way Nx runs tasks and can be set at the root
You can configure `parallel` in `nx.json`, but you can also set a `--parallel` flag in the terminal `nx run-many -t test --parallel=5`.
### Multiple Tasks Runners
Tasks runners are invoked when you run `nx test`, `nx build`, `nx run-many`, `nx affected`, and so on.
There is a tasks runner created from the task options defined at the root of `nx.json` named `default`. You can register another tasks runner by adding it to `nx.json` like this:
```json {% fileName="nx.json" %}
{
"tasksRunnerOptions": {
"another": {
"runner": "nx/tasks-runners/default",
"options": {}
}
}
}
```
Then you can run a task with the new runner using the `--runner` flag:
```shell
nx run-many -t build --runner=another
```
The official types of `runner` supported by Nx are `"nx/tasks-runners/default"` and `"nx-cloud"`.
## Default Base
Tells Nx which base branch to use when calculating affected projects.
+15 -28
View File
@@ -385,24 +385,12 @@ All libraries that we generate automatically have aliases created in the root-le
}
```
Hence we can easily import them into other libraries and our Angular application. As an example, let's create and expose a `ProductListComponent` component from our `libs/products` library. Either create it by hand or run
Hence we can easily import them into other libraries and our Angular application. As an example, let's use the pre-generated `ProductsComponent` component from our `libs/products` library.
```shell
nx g @nx/angular:component product-list --directory=libs/products/src/lib/product-list --standalone --export
```
We don't need to implement anything fancy as we just want to learn how to import it into our main Angular application.
```html {% fileName="libs/products/src/lib/product-list/product-list.component.html" %}
<p>product-list works!</p>
```
Make sure the `ProductListComponent` is exported via the `index.ts` file of our `products` library and is listed in the `exports` of the `ProductsModule`. This is our public API with the rest of the workspace. Only export what's really necessary to be usable outside the library itself.
You can see that the `ProductsComponent` is exported via the `index.ts` file of our `products` library so that other projects in the repository can use it. This is our public API with the rest of the workspace. Only export what's really necessary to be usable outside the library itself.
```ts {% fileName="libs/products/src/index.ts" %}
export * from './lib/products/products.component';
export * from './lib/product-list/product-list.component';
```
We're ready to import it into our main application now. First (if you haven't already), let's set up the Angular router. Configure it in the `app.config.ts`.
@@ -426,7 +414,7 @@ And in `app.component.html`:
<router-outlet></router-outlet>
```
Then we can add the `ProductListComponent` component to our `app.routes.ts` and render it via the routing mechanism whenever a user hits the `/products` route.
Then we can add the `ProductsComponent` component to our `app.routes.ts` and render it via the routing mechanism whenever a user hits the `/products` route.
```ts {% fileName="apps/angular-store/src/app/app.routes.ts" highlightLines=[10,11,12,13,14] %}
import { Route } from '@angular/router';
@@ -441,7 +429,7 @@ export const appRoutes: Route[] = [
{
path: 'products',
loadComponent: () =>
import('@angular-monorepo/products').then((m) => m.ProductListComponent),
import('@angular-monorepo/products').then((m) => m.ProductsComponent),
},
];
```
@@ -452,8 +440,7 @@ Serving your app (`nx serve angular-store`) and then navigating to `/products` s
Let's apply the same for our `orders` library.
- generate a new component `OrderListComponent` in `libs/orders` and export it in the corresponding `index.ts` file
- import it into the `app.routes.ts` and render it via the routing mechanism whenever a user hits the `/orders` route
- import the `OrdersComponent` from `libs/orders` into the `app.routes.ts` and render it via the routing mechanism whenever a user hits the `/orders` route
In the end, your `app.routes.ts` should look similar to this:
@@ -470,12 +457,12 @@ export const appRoutes: Route[] = [
{
path: 'products',
loadComponent: () =>
import('@angular-monorepo/products').then((m) => m.ProductListComponent),
import('@angular-monorepo/products').then((m) => m.ProductsComponent),
},
{
path: 'orders',
loadComponent: () =>
import('@angular-monorepo/orders').then((m) => m.OrderListComponent),
import('@angular-monorepo/orders').then((m) => m.OrdersComponent),
},
];
```
@@ -484,12 +471,12 @@ Let's also show products in the `inventory` app.
```ts {% fileName="apps/inventory/src/app/app.component.ts" highlightLines=[2,6] %}
import { Component } from '@angular/core';
import { ProductListComponent } from '@angular-monorepo/products';
import { ProductsComponent } from '@angular-monorepo/products';
@Component({
standalone: true,
imports: [ProductListComponent],
selector: 'angular-monorepo-root',
imports: [ProductsComponent],
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
@@ -499,7 +486,7 @@ export class AppComponent {
```
```ts {% fileName="apps/inventory/src/app/app.component.html" %}
<angular-monorepo-product-list></angular-monorepo-product-list>
<lib-products></lib-products>
```
## Visualizing your Project Structure
@@ -1185,14 +1172,14 @@ To enforce the rules, Nx ships with a custom ESLint rule. Open the `.eslintrc.ba
}
```
To test it, go to your `libs/products/src/lib/product-list/product-list.component.ts` file and import the `OrderListComponent` from the `orders` project:
To test it, go to your `libs/products/src/lib/product-list/product-list.component.ts` file and import the `OrdersComponent` from the `orders` project:
```ts {% fileName="libs/products/src/lib/product-list/product-list.component.ts" highlightLines=[4,5] %}
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
// This import is not allowed 👇
import { OrderListComponent } from '@angular-monorepo/orders';
import { OrdersComponent } from '@angular-monorepo/orders';
@Component({
selector: 'angular-monorepo-product-list',
@@ -1201,7 +1188,7 @@ import { OrderListComponent } from '@angular-monorepo/orders';
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.css'],
})
export class ProductListComponent {}
export class ProductsComponent {}
```
If you lint your workspace you'll get an error now:
@@ -1213,7 +1200,7 @@ NX Running target lint for 7 projects
/Users/isaac/Documents/code/nx-recipes/angular-monorepo/libs/products/src/lib/product-list/product-list.component.ts
5:1 error A project tagged with "scope:products" can only depend on libs tagged with "scope:products", "scope:shared" @nx/enforce-module-boundaries
5:10 warning 'OrderListComponent' is defined but never used @typescript-eslint/no-unused-vars
5:10 warning 'OrdersComponent' is defined but never used @typescript-eslint/no-unused-vars
✖ 2 problems (1 error, 1 warning)
+4 -4
View File
@@ -302,7 +302,7 @@ First, let's delete the `outputs` array from `nx.json` so that we don't override
Now let's add the `@nx/vite` plugin:
```{% command="npx nx add @nx/vite" path="~/tuskydesign" %}
✔ Installing @nx/vite@18.1.0...
✔ Installing @nx/vite...
✔ Initializing @nx/vite...
NX Package @nx/vite added successfully.
@@ -311,13 +311,13 @@ Now let's add the `@nx/vite` plugin:
The `nx add` command installs the version of the plugin that matches your repo's Nx version and runs that plugin's initialization script. For `@nx/vite`, the initialization script registers the plugin in the `plugins` array of `nx.json` and updates any `package.json` scripts that execute Vite related tasks. Open the project details view for the `demo` app and look at the `build` task.
```shell {% path="~/tuskydesigns" %}
npx nx show project @tuskdesign/demo --web
npx nx show project @tuskdesign/demo
```
{% project-details title="Project Details View" jsonFile="shared/tutorials/npm-workspaces-pdv.json" %}
{% /project-details %}
If you hover over the settings for the `build` task, you can see where those settings come from. The `inputs` and `outputs` are defined by the `@nx/vite` plugin from the `vite.config.ts` file where as the `dependsOn` property we set earlier in the tutorial in the `targetDefaults` in the `nx.json` file.
If you hover over the settings for the `vite:build` task, you can see where those settings come from. The `inputs` and `outputs` are defined by the `@nx/vite` plugin from the `vite.config.ts` file where as the `dependsOn` property we set earlier in the tutorial in the `targetDefaults` in the `nx.json` file.
Now let's change where the `build` results are output to in the `vite.config.ts` file.
@@ -403,7 +403,7 @@ This generator creates a `.github/workflows/ci.yml` file that contains a CI pipe
The key line in the CI pipeline is:
```yml
- run: npx nx affected -t lint test build e2e-ci
- run: npx nx affected -t lint test build
```
### Connect to Nx Cloud
+34 -74
View File
@@ -98,7 +98,7 @@ Let's name the initial application `react-store`. In this tutorial we're going t
The setup includes..
- a new React application (`apps/react-store/`)
- a Cypress based set of e2e tests (`apps/react-store-e2e/`)
- a Playwright based set of e2e tests (`apps/react-store-e2e/`)
- Prettier preconfigured
- ESLint preconfigured
- Jest preconfigured
@@ -128,7 +128,7 @@ Nx uses the following syntax to run tasks:
Nx identifies available tasks for your project from [tooling configuration files](/concepts/inferred-tasks), `package.json` scripts and the targets defined in `project.json`. To view the tasks that Nx has detected, look in the [Nx Console](/getting-started/editor-setup) project detail view or run:
```shell
nx show project react-store --web
nx show project react-store
```
{% project-details title="Project Details View (Simplified)" height="100px" %}
@@ -137,13 +137,9 @@ nx show project react-store --web
{
"project": {
"name": "react-store",
"type": "app",
"data": {
"metadata": {
"technologies": ["react"]
},
"root": "apps/react-store",
"includedScripts": [],
"name": "react-store",
"targets": {
"build": {
"options": {
@@ -161,15 +157,13 @@ nx show project react-store --web
],
"outputs": ["{workspaceRoot}/dist/apps/react-store"],
"executor": "nx:run-commands",
"configurations": {},
"metadata": {
"technologies": ["vite"]
}
"configurations": {}
}
},
"name": "react-store",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/react-store/src",
"projectType": "application",
"$schema": "node_modules/nx/schemas/project-schema.json",
"tags": [],
"implicitDependencies": []
}
@@ -433,35 +427,12 @@ All libraries that we generate automatically have aliases created in the root-le
}
```
Hence we can easily import them into other libraries and our React application. As an example, let's create and expose a `ProductList` component from our `libs/products` library. Either create it by hand or run
Hence we can easily import them into other libraries and our Angular application. As an example, let's use the pre-generated `ProductsComponent` component from our `libs/products` library.
```shell
nx g @nx/react:component product-list --project=products --directory="libs/products/src/lib/product-list"
```
We don't need to implement anything fancy as we just want to learn how to import it into our main React application.
```tsx {% fileName="libs/products/src/lib/product-list/product-list.tsx" %}
import styles from './product-list.module.css';
/* eslint-disable-next-line */
export interface ProductListProps {}
export function ProductList(props: ProductListProps) {
return (
<div className={styles['container']}>
<h1>Welcome to ProductList!</h1>
</div>
);
}
export default ProductList;
```
Make sure the `ProductList` is exported via the `index.ts` file of our `products` library. This is our public API with the rest of the workspace. Only export what's really necessary to be usable outside the library itself.
You can see that the `Products` component is exported via the `index.ts` file of our `products` library so that other projects in the repository can use it. This is our public API with the rest of the workspace. Only export what's really necessary to be usable outside the library itself.
```ts {% fileName="libs/products/src/index.ts" %}
export * from './lib/product-list/product-list';
export * from './lib/products';
```
We're ready to import it into our main application now. First (if you haven't already), let's set up React Router.
@@ -512,13 +483,13 @@ root.render(
);
```
Then we can import the `ProductList` component into our `app.tsx` and render it via the routing mechanism whenever a user hits the `/products` route.
Then we can import the `Products` component into our `app.tsx` and render it via the routing mechanism whenever a user hits the `/products` route.
```tsx {% fileName="apps/react-store/src/app/app.tsx" %}
import { Route, Routes } from 'react-router-dom';
// importing the component from the library
import { ProductList } from '@react-monorepo/products';
import { Products } from '@react-monorepo/products';
function Home() {
return <h1>Home</h1>;
@@ -528,7 +499,7 @@ export function App() {
return (
<Routes>
<Route path="/" element={<Home />}></Route>
<Route path="/products" element={<ProductList />}></Route>
<Route path="/products" element={<Products />}></Route>
</Routes>
);
}
@@ -542,15 +513,14 @@ Serving your app (`nx serve react-store`) and then navigating to `/products` sho
Let's apply the same for our `orders` library.
- generate a new component `OrderList` in `libs/orders` and export it in the corresponding `index.ts` file
- import it into the `app.tsx` and render it via the routing mechanism whenever a user hits the `/orders` route
- import the `Orders` component from `libs/orders` into the `app.tsx` and render it via the routing mechanism whenever a user hits the `/orders` route
In the end, your `app.tsx` should look similar to this:
```tsx {% fileName="apps/react-store/src/app/app.tsx" %}
import { Route, Routes } from 'react-router-dom';
import { ProductList } from '@react-monorepo/products';
import { OrderList } from '@react-monorepo/orders';
import { Products } from '@react-monorepo/products';
import { Orders } from '@react-monorepo/orders';
function Home() {
return <h1>Home</h1>;
@@ -560,8 +530,8 @@ export function App() {
return (
<Routes>
<Route path="/" element={<Home />}></Route>
<Route path="/products" element={<ProductList />}></Route>
<Route path="/orders" element={<OrderList />}></Route>
<Route path="/products" element={<Products />}></Route>
<Route path="/orders" element={<Orders />}></Route>
</Routes>
);
}
@@ -572,10 +542,10 @@ export default App;
Let's also show products in the `inventory` app.
```tsx {% fileName="apps/inventory/src/app/app.tsx" %}
import { ProductList } from '@react-monorepo/products';
import { Products } from '@react-monorepo/products';
export function App() {
return <ProductList />;
return <Products />;
}
export default App;
@@ -735,22 +705,19 @@ git commit -a -m "some commit message"
And then make a small change to the `products` library.
```tsx {% fileName="libs/products/src/lib/product-list/product-list.tsx" %}
import styles from './product-list.module.css';
```tsx {% fileName="libs/products/src/lib/products.tsx" %}
import styles from './products.module.css';
/* eslint-disable-next-line */
export interface ProductListProps {}
export function ProductList(props: ProductListProps) {
export function Products() {
return (
<div className={styles['container']}>
<h1>Welcome to ProductList!</h1>
<h1>Welcome to Products!</h1>
<p>This is a change. 👋</p>
</div>
);
}
export default ProductList;
export default Products;
```
One of the key features of Nx in a monorepo setting is that you're able to run tasks only for projects that are actually affected by the code changes that you've made. To run the tests for only the projects affected by this change, run:
@@ -970,10 +937,6 @@ To enforce the rules, Nx ships with a custom ESLint rule. Open the `.eslintrc.ba
"enforceBuildableLibDependency": true,
"allow": [],
"depConstraints": [
{
"sourceTag": "*",
"onlyDependOnLibsWithTags": ["*"]
},
{
"sourceTag": "type:feature",
"onlyDependOnLibsWithTags": ["type:feature", "type:ui"]
@@ -1008,27 +971,24 @@ To enforce the rules, Nx ships with a custom ESLint rule. Open the `.eslintrc.ba
}
```
To test it, go to your `libs/products/src/lib/product-list/product-list.tsx` file and import the `OrderList` from the `orders` project:
To test it, go to your `libs/products/src/lib/products.tsx` file and import the `Orders` component from the `orders` project:
```tsx {% fileName="libs/products/src/lib/product-list/product-list.tsx" %}
import styles from './product-list.module.css';
```tsx {% fileName="libs/products/src/lib/products.tsx" %}
import styles from './products.module.css';
// This import is not allowed 👇
import { OrderList } from '@react-monorepo/orders';
import { Orders } from '@react-monorepo/orders';
/* eslint-disable-next-line */
export interface ProductListProps {}
export function ProductList(props: ProductListProps) {
export function Products() {
return (
<div className={styles['container']}>
<h1>Welcome to ProductList!</h1>
<OrderList />
<h1>Welcome to Products!</h1>
<p>This is a change. 👋</p>
</div>
);
}
export default ProductList;
export default Products;
```
If you lint your workspace you'll get an error now:
@@ -1038,9 +998,9 @@ If you lint your workspace you'll get an error now:
✖ nx run products:lint
Linting "products"...
/Users/isaac/Documents/code/nx-recipes/react-monorepo/libs/products/src/lib/product-list/product-list.tsx
/Users/isaac/Documents/code/nx-recipes/react-monorepo/libs/products/src/lib/products.tsx
4:1 error A project tagged with "scope:products" can only depend on libs tagged with "scope:products", "scope:shared" @nx/enforce-module-boundaries
4:10 warning 'OrderList' is defined but never used @typescript-eslint/no-unused-vars
4:10 warning 'Orders' is defined but never used @typescript-eslint/no-unused-vars
✖ 2 problems (1 error, 1 warning)
+15 -1
View File
@@ -146,12 +146,26 @@ describe('@nx/expo (legacy)', () => {
it('should install', async () => {
// run install command
const installResults = await runCLIAsync(
let installResults = await runCLIAsync(
`install ${appName} --no-interactive`
);
expect(installResults.combinedOutput).toContain(
'Successfully ran target install'
);
installResults = await runCLIAsync(
`install ${appName} --packages=@react-native-async-storage/async-storage,react-native-image-picker --no-interactive`
);
expect(installResults.combinedOutput).toContain(
'Successfully ran target install'
);
const packageJson = readJson(join('apps', appName, 'package.json'));
expect(packageJson).toMatchObject({
dependencies: {
'@react-native-async-storage/async-storage': '*',
'react-native-image-picker': '*',
},
});
});
it('should start', async () => {
+24
View File
@@ -112,6 +112,30 @@ describe('@nx/expo', () => {
);
});
it('should install', async () => {
// run install command
let installResults = await runCLIAsync(
`install ${appName} --no-interactive`
);
expect(installResults.combinedOutput).toContain(
'Successfully ran target install'
);
installResults = await runCLIAsync(
`install ${appName} --packages=@react-native-async-storage/async-storage,react-native-image-picker --no-interactive`
);
expect(installResults.combinedOutput).toContain(
'Successfully ran target install'
);
const packageJson = readJson(join(appName, 'package.json'));
expect(packageJson).toMatchObject({
dependencies: {
'@react-native-async-storage/async-storage': '*',
'react-native-image-picker': '*',
},
});
});
it('should run e2e for cypress', async () => {
if (runE2ETests()) {
const results = runCLI(`e2e ${appName}-e2e`);
+50 -36
View File
@@ -2,7 +2,6 @@ import { parseJson } from '@nx/devkit';
import {
checkFilesExist,
cleanupProject,
getSelectedPackageManager,
isNotWindows,
newProject,
readFile,
@@ -293,49 +292,64 @@ describe('Extra Nx Misc Tests', () => {
});
describe('Env File', () => {
it('should have the right env', () => {
const appName = uniq('app');
const libName = uniq('lib');
beforeAll(() => {
runCLI(
`generate @nx/react:app ${appName} --style=css --bundler=webpack --no-interactive`
`generate @nx/js:lib ${libName} --bundler=none --unitTestRunner=none --no-interactive`
);
});
it('should have the right env', () => {
updateFile(
'.env',
`FIRSTNAME="firstname"
LASTNAME="lastname"
NX_USERNAME=$FIRSTNAME $LASTNAME`
LASTNAME="lastname"
NX_USERNAME=$FIRSTNAME $LASTNAME`
);
updateFile(
`apps/${appName}/src/app/app.tsx`,
`
import NxWelcome from './nx-welcome';
export function App() {
return (
<>
<NxWelcome title={process.env.NX_USERNAME} />
</>
);
}
export default App;
`
);
updateFile(
`apps/${appName}/src/app/app.spec.tsx`,
`import { render } from '@testing-library/react';
import App from './app';
describe('App', () => {
it('should have a greeting as the title', () => {
const { getByText } = render(<App />);
expect(getByText(/Welcome firstname lastname/gi)).toBeTruthy();
updateJson(join('libs', libName, 'project.json'), (config) => {
config.targets.echo = {
command: 'echo $NX_USERNAME',
};
return config;
});
let result = runCLI(`run ${libName}:echo`);
expect(result).toContain('firstname lastname');
updateFile('.env', (content) => {
content = content.replace('firstname', 'firstname2');
content = content.replace('lastname', 'lastname2');
return content;
});
result = runCLI(`run ${libName}:echo`);
expect(result).toContain('firstname2 lastname2');
});
`
);
const unitTestsOutput = runCLI(`test ${appName}`);
expect(unitTestsOutput).toContain('Successfully ran target test');
it('should work with custom env file', () => {
updateFile(`libs/${libName}/.custom1.env`, `hello="hello1"`);
updateFile(`libs/${libName}/.custom2.env`, `hello="hello2"`);
updateJson(join('libs', libName, 'project.json'), (config) => {
config.targets.hello1 = {
command: 'echo $hello',
options: {
envFile: `libs/${libName}/.custom1.env`,
},
};
config.targets.hello2 = {
command: 'echo $hello',
options: {
envFile: `libs/${libName}/.custom2.env`,
},
};
return config;
});
let result = runCLI(`run ${libName}:hello1`);
expect(result).toContain('hello1');
result = runCLI(`run ${libName}:hello2`);
expect(result).toContain('hello2');
result = runCLI(`run-many --target=hello1,hello2`);
expect(result).toContain('hello1');
expect(result).toContain('hello2');
});
});
+24 -5
View File
@@ -8,15 +8,34 @@ import {
uniq,
updateFile,
runCommandAsync,
listFiles,
} from '@nx/e2e/utils';
describe('Remix E2E Tests', () => {
describe('--integrated', () => {
let proj: string;
describe('--integrated (npm)', () => {
beforeAll(() => {
proj = newProject({ packages: ['@nx/remix', '@nx/react'] });
newProject({
packages: ['@nx/remix', '@nx/react'],
packageManager: 'npm',
});
});
afterAll(() => {
killPorts();
cleanupProject();
});
it('should not cause peer dependency conflicts', async () => {
const plugin = uniq('remix');
runCLI(
`generate @nx/remix:app ${plugin} --projectNameAndRootFormat=as-provided`
);
await runCommandAsync('npm install');
}, 120000);
});
describe('--integrated (yarn)', () => {
beforeAll(() => {
newProject({ packages: ['@nx/remix', '@nx/react'] });
});
afterAll(() => {
@@ -29,7 +29,7 @@ import {
fetchProjectGraph,
getProjectGraphDataService,
useEnvironmentConfig,
useIntervalWhen,
usePoll,
useRouteConstructor,
} from '@nx/graph/shared';
import {
@@ -295,24 +295,23 @@ export function ProjectsSidebar(): JSX.Element {
}
}, [searchParams]);
useIntervalWhen(
() => {
fetchProjectGraph(
usePoll(
async () => {
const response: ProjectGraphClientResponse = await fetchProjectGraph(
projectGraphDataService,
params,
environmentConfig.appConfig
).then((response: ProjectGraphClientResponse) => {
if (response.hash === lastHash) {
return;
}
projectGraphService.send({
type: 'updateGraph',
projects: response.projects,
dependencies: response.dependencies,
fileMap: response.fileMap,
});
setLastHash(response.hash);
);
if (response.hash === lastHash) {
return;
}
projectGraphService.send({
type: 'updateGraph',
projects: response.projects,
dependencies: response.dependencies,
fileMap: response.fileMap,
});
setLastHash(response.hash);
},
5000,
environmentConfig.watch
+7 -7
View File
@@ -16,7 +16,7 @@ import {
fetchProjectGraph,
getProjectGraphDataService,
useEnvironmentConfig,
useIntervalWhen,
usePoll,
} from '@nx/graph/shared';
import { Dropdown, Spinner } from '@nx/graph/ui-components';
import { getSystemTheme, Theme, ThemePanel } from '@nx/graph/ui-theme';
@@ -71,15 +71,15 @@ export function Shell(): JSX.Element {
useLayoutEffect(() => {
setErrors(routerErrors);
}, [routerErrors]);
useIntervalWhen(
() => {
fetchProjectGraph(
usePoll(
async () => {
const response: ProjectGraphClientResponse = await fetchProjectGraph(
projectGraphDataService,
params,
environmentConfig.appConfig
).then((response: ProjectGraphClientResponse) => {
setErrors(response.errors);
});
);
setErrors(response.errors);
},
1000,
environmentConfig.watch
@@ -3,7 +3,7 @@ import {
fetchProjectGraph,
getProjectGraphDataService,
useEnvironmentConfig,
useIntervalWhen,
usePoll,
} from '@nx/graph/shared';
import { ErrorRenderer } from '@nx/graph/ui-components';
import {
@@ -23,20 +23,20 @@ export function ErrorBoundary() {
const hasErrorData =
isRouteErrorResponse(error) && error.data.errors?.length > 0;
useIntervalWhen(
usePoll(
async () => {
fetchProjectGraph(projectGraphDataService, params, appConfig).then(
(data) => {
if (
isRouteErrorResponse(error) &&
error.data.id === 'project-not-found' &&
data.projects.find((p) => p.name === error.data.projectName)
) {
window.location.reload();
}
return;
}
const data = await fetchProjectGraph(
projectGraphDataService,
params,
appConfig
);
if (
isRouteErrorResponse(error) &&
error.data.id === 'project-not-found' &&
data.projects.find((p) => p.name === error.data.projectName)
) {
window.location.reload();
}
},
1000,
watch
@@ -16,7 +16,7 @@ import {
fetchProjectGraph,
getProjectGraphDataService,
useEnvironmentConfig,
useIntervalWhen,
usePoll,
} from '@nx/graph/shared';
import { ProjectDetailsHeader } from './project-details-header';
@@ -35,16 +35,16 @@ export function ProjectDetailsPage() {
const projectGraphDataService = getProjectGraphDataService();
const params = useParams();
useIntervalWhen(
usePoll(
async () => {
fetchProjectGraph(projectGraphDataService, params, appConfig).then(
(data) => {
if (data?.hash !== hash) {
window.location.reload();
}
return;
}
const data = await fetchProjectGraph(
projectGraphDataService,
params,
appConfig
);
if (data?.hash !== hash) {
window.location.reload();
}
},
1000,
watch
@@ -50,7 +50,8 @@ export function ProjectDetailsWrapper({
navigate(
routeConstructor(
`/projects/${encodeURIComponent(data.projectName)}`,
true
true,
['expanded'] // omit expanded targets from search params
)
);
}
@@ -75,7 +76,8 @@ export function ProjectDetailsWrapper({
pathname: `/tasks/${encodeURIComponent(data.targetName)}`,
search: `?projects=${encodeURIComponent(data.projectName)}`,
},
true
true,
['expanded'] // omit expanded targets from search params
)
);
}
@@ -95,9 +97,9 @@ export function ProjectDetailsWrapper({
const updateSearchParams = (
params: URLSearchParams,
targetNames: string[]
targetNames?: string[]
) => {
if (targetNames.length === 0) {
if (!targetNames || targetNames.length === 0) {
params.delete('expanded');
} else {
params.set('expanded', targetNames.join(','));
@@ -118,13 +120,6 @@ export function ProjectDetailsWrapper({
if (collapseAllTargets) {
collapseAllTargets();
}
setSearchParams(
(currentSearchParams) => {
currentSearchParams.delete('expanded');
return currentSearchParams;
},
{ replace: true, preventScrollReset: true }
);
};
}, []); // only run on mount
@@ -132,7 +127,7 @@ export function ProjectDetailsWrapper({
const expandedTargetsParams =
searchParams.get('expanded')?.split(',') || [];
if (expandedTargetsParams.join(',') === expandedTargets.join(',')) {
if (expandedTargetsParams.join(',') === expandedTargets?.join(',')) {
return;
}
+1 -1
View File
@@ -3,7 +3,7 @@ export * from './lib/external-api-service';
export * from './lib/use-environment-config';
export * from './lib/app-config';
export * from './lib/use-route-constructor';
export * from './lib/use-interval-when';
export * from './lib/use-poll';
export * from './lib/project-graph-data-service/get-project-graph-data-service';
export * from './lib/fetch-project-graph';
export * from './lib/error-toast';
-28
View File
@@ -1,28 +0,0 @@
import { useEffect, useRef } from 'react';
export const useIntervalWhen = (
callback: () => void,
delay: number,
condition: boolean
) => {
const savedCallback = useRef(() => {});
useEffect(() => {
if (condition) {
savedCallback.current = callback;
}
}, [callback, condition]);
useEffect(() => {
if (condition) {
const tick = () => {
savedCallback.current();
};
if (delay !== null) {
let id = setInterval(tick, delay);
return () => clearInterval(id);
}
}
}, [delay, condition]);
};
+37
View File
@@ -0,0 +1,37 @@
import { useEffect, useRef } from 'react';
export const usePoll = (
callback: () => Promise<void>,
delay: number,
condition: boolean
) => {
const savedCallback = useRef(() => Promise.resolve());
useEffect(() => {
if (condition) {
savedCallback.current = callback;
}
}, [callback, condition]);
useEffect(() => {
if (!condition) {
return;
}
let timeoutId: NodeJS.Timeout;
async function callTickAfterDelay() {
await savedCallback.current();
if (delay !== null) {
timeoutId = setTimeout(callTickAfterDelay, delay);
}
}
callTickAfterDelay();
return () => {
if (timeoutId) {
clearTimeout(timeoutId);
}
};
}, [delay, condition]);
};
+12 -2
View File
@@ -3,13 +3,23 @@ import { getEnvironmentConfig } from './use-environment-config';
export const useRouteConstructor = (): ((
to: To,
retainSearchParams: boolean
retainSearchParams: boolean,
searchParamsKeysToOmit?: string[]
) => To) => {
const { environment } = getEnvironmentConfig();
const { selectedWorkspaceId } = useParams();
const [searchParams] = useSearchParams();
return (to: To, retainSearchParams: true) => {
return (
to: To,
retainSearchParams: boolean = true,
searchParamsKeysToOmit: string[] = []
) => {
if (searchParamsKeysToOmit?.length) {
searchParamsKeysToOmit.forEach((key) => {
searchParams.delete(key);
});
}
let pathname = '';
if (typeof to === 'object') {
@@ -103,13 +103,10 @@ export function sourcesRenderer(
}
}
return (
<span
className="group/line shrink-1 flex flex min-w-0"
key={`code-group${idx}`}
>
<span className="group/line flex" key={`code-group${idx}`}>
<span>{element}</span>
{sourceElement && (
<span className="shrink-1 inline flex min-w-0 pl-2 opacity-0 transition-opacity duration-150 ease-in-out group-hover/line:opacity-100">
<span className="min-w-0 flex-1 pl-2 opacity-0 transition-opacity duration-150 ease-in-out group-hover/line:opacity-100">
{sourceElement}
</span>
)}
+2 -2
View File
@@ -37,8 +37,8 @@ export class GraphTooltipService {
if (graph.getTaskInputs) {
graph.getTaskInputs(event.data.id).then((inputs) => {
if (
this.currentTooltip.type === 'taskNode' &&
this.currentTooltip.props.id === event.data.id
this.currentTooltip?.type === 'taskNode' &&
this.currentTooltip?.props.id === event.data.id
) {
this.openTaskNodeTooltip(event.ref, {
...event.data,
@@ -835,3 +835,64 @@ export const Cart = {
},
},
};
// We're normalizing `type` from `projectType`, so if projectType is missing we'll fallback to `type`.
// See: packages/nx/src/project-graph/utils/normalize-project-nodes.ts
export const FallbackType = {
args: {
project: {
name: 'mypkg',
type: 'lib',
data: {
root: '.',
name: 'mypkg',
targets: {
echo: {
executor: 'nx:run-script',
metadata: {
scriptContent: 'echo 1',
runCommand: 'npm run echo',
},
options: {
script: 'echo',
},
configurations: {},
},
},
sourceRoot: '.',
implicitDependencies: [],
tags: [],
},
},
sourceMap: {
root: ['nx/core/project-json', 'project.json'],
name: ['nx/core/project-json', 'project.json'],
targets: ['nx/core/package-json', 'project.json'],
'targets.echo': ['nx/core/package-json-workspaces', 'package.json'],
'targets.echo.executor': [
'nx/core/package-json-workspaces',
'package.json',
],
'targets.echo.options': [
'nx/core/package-json-workspaces',
'package.json',
],
'targets.echo.metadata': [
'nx/core/package-json-workspaces',
'package.json',
],
'targets.echo.options.script': [
'nx/core/package-json-workspaces',
'package.json',
],
'targets.echo.metadata.scriptContent': [
'nx/core/package-json-workspaces',
'package.json',
],
'targets.echo.metadata.runCommand': [
'nx/core/package-json-workspaces',
'package.json',
],
},
},
};
@@ -6,7 +6,6 @@ import type { ProjectGraphProjectNode } from '@nx/devkit';
// nx-ignore-next-line
import { GraphError } from 'nx/src/command-line/graph/graph';
/* eslint-enable @nx/enforce-module-boundaries */
import { EyeIcon } from '@heroicons/react/24/outline';
import { PropertyInfoTooltip, Tooltip } from '@nx/graph/ui-tooltips';
import { TooltipTriggerText } from '../target-configuration-details/tooltip-trigger-text';
@@ -29,6 +28,12 @@ export interface ProjectDetailsProps {
viewInProjectGraphPosition?: 'top' | 'bottom';
}
const typeToProjectType = {
app: 'Application',
lib: 'Library',
e2e: 'E2E',
};
export const ProjectDetails = ({
project,
sourceMap,
@@ -41,11 +46,6 @@ export const ProjectDetails = ({
const projectData = project.data;
const isCompact = variant === 'compact';
const displayType =
projectData.projectType &&
projectData.projectType?.charAt(0)?.toUpperCase() +
projectData.projectType?.slice(1);
const technologies = [
...new Set(
[
@@ -98,24 +98,33 @@ export const ProjectDetails = ({
</div>
<div className="flex justify-between py-2">
<div>
{projectData.metadata?.description ? (
<p className="mb-2 text-sm capitalize text-gray-500 dark:text-slate-400">
{projectData.metadata?.description}
</p>
) : null}
{projectData.tags && projectData.tags.length ? (
<p>
<span className="inline-block w-10 font-medium">Tags:</span>
<span className="font-medium">Tags:</span>
{projectData.tags?.map((tag) => (
<span className="ml-2 font-mono">
<span className="ml-2 font-mono lowercase">
<Pill text={tag} />
</span>
))}
</p>
) : null}
<p>
<span className="inline-block w-10 font-medium">Root:</span>
<span className="font-mono"> {projectData.root}</span>
</p>
{displayType ? (
{projectData.root ? (
<p>
<span className="inline-block w-10 font-medium">Type:</span>
<span className="font-mono"> {displayType}</span>
<span className="font-medium">Root:</span>
<span className="font-mono"> {projectData.root.trim()}</span>
</p>
) : null}
{projectData.projectType ?? typeToProjectType[project.type] ? (
<p>
<span className="font-medium">Type:</span>
<span className="ml-2 font-mono capitalize">
{projectData.projectType ?? typeToProjectType[project.type]}
</span>
</p>
) : null}
</div>
@@ -5,6 +5,7 @@ import type { ProjectGraphProjectNode } from '@nx/devkit';
import { TargetConfigurationDetailsListItem } from '../target-configuration-details-list-item/target-configuration-details-list-item';
import { TargetConfigurationGroupContainer } from '../target-configuration-details-group-container/target-configuration-details-group-container';
import { groupTargets } from '../utils/group-targets';
import { useMemo } from 'react';
export interface TargetConfigurationGroupListProps {
project: ProjectGraphProjectNode;
@@ -26,19 +27,54 @@ export function TargetConfigurationGroupList({
onViewInTaskGraph,
className = '',
}: TargetConfigurationGroupListProps) {
const targetsGroup = groupTargets(project);
const targetsGroup = useMemo(() => groupTargets(project), [project]);
const hasGroups = useMemo(() => {
for (const group of Object.entries(targetsGroup.groups)) {
if (group[1]?.length > 0) return true;
}
return false;
}, [targetsGroup]);
return (
<>
{Object.entries(targetsGroup.groups).map(([targetGroupName, targets]) => {
return (
<TargetConfigurationGroupContainer
targetGroupName={targetGroupName}
targetsNumber={targets.length}
key={targetGroupName}
>
<ul className={className}>
{targets.map((targetName) => (
if (hasGroups) {
return (
<>
{Object.entries(targetsGroup.groups).map(
([targetGroupName, targets]) => {
if (targets.length === 0) {
return null;
}
return (
<TargetConfigurationGroupContainer
targetGroupName={targetGroupName}
targetsNumber={targets.length}
key={targetGroupName}
>
<ul className={className}>
{targets.map((targetName) => (
<TargetConfigurationDetailsListItem
project={project}
sourceMap={sourceMap}
variant={variant}
onRunTarget={onRunTarget}
onViewInTaskGraph={onViewInTaskGraph}
targetName={targetName}
collapsable={true}
key={targetName}
/>
))}
</ul>
</TargetConfigurationGroupContainer>
);
}
)}
<TargetConfigurationGroupContainer
targetGroupName="Others"
targetsNumber={targetsGroup.targets.length}
key="others-group"
>
<ul className={`p-2 ${className}`}>
{targetsGroup.targets.map((targetName) => {
return (
<TargetConfigurationDetailsListItem
project={project}
sourceMap={sourceMap}
@@ -49,12 +85,15 @@ export function TargetConfigurationGroupList({
collapsable={true}
key={targetName}
/>
))}
</ul>
</TargetConfigurationGroupContainer>
);
})}
<ul className={`mt-8 p-2 ${className}`}>
);
})}
</ul>
</TargetConfigurationGroupContainer>
</>
);
} else {
return (
<ul className={className}>
{targetsGroup.targets.map((targetName) => {
return (
<TargetConfigurationDetailsListItem
@@ -70,6 +109,6 @@ export function TargetConfigurationGroupList({
);
})}
</ul>
</>
);
);
}
}
@@ -129,14 +129,15 @@ export const TargetConfigurationDetailsHeader = ({
// TODO: fix tooltip overflow in collapsed state
data-tooltip={isCollasped ? false : 'View in Task Graph'}
data-tooltip-align-right
onClick={(e) => {
if (isCollasped) {
return;
}
e.stopPropagation();
onViewInTaskGraph({ projectName, targetName });
}}
>
<EyeIcon
className={`h-5 w-5 !cursor-pointer`}
onClick={(e) => {
e.stopPropagation();
onViewInTaskGraph({ projectName, targetName });
}}
/>
<EyeIcon className={`h-5 w-5 !cursor-pointer`} />
</button>
)}
@@ -50,7 +50,7 @@ export function ProjectNodeToolTip({
)}
</h4>
{tags.length > 0 ? (
<p className="my-2">
<p className="my-2 lowercase">
<strong>tags</strong>
<br></br>
{tags.join(', ')}
+1 -1
View File
@@ -138,7 +138,7 @@ export function Tooltip({
width: 'max-content',
...animationStyles,
}}
className="z-10 min-w-[250px] rounded-md border border-slate-500"
className="z-10 min-w-[250px] max-w-prose rounded-md border border-slate-500"
{...getFloatingProps()}
>
{showTooltipArrow && (
+28
View File
@@ -1081,6 +1081,34 @@ const decisionsSection = {
// Blog post redirects
const blogPosts = {
'/blog/2024-05-07-nx-19-release': '/blog/2024-05-08-nx-19-release',
'/blog/2024-05-08-nx-19-release': '/blog/nx-19-release',
'/blog/2024-04-19-manage-your-gradle':
'/blog/manage-your-gradle-project-using-nx',
'/blog/2024-03-21-reliable-ci':
'/blog/reliable-ci-a-new-execution-model-fixing-both-flakiness-and-slowness',
'/blog/2024-03-20-why-speed-matters': '/blog/monorepos-why-speed-matters',
'/blog/2024-02-15-launch-week-recap': '/blog/launch-nx-week-recap',
'/blog/2024-02-09-versioning-and-releasing-packages':
'/blog/versioning-and-releasing-packages-in-a-monorepo',
'/blog/2024-02-07-fast-effortless-ci': '/blog/fast-effortless-ci',
'/blog/2024-02-06-nuxt-js-support-in-nx':
'/blog/introducing-nx-nuxt-enhanced-nuxt-js-support-in-nx',
'/blog/2024-02-05-nx-18-project-crystal':
'/blog/what-if-nx-plugins-were-more-like-vscode-extensions',
'/blog/2023-12-28-highlights-2023': '/blog/nx-highlights-of-2023',
'/blog/2023-12-20-nx-17-2-release': '/blog/nx-17-2-release',
'/blog/2023-11-22-unit-testing-expo':
'/blog/unit-testing-expo-apps-with-jest',
'/blog/2023-11-21-ai-assistant': '/blog/nx-docs-ai-assistant',
'/blog/2023-11-08-state-management':
'/blog/state-management-nx-react-native-expo-apps-with-tanstack-query-and-redux',
'/blog/2023-10-20-nx-17-release': '/blog/nx-17-release',
'/blog/2023-10-13-nx-conf-2023-recap': '/blog/nx-conf-2023-recap',
'/blog/2023-09-25-nx-raises': '/blog/nx-raises-16m-series-a',
'/blog/2023-08-15-qwikify-your-dev': '/blog/qwikify-your-development-with-nx',
'/blog/2023-06-29-nx-console-gets-lit': '/blog/nx-console-gets-lit',
'/blog/2023-04-19-nx-cloud-3':
'/blog/nx-cloud-3-0-faster-more-efficient-modernized',
};
/**
@@ -8,7 +8,7 @@ export function AnnouncementBanner(): JSX.Element {
<p className="text-sm font-medium">
<span className="md:hidden">
<Link
href="https://monorepo.tools/conf?utm_source=nx.dev"
href="https://monorepo.world?utm_source=nx.dev"
className="underline"
>
Monorepo World: October 7, 2024
@@ -21,7 +21,7 @@ export function AnnouncementBanner(): JSX.Element {
</span>
<span className="ml-2 inline-block">
<Link
href="https://monorepo.tools/conf?utm_source=nx.dev"
href="https://monorepo.world?utm_source=nx.dev"
className="font-semibold text-blue-500 underline dark:text-sky-500"
>
<span className="absolute inset-0" aria-hidden="true" />
@@ -207,7 +207,7 @@ export const eventItems: MenuItem[] = [
name: 'Monorepo World',
description:
'In person & virtual conference about the latest monorepo advancements.',
href: 'https://monorepo.tools/conf',
href: 'https://monorepo.world',
icon: null,
isNew: false,
isHighlight: false,
@@ -7,4 +7,19 @@ describe('heading schema: generateID', () => {
'pro-simple-setup'
);
});
it('should create id for code based headers', () => {
const codeHeader = [
{
$$mdtype: 'Tag',
name: 'code',
attributes: {},
children: ['launch-templates.<template-name>.init-steps[*].env'],
},
];
expect(generateID(codeHeader, {})).toEqual(
'launchtemplatestemplatenameinitstepsenv'
);
});
});
@@ -7,8 +7,31 @@ export function generateID(
if (attributes['id'] && typeof attributes['id'] === 'string') {
return attributes['id'];
}
return children
.filter((child) => typeof child === 'string')
const validChildrenNodes: RenderableTreeNode[] = [];
for (const child of children) {
if (!child) {
continue;
}
if (typeof child === 'string') {
validChildrenNodes.push(child);
} else if (
// allow rendering titles that are wrapped in `code` tags
typeof child === 'object' &&
'children' in child &&
child.name === 'code' &&
Array.isArray(child.children)
) {
const validNestedChild = child.children.filter(
(c) => typeof c === 'string'
);
validChildrenNodes.push(...validNestedChild);
}
}
return validChildrenNodes
.join(' ')
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
+5 -6
View File
@@ -59,9 +59,8 @@
"@nestjs/schematics": "^9.1.0",
"@nestjs/swagger": "^6.0.0",
"@nestjs/testing": "^9.0.0",
"@ngrx/effects": "17.0.1",
"@ngrx/router-store": "17.0.1",
"@ngrx/store": "17.0.1",
"@ngrx/router-store": "^18.0.0",
"@ngrx/store": "^18.0.0",
"@nuxt/kit": "^3.10.0",
"@nuxt/schema": "^3.10.0",
"@nx/angular": "19.2.0-rc.0",
@@ -161,8 +160,8 @@
"cz-git": "^1.4.0",
"czg": "^1.4.0",
"detect-port": "^1.5.1",
"dotenv": "~16.3.1",
"dotenv-expand": "^10.0.0",
"dotenv": "~16.4.5",
"dotenv-expand": "~11.0.6",
"ejs": "^3.1.7",
"enhanced-resolve": "^5.8.3",
"esbuild": "0.19.5",
@@ -250,7 +249,7 @@
"react-markdown": "^8.0.7",
"react-redux": "8.0.5",
"react-refresh": "^0.10.0",
"react-router-dom": "^6.21.2",
"react-router-dom": "^6.23.1",
"react-textarea-autosize": "^8.5.3",
"regenerator-runtime": "0.13.7",
"resolve.exports": "1.1.0",
+12
View File
@@ -1921,6 +1921,18 @@
"alwaysAddToPackageJson": false
}
}
},
"19.4.0-ngrx": {
"version": "19.4.0-beta.1",
"requires": {
"@angular/core": "^18.0.0"
},
"packages": {
"@ngrx/store": {
"version": "^18.0.0",
"alwaysAddToPackageJson": false
}
}
}
}
}
@@ -67,13 +67,16 @@ export async function buildStaticRemotes(
}
});
staticProcess.stderr.on('data', (data) => logger.info(data.toString()));
staticProcess.on('exit', (code) => {
staticProcess.once('exit', (code) => {
stdoutStream.end();
staticProcess.stdout.removeAllListeners('data');
staticProcess.stderr.removeAllListeners('data');
if (code !== 0) {
throw new Error(
`Remote failed to start. A complete log can be found in: ${remoteBuildLogFile}`
);
}
res();
});
process.on('SIGTERM', () => staticProcess.kill('SIGTERM'));
process.on('exit', () => staticProcess.kill('SIGTERM'));
@@ -14,8 +14,7 @@ import { loadEsmModule } from './module-loader';
async function readDefaultTsConfig(fileName: string) {
// these options are mandatory
const extraOptions: ts.CompilerOptions = {
target: ts.ScriptTarget.ES2020,
experimentalDecorators: true,
target: ts.ScriptTarget.ES2022,
// sourcemaps
sourceMap: false,
@@ -25,7 +24,7 @@ async function readDefaultTsConfig(fileName: string) {
outDir: '',
declaration: true,
// ng compiler to options
// ng compiler
enableResourceInlining: true,
// these are required to set the appropriate EmitFlags
@@ -52,6 +52,18 @@ describe('app migrator', () => {
jest.clearAllMocks();
});
it('should not migrate project when validation fails', async () => {
// add project with no root
const project = addProject('app1', {} as any);
const migrator = new AppMigrator(tree, {}, project);
await migrator.migrate();
expect(tree.exists('apps/app1/project.json')).toBe(false);
const { projects } = readJson(tree, 'angular.json');
expect(projects.app1).toBeDefined();
});
describe('validation', () => {
it('should fail validation when the project root is not specified', async () => {
const project = addProject('app1', {} as any);
@@ -103,12 +103,12 @@ export class AppMigrator extends ProjectMigrator<SupportedTargets> {
}
override async migrate(): Promise<void> {
await super.migrate();
if (this.skipMigration === true) {
return;
}
await super.migrate();
this.updateProjectConfiguration();
await this.e2eMigrator.migrate();
@@ -50,6 +50,18 @@ describe('lib migrator', () => {
jest.clearAllMocks();
});
it('should not migrate project when validation fails', async () => {
// add project with no root
const project = addProject('lib1', {} as any);
const migrator = new LibMigrator(tree, {}, project);
await migrator.migrate();
expect(tree.exists('libs/lib1/project.json')).toBe(false);
const { projects } = readJson(tree, 'angular.json');
expect(projects.lib1).toBeDefined();
});
describe('validation', () => {
it('should fail validation when the project root is not specified', async () => {
const project = addProject('lib1', {} as any);
@@ -41,12 +41,12 @@ export class LibMigrator extends ProjectMigrator {
}
override async migrate(): Promise<void> {
await super.migrate();
if (this.skipMigration === true) {
return;
}
await super.migrate();
await this.updateProjectConfiguration();
this.moveProjectFiles();
@@ -1,4 +1,4 @@
import * as chalk from 'chalk';
import chalk = require('chalk');
import {
arrayToString,
getProjectValidationResultMessage,
@@ -1,4 +1,4 @@
import * as chalk from 'chalk';
import chalk = require('chalk');
import type { ValidationError } from './types';
export function arrayToString(array: string[]): string {
@@ -67,7 +67,7 @@ function updateConfig(config: {
browserTarget?: string;
buildTarget?: string;
}): void {
if (config.browserTarget) {
if (config && config.browserTarget) {
config.buildTarget ??= config.browserTarget;
delete config.browserTarget;
}
+1
View File
@@ -14,6 +14,7 @@ export {
addProviderToAppConfig,
addProviderToComponent,
addProviderToModule,
addViewProviderToComponent,
} from './nx-devkit/ast-utils';
export { addRoute, addProviderToRoute } from './nx-devkit/route-utils';
@@ -5,6 +5,7 @@ import {
addImportToPipe,
addProviderToAppConfig,
addProviderToBootstrapApplication,
addViewProviderToComponent,
isStandalone,
} from './ast-utils';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
@@ -334,4 +335,50 @@ export const appConfig: ApplicationConfig = {
};"
`);
});
it('should add view provider to a component', () => {
// ARRANGE
const pathToComponent = 'app.component.ts';
const componentOriginal = `import { Component } from '@angular/core';
@Component({
selector: 'app-app',
template: ''
})
export class AppComponent {}
`;
const providerName = 'MyViewProvider';
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
tree.write(pathToComponent, componentOriginal);
const tsSourceFile = createSourceFile(
pathToComponent,
componentOriginal,
ScriptTarget.Latest,
true
);
// ACT
addViewProviderToComponent(
tree,
tsSourceFile,
pathToComponent,
providerName
);
// ASSERT
expect(tree.read(pathToComponent, 'utf-8')).toMatchInlineSnapshot(`
"import { Component } from '@angular/core';
@Component({
selector: 'app-app',
template: '',
viewProviders: [MyViewProvider]
})
export class AppComponent {}
"
`);
});
});
@@ -826,6 +826,29 @@ export function addProviderToComponent(
);
}
/**
* Add a view provider to a Standalone Component
* @param host Virtual Tree
* @param source TS Source File containing the Component
* @param componentPath Path to the Component
* @param symbolName The provider to add
*/
export function addViewProviderToComponent(
host: Tree,
source: ts.SourceFile,
componentPath: string,
symbolName: string
): ts.SourceFile {
return _addSymbolToDecoratorMetadata(
host,
source,
componentPath,
'viewProviders',
symbolName,
'Component'
);
}
export function addDeclarationToModule(
host: Tree,
source: ts.SourceFile,
+1 -1
View File
@@ -3,7 +3,7 @@ export const nxVersion = require('../../package.json').version;
export const angularVersion = '~18.0.0';
export const angularDevkitVersion = '~18.0.0';
export const ngPackagrVersion = '~18.0.0';
export const ngrxVersion = '~17.0.0';
export const ngrxVersion = '^18.0.0';
export const rxjsVersion = '~7.8.0';
export const zoneJsVersion = '~0.14.3';
export const angularJsVersion = '1.7.9';
@@ -283,28 +283,18 @@ async function normalizeArgsMiddleware(
const packageManager = await determinePackageManager(argv);
const defaultBase = await determineDefaultBase(argv);
if (process.env.NX_NEW_CLOUD_ONBOARDING === 'true') {
const nxCloud =
argv.skipGit === true ? 'skip' : await determineNxCloud(argv);
const useGitHub =
nxCloud === 'skip'
? undefined
: nxCloud === 'github' ||
(await determineIfGitHubWillBeUsed(nxCloud));
Object.assign(argv, {
nxCloud,
useGitHub,
packageManager,
defaultBase,
});
} else {
const nxCloud = await determineNxCloud(argv);
Object.assign(argv, {
nxCloud,
packageManager,
defaultBase,
});
}
const nxCloud =
argv.skipGit === true ? 'skip' : await determineNxCloud(argv);
const useGitHub =
nxCloud === 'skip'
? undefined
: nxCloud === 'github' || (await determineIfGitHubWillBeUsed(nxCloud));
Object.assign(argv, {
nxCloud,
useGitHub,
packageManager,
defaultBase,
});
} catch (e) {
console.error(e);
process.exit(1);
@@ -5,7 +5,7 @@ import { createSandbox } from './create-sandbox';
import { createEmptyWorkspace } from './create-empty-workspace';
import { createPreset } from './create-preset';
import { setupCI } from './utils/ci/setup-ci';
import { initializeGitRepo } from './utils/git/git';
import { commitChanges, initializeGitRepo } from './utils/git/git';
import { getPackageNameFromThirdPartyPreset } from './utils/preset/get-third-party-preset';
import { mapErrorToBodyLines } from './utils/error-utils';
@@ -51,27 +51,11 @@ export async function createWorkspace<T extends CreateWorkspaceOptions>(
);
}
let nxCloudInstallRes;
if (nxCloud !== 'skip') {
nxCloudInstallRes = await setupNxCloud(
directory,
packageManager,
nxCloud,
useGitHub
);
if (nxCloud !== 'yes') {
await setupCI(
directory,
nxCloud,
packageManager,
nxCloudInstallRes?.code === 0
);
}
}
let gitSuccess = false;
if (!skipGit && commit) {
try {
await initializeGitRepo(directory, { defaultBase, commit });
gitSuccess = true;
} catch (e) {
if (e instanceof Error) {
output.error({
@@ -84,6 +68,28 @@ export async function createWorkspace<T extends CreateWorkspaceOptions>(
}
}
let nxCloudInstallRes;
if (nxCloud !== 'skip') {
nxCloudInstallRes = await setupNxCloud(
directory,
packageManager,
nxCloud,
useGitHub
);
if (nxCloud !== 'yes') {
const nxCIsetupRes = await setupCI(
directory,
nxCloud,
packageManager,
nxCloudInstallRes?.code === 0
);
if (nxCIsetupRes?.code === 0) {
commitChanges(directory, `feat(nx): Generated CI workflow`);
}
}
}
return {
nxCloudInfo: nxCloudInstallRes?.stdout,
directory,
@@ -84,3 +84,19 @@ export async function initializeGitRepo(
await execute(['commit', `-m "${message}"`]);
}
}
export function commitChanges(directory: string, message: string) {
try {
execSync('git add -A', { encoding: 'utf8', stdio: 'pipe', cwd: directory });
execSync('git commit --no-verify -F -', {
encoding: 'utf8',
stdio: 'pipe',
input: message,
cwd: directory,
});
} catch (e) {
console.error(`There was an error committing your Nx Cloud token.\n
Please commit the changes manually and push to your new repository.\n
\n${e}`);
}
}
@@ -16,13 +16,11 @@ export async function setupNxCloud(
try {
const pmc = getPackageManagerCommand(packageManager);
const res = await execAndWait(
process.env.NX_NEW_CLOUD_ONBOARDING === 'true'
? `${
pmc.exec
} nx g nx:connect-to-nx-cloud --installationSource=create-nx-workspace ${
useGitHub ? '--github' : ''
} --no-interactive`
: `${pmc.exec} nx g nx:connect-to-nx-cloud --no-interactive --quiet`,
`${
pmc.exec
} nx g nx:connect-to-nx-cloud --installationSource=create-nx-workspace --directory=${directory} ${
useGitHub ? '--github' : ''
} --no-interactive`,
directory
);
+1 -1
View File
@@ -5,7 +5,7 @@
"init": {
"factory": "./src/generators/init/init#cypressInitGeneratorInternal",
"schema": "./src/generators/init/schema.json",
"description": "Initialize the `@nrwl/cypress` plugin.",
"description": "Initialize the `@nx/cypress` plugin.",
"aliases": ["ng-add"],
"hidden": true
},
+1 -1
View File
@@ -6,7 +6,7 @@
"init": {
"factory": "./src/generators/init/init#detoxInitGeneratorInternal",
"schema": "./src/generators/init/schema.json",
"description": "Initialize the `@nrwl/detox` plugin.",
"description": "Initialize the `@nx/detox` plugin.",
"hidden": true
},
"application": {
+1 -1
View File
@@ -5,7 +5,7 @@
"init": {
"factory": "./src/generators/init/init#esbuildInitGenerator",
"schema": "./src/generators/init/schema.json",
"description": "Initialize the `@nrwl/esbuild` plugin.",
"description": "Initialize the `@nx/esbuild` plugin.",
"aliases": ["ng-add"],
"hidden": true
},
@@ -2,7 +2,7 @@ import { joinPathFragments, type ExecutorContext } from '@nx/devkit';
import type { ESLint } from 'eslint';
import { mkdirSync, writeFileSync } from 'fs';
import { interpolate } from 'nx/src/tasks-runner/utils';
import { dirname, posix, resolve } from 'path';
import { dirname, posix, relative, resolve } from 'path';
import { findFlatConfigFile, findOldConfigFile } from '../../utils/config-file';
import type { Schema } from './schema';
import { resolveAndInstantiateESLint } from './utility/eslint-utils';
@@ -45,10 +45,7 @@ export default async function run(
// the flat config would be resolved starting from the cwd, which we changed to the workspace root
// so we explicitly set the config path to the flat config file path we previously found
if (hasFlatConfig && !normalizedOptions.eslintConfig) {
normalizedOptions.eslintConfig = posix.relative(
systemRoot,
flatConfigFilePath
);
normalizedOptions.eslintConfig = relative(systemRoot, flatConfigFilePath);
}
/**
@@ -1,5 +1,6 @@
import {
addDependenciesToPackageJson,
GeneratorCallback,
joinPathFragments,
offsetFromRoot,
ProjectConfiguration,
@@ -15,7 +16,7 @@ import {
getGlobalFlatEslintConfiguration,
} from './global-eslint-config';
import { useFlatConfig } from '../../utils/flat-config';
import { eslintVersion } from '../../utils/versions';
import { eslintVersion, nxVersion } from '../../utils/versions';
import {
addBlockToFlatConfigExport,
addImportToFlatConfig,
@@ -31,7 +32,7 @@ export function migrateConfigToMonorepoStyle(
tree: Tree,
unitTestRunner: string,
keepExistingVersions?: boolean
): void {
): GeneratorCallback {
const rootEslintConfig = findEslintFile(tree);
let skipCleanup = false;
if (
@@ -105,6 +106,14 @@ export function migrateConfigToMonorepoStyle(
}
}
});
return addDependenciesToPackageJson(
tree,
{},
{
'@nx/eslint-plugin': nxVersion,
}
);
}
export function findLintTarget(
@@ -0,0 +1,92 @@
import {
addProjectConfiguration,
ProjectGraph,
readJson,
Tree,
} from '@nx/devkit';
import { Linter } from '../utils/linter';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { lintProjectGenerator } from './lint-project';
let projectGraph: ProjectGraph;
jest.mock('@nx/devkit', () => ({
...jest.requireActual<any>('@nx/devkit'),
createProjectGraphAsync: jest
.fn()
.mockImplementation(async () => projectGraph),
}));
describe('@nx/eslint:lint-project (convert to monorepo style)', () => {
let tree: Tree;
const defaultOptions = {
skipFormat: false,
addPlugin: true,
};
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
const rootpkg = {
root: '.',
projectType: 'library' as const,
targets: {
'eslint:lint': {
executor: 'nx:run-commands',
options: {
command: 'eslint .',
},
},
},
};
projectGraph = {
nodes: {
rootpkg: {
type: 'lib',
name: 'rootpkg',
data: rootpkg,
},
},
dependencies: {},
};
addProjectConfiguration(tree, 'rootpkg', rootpkg);
tree.write(
'.eslintrc.cjs',
`
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
}
`
);
});
it('should generate a eslint config and configure the target in project configuration', async () => {
addProjectConfiguration(tree, 'nestedpkg', {
root: 'nestedpkg',
projectType: 'library',
targets: {},
});
await lintProjectGenerator(tree, {
...defaultOptions,
linter: Linter.EsLint,
project: 'nestedpkg',
setParserOptionsProject: false,
});
expect(readJson(tree, 'package.json')).toMatchObject({
devDependencies: {
'@nx/eslint-plugin': expect.any(String),
},
});
});
});
@@ -1,16 +1,16 @@
import {
createProjectGraphAsync,
formatFiles,
GeneratorCallback,
NxJsonConfiguration,
offsetFromRoot,
ProjectConfiguration,
ProjectGraph,
Tree,
readNxJson,
formatFiles,
offsetFromRoot,
readJson,
readNxJson,
readProjectConfiguration,
runTasksInSerial,
Tree,
updateJson,
updateProjectConfiguration,
writeJson,
@@ -21,10 +21,7 @@ import { findEslintFile } from '../utils/eslint-file';
import { join } from 'path';
import { lintInitGenerator } from '../init/init';
import type { Linter } from 'eslint';
import {
findLintTarget,
migrateConfigToMonorepoStyle,
} from '../init/init-migration';
import { migrateConfigToMonorepoStyle } from '../init/init-migration';
import { getProjects } from 'nx/src/generators/utils/project-configuration';
import { useFlatConfig } from '../../utils/flat-config';
import {
@@ -36,7 +33,6 @@ import {
import {
baseEsLintConfigFile,
baseEsLintFlatConfigFile,
ESLINT_CONFIG_FILENAMES,
} from '../../utils/config-file';
import { hasEslintPlugin } from '../utils/plugin';
import { setupRootEsLint } from './setup-root-eslint';
@@ -144,12 +140,13 @@ export async function lintProjectGeneratorInternal(
filteredProjects.push(project);
}
});
migrateConfigToMonorepoStyle(
const migrateTask = migrateConfigToMonorepoStyle(
filteredProjects,
tree,
options.unitTestRunner,
options.keepExistingVersions
);
tasks.push(migrateTask);
}
}
+2 -4
View File
@@ -100,8 +100,7 @@ function buildExpoTargets(
const targets: Record<string, TargetConfiguration> = {
[options.startTargetName]: {
command: `expo start`,
options: { cwd: projectRoot },
executor: `@nx/expo:start`,
},
[options.serveTargetName]: {
command: `expo start --web`,
@@ -124,8 +123,7 @@ function buildExpoTargets(
outputs: [getOutputs(projectRoot, 'dist')],
},
[options.installTargetName]: {
command: `expo install`,
options: { cwd: workspaceRoot }, // install at workspace root
executor: '@nx/expo:install',
},
[options.prebuildTargetName]: {
executor: `@nx/expo:prebuild`,

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