https://www.metachris.com/2021/04/starting-a-typescript-project-in-2021/ Chris Hager [ ] * About * Blog * Projects * Starting a TypeScript Project in 2021 April 15, 2021 8 minutes read TypeScript * WebDev This is a guide for starting a TypeScript project in 2021 with modern tooling. * TypeScript 4 * Optionally esbuild to bundle for browsers (and Node.js) * Linting with typescript-eslint (tslint is deprecated) * Testing with Jest (and ts-jest) * Publishing a package to npm * Continuous integration (GitHub Actions / GitLab CI) * Automatic API documentation with TypeDoc You can use the example repository (instead of the manual setup in this guide): git clone https://github.com/metachris/typescript-boilerplate.git --------------------------------------------------------------------- Contents * Basic project setup * Tests with Jest * esbuild + Bundling for Node.js + Building a browser-compatible module * Publishing to npm + Using from Node.js + Using from the browser * Continuous integration + GitHub Actions + GitLab CI * API documentation with TypeDoc * Summary * References * Notes --------------------------------------------------------------------- Basic project setup The basic setup consists of four steps: 1. Create the project and source directories 2. Create a package.json 3. Get a .gitignore, tsconfig.json, .eslintrc.js 4. Install TypeScript & dependencies Note: This guide uses yarn, but if you prefer npm it has similar commands. # Create project folder mkdir my-project cd my-project # Create source folder and files mkdir src touch src/main.ts src/main.test.ts src/cli.ts # Create a package.json yarn init # Install TypeScript, linter and Jest yarn add -D typescript @types/node ts-node yarn add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin yarn add -D jest ts-jest @types/jest # Get a .gitignore wget https://raw.githubusercontent.com/metachris/typescript-boilerplate/master/.gitignore # Get a tsconfig.json with some defaults (adapt as needed) wget https://raw.githubusercontent.com/metachris/typescript-boilerplate/master/tsconfig.json # Alternatively you can create a fresh tsconfig.json (with extensive docstrings) tsc --init # Get a .eslintrc.js wget https://raw.githubusercontent.com/metachris/typescript-boilerplate/master/.eslintrc.js # Get a jest.config.json, for ts-jest to run the tests without a separate typescript compile step wget https://raw.githubusercontent.com/metachris/typescript-boilerplate/master/jest.config.js # Create a git repo and make the first commit git init git add . git commit -am "initial commit" Use src/cli.ts for code that's run from the command line. This way code from main.ts can be included without running the entrypoint code, and allows for easier cross-target building and code branches (eg. Node.js and browsers). Add scripts to your package.json: { "scripts": { "cli": "ts-node src/cli.ts", "test": "jest", "lint": "tslint -c tslint.json 'src/**/*.ts'", "build": "tsc -p tsconfig.json", "clean": "rm -rf dist build", "ts-node": "ts-node" } } Now you can run yarn cli, yarn test, yarn lint, yarn build and yarn ts-node . In Visual Studio Code you can use the build and test tasks to start scripts with keyboard shortcuts. In the command palette "Configure Default Build Task" and "Configure Default Test Task" (see the VS Code docs). --------------------------------------------------------------------- Tests with Jest You can write Jest tests like this: import { greet } from './main' test('the data is peanut butter', () => { expect(1).toBe(1) }); test('greeting', () => { expect(greet('Foo')).toBe('Hello Foo') }); Run the tests with yarn test, no separate compile step is necessary. * See also the Jest documentation * Take a look at other modern test runners such as ava, uvu and tape --------------------------------------------------------------------- esbuild esbuild is an extremely fast JavaScript bundler that can also compile a large subset of TypeScript code. You can use it to bundle both for Node.js as well as for browsers. esbuild is still relatively young and under active / heavy development; see also esbuild on GitHub. Why use esbuild in addition to tsc? The TypeScript compiler doesn't bundle well for browsers (developers usually resort to additional bundlers like webpack, parcel or rollup), and it's pretty slow. Install esbuild: yarn add -D esbuild Bundling for Node.js Additionally to tsc (the TypeScript compiler), you can also bundle code with esbuild for Node.js like this: # Compile and bundle yarn esbuild src/cli.ts --bundle --platform=node --outfile=dist/esbuild/cli.js # Same, but minify and sourcemaps yarn esbuild src/cli.ts --bundle --platform=node --minify --sourcemap=external --outfile=dist/esbuild/cli.js # Run the bundled output node dist/esbuild/cli.js Read more about the esbuild options in the esbuild documentation. Notes: * When building with esbuild, you can use the --watch option to rebuild whenever a file changed * esbuild does currently not support building .d.ts declaration files (see also this issue). You need to build those with tsc. * The example repository includes the esbuild commands as scripts in package.json Building a browser-compatible module You can generate browser compatible modules with bundlers such as esbuild, webpack, parcel and others. This guide uses esbuild: # Bundle for browsers yarn esbuild src/browser.ts --bundle --outfile=dist/esbuild/browser.js # Same, but with minification and sourcemaps yarn esbuild src/browser.ts --bundle --minify --sourcemap=external --outfile=dist/esbuild/browser.js The code in browser.ts will be executed once loaded in the browser. esbuild has a --global-name=xyz flag, to store the exports from the entry point in a global variable. See also the esbuild "Global name" docs. Accessing DOM properties (window, document) You can access window and document in your code when loaded in a browser. You might want to use this to attach parts of your code to the window object. In tsconfig.json, add DOM to the list of libraries: "lib": ["ES6", "DOM"] Create src/browser.ts as entrypoint for browser builds. There you can attach custom properties to window like this: // Import a function import { greet } from './main' // Make it accessible on the window object (window as any).greet = greet Now bundle with esbuild: yarn esbuild src/browser.ts --bundle --outfile=dist/esbuild/browser.js Test the result with a simple website like this: browser-test.html * The example repository includes the esbuild commands as scripts in package.json * If you prefer to use webpack, take a look at this webpack.config.js for inspiration * Rather than casting window to any, you might want to properly extend the Window interface (see here) --------------------------------------------------------------------- Publishing to npm Let's publish the latest code to npm, for use with both Node.js and the browser. npm and yarn ignore the files from .gitignore. Since dist is in there, we need to overwrite the npm ignore settings using a custom .npmignore: wget https://raw.githubusercontent.com/metachris/micropython-ctl/master/.npmignore Create a build and run yarn publish: # Build with tsc and esbuild yarn build-all # Update the version and publish to npm yarn publish build-all builds the project with both tsc to get the type definiton files, and esbuild to build for Node.js and browsers. After running yarn publish the project/new version is live on npm. For example the npm package for this boilerplate project: * https://www.npmjs.com/package/typescript-boilerplate-2021 --------------------------------------------------------------------- Using from Node.js You can install the module with npm: npm install typescript-boilerplate-2021 # or with yarn yarn add typescript-boilerplate-2021 Using the module in custom code: import { greet } from 'typescript-boilerplate-2021' greet("World") --------------------------------------------------------------------- Using from the browser There are several CDNs which automatically deliver npm projects, like jsDelivr, cdnjs, unpkg.com or skypack. Without any manual intervention, you can access packages on jsDelivr like this: * https://cdn.jsdelivr.net/npm/typescript-boilerplate-2021 * https://cdn.jsdelivr.net/npm/typescript-boilerplate-2021/ * https://cdn.jsdelivr.net/npm/[email protected] * https://cdn.jsdelivr.net/npm/[email protected]/package.json * https://cdn.jsdelivr.net/npm/[email protected]/dist/esbuild/ browser.js You can reference the bundle from HTML like this: Test the result with a simple website like this: browser-test.html --------------------------------------------------------------------- Continuous integration You probably want to run the tests and linter on every code push. Additionaly you might want to build and deploy the docs from CI too. GitHub Actions See GitHub Actions docs. Create a file .github/workflows/ lint-and-test.yml: name: Lint and test on: [push, pull_request] jobs: lint_and_test: runs-on: ubuntu-latest strategy: fail-fast: false matrix: nodejs: [10, 12, 14] steps: - uses: actions/[email protected] # https://github.com/actions/setup-node - uses: actions/[email protected] with: node-version: ${{ matrix.nodejs }} - run: yarn install - run: yarn test - run: yarn lint - run: yarn build-all Testing in multiple operating systems If you want to verify your build / package on various operating systems (Windows, Linux, macOS), you can setup a matrix for a job like this: jobs: default-version: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [macos-latest, windows-latest, ubuntu-latest] steps: - uses: actions/[email protected] - uses: actions/[email protected] with: node-version: 12 ... GitLab CI See GitLab CI docs. Create a file .gitlab-ci.yml: image: node:12 cache: paths: - node_modules/ stages: - test lint-and-test: stage: test script: - yarn install - yarn test - yarn lint - yarn build-all --------------------------------------------------------------------- API documentation with TypeDoc You can auto-generate API documentation from the TypeScript source files using TypeDoc, which builds on JSDoc syntax. The generated documentation can be published to GitHub / GitLab pages through the CI. * Install TypeDoc: yarn add -D typedoc * Add docs script to package.json: "typedoc --entryPoints src/ main.ts" Documentation strings look like this: /** * This comment _supports_ [Markdown](https://marked.js.org/) */ export class DocumentMe {} Generate the documentation with yarn docs. The resulting HTML is saved in docs/. You can use CI to automatically publish the docs to GitHub or GitLab pages: * GitHub pages: .github/workflows/deploy-gh-pages.yml * GitLab pages: .gitlab-ci.yml For example this the documentation for the example project: https:// metachris.github.io/typescript-boilerplate/ --------------------------------------------------------------------- Summary This post covered a full TypeScript project setup, with tests, esbuild, bundling for Node.js and browsers, publishing on npm, continuous integration and automatic documentation. You can use the boilerplate repository like this: git clone https://github.com/metachris/typescript-boilerplate.git cd typescript-boilerplate yarn install yarn test yarn lint yarn build-all --------------------------------------------------------------------- References * Example repository * TypeScript Handbook * tsconfig docs * esbuild docs * typescript-eslint docs * Jest docs * GitHub Actions, GitLab CI * Alternative tools and honorable mentions: + Test runners: ava, uvu, tape, Mocha + Bundlers: webpack, Parcel, rollup.js, snowpack --------------------------------------------------------------------- Notes * You might be interested in using Deno instead of Node.js. Deno is a modern V8 runtime with a lot of great features, created by Ryan Dahl, author of Node.js. It's still somewhat new and experimental though. * To bootstrap a full web project, you might want to use hot module replacement (HMR). This is outside the scope of this post. In the meantime, see the webpack docs and parcel docs about HMR. * If you want to target both Node.js and browsers, be aware that several APIs are different, most notably fetch, WebSocket, Buffer. * See also https://github.com/formium/tsdx for a more fully featured TypeScript project boilerplate --------------------------------------------------------------------- Reach out with feedback and ideas: * twitter.com/metachris * github.com/metachris/typescript-boilerplate/issues * Leave a comment below Join the discussion of this post on Hacker News. --------------------------------------------------------------------- [?][?] Subscribe to new posts: [ ] [Subscribe] (about one mail per month) ---------------------------------------------------------------------