The code generator that depends on specific files is designed to implement a Single Source of Truth (SSOT).
In some case, you may need to maintain a file content that has symbols that depend on specific files. For example, to load all component files, declare their paths in the entry point file:
@forward "components/button";
@forward "components/card";
@forward "components/disclosure";
// ...However, it is a waste of time to manually change the content each time these files are added or removed.
Instead, you can automate this task by using drygen. First, create the following configuration file named drygen.config.js:
module.exports = {
rules: [
{
name: "components import",
dependencies: ["components/**/*.scss"],
outputs: [
{
path: "_components.scss",
template: "import.scss.ejs",
},
],
},
],
};Then create an EJS template file named import.scss.ejs to render the file content:
<% dependencies.forEach((dep) => { -%>
@forward "<%- join(relative(dep.dir), dep.name.replace(/^_/, "")) %>";
<% }); -%>The variables are exposed in the templates:
dependencies: an array ofDependencyFile. It contains a file path, contents, etcrelative: returns a relative path from the output filejoin: a reference to POSIX specificationpath.join()
Finally, run the command:
$ drygenThe following file will be generated:
@forward "components/button";
@forward "components/card";
@forward "components/disclosure";If you want to write the file every time the dependency files are changed, you can add the --watch flag:
$ drygen --watchIf you want to see more usage examples, please refer to the examples directory.
$ npm install --save-dev drygen$ drygen --help
Options:
--help Show help [boolean]
--version Show version number [boolean]
--root a path to project root [string]
-c, --config a path to configuration file [string]
-w, --watch watch file changes [boolean]Before running drygen, you need to create a configuration file named drygen.config.js or drygen.config.cjs inside project root.
module.exports = {
rules: [
{
name: "components import",
dependencies: ["components/**/*.scss"],
outputs: [
{
path: "_components.scss",
template: "import.scss.ejs",
},
],
},
],
};Since drygen ships with TypeScript typings, you can leverage your IDE’s IntelliSense with jsdoc type hints:
/**
* @type {import("drygen").UserConfig}
*/
module.exports = {
rules: [
{
name: "components import",
dependencies: ["components/**/*.scss"],
outputs: [
{
path: "_components.scss",
template: "import.scss.ejs",
},
],
},
],
};Type: object[]
Define an array of the rules for file generation.
Type: string
Will be output as logs in your terminal, and can be referenced from the templates.
Type: string[] | Record<keyof any, string[]>
A list of glob matcher patterns. See supported minimatch patterns.
If you specify an array, dependencies variable exposed to the templates will be an array:
{
// ...
dependencies: ["components/**/*.scss"],
}<% dependencies.forEach((dep) => { -%>
@forward "<%- relative(dep.path) %>";
<% }); -%>If you specify an object of arrays, dependencies variable exposed to the templates will be an object:
{
// ...
dependencies: {
objects: ["objects/**/*.scss"],
components: ["components/**/*.scss"],
},
}<% dependencies.objects.forEach((dep) => { -%>
@use "<%- relative(dep.path); %>";
<% }); -%>
<% dependencies.components.forEach((dep) => { -%>
@use "<%- relative(dep.path); %>";
<% }); -%>Type: ({ path: string, template: string, context?: {} } | ({ name, dependencies }: { name: string, dependencies: DependencyFile[] | Record<keyof any, DependencyFile[]> }) => Promise<{ path: string, template: string, context?: {} } | { path: string, template: string, context?: {} }[]>)[]
An array of the entries for the output file. In most cases, you would specify it as an object:
{
// ...
outputs: [
{
path: "_component.scss",
template: "import.scss.ejs",
context: { greet: "Hi" }, // optional
},
],
}path: a path to the output filetemplate: a path to the EJS template file, see templating section for detailscontext: an optional object passed to the templates file, can be referenced bycontextvariable
If the entry needs to be based on dependencies, you can specify a function instead:
{
// ...
outputs: [
({ name, dependencies }) => {
const json = JSON.parse(dependencies[0].content);
return {
path: "output.scss",
template: "output.scss.ejs",
context: json,
};
},
],
}name: a name of the ruledependencies: a list ofDependencyFile
And it can return an array:
{
// ...
outputs: [
({ name, dependencies }) => {
const json = JSON.parse(dependencies[0].content);
return [
{
path: "shared.scss",
template: "shared.scss.ejs",
context: json,
},
{
path: "shared.js",
template: "shared.js.ejs",
context: json,
},
]
},
],
}Or it needs to call async function, you can specify a async function instead:
{
// ...
outputs: [
async ({ name, dependencies }) => {
const inputJSON = JSON.parse(dependencies[0].content)
const data = await asyncProcess(inputJSON);
return {
path: "output.scss",
template: "output.scss.ejs",
context: data,
};
},
],
}drygen uses EJS as a template engine.
The following variables are exposed in the templates.
Type: string
The value passed to rules[].name.
Type: DependencyFile[] | Record<keyof any, DependencyFile[]>
A list of DependencyFile. The type will be based on the value passed to rules[].dependencies.
type DependencyFile = {
path: string;
dir: string;
root: string;
base: string;
name: string;
ext: string;
content: Buffer;
stats: fs.Stats;
};path: an absolute path to the filedir:dirproperty of the return value ofpath.parse()root:rootproperty of the return value ofpath.parse()base:baseproperty of the return value ofpath.parse()name:nameproperty of the return value ofpath.parse()ext:extproperty of the return value ofpath.parse()content: contents of the filestats:fs.Statsobject provides information about the file
Type: Record<keyof any, any>
The value passed to rules[].outputs[].context.
Type: (...paths: string[]) => string
A reference to POSIX specification path.join().
Type: (to: string) => string
Returns a relative path from the output file.
Type: (path: string, extension: string) => string
Replaces the file extension with another one. The wrapper for replace-ext module.
The core modules of Change Case and titleCase are also available.