diff --git a/docs/map.json b/docs/map.json index 9b614330ec382..0e893fde01e6a 100644 --- a/docs/map.json +++ b/docs/map.json @@ -142,6 +142,42 @@ } ] }, + { + "name": "Core Tutorial", + "id": "core-tutorial", + "itemList": [ + { + "name": "1 - Create Blog", + "id": "01-create-blog", + "file": "shared/core-tutorial/01-create-blog" + }, + { + "name": "2 - Create CLI", + "id": "02-create-cli", + "file": "shared/core-tutorial/02-create-cli" + }, + { + "name": "3 - Share Assets", + "id": "03-share-assets", + "file": "shared/core-tutorial/03-share-assets" + }, + { + "name": "4 - Build Affected Projects", + "id": "04-build-affected-projects", + "file": "shared/core-tutorial/04-build-affected-projects" + }, + { + "name": "5 - Automatically Detect Dependencies", + "id": "05-auto-detect-dependencies", + "file": "shared/core-tutorial/05-auto-detect-dependencies" + }, + { + "name": "6 - Summary", + "id": "06-summary", + "file": "shared/core-tutorial/06-summary" + } + ] + }, { "name": "React Tutorial", "id": "react-tutorial", diff --git a/docs/shared/core-tutorial/01-create-blog.md b/docs/shared/core-tutorial/01-create-blog.md new file mode 100644 index 0000000000000..d1284edee1d23 --- /dev/null +++ b/docs/shared/core-tutorial/01-create-blog.md @@ -0,0 +1,175 @@ +# Core Nx Tutorial - Step 1: Create Eleventy Blog + +In this tutorial you create multiple projects in a monorepo and take advantage of the core Nx features with a minimum of configuration. + +## Create a New Workspace + +**Start by creating a new workspace.** + +```bash +npx create-nx-workspace@latest +``` + +You then receive the following prompts in your command line: + +```bash +Workspace name (e.g., org name) myorg +What to create in the new workspace core +``` + +> You can also choose to add [Nx Cloud](https://nx.app), but its not required for the tutorial. + +```treeview +myorg/ +├── packages/ +├── tools/ +├── nx.json +├── package.json +├── README.md +└── tsconfig.base.json +``` + +## Yarn workspaces + +The `package.json` file contains this property: + +```json + "workspaces": [ + "packages/**" + ] +``` + +Which tells yarn (or npm) and Nx to look in the `packages` folder for projects that will each be identified by a `package.json` file. + +## Adding Eleventy + +**Install Eleventy** + +To install Eleventy run: + +```bash +yarn add -D -W @11ty/eleventy@1.0.0 +``` + +or + +```bash +npm add -D @11ty/eleventy@1.0.0 +``` + +Note: We are intentionally installing the package at the root of the workspace because this forces the organization to have the upfront cost of agreeing on the same versions of dependencies rather than the delayed cost of having projects using multiple different incompatible versions of dependencies. Yarn needs the `-W` flag so that you can install dependencies at the root. This is not a requirement of Nx, just a suggestion to help you maintain a growing repo. + +**Eleventy Hello World** + +Create a file at `packages/blog/package.json` with these contents: + +```json +{ + "name": "blog", + "description": "eleventy blog", + "version": "1.0.0", + "scripts": { + "build": "eleventy --input=./src --output=../../dist/packages/blog", + "serve": "eleventy --serve --input=./src --output=../../dist/packages/blog" + } +} +``` + +These scripts tell Eleventy to read from the `src` folder we'll create next and output to Nx's default location under `dist`. + +Next, add `packages/blog/src/index.html`: + +```html +

Hello, Eleventy

+``` + +## Running Eleventy with Nx + +Now that we have the bare minimum set up for Eleventy, you can run: + +```bash +nx serve blog +``` + +And you can see `Hello, Eleventy` at `http://localhost:8080`. + +Also, if you run: + +```bash +nx build blog +``` + +The build output will be created under `dist/packages/blog`. So far, Nx isn't doing anything special. If you run `nx build blog` again, though, you'll see it finish in less than 100 ms (instead of 1s). The caching doesn't matter yet, but as build times grow, it will become far more useful. + +The main value of Nx at this stage of the project is that it doesn't require any custom configuration on your project. The blog could have been built with any of a dozen different platforms and Nx would cache the output just the same. + +## Build a Basic Blog + +To actually create a blog, we'll have to change a few more files. This is all Eleventy specific configuration, so if you have questions consult [their documentation](https://www.11ty.dev/docs/config/) or [this tutorial](https://www.filamentgroup.com/lab/build-a-blog/). + +Update `index.html`: + +```html +--- +layout: layout.liquid +pageTitle: Welcome to my blog +--- + +{% for post in collections.posts %} +

{{ post.data.pageTitle }}

+{{ post.date | date: "%Y-%m-%d" }} +{% endfor %} +``` + +Create the following files: + +`packages/blog/src/_includes/layout.liquid`: + +```html + + + + + My Blog + + +

{{ pageTitle }}

+ + {{ content }} + + +``` + +`packages/blog/src/posts/ascii.md`: + +```markdown +--- +pageTitle: Some ASCII Art +--- + +Welcome to [The Restaurant at the End of the Universe](https://hitchhikers.fandom.com/wiki/Ameglian_Major_Cow) + +
+ _____
+< moo >
+ -----
+        \   ^__^
+         \  (oo)\_______
+            (__)\       )\/\
+                ||----w |
+                ||     ||
+
+ +Art courtesy of [cowsay](https://www.npmjs.com/package/cowsay). +``` + +`packages/blog/src/posts/posts.json`: + +```json +{ + "layout": "layout.liquid", + "tags": ["posts"] +} +``` + +Once these files are in place, run `nx serve blog` again. Navigate to `http://localhost:8080/posts/ascii/` in a browser and you should see the blog post. diff --git a/docs/shared/core-tutorial/02-create-cli.md b/docs/shared/core-tutorial/02-create-cli.md new file mode 100644 index 0000000000000..4ef51640727d1 --- /dev/null +++ b/docs/shared/core-tutorial/02-create-cli.md @@ -0,0 +1,155 @@ +# Core Nx Tutorial - Step 2: Create Go CLI + +Great! you now have a simple blog set up. + +Next, you're going to create a CLI written in Go. + +## Install Go Locally + +Make sure you have Go installed locally by following [these instructions](https://go.dev/doc/install). + +You can verify that Go is installed correctly by running: + +```bash +go version +``` + +## Create the CLI Project + +Create a `project.json` file for your Go CLI. + +`packages/cli/project.json`: + +```json +{ + "root": "packages/cli", + "sourceRoot": "packages/cli/src", + "projectType": "application", + "targets": { + "build": { + "executor": "@nrwl/workspace:run-commands", + "options": { + "command": "go build -o='../../dist/packages/cli/' ./src/ascii.go", + "cwd": "packages/cli" + } + }, + "serve": { + "executor": "@nrwl/workspace:run-commands", + "options": { + "command": "go run ./src/ascii.go", + "cwd": "packages/cli" + } + } + } +} +``` + +You could have the exact same functionality with a `package.json` file with a `scripts` section like this: + +```json +{ + "scripts": { + "build": "go build -o='../../dist/packages/cli/' ./src/ascii.go", + "serve": "go run ./src/ascii.˙go" + } +} +``` + +There are a few reasons to choose `project.json` for the CLI project. + +1. The presence of `package.json` might cause other developers to think there is javascript code in this project. +2. As the scripts in the project get more complex, `project.json` tends to have a flatter structure - rather than a long horizontal line in `package.json` with all the cli flags. +3. The easiest method to run scripts provided in Nx plugins is to use a `project.json` file. + +All of these reasons are matters of preference. After this tutorial, you should have enough of a taste of both styles to make an informed decision about which format you prefer. Read more about [package.json configuration](/configuration/packagejson) and [project.json configuration](configuration/projectjson) in their respective guides. + +### Project.json syntax + +- `root`, `sourceRoot` and `application` are properties that help Nx know more about your project. +- `targets` is similar to the `scripts` property in `package.json`. +- Just as in `package.json`, `build` and `serve` can be any string you pick. +- The `executor` is the code that runs the target. In this case, [`@nrwl/workspace:run-commands`](https://nx.dev/workspace/run-commands-executor) launches a terminal process to execute whatever command you pass in. +- `options` contains whatever configuration properties the executor needs to run. + +## Create the CLI + +This CLI will display some ASCII art in the terminal. Create the following files: + +`packages/cli/src/ascii.go`: + +```go +package main + +import ( + "fmt" + "os" +) + +func check(e error) { + if e != nil { + panic(e) + } +} + +func main() { + fmt.Println("Hello, World!") + dat, err := os.ReadFile("src/cow.txt") + check(err) + fmt.Print(string(dat)) +} +``` + +`packages/cli/src/cow.txt`: + +```bash + _____ +< moo > + ----- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || +``` + +## Run the CLI + +Now if you run `nx serve cli`, you'll see a friendly message: + +```bash +❯ nx serve cli + +> nx run cli:serve + + +> cli@ serve /Users/isaac/Documents/code/myorg/packages/cli +> go run ./src/ascii.go + +Hello, World! + _____ +< moo > + ----- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || + + ————————————————————————————————————————————————————————————————————————————————————————— + + > NX Successfully ran target serve for project cli (2s) + + See Nx Cloud run details at https://nx.app/runs/THRW7SDRL9S + +``` + +Nx only caches the targets that you tell it to cache. `serve` is not in the default list of cached targets, so running this command a second time will take the same amount of time. You can see the current list of `cacheableOperations` in `nx.json`. + +```json +{ + //... + "cacheableOperations": ["build", "lint", "test", "e2e"] +} +``` + +If you run `nx build cli` twice, you'll see that Nx is able to cache the commands even though they're entirely written in Go. diff --git a/docs/shared/core-tutorial/03-share-assets.md b/docs/shared/core-tutorial/03-share-assets.md new file mode 100644 index 0000000000000..db9ea253a80e6 --- /dev/null +++ b/docs/shared/core-tutorial/03-share-assets.md @@ -0,0 +1,183 @@ +# Core Nx Tutorial - Step 3: Share Assets + +You probably noticed that you're using the same friendly cow ASCII art in the blog and CLI. Since both projects are in the same repo, it would be good to share that asset across both projects. + +## Create an Asset Library + +You can make a library project just for holding the ASCII asset files. Let Nx know about the project by creating a `project.json` file like this: + +`packages/ascii/project.json`: + +```json +{ + "root": "packages/ascii", + "sourceRoot": "packages/ascii/assets", + "projectType": "library" +} +``` + +Note: You could choose to make a `package.json` file here instead, if you prefer. + +Then move `cow.txt` out of the `cli` project to: + +`packages/ascii/assets/cow.txt`: + +```bash + _____ +< moo > + ----- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || +``` + +## Use the Shared Assets Library in the Blog + +In the eleventy blog, you need to add some configuration so that Eleventy knows how to read `.txt` files. + +`packages/blog/.eleventy.js`: + +```javascript +const { EleventyRenderPlugin } = require('@11ty/eleventy'); + +module.exports = function (eleventyConfig) { + eleventyConfig.addPlugin(EleventyRenderPlugin); + eleventyConfig.extensionMap = [ + { + key: 'txt', + extension: 'txt', + compile: function compile(str, inputPath, preTemplateEngine, bypass) { + return function render(data) { + return str; + }; + }, + }, + ]; +}; +``` + +Then you can reference that shared asset file in a blog post. + +`packages/blog/src/posts/ascii.md`: + +```markdown +--- +pageTitle: Some ASCII Art +--- + +Welcome to [The Restaurant at the End of the Universe](https://hitchhikers.fandom.com/wiki/Ameglian_Major_Cow) + +
+{% renderFile "../ascii/assets/cow.txt" %}
+
+ +Art courtesy of [cowsay](https://www.npmjs.com/package/cowsay). +``` + +## Use the Shared Assets Library in the CLI + +For the Go CLI, you only need to update the Go code. + +`packages/cli/src/ascii.go`: + +```go +package main + +import ( + "fmt" + "os" +) + +func check(e error) { + if e != nil { + panic(e) + } +} + +func main() { + fmt.Println("Hello, World!") + dat, err := os.ReadFile("../ascii/assets/cow.txt") + check(err) + fmt.Print(string(dat)) +} +``` + +## Tell Nx About the Dependencies + +Nx without plugins is unable to automatically detect dependencies in Go code or markdown, so you'll have to tell Nx about the dependencies manually. (For Go code, there is [@nx-go/nx-go](https://github.com/nx-go/nx-go) which will automatically detect dependencies between Go projects.) + +For the blog project, you'll need to add `ascii` as a `dependency` (or `devDependency`) in the `package.json` file. + +`packages/blog/package.json`: + +```json +{ + "name": "blog", + "description": "eleventy blog", + "version": "1.0.0", + "dependency": { + "ascii": "*" + }, + "scripts": { + "build": "eleventy --input=./src --output=../../dist/packages/blog", + "serve": "eleventy --serve --input=./src --output=../../dist/packages/blog" + } +} +``` + +For the cli project, you add the implicit dependencies in the `project.json` file. + +`packages/cli/project.json`: + +```json +{ + "root": "packages/cli", + "sourceRoot": "packages/cli/src", + "projectType": "application", + "implicitDependencies": ["ascii"], + "targets": { + "build": { + "executor": "@nrwl/workspace:run-commands", + "options": { + "command": "go build -o='../../dist/packages/cli/' ./src/ascii.go", + "cwd": "packages/cli" + } + }, + "serve": { + "executor": "@nrwl/workspace:run-commands", + "options": { + "command": "go run ./src/ascii.go", + "cwd": "packages/cli" + } + } + } +} +``` + +## Test the Changes + +You should now be able to run + +```bash +nx serve blog +``` + +and + +```bash +nx serve cli +``` + +and get the same results as before. + +## View the Project Graph + +You can view a visual representation of the project graph by running: + +```bash +nx graph +``` + +When the graph opens in your browser, click the `Show all projects` button in the left sidebar. You should see dependency lines drawn from `blog` and `cli` to `ascii`. diff --git a/docs/shared/core-tutorial/04-build-affected-projects.md b/docs/shared/core-tutorial/04-build-affected-projects.md new file mode 100644 index 0000000000000..ef887fd3e34dd --- /dev/null +++ b/docs/shared/core-tutorial/04-build-affected-projects.md @@ -0,0 +1,87 @@ +# Core Nx Tutorial - Step 4: Build Affected Projects + +Nx scales your development by doing code change analysis to see what apps or libraries are affected by a particular pull request. + +**Commit all the changes in the repo**: + +```bash +git add . +git commit -am 'init' +git checkout -b testbranch +``` + +**Open `packages/cli/src/ascii.go` and change the go code:** + +```go +package main + +import ( + "fmt" + "os" +) + +func check(e error) { + if e != nil { + panic(e) + } +} + +func main() { + fmt.Println("Hello, Dish of the Day") + dat, err := os.ReadFile("../ascii/assets/cow.txt") + check(err) + fmt.Print(string(dat)) +} +``` + +**Run `nx print-affected --select=projects`**, and you should see `cli` printed out. The `nx print-affected` looks at what you have changed and uses the project graph to figure out which projects are affected by this change. + +**Now revert those changes** + +```bash +git checkout . +``` + +**Make a change to the shared ASCII art** + +Update `packages/ascii/assets/cow.txt`: + +```bash + _____ +< Hi! > + ----- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || +``` + +**Run `nx print-affected --select=projects`**, and this time you should see `cli`, `blog` and `ascii` printed out. + +## Build Affected Projects + +Printing the affected projects can be handy, but usually you want to do something with them. For instance, you may want to build everything that has been affected. + +**Run `nx affected --target=build` to rebuild only the projects affected by the change.** + +```bash + ✔ nx run blog:build (1s) + ✔ nx run cli:build (2s) + + —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + + > NX Successfully ran target build for 2 projects (2s) + + See Nx Cloud run details at https://nx.app/runs/XfhRFaOyGCE +``` + +Note that Nx only built `blog` and `cli`. It didn't build `ascii` because there is no build script created for it. + +## Affected --target=\* + +You can run any target against the affected projects in the graph like this: + +```bash +nx affected --target=test +``` diff --git a/docs/shared/core-tutorial/05-auto-detect-dependencies.md b/docs/shared/core-tutorial/05-auto-detect-dependencies.md new file mode 100644 index 0000000000000..c691bba94244b --- /dev/null +++ b/docs/shared/core-tutorial/05-auto-detect-dependencies.md @@ -0,0 +1,118 @@ +# Core Nx Tutorial - Step 5: Automatically Detect Dependencies + +Manually telling Nx about the dependencies between your projects is helpful, but as your repo grows it becomes difficult for a person to keep track of all the dependencies that are introduced. If you miss a dependency, the guarantees of the affected command are voided. + +Luckily, Nx core can automatically detect dependencies that are created in `.ts` or `.js` files. + +**Side note 1:** If you want to disable detecting dependencies from source code and want to only use the dependencies as defined in `package.json` (the same way yarn does), you can add the following configuration to your `nx.json` file: + +```json +{ + "pluginsConfig": { + "@nrwl/js": { + "analyzeSourceFiles": false + } + } +} +``` + +**Side note 2:** If you want Nx to automatically detect dependencies for other languages, you can install a plugin for that language. There is a list of Nrwl maintained and third party plugins on the [community page](/community#plugin-directory). + +## Create Messages Library + +Make two files. + +`packages/messages/package.json`: + +```json +{ + "name": "messages" +} +``` + +`packages/messages/index.js`: + +```javascript +const message = 'Welcome to the Restaurant at the End of the Universe'; + +module.exports = { message }; +``` + +This library is exporting a single `message` string. + +## Create Cow Application + +Install the `cowsay` npm package at the root of the workspace. + +```bash +yarn add -W cowsay@1.5.0 +``` + +Make an application that uses the `messages` library. Note that you won't specify the dependency manually in the `package.json` file. + +`packages/cow/package.json`: + +```json +{ + "name": "cow", + "version": "0.0.1", + "scripts": { + "serve": "node index.js" + } +} +``` + +`packages/cow/index.js`: + +```javascript +var cowsay = require('cowsay'); +var { message } = require('../messages'); + +console.log( + cowsay.say({ + text: message, + }) +); +``` + +Now if you run `nx serve cow`, you'll see this: + +```bash +$ node index.js + ______________________________________________________ +< Welcome to the Restaurant at the End of the Universe > + ------------------------------------------------------ + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || +Done in 0.14s. + + —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + + > NX Successfully ran target serve for project cow + + + See Nx Cloud run details at https://nx.app/runs/nZBYYBEuIfG +``` + +## View the Project Graph + +Run `nx graph` to view the new project graph. You'll see a dependency line has been drawn between `cow` and `messages` because Nx recognises that `cow` is referencing code inside the `messages` project. + +This line tells Nx about the dependency: + +```javascript +var { message } = require('../messages'); +``` + +If at some point in the future the code is refactored so that cow no longer references messages, the project graph will automatically update accordingly. + +## More Tooling + +If you want Nx to do more for you, you can install the `@nrwl/js` plugin to help with typescript or javascript tooling. This plugin provides out of the box: + +- Typescript alias paths +- Build with `tsc` or `swc` +- Jest and ESLint configuration diff --git a/docs/shared/core-tutorial/06-summary.md b/docs/shared/core-tutorial/06-summary.md new file mode 100644 index 0000000000000..4ce3534036783 --- /dev/null +++ b/docs/shared/core-tutorial/06-summary.md @@ -0,0 +1,22 @@ +# Core Nx Tutorial - Step 6: Summary + +In this tutorial you: + +- Built a blog using Eleventy +- Built a CLI with Go +- Shared asset files between projects +- Used Nx's computation caching to never build the same code twice +- Used Nx's affected commands to only rebuild affected projects +- Used Nx's ability to automatically detect dependencies between js/ts projects + +You created a workspace from scratch in this tutorial, but if you would like to add Nx to an existing repository, you can use the `npx add-nx-to-monorepo` terminal command to get started. For more information see the [Adding Nx to Lerna/Yarn/PNPM/NPM Workspace](migration/adding-to-monorepo) guide. + +## Learn more + +- [Free Nx Course on YouTube](https://www.youtube.com/watch?time_continue=49&v=2mYLe9Kp9VM&feature=emb_logo) + +**Dive Deep:** + +- [Nx CLI](/using-nx/nx-cli) +- [Computation Caching](/using-nx/caching) +- [Rebuilding What is Affected](/using-nx/affected) diff --git a/nx-dev/data-access-documents/src/lib/menu.utils.ts b/nx-dev/data-access-documents/src/lib/menu.utils.ts index d0e9cc489cdc1..095c0492a462b 100644 --- a/nx-dev/data-access-documents/src/lib/menu.utils.ts +++ b/nx-dev/data-access-documents/src/lib/menu.utils.ts @@ -43,6 +43,7 @@ export function getBasicSection(items: MenuItem[]): MenuSection { m.id === 'migration' || m.id === 'configuration' || m.id === 'using-nx' || + m.id === 'core-tutorial' || m.id === 'react-tutorial' || m.id === 'angular-tutorial' || m.id === 'node-tutorial' diff --git a/nx-dev/ui-home/src/lib/getting-started.tsx b/nx-dev/ui-home/src/lib/getting-started.tsx index 89e10784b8c5c..d96c83483a2ad 100644 --- a/nx-dev/ui-home/src/lib/getting-started.tsx +++ b/nx-dev/ui-home/src/lib/getting-started.tsx @@ -818,7 +818,37 @@ function TypescriptPane(): ReactComponentElement {

- TypeScript/JavaScript{' '} + Minimal Configuration{' '} + + + (follow our Core Nx tutorial) + + +

+ +
+ + sendCustomEvent('code-snippets', 'click', router.pathname) + } + /> +
+ + +
+ + + +

+ TypeScript/JavaScript Tooling{' '} (follow our Nx and TypeScript tutorial)