Aside from just bundling your module into different formats, DTS comes with some optimizations for your convenience. They yield objectively better code and smaller bundle sizes.
After DTS compiles your code with TypeScript, it processes your code with 3 Babel plugins:
babel-plugin-annotate-pure-calls
: Injects for #__PURE
annotations to enable treeshaking
babel-plugin-dev-expressions
: A mirror of Facebook's dev-expression Babel plugin. It reduces or eliminates development checks from production code
babel-plugin-rename-import
: Used to rewrite any lodash
imports
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:
1// ./src/index.ts2export const sum = (a: number, b: number) => {3if (process.env.NODE_ENV !== 'production') {4console.log('Helpful dev-only error message');5}6return a + b;7};
dts 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):
1// Entry File2// ./dist/index.js3'use strict';45// This determines which build to use based on the `NODE_ENV` of your end user.6if (process.env.NODE_ENV === 'production') {7module.exports = require('./mylib.cjs.production.js');8} else {9module.exports = require('./mylib.cjs.development.js');10}
1// CommonJS Development Build2// ./dist/mylib.cjs.development.js3'use strict';45const sum = (a, b) => {6{7console.log('Helpful dev-only error message');8}910return a + b;11};1213exports.sum = sum;14//# sourceMappingURL=mylib.cjs.development.js.map
1// CommonJS Production Build2// ./dist/mylib.cjs.production.js3'use strict';4exports.sum = (s, t) => s + t;5//# sourceMappingURL=test-react-dts-cli.cjs.production.js.map
As you can see, DTS 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).
DTS's rollup config removes getters and setters on objects so that property access has no side effects. Don't do it.
babel-plugin-dev-expressions
#DTS will use babel-plugin-dev-expressions
to make the following replacements before treeshaking.
__DEV__
Replaces
1if (__DEV__) {2console.log('foo');3}
with
1if (process.env.NODE_ENV !== 'production') {2console.log('foo');3}
IMPORTANT: To use __DEV__
in TypeScript, you need to add declare var __DEV__: boolean
somewhere in your project's type path (e.g. ./types/index.d.ts
).
1// ./types/index.d.ts2declare 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
1invariant(condition, 'error message here');
with
1if (!condition) {2if ('production' !== process.env.NODE_ENV) {3invariant(false, 'error message here');4} else {5invariant(false);6}7}
Note: DTS 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
1warning(condition, 'dev warning here');
with
1if ('production' !== process.env.NODE_ENV) {2warning(condition, 'dev warning here');3}
Note: DTS doesn't supply a warning
function for you, you need to import one yourself. We recommend https://github.com/alexreardon/tiny-warning.
If you want to use a lodash function in your package, DTS 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
1yarn add lodash lodash-es
Now install @types/lodash
to your development dependencies.
1yarn add @types/lodash --dev
Import your lodash method however you want, DTS will optimize it like so.
1// ./src/index.ts2import kebabCase from 'lodash/kebabCase';34export const KebabLogger = (msg: string) => {5console.log(kebabCase(msg));6};
For brevity let's look at the ES module output.
1import o from"lodash-es/kebabCase";const e=e=>{console.log(o(e))};export{e as KebabLogger};2//# sourceMappingURL=test-react-dts-cli.esm.production.js.map
DTS 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: DTS will also transform destructured imports. For example, import { kebabCase } from 'lodash'
would have also been transformed to `import o from "lodash-es/kebabCase".
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.
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.
TODO: Simple guide to host error codes to be completed