rename templates folders with a gruntjs custom init task - javascript

I'm trying to create a custom init task for a personal template in Grunt.
This is the js which generate my new project after a grunt init:mytemplate
exports.description = 'Try Grunt';
exports.warnOn = '*';
exports.template = function(grunt, init, done) {
grunt.helper('prompt', {type: 'skin'}, [
grunt.helper('prompt_for', 'name', 'trygrunt'),
grunt.helper('prompt_for', 'title', 'Im Trying GruntJS'),
grunt.helper('prompt_for', 'author_name', 'Myself')
],
function(err, props) {
var files = init.filesToCopy(props);
init.copyAndProcess(files, props);
done();
});
};
Everything works fine: files and folder are correctly generated or renamed from the root folder of the custom template based on rename.json info.
The question is: how can i also dynamically rename folders and not only files?
i.e.
{
"libs/name.js": "libs/{%= name %}.js" //this works fine
"src/name": "src/{%= name %}" //this doesn't work
}

The init.filesToCopy method only looks at renames.json for specific file (not directory) matches when it first builds the files object. Your best bet is to programmatically modify the files object between init.filesToCopy and init.copyAndProcess.

This is possible by modifying the result of the init.filesToCopy object. However you need to modify the key rather than the value of each pair.
For example, I have a folder called lib/ that I wish to copy the contents into app/
var files = init.filesToCopy(props),
libFolder = 'app';
// Repath the files correctly
for (var file in files) {
if (file.indexOf('lib/') > -1) {
var path = files[file],
newFile = file.replace('lib/', libFolder + '/');
files[newFile] = path;
delete files[file];
}
}
init.copyAndProcess(files, props);
It's also worth noting that rename.json works on the lib/ value not the new folder.
One thing that I've done is to use the props.main value to extract the libFolder value (e.g. libFolder = props.main.split('/')[0])

Another way to accomplish this and get around the limitation of not being able to rename folders, is to 1) setup a grunt-contrib-copy task to copy the folders and files and apply whatever names you require to the new folders/files, and then 2) have a grunt-contrib-clean task clean out the old files/folders resulting in the same net effect as renaming the folders.

Related

Is there any way to get a list of files in a directory into a variable when using webpack?

When creating a browser app, there doesn't seem to be any way to get a list of files in a particular location using javascript. In Nodejs this is easily done using fs.
Basically I have a directory called images/, and I want to manipulate a list of all the files as a javascript variable without having to manually create the list of files. I thought that since webpack bundles all of the files that there might be some way to generate the list as a JSON file (or an alternative) which could be read in with javascript -- though I haven't found any way to do that yet.
What is the best way to do this?
I was able to solve this by creating a plugin:
src/plugins/FileLister.js:
const fs = require('fs');
class FileLister {
constructor(options) {
if (!options || !options.path || !options.outputFile) {
const msg = "Please specify the path and outputFile options.";
throw new Error(msg);
}
this.options = options
}
apply(compiler) {
compiler.hooks.done.tap({name: 'FileLister'}, () => {
const files = fs.readdirSync(this.options.path)
fs.writeFileSync(this.options.outputFile, JSON.stringify(files));
})
}
}
module.exports = FileLister;
Then in my webpackage.config.js:
import:
const FileLister = require('./src/plugins/FileLister.js')
plugins section:
new FileeLister({
path: path.resolve(__dirname, 'src/important_files/'),
outputFile: path.resolve(__dirname, 'dist/important_files.json')
}),
This creates a file called important_files.json in the dist directory containing a list of the files in src/important_files/.

Gulp replace not renaming files but does replace file contents

I have the following gulp task which I want to change the filename and contents of a file replacing any matching strings with the replacement.
The matching strings in the file contents get changed, but the file's name does not. I thought it would as my code appears to match the examples on https://www.npmjs.com/package/gulp-replace
What am I doing wrong?
function renameFileContents() {
return gulp.src([
'**/*',
'!.github/**',
'!languages/**',
'!node_modules/**',
'!.babelrc',
'!.editconfig',
'!.gitignore',
'!.travis.yml',
'!CHANGELOG.md',
'!codesniffer.ruleset.xml',
'!composer.json',
'!composer.lock',
'!config.yml',
'!config-default.yml',
'!gulpfile.babel.js',
'!MIT-LICENSE.txt',
'!package-lock.json',
'!package.json',
'!phpunit.xml.dist',
'!README.md',
'!webpack.config.js'
])
.pipe($.replace('BigTest', 'Tester'))
.pipe($.replace('Bigtest', 'Tester'))
.pipe($.replace('bigtest', 'tester'))
.pipe(gulp.dest('./'));
}
Use gulp-rename to alter filenames. Add:
const rename = require('gulp-rename');
and before .pipe(gulp.dest('./'));:
.pipe(
rename(function(path) {
path.basename = path.basename.replace(/BigTest|Bigtest|bigtest/, function(matched) {
return { BigTest: 'Tester', Bigtest: 'Tester', bigtest: 'tester' }[matched];
});
})
)
You asked in a comment why new files are created (with the new names) but the original files still remain. Why does gulp-rename not actually rename the original files as you might expect?
Gulp-rename is not working with the original files. This can be a little confusing.
It's called gulp-rename because it renames an in-memory gulp file
object. gulp is like functional programming, each plugin takes in
input and produces output in-memory without causing side effects. [emphasis added]
gulp works like this:
read file (gulp.src)
do some stuff, modify the file in-memory (plugins)
commit file changes back to fs (gulp.dest/or others)
From gulp-rename issues: not renaming the original files.
The suggested fix (from gulp recipes: deleting files from a pipeline) which I tested is:
const del = require('del');
const vinylPaths = require('vinyl-paths');
and add this pipe before the replace pipe:
.pipe(vinylPaths(del))
.pipe(
rename(function(path) { ......
and your original files will be deleted, leaving only the newly named files. Obviously, make sure you test this on good test cases before deleting any of your files!

grunt configure settings file dynamically

I have two files that get loaded, shown below. I want to dynamically load the settings file by name in properties.js. I want to replace <%= settings["build.target.environment"] %> with the value from the environment build option. Whenever i try to replace the value i get a compilation error in grunt. Basically, cant load tasks, X task isnt found because no tasks loaded properly. I have an alias called init that runs both of these items in order. How can i get the build option into the properties file so i can dynamically load the config i want to load. or is there another option? It seems like my build option wouldnt be picked up at the time these files load.
please bear with me and any ignorances with grunt, relatively new to grunt.
properties.js:
module.exports = {
settings: 'config/build.properties',
instance: 'config/environment.<%= settings["build.target.environment"] %>.properties'
}
buildoptions.js:
module.exports = function(grunt) {
grunt.registerTask('buildoptions', 'set build version and repo branch', function() {
var build = grunt.option("build");
var branch = grunt.option("branch") || '';
var environment = grunt.option("environment");
grunt.config('build', build);
grunt.config('branch', branch);
grunt.config('environment', environment)
});
};
aliases.json:
"init": [
"buildoptions",
"properties"
]
You don't need to set local variables to access grunt.option values within template strings, instead reference it directly:
module.exports = {
settings: 'config/build.properties',
instance: "config/environment.<%= grunt.option('environment') %>.properties"
}

Why Gulp does not keep file names returned from dest function?

I have the following file paths:
resources/assets/css/site1/app.css
resources/assets/css/site2/app.css
resources/assets/css/common/common.css
and I would like them to be copied to public folder without keeping my nested folder structure. Obviously, I need to modify target file names because I have two app.css here. So, I decided to take the last folder of the path as a prefix for filename (and also add -dev postfix because these files are only for development mode and will be deleted when building final release with elixir minification). As the result I should get:
public/css/site1-app-dev.css
public/css/site2-app-dev.css
public/css/common-common-dev.css
Now I have the following gulp code:
gulp.src("resources/assets/css/**/*.css")
.pipe(gulp.dest(
function(file) {
var newPath = "public/css/" +
// folder name, like admin or public
path.basename(path.dirname(file.path)) + "-" +
path.basename(file.path, ".css") + "-dev.css";
console.log(newPath);
return newPath;
}));
I see that console outputs the result as expected. But at the end I get the following files:
public/css/site1-app-dev.css/site1/app.css
public/css/site2-app-dev.css/site2/app.css
public/css/common-common-dev.css/common/common.css
Obviously, gulp treats newPath as a folder name to use when copying the files matching **/*.css and preserving the folder hierarchy.
Is there any way to tell gulp that I actually want it to treat newPath as the final destination filename and not as a directory?
Use gulp-rename to add suffix on file names, the base is specified to keep the nested folder structure.
var rename = require('gulp-rename');
gulp.src("resources/assets/css/**/*.css", {base: 'resources/assets/css/'})
.pipe(rename({ suffix: "-dev", }))
.pipe(gulp.dest("public/css/"));
https://www.npmjs.com/package/gulp-rename

Using Gulp to create angular $templateCache per module/directory

So, I'm moving from grunt to gulp (or trying to anyway), and I'm having trouble getting gulp to do what I'm doing in grunt. Specifically the $templateCache stuff.
My angular app is broken up into several components/modules. Each module contains everything it needs to run (controllers, directives, partials, scss, etc.).
Using Grunt, I've been able to boil each module down into 5 files:
module.min.css // all module scss files compiled and concatenated
module.min.js // all module controllers, directives, services, etc. concatenated
module.tpls.min.js // all partials in $templateCache for this module
module.mocks.min.js // all unit test mock objects for this module
module.specs.min.js // all unit test specs for this module
This has worked really well for 2 years now and been a cornerstone of my modular architecture. My only reasons to try out gulp was 1) Curiosity, 2) My grunt file is getting kinda hairy as we add in deployment and environment specific stuff and so far gulp has really slimmed that down.
For the most part, I've figured out how to do all my grunt tasks in gulp, but I'm having trouble figuring out how to generate a template cache file for each module. All the gulp-ng|angular-templates|templatecache plugins take all my partials and create one file. I'd like to take all my files under module/partials/*.html and create a single module.tpls.min.js; and do that for each module.
This was actually a problem with grunt too, but I figured it out with grunt.file.expand().forEach() like this:
grunt.registerTask('prepModules', '...', function(){
// loop through our modules directory and create subtasks
// for each module, modifying tasks that affect modules.
grunt.file.expand("src/js/modules/*").forEach(function (dir) {
// get the module name by looking at the directory we're in
var mName = dir.substr(dir.lastIndexOf('/') + 1);
// add ngtemplate subtasks for each module, turning
// all module partials into $templateCache objects
ngtemplates[mName] = {
module: mName,
src: dir + "/partials/**/*.html",
dest: 'dev/modules/' + mName + '/' + mName + '.tpls.min.js'
};
grunt.config.set('ngtemplates', ngtemplates);
});
});
My current gulp for this same task:
var compileTemplates = gulp.src('./src/js/modules/**/partials/*.html', {base:'.'})
.pipe(ngTemplates())
.pipe(gulp.dest('.'));
I've only really looked at the options, but none of them seemed to do what I wanted. They were all around changing the file name, or the final destination of the file, or a module name, or whatever else; nothing that said anything about doing it for only the directory it happens to be in.
I had thought about using gulp-rename because it worked well for me when doing the CSS compilation:
var compileScss = gulp.src('./src/js/modules/**/scss/*.scss', {base:'.'})
.pipe(sass({includePaths: ['./src/scss']}))
.pipe(rename(function(path){
path.dirname = path.dirname.replace(/scss/,'css');
}))
.pipe(gulp.dest('.'));
However, when I pipe rename() after doing ngTemplates() it only has the path of the final output file (one log entry). When you console.log() path after sass(), it has all the paths of all the files that it found (lots of log entries).
Any ideas? Thanks!
This SO post has the correct answer, but the wasn't coming up in my searches for this specific usage. I was going to vote to close my question, but since someone else might search using my own specific terms (since I did), it seems more appropriate to leave it alone and just redirect to the original question as well as show how I solved my own particular problem.
var fs = require('fs');
var ngTemplates = require('gulp-ng-templates');
var rename = require('gulp-rename');
var modulesDir = './src/js/modules/';
var getModules = function(dir){
return fs.readdirSync(dir)
.filter(function(file){
return fs.statSync(path.join(dir, file)).isDirectory();
});
};
gulp.task('default', function(){
var modules = getModules(modulesDir);
var moduleTasks = modules.map(function(folder){
// get all partials for this module
// parse into $templateCache file
// rename to be /dev/modules/_____/______.tpls.min.js
return gulp.src(modulesDir + folder + '/partials/*.html', {basedir:'.'})
.pipe(ngTemplates({module:folder}))
.pipe(rename(function(path){
path.dirname = './dev/apps/' + folder + '/';
path.basename = folder + '.tpls.min';
}))
.pipe(gulp.dest('.'));
});
});
It's essentially like the tasks per folder recipe but with a change to use gulp-ng-templates. I'll probably be using this same pattern for my SCSS and JS now that I'm more aware of it.
Seems like the gulp equivalent of grunt.file.expand().forEach().
Whenever I deal with scss/sass for gulp tasks, I will only put one scss file as the source parameter. This parameter file is composed of a list of imports. This way you don't need to rely on gulp to concat the scss file contents for you.
//in gulpfile
gulp.src('./src/js/modules/**/scss/main.scss', {base:'.'})
//in main.scss
#import 'a', 'b', 'c';
a, b, and c would represent your other scss files.

Categories

Resources