In this article, we review how Father, an NPM package development tool is installs npm dependencies programmatically.
How did I find this code snippet?
I wrote an article about Father and in its README.md, I found that it supports micro generators that adds commonly used engineering capabilities to projects, such as setting up Jest for testing. This is similar to the CLI tool I am building, to generate code for authentication or S3 upload in Next.js.
I started searching for the micro generators code and found a folder named commands/generators.
Common pattern in the generators
You will see that there is a common pattern in the way these generators are defined.
generators/eslint.ts
eslint.ts has the below code
import { GeneratorType } from '@umijs/core';
import { logger } from '../../utils';
import fg from 'fast-glob';
import { writeFileSync } from 'fs';
import { join } from 'path';
import { IApi } from '../../types';
import { GeneratorHelper } from './utils';
export default (api: IApi) => {
api.describe({
key: 'generator:eslint',
});
api.registerGenerator({
key: 'eslint',
name: 'Enable ESLint',
description: 'Setup ESLint Configuration',
type: GeneratorType.enable,
checkEnable: () => {
...
},
disabledDescription:
'ESLint has already enabled. You can remove .eslintrc, then run this again to re-setup.',
fn: async () => {
....
},
});
};
generators/jest.ts
jest.ts has the below definition:
import { GeneratorType } from '@umijs/core';
import { logger } from '../../utils';
import { existsSync, writeFileSync } from 'fs';
import { join } from 'path';
import { IApi } from '../../types';
import { GeneratorHelper, promptsExitWhenCancel } from './utils';
export default (api: IApi) => {
api.describe({
key: 'generator:jest',
});
api.registerGenerator({
key: 'jest',
name: 'Enable Jest',
description: 'Setup Jest Configuration',
type: GeneratorType.enable,
checkEnable: () => {
...
},
disabledDescription:
'Jest has already enabled. You can remove jest.config.{ts,js}, then run this again to re-setup.',
fn: async () => {
...
},
});
};
Do you see the common pattern in these two definitions above? there is
- api.describe
This accepts an object that has the below properties:
- key
- api.registerGenerator
This accepts an object that has the below properties:
key
name
description
type
checkEnable
disabledDescription
fn
h.installDeps()
At line 97 in generators/jest.ts, you find this below code snippet
h.installDeps();
What is h here? At line 27, you will see h is initialized as shown below:
const h = new GeneratorHelper(api);
To see how the installDeps is defined, we need to review GeneratorHelper
GeneratorHelper
GeneratorHelper has the below shown functions at the time of writing this article
import { getNpmClient, installWithNpmClient, prompts } from '@umijs/utils';
import { writeFileSync } from 'fs';
import { IApi } from '../../types';
import { logger } from '../../utils';
export class GeneratorHelper {
constructor(readonly api: IApi) {}
addDevDeps(deps: Record<string, string>) {
...
}
addScript(name: string, cmd: string) {
...
}
private addScriptToPkg(name: string, cmd: string) {
...
}
installDeps() {
...
}
}
installDeps
installDeps is defined as shown below in GeneratorHelper.
installDeps() {
const { api } = this;
const npmClient = getNpmClient({ cwd: api.cwd });
installWithNpmClient({
npmClient,
});
logger.quietExpect.info(`Install dependencies with ${npmClient}`);
}
There are two functions that we need to learn about to understand how Father installs npm deps programmatically.
getNpmClient
installWithNpmClient
This will be discussed in part 2, i.e., in the next article.
About me:
Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.
I am open to work on interesting projects. Send me an email at ramu.narasinga@gmail.com
My Github — https://github.com/ramu-narasinga
My website — https://ramunarasinga.com
My Youtube channel — https://www.youtube.com/@thinkthroo
Learning platform — https://thinkthroo.com
Codebase Architecture — https://app.thinkthroo.com/architecture
Best practices — https://app.thinkthroo.com/best-practices
Production-grade projects — https://app.thinkthroo.com/production-grade-projects
Top comments (0)