I am building a yeoman generator for a fairly typical node app:
/ |--package.json |--.gitignore |--.travis.yml |--README.md |--app/ |--index.js |--models |--views |--controllers
In the templates folder of my yeoman generator, I have to rename the dotfiles (and the package.json) to prevent them from being processed as part of the generator:
templates/ |--_package.json |--_gitignore |--_travis.yml |--README.md |--app/ |--index.js |--models |--views |--controllers
I see a lot of generators that copy dotfiles individually manually:
this.copy('_package.json', 'package.json') this.copy('_gitignore', '.gitignore') this.copy('_gitattributes', '.gitattributes')
I think it's a pain to manually change my generator code when I add new template files. I would like to automatically copy all files in the /templates folder, and rename the ones that are prefixed with _.
What's the best way to do this?
If I were to describe my intention in imaginary regex, this is what it would look like:
this.copy(/^_(.*)/, '.$1') ths.copy(/^[^_]/)
EDIT This is the best I can manage:
this.expandFiles('**', { cwd: this.sourceRoot() }).map(function() { this.copy file, file.replace(/^_/, '.') }, this);
Yeoman is very careful when it comes to overwriting users files. Basically, every write happening on a pre-existing file will go through a conflict resolution process. This process requires that the user validate every file write that overwrites content to its file. This behaviour prevents bad surprises and limits the risk of errors.
Yeoman calls this internally after the conflicts stage of the run loop. Here’s an example where we’d want to copy and process a template file. We’ll then use the copyTpl method to copy the file while processing the content as a template. copyTpl is using ejs template syntax.
You can basically use any gulp plugins with the Yeoman transform stream to process generated files during the writing phase. Updating a pre-existing file is not always a simple task. The most reliable way to do so is to parse the file AST ( abstract syntax tree) and edit it.
As asynchronous APIs are harder to use, Yeoman provide a synchronous file-system API where every file gets written to an in-memory file system and are only written to disk once when Yeoman is done running. This memory file system is shared between all composed generators.
I found this question through Google as I was looking for the solution, and then I figured it out myself.
Using the new fs
API, you can use globs!
// Copy all non-dotfiles this.fs.copy( this.templatePath('static/**/*'), this.destinationRoot() ); // Copy all dotfiles this.fs.copy( this.templatePath('static/.*'), this.destinationRoot() );
Adding to @callumacrae 's answer: you can also define dot: true
in the globOptions
of copy()
. That way a /**
glob will include dotfiles. Example:
this.fs.copy( this.templatePath('files/**'), this.destinationPath('client'), { globOptions: { dot: true } } );
A list of available Glob options can be found in the README of node-glob
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With