Grunt browserify transform ReactJS then bundle - gruntjs

In my project I am using Grunt to build the javascript files, I have ReactJS components which makes Grunt complain about Error: Parsing file in one of my javascript file, caused by the JSX syntax:
"use strict";
var $ = require('jquery');
var React = require('react');
require('app/comments/comment_box_react.js');
$.fn.comment_box = function(options){
var opts = $.extend({}, $.fn.comment_box.defaults, options);
var me = this;
React.render(<CommentBox url="comments.json" />, this);
return me;
}
$.fn.comment_box.defaults = {}
My browerify config in Grunt looks like this:
browserify: {
main: {
files: {
'<%= paths.js_built %>/bundle.js': ['<%=paths.js %>/project.js'],
}
},
transform: ['reactify'],
},
How do I perform transform first before the bundle?

The transform example in their docs has the transform array in an options object.
browserify: {
dist: {
files: {
'build/module.js': ['client/scripts/**/*.js', 'client/scripts/**/*.coffee'],
},
options: {
transform: ['coffeeify']
}
}
}
Also, looks like your transform definition is outside of your main definition. Not sure if that would be global or not, so you might have to move it inside of main. Something like this
browserify: {
main: {
files: {
'<%= paths.js_built %>/bundle.js': ['<%=paths.js %>/project.js'],
},
options: {
transform: ['reactify']
}
}
}

I ended up using gulp and transform globally before bundle:
https://github.com/andreypopp/reactify/issues/66
gulp.task('activitiesjs', function() {
browserify({
entries: [
paths.js+'/lib/activities/activities.js',
]
}).transform(reactify, {global:true}).bundle().pipe(source('bundle.js')).pipe(gulp.dest(paths.js_built+'/activities'));
});

Related

React client rendering -- handleClick not working

Here's a simple react file that handles click:
//src/react/components/list.js
/** #jsx React.DOM */
var React = require('react/addons');
var List = React.createClass({
displayName: 'List',
handleClick: function() {
console.error('click');
var resultData = {
name: 'test',
version: '0.0.1'
};
},
render: function() {
return (
<div>
List
<button onClick={this.handleClick}>Add</button>
</div>
);
}
});
module.exports = List;
Button renders with no problem but nothing happens when I clicked it. I suppose it means server-side rendering works but client-side rendering is not working? I'm using grunt and browserify, and this is my Gruntfile.js:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
browserify: {
client: {
src: ['src/react/**/*.js'],
dest: 'public/js/react/main.js'
},
options: {
debug: true,
transform: ['reactify']
}
},
watch: {
js: {
files: ['src/react/**/*.js'],
tasks: ['browserify']
}
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-browserify');
grunt.registerTask('default', ['browserify', 'watch']);
};
And then I confirmed code in src/react/components/list.js is built into /public/js/react/main.js. So what could the problem be? Any help is appreciated!
http://plnkr.co/edit/lJ2aWzvcR2vQ6PVuneqK?p=preview
I tried it on plnkr, and it works well (open Chrome Console or Firebug to actually see that when you click the button, a console.error is thrown).
Maybe on your side is the require('react/addons') that is not working ? If you already have React as a global variable, this require is the source of your problems I think.

How to execute tasks based on a subfolder with Grunt and Grunt-Watch

I want to be able to have different subprojects inside my main project. For example:
-- my-project/
- Gruntfile.js
- subproject1/
- index.html
- scss/
- main.scss
- subproject2/
- index.html
- scss/
- main.scss
I want to be able to modify a file in subproject1 without triggering subproject2 tasks.
As of right now I'm configuring my gruntfile like so:
watch: {
subproject1: {
files: ['subproject1/*.html', 'subproject1/scss/**/*.scss'],
tasks: ['sass', 'premailer:subproject1']
},
subproject2: {
files: ['subproject2/*.html', 'subproject2/scss/**/*.scss'],
tasks: ['sass', 'premailer:subproject2']
}
},
premailer: {
subproject1: {
options: {
css: 'subproject1/css/main.css',
verbose: false
},
files: [
{
'subproject1/dist/index.html' : 'subproject1/index.html'
}
]
},
subproject2: {
options: {
css: 'subproject2/css/main.css',
verbose: false
},
files: [
{
'subproject2/dist/index.html' : 'subproject2/index.html'
}
]
},
}
Is there a way to dynamically specify to grunt what task to run depending on file modified (eg, I modify folder/index.html, then run premailer:folder) or is this the only way to achieve it ?
You can check all folders in your main folder inside your Gruntfile, using the grunt.file methods (docs here), create an array of subproject names and then using forEach to create your task dynamically.
Something like this should go:
/*global module:false*/
module.exports = function(grunt) {
var mycwd = "./";
var tempFileList = grunt.file.expand(
{ filter: function (src) {
if (grunt.file.isDir(src) == true) {
return true;
}
return false;
} },
[ mycwd + "!(Gruntfile.js|node_modules|package.json)" ] // structure to analyse
);
// I create an empty array to put all elements in, once cleaned.
var fileList = [];
tempFileList.forEach(function(url){
var cwd = url;
cwd = cwd.replace(mycwd, "");
fileList.push(cwd);
})
var watchObject = {};
var premailerObject = {};
fileList.forEach(function(name) {
watchObject[name] = {
files: [name + '/*.html', name + '/scss/**/*.scss'],
tasks: ['sass', 'premailer:' + name]
};
var filesObject = {};
filesObject[name+'/css/main.css'] = name + '/index.html';
premailerObject[name] = {
options: { css: name + '/css/main.css', verbose: false },
files: [ filesObject ]
};
});
var configObject = {
watch: watchObject,
premailer: premailerObject
};
// just to check the final structure
console.log(configObject);
grunt.initConfig(configObject);
};

Access variables from other tasks when using load-grunt-config?

I'm using load-grunt-config to split my gruntfile and I have a requirement to access the variables of one task in another. The tasks are being exported using module.exports. Is it possible to access job variables in one task from another task that runs after it?
module.exports= function(grunt) {
combine: {
files: {
'dist/lib.min.css' : ['file1', 'file2']
}
}
}
module.exports = function (grunt) {
for (var file in //grunt.combine.files???
//do stuff with files
}
It looks like you are in need of a shared configuration between two tasks.
load-grunt-config exposes the 'data' object that lets you tweak the grunt configuration.
module.exports = function(grunt) {
require('load-grunt-config')(grunt, {
// data passed into config.
data: {
files: ['file1', 'file2']
}
});
}
that you can later use, in your example, as such
module.exports = function(grunt) {
combine: {
files: {
'dist/lib.min.css' : '<%= files %>'
}
}
}
module.exports = function (grunt) {
for (var file in grunt.config('files')) {
//do stuff with files
}
}

Dynamic config for Grunt task

I'm trying to change a boolean value based on the task called.
For example, given this task definition inside the grunt.initConfig block:
myTask:{
options:{
someConfig:doTheAction
},
build:{...}
}
The doTheAction var is defined above the grunt.initConfig block. (e.g. var doTheAction=true;).
What I'm trying to do is this:
grunt.registerTask('prod','Production',function()
{
doTheAction=true;
grunt.task.run('default');
});
grunt.registerTask('prod','Production',function()
{
doTheAction=false;
grunt.task.run('default');
});
The issue is that while doTheAction changes value, the myTask's option someConfig is set to the init value of that var.
How can I make someConfig change based on the task called?
Here is how I do it using grunt.config :
var taskConfig = {
pkg: {
var1: null
},
myTask:{
options:{
someConfig : '<%= pkg.var1%>',
someOtherConfig: grunt.config.get('pkg.var1') //alternative
},
build:{...}
}
}
grunt.registerTask('prod','Production',function()
{
grunt.config.set('pkg.var1', true);
grunt.task.run('default');
});
grunt.registerTask('prod','Production',function()
{
grunt.config.set('pkg.var1', false);
grunt.task.run('default');
});
Hope this helps

Conditionally running tasks in grunt if some files are changed

I'm new to Grunt, and from what I understood up till now, Grunt has the "watch" task, which continuously checks files for modifications, and each time modification happens, runs corresponding tasks.
What I'm looking for would be a kind of discrete version of this - a task, that would run other tasks, if and only if some files were changed since the last build.
Seems to be a natural thing to ask for, but I couldn't find this. Is it just me, or is this really an issue?
Configuration file should look like this:
grunt.initConfig({
foo: {
files: "foo/*"
// some task
},
bar: {
files: "bar/*"
// some other task
},
ifModified: {
foo: {
files: "foo/*",
tasks: ['foo']
},
bar: {
files: 'bar/*',
tasks: ['bar', 'foo']
}
}
});
grunt.registerTask('default', ['bar', 'foo']);
Running grunt should always execute tasks 'bar', 'foo', while running grunt ifModified should execute any tasks only if some of the files were actually changed since the previous build.
Made my own task for that. It turned out to be not hard, here is the code:
build/tasks/if-modified.js:
var fs = require('fs');
var crypto = require('crypto');
module.exports = function (grunt) {
grunt.registerMultiTask('if-modified', 'Conditionally running tasks if files are changed.', function () {
var options = this.options({});
grunt.verbose.writeflags(options, 'Options');
var hashes = {};
if (grunt.file.exists(options.hashFile)) {
try {
hashes = grunt.file.readJSON(options.hashFile);
}
catch (err) {
grunt.log.warn(err);
}
}
grunt.verbose.writeflags(hashes, 'Hashes');
var md5 = crypto.createHash('md5');
this.files.forEach(function (f) {
f.src.forEach(function (filepath) {
var stats = fs.statSync(filepath);
md5.update(JSON.stringify({
filepath: filepath,
isFile: stats.isFile(),
size: stats.size,
ctime: stats.ctime,
mtime: stats.mtime
}));
});
});
var hash = md5.digest('hex');
grunt.verbose.writeln('Hash: ' + hash);
if (hash != hashes[this.target]) {
grunt.log.writeln('Something changed, executing tasks: ' + JSON.stringify(options.tasks));
grunt.task.run(options.tasks);
hashes[this.target] = hash;
grunt.file.write(options.hashFile, JSON.stringify(hashes));
}
else
grunt.log.writeln('Nothing changed.');
});
};
Gruntfile.js:
grunt.initConfig({
foo: {
src: ["foo/**/*"],
dest: "foo-dest"
// some task
},
bar: {
src: ["bar/**/*", "foo-dest"]
// some other task
},
'if-modified': {
options: {
hashFile: 'build/hashes.json'
},
foo: {
src: ['foo/**/*', 'Gruntfile.js', 'package.json'],
options: {tasks: ['foo']}
},
bar: {
src: ['bar/**/*', "foo-dest", 'Gruntfile.js', 'package.json'],
options: {tasks: ['bar']}
}
}
});
grunt.loadTasks('build/tasks'); // if-modified.js in this dir
grunt.registerTask('default', ['foo', 'bar']);
run:
grunt if-modified
You could create a task that runs conditionally other tasks, from https://github.com/gruntjs/grunt/wiki/Creating-tasks :
grunt.registerTask('foo', 'My "foo" task.', function() {
// Enqueue "bar" and "baz" tasks, to run after "foo" finishes, in-order.
grunt.task.run('bar', 'baz');
// Or:
grunt.task.run(['bar', 'baz']);
});
What you need might be grunt-newer :
The newer task will configure another task to run with src files that are a) newer than the dest files or b) newer than the last successful run (if there are no dest files). See below for examples and more detail.
https://github.com/tschaub/grunt-newer

Resources