Build a TypeScript Custom Transformer for On‑Demand Ant Design Imports

This article explains how to use TypeScript's custom transformation feature to rewrite import statements like "import { Button } from 'antd'" into per‑component imports, reducing bundle size, and walks through the required AST manipulation, visitor logic, and integration with ts‑loader.

Baixing.com Technical Team
Baixing.com Technical Team
Baixing.com Technical Team
Build a TypeScript Custom Transformer for On‑Demand Ant Design Imports

Users of ant‑design may know babel-plugin-import, which rewrites imports such as import { Button } from 'antd' into per‑component imports to shrink bundle size. In a TypeScript project without Babel, the same effect can be achieved with a custom transformation introduced in TypeScript 2.3.

Custom transformers let you modify the TypeScript AST before emitting JavaScript. The article first introduces AST basics, showing a simple variable declaration and its tree representation, and explains that the root node is SourceFile. It also lists the main parts of the TS compilation pipeline: Scanner, Parser, Binder, Checker, and Emitter.

The transformer plugin is applied during the Emitter phase. To enable it, you can configure ts-loader in a Webpack setup by providing a getCustomTransformers option that returns the transformer.

{
  test: /\.tsx?$/,
  loader: 'ts-loader',
  options: {
    // other loader options
    getCustomTransformers: () => ({ before: [yourImportedTransformer] })
  }
}

The goal is to convert the example import into:

// before
import { Button } from 'antd'

// after
import Button from 'antd/lib/button'

To achieve this, the transformer must replace the NamedImports node with its identifier and modify the StringLiteral to append the identifier in kebab‑case. Traversal is done with ts.visitEachChild, which allows returning a new node to replace the current one.

Node creation uses factory functions prefixed with create, e.g., ts.createIdentifier or ts.createLiteral. The article shows how to detect node types via ts.SyntaxKind or the ts‑is‑kind helper.

The core updateImportNode function examines each node: if it is a NamedImports, it extracts the identifier name and returns a new identifier; if it is a StringLiteral, it builds a new path using the identifier converted to dash‑case (e.g., Buttonbutton).

function updateImportNode(node: ts.Node, ctx: ts.TransformationContext) {
  const visitor: ts.Visitor = node => {
    if (kind.isNamedImports(node)) {
      const identifierName = node.getChildAt(1).getText();
      return ts.createIdentifier(identifierName);
    }
    if (kind.isStringLiteral(node)) {
      const libName = node.getText().replace(/["']/g, '');
      if (identifierName) {
        const fileName = camel2Dash(identifierName);
        return ts.createLiteral(`${libName}/lib/${fileName}`);
      }
    }
    if (node.getChildCount()) {
      return ts.visitEachChild(node, visitor, ctx);
    }
    return node;
  };
}

With this implementation, the transformer successfully rewrites the import as shown earlier. The article notes that this is a minimal version; a full‑featured solution would need to handle multiple imports, aliasing with as, and CSS imports.

References

TS transformer plugin example: https://github.com/Brooooooklyn/ts-import-plugin

TypeScript declaration file: https://github.com/Microsoft/TypeScript/blob/.../typescript.d.ts

AST Explorer: http://astexplorer.net

ts‑loader transformer docs: https://github.com/TypeStrong/ts-loader#getcustomtransformers

Full plugin source: https://github.com/newraina/learning-ts-transfomer-plugin

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

TypeScriptASTts-loaderCustom TransformerImport Optimization
Baixing.com Technical Team
Written by

Baixing.com Technical Team

A collection of the Baixing.com tech team's insights and learnings, featuring one weekly technical article worth following.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.