Using a flag for a specific folder in Grunt to build from - gruntjs

I would like to now if there is a way to load certain files from a certain folder when running Grunt.
Let's say I have a folder structure that looks like this:
[html]
[css]
[js]
[custom]
[X] x.css
[Y] y.css
[Z] z.css
I'm trying to build my website for client [X] and need to add some custom css to their x.css file and just load that one to test.
What I would love to be able to do is run my grunt task (right now it runs sass, jsx compiler and spins up a localhost server with livereload) and say grunt client-x.
Which then would load my x.css file and all content of that folder but not use touch the [Y] and [Z] folder at all.
Is this possible with a task runner?

So I looked at Grunt dynamic dest location sass which seemed to solve my problem initially but I couldn't really get it to work the way I wanted to and it muddled up my existing grunt tasks I had already set up.
But then I found grunt options - this parameter solved all my problems. Grunt file below:
module.exports = function(grunt) {
var theme = grunt.option('theme')
grunt.initConfig({
concat: {
options: {
separator: 'rn'
},
dist: {
files: {
'js/script.js': 'themes/' + theme + '/js/custom.js'
}
}
},
watch: {
sass: {
files: ['themes/' + theme + '/**/*.{scss,sass}', 'themes/' + theme + '/_partials/**/*.{scss,sass}', 'sass/**/*.{scss,sass}', 'sass/_partials/**/*.{scss,sass}', 'themes/' + theme + '/js/custom.js'],
tasks: ['sass:dist', 'shell:upload', 'concat:dist'],
options: {
livereload: true,
},
},
livereload: {
files: ['*.vm', 'js/*.{js,json}', 'css/*.css','images/*.{png,jpg,jpeg,gif,webp,svg}', 'themes/' + theme + '/js/custom.js'],
options: {
livereload: true,
debounceDelay: 2000
}
}
},
sass: {
options: {
sourceMap: true,
outputStyle: 'nested'
},
dist: {
files: {
'css/lyria.css': 'themes/' + theme + '/styles.scss'
}
}
},
shell: {
options: {
stdout: true,
stderr: true
},
upload: {
command: './theme-uploader.sh'
}
},
})
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-shell');
grunt.registerTask('default', [
'sass:dist',
'concat',
'shell:upload',
'watch'
]);
};
As you can see the theme parameter is used as a argument for the grunt default task which then compiles the correct files to the correct place. When I run grunt --theme=x it watches and compiles the corresponding folders in that specific directory as set up by my different tasks.
The reason for this setup is that I'm developing and maintaining different child themes for different clients in the same repository. I need to be able to generate a client specific jar with their corresponding stylesheets and custom js.
This way I get to keep all my directories in the same repo and just specify when running my grunt task which client folder to get the css from.

Related

How do I generate sourcemaps for Uglified files using Grunt?

I have a Grunt project that uses both Browserify and Uglify. Here are the core bits of it:
browserify: {
myapp: {
options: {
transform: ['babelify'],
browserifyOptions: {
debug: true
},
},
src: 'src/index.js',
dest: 'build/myapp.js'
}
},
uglify: {
options: {
sourceMap: true,
banner: bannerContent
},
target: {
src: 'build/myapp.js',
dest: 'build/myapp.min.js'
}
},
It seems to generate a myapp.min.js.map file but it no longer has the raw sources in the source-map that existed prior to the Browserification.
Here's what the resultant source-map file contains:
{
"version":3,
"sources":[
"myapp.js"
],
"names":[
...
...
...
],
"mappings":".........",
"file":"myapp.min.js"
}
I've tried using the uglifyify transform for Browserify but that does not seem to generate as small files as the Uglify task.
I've also bumped all my dependencies to the latest but I haven't been able to resolve this issue.
grunt-contrib-uglify has a sourceMapIn option that allows you to specify the location of an input source map file from an earlier compilation - which in your scenario is the browserify task.
However, whilst setting browserifyOptions: { debug: true } in your browserify task does generate an inline source map in the resultant .js file (i.e. in build/myapp.js), the crux of the problem is twofold:
We don't have an external source map file that we can configure the sourceMapIn option of the subsequent grunt-contrib-uglify task to utilize.
grunt-browserify doesn't provide a feature to create an external .map file, it only creates them inline (see here)
To address the aforementioned issue consider utilizing grunt-extract-sourcemap to extract the inline source map from build/myapp.js (i.e. from the output file generated by your browserify task) after it has been produced.
Gruntfile.js
The following gist shows how your Gruntfile.js should be configured:
module.exports = function (grunt) {
grunt.initConfig({
browserify: {
myapp: {
options: {
transform: ['babelify'],
browserifyOptions: {
debug: true
},
},
src: 'src/index.js',
dest: 'build/myapp.js'
}
},
extract_sourcemap: {
myapp: {
files: {
'build': ['build/myapp.js']
}
}
},
uglify: {
options: {
sourceMap: true,
sourceMapIn: 'build/myapp.js.map'
},
target: {
src: 'build/myapp.js',
dest: 'build/myapp.min.js'
}
}
});
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-extract-sourcemap');
grunt.loadNpmTasks('grunt-contrib-uglify');
// Note the order of the tasks in your task list is important.
grunt.registerTask('default', ['browserify', 'extract_sourcemap', 'uglify']);
};
Explanation
First the browserify task is invoked which outputs a new file (i.e. build/myapp.js) containing your bundled JavaScript and an "inlined" source map info. If you were to inspect the content of build/myapp.js at this stage it includes something like the following at the end:
//# sourceMappingURL=data:application/json;charset=utf-8;base64, ...
Next the extract_sourcemap task is invoked. This essentially extracts the "inlined" source map info from build/myapp.js and writes it to a new file named myapp.js.map which is saved in your build directory.
The original "inlined" source map info in build/myapp.js is replaced with a link to the newly generated source map file, i.e. myapp.js.map. If you inspect the content of build/myapp.js you'll now notice the following at the end of the file instead:
//# sourceMappingURL=myapp.js.map
Lastly the uglify task is invoked. Notice how its sourceMapIn option is configured to read build/myapp.js.map, i.e the source map file we generated at step 2.
This task creates your desired build/myapp.min.js file containing; your minified JS, and a link to a newly generated source map file build/myapp.min.js.map.
Note The final resultant file (i.e. build/myapp.min.js) now correctly maps back to the original src/index.js file and any file(s) that index.js itself may have import'ed or require()'d

Grunt run task depending of file modified, it's possible?

can you help-me with this problem?
I need run a specific task depending of file modified, for example:
Modifie: _header.scss
Run: sass:header task
Modifie: _footer.scss
Run: sass:footer task
Modifie: _banners.scss
Run: sass:banners task
I've been trying to get the name of the file at save time to use it as a parameter, but I can not figure out ways to do this.
My project allows more people to work simultaneously but the work of defining which component of the project will be exported to CSS is manual, so I am trying to make this process of compiling the final CSS of each module as automatic.
My problem is how I can identify the name of the modified file, not the type of file.
Thank you very much!
It should look like this. When sass files are changed, grunt generates css files and copies (to dist directory) changed files only. Also as far as you can see connect and watch task implement live reload.
connect: {
options: {
port: ...
livereload: 35729,
hostname: '127.0.0.1'
},
livereload: {
options: {
base: [
'some dist'
]
}
}
},
// check that files are changed
watch: {
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'your dist/*.css'
]
},
// when sass file is changed, tasks will run
// newer:copy means that we have to do task copy with changed files only
sass: {
files: ['your dir/*.sass'],
tasks: ['sass', ...some other tasks like cssmin..., 'newer:copy']
}
},
sass: {
dist: {
files: [
...sass to css
]
}
},
copy: {
css: {
....
}
}
Also you can be interested in task like grunt-changed. The task configures another task to run with src files that have been changed. For more information please check the page grunt-changed

Grunt.js watch - node_modules always being watched

I'm using Grunt for livereload only. It works fine, but I noticed that it has high CPU, and when I run it with "--verbose" I see that it's watching the whole "node_modules" folder.
So, I made some research, and tried to ignore this. Unfortunately, with no success.
My watch part of "gruntfile.js" is:
// the watch stuff ..
watch: {
all: {
files: ['!**/node_modules/**', 'js/**/*.js', 'css/**/*.css', 'index.html'],
options: {
interval: 5007,
livereload: true
}
}
},
and basically I'm saying I want grunt to watch all js, css and the index.html file. Explicitly added the code for ignoring "node_modules", but it still says it's watching it and the CPU goes around 30%. (Mac OSx)
==================
One thing I noticed though:
When I make a change in the "gruntfile.js" - for example add one more file to the "files" property of the "watch" task - then it restarts the grunt, and in the console I see it start watching only the files I want, and then CPU goes below 1%. (I guess it's how it should be originally.)
What am I doing wrong?
====================
Edit: Unfortunately, when I change the gruntfile and I see only the files I want are being watched - then the livereload stuff is no longer working.
====================
This is the article I started from:
http://thecrumb.com/2014/03/15/using-grunt-for-live-reload/
Here is my package.json file:
{
"name": "grunt-reload",
"version": "1.0.0",
"devDependencies": {
"grunt": "~0.4.3",
"matchdep": "~0.3.0",
"grunt-express": "~1.2.1",
"grunt-contrib-watch": "~0.6.0",
"grunt-open": "~0.2.3"
}
}
And here is my Gruntfile.js:
module.exports = function(grunt) {
require('matchdep')
.filterDev('grunt-*')
.forEach(grunt.loadNpmTasks);
grunt.initConfig({
// the web server ..
express: {
all: {
options: {
bases: [__dirname],
port: 8888,
hostname: 'localhost',
livereload: true
}
}
},
// the watch stuff ..
watch: {
all: {
files: ['js/**/*.js', 'css/**/*.css', 'index.html'],
options: {
livereload: true
}
}
},
// the automatic opening stuff ..
open: {
all: {
path: 'http://localhost:8888/index.html'
}
}
});
// create the server task ..
grunt.registerTask(
'server',
['express', 'open', 'watch']
);
}; // end of "module.exports" ..
And I start all of this with "grunt server".
edit: After you shared your Gruntfile, the problem became more clearer.
In your grunt-express config, you have set livereload to true and bases to __dirname, which is the folder Gruntfile in ran from.
Now, let's look at the grunt-express documentation:
bases
Type: String|Array Default: null
The bases (or root) directories from which static files will be served. A connect.static() will be generated for each entry of bases. When livereload is set to true (or set to a specific port number), a watch task will be created for you (at runtime) to watch your basePath/**/*.*.
(Emphasis mine)
So in your grunt-express config, you set your livereload to watch all the files in your basepath, which of course includes node_modules.
You have couple of options:
Remove your other watch task and config grunt-expresses basepath accordingly (just copy your other config basically).
Keep both of the watch tasks and just ignore the node_modules in the other grunt-express -> bases config.
Remove the bases and handle livereloading in the other watch task
Where is the node_modules folder located? If it's on root, you can just remove the node_modules parameter altogether as long as there aren't any matching glob patterns:
// the watch stuff ..
watch: {
all: {
files: ['js/**/*.js', 'css/**/*.css', 'index.html'],
options: {
interval: 5007,
livereload: true
}
}
},
Now you are watching: All .js-files under js folder, index.html on root and so on.
However if you have node_modules under js/node_modules, you can the explicitly ignore that folder and the files in it:
files: ['!js/node_modules/**', 'js/**/*.js', 'css/**/*.css', 'index.html'],
Anyway, depending on your Gruntfiles and node_module-folders location your configuration should work just fine anyway.

Grunt Compass for multiple SASS files for different sites

I have lots of different partials and sass files to generate 11 individual website specific style sheets so if I make a changes in a partial that is being used in all 11 style sheets then I have to wait for grunt to compile all these before I can refresh my browser and see the change, one workaround I have is to use the specify option and change the site ID depending on which site I am working on -
compass: {
dev: {
options: {
sassDir: "assets/sass",
specify: "assets/sass/site_##.scss",
cssDir: "assets/styles",
outputStyle: "expanded",
noLineComments: false,
sourcemap: true
}
}
},
watch: {
css: {
files: 'assets/sass/**/*',
tasks: 'compass',
},
},
Is there a way I could make this dynamic in the watch task, i.e. using an ID appended to the body or something?
My partials -
_reset
_grid
_layout
_variables
_mixins
_brand1
_brand2
_brand3
_summer
_winter
_site_1_specific
_site_2_specific
_site_3_specific
_site_4_specific
_site_5_specific
_site_6_specific
_site_7_specific
_site_7_specific
_site_9_specific
_site_10_specific
_site_11_specific
I then have 11 SCSS files importing a combination of the above partials to make the final style sheets.
You can use grunt-newer, that helps you to execute the compass task only in the file that is changed:
https://github.com/tschaub/grunt-newer
npm install grunt-newer --save-dev
grunt.loadNpmTasks('grunt-newer');
Then, you have to change your watch task:
watch: {
css: {
files: '<%= tui.sass %>/**/*',
tasks: ['newer:compass']
},
},
Hope it helps.
Regards.

Grunt - livereload only uglified script.js?

GruntJS newbie here. I currently have my gruntfile.js using the watch task to look for changes to any .js files in my js/components/ folder and uglify those scripts into a single script.js file.
The issue that I'm having is that these changes cause a full page reload.
Is it possible to only reload the script.js file without also reloading the HTML/CSS? The effect I'm after is the same effect I'm currently getting with SASS/CSS files like so:
watch : {
options: { livereload: true },
sass: {
options: {
livereload: false
},
files: ['css/sass/*.scss'],
tasks: ['compass:dev']
},
css: {
files: ['css/*.css']
}
}
This reloads only my CSS without reloading the entire page, which makes for a much smoother workflow. Is it possible to do the same for JS? If not, why not? My current JS workflow configuration looks like this:
grunt.initConfig({
uglify: {
my_target: {
files: {
'js/script.js' : ['js/components/*.js']
}
}
},
watch : {
options: { livereload: true },
scripts: {
files: ['js/components/*.js'],
tasks: ['uglify']
}
}
});
After reading around I finally wound up on the livereload.js Github page. Under the developer's rundown of the project's current status, "Live JS reloading" is the one remaining to-do item. So it's a planned feature, but not yet implemented. The last commit on the project was 7 months back, so I'm not sure when/if we can anticipate this update.

Resources