Including Hidden Files and Directories in Turborepo Generator Actions
January 25, 2025 | 2 minutesIf you're using Turborepo to manage your Javascript/Typescript packages, the custom generator feature is an excellent way to quickly create a new package in the monorepo with specific defaults. With a custom generator, you can
- copy files as-is from an existing package to a new one,
- create custom templates for files that you want to customize,
- run
npm install
directly after copying files, - update documentation links to point to the new site,
and anything else that you can script with Javascript.
Turborepo uses Plop.js as its generator framework. This framework offers a standard set of actions for generating packages. The actions support adding files to the new package and rely on glob patterns to identify the files to manipulate.
If you're unfamiliar with glob patterns, they use a string of literal and wildcard characters to match filepaths. For example, the glob pattern template/**/*
would match all files and directories within the template
directory, including nested subdirectories at any depth. Malik Brown has a good beginner's guide to glob patterns if you'd like more information.
On the surface, it seems like the glob pattern above would be enough to copy all package files from a template
directory to a new package. Hidden files and directories (those that start with .
) present a complication, though. In modern Javascript/Typescript packages, it's common to have configuration files and directories that start with a .
such as .nvmrc
, .npmignore
, and .storybook/
, but glob patterns usually don't include hidden files and directories by default. When generating a new package, we'd like to include these files as well, so what do we do?
Plop.js' AddMany action offers a globOptions
parameter that can be used to tell it to include hidden files and directories. Plop.js passes this value on to the package it uses to interpret glob patterns. To use it, set globOptions
as an object with the key/value pair { dot: true }
. Here's an example of how to use it in a Turborepo generator action:
1export default function generator(plop: PlopTypes.NodePlopAPI): void {
2 // create a generator
3 plop.setGenerator("Generator name", {
4 description: "Generator description",
5 // gather information from the user
6 prompts: [
7 ...
8 ],
9 // perform actions based on the prompts
10 actions: [
11 {
12 type: "addMany",
13 // Where to copy the resulting files
14 destination: 'packages/{{kebabCase name}}',
15
16 // The base directory containing your template files
17 base: 'templates/component',
18
19 // Glob pattern for the template files
20 templateFiles: 'templates/component/**',
21
22 // This enables matching dotfiles (e.g. .gitignore, .eslintrc, etc.)
23 globOptions: {
24 dot: true,
25 },
26 },
27 ],
28 });
29}