Initial draft of "Getting started with Heft" and "Adding more tasks" tutorials
This commit is contained in:
Родитель
94d9494e81
Коммит
3374fff509
|
@ -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
|
||||
|
||||
|
||||
|
||||
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!)
|
Загрузка…
Ссылка в новой задаче