diff --git a/.github/PULL_REQUEST_TEMPLATE/COMMUNITY_PLUGIN.MD b/.github/PULL_REQUEST_TEMPLATE/COMMUNITY_PLUGIN.MD index e344666bc5519..bb74db7c12361 100644 --- a/.github/PULL_REQUEST_TEMPLATE/COMMUNITY_PLUGIN.MD +++ b/.github/PULL_REQUEST_TEMPLATE/COMMUNITY_PLUGIN.MD @@ -5,6 +5,27 @@ _[Please make sure you have read the submission guidelines before posting an PR] Thanks for submitting your Nx Plugin to our community plugins list. Make sure to follow these steps to ensure that your PR is approved in a timely manner. +## Plugin Requirements + +Before you submit your plugin to be listed in our registry, it needs to meet the following requirements: +- Run some kind of automated e2e tests in your repository +- Include `@nx/devkit` as a `dependency` in the plugin's `package.json` +- List a `repository.url` in the plugin's `package.json` + +i.e. + +``` +{ + "repository": { + "type": "git", + "url": "https://github.com/nrwl/nx.git", + "directory": "packages/web" + } +} +``` + +Note: We reserve the right to remove unmaintained plugins from the registry. If the plugins become maintained again, they can be resubmitted to the registry. + ## Steps to Submit Your Plugin - Use the following commit message template: `chore(core): nx plugin submission [PLUGIN_NAME]` - Update the `community/approved-plugins.json` file with a new entry for your plugin that includes `name`, `url`, `description`: @@ -21,7 +42,7 @@ Example: }] ``` -Once merged, your will plugin will be available when running the `nx list` command, and will also be available in the Plugin browser on [nx.dev](https://nx.dev) +Once merged, your plugin will be available when running the `nx list` command, and will also be available in the Plugin Registry on [nx.dev](https://nx.dev/extending-nx/registry) --> # Community Plugin Submission diff --git a/community/approved-plugins.json b/community/approved-plugins.json index 548d8c90a1ec3..232f755b1a05c 100644 --- a/community/approved-plugins.json +++ b/community/approved-plugins.json @@ -25,14 +25,24 @@ "url": "https://github.com/nxkit/nxkit" }, { - "name": "nx-plugins", - "description": "Nx plugin integrations with ESBuild / Vite / Snowpack / Prisma, with derived ESBuild / Snowpack / ... plugins.", + "name": "nx-plugin-esbuild", + "description": "Nx plugin integrations with ESBuild.", "url": "https://nx-plugins.netlify.app/" }, { - "name": "@codebrew/nx-aws-cdk", - "description": "An Nx plugin for aws cdk develop.", - "url": "https://github.com/codebrewlab/nx-plugins/tree/main/packages/nx-aws-cdk" + "name": "nx-plugin-vite", + "description": "Nx plugin integrations with Vite.", + "url": "https://nx-plugins.netlify.app/" + }, + { + "name": "nx-plugin-snowpack", + "description": "Nx plugin integrations with Snowpack.", + "url": "https://nx-plugins.netlify.app/" + }, + { + "name": "nx-plugin-prisma", + "description": "Nx plugin integrations with Snowpack.", + "url": "https://nx-plugins.netlify.app/" }, { "name": "@ago-dev/nx-aws-cdk-v2", @@ -74,21 +84,11 @@ "description": "An Nx plugin for developing cross-platform applications using Capacitor", "url": "https://github.com/nxext/nx-extensions/tree/main/packages/capacitor" }, - { - "name": "@nxtend/firebase", - "description": "An Nx plugin for developing applications using Firebase", - "url": "https://github.com/nxtend-team/nxtend/tree/main/packages/firebase" - }, { "name": "@angular-architects/ddd", "description": "Nx plugin for structuring a monorepo with domains and layers", "url": "https://github.com/angular-architects/nx-ddd-plugin" }, - { - "name": "@offeringsolutions/nx-karma-to-jest", - "description": "Nx plugin for replacing karma with jest in an Nx workspace", - "url": "https://github.com/FabianGosebrink/nx-karma-to-jest" - }, { "name": "@flowaccount/nx-serverless", "description": "Nx plugin for node/angular-universal schematics and deployment builders in an Nx workspace", @@ -109,21 +109,6 @@ "description": "Nx plugin to run playwright e2e tests in an Nx workspace", "url": "https://github.com/Bielik20/nx-plugins/tree/master/packages/nx-playwright" }, - { - "name": "@dev-thought/nx-deploy-it", - "description": "Nx plugin to deploy applications on your favorite cloud provider", - "url": "https://github.com/Dev-Thought/nx-plugins/tree/master/libs/nx-deploy-it" - }, - { - "name": "@offeringsolutions/nx-protractor-to-cypress", - "description": "Nx plugin to replace protractor with cypress in an nx workspace", - "url": "https://github.com/FabianGosebrink/nx-protractor-to-cypress" - }, - { - "name": "@angular-custom-builders/lite-serve", - "description": "Nx plugin to run the e2e test on an existing dist folder", - "url": "https://github.com/mauriziovitale/angular-plugins/tree/master/libs/lite-serve" - }, { "name": "@nx-plus/nuxt", "description": "Nx plugin adding first class support for Nuxt in your Nx workspace.", @@ -235,7 +220,7 @@ "url": "https://github.com/trafilea/nx-shopify" }, { - "name": "nx-dotnet", + "name": "@nx-dotnet/core", "description": "Nx plugin for developing and housing .NET projects within an Nx workspace.", "url": "https://github.com/nx-dotnet/nx-dotnet" }, diff --git a/docs/shared/plugins/maintain-published-plugin.md b/docs/shared/plugins/maintain-published-plugin.md index 0bd0b5419c4c2..8de512b25418a 100644 --- a/docs/shared/plugins/maintain-published-plugin.md +++ b/docs/shared/plugins/maintain-published-plugin.md @@ -19,7 +19,27 @@ After that, you can then install your plugin like any other npm package, ## List your Nx Plugin -Nx provides a utility (`nx list`) that lists both core and community plugins. To submit your plugin, please follow the steps below: +Nx provides a utility (`nx list`) that lists both core and community plugins. You can submit your plugin to be added to this list, but it needs to meet a few criteria first: + +- Run some kind of automated e2e tests in your repository +- Include `@nx/devkit` as a `dependency` in the plugin's `package.json` +- List a `repository.url` in the plugin's `package.json` + +```jsonc {% fileName="package.json" %} +{ + "repository": { + "type": "git", + "url": "https://github.com/nrwl/nx.git", + "directory": "packages/web" + } +} +``` + +{% callout type="warning" title="Unmaintained Plugins" %} +We reserve the right to remove unmaintained plugins from the registry. If the plugins become maintained again, they can be resubmitted to the registry. +{% /callout %} + +Once those criteria are met, you can submit your plugin by following the steps below: - Fork the [Nx repo](https://github.com/nrwl/nx/fork) (if you haven't already) - Update the [`community/approved-plugins.json` file](https://github.com/nrwl/nx/blob/master/community/approved-plugins.json) with a new entry for your plugin that includes name, url and description diff --git a/nx-dev/nx-dev/pages/extending-nx/quality-indicators.json b/nx-dev/nx-dev/pages/extending-nx/quality-indicators.json new file mode 100644 index 0000000000000..28a67c9fd1ca6 --- /dev/null +++ b/nx-dev/nx-dev/pages/extending-nx/quality-indicators.json @@ -0,0 +1,676 @@ +{ + "@nx/angular": { + "lastPublishedDate": "2023-07-31T13:26:25.163Z", + "npmDownloads": 451513, + "githubStars": 18547 + }, + "@nx/cypress": { + "lastPublishedDate": "2023-07-31T13:26:10.027Z", + "npmDownloads": 1206854, + "githubStars": 18547 + }, + "@nx/detox": { + "lastPublishedDate": "2023-07-31T13:26:44.703Z", + "npmDownloads": 74541, + "githubStars": 18547 + }, + "@nx/devkit": { + "lastPublishedDate": "2023-07-31T13:25:14.034Z", + "npmDownloads": 4620584, + "githubStars": 18547 + }, + "@nx/esbuild": { + "lastPublishedDate": "2023-07-31T13:25:35.264Z", + "npmDownloads": 229089, + "githubStars": 18547 + }, + "@nx/eslint-plugin": { + "lastPublishedDate": "2023-07-31T13:25:37.806Z", + "npmDownloads": 1588081, + "githubStars": 18547 + }, + "@nx/expo": { + "lastPublishedDate": "2023-07-31T13:26:57.711Z", + "npmDownloads": 28596, + "githubStars": 18547 + }, + "@nx/express": { + "lastPublishedDate": "2023-07-31T13:26:32.209Z", + "npmDownloads": 141777, + "githubStars": 18547 + }, + "@nx/jest": { + "lastPublishedDate": "2023-07-31T13:25:46.305Z", + "npmDownloads": 1786802, + "githubStars": 18547 + }, + "@nx/js": { + "lastPublishedDate": "2023-07-31T13:25:30.195Z", + "npmDownloads": 2560691, + "githubStars": 18547 + }, + "@nx/linter": { + "lastPublishedDate": "2023-07-31T13:25:53.612Z", + "npmDownloads": 1975637, + "githubStars": 18547 + }, + "@nx/nest": { + "lastPublishedDate": "2023-07-31T13:26:35.646Z", + "npmDownloads": 490567, + "githubStars": 18547 + }, + "@nx/next": { + "lastPublishedDate": "2023-07-31T13:26:54.477Z", + "npmDownloads": 384056, + "githubStars": 18547 + }, + "@nx/node": { + "lastPublishedDate": "2023-07-31T13:26:12.510Z", + "npmDownloads": 830340, + "githubStars": 18547 + }, + "nx": { + "lastPublishedDate": "2023-07-31T13:25:19.774Z", + "npmDownloads": 16270290, + "githubStars": 18547 + }, + "@nx/playwright": { + "lastPublishedDate": "2023-08-03T03:30:49.402Z", + "npmDownloads": "", + "githubStars": 18547 + }, + "@nx/plugin": { + "lastPublishedDate": "2023-07-31T13:26:17.005Z", + "npmDownloads": 615978, + "githubStars": 18547 + }, + "@nx/react": { + "lastPublishedDate": "2023-07-31T13:26:19.350Z", + "npmDownloads": 828724, + "githubStars": 18547 + }, + "@nx/react-native": { + "lastPublishedDate": "2023-07-31T13:27:02.407Z", + "npmDownloads": 45656, + "githubStars": 18547 + }, + "@nx/rollup": { + "lastPublishedDate": "2023-07-31T13:25:56.293Z", + "npmDownloads": 143102, + "githubStars": 18547 + }, + "@nx/storybook": { + "lastPublishedDate": "2023-07-31T13:26:41.485Z", + "npmDownloads": 589880, + "githubStars": 18547 + }, + "@nx/vite": { + "lastPublishedDate": "2023-07-31T13:25:59.567Z", + "npmDownloads": 302208, + "githubStars": 18547 + }, + "@nx/web": { + "lastPublishedDate": "2023-07-31T13:26:02.010Z", + "npmDownloads": 1029649, + "githubStars": 18547 + }, + "@nx/webpack": { + "lastPublishedDate": "2023-07-31T13:26:06.719Z", + "npmDownloads": 1197589, + "githubStars": 18547 + }, + "@nx/workspace": { + "lastPublishedDate": "2023-07-31T13:25:27.694Z", + "npmDownloads": 2602643, + "githubStars": 18547 + }, + "@ahryman40k/nx-vitepress": { + "lastPublishedDate": "2022-12-23T01:15:39.916Z", + "npmDownloads": 51, + "githubStars": 0 + }, + "@nightwatch/nx": { + "lastPublishedDate": "2022-12-05T21:50:17.172Z", + "npmDownloads": 59, + "githubStars": 2 + }, + "@nxkit/playwright": { + "lastPublishedDate": "2023-06-06T17:50:01.235Z", + "npmDownloads": 16854, + "githubStars": 36 + }, + "qwik-nx": { + "lastPublishedDate": "2023-07-27T04:27:50.074Z", + "npmDownloads": 3896, + "githubStars": 113, + "nxVersion": ">= 15 <= 17" + }, + "@nxkit/style-dictionary": { + "lastPublishedDate": "2023-06-06T17:50:01.313Z", + "npmDownloads": 8575, + "githubStars": 36 + }, + "nx-plugin-esbuild": { + "lastPublishedDate": "2021-10-02T13:53:16.067Z", + "npmDownloads": 480, + "githubStars": -1, + "nxVersion": "12.7.2" + }, + "nx-plugin-vite": { + "lastPublishedDate": "2022-07-09T09:40:02.353Z", + "npmDownloads": 560, + "githubStars": 94 + }, + "nx-plugin-snowpack": { + "lastPublishedDate": "2021-10-04T02:55:28.868Z", + "npmDownloads": 39, + "githubStars": -1, + "nxVersion": "12.7.2" + }, + "nx-plugin-prisma": { + "lastPublishedDate": "2021-09-30T04:07:48.904Z", + "npmDownloads": 12, + "githubStars": -1, + "nxVersion": "12.7.2" + }, + "@codebrew/nx-aws-cdk": { + "lastPublishedDate": "2022-01-28T05:22:43.508Z", + "npmDownloads": 1576, + "githubStars": 20, + "nxVersion": "" + }, + "@ago-dev/nx-aws-cdk-v2": { + "lastPublishedDate": "2023-05-08T11:33:02.618Z", + "npmDownloads": 37529, + "githubStars": 30, + "nxVersion": "" + }, + "@berenddeboer/nx-sst": { + "lastPublishedDate": "2023-07-28T02:12:51.950Z", + "npmDownloads": 1222, + "githubStars": 4, + "nxVersion": ">= 15 <= 17" + }, + "@rxap/plugin-localazy": { + "lastPublishedDate": "2022-12-14T13:23:03.536Z", + "npmDownloads": 511, + "githubStars": -1, + "nxVersion": ">= 14 <= 16" + }, + "nx-electron": { + "lastPublishedDate": "2023-06-22T13:23:58.845Z", + "npmDownloads": 15276, + "githubStars": 273, + "nxVersion": ">= 14.1 <= 16" + }, + "nx-stylelint": { + "lastPublishedDate": "2023-02-16T14:16:46.275Z", + "npmDownloads": 120338, + "githubStars": 64, + "nxVersion": ">= 14 <= 16" + }, + "@nxext/ionic-react": { + "lastPublishedDate": "2023-05-26T12:53:11.721Z", + "npmDownloads": 689, + "githubStars": -1 + }, + "@nxext/ionic-angular": { + "lastPublishedDate": "2023-05-26T12:52:58.419Z", + "npmDownloads": 33272, + "githubStars": 190 + }, + "@nxext/capacitor": { + "lastPublishedDate": "2023-06-12T07:43:34.104Z", + "npmDownloads": 51591, + "githubStars": 395, + "nxVersion": ">= 15 <= 17" + }, + "@nxtend/firebase": { + "lastPublishedDate": "2021-12-02T15:22:22.629Z", + "npmDownloads": 291, + "githubStars": 190, + "nxVersion": "12.0.0" + }, + "@angular-architects/ddd": { + "lastPublishedDate": "2023-05-20T19:52:32.293Z", + "npmDownloads": 20613, + "githubStars": 276 + }, + "@offeringsolutions/nx-karma-to-jest": { + "lastPublishedDate": "2020-03-08T19:29:18.913Z", + "npmDownloads": 18, + "githubStars": 9 + }, + "@flowaccount/nx-serverless": { + "lastPublishedDate": "2023-07-10T19:06:16.916Z", + "npmDownloads": 7236, + "githubStars": -1, + "nxVersion": ">= 13.10 <= 15" + }, + "@ns3/nx-serverless": { + "lastPublishedDate": "2023-07-12T07:08:25.829Z", + "npmDownloads": 55611, + "githubStars": 59 + }, + "@ns3/nx-jest-playwright": { + "lastPublishedDate": "2023-05-03T07:05:36.802Z", + "npmDownloads": 7036, + "githubStars": 59 + }, + "@ns3/nx-playwright": { + "lastPublishedDate": "2023-05-03T07:05:36.629Z", + "npmDownloads": 4907, + "githubStars": 59 + }, + "@dev-thought/nx-deploy-it": { + "lastPublishedDate": "2021-02-12T21:12:18.923Z", + "npmDownloads": 218, + "githubStars": 77 + }, + "@offeringsolutions/nx-protractor-to-cypress": { + "lastPublishedDate": "2021-03-04T15:12:40.394Z", + "npmDownloads": 11, + "githubStars": 4, + "nxVersion": "" + }, + "@angular-custom-builders/lite-serve": { + "lastPublishedDate": "2021-03-08T14:21:34.424Z", + "npmDownloads": 1682, + "githubStars": 6 + }, + "@nx-plus/nuxt": { + "lastPublishedDate": "2022-07-02T16:45:19.149Z", + "npmDownloads": 3343, + "githubStars": 298, + "nxVersion": ">= 13.10 <= 15" + }, + "@nx-plus/vue": { + "lastPublishedDate": "2022-12-05T02:51:23.682Z", + "npmDownloads": 9789, + "githubStars": 298, + "nxVersion": ">= 14 <= 16" + }, + "@nx-plus/docusaurus": { + "lastPublishedDate": "2022-12-05T02:51:37.534Z", + "npmDownloads": 61760, + "githubStars": 298, + "nxVersion": ">= 14 <= 16" + }, + "@twittwer/compodoc": { + "lastPublishedDate": "2023-06-25T12:35:20.159Z", + "npmDownloads": 18068, + "githubStars": 40, + "nxVersion": ">= 15 <= 17" + }, + "@enio.ai/nx-install": { + "lastPublishedDate": "2023-03-05T20:18:09.761Z", + "npmDownloads": 61, + "githubStars": 22, + "nxVersion": ">= 14.1 <= 16" + }, + "@enio.ai/typedoc": { + "lastPublishedDate": "2023-03-05T20:17:20.752Z", + "npmDownloads": 3643, + "githubStars": 22, + "nxVersion": ">= 14.1 <= 16" + }, + "@nxext/svelte": { + "lastPublishedDate": "2023-05-26T12:47:54.560Z", + "npmDownloads": 5277, + "githubStars": 395 + }, + "@nxext/stencil": { + "lastPublishedDate": "2023-06-21T09:20:15.486Z", + "npmDownloads": 11402, + "githubStars": 395, + "nxVersion": ">= 15 <= 17" + }, + "@nxext/vite": { + "lastPublishedDate": "2023-02-28T19:05:21.436Z", + "npmDownloads": 24063, + "githubStars": 395, + "nxVersion": ">= 14.1 <= 16" + }, + "@nxext/solid": { + "lastPublishedDate": "2023-05-26T12:47:38.232Z", + "npmDownloads": 1555, + "githubStars": 395 + }, + "@joelcode/gcp-function": { + "lastPublishedDate": "2021-09-15T16:46:35.377Z", + "npmDownloads": 29, + "githubStars": -1 + }, + "@nx-go/nx-go": { + "lastPublishedDate": "2022-10-17T07:48:25.180Z", + "npmDownloads": 242857, + "githubStars": -1 + }, + "@nx-golang/gin": { + "lastPublishedDate": "2023-01-04T14:57:24.660Z", + "npmDownloads": 37, + "githubStars": 0 + }, + "@angular-architects/module-federation": { + "lastPublishedDate": "2023-06-20T16:52:19.205Z", + "npmDownloads": 445713, + "githubStars": 577 + }, + "@nxrocks/nx-spring-boot": { + "lastPublishedDate": "2023-05-12T16:58:52.743Z", + "npmDownloads": 6938, + "githubStars": 231, + "nxVersion": ">= 15 <= 17" + }, + "@trumbitta/nx-plugin-openapi": { + "lastPublishedDate": "2022-08-28T20:54:50.978Z", + "npmDownloads": 27028, + "githubStars": -1, + "nxVersion": "13.0.0" + }, + "@trumbitta/nx-plugin-unused-deps": { + "lastPublishedDate": "2022-08-28T20:55:11.226Z", + "npmDownloads": 65267, + "githubStars": -1, + "nxVersion": "13.0.0" + }, + "@nxrocks/nx-flutter": { + "lastPublishedDate": "2023-05-12T16:59:33.230Z", + "npmDownloads": 8587, + "githubStars": 231, + "nxVersion": ">= 15 <= 17" + }, + "@srleecode/domain": { + "lastPublishedDate": "2023-06-22T13:44:39.620Z", + "npmDownloads": 381, + "githubStars": -1, + "nxVersion": "" + }, + "@jscutlery/semver": { + "lastPublishedDate": "2023-07-31T06:50:30.918Z", + "npmDownloads": 523358, + "githubStars": 619, + "nxVersion": ">= 15 <= 17" + }, + "ngx-deploy-npm": { + "lastPublishedDate": "2023-05-15T07:18:38.684Z", + "npmDownloads": 287616, + "githubStars": 99, + "nxVersion": ">= 15 <= 17" + }, + "@trafilea/nx-shopify": { + "lastPublishedDate": "2021-06-02T19:51:43.707Z", + "npmDownloads": 102, + "githubStars": 42, + "nxVersion": "12.0.8" + }, + "@nx-dotnet/core": { + "lastPublishedDate": "2023-04-12T17:54:41.139Z", + "npmDownloads": 58546, + "githubStars": 214, + "nxVersion": ">= 14.1 <= 16" + }, + "@nxrocks/nx-quarkus": { + "lastPublishedDate": "2023-05-12T16:59:55.758Z", + "npmDownloads": 10003, + "githubStars": 231, + "nxVersion": ">= 15 <= 17" + }, + "@nx-extend/gcp-secrets": { + "lastPublishedDate": "2023-06-22T17:40:46.440Z", + "npmDownloads": 95, + "githubStars": 98, + "nxVersion": ">= 15 <= 17" + }, + "@nx-extend/gcp-storage": { + "lastPublishedDate": "2023-06-22T17:40:53.943Z", + "npmDownloads": 987, + "githubStars": 98, + "nxVersion": ">= 15 <= 17" + }, + "@nx-extend/gcp-functions": { + "lastPublishedDate": "2023-07-22T09:38:42.753Z", + "npmDownloads": 4113, + "githubStars": 98, + "nxVersion": ">= 15 <= 17" + }, + "@nx-extend/gcp-deployment-manager": { + "lastPublishedDate": "2023-06-22T17:40:40.176Z", + "npmDownloads": 107, + "githubStars": 98, + "nxVersion": ">= 15 <= 17" + }, + "@nx-extend/gcp-cloud-run": { + "lastPublishedDate": "2023-06-22T17:40:52.218Z", + "npmDownloads": 2142, + "githubStars": 98, + "nxVersion": ">= 15 <= 17" + }, + "@nx-extend/translations": { + "lastPublishedDate": "2023-06-22T17:40:44.178Z", + "npmDownloads": 233, + "githubStars": 98, + "nxVersion": ">= 15 <= 17" + }, + "@nx-extend/firebase-hosting": { + "lastPublishedDate": "2023-07-13T10:38:12.436Z", + "npmDownloads": 1382, + "githubStars": 98, + "nxVersion": ">= 15 <= 17" + }, + "@nx-extend/e2e-runner": { + "lastPublishedDate": "2023-07-21T20:54:54.000Z", + "npmDownloads": 6501, + "githubStars": 98, + "nxVersion": ">= 15 <= 17" + }, + "@nx-extend/vercel": { + "lastPublishedDate": "2023-07-28T08:36:42.305Z", + "npmDownloads": 820, + "githubStars": 98, + "nxVersion": ">= 15 <= 17" + }, + "@nx-extend/strapi": { + "lastPublishedDate": "2023-07-12T07:02:19.604Z", + "npmDownloads": 9188, + "githubStars": 98, + "nxVersion": ">= 15 <= 17" + }, + "@nx-extend/playwright": { + "lastPublishedDate": "2023-06-22T17:40:55.663Z", + "npmDownloads": 7561, + "githubStars": 98, + "nxVersion": ">= 15 <= 17" + }, + "@nx-extend/terraform": { + "lastPublishedDate": "2023-06-22T17:40:57.454Z", + "npmDownloads": 570, + "githubStars": 98, + "nxVersion": ">= 15 <= 17" + }, + "@nx-extend/pulumi": { + "lastPublishedDate": "2023-06-22T17:40:59.131Z", + "npmDownloads": 467, + "githubStars": 98, + "nxVersion": ">= 15 <= 17" + }, + "@nativescript/nx": { + "lastPublishedDate": "2023-07-05T22:55:56.178Z", + "npmDownloads": 10409, + "githubStars": 58, + "nxVersion": ">= 15 <= 17" + }, + "@nx-clean/plugin-core": { + "lastPublishedDate": "2022-03-10T15:36:11.690Z", + "npmDownloads": 145, + "githubStars": 65, + "nxVersion": "" + }, + "@jnxplus/nx-boot-gradle": { + "lastPublishedDate": "2023-07-28T16:33:38.123Z", + "npmDownloads": 2384, + "githubStars": -1, + "nxVersion": ">= 15 <= 17" + }, + "@jnxplus/nx-boot-maven": { + "lastPublishedDate": "2023-07-28T16:34:00.918Z", + "npmDownloads": 7475, + "githubStars": -1, + "nxVersion": ">= 15 <= 17" + }, + "@nxtensions/astro": { + "lastPublishedDate": "2023-07-30T14:40:23.494Z", + "npmDownloads": 4841, + "githubStars": 43, + "nxVersion": ">= 15 <= 17" + }, + "@nxrs/cargo": { + "lastPublishedDate": "2022-05-25T02:55:50.238Z", + "npmDownloads": 2601, + "githubStars": 101 + }, + "nx-uvu": { + "lastPublishedDate": "2023-06-16T16:07:57.812Z", + "npmDownloads": 563, + "githubStars": -1, + "nxVersion": ">= 15 <= 17" + }, + "@ndrsg/nx-http": { + "lastPublishedDate": "2022-06-07T13:16:25.323Z", + "npmDownloads": 18, + "githubStars": 6, + "nxVersion": "14.0.0" + }, + "@diogovcs/graphql-mesh": { + "lastPublishedDate": "2023-01-22T11:38:26.303Z", + "npmDownloads": 633, + "githubStars": -1 + }, + "@computas/nx-yarn": { + "lastPublishedDate": "2022-05-30T07:04:03.376Z", + "npmDownloads": 463, + "githubStars": -1, + "nxVersion": ">= 13.10 <= 15" + }, + "@theunderscorer/nx-semantic-release": { + "lastPublishedDate": "2023-07-16T18:50:55.453Z", + "npmDownloads": 17537, + "githubStars": 61, + "nxVersion": ">= 15 <= 17" + }, + "nx-pwm": { + "lastPublishedDate": "2022-12-03T18:41:17.623Z", + "npmDownloads": 19, + "githubStars": 4, + "nxVersion": ">= 14 <= 16" + }, + "@nxrocks/nx-micronaut": { + "lastPublishedDate": "2023-05-12T16:59:13.295Z", + "npmDownloads": 201, + "githubStars": 231, + "nxVersion": ">= 15 <= 17" + }, + "@koliveira15/nx-sonarqube": { + "lastPublishedDate": "2023-08-02T00:25:44.844Z", + "npmDownloads": 43559, + "githubStars": 21 + }, + "@mands/nx-playwright": { + "lastPublishedDate": "2023-05-16T10:59:21.495Z", + "npmDownloads": 63690, + "githubStars": 58 + }, + "@diogovcs/stryker-mutator": { + "lastPublishedDate": "2023-03-18T12:51:54.214Z", + "npmDownloads": 2414, + "githubStars": -1, + "nxVersion": "" + }, + "@spaceribs/nx-web-ext": { + "lastPublishedDate": "2023-07-16T15:45:19.229Z", + "npmDownloads": 256, + "githubStars": 5, + "nxVersion": ">= 15 <= 17" + }, + "@spaceribs/nx-betterer": { + "lastPublishedDate": "2023-07-16T15:45:12.663Z", + "npmDownloads": 176, + "githubStars": 5, + "nxVersion": ">= 15 <= 17" + }, + "@nx-tools/nx-container": { + "lastPublishedDate": "2023-06-21T06:38:36.059Z", + "npmDownloads": 103868, + "githubStars": 261, + "nxVersion": ">= 15 <= 17" + }, + "@nxrocks/nx-melos": { + "lastPublishedDate": "2023-05-12T17:00:25.890Z", + "npmDownloads": 166, + "githubStars": 231, + "nxVersion": ">= 15 <= 17" + }, + "@monodon/rust": { + "lastPublishedDate": "2023-06-30T16:35:58.528Z", + "npmDownloads": 7138, + "githubStars": 15, + "nxVersion": ">= 15 <= 17" + }, + "nx-mesh": { + "lastPublishedDate": "2023-04-26T20:23:43.825Z", + "npmDownloads": 2113, + "githubStars": 19, + "nxVersion": ">= 14.1 <= 16" + }, + "@nxazure/func": { + "lastPublishedDate": "2023-06-17T22:19:57.878Z", + "npmDownloads": 2041, + "githubStars": 9 + }, + "@rbnx/webdriverio": { + "lastPublishedDate": "2023-05-05T06:51:41.339Z", + "npmDownloads": 233, + "githubStars": 7, + "nxVersion": ">= 15 <= 17" + }, + "nx-ngrok": { + "lastPublishedDate": "2023-04-17T21:34:27.110Z", + "npmDownloads": 244, + "githubStars": 0, + "nxVersion": ">= 14.1 <= 16" + }, + "@nxrocks/nx-ktor": { + "lastPublishedDate": "2023-05-25T05:35:48.467Z", + "npmDownloads": 27, + "githubStars": 231, + "nxVersion": ">= 15 <= 17" + }, + "nx-size-limit": { + "lastPublishedDate": "2023-04-22T07:50:24.764Z", + "npmDownloads": 313, + "githubStars": 7 + }, + "@jnxplus/nx-quarkus-gradle": { + "lastPublishedDate": "2023-07-28T16:33:30.811Z", + "npmDownloads": 750, + "githubStars": -1, + "nxVersion": ">= 15 <= 17" + }, + "@jnxplus/nx-quarkus-maven": { + "lastPublishedDate": "2023-07-28T16:33:52.833Z", + "npmDownloads": 725, + "githubStars": -1, + "nxVersion": ">= 15 <= 17" + }, + "@loft-orbital/terraform": { + "lastPublishedDate": "2023-03-25T21:03:22.028Z", + "npmDownloads": 432, + "githubStars": -1 + }, + "@nxlv/python": { + "lastPublishedDate": "2023-07-06T13:05:49.453Z", + "npmDownloads": 9584, + "githubStars": 43, + "nxVersion": ">= 15 <= 17" + } +} diff --git a/nx-dev/nx-dev/pages/extending-nx/registry.tsx b/nx-dev/nx-dev/pages/extending-nx/registry.tsx index 1d215e36174ea..836ec480d7918 100644 --- a/nx-dev/nx-dev/pages/extending-nx/registry.tsx +++ b/nx-dev/nx-dev/pages/extending-nx/registry.tsx @@ -13,6 +13,7 @@ import { useRef } from 'react'; import { menusApi } from '../../lib/menus.api'; import { useNavToggle } from '../../lib/navigation-toggle.effect'; import { nxPackagesApi } from '../../lib/packages.api'; +import * as qualityIndicators from './quality-indicators.json'; declare const fetch: any; @@ -50,10 +51,13 @@ export async function getStaticProps(): Promise<{ props: BrowseProps }> { name: plugin.packageName, description: plugin.description ?? '', url: plugin.path, + ...qualityIndicators[plugin.packageName], + nxVersion: 'official', isOfficial: true, })), ...pluginList.map((plugin) => ({ ...plugin, + ...qualityIndicators[plugin.name], isOfficial: false, })), ], diff --git a/nx-dev/ui-common/src/lib/plugin-card.tsx b/nx-dev/ui-common/src/lib/plugin-card.tsx index 70af01a778e9c..0d68d743d780a 100644 --- a/nx-dev/ui-common/src/lib/plugin-card.tsx +++ b/nx-dev/ui-common/src/lib/plugin-card.tsx @@ -1,8 +1,18 @@ +import { + ArrowDownIcon, + ClockIcon, + StarIcon, +} from '@heroicons/react/24/outline'; + export interface PluginCardProps { name: string; description: string; url: string; isOfficial: boolean; + lastPublishedDate?: string; + npmDownloads?: string; + githubStars?: string; + nxVersion?: string; } export function PluginCard({ @@ -10,9 +20,13 @@ export function PluginCard({ description, url, isOfficial, + lastPublishedDate, + npmDownloads, + githubStars, + nxVersion, }: PluginCardProps): JSX.Element { return ( -
+

); } + +export function LastPublishedWidget({ + lastPublishedDate, +}: { + lastPublishedDate: string | undefined; +}) { + if (!lastPublishedDate) { + return
; + } + return ( + + + {/* yyyy-MM-dd */} + {new Date(lastPublishedDate).toISOString().slice(0, 10)} + +
+ Most Recent Release Date +
+
+ ); +} + +function NpmDownloadsWidget({ + npmDownloads, +}: { + npmDownloads: string | undefined; +}) { + if (!npmDownloads) { + return
; + } + return ( + + + {shortenNumber(npmDownloads)} + +
+ Monthly NPM Downloads +
+
+ ); +} + +function GithubStarsWidget({ + githubStars, +}: { + githubStars: string | undefined; +}) { + if (!githubStars || githubStars == '-1') { + return
; + } + return ( + + + {shortenNumber(githubStars)} + +
+ GitHub Stars +
+
+ ); +} + +function shortenNumber(number: string | number): string { + const num = Number.parseInt(number + ''); + if (num > 1000000) { + return Math.floor(num / 1000000) + 'M'; + } + if (num > 1000) { + return Math.floor(num / 1000) + 'k'; + } + return num + ''; +} + +function NxVersionWidget({ nxVersion }: { nxVersion: string | undefined }) { + if (!nxVersion) { + return
; + } + return ( + + {/* Nx Logo */} + + Nx + + + {nxVersion} + +
+ Supported Nx Versions +
+
+ ); +} diff --git a/nx-dev/ui-community/src/lib/plugin-directory.tsx b/nx-dev/ui-community/src/lib/plugin-directory.tsx index 0c9a9d25c8277..8cc87d9015888 100644 --- a/nx-dev/ui-community/src/lib/plugin-directory.tsx +++ b/nx-dev/ui-community/src/lib/plugin-directory.tsx @@ -1,3 +1,10 @@ +import { + ArrowDownIcon, + ArrowLongDownIcon, + ArrowLongUpIcon, + ClockIcon, + StarIcon, +} from '@heroicons/react/24/outline'; import { MagnifyingGlassIcon } from '@heroicons/react/24/solid'; import { PluginCard, SectionHeading } from '@nx/nx-dev/ui-common'; import { useState } from 'react'; @@ -7,6 +14,26 @@ interface Plugin { name: string; url: string; isOfficial: boolean; + lastPublishedDate?: string; + npmDownloads?: string; + githubStars?: string; + nxVersion?: string; +} + +type OrderByStatus = + | 'lastPublishDate' + | 'npmDownloads' + | 'githubStars' + | 'nxVersion' + | undefined; +interface Modifiers { + term: string; + officialStatus: 'official' | 'community' | undefined; + minimumDownloads: number | undefined; + minimumStars: number | undefined; + minimumNxVersion: string | undefined; + orderBy: OrderByStatus; + orderDirection: 'ASC' | 'DESC'; } export function PluginDirectory({ @@ -14,12 +41,33 @@ export function PluginDirectory({ }: { pluginList: Plugin[]; }): JSX.Element { - const [searchTerm, setSearchTerm] = useState(''); + const [modifiers, setModifiers] = useState({ + term: '', + officialStatus: undefined, + minimumDownloads: undefined, + minimumStars: undefined, + minimumNxVersion: undefined, + orderBy: undefined, + orderDirection: 'ASC', + }); + function setOrderBy(status: OrderByStatus) { + if (modifiers.orderBy === status) { + setModifiers({ + ...modifiers, + orderDirection: modifiers.orderDirection === 'ASC' ? 'DESC' : 'ASC', + }); + } else { + setModifiers({ + ...modifiers, + orderBy: status, + }); + } + } return (
- Nx Plugins Registry + Nx Plugins Registry
+
+
Order by:
+
+ + + + +
+
{pluginList .filter((plugin) => - !!searchTerm - ? plugin.name.toLowerCase().includes(searchTerm.toLowerCase()) || + !!modifiers.term + ? plugin.name + .toLowerCase() + .includes(modifiers.term.toLowerCase()) || plugin.description .toLowerCase() - .includes(searchTerm.toLowerCase()) + .includes(modifiers.term.toLowerCase()) : true ) + .sort((a, b) => { + if (modifiers.orderBy === 'lastPublishDate') { + return ( + (modifiers.orderDirection === 'ASC' ? 1 : -1) * + (new Date(a.lastPublishedDate || '').getTime() - + new Date(b.lastPublishedDate || '').getTime()) + ); + } else if (modifiers.orderBy === 'npmDownloads') { + return ( + (modifiers.orderDirection === 'ASC' ? 1 : -1) * + (Number.parseInt(a.npmDownloads || '0') - + Number.parseInt(b.npmDownloads || '0')) + ); + } else if (modifiers.orderBy === 'githubStars') { + return ( + (modifiers.orderDirection === 'ASC' ? 1 : -1) * + (Number.parseInt(a.githubStars || '0') - + Number.parseInt(b.githubStars || '0')) + ); + } else if (modifiers.orderBy === 'nxVersion') { + const versionValueMap: Record = { + unknown: 0, + '12': 12, + '13': 13, + '14': 14, + '15': 15, + '16': 16, + '17': 17, + '18': 18, + '>= 15': 17, + '>= 14': 16, + '>= 13': 15, + official: 1000, + }; + function getValueFromVersion(version: string = 'unknown') { + const mapKey = + Object.keys(versionValueMap).find((key) => + version.startsWith(key) + ) || 'unknown'; + return versionValueMap[mapKey]; + } + return ( + (modifiers.orderDirection === 'ASC' ? 1 : -1) * + (getValueFromVersion(a.nxVersion) - + getValueFromVersion(b.nxVersion)) + ); + } + return 0; + }) .map((plugin) => ( ))} diff --git a/scripts/documentation/plugin-quality-indicators.ts b/scripts/documentation/plugin-quality-indicators.ts new file mode 100644 index 0000000000000..972af7a110e07 --- /dev/null +++ b/scripts/documentation/plugin-quality-indicators.ts @@ -0,0 +1,198 @@ +import { writeFileSync } from 'fs'; +import axios from 'axios'; + +interface Interval { + start: Date; + end: Date; +} + +interface PluginRegistry { + name: string; + description: string; + url: string; +} + +const packagesJson = require('../../nx-dev/nx-dev/public/documentation/generated/manifests/packages.json'); +const officialPlugins = Object.keys(packagesJson) + .filter( + (m: any) => + packagesJson[m].name !== 'add-nx-to-monorepo' && + packagesJson[m].name !== 'cra-to-nx' && + packagesJson[m].name !== 'create-nx-plugin' && + packagesJson[m].name !== 'create-nx-workspace' && + packagesJson[m].name !== 'make-angular-cli-faster' && + packagesJson[m].name !== 'tao' + ) + .map((k) => ({ + name: packagesJson[k].name === 'nx' ? 'nx' : '@nx/' + packagesJson[k].name, + description: packagesJson[k].description, + url: packagesJson[k].githubRoot, + })); + +const plugins = + require('../../community/approved-plugins.json') as PluginRegistry[]; + +async function main() { + const qualityIndicators: any = {}; + const { data } = await axios.get(`https://api.github.com/repos/nrwl/nx`, { + headers: { + Authorization: `Bearer ${process.env.GITHUB_PAT}`, + }, + }); + const nxGithubStars = data.stargazers_count; + for (let i = 0; i < officialPlugins.length; i++) { + const plugin = officialPlugins[i]; + console.log(`Fetching data for ${plugin.name}`); + const npmData = await getNpmData(plugin, true); + const npmDownloads = await getNpmDownloads(plugin); + qualityIndicators[plugin.name] = { + lastPublishedDate: npmData.lastPublishedDate, + npmDownloads, + githubStars: nxGithubStars, + }; + } + for (let i = 0; i < plugins.length; i++) { + const plugin = plugins[i]; + console.log(`Fetching data for ${plugin.name}`); + const npmData = await getNpmData(plugin); + const npmDownloads = await getNpmDownloads(plugin); + const githubStars = await getGithubStars(npmData.githubRepo); + qualityIndicators[plugin.name] = { + lastPublishedDate: npmData.lastPublishedDate, + npmDownloads, + githubStars, + nxVersion: npmData.nxVersion, + }; + } + + writeFileSync( + './nx-dev/nx-dev/pages/extending-nx/quality-indicators.json', + JSON.stringify(qualityIndicators, null, 2) + ); +} +main(); + +// Publish date (and github directory, readme content) +// i.e. https://registry.npmjs.org/@nxkit/playwright +async function getNpmData(plugin: PluginRegistry, skipNxVersion = false) { + try { + const { data } = await axios.get( + `https://registry.npmjs.org/${plugin.name}` + ); + const lastPublishedDate = data.time[data['dist-tags'].latest]; + const nxVersion = skipNxVersion || (await getNxVersion(data)); + if (!data.repository) { + console.warn('- No repository defined in package.json!'); + return { lastPublishedDate, nxVersion, githubRepo: '' }; + } + const url: String = data.repository.url; + const githubRepo = url + .slice(url.indexOf('github.com/') + 11) + .replace('.git', ''); + return { + lastPublishedDate, + githubRepo, + nxVersion, + // readmeContent: plugin.name + }; + } catch (ex) { + return { lastPublishedDate: '', githubRepo: '' }; + } +} + +// Download count +// i.e. https://api.npmjs.org/downloads/point/2023-06-01:2023-07-01/@nxkit/playwright +async function getNpmDownloads(plugin: PluginRegistry) { + const lastMonth = getLastMonth(); + try { + const { data } = await axios.get( + `https://api.npmjs.org/downloads/point/${stringifyIntervalForUrl( + lastMonth + )}/${plugin.name}` + ); + return data.downloads; + } catch (ex) { + return ''; + } +} + +export function getLastMonth() { + const now = new Date(); + const oneMonthAgo = new Date(); + oneMonthAgo.setMonth(now.getMonth() - 1); + return { + start: oneMonthAgo, + end: now, + }; +} + +export function stringifyIntervalForUrl(interval: Interval): string { + return `${stringifyDate(interval.start)}:${stringifyDate(interval.end)}`; +} + +export function stringifyDate(date: Date) { + // yyyy-MM-dd + return date.toISOString().slice(0, 10); +} + +// Stars +// i.e. https://api.github.com/repos/nxkit/nxkit +async function getGithubStars(repo: String) { + try { + const { data } = await axios.get(`https://api.github.com/repos/${repo}`, { + headers: { + Authorization: `Bearer ${process.env.GITHUB_PAT}`, + }, + }); + return data.stargazers_count; + } catch (ex) { + console.warn('- Could not load GitHub stars!'); + return -1; + } +} + +async function getNxVersion(data: any) { + const latest = data['dist-tags'].latest; + const nxPackages = [ + '@nx/devkit', + '@nrwl/devkit', + '@nx/workspace', + '@nrwl/workspace', + ]; + let devkitVersion = ''; + for (let i = 0; i < nxPackages.length && !devkitVersion; i++) { + const packageName = nxPackages[i]; + if (data.versions[latest]?.dependencies) { + devkitVersion = data.versions[latest]?.dependencies[packageName]; + if (devkitVersion) { + return await findNxRange(packageName, devkitVersion); + } + } + if (!devkitVersion && data.versions[latest]?.peerDependencies) { + devkitVersion = data.versions[latest]?.peerDependencies[packageName]; + if (devkitVersion) { + return await findNxRange(packageName, devkitVersion); + } + } + } + console.warn('- No dependency on @nx/devkit!'); + return devkitVersion; +} + +async function findNxRange(packageName: string, devkitVersion: string) { + devkitVersion = devkitVersion + .replace('^', '') + .replace('>=', '') + .replace('>', ''); + const lookupPackage = packageName.includes('@nx') + ? '@nx/devkit' + : '@nrwl/devkit'; + const { data: devkitData } = await axios.get( + `https://registry.npmjs.org/${lookupPackage}` + ); + if (!devkitData.versions[devkitVersion]?.peerDependencies) { + const dependencies = devkitData.versions[devkitVersion]?.dependencies; + return dependencies && (dependencies?.nx || dependencies['@nrwl/tao']); + } + return devkitData.versions[devkitVersion]?.peerDependencies.nx; +}