From 778f13fdafd22977bffcaa68c33d0e6ce6eead5f Mon Sep 17 00:00:00 2001 From: Benjamin Cabanes <3447705+bcabanes@users.noreply.github.com> Date: Thu, 30 Jun 2022 15:30:38 -0400 Subject: [PATCH] docs(nxdev): improve markdown capabilities (#10965) --- docs/generated/packages/nx-plugin.json | 2 +- docs/generated/packages/storybook.json | 2 +- docs/nx-cloud/intro/nx-cloud.md | 10 +- .../angular-tutorial/01-create-application.md | 5 +- .../angular-tutorial/02-add-e2e-test.md | 5 +- .../angular-tutorial/03-display-todos.md | 5 +- .../angular-tutorial/04-connect-to-api.md | 5 +- .../angular-tutorial/05-add-node-app.md | 5 +- docs/shared/angular-tutorial/06-proxy.md | 5 +- docs/shared/angular-tutorial/07-share-code.md | 5 +- .../shared/angular-tutorial/08-create-libs.md | 7 +- docs/shared/angular-tutorial/09-dep-graph.md | 5 +- .../10-computation-caching.md | 5 +- .../11-test-affected-projects.md | 5 +- docs/shared/ci-overview.md | 4 +- docs/shared/console.md | 35 ++++-- docs/shared/getting-started/nx-and-angular.md | 5 +- docs/shared/getting-started/nx-and-react.md | 5 +- docs/shared/guides/nx-and-ts.md | 7 +- .../shared/guides/nx-devkit-angular-devkit.md | 4 - .../storybook/migrate-webpack-final-react.md | 5 +- docs/shared/migration/adding-to-monorepo.md | 20 ++- docs/shared/migration/migration-angular.md | 5 +- docs/shared/migration/migration-cra.md | 5 +- docs/shared/monorepo-ci-azure.md | 4 +- docs/shared/monorepo-ci-circle-ci.md | 4 +- docs/shared/monorepo-ci-github-actions.md | 4 +- docs/shared/monorepo-ci-gitlab.md | 4 +- docs/shared/monorepo-ci-jenkins.md | 4 +- .../node-tutorial/01-create-application.md | 5 +- docs/shared/node-tutorial/02-display-todos.md | 5 +- docs/shared/node-tutorial/03-share-code.md | 5 +- docs/shared/node-tutorial/04-create-libs.md | 5 +- docs/shared/node-tutorial/05-dep-graph.md | 5 +- .../node-tutorial/06-computation-caching.md | 5 +- .../07-test-affected-projects.md | 5 +- docs/shared/nx-cloud-logo.svg | 4 + docs/shared/nx-core.md | 5 +- docs/shared/nx-plugin.md | 18 ++- .../react-tutorial/01-create-application.md | 5 +- docs/shared/react-tutorial/02-add-e2e-test.md | 5 +- .../shared/react-tutorial/03-display-todos.md | 5 +- .../react-tutorial/04-connect-to-api.md | 5 +- docs/shared/react-tutorial/05-add-node-app.md | 5 +- docs/shared/react-tutorial/06-proxy.md | 5 +- docs/shared/react-tutorial/07-share-code.md | 5 +- docs/shared/react-tutorial/08-create-libs.md | 5 +- docs/shared/react-tutorial/09-dep-graph.md | 5 +- .../react-tutorial/10-computation-caching.md | 5 +- .../11-test-affected-projects.md | 5 +- docs/shared/using-nx/caching.md | 4 +- docs/shared/using-nx/dte.md | 4 +- .../workspace/structure/dependency-graph.md | 5 +- nx-dev/feature-doc-viewer/src/lib/content.tsx | 117 ++---------------- .../src/lib/renderers/render-iframe.ts | 21 ---- .../src/lib/renderers/transform-image-path.ts | 25 ---- .../src/lib/content.tsx | 36 +++--- .../src/lib/package-schema-list.tsx | 40 +++--- .../src/lib/parameter-view.tsx | 20 ++- .../src/lib/ui/markdown/code-block.tsx | 69 ----------- .../src/lib/ui/markdown/markdown.tsx | 104 ---------------- .../ui/markdown/renderers/render-iframe.ts | 21 ---- nx-dev/nx-dev/styles/main.css | 19 +-- nx-dev/ui-markdoc/.babelrc | 12 ++ nx-dev/ui-markdoc/.eslintrc.json | 18 +++ nx-dev/ui-markdoc/README.md | 7 ++ nx-dev/ui-markdoc/jest.config.ts | 10 ++ nx-dev/ui-markdoc/project.json | 23 ++++ nx-dev/ui-markdoc/src/index.ts | 70 +++++++++++ .../src/lib/nodes/fence.component.tsx} | 19 +-- .../ui-markdoc/src/lib/nodes/fence.schema.ts | 9 ++ .../src/lib/nodes/heading.component.tsx | 28 +++++ .../src/lib/nodes/heading.schema.ts | 38 ++++++ .../helpers}/transform-image-path.spec.ts | 22 ++-- .../nodes/helpers}/transform-image-path.ts | 7 +- .../src/lib/nodes/helpers/uri-transformer.ts | 43 +++++++ .../ui-markdoc/src/lib/nodes/image.schema.ts | 29 +++++ .../src/lib/nodes/link.component.tsx | 18 +++ .../ui-markdoc/src/lib/nodes/link.schema.ts | 47 +++++++ .../src/lib/tags/callout.component.tsx | 90 ++++++++++++++ .../ui-markdoc/src/lib/tags/callout.schema.ts | 21 ++++ .../src/lib/tags/iframe.component.tsx | 4 + .../ui-markdoc/src/lib/tags/iframe.schema.ts | 19 +++ .../lib/tags/nx-cloud-section.component.tsx | 44 +++++++ .../src/lib/tags/nx-cloud-section.schema.ts | 6 + .../src/lib/tags/side-by-side.component.tsx | 11 ++ .../src/lib/tags/side-by-side.schema.ts | 6 + .../src/lib/tags/tabs.component.tsx | 61 +++++++++ nx-dev/ui-markdoc/src/lib/tags/tabs.schema.ts | 23 ++++ .../src/lib/tags/vs-code-ad.component.tsx | 33 +++++ .../src/lib/tags/vs-code-ad.schema.ts | 6 + .../src/lib/tags/youtube.components.tsx | 12 ++ .../ui-markdoc/src/lib/tags/youtube.schema.ts | 19 +++ nx-dev/ui-markdoc/tsconfig.json | 25 ++++ nx-dev/ui-markdoc/tsconfig.lib.json | 23 ++++ nx-dev/ui-markdoc/tsconfig.spec.json | 20 +++ package.json | 2 +- tsconfig.base.json | 1 + workspace.json | 1 + yarn.lock | 5 + 100 files changed, 1108 insertions(+), 512 deletions(-) create mode 100644 docs/shared/nx-cloud-logo.svg delete mode 100644 nx-dev/feature-doc-viewer/src/lib/renderers/render-iframe.ts delete mode 100644 nx-dev/feature-doc-viewer/src/lib/renderers/transform-image-path.ts delete mode 100644 nx-dev/feature-package-schema-viewer/src/lib/ui/markdown/code-block.tsx delete mode 100644 nx-dev/feature-package-schema-viewer/src/lib/ui/markdown/markdown.tsx delete mode 100644 nx-dev/feature-package-schema-viewer/src/lib/ui/markdown/renderers/render-iframe.ts create mode 100644 nx-dev/ui-markdoc/.babelrc create mode 100644 nx-dev/ui-markdoc/.eslintrc.json create mode 100644 nx-dev/ui-markdoc/README.md create mode 100644 nx-dev/ui-markdoc/jest.config.ts create mode 100644 nx-dev/ui-markdoc/project.json create mode 100644 nx-dev/ui-markdoc/src/index.ts rename nx-dev/{feature-doc-viewer/src/lib/code-block.tsx => ui-markdoc/src/lib/nodes/fence.component.tsx} (83%) create mode 100644 nx-dev/ui-markdoc/src/lib/nodes/fence.schema.ts create mode 100644 nx-dev/ui-markdoc/src/lib/nodes/heading.component.tsx create mode 100644 nx-dev/ui-markdoc/src/lib/nodes/heading.schema.ts rename nx-dev/{feature-doc-viewer/src/lib/renderers => ui-markdoc/src/lib/nodes/helpers}/transform-image-path.spec.ts (66%) rename nx-dev/{feature-package-schema-viewer/src/lib/ui/markdown/renderers => ui-markdoc/src/lib/nodes/helpers}/transform-image-path.ts (64%) create mode 100644 nx-dev/ui-markdoc/src/lib/nodes/helpers/uri-transformer.ts create mode 100644 nx-dev/ui-markdoc/src/lib/nodes/image.schema.ts create mode 100644 nx-dev/ui-markdoc/src/lib/nodes/link.component.tsx create mode 100644 nx-dev/ui-markdoc/src/lib/nodes/link.schema.ts create mode 100644 nx-dev/ui-markdoc/src/lib/tags/callout.component.tsx create mode 100644 nx-dev/ui-markdoc/src/lib/tags/callout.schema.ts create mode 100644 nx-dev/ui-markdoc/src/lib/tags/iframe.component.tsx create mode 100644 nx-dev/ui-markdoc/src/lib/tags/iframe.schema.ts create mode 100644 nx-dev/ui-markdoc/src/lib/tags/nx-cloud-section.component.tsx create mode 100644 nx-dev/ui-markdoc/src/lib/tags/nx-cloud-section.schema.ts create mode 100644 nx-dev/ui-markdoc/src/lib/tags/side-by-side.component.tsx create mode 100644 nx-dev/ui-markdoc/src/lib/tags/side-by-side.schema.ts create mode 100644 nx-dev/ui-markdoc/src/lib/tags/tabs.component.tsx create mode 100644 nx-dev/ui-markdoc/src/lib/tags/tabs.schema.ts create mode 100644 nx-dev/ui-markdoc/src/lib/tags/vs-code-ad.component.tsx create mode 100644 nx-dev/ui-markdoc/src/lib/tags/vs-code-ad.schema.ts create mode 100644 nx-dev/ui-markdoc/src/lib/tags/youtube.components.tsx create mode 100644 nx-dev/ui-markdoc/src/lib/tags/youtube.schema.ts create mode 100644 nx-dev/ui-markdoc/tsconfig.json create mode 100644 nx-dev/ui-markdoc/tsconfig.lib.json create mode 100644 nx-dev/ui-markdoc/tsconfig.spec.json diff --git a/docs/generated/packages/nx-plugin.json b/docs/generated/packages/nx-plugin.json index 427d7ed292..838ba56845 100644 --- a/docs/generated/packages/nx-plugin.json +++ b/docs/generated/packages/nx-plugin.json @@ -10,7 +10,7 @@ "name": "Overview", "path": "/packages/nx-plugin", "file": "shared/nx-plugin", - "content": "Nx plugins are npm packages that contain generators and executors to extend a Nx workspace. Generators are blueprints to create new files from templates, and executors run those files. These plugins also update the `nx.json` when generating new libs or apps.\n\n> A list of plugins that is maintained by Nrwl is found in the [Nrwl/nx repo](https://github.com/nrwl/nx/tree/master/packages). \\\n> A list of custom plugins created by the community is found in the [Community](/community) section.\n> Plugins are written using Nx Devkit. **Read [Nx Devkit](/devkit/index) for more information.**\n\n\n\n## Generating a Plugin\n\nTo get started with building a Nx Plugin, run the following command:\n\n```bash\nnpx create-nx-plugin my-org --pluginName my-plugin\n```\n\nThis command creates a brand new workspace, and sets up a pre-configured plugin with the specified name.\n\n> Note, the command above will create a plugin the package name set to `@my-org/my-plugin`. You can pass `--importPath` to provide a different package name.\n\n> If you do not want to create a new workspace, install the `@nrwl/nx-plugin` dependency in an already existing workspace with npm or yarn. Then run `nx g @nrwl/nx-plugin:plugin [pluginName]`.\n\nA new plugin is created with a default generator, executor, and e2e app.\n\n## Generator\n\nThe created generator contains boilerplate that will do the following:\n\n- Normalize a schema (the options that the generator accepts)\n- Update the `workspace.json`\n- Add the plugin's project to the `nx.json` file\n- Add files to the disk using templates\n\nThere will be a exported default function that will be the main entry for the generator.\n\n### Generator options\n\nThe `schema.d.ts` file contains all the options that the generator supports. By default, it includes `directory`, `tags`, and `name` as the options. If more options need to be added, please update this file and the `schema.json` file.\n\n> Note: The `schema.d.ts` file is used for type checking inside the implementation file. It should match the properties in `schema.json`.\n\n### Adding more generators\n\nTo add more generators to the plugin, run the following command:\n`nx generate @nrwl/nx-plugin:generator [generatorName] --project=[pluginName]`.\n\nThis will scaffold out a new generator and update the necessary files to support it.\n\n### Generator Testing\n\nThe generator spec file includes boilerplate to help get started with testing. This includes setting up an empty workspace.\n\nThese tests should ensure that files within the tree (created with `createTreeWithEmptyWorkspace`) are in the correct place, and contain the right content.\n\nFull E2Es are supported (and recommended) and will run everything on the file system like a user would.\n\n## Executor\n\nThe default executor is set up to just emit a console log. Some examples of what an executor can do are:\n\n- Support different languages, (Java, Go, Python, C#)\n- Compile new UI framework components\n- Deploy an app on a CDN\n- Publish to NPM\n- and many more!\n\n### Adding more executors\n\nTo add more executors to the plugin, run the following command:\n`nx generate @nrwl/nx-plugin:executor [executor] --project=[pluginName]`.\n\nThis will scaffold out a new generator and update the necessary files to support it.\n\n### Executor testing\n\nThe executor spec file contains boilerplate to run the default exported function from the executor.\n\nThese tests should make sure that the executor is executing and calling the functions that it relies on.\n\nFull E2Es are supported (and recommended) and will run everything on the file system like a user would.\n\n## Testing your plugin\n\nOne of the biggest benefits that the Nx Plugin package provides is support for E2E and unit testing.\n\nWhen the E2E app runs, a temporary E2E directory is created in the root of the workspace. This directory is a blank Nx workspace, and will have the plugin's built package installed locally.\n\n### E2E Testing file\n\nWhen the plugin is generated, a test file is created in the `my-plugin-e2e` app. Inside this test file, there are already tests for making sure that the executor ran, checking if directories are created with the `--directory` option, and checking if tags are added to the project configuration.\n\nWe'll go over a few parts of a test file below:\n\n```typescript\nit('should create my-plugin', async (done) => {\n const plugin = uniq('my-plugin');\n ensureNxProject('@my-org/my-plugin', 'dist/packages/my-plugin');\n await runNxCommandAsync(`generate @my-org/my-plugin:myPlugin ${plugin}`);\n\n const result = await runNxCommandAsync(`build ${plugin}`);\n expect(result.stdout).toContain('Executor ran');\n\n done();\n});\n```\n\n- The `uniq` function creates a random name with the prefix and a random number.\n- The `ensureNxProject` is the function that will create the temporary directory. It takes two arguments, the plugin package name and the dist directory of when it's built.\n- The `runNxCommandAsync` will execute a `nx` command in the E2E directory.\n\nThere are additional functions that the `@nrwl/nx-plugin/testing` package exports. Most of them are file utilities to manipulate and read files in the E2E directory.\n\n## Including Assets\n\nSometimes you might want to include some assets with the plugin. This might be a image or some additional binaries.\n\nTo make sure that assets are copied to the dist folder, open the plugin's `project.json` file. Inside the `build` property, add additional assets. By default, all `.md` files in the root, all non-ts files in folders, and the `generators.json` and `executors.json` files are included.\n\n```json\n\"build\": {\n \"executor\": \"@nrwl/node:package\",\n \"options\": {\n // shortened...\n \"assets\": [\n \"packages/my-plugin/*.md\",\n {\n \"input\": \"./packages/my-plugin/src\",\n \"glob\": \"**/*.!(ts)\",\n \"output\": \"./src\"\n },\n {\n \"input\": \"./packages/my-plugin\",\n \"glob\": \"generators.json\",\n \"output\": \".\"\n },\n {\n \"input\": \"./packages/my-plugin\",\n \"glob\": \"executors.json\",\n \"output\": \".\"\n }\n ]\n }\n}\n```\n\n## Using your Nx Plugin\n\nTo use your plugin, simply list it in `nx.json` or use its generators and executors as you would for any other plugin. This could look like `nx g @my-org/my-plugin:lib` for generators or `\"executor\": \"@my-org/my-plugin:build\"` for executors. It should be usable in all of the same ways as published plugins in your local workspace immediately after generating it. This includes setting it up as the default collection in `nx.json`, which would allow you to run `nx g lib` and hit your plugin's generator.\n\n## Publishing your Nx Plugin\n\nIn order to use your plugin in other workspaces or share it with the community, you will need to publish it to an npm registry. To publish your plugin follow these steps:\n\n1. Build your plugin with the command `nx run my-plugin:build`\n1. `npm publish ./dist/package/my-plugin` and follow the prompts from npm.\n1. That's it!\n\n> Note: currently you will have to modify the `package.json` version by yourself or with a tool.\n\nAfter that, you can then install your plugin like any other npm package,\n`npm i -D @my-org/my-plugin` or `yarn add -D @my-org/my-plugin`.\n\n### Listing your Nx Plugin\n\nNx provides a utility (`nx list`) that lists both core and community plugins. To submit your plugin, please follow the steps below:\n\n- Fork the [Nx repo](https://github.com/nrwl/nx/fork) (if you haven't already)\n- 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\n- Use the following commit message template: `chore(core): nx plugin submission [PLUGIN_NAME]`\n- push your changes, and run `yarn submit-plugin`\n\n> The `yarn submit-plugin` command automatically opens the Github pull request process with the correct template.\n\nWe will then verify the plugin, offer suggestions or merge the pull request!\n\n## Preset\n\nA Preset is a customization option which you provide when creating a new workspace. TS, Node, React are some of the internal presets that Nx provides by default.\n\n\n \n### Custom Preset\n\nAt its core a preset is a generator, which we can create inside of a plugin.\nIf you **don't** have an existing plugin you can create one by running\n\n```bash\n npx create-nx-plugin my-org --pluginName my-plugin\n```\n\nTo create our preset inside of our plugin we can run\n\n```bash\n nx generate @nrwl/nx-plugin:generator --name=preset --project=happynrwl\n```\n\n> Note: the word `preset` is required for the name of this generator\n\nYou should have a similar structure to this:\n\n```treeview\nhappynrwl/\n\t├── e2e\n\t├── jest.config.js\n\t├── jest.preset.js\n\t├── nx.json\n\t├── package-lock.json\n\t├── package.json\n\t├── packages\n\t│ └── happynrwl\n\t│ ├── src\n\t│ │ ├── executors\n\t│ │ ├── generators\n\t│ │ │ ├── happynrwl\n\t│ │ │ └── preset \t\t// <------------- Here\n\t│ │ └── index.ts\n\t├── tools\n\t├── tsconfig.base.json\n\t└── workspace.json\n```\n\nAfter the command is finished, the preset generator is created under the folder named **preset**.\nThe **generator.ts** provides an entry point to the generator. This file contains a function that is called to perform manipulations on a tree that represents the file system. The **schema.json** provides a description of the generator, available options, validation information, and default values.\n\nHere is the sample generator function which you can customize to meet your needs.\n\n```typescript\nexport default async function (tree: Tree, options: PresetGeneratorSchema) {\n const normalizedOptions = normalizeOptions(tree, options);\n addProjectConfiguration(tree, normalizedOptions.projectName, {\n root: normalizedOptions.projectRoot,\n projectType: 'application',\n sourceRoot: `${normalizedOptions.projectRoot}/src`,\n targets: {\n exec: {\n executor: 'nx:run-commands',\n options: {\n command: `node ${projectRoot}/src/index.js`,\n },\n },\n },\n tags: normalizedOptions.parsedTags,\n });\n addFiles(tree, normalizedOptions);\n await formatFiles(tree);\n}\n```\n\nTo get an in-depth guide on customizing/running or debugging your generator see [workspace generators](https://nx.dev/generators/workspace-generators#running-a-workspace-generator).\n\n#### Usage\n\nBefore you are able to use your newly created preset you must package and publish it to a registry.\n\nAfter you have published your plugin to a registry you can now use your preset when creating a new workspace\n\n```bash\nnpx create-nx-workspace my-workspace --preset=my-plugin-name\n```\n" + "content": "Nx plugins are npm packages that contain generators and executors to extend a Nx workspace. Generators are blueprints to create new files from templates, and executors run those files. These plugins also update the `nx.json` when generating new libs or apps.\n\n> A list of plugins that is maintained by Nrwl is found in the [Nrwl/nx repo](https://github.com/nrwl/nx/tree/master/packages). \\\n> A list of custom plugins created by the community is found in the [Community](/community) section.\n> Plugins are written using Nx Devkit. **Read [Nx Devkit](/devkit/index) for more information.**\n\n{% youtube\nsrc=\"https://www.youtube.com/embed/fC1-4fAZDP4\"\ntitle=\"Nx Tutorial: Building Custom Plugins for Nx\"\nwidth=\"100%\" /%}\n\n## Generating a Plugin\n\nTo get started with building a Nx Plugin, run the following command:\n\n```bash\nnpx create-nx-plugin my-org --pluginName my-plugin\n```\n\nThis command creates a brand-new workspace, and sets up a pre-configured plugin with the specified name.\n\n> Note, the command above will create a plugin the package name set to `@my-org/my-plugin`. You can pass `--importPath` to provide a different package name.\n\n> If you do not want to create a new workspace, install the `@nrwl/nx-plugin` dependency in an already existing workspace with npm or yarn. Then run `nx g @nrwl/nx-plugin:plugin [pluginName]`.\n\nA new plugin is created with a default generator, executor, and e2e app.\n\n## Generator\n\nThe created generator contains boilerplate that will do the following:\n\n- Normalize a schema (the options that the generator accepts)\n- Update the `workspace.json`\n- Add the plugin's project to the `nx.json` file\n- Add files to the disk using templates\n\nThere will be an exported default function that will be the main entry for the generator.\n\n### Generator options\n\nThe `schema.d.ts` file contains all the options that the generator supports. By default, it includes `directory`, `tags`, and `name` as the options. If more options need to be added, please update this file and the `schema.json` file.\n\n> Note: The `schema.d.ts` file is used for type checking inside the implementation file. It should match the properties in `schema.json`.\n\n### Adding more generators\n\nTo add more generators to the plugin, run the following command:\n`nx generate @nrwl/nx-plugin:generator [generatorName] --project=[pluginName]`.\n\nThis will scaffold out a new generator and update the necessary files to support it.\n\n### Generator Testing\n\nThe generator spec file includes boilerplate to help get started with testing. This includes setting up an empty workspace.\n\nThese tests should ensure that files within the tree (created with `createTreeWithEmptyWorkspace`) are in the correct place, and contain the right content.\n\nFull E2Es are supported (and recommended) and will run everything on the file system like a user would.\n\n## Executor\n\nThe default executor is set up to just emit a console log. Some examples of what an executor can do are:\n\n- Support different languages, (Java, Go, Python, C#)\n- Compile new UI framework components\n- Deploy an app on a CDN\n- Publish to NPM\n- and many more!\n\n### Adding more executors\n\nTo add more executors to the plugin, run the following command:\n`nx generate @nrwl/nx-plugin:executor [executor] --project=[pluginName]`.\n\nThis will scaffold out a new generator and update the necessary files to support it.\n\n### Executor testing\n\nThe executor spec file contains boilerplate to run the default exported function from the executor.\n\nThese tests should make sure that the executor is executing and calling the functions that it relies on.\n\nFull E2Es are supported (and recommended) and will run everything on the file system like a user would.\n\n## Testing your plugin\n\nOne of the biggest benefits that the Nx Plugin package provides is support for E2E and unit testing.\n\nWhen the E2E app runs, a temporary E2E directory is created in the root of the workspace. This directory is a blank Nx workspace, and will have the plugin's built package installed locally.\n\n### E2E Testing file\n\nWhen the plugin is generated, a test file is created in the `my-plugin-e2e` app. Inside this test file, there are already tests for making sure that the executor ran, checking if directories are created with the `--directory` option, and checking if tags are added to the project configuration.\n\nWe'll go over a few parts of a test file below:\n\n```typescript\nit('should create my-plugin', async (done) => {\n const plugin = uniq('my-plugin');\n ensureNxProject('@my-org/my-plugin', 'dist/packages/my-plugin');\n await runNxCommandAsync(`generate @my-org/my-plugin:myPlugin ${plugin}`);\n\n const result = await runNxCommandAsync(`build ${plugin}`);\n expect(result.stdout).toContain('Executor ran');\n\n done();\n});\n```\n\n- The `uniq` function creates a random name with the prefix and a random number.\n- The `ensureNxProject` is the function that will create the temporary directory. It takes two arguments, the plugin package name and the dist directory of when it's built.\n- The `runNxCommandAsync` will execute a `nx` command in the E2E directory.\n\nThere are additional functions that the `@nrwl/nx-plugin/testing` package exports. Most of them are file utilities to manipulate and read files in the E2E directory.\n\n## Including Assets\n\nSometimes you might want to include some assets with the plugin. This might be a image or some additional binaries.\n\nTo make sure that assets are copied to the dist folder, open the plugin's `project.json` file. Inside the `build` property, add additional assets. By default, all `.md` files in the root, all non-ts files in folders, and the `generators.json` and `executors.json` files are included.\n\n```json\n\"build\": {\n \"executor\": \"@nrwl/node:package\",\n \"options\": {\n // shortened...\n \"assets\": [\n \"packages/my-plugin/*.md\",\n {\n \"input\": \"./packages/my-plugin/src\",\n \"glob\": \"**/*.!(ts)\",\n \"output\": \"./src\"\n },\n {\n \"input\": \"./packages/my-plugin\",\n \"glob\": \"generators.json\",\n \"output\": \".\"\n },\n {\n \"input\": \"./packages/my-plugin\",\n \"glob\": \"executors.json\",\n \"output\": \".\"\n }\n ]\n }\n}\n```\n\n## Using your Nx Plugin\n\nTo use your plugin, simply list it in `nx.json` or use its generators and executors as you would for any other plugin. This could look like `nx g @my-org/my-plugin:lib` for generators or `\"executor\": \"@my-org/my-plugin:build\"` for executors. It should be usable in all of the same ways as published plugins in your local workspace immediately after generating it. This includes setting it up as the default collection in `nx.json`, which would allow you to run `nx g lib` and hit your plugin's generator.\n\n## Publishing your Nx Plugin\n\nIn order to use your plugin in other workspaces or share it with the community, you will need to publish it to an npm registry. To publish your plugin follow these steps:\n\n1. Build your plugin with the command `nx run my-plugin:build`\n1. `npm publish ./dist/package/my-plugin` and follow the prompts from npm.\n1. That's it!\n\n> Note: currently you will have to modify the `package.json` version by yourself or with a tool.\n\nAfter that, you can then install your plugin like any other npm package,\n`npm i -D @my-org/my-plugin` or `yarn add -D @my-org/my-plugin`.\n\n### Listing your Nx Plugin\n\nNx provides a utility (`nx list`) that lists both core and community plugins. To submit your plugin, please follow the steps below:\n\n- Fork the [Nx repo](https://github.com/nrwl/nx/fork) (if you haven't already)\n- 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\n- Use the following commit message template: `chore(core): nx plugin submission [PLUGIN_NAME]`\n- push your changes, and run `yarn submit-plugin`\n\n> The `yarn submit-plugin` command automatically opens the Github pull request process with the correct template.\n\nWe will then verify the plugin, offer suggestions or merge the pull request!\n\n## Preset\n\nA Preset is a customization option which you provide when creating a new workspace. TS, Node, React are some internal presets that Nx provides by default.\n\n{% youtube\nsrc=\"https://www.youtube.com/embed/yGUrF0-uqaU\"\ntitle=\"Develop a Nx Preset for your Nx Plugin\"\nwidth=\"100%\" /%}\n\n### Custom Preset\n\nAt its core a preset is a generator, which we can create inside of a plugin.\nIf you **don't** have an existing plugin you can create one by running\n\n```bash\n npx create-nx-plugin my-org --pluginName my-plugin\n```\n\nTo create our preset inside of our plugin we can run\n\n```bash\n nx generate @nrwl/nx-plugin:generator --name=preset --project=happynrwl\n```\n\n> Note: the word `preset` is required for the name of this generator\n\nYou should have a similar structure to this:\n\n```treeview\nhappynrwl/\n\t├── e2e\n\t├── jest.config.js\n\t├── jest.preset.js\n\t├── nx.json\n\t├── package-lock.json\n\t├── package.json\n\t├── packages\n\t│ └── happynrwl\n\t│ ├── src\n\t│ │ ├── executors\n\t│ │ ├── generators\n\t│ │ │ ├── happynrwl\n\t│ │ │ └── preset \t\t// <------------- Here\n\t│ │ └── index.ts\n\t├── tools\n\t├── tsconfig.base.json\n\t└── workspace.json\n```\n\nAfter the command is finished, the preset generator is created under the folder named **preset**.\nThe **generator.ts** provides an entry point to the generator. This file contains a function that is called to perform manipulations on a tree that represents the file system. The **schema.json** provides a description of the generator, available options, validation information, and default values.\n\nHere is the sample generator function which you can customize to meet your needs.\n\n```typescript\nexport default async function (tree: Tree, options: PresetGeneratorSchema) {\n const normalizedOptions = normalizeOptions(tree, options);\n addProjectConfiguration(tree, normalizedOptions.projectName, {\n root: normalizedOptions.projectRoot,\n projectType: 'application',\n sourceRoot: `${normalizedOptions.projectRoot}/src`,\n targets: {\n exec: {\n executor: 'nx:run-commands',\n options: {\n command: `node ${projectRoot}/src/index.js`,\n },\n },\n },\n tags: normalizedOptions.parsedTags,\n });\n addFiles(tree, normalizedOptions);\n await formatFiles(tree);\n}\n```\n\nTo get an in-depth guide on customizing/running or debugging your generator see [workspace generators](https://nx.dev/generators/workspace-generators#running-a-workspace-generator).\n\n#### Usage\n\nBefore you are able to use your newly created preset you must package and publish it to a registry.\n\nAfter you have published your plugin to a registry you can now use your preset when creating a new workspace\n\n```bash\nnpx create-nx-workspace my-workspace --preset=my-plugin-name\n```\n" } ], "generators": [ diff --git a/docs/generated/packages/storybook.json b/docs/generated/packages/storybook.json index 40a8070e60..b5fdad5673 100644 --- a/docs/generated/packages/storybook.json +++ b/docs/generated/packages/storybook.json @@ -34,7 +34,7 @@ "id": "migrate-webpack-final-react", "name": "Migrate to the Nrwl React Storybook Preset", "file": "shared/guides/storybook/migrate-webpack-final-react", - "content": "# Nrwl React Storybook Preset\n\nNx 12.7 comes with a dedicated Storybook preset for React which drammatically simplifies the Storybook setup and makes sure that Storybook uses the same webpack configuration as your React applications running within an Nx workspace.\n\n\n\nHere are the main differences to the previous versions of Nx:\n\n- there's no `webpack.config.js`; Custom webpack configurations can be added in the `webpackFinal` property of the `main.js` file\n- the `main.js` file now contains a predefined Storybook preset exported by `@nrwl/react/plugins/storybook`.\n\nHere's an example of a newly generated `main.js` file:\n\n```javascript\n// project-level .storybook/main.js file\nconst rootMain = require('../../../.storybook/main');\n\nmodule.exports = {\n ...rootMain,\n\n core: {\n ...rootMain.core,\n // opt-into Storybook Webpack 5\n builder: 'webpack5'\n }\n\n stories: [\n ...rootMain.stories,\n '../src/lib/**/*.stories.mdx',\n '../src/lib/**/*.stories.@(js|jsx|ts|tsx)',\n ],\n addons: [...rootMain.addons, '@nrwl/react/plugins/storybook'],\n webpackFinal: async (config, { configType }) => {\n // apply any global webpack configs that might have been specified in .storybook/main.js\n if (rootMain.webpackFinal) {\n config = await rootMain.webpackFinal(config, { configType });\n }\n\n // add your own webpack tweaks if needed\n\n return config;\n },\n};\n```\n\nAt the Nx workspace root level, the configuration file looks as follows:\n\n```javascript\n// root level .storybook/main.js file\nmodule.exports = {\n stories: [],\n addons: ['@storybook/addon-essentials'],\n // uncomment the property below if you want to apply some webpack config globally\n // webpackFinal: async (config, { configType }) => {\n // // Make whatever fine-grained changes you need that should apply to all storybook configs\n\n // // Return the altered config\n // return config;\n // },\n};\n```\n\n## Migrating\n\nIf you're upgrading from a lower version of Nx, your old Storybook configuration will still work. New configurations generated will use the new syntax as shown above. The newly generated code will also make sure to extend from a global `webpack.config.js` which might exist in the root-level `.storybook/` directory of your Nx workspace.\n\nThis gives you the flexibility to incrementally migrate your configurations.\n\nHere's the step-by-step migration process:\n\n### 1. adjust the `main.js` file\n\nRestructure your `main.js` file so that it looks like in the example illustrated above.\n\nIf you need to keep your root-level `.storybook/webpack.config.js` for now, then make sure you adjust the `main.js` in a way that it properly calls the root-level `webpack.config.js` to inherit all of the global configurations.\n\n```javascript\nconst rootMain = require('../../../.storybook/main');\nconst rootWebpackConfig = require('../../../.storybook/webpack.config');\n\nmodule.exports = {\n ...rootMain,\n ...\n webpackFinal: async (config) => {\n // for backwards compatibility call the `rootWebpackConfig`\n // this can be removed once that one is migrated fully to\n // use the `webpackFinal` property in the `main.js` file\n config = rootWebpackConfig({ config });\n\n // add your own webpack tweaks if needed\n\n return config;\n },\n};\n```\n\n**Note:** The easiest way is probably to generate a new library and Storybook configuration and then copy & paste the `main.js`.\n\n### 2. Move any custom webpack configuration to `webpackFinal`\n\nIn previous versions of Nx a custom `webpack.config.js` was generated with the following content:\n\n```javascript\nmodule.exports = async ({ config, mode }) => {\n config = await rootWebpackConfig({ config, mode });\n\n const tsPaths = new TsconfigPathsPlugin({\n configFile: './tsconfig.base.json',\n });\n\n config.resolve.plugins\n ? config.resolve.plugins.push(tsPaths)\n : (config.resolve.plugins = [tsPaths]);\n\n // Found this here: https://github.com/nrwl/nx/issues/2859\n // And copied the part of the solution that made it work\n\n const svgRuleIndex = config.module.rules.findIndex((rule) => {\n const { test } = rule;\n\n return test.toString().startsWith('/\\\\.(svg|ico');\n });\n config.module.rules[svgRuleIndex].test =\n /\\.(ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\\?.*)?$/;\n\n config.module.rules.push(\n {\n test: /\\.(png|jpe?g|gif|webp)$/,\n loader: require.resolve('url-loader'),\n options: {\n limit: 10000, // 10kB\n name: '[name].[hash:7].[ext]',\n },\n },\n {\n test: /\\.svg$/,\n oneOf: [\n // If coming from JS/TS file, then transform into React component using SVGR.\n {\n issuer: {\n test: /\\.[jt]sx?$/,\n },\n use: [\n {\n loader: require.resolve('@svgr/webpack'),\n options: {\n svgo: false,\n titleProp: true,\n ref: true,\n },\n },\n {\n loader: require.resolve('url-loader'),\n options: {\n limit: 10000, // 10kB\n name: '[name].[hash:7].[ext]',\n esModule: false,\n },\n },\n ],\n },\n // Fallback to plain URL loader.\n {\n use: [\n {\n loader: require.resolve('url-loader'),\n options: {\n limit: 10000, // 10kB\n name: '[name].[hash:7].[ext]',\n },\n },\n ],\n },\n ],\n }\n );\n\n return config;\n};\n```\n\nSuch webpack file is no more needed as the `@nrwl/react/plugins/storybook` now takes care of it.\n\nIn case you made custom modifications to the `webpack.config.js` file, you need to move them over to the `main.js` `webpackFinal` property and then delete the `webpack.config.js`.\n\n### 3. Remove the root-level `.storybook/webpack.config.js` file\n\nOnce you've migrated all your libraries, you can think about removing the root-level `.storybook/webpack.config.js` file and migrate any custom configuration there to `.storybook/main.js` `webpackFinal` property in the very same folder.\n\n### 4. Opting in to Webpack 5\n\nIf you choose to opt-in to Webpack 5, by specifying `builder: 'webpack5'` in your project's `.storybook/main.(js|ts)` (as shown above, in the example of a newly generated `main.js` file), don't forget to add the Storybook dependencies for Webpack 5 to work:\n\n```shell\nyarn add -D @storybook/builder-webpack5 @storybook/manager-webpack5\n```\n\nor if you're using `npm`:\n\n```shell\nnpm install --save-dev @storybook/builder-webpack5 @storybook/manager-webpack5\n```\n" + "content": "# Nrwl React Storybook Preset\n\nNx 12.7 comes with a dedicated Storybook preset for React which drammatically simplifies the Storybook setup and makes sure that Storybook uses the same webpack configuration as your React applications running within an Nx workspace.\n\n{% youtube\nsrc=\"https://www.youtube.com/embed/oUE74McS_NY\"\ntitle=\"New in Nx 12.7: React Storybook Preset\"\nwidth=\"100%\" /%}\n\nHere are the main differences to the previous versions of Nx:\n\n- there's no `webpack.config.js`; Custom webpack configurations can be added in the `webpackFinal` property of the `main.js` file\n- the `main.js` file now contains a predefined Storybook preset exported by `@nrwl/react/plugins/storybook`.\n\nHere's an example of a newly generated `main.js` file:\n\n```javascript\n// project-level .storybook/main.js file\nconst rootMain = require('../../../.storybook/main');\n\nmodule.exports = {\n ...rootMain,\n\n core: {\n ...rootMain.core,\n // opt-into Storybook Webpack 5\n builder: 'webpack5'\n }\n\n stories: [\n ...rootMain.stories,\n '../src/lib/**/*.stories.mdx',\n '../src/lib/**/*.stories.@(js|jsx|ts|tsx)',\n ],\n addons: [...rootMain.addons, '@nrwl/react/plugins/storybook'],\n webpackFinal: async (config, { configType }) => {\n // apply any global webpack configs that might have been specified in .storybook/main.js\n if (rootMain.webpackFinal) {\n config = await rootMain.webpackFinal(config, { configType });\n }\n\n // add your own webpack tweaks if needed\n\n return config;\n },\n};\n```\n\nAt the Nx workspace root level, the configuration file looks as follows:\n\n```javascript\n// root level .storybook/main.js file\nmodule.exports = {\n stories: [],\n addons: ['@storybook/addon-essentials'],\n // uncomment the property below if you want to apply some webpack config globally\n // webpackFinal: async (config, { configType }) => {\n // // Make whatever fine-grained changes you need that should apply to all storybook configs\n\n // // Return the altered config\n // return config;\n // },\n};\n```\n\n## Migrating\n\nIf you're upgrading from a lower version of Nx, your old Storybook configuration will still work. New configurations generated will use the new syntax as shown above. The newly generated code will also make sure to extend from a global `webpack.config.js` which might exist in the root-level `.storybook/` directory of your Nx workspace.\n\nThis gives you the flexibility to incrementally migrate your configurations.\n\nHere's the step-by-step migration process:\n\n### 1. adjust the `main.js` file\n\nRestructure your `main.js` file so that it looks like in the example illustrated above.\n\nIf you need to keep your root-level `.storybook/webpack.config.js` for now, then make sure you adjust the `main.js` in a way that it properly calls the root-level `webpack.config.js` to inherit all of the global configurations.\n\n```javascript\nconst rootMain = require('../../../.storybook/main');\nconst rootWebpackConfig = require('../../../.storybook/webpack.config');\n\nmodule.exports = {\n ...rootMain,\n ...\n webpackFinal: async (config) => {\n // for backwards compatibility call the `rootWebpackConfig`\n // this can be removed once that one is migrated fully to\n // use the `webpackFinal` property in the `main.js` file\n config = rootWebpackConfig({ config });\n\n // add your own webpack tweaks if needed\n\n return config;\n },\n};\n```\n\n**Note:** The easiest way is probably to generate a new library and Storybook configuration and then copy & paste the `main.js`.\n\n### 2. Move any custom webpack configuration to `webpackFinal`\n\nIn previous versions of Nx a custom `webpack.config.js` was generated with the following content:\n\n```javascript\nmodule.exports = async ({ config, mode }) => {\n config = await rootWebpackConfig({ config, mode });\n\n const tsPaths = new TsconfigPathsPlugin({\n configFile: './tsconfig.base.json',\n });\n\n config.resolve.plugins\n ? config.resolve.plugins.push(tsPaths)\n : (config.resolve.plugins = [tsPaths]);\n\n // Found this here: https://github.com/nrwl/nx/issues/2859\n // And copied the part of the solution that made it work\n\n const svgRuleIndex = config.module.rules.findIndex((rule) => {\n const { test } = rule;\n\n return test.toString().startsWith('/\\\\.(svg|ico');\n });\n config.module.rules[svgRuleIndex].test =\n /\\.(ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\\?.*)?$/;\n\n config.module.rules.push(\n {\n test: /\\.(png|jpe?g|gif|webp)$/,\n loader: require.resolve('url-loader'),\n options: {\n limit: 10000, // 10kB\n name: '[name].[hash:7].[ext]',\n },\n },\n {\n test: /\\.svg$/,\n oneOf: [\n // If coming from JS/TS file, then transform into React component using SVGR.\n {\n issuer: {\n test: /\\.[jt]sx?$/,\n },\n use: [\n {\n loader: require.resolve('@svgr/webpack'),\n options: {\n svgo: false,\n titleProp: true,\n ref: true,\n },\n },\n {\n loader: require.resolve('url-loader'),\n options: {\n limit: 10000, // 10kB\n name: '[name].[hash:7].[ext]',\n esModule: false,\n },\n },\n ],\n },\n // Fallback to plain URL loader.\n {\n use: [\n {\n loader: require.resolve('url-loader'),\n options: {\n limit: 10000, // 10kB\n name: '[name].[hash:7].[ext]',\n },\n },\n ],\n },\n ],\n }\n );\n\n return config;\n};\n```\n\nSuch webpack file is no more needed as the `@nrwl/react/plugins/storybook` now takes care of it.\n\nIn case you made custom modifications to the `webpack.config.js` file, you need to move them over to the `main.js` `webpackFinal` property and then delete the `webpack.config.js`.\n\n### 3. Remove the root-level `.storybook/webpack.config.js` file\n\nOnce you've migrated all your libraries, you can think about removing the root-level `.storybook/webpack.config.js` file and migrate any custom configuration there to `.storybook/main.js` `webpackFinal` property in the very same folder.\n\n### 4. Opting in to Webpack 5\n\nIf you choose to opt-in to Webpack 5, by specifying `builder: 'webpack5'` in your project's `.storybook/main.(js|ts)` (as shown above, in the example of a newly generated `main.js` file), don't forget to add the Storybook dependencies for Webpack 5 to work:\n\n```shell\nyarn add -D @storybook/builder-webpack5 @storybook/manager-webpack5\n```\n\nor if you're using `npm`:\n\n```shell\nnpm install --save-dev @storybook/builder-webpack5 @storybook/manager-webpack5\n```\n" }, { "id": "migrate-webpack-final-angular", diff --git a/docs/nx-cloud/intro/nx-cloud.md b/docs/nx-cloud/intro/nx-cloud.md index 463785c882..63c9578b77 100644 --- a/docs/nx-cloud/intro/nx-cloud.md +++ b/docs/nx-cloud/intro/nx-cloud.md @@ -14,8 +14,14 @@ Most developers will benefit from Nx Cloud without ever changing any of their wo The [top level organization page](https://nx.app/orgs/5e38af6de037b5000598b2d6/workspaces/5edaf12087863a0005781f17) displays recent runs and a helpful dashboard of information about commands run in the repository. - +{% iframe +src="https://nx.app/orgs/5e38af6de037b5000598b2d6/workspaces/5edaf12087863a0005781f17?hideHeader=true" +title="Nx Cloud dashboard" +width="100%" /%} Each branch in the repository has its own [dedicated page](https://nx.app/branch?workspaceId=5edaf12087863a0005781f17&branchName=master) where you can view agent utilization and a waterfall task execution graph for the most recent runs against that branch. - +{% iframe +src="https://nx.app/branch?workspaceId=5edaf12087863a0005781f17&branchName=master&hideHeader=true" +title="Nx Cloud branch view" +width="100%" /%} diff --git a/docs/shared/angular-tutorial/01-create-application.md b/docs/shared/angular-tutorial/01-create-application.md index 891c9f1b50..593c56c2d3 100644 --- a/docs/shared/angular-tutorial/01-create-application.md +++ b/docs/shared/angular-tutorial/01-create-application.md @@ -1,6 +1,9 @@ # Angular Nx Tutorial - Step 1: Create Application - +{% youtube +src="https://www.youtube.com/embed/i37yJKK8qGI" +title="Nx.dev Tutorial | Angular | Step 1: Create Application" +width="100%" /%} In this tutorial you use Nx to build a full-stack application out of common libraries using modern technologies like Cypress and Nest. diff --git a/docs/shared/angular-tutorial/02-add-e2e-test.md b/docs/shared/angular-tutorial/02-add-e2e-test.md index 58bef5d334..428d6d847d 100644 --- a/docs/shared/angular-tutorial/02-add-e2e-test.md +++ b/docs/shared/angular-tutorial/02-add-e2e-test.md @@ -1,6 +1,9 @@ # Angular Nx Tutorial - Step 2: Add E2E Tests - +{% youtube +src="https://www.youtube.com/embed/owRAO75DIR4" +title="Nx.dev Tutorial | Angular | Step 2: Add E2E Test" +width="100%" /%} By default, Nx uses [Cypress](/cypress/overview) to run E2E tests. diff --git a/docs/shared/angular-tutorial/03-display-todos.md b/docs/shared/angular-tutorial/03-display-todos.md index c3e46d00de..124c57eac3 100644 --- a/docs/shared/angular-tutorial/03-display-todos.md +++ b/docs/shared/angular-tutorial/03-display-todos.md @@ -1,6 +1,9 @@ # Angular Nx Tutorial - Step 3: Display Todos - +{% youtube +src="https://www.youtube.com/embed/JlKAwGXmpac" +title="Nx.dev Tutorial | Angular | Step 3: Display Todos" +width="100%" /%} Great! You have a failing E2E test. Now you can make it pass! diff --git a/docs/shared/angular-tutorial/04-connect-to-api.md b/docs/shared/angular-tutorial/04-connect-to-api.md index bb79a5386f..087412ef74 100644 --- a/docs/shared/angular-tutorial/04-connect-to-api.md +++ b/docs/shared/angular-tutorial/04-connect-to-api.md @@ -1,6 +1,9 @@ # Angular Nx Tutorial - Step 4: Connect to an API - +{% youtube +src="https://www.youtube.com/embed/JlKAwGXmpac" +title="Nx.dev Tutorial | Angular | Step 4: Connect to API" +width="100%" /%} Real-world applications do not live in isolation — they need APIs to talk to. Setup your app to talk to an API. diff --git a/docs/shared/angular-tutorial/05-add-node-app.md b/docs/shared/angular-tutorial/05-add-node-app.md index bd7cbe34be..041a18afa5 100644 --- a/docs/shared/angular-tutorial/05-add-node-app.md +++ b/docs/shared/angular-tutorial/05-add-node-app.md @@ -1,6 +1,9 @@ # Angular Nx Tutorial - Step 5: Add Node Application Implementing an API - +{% youtube +src="https://www.youtube.com/embed/SsCx2WErVTI" +title="Nx.dev Tutorial | Angular | Step 5: Add Node Application Implementing API" +width="100%" /%} The requests fail because the API has not been created yet. Using Nx you can develop node applications next to your Angular applications. You can use same commands to run and test them. You can share code between the backend and the frontend. Use this capability to implement the API service. diff --git a/docs/shared/angular-tutorial/06-proxy.md b/docs/shared/angular-tutorial/06-proxy.md index 70c934a049..d858b7196e 100644 --- a/docs/shared/angular-tutorial/06-proxy.md +++ b/docs/shared/angular-tutorial/06-proxy.md @@ -1,6 +1,9 @@ # Angular Nx Tutorial - Step 6: Proxy - +{% youtube +src="https://www.youtube.com/embed/7d6jDAbmVnE" +title="Nx.dev Tutorial | Angular | Step 6: Configure Proxy" +width="100%" /%} You passed `--frontendProject=todos` when creating the node application. What did that argument do? diff --git a/docs/shared/angular-tutorial/07-share-code.md b/docs/shared/angular-tutorial/07-share-code.md index 61e1959edb..bd0643f3fb 100644 --- a/docs/shared/angular-tutorial/07-share-code.md +++ b/docs/shared/angular-tutorial/07-share-code.md @@ -1,6 +1,9 @@ # Angular Nx Tutorial - Step 7: Share Code - +{% youtube +src="https://www.youtube.com/embed/icyOSQ6gAm0" +title="Nx.dev Tutorial | Angular | Step 7: Share Code" +width="100%" /%} Awesome! The application is working end to end! However, there is a problem. Both the backend and the frontend define the `Todo` interface. The interface is in sync now, but in a real application, over time, it will diverge, and, as a result, runtime errors will creep in. You should share this interface between the backend and the frontend. In Nx, you can do this by creating a library. diff --git a/docs/shared/angular-tutorial/08-create-libs.md b/docs/shared/angular-tutorial/08-create-libs.md index dd49256082..009698b91a 100644 --- a/docs/shared/angular-tutorial/08-create-libs.md +++ b/docs/shared/angular-tutorial/08-create-libs.md @@ -1,6 +1,9 @@ # Angular Nx Tutorial - Step 8: Create Libs - +{% youtube +src="https://www.youtube.com/embed/szaH7fNw0zg" +title="Nx.dev Tutorial | Angular | Step 8: Create Libraries" +width="100%" /%} Libraries are not just a way to share code in Nx. They are also useful for factoring out code into small units with a well-defined public API. @@ -12,7 +15,7 @@ Every library has an `index.ts` file, which defines its public API. Other applic To illustrate how useful libraries can be, create a library of Angular components. -Use the generate to scaffold a new library: +Use the generator to scaffold a new library: ```sh npx nx g @nrwl/angular:lib ui diff --git a/docs/shared/angular-tutorial/09-dep-graph.md b/docs/shared/angular-tutorial/09-dep-graph.md index f263a020b7..13a6b48503 100644 --- a/docs/shared/angular-tutorial/09-dep-graph.md +++ b/docs/shared/angular-tutorial/09-dep-graph.md @@ -1,6 +1,9 @@ # Angular Nx Tutorial - Step 9: Using the Project Graph - +{% youtube +src="https://www.youtube.com/embed/8fr2RukmfW0" +title="Nx.dev Tutorial | Angular | Step 9: Dep Graph" +width="100%" /%} An Nx workspace can contain dozens or hundreds of applications and libraries. As a codebase grows, it becomes more difficult to understand how they depend on each other and the implications of making a particular change. diff --git a/docs/shared/angular-tutorial/10-computation-caching.md b/docs/shared/angular-tutorial/10-computation-caching.md index 0a60b6601c..4aea850da5 100644 --- a/docs/shared/angular-tutorial/10-computation-caching.md +++ b/docs/shared/angular-tutorial/10-computation-caching.md @@ -1,6 +1,9 @@ # Angular Nx Tutorial - Step 10: Computation Caching - +{% youtube +src="https://www.youtube.com/embed/HX3--ilBhBs" +title="Nx.dev Tutorial | Angular | Step 10: Use Computation Caching" +width="100%" /%} Nx has built-in computation caching, which helps drastically improve the performance of the commands. diff --git a/docs/shared/angular-tutorial/11-test-affected-projects.md b/docs/shared/angular-tutorial/11-test-affected-projects.md index 550b95fa45..45f1f2153a 100644 --- a/docs/shared/angular-tutorial/11-test-affected-projects.md +++ b/docs/shared/angular-tutorial/11-test-affected-projects.md @@ -1,6 +1,9 @@ # Angular Nx Tutorial - Step 11: Testing Affected Projects - +{% youtube +src="https://www.youtube.com/embed/5t77CPl-bbM" +title="Nx.dev Tutorial | Angular | Step 11: Test Affected Projects" +width="100%" /%} Because Nx understands the project graph of your workspace, Nx is efficient at retesting and rebuilding your projects. diff --git a/docs/shared/ci-overview.md b/docs/shared/ci-overview.md index f549850f1f..13aaca0109 100644 --- a/docs/shared/ci-overview.md +++ b/docs/shared/ci-overview.md @@ -16,7 +16,7 @@ Adding Nx to your CI pipeline makes this more efficient. Nx provides out-of-the-box implementation of CI workflows for `GitHub`, `Azure` and `CircleCI` during the [creation of the Nx workspace](/cli/create-nx-workspace#ci) or later using the [ci-workflow](/packages/workspace/generators/ci-workflow) generator. -
+{% nx-cloud-section %} ## Distributed CI with Nx Cloud @@ -45,7 +45,7 @@ npx nx-cloud stop-all-agents Learn more about configuring your CI environment using Nx Cloud with [Distributed Caching](/nx-cloud/set-up/set-up-caching) and [Distributed Task Execution](/nx-cloud/set-up/set-up-dte) in the Nx Cloud docs. -
+{% /nx-cloud-section %} ## CI provider specific documentation diff --git a/docs/shared/console.md b/docs/shared/console.md index b5ccca4453..68d83260af 100644 --- a/docs/shared/console.md +++ b/docs/shared/console.md @@ -56,35 +56,53 @@ Even though we started building Nx Console as a tool for experts, we also aimed The `Generate` action allows you to choose a generator and then opens a form listing out all the options for that generator. As you make changes to the form, the generator is executed in `--dry-run` mode in a terminal so you can preview the results of running the generator in real time. - +{% youtube +src="https://www.youtube.com/embed/-nUr66MWRiE" +title="Nx Console Generate UI Form" +width="100%" /%} **From the Command Palette** You can also launch the `Generate` action from the Command Palette (`⇧⌘P`) by selecting `nx: generate (ui)`. - +{% youtube +src="https://www.youtube.com/embed/Sk2XjFwF8Zo" +title="Nx Console Generate UI from Command Palette" +width="100%" /%} You can even construct the generator options while staying entirely within the Command Palette. Use `⇧⌘P` to open the Command Palette, then select `nx: generate`. After choosing a generator, select any of the listed options to modify the generator command. When you're satisfied with the constructed command, choose the `Execute` command at the top of the list. - +{% youtube +src="https://www.youtube.com/embed/q5NTTqRYq9c" +title="Nx Console Generate with Command Palette" +width="100%" /%} #### Run The `Run` action allows you to choose an executor command and then opens a form listing out all the options for that executor. The frequently used executor commands `build`, `serve`, `test`, `e2e` and `lint` also have their own dedicated actions. - +{% youtube +src="https://www.youtube.com/embed/rNImFxo9gYs" +title="Nx Console Run UI Form" +width="100%" /%} **From the Command Palette** You can also construct the executor command options while staying entirely within the Command Palette. Use `⇧⌘P` to open the Command Palette, then select `nx: test`. After choosing a project, select any of the listed options to modify the executor command options. When you're satisfied with the constructed command, choose the `Execute` command at the top of the list. - +{% youtube +src="https://www.youtube.com/embed/CsUkSyQcxwQ" +title="Nx Console Run from Command Palette" +width="100%" /%} #### Common Nx Commands You can also launch other common Nx commands with the options listed out in the Command Palette. - +{% youtube +src="https://www.youtube.com/embed/v6Tso0lB6S4" +title="Nx Console Affected" +width="100%" /%} #### Projects @@ -96,7 +114,10 @@ Clicking the ![folder-light.svg](./folder-light.svg) icon next to a project reve Clicking the ![continue-light.svg](./continue-light.svg) icon next to an executor command executes that command without prompting for options. - +{% youtube +src="https://www.youtube.com/embed/ve_N3unDqAg" +title="Nx Console Projects Pane" +width="100%" /%} #### Streamlining diff --git a/docs/shared/getting-started/nx-and-angular.md b/docs/shared/getting-started/nx-and-angular.md index 0023c06d33..b490f3e34a 100644 --- a/docs/shared/getting-started/nx-and-angular.md +++ b/docs/shared/getting-started/nx-and-angular.md @@ -21,7 +21,10 @@ Nx plugins helps you develop [Angular](/packages/angular) applications with full modern tools and libraries like [Jest](/jest/overview), [Cypress](/cypress/overview), [ESLint](/linter/eslint), [Storybook](/packages/storybook), [NgRx](/guides/misc-ngrx) and more. - +{% youtube +src="https://www.youtube.com/embed/cXOkmOy-8dk" +title="Modern Angular with Nx Dev Tools" +width="100%" /%} Check out the following to get started: diff --git a/docs/shared/getting-started/nx-and-react.md b/docs/shared/getting-started/nx-and-react.md index 1c6755f223..f9c6fbc588 100644 --- a/docs/shared/getting-started/nx-and-react.md +++ b/docs/shared/getting-started/nx-and-react.md @@ -21,7 +21,10 @@ and libraries like [Jest](/jest/overview), [Cypress](/cypress/overview), [Storybook](/packages/storybook), [ESLint](/linter/eslint), and more. Nx also supports React frameworks like [Next.js](/next/overview), Remix, and has great support for [React Native](/react-native/overview). - +{% youtube +src="https://www.youtube.com/embed/sNz-4PUM0k8" +title="Scale your React development with Nx" +width="100%" /%} Check out the following to get started: diff --git a/docs/shared/guides/nx-and-ts.md b/docs/shared/guides/nx-and-ts.md index 8f6e8c5fc5..7a7ef13e62 100644 --- a/docs/shared/guides/nx-and-ts.md +++ b/docs/shared/guides/nx-and-ts.md @@ -4,9 +4,12 @@ The `@nrwl/js` package ships with corresponding generators and executors that best work when it comes to developing TypeScript applications and libraries. -> Note, you can also opt-out of TypeScript and use plain JavaScript by passing the `--js` flag to the generators. +> Note, you can also opt out of TypeScript and use plain JavaScript by passing the `--js` flag to the generators. - +{% youtube +src="https://www.youtube.com/embed/-OmQ-PaSY5M" +title="Develop great Typescript Packages with Nx" +width="100%" /%} `@nrwl/js` is particularly useful if you want to diff --git a/docs/shared/guides/nx-devkit-angular-devkit.md b/docs/shared/guides/nx-devkit-angular-devkit.md index 73408a07cb..6d7f6b599e 100644 --- a/docs/shared/guides/nx-devkit-angular-devkit.md +++ b/docs/shared/guides/nx-devkit-angular-devkit.md @@ -193,7 +193,3 @@ The schema files for both Nx Devkit executors and Angular Builders are the same. If you are writing an Nx plugin, use Nx Devkit. It's **much** easier to use and debug. It has better docs and more people supporting it. Do you have to rewrite your Nx Plugin if it is written using Angular Devkit? No. Nx supports both and will always support both. And, most importantly, the end user might not even know what you used to write a generator or an executor. - -``` - -``` diff --git a/docs/shared/guides/storybook/migrate-webpack-final-react.md b/docs/shared/guides/storybook/migrate-webpack-final-react.md index 6ad1e4cbc8..7b4a70e038 100644 --- a/docs/shared/guides/storybook/migrate-webpack-final-react.md +++ b/docs/shared/guides/storybook/migrate-webpack-final-react.md @@ -2,7 +2,10 @@ Nx 12.7 comes with a dedicated Storybook preset for React which drammatically simplifies the Storybook setup and makes sure that Storybook uses the same webpack configuration as your React applications running within an Nx workspace. - +{% youtube +src="https://www.youtube.com/embed/oUE74McS_NY" +title="New in Nx 12.7: React Storybook Preset" +width="100%" /%} Here are the main differences to the previous versions of Nx: diff --git a/docs/shared/migration/adding-to-monorepo.md b/docs/shared/migration/adding-to-monorepo.md index 57031bcfa5..5ebb8563a9 100644 --- a/docs/shared/migration/adding-to-monorepo.md +++ b/docs/shared/migration/adding-to-monorepo.md @@ -12,7 +12,10 @@ npx add-nx-to-monorepo Here's a short video walking you through the steps of adding Nx to a Lerna & Yarn workspaces based monorepo: - +{% youtube +src="https://www.youtube.com/embed/hCm373Aq1uQ" +title="Add Nx to a Lerna & Yarn workspaces monorepo" +width="100%" /%} `npx add-nx-to-monorepo` does the following: @@ -94,12 +97,21 @@ In addition, Nx makes a lot of things much easier, like building large apps incr ### Speeding Up Facebook React Monorepo with Nx - +{% youtube +src="https://www.youtube.com/embed/XLP2RAOwfLQ" +title="Speeding Up github.com/facebook/react with Nx" +width="100%" /%} ### Speeding Up Remotion Monorepo with Nx - +{% youtube +src="https://www.youtube.com/embed/TXySu4dZLp0" +title="Speeding Up Remotion Monorepo with Nx" +width="100%" /%} ### Speeding Up Storybook Monorepo with Nx - +{% youtube +src="https://www.youtube.com/embed/3o8w6jbDr4A" +title="Speeding Up Storybook Monorepo with Nx" +width="100%" /%} diff --git a/docs/shared/migration/migration-angular.md b/docs/shared/migration/migration-angular.md index 7d3edbcabf..fea7de32d7 100644 --- a/docs/shared/migration/migration-angular.md +++ b/docs/shared/migration/migration-angular.md @@ -410,7 +410,10 @@ Learn more about the advantages of Nx in the following guides: ## From Nx Console - +{% youtube +src="https://www.youtube.com/embed/vRj9SNVYKrE" +title="Nx Console Updates 17.15.0" +width="100%" /%} As of Nx Console version 17.15.0, Angular CLI users will receive a notice periodically when running commands via Nx Console, asking if they want to use Nx to make their Angular commands faster. diff --git a/docs/shared/migration/migration-cra.md b/docs/shared/migration/migration-cra.md index 99d15aeee8..6a2245bdfb 100644 --- a/docs/shared/migration/migration-cra.md +++ b/docs/shared/migration/migration-cra.md @@ -25,7 +25,10 @@ Start from [the commands mentioned in this article](https://nx.dev/migration/mig See it in action: - +{% youtube +src="https://www.youtube.com/embed/_XmbVpwo1vs" +title="Switch from CRA to Nx" +width="100%" /%} ## Doing the migration manually diff --git a/docs/shared/monorepo-ci-azure.md b/docs/shared/monorepo-ci-azure.md index 640d939ea9..3bf8413017 100644 --- a/docs/shared/monorepo-ci-azure.md +++ b/docs/shared/monorepo-ci-azure.md @@ -40,7 +40,7 @@ jobs: The `main` job implements the CI workflow. -
+{% nx-cloud-section %} ## Distributed CI with Nx Cloud @@ -97,4 +97,4 @@ jobs: You can also use our [ci-workflow generator](/packages/workspace/generators/ci-workflow) to generate the pipeline file. -
+{% /nx-cloud-section %} diff --git a/docs/shared/monorepo-ci-circle-ci.md b/docs/shared/monorepo-ci-circle-ci.md index 891db9494e..9edf92f9e0 100644 --- a/docs/shared/monorepo-ci-circle-ci.md +++ b/docs/shared/monorepo-ci-circle-ci.md @@ -37,7 +37,7 @@ To use the [Nx Orb](https://github.com/nrwl/nx-orb) with a private repository on > Note: It should be a user token, not project token. -
+{% nx-cloud-section %} ## Distributed CI with Nx Cloud @@ -93,4 +93,4 @@ workflows: You can also use our [ci-workflow generator](/packages/workspace/generators/ci-workflow) to generate the configuration file. -
+{% /nx-cloud-section %} diff --git a/docs/shared/monorepo-ci-github-actions.md b/docs/shared/monorepo-ci-github-actions.md index 3e858beff6..ae0243b7d3 100644 --- a/docs/shared/monorepo-ci-github-actions.md +++ b/docs/shared/monorepo-ci-github-actions.md @@ -32,7 +32,7 @@ jobs: The `pr` and `main` jobs implement the CI workflow. Setting `timeout-minutes` is needed only if you have very slow tasks. -
+{% nx-cloud-section %} ## Distributed CI with Nx Cloud @@ -71,4 +71,4 @@ jobs: You can also use our [ci-workflow generator](/packages/workspace/generators/ci-workflow) to generate the workflow file. -
+{% /nx-cloud-section %} diff --git a/docs/shared/monorepo-ci-gitlab.md b/docs/shared/monorepo-ci-gitlab.md index 99c690db2d..9abdeb75c2 100644 --- a/docs/shared/monorepo-ci-gitlab.md +++ b/docs/shared/monorepo-ci-gitlab.md @@ -61,7 +61,7 @@ build: The `build` and `test` jobs implement the CI workflow using `.distributed` as template to keep CI configuration file more readable. -
+{% nx-cloud-section %} ## Distributed CI with Nx Cloud @@ -69,4 +69,4 @@ In order to use distributed task execution, we need to start agents and set the Read more about the [Distributed CI setup with Nx Cloud](/using-nx/ci-overview#distributed-ci-with-nx-cloud). -
+{% /nx-cloud-section %} diff --git a/docs/shared/monorepo-ci-jenkins.md b/docs/shared/monorepo-ci-jenkins.md index f035426167..fd72821414 100644 --- a/docs/shared/monorepo-ci-jenkins.md +++ b/docs/shared/monorepo-ci-jenkins.md @@ -51,7 +51,7 @@ pipeline { The `pr` and `main` jobs implement the CI workflow. -
+{% nx-cloud-section %} ## Distributed CI with Nx Cloud @@ -107,4 +107,4 @@ pipeline { } ``` -
+{% /nx-cloud-section %} diff --git a/docs/shared/node-tutorial/01-create-application.md b/docs/shared/node-tutorial/01-create-application.md index 29286db958..67349cb4e8 100644 --- a/docs/shared/node-tutorial/01-create-application.md +++ b/docs/shared/node-tutorial/01-create-application.md @@ -1,6 +1,9 @@ # Node Nx Tutorial - Step 1: Create Application - +{% youtube +src="https://www.youtube.com/embed/UcBSBQYNlhE" +title="Nx.dev Tutorial | Node | Step 1: Create Application" +width="100%" /%} In this tutorial you use Nx to build a server application out of common libraries using modern technologies. diff --git a/docs/shared/node-tutorial/02-display-todos.md b/docs/shared/node-tutorial/02-display-todos.md index abc5772b56..4a83d1114c 100644 --- a/docs/shared/node-tutorial/02-display-todos.md +++ b/docs/shared/node-tutorial/02-display-todos.md @@ -1,6 +1,9 @@ # Node Nx Tutorial - Step 2: Display todos - +{% youtube +src="https://www.youtube.com/embed/I4-sO2LeVbU" +title="Nx.dev Tutorial | Node | Step 2: Display Todos" +width="100%" /%} Great! you now have a server application set up to show some data when going to the `/api` route. diff --git a/docs/shared/node-tutorial/03-share-code.md b/docs/shared/node-tutorial/03-share-code.md index ef4088bb4f..27a9167cd7 100644 --- a/docs/shared/node-tutorial/03-share-code.md +++ b/docs/shared/node-tutorial/03-share-code.md @@ -1,6 +1,9 @@ # Node Nx Tutorial - Step 3: Share Code - +{% youtube +src="https://www.youtube.com/embed/MqqwOoKa-Ho" +title="Nx.dev Tutorial | Node | Step 3: Share Code" +width="100%" /%} Awesome! The application is working as expected! diff --git a/docs/shared/node-tutorial/04-create-libs.md b/docs/shared/node-tutorial/04-create-libs.md index f9d9ba6f47..f9f610efea 100644 --- a/docs/shared/node-tutorial/04-create-libs.md +++ b/docs/shared/node-tutorial/04-create-libs.md @@ -1,6 +1,9 @@ # Node Nx Tutorial - Step 4: Create Libraries - +{% youtube +src="https://www.youtube.com/embed/V29I_DHGlB8" +title="Nx.dev Tutorial | Node | Step 4: Create Libraries" +width="100%" /%} Libraries are not just a way to share code in Nx. They are also useful for factoring out code into small units with a well-defined public API. diff --git a/docs/shared/node-tutorial/05-dep-graph.md b/docs/shared/node-tutorial/05-dep-graph.md index 21d2c86420..53d125ee27 100644 --- a/docs/shared/node-tutorial/05-dep-graph.md +++ b/docs/shared/node-tutorial/05-dep-graph.md @@ -1,6 +1,9 @@ # Node Nx Tutorial - Step 5: Project Graph - +{% youtube +src="https://www.youtube.com/embed/l9MjZ9IPdu4" +title="Nx.dev Tutorial | Node | Step 5: Dep Graph" +width="100%" /%} An Nx workspace can contain dozens or hundreds of applications and libraries. As a codebase grows, it becomes more difficult to understand how they depend on each other and the implications of making a particular change. diff --git a/docs/shared/node-tutorial/06-computation-caching.md b/docs/shared/node-tutorial/06-computation-caching.md index 5707e67af1..dcea04838d 100644 --- a/docs/shared/node-tutorial/06-computation-caching.md +++ b/docs/shared/node-tutorial/06-computation-caching.md @@ -1,6 +1,9 @@ # Node Nx Tutorial - Step 6: Computation Caching - +{% youtube +src="https://www.youtube.com/embed/gXChzhI1Qpg" +title="Nx.dev Tutorial | Node | Step 6: Computation Caching" +width="100%" /%} Nx has built-in computation caching, which drastically improves the performance of the commands. diff --git a/docs/shared/node-tutorial/07-test-affected-projects.md b/docs/shared/node-tutorial/07-test-affected-projects.md index df8eeafed1..3e3a769ea1 100644 --- a/docs/shared/node-tutorial/07-test-affected-projects.md +++ b/docs/shared/node-tutorial/07-test-affected-projects.md @@ -1,6 +1,9 @@ # Node Nx Tutorial - Step 7: Test Affected Projects - +{% youtube +src="https://www.youtube.com/embed/TRRVLyHfN60" +title="Nx.dev Tutorial | Node | Step 7: Test Affected Projects" +width="100%" /%} In addition to supporting computation caching, Nx scales your development by doing code change analysis to see what apps or libraries are affected by a particular pull request. diff --git a/docs/shared/nx-cloud-logo.svg b/docs/shared/nx-cloud-logo.svg new file mode 100644 index 0000000000..bdbbc8fb36 --- /dev/null +++ b/docs/shared/nx-cloud-logo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/docs/shared/nx-core.md b/docs/shared/nx-core.md index cd259b937d..7adb88c32f 100644 --- a/docs/shared/nx-core.md +++ b/docs/shared/nx-core.md @@ -186,4 +186,7 @@ what `build` means. It can be an npm script, a custom Nx executor, a Gradle task As you can see, the core of Nx is generic, simple, and unobtrusive. Nx Plugins are completely optional, but they can really level up your developer experience. Watch this video to see the plugins in action. - +{% youtube +src="https://www.youtube.com/embed/BO1rwynFBLM" +title="Lerna/Yarn to Nx: Faster Build Times + Better Dev Ergonomics" +width="100%" /%} diff --git a/docs/shared/nx-plugin.md b/docs/shared/nx-plugin.md index 89e0a56d94..106f34ee61 100644 --- a/docs/shared/nx-plugin.md +++ b/docs/shared/nx-plugin.md @@ -4,7 +4,10 @@ Nx plugins are npm packages that contain generators and executors to extend a Nx > A list of custom plugins created by the community is found in the [Community](/community) section. > Plugins are written using Nx Devkit. **Read [Nx Devkit](/devkit/index) for more information.** - +{% youtube +src="https://www.youtube.com/embed/fC1-4fAZDP4" +title="Nx Tutorial: Building Custom Plugins for Nx" +width="100%" /%} ## Generating a Plugin @@ -14,7 +17,7 @@ To get started with building a Nx Plugin, run the following command: npx create-nx-plugin my-org --pluginName my-plugin ``` -This command creates a brand new workspace, and sets up a pre-configured plugin with the specified name. +This command creates a brand-new workspace, and sets up a pre-configured plugin with the specified name. > Note, the command above will create a plugin the package name set to `@my-org/my-plugin`. You can pass `--importPath` to provide a different package name. @@ -31,7 +34,7 @@ The created generator contains boilerplate that will do the following: - Add the plugin's project to the `nx.json` file - Add files to the disk using templates -There will be a exported default function that will be the main entry for the generator. +There will be an exported default function that will be the main entry for the generator. ### Generator options @@ -175,10 +178,13 @@ We will then verify the plugin, offer suggestions or merge the pull request! ## Preset -A Preset is a customization option which you provide when creating a new workspace. TS, Node, React are some of the internal presets that Nx provides by default. +A Preset is a customization option which you provide when creating a new workspace. TS, Node, React are some internal presets that Nx provides by default. + +{% youtube +src="https://www.youtube.com/embed/yGUrF0-uqaU" +title="Develop a Nx Preset for your Nx Plugin" +width="100%" /%} - - ### Custom Preset At its core a preset is a generator, which we can create inside of a plugin. diff --git a/docs/shared/react-tutorial/01-create-application.md b/docs/shared/react-tutorial/01-create-application.md index dfa57e1c5d..1c073e7a32 100644 --- a/docs/shared/react-tutorial/01-create-application.md +++ b/docs/shared/react-tutorial/01-create-application.md @@ -1,6 +1,9 @@ # React Nx Tutorial - Step 1: Create Application - +{% youtube +src="https://www.youtube.com/embed/HcQE5R6ucng" +title="Nx.dev Tutorial | React | Step 1: Create Application" +width="100%" /%} In this tutorial you use Nx to build a full-stack application out of common libraries using modern technologies. diff --git a/docs/shared/react-tutorial/02-add-e2e-test.md b/docs/shared/react-tutorial/02-add-e2e-test.md index ae4830e78d..2254738e3a 100644 --- a/docs/shared/react-tutorial/02-add-e2e-test.md +++ b/docs/shared/react-tutorial/02-add-e2e-test.md @@ -1,6 +1,9 @@ # React Nx Tutorial - Step 2: Add E2E Tests - +{% youtube +src="https://www.youtube.com/embed/3HSzqt3WiVg" +title="Nx.dev Tutorial | React | Step 2: Add E2E Tests" +width="100%" /%} By default, Nx uses [Cypress](https://cypress.io) to run E2E tests. diff --git a/docs/shared/react-tutorial/03-display-todos.md b/docs/shared/react-tutorial/03-display-todos.md index e13c3edef7..79e3d302c2 100644 --- a/docs/shared/react-tutorial/03-display-todos.md +++ b/docs/shared/react-tutorial/03-display-todos.md @@ -1,6 +1,9 @@ # React Nx Tutorial - Step 3: Display Todos - +{% youtube +src="https://www.youtube.com/embed/fNehP0WX__c" +title="Nx.dev Tutorial | React | Step 3: Display Todos" +width="100%" /%} Great! You have a failing E2E test. Now you can make it pass! diff --git a/docs/shared/react-tutorial/04-connect-to-api.md b/docs/shared/react-tutorial/04-connect-to-api.md index 4dab973a7c..ab59f56a9a 100644 --- a/docs/shared/react-tutorial/04-connect-to-api.md +++ b/docs/shared/react-tutorial/04-connect-to-api.md @@ -1,6 +1,9 @@ # React Nx Tutorial - Step 4: Connect to an API - +{% youtube +src="https://www.youtube.com/embed/HexxYHpIfAo" +title="Nx.dev Tutorial | React | Step 4: Connect to an API" +width="100%" /%} Real-world applications do not live in isolation — they need APIs to talk to. Setup your app to talk to an API. diff --git a/docs/shared/react-tutorial/05-add-node-app.md b/docs/shared/react-tutorial/05-add-node-app.md index 91bb44b66b..8fe01e90bc 100644 --- a/docs/shared/react-tutorial/05-add-node-app.md +++ b/docs/shared/react-tutorial/05-add-node-app.md @@ -1,6 +1,9 @@ # React Nx Tutorial - Step 5: Add Node Application Implementing API - +{% youtube +src="https://www.youtube.com/embed/XgfknOqgxQ0" +title="Nx.dev Tutorial | React | Step 5: Add Node Application Implementing API" +width="100%" /%} The requests fail because the API has not been created yet. Using Nx you develop node applications next to your React applications. You can use same commands to run and test them. You share code between the backend and the frontend. Use this capability to implement the API service. diff --git a/docs/shared/react-tutorial/06-proxy.md b/docs/shared/react-tutorial/06-proxy.md index adb87c5801..a03238b4f0 100644 --- a/docs/shared/react-tutorial/06-proxy.md +++ b/docs/shared/react-tutorial/06-proxy.md @@ -1,6 +1,9 @@ # React Nx Tutorial - Step 6: Proxy Configuration - +{% youtube +src="https://www.youtube.com/embed/xfvCz-yLeEw" +title="Nx.dev Tutorial | React | Step 6: Proxy" +width="100%" /%} You passed `--frontendProject=todos` when creating the node application. What did that argument do? diff --git a/docs/shared/react-tutorial/07-share-code.md b/docs/shared/react-tutorial/07-share-code.md index 822f4835bf..5dcb50f191 100644 --- a/docs/shared/react-tutorial/07-share-code.md +++ b/docs/shared/react-tutorial/07-share-code.md @@ -1,6 +1,9 @@ # React Nx Tutorial - Step 7: Share Code - +{% youtube +src="https://www.youtube.com/embed/-zzw4_oT_2I" +title="Nx.dev Tutorial | React | Step 7: Share Code" +width="100%" /%} Awesome! The application is working end to end! However, there is a problem. Both the backend and the frontend define the `Todo` interface. The interface is in sync now, but in a real application, over time, it diverges, and, as a result, runtime errors creep in. You should share this interface between the backend and the frontend. In Nx, you do this by creating a library. diff --git a/docs/shared/react-tutorial/08-create-libs.md b/docs/shared/react-tutorial/08-create-libs.md index 4fe1e821cb..fac5748f4d 100644 --- a/docs/shared/react-tutorial/08-create-libs.md +++ b/docs/shared/react-tutorial/08-create-libs.md @@ -1,6 +1,9 @@ # React Nx Tutorial - Step 8: Create Libs - +{% youtube +src="https://www.youtube.com/embed/a1CAYlXizWM" +title="Nx.dev Tutorial | React | Step 8: Create Libs" +width="100%" /%} Libraries are not just a way to share code in Nx. They are also useful for factoring out code into small units with a well-defined public API. diff --git a/docs/shared/react-tutorial/09-dep-graph.md b/docs/shared/react-tutorial/09-dep-graph.md index fa6a7d220a..39ebd3c1a1 100644 --- a/docs/shared/react-tutorial/09-dep-graph.md +++ b/docs/shared/react-tutorial/09-dep-graph.md @@ -1,6 +1,9 @@ # React Nx Tutorial - Step 9: Project Graph - +{% youtube +src="https://www.youtube.com/embed/Dr7jI9RYcmY" +title="Nx.dev Tutorial | React | Step 9: Dep Graph" +width="100%" /%} An Nx workspace can contain dozens or hundreds of applications and libraries. As a codebase grows, it can be difficult to understand how they depend on each other and the implications of making a particular change. diff --git a/docs/shared/react-tutorial/10-computation-caching.md b/docs/shared/react-tutorial/10-computation-caching.md index 4678e3a3e2..949af937a2 100644 --- a/docs/shared/react-tutorial/10-computation-caching.md +++ b/docs/shared/react-tutorial/10-computation-caching.md @@ -1,6 +1,9 @@ # React Nx Tutorial - Step 10: Computation Caching - +{% youtube +src="https://www.youtube.com/embed/aNjvT3VX1Ts" +title="Nx.dev Tutorial | React | step 10: Computation Caching" +width="100%" /%} Nx has built-in computation caching, which helps drastically improve the performance of the commands. diff --git a/docs/shared/react-tutorial/11-test-affected-projects.md b/docs/shared/react-tutorial/11-test-affected-projects.md index 68c2275b1d..989665605d 100644 --- a/docs/shared/react-tutorial/11-test-affected-projects.md +++ b/docs/shared/react-tutorial/11-test-affected-projects.md @@ -1,6 +1,9 @@ # React Nx Tutorial - Step 11: Test Affected Projects - +{% youtube +src="https://www.youtube.com/embed/_mBBFRjs01g" +title="Nx.dev Tutorial | React | Step 11: Test Affected Projects" +width="100%" /%} In addition to supporting computation caching, Nx scales your development by doing code change analysis to see what is affected by a particular pull request. diff --git a/docs/shared/using-nx/caching.md b/docs/shared/using-nx/caching.md index 54afec7cbe..460cccf0ce 100644 --- a/docs/shared/using-nx/caching.md +++ b/docs/shared/using-nx/caching.md @@ -199,7 +199,7 @@ The cache is stored in `node_modules/.cache/nx` by default. To change the cache By default, Nx uses a local computation cache. Nx stores the cached values only for a week, after which they are deleted. To clear the cache run `nx reset`, and Nx creates a new one the next time it tries to access it. -
+{% nx-cloud-section %} ## Distributed Computation Caching @@ -243,7 +243,7 @@ Tony pushes a branch up to CI, but CI doesn't pass. He asks Sofija to help. Sofi Maya and Trey push up changes to two different apps that both depend on an unchanged shared buildable library. CI reuses the build output of the shared buildable library when building the apps in the two different PRs. -
+{% /nx-cloud-section %} ## Example diff --git a/docs/shared/using-nx/dte.md b/docs/shared/using-nx/dte.md index f9f13abc64..ab9e930efd 100644 --- a/docs/shared/using-nx/dte.md +++ b/docs/shared/using-nx/dte.md @@ -2,7 +2,7 @@ > Before reading this guide, check out the [mental model guide](/using-nx/mental-model). It will help you understand how computation caching fits into the rest of Nx. -
+{% nx-cloud-section %} ## Overview @@ -35,4 +35,4 @@ These are the savings you get by enabling Distributed Task Execution in your CI ![DTE](/shared/using-nx/dte.png) -
+{% /nx-cloud-section %} diff --git a/docs/shared/workspace/structure/dependency-graph.md b/docs/shared/workspace/structure/dependency-graph.md index b63c74b51a..de3d678470 100644 --- a/docs/shared/workspace/structure/dependency-graph.md +++ b/docs/shared/workspace/structure/dependency-graph.md @@ -2,7 +2,10 @@ To be able to support the monorepo-style development, the tools must know how different projects in your workspace depend on each other. Nx uses advanced code analysis to construct this project graph. And it gives you a way to explore it: - +{% youtube +src="https://www.youtube.com/embed/cMZ-ReC-jWU" +title="Nx Tutorial: Improved Dependency Graph Visualization for Nx" +width="100%" /%} ## How the Project Graph is Built diff --git a/nx-dev/feature-doc-viewer/src/lib/content.tsx b/nx-dev/feature-doc-viewer/src/lib/content.tsx index 88567e8362..79f6feec8a 100644 --- a/nx-dev/feature-doc-viewer/src/lib/content.tsx +++ b/nx-dev/feature-doc-viewer/src/lib/content.tsx @@ -1,118 +1,15 @@ -import { sendCustomEvent } from '@nrwl/nx-dev/feature-analytics'; import { DocumentData } from '@nrwl/nx-dev/models-document'; -import { ReactComponentElement } from 'react'; -import ReactMarkdown from 'react-markdown'; -import raw from 'rehype-raw'; -import autolinkHeadings from 'rehype-autolink-headings'; -import slug from 'rehype-slug'; -import gfm from 'remark-gfm'; -import { CodeBlock } from './code-block'; -import { renderIframes } from './renderers/render-iframe'; -import { transformImagePath } from './renderers/transform-image-path'; +import { renderMarkdown } from '@nrwl/nx-dev/ui-markdoc'; +import { ReactNode } from 'react'; export interface ContentProps { document: DocumentData; } -interface ComponentsConfig { - readonly code: { callback: (command: string) => void }; -} - -const components: any = (config: ComponentsConfig) => ({ - img({ node, alt, src, ...props }) { - return {alt}; - }, - code({ node, inline, className, children, ...props }) { - const language = /language-(\w+)/.exec(className || '')?.[1]; - return !inline && language ? ( - config.code.callback(command)} - /> - ) : ( - - {children} - - ); - }, - pre({ children }) { - return <>{children}; - }, -}); - -export function Content(props: ContentProps): ReactComponentElement { - return ( -
- - sendCustomEvent( - 'code-snippets', - 'click', - props.document.filePath - ), - }, - })} - /> -
- ); -} - -function createAnchorContent(node: any) { - node.properties.className = ['group']; - return { - type: 'element', - tagName: 'svg', - properties: { - xmlns: 'http://www.w3.org/2000/svg', - className: [ - 'inline', - 'ml-2', - 'mb-1', - `h-5`, - `w-5`, - 'opacity-0', - 'group-hover:opacity-100', - ], - fill: 'none', - viewBox: '0 0 24 24', - stroke: 'currentColor', - }, - children: [ - { - type: 'element', - tagName: 'path', - properties: { - 'stroke-linecap': 'round', - 'stroke-linejoin': 'round', - 'stroke-width': '2', - d: 'M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1', - }, - children: [], - }, - ], - }; -} +export const Content = (props: ContentProps): ReactNode => ( +
+
{renderMarkdown(props.document)}
+
+); export default Content; diff --git a/nx-dev/feature-doc-viewer/src/lib/renderers/render-iframe.ts b/nx-dev/feature-doc-viewer/src/lib/renderers/render-iframe.ts deleted file mode 100644 index aaee57a8c6..0000000000 --- a/nx-dev/feature-doc-viewer/src/lib/renderers/render-iframe.ts +++ /dev/null @@ -1,21 +0,0 @@ -export function renderIframes(): (tree: any) => void { - return (tree): void => { - const iframeList = tree.children.filter( - (child) => child.type === 'raw' && child.value.includes(' { - item.type = 'element'; - item.tagName = 'iframe'; - item.children = []; - item.properties = {}; - let match; - const regex = new RegExp( - '[\\s\\r\\t\\n]*([a-z0-9\\-_]+)[\\s\\r\\t\\n]*=[\\s\\r\\t\\n]*([\'"])((?:\\\\\\2|(?!\\2).)*)\\2', - 'ig' - ); - while ((match = regex.exec(item.value))) { - item.properties[match[1]] = match[3]; - } - }); - }; -} diff --git a/nx-dev/feature-doc-viewer/src/lib/renderers/transform-image-path.ts b/nx-dev/feature-doc-viewer/src/lib/renderers/transform-image-path.ts deleted file mode 100644 index e697e88318..0000000000 --- a/nx-dev/feature-doc-viewer/src/lib/renderers/transform-image-path.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { DocumentData } from '@nrwl/nx-dev/data-access-documents'; -import { join } from 'path'; -import { uriTransformer } from 'react-markdown'; - -export function transformImagePath({ - document, -}: { - document: DocumentData; -}): (src: string) => string { - return (src) => { - const isRelative = src.startsWith('.'); - - if (!/\.(gif|jpe?g|tiff?|png|webp|bmp|svg)$/i.test(src)) { - return uriTransformer(src); - } - - if (isRelative) { - return uriTransformer( - join('/', document.filePath.split('/').splice(3).join('/'), '..', src) - ); - } - - return uriTransformer(`/documentation`.concat(src)); - }; -} diff --git a/nx-dev/feature-package-schema-viewer/src/lib/content.tsx b/nx-dev/feature-package-schema-viewer/src/lib/content.tsx index 78183cfdd0..0c7cd81b3a 100644 --- a/nx-dev/feature-package-schema-viewer/src/lib/content.tsx +++ b/nx-dev/feature-package-schema-viewer/src/lib/content.tsx @@ -2,15 +2,15 @@ import { XCircleIcon } from '@heroicons/react/solid'; import { getSchemaFromReference } from '@nrwl/nx-dev/data-access-packages'; import { JsonSchema1, NxSchema } from '@nrwl/nx-dev/models-package'; import { Breadcrumbs } from '@nrwl/nx-dev/ui-common'; +import { renderMarkdown } from '@nrwl/nx-dev/ui-markdoc'; import Link from 'next/link'; import { useRouter } from 'next/router'; -import { useState } from 'react'; +import React, { ReactNode, useState } from 'react'; import { generateJsonExampleFor, isErrors } from './examples'; import { SchemaViewModel } from './get-schema-view-model'; import { SchemaEditor } from './schema-editor'; import { SchemaViewer } from './schema-viewer'; import { Heading2, Heading3 } from './ui/headings'; -import { Markdown } from './ui/markdown/markdown'; function pathCleaner(path: string): string { return path.split('?')[0]; @@ -77,6 +77,19 @@ export function Content({ (x): x is { name: string; href: string; current: boolean } => !!x ); }, + get markdown(): ReactNode { + return renderMarkdown({ + content: getMarkdown({ + type: schemaViewModel.type, + packageName: schemaViewModel.packageName, + schemaName: schemaViewModel.schemaMetadata.name, + schemaAlias: schemaViewModel.schemaMetadata.aliases[0] ?? '', + schema: schemaViewModel.currentSchema as NxSchema, + }), + filePath: '', + data: {}, + }); + }, }; return ( @@ -116,15 +129,7 @@ export function Content({ {/* We remove the top description on sub property lookup */} {!schemaViewModel.subReference && ( <> - +
{vm.markdown}
{/* SPACER */}
)} @@ -221,10 +226,9 @@ const getMarkdown = (data: { packageName: string; schemaAlias: string; schemaName: string; - schema: JsonSchema1; + schema: NxSchema; type: 'executors' | 'generators'; }): string => { - const hasExamples = !!data.schema['examples']; const hasExamplesFile = !!data.schema['examplesFile']; const executorNotice: string = `Options can be configured in \`project.json\` when defining the executor, or when invoking it. Read more about how to configure targets and executors here: [https://nx.dev/configuration/projectjson#targets](https://nx.dev/configuration/projectjson#targets).`; @@ -241,9 +245,11 @@ const getMarkdown = (data: { ? data.schema['examplesFile'] : getUsage(data.packageName, data.schemaName, data.schemaAlias) : '', - hasExamples + !!data.schema['examples'] ? `### Examples \n ${data.schema['examples'] - .map((e) => `${e.description}: \n \`\`\`bash\n${e.command}\n\`\`\``) + .map( + (e: any) => `${e.description}: \n \`\`\`bash\n${e.command}\n\`\`\`` + ) .join('\n')}` : '', `\n\n`, diff --git a/nx-dev/feature-package-schema-viewer/src/lib/package-schema-list.tsx b/nx-dev/feature-package-schema-viewer/src/lib/package-schema-list.tsx index 26d38c5dbe..418199d5ab 100644 --- a/nx-dev/feature-package-schema-viewer/src/lib/package-schema-list.tsx +++ b/nx-dev/feature-package-schema-viewer/src/lib/package-schema-list.tsx @@ -2,14 +2,14 @@ import { ChipIcon, CogIcon } from '@heroicons/react/solid'; import { Menu } from '@nrwl/nx-dev/models-menu'; import { PackageMetadata } from '@nrwl/nx-dev/models-package'; import { Sidebar } from '@nrwl/nx-dev/ui-common'; +import { renderMarkdown } from '@nrwl/nx-dev/ui-markdoc'; import cx from 'classnames'; import { NextSeo } from 'next-seo'; import Link from 'next/link'; import { useRouter } from 'next/router'; -import { ReactComponentElement } from 'react'; +import React, { ReactComponentElement, ReactNode } from 'react'; import { getPublicPackageName } from './get-public-package-name'; import { Heading1, Heading2 } from './ui/headings'; -import { Markdown } from './ui/markdown/markdown'; export function PackageSchemaList({ pkg, @@ -30,6 +30,7 @@ export function PackageSchemaList({ readme: { content: string; filePath: string }; }; seo: { title: string; description: string; url: string; imageUrl: string }; + markdown: ReactNode; } = { pkg: { name: getPublicPackageName(pkg.name), @@ -53,6 +54,13 @@ export function PackageSchemaList({ .replace(/\//gi, '-')}.jpg`, url: 'https://nx.dev' + router.asPath, }, + get markdown(): ReactNode { + return renderMarkdown({ + content: this.pkg.readme.content, + filePath: this.pkg.readme.filePath, + data: {}, + }); + }, }; return ( @@ -109,11 +117,7 @@ export function PackageSchemaList({ - +
{vm.markdown}
@@ -147,10 +151,13 @@ export function PackageSchemaList({

- +
+ {renderMarkdown({ + content: executors.description, + data: {}, + filePath: '', + })} +
))} @@ -182,10 +189,13 @@ export function PackageSchemaList({

- +
+ {renderMarkdown({ + content: generators.description, + data: {}, + filePath: '', + })} +
))} diff --git a/nx-dev/feature-package-schema-viewer/src/lib/parameter-view.tsx b/nx-dev/feature-package-schema-viewer/src/lib/parameter-view.tsx index a3505a0d83..ad8722e793 100644 --- a/nx-dev/feature-package-schema-viewer/src/lib/parameter-view.tsx +++ b/nx-dev/feature-package-schema-viewer/src/lib/parameter-view.tsx @@ -1,10 +1,10 @@ import { Lookup } from '@nrwl/nx-dev/data-access-packages'; import { JsonSchema } from '@nrwl/nx-dev/models-package'; +import { renderMarkdown } from '@nrwl/nx-dev/ui-markdoc'; import { getParameterMetadata } from './parameter-metadata'; import { getEnum } from './types/get-enum'; import { Type } from './types/type'; import { Heading3 } from './ui/headings'; -import { Markdown } from './ui/markdown/markdown'; export const ParameterView = (props: { key: string; @@ -60,11 +60,21 @@ export const ParameterView = (props: { )} - +
+ {renderMarkdown({ + content: props.description, + data: {}, + filePath: '', + })} +
- {props.deprecated && props.schema['x-deprecated'] && ( -
- + {props.deprecated && !!props.schema['x-deprecated'] && ( +
+ {renderMarkdown({ + content: props.schema['x-deprecated'] as string, + data: {}, + filePath: '', + })}
)}
diff --git a/nx-dev/feature-package-schema-viewer/src/lib/ui/markdown/code-block.tsx b/nx-dev/feature-package-schema-viewer/src/lib/ui/markdown/code-block.tsx deleted file mode 100644 index 1a84cf1633..0000000000 --- a/nx-dev/feature-package-schema-viewer/src/lib/ui/markdown/code-block.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import React, { useEffect, useState } from 'react'; -// @ts-ignore -import { CopyToClipboard } from 'react-copy-to-clipboard'; -import SyntaxHighlighter from 'react-syntax-highlighter'; - -export function CodeBlock({ - text, - language, - callback, - ...rest -}: { - text: string; - language: string; - [key: string]: any; - callback: (text: string) => void; -}) { - const [copied, setCopied] = useState(false); - useEffect(() => { - let t: NodeJS.Timeout; - if (copied) { - t = setTimeout(() => { - setCopied(false); - }, 3000); - } - return () => { - t && clearTimeout(t); - }; - }, [copied]); - return ( -
- { - setCopied(true); - callback(text); - }} - > - - - -
- ); -} diff --git a/nx-dev/feature-package-schema-viewer/src/lib/ui/markdown/markdown.tsx b/nx-dev/feature-package-schema-viewer/src/lib/ui/markdown/markdown.tsx deleted file mode 100644 index 502d7662b7..0000000000 --- a/nx-dev/feature-package-schema-viewer/src/lib/ui/markdown/markdown.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import classNames from 'classnames'; -import ReactMarkdown from 'react-markdown'; -import autolinkHeadings from 'rehype-autolink-headings'; -import slug from 'rehype-slug'; -import gfm from 'remark-gfm'; -import { CodeBlock } from './code-block'; -import { renderIframes } from './renderers/render-iframe'; -import { transformImagePath } from './renderers/transform-image-path'; - -export const Markdown = ({ - content, - classes = '', - documentFilePath = '', -}: { - content: string; - classes?: string; - documentFilePath?: string; -}) => ( - void 0, - }, - })} - /> -); - -function createAnchorContent(node: any) { - node.properties.className = ['group']; - return { - type: 'element', - tagName: 'svg', - properties: { - xmlns: 'http://www.w3.org/2000/svg', - className: [ - 'inline', - 'ml-2', - 'mb-1', - `h-5`, - `w-5`, - 'opacity-0', - 'group-hover:opacity-100', - ], - fill: 'none', - viewBox: '0 0 24 24', - stroke: 'currentColor', - }, - children: [ - { - type: 'element', - tagName: 'path', - properties: { - 'stroke-linecap': 'round', - 'stroke-linejoin': 'round', - 'stroke-width': '2', - d: 'M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1', - }, - children: [], - }, - ], - }; -} - -interface ComponentsConfig { - readonly code: { callback: (command: string) => void }; -} -const components: any = (config: ComponentsConfig) => ({ - img({ node, alt, src, ...props }) { - return {alt}; - }, - code({ node, inline, className, children, ...props }) { - const language = /language-(\w+)/.exec(className || '')?.[1]; - return !inline && language ? ( - config.code.callback(command)} - /> - ) : ( - - {children} - - ); - }, - pre({ children }) { - return <>{children}; - }, -}); diff --git a/nx-dev/feature-package-schema-viewer/src/lib/ui/markdown/renderers/render-iframe.ts b/nx-dev/feature-package-schema-viewer/src/lib/ui/markdown/renderers/render-iframe.ts deleted file mode 100644 index aaee57a8c6..0000000000 --- a/nx-dev/feature-package-schema-viewer/src/lib/ui/markdown/renderers/render-iframe.ts +++ /dev/null @@ -1,21 +0,0 @@ -export function renderIframes(): (tree: any) => void { - return (tree): void => { - const iframeList = tree.children.filter( - (child) => child.type === 'raw' && child.value.includes(' { - item.type = 'element'; - item.tagName = 'iframe'; - item.children = []; - item.properties = {}; - let match; - const regex = new RegExp( - '[\\s\\r\\t\\n]*([a-z0-9\\-_]+)[\\s\\r\\t\\n]*=[\\s\\r\\t\\n]*([\'"])((?:\\\\\\2|(?!\\2).)*)\\2', - 'ig' - ); - while ((match = regex.exec(item.value))) { - item.properties[match[1]] = match[3]; - } - }); - }; -} diff --git a/nx-dev/nx-dev/styles/main.css b/nx-dev/nx-dev/styles/main.css index 6c16ebe665..9000793460 100644 --- a/nx-dev/nx-dev/styles/main.css +++ b/nx-dev/nx-dev/styles/main.css @@ -39,13 +39,14 @@ pre, General CSS rules for markdown iframes and img */ iframe[src*='youtube'] { + aspect-ratio: 16 / 9; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); border-radius: 0.375rem; } .prose iframe, .prose img { display: block; - margin: 1.7rem auto; + margin: 2rem auto; } .prose iframe { width: 100%; @@ -78,7 +79,6 @@ iframe[src*='youtube'] { /* Headers */ - .prose h5, .prose h6 { font-weight: 600; @@ -184,18 +184,3 @@ iframe[src*='youtube'] { opacity: 1; visibility: visible; } - -/* Nx Cloud section */ -.nx-cloud-section { - border-left-width: 0.25em; - border-left-color: hsla(162, 47%, 50%, 1); - padding-left: 1em; - margin-left: -1.25em; -} - -.nx-cloud-section h2 { - background: url('/documentation/shared/nx-cloud-logo-horizontal-white.svg') - no-repeat left center; - background-size: contain; - padding-left: 40px; -} diff --git a/nx-dev/ui-markdoc/.babelrc b/nx-dev/ui-markdoc/.babelrc new file mode 100644 index 0000000000..ccae900be4 --- /dev/null +++ b/nx-dev/ui-markdoc/.babelrc @@ -0,0 +1,12 @@ +{ + "presets": [ + [ + "@nrwl/react/babel", + { + "runtime": "automatic", + "useBuiltIns": "usage" + } + ] + ], + "plugins": [] +} diff --git a/nx-dev/ui-markdoc/.eslintrc.json b/nx-dev/ui-markdoc/.eslintrc.json new file mode 100644 index 0000000000..734ddaceea --- /dev/null +++ b/nx-dev/ui-markdoc/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/nx-dev/ui-markdoc/README.md b/nx-dev/ui-markdoc/README.md new file mode 100644 index 0000000000..aeeb30bae5 --- /dev/null +++ b/nx-dev/ui-markdoc/README.md @@ -0,0 +1,7 @@ +# nx-dev-ui-markdown + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test nx-dev-ui-markdown` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/nx-dev/ui-markdoc/jest.config.ts b/nx-dev/ui-markdoc/jest.config.ts new file mode 100644 index 0000000000..6d5aa66f9c --- /dev/null +++ b/nx-dev/ui-markdoc/jest.config.ts @@ -0,0 +1,10 @@ +/* eslint-disable */ +export default { + displayName: 'nx-dev-ui-markdoc', + preset: '../../jest.preset.js', + transform: { + '^.+\\.[tj]sx?$': 'babel-jest', + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + coverageDirectory: '../../coverage/nx-dev/ui-markdoc', +}; diff --git a/nx-dev/ui-markdoc/project.json b/nx-dev/ui-markdoc/project.json new file mode 100644 index 0000000000..d9c1de8270 --- /dev/null +++ b/nx-dev/ui-markdoc/project.json @@ -0,0 +1,23 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "nx-dev/ui-markdoc/src", + "projectType": "library", + "tags": [], + "targets": { + "lint": { + "executor": "@nrwl/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["nx-dev/ui-markdoc/**/*.{ts,tsx,js,jsx}"] + } + }, + "test": { + "executor": "@nrwl/jest:jest", + "outputs": ["coverage/nx-dev/ui-markdoc"], + "options": { + "jestConfig": "nx-dev/ui-markdoc/jest.config.ts", + "passWithNoTests": true + } + } + } +} diff --git a/nx-dev/ui-markdoc/src/index.ts b/nx-dev/ui-markdoc/src/index.ts new file mode 100644 index 0000000000..ed4822dd10 --- /dev/null +++ b/nx-dev/ui-markdoc/src/index.ts @@ -0,0 +1,70 @@ +import Markdoc from '@markdoc/markdoc'; +import { DocumentData } from '@nrwl/nx-dev/models-document'; +import React, { ReactNode } from 'react'; +import { Fence } from './lib/nodes/fence.component'; +import { fence } from './lib/nodes/fence.schema'; +import { Heading } from './lib/nodes/heading.component'; +import { heading } from './lib/nodes/heading.schema'; +import { getImageSchema } from './lib/nodes/image.schema'; +import { CustomLink } from './lib/nodes/link.component'; +import { link } from './lib/nodes/link.schema'; +import { Callout } from './lib/tags/callout.component'; +import { callout } from './lib/tags/callout.schema'; +import { Iframe } from './lib/tags/iframe.component'; +import { iframe } from './lib/tags/iframe.schema'; +import { nxCloudSection } from './lib/tags/nx-cloud-section.schema'; +import { NxCloudSection } from './lib/tags/nx-cloud-section.component'; +import { SideBySide } from './lib/tags/side-by-side.component'; +import { sideBySide } from './lib/tags/side-by-side.schema'; +import { Tab, Tabs } from './lib/tags/tabs.component'; +import { tab, tabs } from './lib/tags/tabs.schema'; +import { YouTube } from './lib/tags/youtube.components'; +import { youtube } from './lib/tags/youtube.schema'; + +export const getMarkdocCustomConfig = ( + document: DocumentData +): { config: any; components: any } => ({ + config: { + nodes: { + fence, + heading, + image: getImageSchema(document), + link, + }, + tags: { + callout, + iframe, + 'nx-cloud-section': nxCloudSection, + 'side-by-side': sideBySide, + tab, + tabs, + youtube, + }, + }, + components: { + Callout, + CustomLink, + Fence, + Heading, + Iframe, + NxCloudSection, + SideBySide, + Tab, + Tabs, + YouTube, + }, +}); + +export const renderMarkdown: (document: DocumentData) => ReactNode = ( + document: DocumentData +): ReactNode => { + const configuration = getMarkdocCustomConfig(document); + const ast = Markdoc.parse(document.content.toString()); + return Markdoc.renderers.react( + Markdoc.transform(ast, configuration.config), + React, + { + components: configuration.components, + } + ); +}; diff --git a/nx-dev/feature-doc-viewer/src/lib/code-block.tsx b/nx-dev/ui-markdoc/src/lib/nodes/fence.component.tsx similarity index 83% rename from nx-dev/feature-doc-viewer/src/lib/code-block.tsx rename to nx-dev/ui-markdoc/src/lib/nodes/fence.component.tsx index 69552d10e1..f1f04cb53a 100644 --- a/nx-dev/feature-doc-viewer/src/lib/code-block.tsx +++ b/nx-dev/ui-markdoc/src/lib/nodes/fence.component.tsx @@ -14,16 +14,12 @@ function resolveLanguage(lang: string) { } } -export function CodeBlock({ - text, +export function Fence({ + children, language, - callback, - ...rest }: { - text: string; + children: string; language: string; - [key: string]: any; - callback: (text: string) => void; }) { const [copied, setCopied] = useState(false); useEffect(() => { @@ -40,15 +36,14 @@ export function CodeBlock({ return (
{ setCopied(true); - callback(text); }} >
); diff --git a/nx-dev/ui-markdoc/src/lib/nodes/fence.schema.ts b/nx-dev/ui-markdoc/src/lib/nodes/fence.schema.ts new file mode 100644 index 0000000000..f61c2f9238 --- /dev/null +++ b/nx-dev/ui-markdoc/src/lib/nodes/fence.schema.ts @@ -0,0 +1,9 @@ +import { Schema } from '@markdoc/markdoc'; + +export const fence: Schema = { + render: 'Fence', + attributes: { + text: { type: 'String', required: true }, + language: { type: 'String' }, + }, +}; diff --git a/nx-dev/ui-markdoc/src/lib/nodes/heading.component.tsx b/nx-dev/ui-markdoc/src/lib/nodes/heading.component.tsx new file mode 100644 index 0000000000..6d4adf260e --- /dev/null +++ b/nx-dev/ui-markdoc/src/lib/nodes/heading.component.tsx @@ -0,0 +1,28 @@ +import { LinkIcon } from '@heroicons/react/outline'; +import { ReactNode } from 'react'; + +export function Heading({ + id = '', + level = 1, + children, + className, +}: { + id: string; + level: number; + children: ReactNode; + className: string; +}) { + const Component: any = `h${level}`; + + return ( + + {children} + + + ); +} diff --git a/nx-dev/ui-markdoc/src/lib/nodes/heading.schema.ts b/nx-dev/ui-markdoc/src/lib/nodes/heading.schema.ts new file mode 100644 index 0000000000..929ec0e4cd --- /dev/null +++ b/nx-dev/ui-markdoc/src/lib/nodes/heading.schema.ts @@ -0,0 +1,38 @@ +import { RenderableTreeNode, Schema, Tag } from '@markdoc/markdoc'; + +function generateID( + children: RenderableTreeNode[], + attributes: Record +) { + if (attributes.id && typeof attributes.id === 'string') { + return attributes.id; + } + return children + .filter((child) => typeof child === 'string') + .join(' ') + .replace(/[?]/g, '') + .replace(/\s+/g, '-') + .toLowerCase(); +} + +export const heading: Schema = { + render: 'Heading', + children: ['inline'], + attributes: { + id: { type: 'String' }, + level: { type: 'Number', required: true, default: 1 }, + className: { type: 'String' }, + }, + transform(node, config) { + const attributes = node.transformAttributes(config); + const children = node.transformChildren(config); + const id = generateID(children, attributes); + + return new Tag( + this.render, + // `h${node.attributes['level']}`, + { ...attributes, id }, + children + ); + }, +}; diff --git a/nx-dev/feature-doc-viewer/src/lib/renderers/transform-image-path.spec.ts b/nx-dev/ui-markdoc/src/lib/nodes/helpers/transform-image-path.spec.ts similarity index 66% rename from nx-dev/feature-doc-viewer/src/lib/renderers/transform-image-path.spec.ts rename to nx-dev/ui-markdoc/src/lib/nodes/helpers/transform-image-path.spec.ts index 326bc44f21..492083b463 100644 --- a/nx-dev/feature-doc-viewer/src/lib/renderers/transform-image-path.spec.ts +++ b/nx-dev/ui-markdoc/src/lib/nodes/helpers/transform-image-path.spec.ts @@ -3,12 +3,10 @@ import { transformImagePath } from './transform-image-path'; describe('transformImagePath', () => { it('should transform relative paths', () => { const opts = { - document: { - content: '', - excerpt: '', - filePath: 'nx-dev/nx-dev/public/documentation/shared/using-nx/dte.md', - data: {}, - }, + content: '', + excerpt: '', + filePath: 'nx-dev/nx-dev/public/documentation/shared/using-nx/dte.md', + data: {}, }; const transform = transformImagePath(opts); @@ -21,13 +19,11 @@ describe('transformImagePath', () => { it('should transform absolute paths', () => { const opts = { - document: { - content: '', - excerpt: '', - filePath: - 'nx-dev/nx-dev/public/documentation/angular/generators/workspace-generators.md', - data: {}, - }, + content: '', + excerpt: '', + filePath: + 'nx-dev/nx-dev/public/documentation/angular/generators/workspace-generators.md', + data: {}, }; const transform = transformImagePath(opts); diff --git a/nx-dev/feature-package-schema-viewer/src/lib/ui/markdown/renderers/transform-image-path.ts b/nx-dev/ui-markdoc/src/lib/nodes/helpers/transform-image-path.ts similarity index 64% rename from nx-dev/feature-package-schema-viewer/src/lib/ui/markdown/renderers/transform-image-path.ts rename to nx-dev/ui-markdoc/src/lib/nodes/helpers/transform-image-path.ts index cf75f59b9d..7d6f4e8bc1 100644 --- a/nx-dev/feature-package-schema-viewer/src/lib/ui/markdown/renderers/transform-image-path.ts +++ b/nx-dev/ui-markdoc/src/lib/nodes/helpers/transform-image-path.ts @@ -1,8 +1,9 @@ +import { DocumentData } from '@nrwl/nx-dev/models-document'; import { join } from 'path'; -import { uriTransformer } from 'react-markdown'; +import { uriTransformer } from './uri-transformer'; export function transformImagePath( - documentFilePath: string + document: DocumentData ): (src: string) => string { return (src) => { const isRelative = src.startsWith('.'); @@ -13,7 +14,7 @@ export function transformImagePath( if (isRelative) { return uriTransformer( - join('/', documentFilePath.split('/').splice(3).join('/'), '..', src) + join('/', document.filePath.split('/').splice(3).join('/'), '..', src) ); } diff --git a/nx-dev/ui-markdoc/src/lib/nodes/helpers/uri-transformer.ts b/nx-dev/ui-markdoc/src/lib/nodes/helpers/uri-transformer.ts new file mode 100644 index 0000000000..469904a9f3 --- /dev/null +++ b/nx-dev/ui-markdoc/src/lib/nodes/helpers/uri-transformer.ts @@ -0,0 +1,43 @@ +/** + * @param {string} uri + * @returns {string} + */ +export function uriTransformer(uri: string): string { + const protocols = ['http', 'https', 'mailto', 'tel']; + const url = (uri || '').trim(); + const first = url.charAt(0); + + if (first === '#' || first === '/') { + return url; + } + + const colon = url.indexOf(':'); + if (colon === -1) { + return url; + } + + let index = -1; + + while (++index < protocols.length) { + const protocol = protocols[index]; + + if ( + colon === protocol.length && + url.slice(0, protocol.length).toLowerCase() === protocol + ) { + return url; + } + } + + index = url.indexOf('?'); + if (index !== -1 && colon > index) { + return url; + } + + index = url.indexOf('#'); + if (index !== -1 && colon > index) { + return url; + } + + return 'javascript:void(0)'; +} diff --git a/nx-dev/ui-markdoc/src/lib/nodes/image.schema.ts b/nx-dev/ui-markdoc/src/lib/nodes/image.schema.ts new file mode 100644 index 0000000000..0346a0f6be --- /dev/null +++ b/nx-dev/ui-markdoc/src/lib/nodes/image.schema.ts @@ -0,0 +1,29 @@ +import { + Config, + Node, + RenderableTreeNodes, + Schema, + Tag, +} from '@markdoc/markdoc'; +import { DocumentData } from '@nrwl/nx-dev/models-document'; +import { transformImagePath } from './helpers/transform-image-path'; + +export const getImageSchema = (document: DocumentData): Schema => ({ + render: 'img', + attributes: { + src: { type: 'String', required: true }, + alt: { type: 'String', required: true }, + }, + transform(node: Node, config: Config): RenderableTreeNodes { + const attributes = node.transformAttributes(config); + const children = node.transformChildren(config); + const src = transformImagePath(document)(attributes['src']); + + return new Tag( + this.render, + // `h${node.attributes['level']}`, + { ...attributes, src, loading: 'lazy' }, + children + ); + }, +}); diff --git a/nx-dev/ui-markdoc/src/lib/nodes/link.component.tsx b/nx-dev/ui-markdoc/src/lib/nodes/link.component.tsx new file mode 100644 index 0000000000..7d320e4883 --- /dev/null +++ b/nx-dev/ui-markdoc/src/lib/nodes/link.component.tsx @@ -0,0 +1,18 @@ +import Link from 'next/link'; + +export function CustomLink(props: any) { + const target = + props.target || (props.href.startsWith('http') ? '_blank' : undefined); + + return ( + + + {props.children} + + + ); +} diff --git a/nx-dev/ui-markdoc/src/lib/nodes/link.schema.ts b/nx-dev/ui-markdoc/src/lib/nodes/link.schema.ts new file mode 100644 index 0000000000..56109747a2 --- /dev/null +++ b/nx-dev/ui-markdoc/src/lib/nodes/link.schema.ts @@ -0,0 +1,47 @@ +export const link = { + render: 'CustomLink', + description: 'Displays a Next.js link', + attributes: { + href: { + description: 'The path or URL to navigate to.', + type: String, + errorLevel: 'critical', + required: true, + }, + as: { + description: + 'Optional decorator for the path that will be shown in the browser URL bar.', + type: String, + }, + passHref: { + description: 'Forces Link to send the href property to its child.', + type: Boolean, + default: false, + }, + prefetch: { + description: 'Prefetch the page in the background.', + type: Boolean, + }, + replace: { + description: + 'Replace the current history state instead of adding a new url into the stack.', + type: Boolean, + default: false, + }, + scroll: { + description: 'Scroll to the top of the page after a navigation.', + type: Boolean, + default: true, + }, + shallow: { + description: + 'Update the path of the current page without rerunning getStaticProps, getServerSideProps or getInitialProps.', + type: Boolean, + default: true, + }, + locale: { + description: 'The active locale is automatically prepended.', + type: Boolean, + }, + }, +}; diff --git a/nx-dev/ui-markdoc/src/lib/tags/callout.component.tsx b/nx-dev/ui-markdoc/src/lib/tags/callout.component.tsx new file mode 100644 index 0000000000..e5589076db --- /dev/null +++ b/nx-dev/ui-markdoc/src/lib/tags/callout.component.tsx @@ -0,0 +1,90 @@ +import { + CheckCircleIcon, + ExclamationIcon, + InformationCircleIcon, + XCircleIcon, +} from '@heroicons/react/outline'; +import cx from 'classnames'; +import { ReactNode } from 'react'; + +type CalloutType = 'note' | 'warning' | 'check' | 'error'; +const typeMap: Record< + CalloutType, + { + icon: JSX.Element; + backgroundColor: string; + borderColor: string; + titleColor: string; + textColor: string; + } +> = { + note: { + icon: ( +