Features

Zero Config

Start with a JS/TS file, and Mako will handle the rest. TypeScript, Less, CSS, CSS Modules, React, Images, Fonts, WASM, Node Polyfill and more are supported out of the box. No need to configure loaders, plugins, or anything else.

But, everything is configurable. If you have a file type that Mako doesn’t support, you can add a plugin with loader for it.

Production Grade

Mako is reliable. It’s used in hundreds of projects at Ant Group, like Web App,Hybrid App, Mini Program (Partly), Low Code, Serverless, Library Development, Ant Design and others. We have a lot of tests and benchmarks to ensure the quality of Mako. We have also tested Mako in thousands of old projects, and thousands of npm packages and it’s different versions to ensure the compatibility.

Blazing Fast

Mako is designed to be blazing fast. We use Rust for the core bundling logic, and we use workers in Node.js with piscina to compile files in parallel. We have spend lots of time optimizing the performance of Mako. And Mako is faster than other Rust bundlers and Webpack in benchmark case.

Check out 《聊下 Mako 的 Benchmark》 and the benchmark repo for more details.

Hot Module Replacement

When files change, Mako will automatically update your code in the browser. No need to refresh the page manually.

And Mako has integrated React Fast Refresh, when you change a React component, it will only update the component, not the whole page.

HMR in full ant-design-pro project: Webpack(above) vs Mako(below).

Diagnostics

Mako has a built-in diagnostics system that will show you errors and warnings in the terminal. (WIP: And in the browser, in the future version.)

When you have an error in your code, Mako will show you beautiful diagnostics. Every error includes a code frame that shows you the context of the error. Many errors also include suggestions for how to fix the error.

TypeScript

TypeScript is supported out of the box. Mako will automatically compile your TypeScript files to JavaScript.

And there’re something you might want to know:

Less

Less is supported out of the box. Mako will automatically compile your Less files to CSS.

Since less is used heavily in Ant Group, Mako has been optimized for this. We use workers in Node.js with piscina to compile less files in parallel, which can speed up the compilation process. So, it’s faster than other rust bundle tools in this case by default. Checkout 《Node 多线程的魔力 - Mako 中的 Less 并行编译》 for more details.

And there’re something you might want to know:

CSS Modules

By default, files ending with .module.css or .module.less will be treated as CSS Modules. You can import them like this:

/* styles.module.css */
.container {
  color: red;
}
import styles from './styles.module.css';
console.log(styles.container); // styles.container will be a string

And there’re something you might want to know:

SVG as React Component

You can import SVG files as React components. Mako will automatically optimize the SVG files and convert them to React components.

import { ReactComponent as Logo } from './logo.svg';

CLI

Mako has a simple built-in CLI that you can use to start a development server, build your project, and more. It only has a build command for now, and more commands might be added in the future.

$ npm i @umijs/mako -D
$ npx mako -h

Mako vX.X.X

Usage: mako <command> [options]

Commands:
  build

Options:
  --help,-h
  --version,-v

Examples:
  mako build
  mako -v

If you want to use Mako in development, you can add the --watch parameter to the build command. Check npx mako build -h for more details.

$ npx mako build --watch

It’s also suggested to use Mako with API in your framework or tool, like what Umi does.

const { build } = require('@umijs/mako');
await build({
  root: process.cwd(),
  watch: false,
  config: {},
});

Plugins

NOTICE: Plugin system is still under development, and the API may change in the future.

Plugins are JavaScript Objects that can modify the behavior of Mako. They can add new features, modify existing features, or even remove features.

{
  name?: string;
  buildStart?: () => void;
  generateEnd?: (data: {
    isFirstCompile: boolean;
    time: number;
    stats: {
      startTime: number;
      endTime: number;
    };
  }) => void;
  load?: (filePath: string) => Promise<{ content: string, type: 'css'|'js'|'jsx'|'ts'|'tsx' }>;
}

If you want to use plugins in your project, you can add them to the plugins field in the config.

{
  plugins: [
    require.resolve('./my-plugin'),
  ],
}

Code Splitting

Mako has built-in support for code splitting. You can use dynamic imports to split your code into separate bundles. Resulting in smaller initial bundle sizes and faster load times.

import('./module').then(module => {
  console.log(module);
});

Mako has a codeSplitting config that you can use to customize the behavior of code splitting. We have three strategies for code splitting:

Notice: There’s no Silver Bullet for code splitting, you should choose the strategy based on your project.

One more thing you might want to know:

Tree Shaking

Tree shaking is a technique used to eliminate dead code by analyzing the import/export relationships between JavaScript modules. In Mako, the tree shaking feature is enabled by default in production builds and disabled in watch mode. For more information on tree shaking, refer to our blog.

In addition to removing dead code between modules, Mako introduces a feature called “skipModules” to eliminate redundant modules. If a module’s exported variable is imported through some side-effect-free modules, this feature allows the importer module to bypass the intermediary modules and import it directly.

skipModules-demo

Module Concatenation

Module concatenation is an optimization feature designed to reduce both bundle size and runtime overhead. It is equivalent to the implementation found in Webpack’s optimization documentation.

This feature identifies groups of modules that are exclusively dependent on the modules in the same group and concatenates every groups into a single module respectively.

Targets

Mako has a targets config that you can use to specify the browsers that you want to target. Mako will automatically compile your code to be compatible with the specified browsers, including injecting polyfills(not yet), helpers and more.

{
  targets: {
    chrome: 40,
    ie: 11,
  },
}

When you want to build for node, you should also set platform to node and dynamicImportToRequire to true in the config. (Why need to set dynamicImportToRequire to true? Because the runtime does not yet support node-style chunk loading.)

{
  platform: 'node',
  dynamicImportToRequire: true,
}

Notice: When platform is set to 'node', Mako will ignore all Node.js built-in modules (like fs, path, http, etc.) to keep the origin require expression.

Node Polyfill

When platform is not set or is set to 'browser', Mako will automatically inject a Node.js polyfill to your code. This polyfill includes all Node.js built-in modules (like fs, path, http, etc.) and global objects (like process, Buffer, etc.). And process.env.NODE_ENV will be set to 'development' in development mode and 'production' in production mode.

Native Node.js modules polyfill is based on node-libs-browser-okam which is forked from node-libs-browser. If you are curious about which polyfill is for which module, you can checkout the source code.

Code Analysis

Mako has a basic built-in code analysis system that will show you the size of your code and the size of each module. Enable it by setting analyze in the config.

{
  analyze: {},
}

The output will be like this:

RSC

Mako has a built-in RSC (React Server Components) support, but it’s still experimental and not optimized for general usage. It has been used in pages in the Alipay App like 618 Activity, Voucher, Ant Forest, etc.

Mako has two config for RSC:

You can find a simple example in the examples/rsc.

Notice: RSC is complex and RSC support in Mako is experimental, and it’s not suggested to use it in your project unless you know what you are doing.

Umi Integration

Umi is a popular React framework. Mako is designed to be compatible with Umi, and you can use Mako as the bundler in Umi 4 by just setting the mako field in the config.

{
+   mako: {},
}

Checkout Bundle with Umi for more details.

Libraries

Suggest use father, which is used to bundle libraries based on Mako.

Edit this page on GitHub