April 05, 2020
component librariesWhen you’re working on a component library for your organization, you want your teammates to contribute. If your teammates aren’t contributing to your efforts, it could mean a couple of different things.
As an individual contributor, you might not be able to solve problems #1 and #3, but you can make it easier to contribute to your library by providing developers with tools to get up and running more quickly. By simplifying the process, you’re also positively impacting problems #1 and #3 indirectly.
An example is package creation. Every single person who adds a component to your library needs to create a new package.
When using TypeScript, a contributor needs to set up a package.json
, tsconfig.json
, and a README.md
that matches the conventions you have in your project. This can be time-consuming, depending on how familiar the contributor is with the library. It’s also something that you can automate in an afternoon. It’s a high-value, low-effort win.
You should start by creating an example package that can serve as a guide for people new to the repo. It’ll probably have a package.json
with some commonly used scripts, and a tsconfig.json
file with common defaults set.
You can take a look at what an example package might look like here.
Once you have an example package, you can write a script to allow developers to generate a new package from the command line.
I wrote a script like this that almost every contributor to my organization’s component library has used. You can use this script as an example to write one that works with your library’s filesystem.
const fs = require('fs'); | |
const path = require('path'); | |
const inquirer = require('inquirer'); | |
const { exec } = require('child_process'); | |
// Pull the arguments off of the command | |
let args = process.argv.slice(2); | |
// Write your own custom questions that the script will ask | |
const cliQuestions = [ | |
{ | |
type: 'input', | |
name: 'description', | |
message: 'What should the package.json description be?', | |
}, | |
{ | |
type: 'input', | |
name: 'version', | |
message: 'What should the package.json version be?', | |
}, | |
]; | |
// Find the path in the `/packages` directory where the package | |
// is going to live | |
const getPathToFile = packagesDir => { | |
return fs | |
.readdirSync(packagesDir) | |
.map(filename => path.join(packagesDir, filename)) | |
.filter(filePath => filePath.includes('package.json'))[0]; | |
}; | |
// Update the example package's package.json file with the | |
// user's responses to the cliQuestions | |
const editPackageJson = packageName => { | |
inquirer.prompt(cliQuestions).then(answers => { | |
const packagesDir = path.resolve(`./packages/${packageName}`); | |
const content = { | |
name: `@maecapozzi/${packageName}`, | |
description: answers.description, | |
version: answers.version, | |
}; | |
const pathToFile = getPathToFile(packagesDir); | |
const file = require(pathToFile); | |
const editedFile = JSON.stringify( | |
Object.assign(file, { | |
...content, | |
}) | |
); | |
return fs.writeFileSync(pathToFile, editedFile, err => { | |
if (err) { | |
console.error(err); | |
return; | |
} | |
console.log('You successfully update the package.json file.'); | |
}); | |
}); | |
}; | |
const execute = packageName => { | |
if (packageName[0] === undefined) { | |
throw Error('Please provide a package name'); | |
} | |
if (packageName.length > 1) { | |
throw Error('Please only provide a single package name'); | |
} | |
if (fs.existsSync(`./packages/${packageName[0]}`)) { | |
throw Error('Please provide a package name that does not already exist'); | |
} | |
// copy the example package to the new path | |
exec( | |
`cp -r ./examples/example-package ./packages/${packageName}`, | |
(err, stdout, stderr) => { | |
if (err) { | |
throw err; | |
} | |
console.log(stdout); | |
console.log(stderr); | |
console.log(`${packageName} has been successfully created`); | |
editPackageJson(packageName); | |
} | |
); | |
}; | |
execute(args); |
When the script is run, the output looks something like this:
$ yarn generate-package new-package
yarn run v1.19.1
$ babel-node scripts/generatePackage.js new-package
new-package has been successfully created
? What should the package.json description be? New package description
? What should the package.json version be? 1.0.0
✨ Done in 13.32s.
If you liked this post, please consider sharing it!
Sign up for the Design Systems Newsletter today!