@valy/tsd

    0.0.13 • Public • Published

    tsd

    Blazing Fast Blazing Fast Blazing Fast Greenkeeper badge

    Despite all the recent hype, setting up a new TypeScript (x React) library can be tough. Between Rollup, Jest, tsconfig, Yarn resolutions, ESLint, and getting VSCode to play nicely....there is just a whole lot of stuff to do (and things to screw up). TSD 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.

    Features

    TSD comes with the "battery-pack included" and is part of a complete TypeScript breakfast:

    • Bundles your code with Rollup and outputs multiple module formats (CJS & ESM by default, and also UMD if you want) plus development and production builds
    • Comes with treeshaking, ready-to-rock lodash optimizations, and minification/compression
    • Live reload / watch-mode
    • Works with React
    • Human readable error messages (and in VSCode-friendly format)
    • Bundle size snapshots
    • Opt-in to extract invariant error codes
    • Jest test runner setup with sensible defaults via tsd test
    • Zero-config, single dependency

    Quick Start

    npx tsd create mylib
    cd mylib
    yarn start
    

    That'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!

    Below is a list of commands you will probably find useful:

    npm start or yarn start

    Runs the project in development/watch mode. Your project will be rebuilt upon changes. TSD has a special logger for your convenience. Error messages are pretty printed and formatted for compatibility VS Code's Problems tab.

    Your library will be rebuilt if you make edits.

    npm run build or yarn build

    Bundles the package to the dist folder. The package is optimized and bundled with Rollup into multiple formats (CommonJS, UMD, and ES Module).

    npm test or yarn test

    Runs the test watcher (Jest) in an interactive mode. By default, runs tests related to files changed since the last commit.

    npm run lint or yarn lint

    Runs Eslint with Prettier on .ts and .tsx files. If 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.

    Optimizations

    Aside from just bundling your module into different formats, TSD comes with some optimizations for your convenience. They yield objectively better code and smaller bundle sizes.

    After TSD compiles your code with TypeScript, it processes your code with 3 Babel plugins:

    Development-only Expressions + Treeshaking

    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.

    Imagine our source code is just this:

    // ./src/index.ts
    export const sum = (a: number, b: number) => {
      if (process.env.NODE_ENV !== 'production') {
        console.log('Helpful dev-only error message');
      }
      return a + b;
    };

    tsd 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):

    // Entry File
    // ./dist/index.js
    'use strict';
    
    // This determines which build to use based on the `NODE_ENV` of your end user.
    if (process.env.NODE_ENV === 'production') {
      module.exports = require('./mylib.cjs.production.js');
    } else {
      module.exports = require('./mylib.cjs.development.js');
    }
    // CommonJS Development Build
    // ./dist/mylib.cjs.development.js
    'use strict';
    
    const sum = (a, b) => {
      {
        console.log('Helpful dev-only error message');
      }
    
      return a + b;
    };
    
    exports.sum = sum;
    //# sourceMappingURL=mylib.cjs.development.js.map
    // CommonJS Production Build
    // ./dist/mylib.cjs.production.js
    'use strict';
    exports.sum = (s, t) => s + t;
    //# sourceMappingURL=test-react-tsd.cjs.production.js.map

    AS you can see, TSD 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.

    For ESM build, it's up to end-user to build environment specific build with NODE_ENV replace (done by Webpack 4 automatically).

    Advanced babel-plugin-dev-expressions

    TSD will use babel-plugin-dev-expressions to make the following replacements before treeshaking.

    __DEV__

    Replaces

    if (__DEV__) {
      console.log('foo');
    }

    with

    if (process.env.NODE_ENV !== 'production') {
      console.log('foo');
    }

    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).

    // ./types/index.d.ts
    declare var __DEV__: boolean;

    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.

    invariant

    Replaces

    invariant(condition, 'error message here');

    with

    if (!condition) {
      if ('production' !== process.env.NODE_ENV) {
        invariant(false, 'error message here');
      } else {
        invariant(false);
      }
    }

    Note: TSD doesn't supply an invariant function for you, you need to import one yourself. We recommend https://github.com/alexreardon/tiny-invariant.

    To 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.

    warning

    Replaces

    warning(condition, 'dev warning here');

    with

    if ('production' !== process.env.NODE_ENV) {
      warning(condition, 'dev warning here');
    }

    Note: TSD doesn't supply a warning function for you, you need to import one yourself. We recommend https://github.com/alexreardon/tiny-warning.

    Using lodash

    If you want to use a lodash function in your package, TSD 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.

    First, install lodash and lodash-es as dependencies

    yarn add lodash lodash-es

    Now install @types/lodash to your development dependencies.

    yarn add @types/lodash --dev

    Import your lodash method however you want, TSD will optimize it like so.

    // ./src/index.ts
    import kebabCase from 'lodash/kebabCase';
    
    export const KebabLogger = (msg: string) => {
      console.log(kebabCase(msg));
    };

    For brevity let's look at the ES module output.

    import o from"lodash-es/kebabCase";const e=e=>{console.log(o(e))};export{e as KebabLogger};
    //# sourceMappingURL=test-react-tsd.esm.production.js.map

    TSD 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.

    Note: TSD will also transform destructured imports. For example, import { kebabCase } from 'lodash' would have also been transformed to `import o from "lodash-es/kebabCase".

    Error extraction

    After 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.

    Note: 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.

    ⚠️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.

    Customization

    Rollup

    TSD 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 tsd.config.js at the root of your project like so:

    // Not transpiled with TypeScript or Babel, so use plain Es6/Node.js!
    module.exports = {
      // This function will run for each entry/format/env combination
      rollup(config, options) {
        return config; // always return a config.
      },
    };

    The options object contains the following:

    export interface TsdxOptions {
      // path to file
      input: string;
      // Safe name (for UMD)
      name: string;
      // JS target
      target: 'node' | 'browser';
      // Module format
      format: 'cjs' | 'umd' | 'esm' | 'system';
      // Environment
      env: 'development' | 'production';
      // Path to tsconfig file
      tsconfig?: string;
      // Is opt-in invariant error extraction active?
      extractErrors?: boolean;
      // Is minifying?
      minify?: boolean;
      // Is this the very first rollup config (and thus should one-off metadata be extracted)?
      writeMeta?: boolean;
    }

    Example: Adding Postcss

    const postcss = require('rollup-plugin-postcss');
    const autoprefixer = require('autoprefixer');
    const cssnano = require('cssnano');
    
    module.exports = {
      rollup(config, options) {
        config.plugins.push(
          postcss({
            plugins: [
              autoprefixer(),
              cssnano({
                preset: 'default',
              }),
            ],
            inject: false,
            // only write out CSS for the first bundle (avoids pointless extra files):
            extract: !!options.writeMeta,
          })
        );
        return config;
      },
    };

    Babel

    You can add your own .babelrc to the root of your project and TSD will merge it with its own babel transforms (which are mostly for optimization).

    Inspiration

    TSD is ripped out of Formik's build tooling. TSD is very similar to @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.

    Comparison to Microbundle

    • TSD includes out-of-the-box test running via Jest
    • TSD includes a bootstrap command and default package template
    • TSD is 100% TypeScript focused. While yes, TSD does use Babel to run a few optimizations (related to treeshaking and lodash), it does not support custom babel configurations.
    • TSD 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.

    API Reference

    tsd watch

    Description
      Rebuilds on any change
    
    Usage
      $ tsd watch [options]
    
    Options
      -i, --entry           Entry module(s)
      --target              Specify your target environment  (default web)
      --name                Specify name exposed in UMD builds
      --format              Specify module format(s)  (default cjs,esm)
      --tsconfig            Specify your custom tsconfig path (default <root-folder>/tsconfig.json)
      --verbose             Keep outdated console output in watch mode instead of clearing the screen
      --noClean             Don't clean the dist folder
      -h, --help            Displays this message
    
    Examples
      $ tsd watch --entry src/foo.tsx
      $ tsd watch --target node
      $ tsd watch --name Foo
      $ tsd watch --format cjs,esm,umd
      $ tsd watch --tsconfig ./tsconfig.foo.json
      $ tsd watch --noClean

    tsd build

    Description
      Build your project once and exit
    
    Usage
      $ tsd build [options]
    
    Options
      -i, --entry           Entry module(s)
      --target              Specify your target environment  (default web)
      --name                Specify name exposed in UMD builds
      --format              Specify module format(s)  (default cjs,esm)
      --extractErrors       Opt-in to extracting invariant error codes
      --tsconfig            Specify your custom tsconfig path (default <root-folder>/tsconfig.json)
      -h, --help            Displays this message
    
    Examples
      $ tsd build --entry src/foo.tsx
      $ tsd build --target node
      $ tsd build --name Foo
      $ tsd build --format cjs,esm,umd
      $ tsd build --extractErrors
      $ tsd build --tsconfig ./tsconfig.foo.json

    tsd test

    This runs Jest v24.x in watch mode. See https://jestjs.io for options. If you are using the React template, jest uses the flag --env=jsdom by default.

    tsd lint

    Description
      Run eslint with Prettier
    
    Usage
      $ tsd lint [options]
    
    Options
      --fix               Fixes fixable errors and warnings
      --ignore-pattern    Ignore a pattern
      --write-file        Write the config file locally
      --report-file       Write JSON report to file locally
      -h, --help          Displays this message
    
    Examples
      $ tsd lint src
      $ tsd lint src --fix
      $ tsd lint src test --ignore-pattern test/foo.ts
      $ tsd lint src --write-file
      $ tsd lint src --report-file report.json

    Author

    License

    MIT

    Contributors

    Thanks goes to these wonderful people (emoji key):

    Valery Bugakov
    Valery Bugakov

    📖 🎨 👀 🔧 ⚠️ 🚧 💻
    swyx
    swyx

    🐛 💻 📖 🎨 🤔 🚇 🚧 👀
    Jason Etcovitch
    Jason Etcovitch

    🐛 ⚠️
    Sam Kvale
    Sam Kvale

    💻 ⚠️ 🐛 📖

    This project follows the all-contributors specification. Contributions of any kind welcome!

    Install

    npm i @valy/tsd

    DownloadsWeekly Downloads

    2

    Version

    0.0.13

    License

    MIT

    Unpacked Size

    87.5 kB

    Total Files

    38

    Last publish

    Collaborators

    • valerybugakov