father-build (UmiJS Father)
Father-build is the primary library build tool within the UmiJS ecosystem, often referred to simply as 'Father'. Currently stable at version 4.6.17, it's a powerful and highly configurable solution for packaging JavaScript and TypeScript libraries. It leverages Rollup for robust bundling and integrates esbuild for performance optimizations across various output formats, including ESM, CJS, UMD, and a 'bundless' mode for individual file compilation. The project maintains a very active development pace, frequently issuing multiple minor and patch updates each month, incorporating new features like CSS extraction, enhanced JSX runtime support, and parallel bundless compilation. Key differentiators include comprehensive TypeScript support (shipping its own types and regularly upgrading internal TS versions), flexible configuration via `father.config.ts` using `defineConfig`, and a strong focus on delivering optimized output for diverse JavaScript environments. It aims to streamline library development by abstracting complex build configurations and providing a consistent developer experience.
Common errors
-
Error: Cannot find module 'babel-plugin-dynamic-import-node'
cause Configuration for an older version of father-build (pre-4.5.1) attempting to use a deprecated Babel plugin for dynamic imports.fixRemove `babel-plugin-dynamic-import-node` from your Babel configuration. Father v4.5.1+ handles dynamic imports via its internal `asyncChunks` mechanism. -
TypeError: (0, import_ajv.default) is not a constructor (or similar 'ajv' related error when using Bun)
cause Compatibility issues between Bun and the `ajv` dependency, often related to module resolution or package structure differences.fixTry `npm install` or `yarn install` instead of `bun install`. Ensure your `father` and `ajv` versions are the latest to pick up any compatibility fixes. -
ReferenceError: Buffer is not defined (or other Node.js global/polyfill errors in UMD bundles on Node.js)
cause UMD bundles targeting the 'node' platform no longer automatically include Node.js polyfills since father v4.6.11, leading to missing global objects or functions.fixFor UMD bundles used in Node.js, explicitly add necessary polyfills to your project or adjust your build target if these polyfills are critical for your library's runtime.
Warnings
- breaking Upgrading from `father` v3 to v4 involves a complete rewrite of the build tool, requiring significant refactoring of existing configurations. The configuration schema, API, and underlying build mechanisms have been revamped for improved performance and simplicity.
- breaking Starting from `father` v4.5.1, the internal mechanism for handling dynamic imports shifted from `babel-plugin-dynamic-import-node` to an `asyncChunks` approach. Projects explicitly relying on or configuring the old Babel plugin for dynamic imports will experience build failures.
- gotcha UMD bundles generated with `father` v4.6.11 and later, specifically targeting the 'node' platform, no longer include polyfills from `node-polyfill-provider`. This change can lead to runtime errors in Node.js environments if the application expects certain browser-like polyfills to be present.
- gotcha When using `Bun` as a package manager, users might encounter unexpected compatibility issues with the `ajv` package during installation or build processes. A workaround was introduced in v4.5.5, but environmental factors can still cause problems.
- gotcha The internal TypeScript version used by `father` was upgraded to 5.4.2 in v4.5.3. While this is a feature, projects with older or very specific TypeScript setups might face implicit compatibility issues if their own TypeScript version is not compatible with the one `father` uses internally for type processing.
Install
-
npm install father-build -
yarn add father-build -
pnpm add father-build
Imports
- defineConfig
const { defineConfig } = require('father');import { defineConfig } from 'father'; - father CLI
node_modules/.bin/father-build build
npx father build
Quickstart
// package.json
{
"name": "my-library",
"version": "1.0.0",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "father build"
},
"devDependencies": {
"father": "^4.6.17",
"typescript": "^5.0.0"
}
}
// father.config.ts
import { defineConfig } from 'father';
export default defineConfig({
// Target Node.js v14+ environments
targets: {
node: '14',
},
// Configure ESM build (for modern environments)
esm: {
output: 'dist/esm', // Output directory for ESM
platform: 'browser', // For browser-compatible ESM
// Optional: add aliases
alias: {
'@/utils': './src/utils',
},
},
// Configure CommonJS build (for Node.js)
cjs: {
output: 'dist/cjs', // Output directory for CJS
platform: 'node', // For Node.js CommonJS
},
// Configure UMD build (for browser globals)
umd: {
output: 'dist/umd', // Output directory for UMD
name: 'MyLibrary', // Global variable name
// Optional: define external globals
globals: {
react: 'React',
'react-dom': 'ReactDOM',
},
},
// Configure Bundless build (individual file compilation)
bundless: {
output: 'dist/lib', // Output directory for bundless
},
// Enable TypeScript declaration generation automatically
// extraBabelPlugins: [], // Uncomment and add if you need custom Babel plugins
// entry: 'src/index.ts', // Father can auto-detect entries, specify if needed
});
// src/index.ts
export function greet(name: string): string {
return `Hello, ${name}! Welcome to my library.`;
}
export function add(a: number, b: number): number {
return a + b;
}
// Example of an exported type definition
export type User = {
id: string;
name: string;
};
// Example function (could be framework-dependent in a real library)
export function createUser(id: string, name: string): User {
console.log(`Creating user with id: ${id} and name: ${name}`);
return { id, name };
}