Initial draft of "Getting started with Heft" and "Adding more tasks" tutorials

This commit is contained in:
Pete Gonzalez 2020-07-24 14:59:14 -07:00
Родитель 94d9494e81
Коммит 3374fff509
9 изменённых файлов: 411 добавлений и 11 удалений

Просмотреть файл

@ -34,6 +34,17 @@ docs_nav:
- title: Heft command line
url: /pages/heft/cli
- title: Heft tutorials
subitems:
- title: Getting started with Heft
url: /pages/heft_tutorials/getting_started
- title: Adding more tasks
url: /pages/heft_tutorials/adding_tasks
- title: Everyday Heft commands
url: /pages/heft_tutorials/everyday_commands
- title: Interfacing with Rush
url: /pages/heft_tutorials/heft_and_rush
- title: Heft tasks
subitems:
- title: api-extractor

Просмотреть файл

@ -8,17 +8,16 @@
- **Specific strategy** that integrates popular tools like NodeJS, TypeScript, ESLint, Prettier, Webpack, Jest, etc.
- **Family of projects** that fill in the gaps for this strategy
Although various pieces of this work have been underway for years, we're now bringing them together under a common charter as **Rush Stack**. The new website was just launched in summer of 2019. It still has a ways to go! Track our progress on the [News]({% link pages/news.md %}) page.
Although various pieces of this work have been underway for years, we're now bringing them together under a common charter as **Rush Stack**. Track our progress on the [News]({% link pages/news.md %}) page and [Roadmap]({% link pages/overview/roadmap.md %}).
## What's in the stack?
These tools are developed under the **Rush Stack** umbrella:
- [Rush](https://rushjs.io/): the scalable build orchestrator
- [Rush](https://rushjs.io/): the scalable monorepo build orchestrator
- [Heft]({% link pages/heft/overview.md %}): an extensible build system that interfaces with Rush
- [API Extractor](https://api-extractor.com/): coordinates API reviews, and generates .d.ts rollups
- [API Documenter](https://api-extractor.com/pages/setup/generating_docs/): generates your API documentation website
- **Heft (coming soon!):** a new scalable task rig that replaces the earlier
[gulp-core-build](https://www.npmjs.com/package/@microsoft/gulp-core-build) system
- [@<!---->rushstack/eslint-config](https://www.npmjs.com/package/@rushstack/eslint-config): our standardized
ESLint rule set, specifically designed for large scale TypeScript monorepos

Просмотреть файл

@ -51,12 +51,25 @@ other similar systems, Heft has some unique design goals:
<!-- --------------------------------------------------------------------------- -->
## How do I use it?
## Where to begin?
Heft is still under active development; more documentation and tutorials will be coming soon. In the meantime,
we recommend to use the test projects for examples of Heft setups:
- The [Getting started with Heft]({% link pages/heft_tutorials/getting_started.md %}) tutorial provides a quick
walkthrough of the steps for setting up a project to build using Heft
- [heft-node-test](https://github.com/microsoft/rushstack/tree/master/build-tests/heft-node-test): A basic Node.js
application with Jest and API Extractor
- [heft-webpack-test](https://github.com/microsoft/rushstack/tree/master/build-tests/heft-webpack-test): A basic
- The NPM package page is here: [@rushstack/heft](https://www.npmjs.com/package/@rushstack/heft)
- [Interfacing with Rush]({% link pages/heft_tutorials/heft_and_rush.md %}) explains how Heft and Rush interact
- The [Heft architecture]({% link pages/heft/architecture.md %}) article provides more detail about the
build system's design
## Sample projects
For a couple quick examples of Heft projects in a real Rush monorepo, take a look at these folders:
- [heft-node-basic-test](https://github.com/microsoft/rushstack/tree/master/build-tests/heft-node-basic-test): A basic Node.js
application with Jest and ESLint
- [heft-webpack-basic-test](https://github.com/microsoft/rushstack/tree/master/build-tests/heft-webpack-basic-test): A basic
web application bundled using Webpack

Просмотреть файл

@ -45,6 +45,8 @@ module.exports = {
};
```
> NOTE: If your project uses the [React](https://reactjs.org/) framework, you should also extend from `"@rushstack/eslint-config/react"`. See the [@rushstack/eslint-config documentation](https://www.npmjs.com/package/@rushstack/eslint-config) for instructions.
## package.json dependencies

Просмотреть файл

@ -22,7 +22,7 @@ That said, if for some reason you need to run tests in some other runtime such a
## Config files
There isn't a Heft-specific file for this task. Heft looks for Jest's normal config file in the standard path `config/jest.config.json`. Although Jest supports other config file names and even embedding settings in your **package.json** file, Heft only supports the name `jest.config.json`. Using one standard filename makes it easy to search these files, perform bulk edits, and copy configuration recipes between projects.
There isn't a Heft-specific file for this task. Heft looks for [Jest's config file](https://jestjs.io/docs/en/configuration) in the standard path `config/jest.config.json`. Although Jest supports other config file names and even embedding settings in your **package.json** file, Heft only supports the name `jest.config.json`. Using one standard filename makes it easy to search these files, perform bulk edits, and copy configuration recipes between projects.
Generally your Jest configuration should simply extend Heft's standard preset:
@ -56,3 +56,8 @@ $ rush add --package @types/jest --exact --dev
}
}
```
## See also
- Jest's [API reference](https://jestjs.io/docs/en/api)
- [jest.config.json](https://jestjs.io/docs/en/configuration) documentation

Просмотреть файл

@ -0,0 +1,170 @@
---
layout: page
title: Adding more tasks
navigation_source: docs_nav
---
_This section continues the tutorial project from the [Getting started with Heft]({% link pages/heft_tutorials/getting_started.md %}) article._
Heft comes with a number of built-in tasks that become enabled automatically based on config files that you create.
All the tasks are documented in the [Heft tasks]({% link pages/heft_tasks/api-extractor.md %}) section.
In this section, we'll enable the two most common tasks: [Jest]({% link pages/heft_tasks/jest.md %})
and [ESlint]({% link pages/heft_tasks/eslint.md %}).
## Adding unit tests to your project
1. First, we need to install the TypeScript typings for Jest. These steps continue the **my-app** project from the [Getting started with Heft]({% link pages/heft_tutorials/getting_started.md %}) article. Recall that this project is not using Rush yet, so we will invoke PNPM directly to add the dependency to our **package.json** file:
```shell
$ cd my-app
# Typings should always use "--save-exact" version specifiers.
$ pnpm install --save-dev --save-exact @types/jest
```
2. Since [Jest's API](https://jestjs.io/docs/en/api) consists of global variables, we need to load them globally (whereas most other `@types` packages can be loaded via `import` statements in your source code). Update your **tsconfig.json** file to say `"types": ["jest", "node"]` instead of just `"types": ["node"]`. The result should look like this:
**my-app/tsconfig.json**
```js
{
"$schema": "http://json.schemastore.org/tsconfig",
"compilerOptions": {
"outDir": "lib",
"rootDirs": ["src/"],
"forceConsistentCasingInFileNames": true,
"declaration": true,
"sourceMap": true,
"declarationMap": true,
"inlineSources": true,
"strictNullChecks": true,
"noUnusedLocals": true,
"types": ["jest", "node"],
"module": "commonjs",
"target": "es2017",
"lib": ["es2017"]
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "lib"]
}
```
3. Next, we need to add the [jest.config.json](https://jestjs.io/docs/en/configuration) config file. The presence of this file causes Heft to invoke the Jest test runner. Since it is not a Heft-specific file, it goes in the **config** folder instead of the **.heft** folder. For most cases, your Jest configuration should simply extend Heft's standard preset as shown below:
**my-app/config/jest.config.json**
```js
{
"preset": "./node_modules/@rushstack/heft/includes/jest-shared.config.json"
}
```
4. Now we need to add a unit test. Jest supports quite a lot of features, but for this tutorial we'll create a trivial test file:
**my-app/src/example.test.ts**
```ts
describe('Example Test', () => {
it('correctly runs a test', () => {
expect(true).toBeTruthy();
});
});
```
5. To run the test, we need to use the `heft test` action, because `heft build` normally skips testing to speed up development.
```shell
# For Windows, use backslashes for all these commands
# View the command line help
$ ./node_modules/.bin/heft test --help
# Build the project and run tests
$ ./node_modules/.bin/heft test
```
We should update our **package.json** script to invoke `heft test` instead of `heft build` as well. That way `pnpm run build` will also run the Jest tests:
**my-app/package.json**
```
{
. . .
"scripts": {
"build": "heft test --clean",
"start": "node lib/start.js"
}
. . .
}
```
That's it for Jest! More detail can be found in the [jest task]({% link pages/heft_tasks/jest.md %}) reference.
## Enabling linting
1. To ensure best practices and catch common mistakes, let's also enable the [@rushstack/eslint-config](https://www.npmjs.com/package/@rushstack/eslint-config) standard ruleset. First we need to add a few more NPM dependencies to our **package.json** file.
```shell
$ cd my-app
# Add the ESLint engine.
$ pnpm install --save-dev eslint
# Add Rush Stack's all-in-one ruleset
$ pnpm install --save-dev @rushstack/eslint-config
```
2. Next, create the [.eslintrc.js](https://eslint.org/docs/user-guide/configuring) config file. The presence of this file causes Heft to invoke the ESLint task.:
**my-app/.eslintrc.js**
```js
// This is a workaround for https://github.com/eslint/eslint/issues/3458
require('@rushstack/eslint-config/patch/modern-module-resolution');
module.exports = {
extends: [ "@rushstack/eslint-config" ],
parserOptions: { tsconfigRootDir: __dirname }
};
```
_Note: If your project uses the [React](https://reactjs.org/) framework, you should also extend from `"@rushstack/eslint-config/react"`. See [the documentation](https://www.npmjs.com/package/@rushstack/eslint-config) for instructions._
3. To test it out, try updating your test.ts to introduce a lint issue:
**my-app/src/start.ts**
```ts
console.log("Hello, world!");
export function f() { // <--- oops
}
```
When you run `pnpm run build`, you should see a log message like this:
```
. . .
---- Compile started ----
[copy-static-assets] Copied 0 static assets in 0ms
[typescript] Using TypeScript version 3.9.7
[eslint] Using ESLint version 7.5.0
[eslint] Encountered 1 ESLint error:
[eslint] ERROR: src\start.ts:3:8 - (@typescript-eslint/explicit-function-return-type) Missing return type on function.
. . .
```
To fix the problem, change the code to look like this, and it should now build successfully:
**my-app/src/start.ts**
```ts
console.log("Hello, world!");
export function f(): void { // <--- okay
}
```
That's it for ESLint! More detail can be found in the [eslint task]({% link pages/heft_tasks/eslint.md %}) reference.
#### Next up: [Everyday Heft commands]({% link pages/heft_tutorials/everyday_commands.md %})

Просмотреть файл

@ -0,0 +1,10 @@
---
layout: page
title: Everyday Heft commands
navigation_source: docs_nav
---
(This content has not been posted yet. Coming soon!)
#### Next up: [Interfacing with Rush]({% link pages/heft_tutorials/heft_and_rush.md %})

Просмотреть файл

@ -0,0 +1,183 @@
---
layout: page
title: Getting started with Heft
navigation_source: docs_nav
---
This walkthrough will get you started with Heft by creating a basic Node.js console project.
> If you're in a hurry, the
> [heft-node-basic-test](https://github.com/microsoft/rushstack/tree/master/build-tests/heft-node-basic-test)
> and [heft-webpack-basic-test](https://github.com/microsoft/rushstack/tree/master/build-tests/heft-webpack-basic-test)
> folders illustrate a fully worked out example of a simple project that builds using Heft.
We'll begin by creating a simple standalone project without Rush. (Later the [Interfacing with Rush]({% link pages/heft_tutorials/heft_and_rush.md %}) tutorial will show what changes in a monorepo environment.)
1. We'll use the [PNPM package manager](https://pnpm.js.org/) for this demo. (Its command line is very similar to NPM, so could substitute `npm` for `pnpm` in these steps.) There are [various ways](https://pnpm.js.org/en/installation.html) to install PNPM, but the simplest is like this:
```shell
$ npm install --global pnpm
```
2. Create a new folder **my-app** with a **package.json** file for our project, like this:
**my-app/package.json**
```
{
"name": "my-app",
"version": "1.0.0",
"description": "A Heft tutorial project",
"license": "MIT",
"main": "lib/start.js",
"typings": "lib/start.d.ts",
"scripts": {
"start": "node lib/start.js"
}
}
```
3. Create a TypeScript source file that we'll compile.
**my-app/src/start.ts**
```
console.log("Hello, world!");
```
4. Install [@rushstack/heft](https://www.npmjs.com/package/@rushstack/heft) and [typescript](https://www.npmjs.com/package/typescript) as `devDependenices` for your project:
```shell
$ cd my-app
$ pnpm install --save-dev @rushstack/heft
$ pnpm install --save-dev typescript
# Since this project will use the console.log() API, we also need to add the TypeScript
# typings for Node.js. Typings should always use "--save-exact" version specifiers.
$ pnpm install --save-dev --save-exact @types/node
```
5. Next we need to create the TypeScript [tsconfig.json](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) file. The presence of this file causes Heft to invoke the TypeScript compiler. For now we'll create a simple standalone **tsconfig.json** file; later we'll demonstrate how to share a reusable configuration across many projects.
**my-app/tsconfig.json**
```js
{
"$schema": "http://json.schemastore.org/tsconfig",
"compilerOptions": {
"outDir": "lib",
"rootDirs": ["src/"],
"forceConsistentCasingInFileNames": true,
"declaration": true,
"sourceMap": true,
"declarationMap": true,
"inlineSources": true,
"strictNullChecks": true,
"noUnusedLocals": true,
"types": ["node"],
"module": "commonjs",
"target": "es2017",
"lib": ["es2017"]
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "lib"]
}
```
Note that `"types": ["node"]` references the `@types/node` package that we installed above. This is needed because Node.js is a global environment, so its typings must be loaded globally (whereas most other `@types` packages can be loaded via `import` statements in your source code).
See the [typescript task]({% link pages/heft_tasks/typescript.md %}) documentation for more background about TypeScript configuration with Heft.
6. Let's try manually invoking Heft's [command line]({% link pages/heft/cli.md %}) to build our project.
```shell
# For Windows, use backslashes for all these commands
# View the command line help
$ ./node_modules/.bin/heft --help
$ ./node_modules/.bin/heft build --help
# Build the project
$ ./node_modules/.bin/heft build
```
You should see output like this:
```
Project build folder is "/path/to/my-app"
Starting build
---- Compile started ----
[copy-static-assets] Copied 0 static assets in 0ms
[typescript] Using TypeScript version 3.9.7
---- Compile finished (1494ms) ----
---- Bundle started ----
---- Bundle finished (0ms) ----
-------------------- Finished (2.408s) --------------------
Project: my-app@1.0.0
Heft version: 0.3.0
Node version: v12.17.0
```
To see more detail about what Heft is doing, try `./node_modules/.bin/heft build --verbose`. If you encounter problems, you can do `./node_modules/.bin/heft --debug build` for even more detail.
> Some terminology: When we invoke the `heft build` command from the shell, the "build" verb is called an **action**. Actions are user interface concepts, sort of like macros. The action causes Heft to invoke multiple **tasks** such as `[typescript]` or `[copy-static-assets]`. These tasks often run in parallel. The operations are grouped into **stages** such as "Compile" and "Bundle" in the above log. Stages represent major steps of the operation. These concepts are explained in more depth in the [Heft architecture]({% link pages/heft/architecture.md %}) article.
After the build finishes, confirm that it produced several output files in your `lib` folder:
- **start.js** - the compiled JavaScript code
- **start.d.ts** - the TypeScript typings, for external libraries that might import this module
- **start.js.map** and **start.d.ts.map** - Source map files, which enable tools like debuggers to find the corresponding source code file/line, for a given item in an output file
&nbsp;
7. If you recall, our **package.json** file has a `"scripts"` section that specifies `"start": "node lib/start.js"`. Let's try running the compiled code using `pnpm run`.
```shell
# Invoke the "start" script from package.json
$ pnpm run start
```
You should see output like this:
```
> my-app@1.0.0 start C:\my-app
> node lib/start.js
Hello, world!
```
8. We can also add a `"build"` script to our **package.json** file:
**my-app/package.json**
```
{
. . .
"scripts": {
"build": "heft build --clean",
"start": "node lib/start.js"
}
. . .
}
```
With this change, you can also build by invoking `npm run build`. This toolchain-agnostic convention makes it easier for newcomers to guess how to build your project. It will also be useful later when we integrate with Rush.
9. To complete this project, we need to create one more config file to ensure that `heft clean` properly deletes the output files:
**my-app/.heft/clean.json**
```
/**
* Configures the "clean" stage for Heft.
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/heft/clean.schema.json",
/**
* Glob patterns to be deleted by the "heft clean" action. The paths are resolved relative to the project folder.
*/
"pathsToDelete": ["dist", "lib", "temp"]
}
```
_Note: This final step will be eliminated eventually by [PR #2054](https://github.com/microsoft/rushstack/pull/2054), which provides a standard default `"pathsToDelete"` setting._
#### Next up: [Adding more tasks]({% link pages/heft_tutorials/adding_tasks.md %})

Просмотреть файл

@ -0,0 +1,7 @@
---
layout: page
title: Interfacing with Rush
navigation_source: docs_nav
---
(This content has not been posted yet. Coming soon!)