UNPKG

19.9 kBMarkdownView Raw
1![tsdx](https://user-images.githubusercontent.com/4060187/56918426-fc747600-6a8b-11e9-806d-2da0b49e89e4.png)
2
3[![Blazing Fast](https://badgen.now.sh/badge/speed/blazing%20%F0%9F%94%A5/green)](https://npm.im/tsdx) [![Blazing Fast](https://badgen.now.sh/badge/speed/blazing%20%F0%9F%94%A5/green)](https://npm.im/tsdx) [![Blazing Fast](https://badgen.now.sh/badge/speed/blazing%20%F0%9F%94%A5/green)](https://npm.im/tsdx) [![Greenkeeper badge](https://badges.greenkeeper.io/jaredpalmer/tsdx.svg)](https://greenkeeper.io/)
4
5Despite all the recent hype, setting up a new TypeScript (x React) library can be tough. Between [Rollup](https://github.com/rollup/rollup), [Jest](https://github.com/facebook/jest), `tsconfig`, [Yarn resolutions](https://yarnpkg.com/en/docs/selective-version-resolutions), ESLint, and getting VSCode to play nicely....there is just a whole lot of stuff to do (and things to screw up). TSDX is a zero-config CLI that helps you develop, test, and publish modern TypeScript packages with ease--so you can focus on your awesome new library and not waste another afternoon on the configuration.
6
7<!-- START doctoc generated TOC please keep comment here to allow auto update -->
8<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
9
10- [Features](#features)
11- [Quick Start](#quick-start)
12 - [`npm start` or `yarn start`](#npm-start-or-yarn-start)
13 - [`npm run build` or `yarn build`](#npm-run-build-or-yarn-build)
14 - [`npm test` or `yarn test`](#npm-test-or-yarn-test)
15 - [`npm run lint` or `yarn lint`](#npm-run-lint-or-yarn-lint)
16- [Optimizations](#optimizations)
17 - [Development-only Expressions + Treeshaking](#development-only-expressions--treeshaking)
18 - [Rollup Treeshaking](#rollup-treeshaking)
19 - [Advanced `babel-plugin-dev-expressions`](#advanced-babel-plugin-dev-expressions)
20 - [`__DEV__`](#__dev__)
21 - [`invariant`](#invariant)
22 - [`warning`](#warning)
23 - [Using lodash](#using-lodash)
24 - [Error extraction](#error-extraction)
25- [Customization](#customization)
26 - [Rollup](#rollup)
27 - [Example: Adding Postcss](#example-adding-postcss)
28 - [Babel](#babel)
29- [Inspiration](#inspiration)
30 - [Comparison to Microbundle](#comparison-to-microbundle)
31- [API Reference](#api-reference)
32 - [`tsdx watch`](#tsdx-watch)
33 - [`tsdx build`](#tsdx-build)
34 - [`tsdx test`](#tsdx-test)
35 - [`tsdx lint`](#tsdx-lint)
36- [Author](#author)
37- [License](#license)
38
39<!-- END doctoc generated TOC please keep comment here to allow auto update -->
40
41## Features
42
43TSDX comes with the "battery-pack included" and is part of a complete TypeScript breakfast:
44
45- Bundles your code with [Rollup](https://github.com/rollup/rollup) and outputs multiple module formats (CJS & ESM by default, and also UMD if you want) plus development and production builds
46- Comes with treeshaking, ready-to-rock lodash optimizations, and minification/compression
47- Live reload / watch-mode
48- Works with React
49- Human readable error messages (and in VSCode-friendly format)
50- Bundle size snapshots
51- Opt-in to extract `invariant` error codes
52- Jest test runner setup with sensible defaults via `tsdx test`
53- Zero-config, single dependency
54
55## Quick Start
56
57```
58npx tsdx create mylib
59cd mylib
60yarn start
61```
62
63That's it. You don't need to worry about setting up Typescript or Rollup or Jest or other plumbing. Just start editing `src/index.ts` and go!
64
65Below is a list of commands you will probably find useful:
66
67### `npm start` or `yarn start`
68
69Runs the project in development/watch mode. Your project will be rebuilt upon changes. TSDX has a special logger for your convenience. Error messages are pretty printed and formatted for compatibility VS Code's Problems tab.
70
71<img src="https://user-images.githubusercontent.com/4060187/52168303-574d3a00-26f6-11e9-9f3b-71dbec9ebfcb.gif" width="600" />
72
73Your library will be rebuilt if you make edits.
74
75### `npm run build` or `yarn build`
76
77Bundles the package to the `dist` folder.
78The package is optimized and bundled with Rollup into multiple formats (CommonJS, UMD, and ES Module).
79
80<img src="https://user-images.githubusercontent.com/4060187/52168322-a98e5b00-26f6-11e9-8cf6-222d716b75ef.gif" width="600" />
81
82### `npm test` or `yarn test`
83
84Runs the test watcher (Jest) in an interactive mode.
85By default, runs tests related to files changed since the last commit.
86
87### `npm run lint` or `yarn lint`
88
89Runs Eslint with Prettier on .ts and .tsx files.
90If you want to customize eslint you can add an `eslint` block to your package.json, or you can run `yarn lint --write-file` and edit the generated `.eslintrc.js` file.
91
92## Optimizations
93
94Aside from just bundling your module into different formats, TSDX comes with some optimizations for your convenience. They yield objectively better code and smaller bundle sizes.
95
96After TSDX compiles your code with TypeScript, it processes your code with 3 Babel plugins:
97
98- [`babel-plugin-annotate-pure-calls`](https://github.com/Andarist/babel-plugin-annotate-pure-calls): Injects for `#__PURE` annotations to enable treeshaking
99- [`babel-plugin-dev-expressions`](https://github.com/4Catalyzer/babel-plugin-dev-expression): A mirror of Facebook's dev-expression Babel plugin. It reduces or eliminates development checks from production code
100- [`babel-plugin-rename-import`](https://github.com/laat/babel-plugin-transform-rename-import): Used to rewrite any `lodash` imports
101
102### Development-only Expressions + Treeshaking
103
104`babel-plugin-annotate-pure-calls` + `babel-plugin-dev-expressions` work together to fully eliminate dead code (aka treeshake) development checks from your production code. Let's look at an example to see how it works.
105
106Imagine our source code is just this:
107
108```tsx
109// ./src/index.ts
110export const sum = (a: number, b: number) => {
111 if (process.env.NODE_ENV !== 'production') {
112 console.log('Helpful dev-only error message');
113 }
114 return a + b;
115};
116```
117
118`tsdx build` will output an ES module file and 3 CommonJS files (dev, prod, and an entry file). If you want to specify a UMD build, you can do that as well. For brevity, let's examine the CommonJS output (comments added for emphasis):
119
120```js
121// Entry File
122// ./dist/index.js
123'use strict';
124
125// This determines which build to use based on the `NODE_ENV` of your end user.
126if (process.env.NODE_ENV === 'production') {
127 module.exports = require('./mylib.cjs.production.js');
128} else {
129 module.exports = require('./mylib.cjs.development.js');
130}
131```
132
133```js
134// CommonJS Development Build
135// ./dist/mylib.cjs.development.js
136'use strict';
137
138const sum = (a, b) => {
139 {
140 console.log('Helpful dev-only error message');
141 }
142
143 return a + b;
144};
145
146exports.sum = sum;
147//# sourceMappingURL=mylib.cjs.development.js.map
148```
149
150```js
151// CommonJS Production Build
152// ./dist/mylib.cjs.production.js
153'use strict';
154exports.sum = (s, t) => s + t;
155//# sourceMappingURL=test-react-tsdx.cjs.production.js.map
156```
157
158AS you can see, TSDX stripped out the development check from the production code. **This allows you to safely add development-only behavior (like more useful error messages) without any production bundle size impact.**
159
160For ESM build, it's up to end-user to build environment specific build with NODE_ENV replace (done by Webpack 4 automatically).
161
162#### Rollup Treeshaking
163
164TSDX's rollup config [removes getters and setters on objects](https://github.com/palmerhq/tsdx/blob/1f6a1b6819bb17678aa417f0df5349bec12f59ac/src/createRollupConfig.ts#L73) so that property access has no side effects. Don't do it.
165
166#### Advanced `babel-plugin-dev-expressions`
167
168TSDX will use `babel-plugin-dev-expressions` to make the following replacements _before_ treeshaking.
169
170##### `__DEV__`
171
172Replaces
173
174```ts
175if (__DEV__) {
176 console.log('foo');
177}
178```
179
180with
181
182```js
183if (process.env.NODE_ENV !== 'production') {
184 console.log('foo');
185}
186```
187
188**IMPORTANT:** To use `__DEV__` in TypeScript, you need add `declare var __DEV__: boolean` somewhere in your project's type path (e.g. `./types/index.d.ts`).
189
190```ts
191// ./types/index.d.ts
192declare var __DEV__: boolean;
193```
194
195> **Note:** The `dev-expression` transform does not run when `NODE_ENV` is `test`. As such, if you use `__DEV__`, you will need to define it as a global constant in your test environment.
196
197##### `invariant`
198
199Replaces
200
201```js
202invariant(condition, 'error message here');
203```
204
205with
206
207```js
208if (!condition) {
209 if ('production' !== process.env.NODE_ENV) {
210 invariant(false, 'error message here');
211 } else {
212 invariant(false);
213 }
214}
215```
216
217Note: TSDX doesn't supply an `invariant` function for you, you need to import one yourself. We recommend https://github.com/alexreardon/tiny-invariant.
218
219To extract and minify `invariant` error codes in production into a static `codes.json` file, specify the `--extractErrors` flag in command line. For more details see [Error extraction docs](#error-extraction).
220
221##### `warning`
222
223Replaces
224
225```js
226warning(condition, 'dev warning here');
227```
228
229with
230
231```js
232if ('production' !== process.env.NODE_ENV) {
233 warning(condition, 'dev warning here');
234}
235```
236
237Note: TSDX doesn't supply a `warning` function for you, you need to import one yourself. We recommend https://github.com/alexreardon/tiny-warning.
238
239### Using lodash
240
241If you want to use a lodash function in your package, TSDX will help you do it the _right_ way so that your library does not get fat shamed on Twitter. However, before you continue, seriously consider rolling whatever function you are about to use on your own. Anyways, here is how to do it right.
242
243First, install `lodash` and `lodash-es` as _dependencies_
244
245```bash
246yarn add lodash lodash-es
247```
248
249Now install `@types/lodash` to your development dependencies.
250
251```bash
252yarn add @types/lodash --dev
253```
254
255Import your lodash method however you want, TSDX will optimize it like so.
256
257```tsx
258// ./src/index.ts
259import kebabCase from 'lodash/kebabCase';
260
261export const KebabLogger = (msg: string) => {
262 console.log(kebabCase(msg));
263};
264```
265
266For brevity let's look at the ES module output.
267
268<!-- prettier-ignore -->
269```js
270import o from"lodash-es/kebabCase";const e=e=>{console.log(o(e))};export{e as KebabLogger};
271//# sourceMappingURL=test-react-tsdx.esm.production.js.map
272```
273
274TSDX will rewrite your `import kebabCase from 'lodash/kebabCase'` to `import o from 'lodash-es/kebabCase'`. This allows your library to be treeshakable to end consumers while allowing to you to use `@types/lodash` for free.
275
276> Note: TSDX will also transform destructured imports. For example, `import { kebabCase } from 'lodash'` would have also been transformed to `import o from "lodash-es/kebabCase".
277
278### Error extraction
279
280After running `--extractErrors`, you will have a `./errors/codes.json` file with all your extracted `invariant` error codes. This process scans your production code and swaps out your `invariant` error message strings for a corresponding error code (just like React!). This extraction only works if your error checking/warning is done by a function called `invariant`.
281
282Note: We don't provide this function for you, it is up to you how you want it to behave. For example, you can use either `tiny-invariant` or `tiny-warning`, but you must then import the module as a variable called `invariant` and it should have the same type signature.
283
284⚠️Don't forget: you will need to host the decoder somewhere. Once you have a URL, look at `./errors/ErrorProd.js` and replace the `reactjs.org` URL with yours.
285
286> Known issue: our `transformErrorMessages` babel plugin currently doesn't have sourcemap support, so you will see "Sourcemap is likely to be incorrect" warnings. [We would love your help on this.](https://github.com/palmerhq/tsdx/issues/184)
287
288_TODO: Simple guide to host error codes to be completed_
289
290## Customization
291
292### Rollup
293
294TSDX uses Rollup under the hood. The defaults are solid for most packages (Formik uses the defaults!). However, if you do wish to alter the rollup configuration, you can do so by creating a file called `tsdx.config.js` at the root of your project like so:
295
296```js
297// Not transpiled with TypeScript or Babel, so use plain Es6/Node.js!
298module.exports = {
299 // This function will run for each entry/format/env combination
300 rollup(config, options) {
301 return config; // always return a config.
302 },
303};
304```
305
306The `options` object contains the following:
307
308```tsx
309export interface TsdxOptions {
310 // path to file
311 input: string;
312 // Safe name (for UMD)
313 name: string;
314 // JS target
315 target: 'node' | 'browser';
316 // Module format
317 format: 'cjs' | 'umd' | 'esm' | 'system';
318 // Environment
319 env: 'development' | 'production';
320 // Path to tsconfig file
321 tsconfig?: string;
322 // Is opt-in invariant error extraction active?
323 extractErrors?: boolean;
324 // Is minifying?
325 minify?: boolean;
326 // Is this the very first rollup config (and thus should one-off metadata be extracted)?
327 writeMeta?: boolean;
328}
329```
330
331#### Example: Adding Postcss
332
333```js
334const postcss = require('rollup-plugin-postcss');
335const autoprefixer = require('autoprefixer');
336const cssnano = require('cssnano');
337
338module.exports = {
339 rollup(config, options) {
340 config.plugins.push(
341 postcss({
342 plugins: [
343 autoprefixer(),
344 cssnano({
345 preset: 'default',
346 }),
347 ],
348 inject: false,
349 // only write out CSS for the first bundle (avoids pointless extra files):
350 extract: !!options.writeMeta,
351 })
352 );
353 return config;
354 },
355};
356```
357
358### Babel
359
360You can add your own `.babelrc` to the root of your project and TSDX will **merge** it with its own babel transforms (which are mostly for optimization).
361
362## Inspiration
363
364TSDX is ripped out of [Formik's](https://github.com/jaredpalmer/formik) build tooling. TSDX is very similar to [@developit/microbundle](https://github.com/developit/microbundle), but that is because Formik's Rollup configuration and Microbundle's internals have converged around similar plugins over the last year or so.
365
366### Comparison to Microbundle
367
368- TSDX includes out-of-the-box test running via Jest
369- TSDX includes a bootstrap command and default package template
370- TSDX is 100% TypeScript focused. While yes, TSDX does use Babel to run a few optimizations (related to treeshaking and lodash), it does not support custom babel configurations.
371- TSDX outputs distinct development and production builds (like React does) for CJS and UMD builds. This means you can include rich error messages and other dev-friendly goodies without sacrificing final bundle size.
372
373## API Reference
374
375### `tsdx watch`
376
377```shell
378Description
379 Rebuilds on any change
380
381Usage
382 $ tsdx watch [options]
383
384Options
385 -i, --entry Entry module(s)
386 --target Specify your target environment (default web)
387 --name Specify name exposed in UMD builds
388 --format Specify module format(s) (default cjs,esm)
389 --tsconfig Specify your custom tsconfig path (default <root-folder>/tsconfig.json)
390 --verbose Keep outdated console output in watch mode instead of clearing the screen
391 --noClean Don't clean the dist folder
392 -h, --help Displays this message
393
394Examples
395 $ tsdx watch --entry src/foo.tsx
396 $ tsdx watch --target node
397 $ tsdx watch --name Foo
398 $ tsdx watch --format cjs,esm,umd
399 $ tsdx watch --tsconfig ./tsconfig.foo.json
400 $ tsdx watch --noClean
401```
402
403### `tsdx build`
404
405```shell
406Description
407 Build your project once and exit
408
409Usage
410 $ tsdx build [options]
411
412Options
413 -i, --entry Entry module(s)
414 --target Specify your target environment (default web)
415 --name Specify name exposed in UMD builds
416 --format Specify module format(s) (default cjs,esm)
417 --extractErrors Opt-in to extracting invariant error codes
418 --tsconfig Specify your custom tsconfig path (default <root-folder>/tsconfig.json)
419 -h, --help Displays this message
420
421Examples
422 $ tsdx build --entry src/foo.tsx
423 $ tsdx build --target node
424 $ tsdx build --name Foo
425 $ tsdx build --format cjs,esm,umd
426 $ tsdx build --extractErrors
427 $ tsdx build --tsconfig ./tsconfig.foo.json
428```
429
430### `tsdx test`
431
432This runs Jest v24.x in watch mode. See [https://jestjs.io](https://jestjs.io) for options. If you are using the React template, jest uses the flag `--env=jsdom` by default.
433
434### `tsdx lint`
435
436```shell
437Description
438 Run eslint with Prettier
439
440Usage
441 $ tsdx lint [options]
442
443Options
444 --fix Fixes fixable errors and warnings
445 --ignore-pattern Ignore a pattern
446 --write-file Write the config file locally
447 --report-file Write JSON report to file locally
448 -h, --help Displays this message
449
450Examples
451 $ tsdx lint src
452 $ tsdx lint src --fix
453 $ tsdx lint src test --ignore-pattern test/foo.ts
454 $ tsdx lint src --write-file
455 $ tsdx lint src --report-file report.json
456```
457
458## Author
459
460- [Jared Palmer](https://twitter.com/jaredpalmer)
461
462## License
463
464[MIT](https://oss.ninja/mit/jaredpalmer/)
465
466## Contributors ✨
467
468Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
469
470<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
471<!-- prettier-ignore -->
472<table>
473 <tr>
474 <td align="center"><a href="https://jaredpalmer.com"><img src="https://avatars2.githubusercontent.com/u/4060187?v=4" width="100px;" alt="Jared Palmer"/><br /><sub><b>Jared Palmer</b></sub></a><br /><a href="https://github.com/jaredpalmer/tsdx/commits?author=jaredpalmer" title="Documentation">📖</a> <a href="#design-jaredpalmer" title="Design">🎨</a> <a href="#review-jaredpalmer" title="Reviewed Pull Requests">👀</a> <a href="#tool-jaredpalmer" title="Tools">🔧</a> <a href="https://github.com/jaredpalmer/tsdx/commits?author=jaredpalmer" title="Tests">⚠️</a> <a href="#maintenance-jaredpalmer" title="Maintenance">🚧</a> <a href="https://github.com/jaredpalmer/tsdx/commits?author=jaredpalmer" title="Code">💻</a></td>
475 <td align="center"><a href="https://twitter.com/swyx"><img src="https://avatars1.githubusercontent.com/u/6764957?v=4" width="100px;" alt="swyx"/><br /><sub><b>swyx</b></sub></a><br /><a href="https://github.com/jaredpalmer/tsdx/issues?q=author%3Asw-yx" title="Bug reports">🐛</a> <a href="https://github.com/jaredpalmer/tsdx/commits?author=sw-yx" title="Code">💻</a> <a href="https://github.com/jaredpalmer/tsdx/commits?author=sw-yx" title="Documentation">📖</a> <a href="#design-sw-yx" title="Design">🎨</a> <a href="#ideas-sw-yx" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-sw-yx" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-sw-yx" title="Maintenance">🚧</a> <a href="#review-sw-yx" title="Reviewed Pull Requests">👀</a></td>
476 <td align="center"><a href="https://jasonet.co"><img src="https://avatars1.githubusercontent.com/u/10660468?v=4" width="100px;" alt="Jason Etcovitch"/><br /><sub><b>Jason Etcovitch</b></sub></a><br /><a href="https://github.com/jaredpalmer/tsdx/issues?q=author%3AJasonEtco" title="Bug reports">🐛</a> <a href="https://github.com/jaredpalmer/tsdx/commits?author=JasonEtco" title="Tests">⚠️</a></td>
477 <td align="center"><a href="https://github.com/skvale"><img src="https://avatars0.githubusercontent.com/u/5314713?v=4" width="100px;" alt="Sam Kvale"/><br /><sub><b>Sam Kvale</b></sub></a><br /><a href="https://github.com/jaredpalmer/tsdx/commits?author=skvale" title="Code">💻</a> <a href="https://github.com/jaredpalmer/tsdx/commits?author=skvale" title="Tests">⚠️</a> <a href="https://github.com/jaredpalmer/tsdx/issues?q=author%3Askvale" title="Bug reports">🐛</a> <a href="https://github.com/jaredpalmer/tsdx/commits?author=skvale" title="Documentation">📖</a></td>
478 </tr>
479</table>
480
481<!-- ALL-CONTRIBUTORS-LIST:END -->
482
483This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!