diff --git a/.eslintrc b/.eslintrc
index b45bd56..6b83b73 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -38,7 +38,6 @@
         "no-shadow": 2,
         "no-shadow-restricted-names": 2,
         "no-spaced-func": 2,
-        "semi-spacing": [2, {"before": false, "after": true}],
         "no-sparse-arrays": 2,
         "no-sync": 0,
         "no-undef": 2,
@@ -133,6 +132,7 @@
         "indent": [2, 4, {"SwitchCase": 1}],
         "space-before-function-paren": [2, {"anonymous": "always", "named": "never"}],
         "space-before-blocks": [2, "always"],
+        "space-before-keywords": [2, "always"],
         "operator-linebreak": [2, "after"],
         "dot-location": [2, "property"],
         "semi-spacing": [2, {"before": false, "after": true}],
@@ -145,21 +145,29 @@
 
         "react/display-name": 2,
         "react/jsx-boolean-value": 1,
-        "react/jsx-quotes": 1,
+        "react/jsx-closing-bracket-location": 1,
+        "react/jsx-curly-spacing": 1,
+        "react/jsx-indent-props": 1,
+        "react/jsx-max-props-per-line": 1,
+        "react/jsx-no-duplicate-props": 1,
         "react/jsx-no-undef": 1,
+        "react/jsx-quotes": 1,
+        "react/jsx-sort-prop-types": 1,
         "react/jsx-sort-props": 1,
-        "react/jsx-sort-prop-types": 0,
         "react/jsx-uses-react": 1,
         "react/jsx-uses-vars": 1,
+        "react/no-danger": 1,
         "react/no-did-mount-set-state": 1,
         "react/no-did-update-set-state": 1,
-        "react/no-multi-comp": 0,
+        "react/no-multi-comp": 1,
+        "react/no-set-state": 0,
         "react/no-unknown-property": 1,
         "react/prop-types": 1,
         "react/react-in-jsx-scope": 1,
+        "react/require-extension": 1,
         "react/self-closing-comp": 1,
-        "react/wrap-multilines": 1,
         "react/sort-comp": 1,
+        "react/wrap-multilines": 1,
 
         "lodash3/prop-shorthand": 2,
         "lodash3/matches-prop-shorthand": 2,
@@ -171,7 +179,6 @@
         "lodash3/no-unnecessary-bind": 2,
         "lodash3/unwrap": 2,
         "lodash3/prefer-compact": 2,
-        "lodash3/prefer-compact": 2,
         "lodash3/no-double-unwrap": 2,
         "lodash3/prefer-map": 2,
         "lodash3/prefer-wrapper-method": 2,
diff --git a/package.json b/package.json
index 34c4a9c..7c362e3 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,8 @@
     "test-cov": "istanbul cover test/src/test.js -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
     "patch": "npm version patch -m\"update version to %s\" && git push && git push --tags",
     "minor": "npm version minor -m\"update version to %s\" && git push && git push --tags",
-    "major": "npm version major -m\"update version to %s\" && git push && git push --tags"
+    "major": "npm version major -m\"update version to %s\" && git push && git push --tags",
+    "build": "webpack --config webpack-production.config.js --progress --profile --colors"
   },
   "repository": {
     "type": "git",
@@ -26,7 +27,8 @@
   "dependencies": {
     "chalk": "^1.1.1",
     "cheerio": "^0.19.0",
-    "escodegen": "^1.6.1",
+    "css": "^2.2.1",
+    "escodegen": "^1.7.0",
     "esprima-harmony": "^7001.1.0-dev-harmony-fb",
     "lodash": "^3.10.1",
     "optionator": "^0.6.0",
@@ -36,18 +38,19 @@
     "brace": "^0.5.1",
     "brfs": "^1.4.1",
     "coveralls": "^2.11.4",
-    "eslint-plugin-lodash3": "^0.1.6",
-    "eslint-plugin-react": "^3.3.1",
+    "eslint-plugin-lodash3": "^0.1.9",
+    "eslint-plugin-react": "^3.5.0",
     "grunt": "^0.4.5",
-    "grunt-browserify": "^3.8.0",
+    "grunt-browserify": "^4.0.0",
     "grunt-contrib-requirejs": "^0.4.4",
     "grunt-contrib-uglify": "^0.9.2",
     "grunt-contrib-watch": "^0.6.1",
-    "grunt-eslint": "^17.1.0",
+    "grunt-eslint": "^17.2.0",
     "grunt-node-tap": "^0.1.61",
-    "istanbul": "^0.3.18",
+    "istanbul": "^0.3.21",
     "react": "^0.12.2",
     "react-native": "^0.9.0",
+    "react-templates": "^0.1.22",
     "tape": "^4.2.0"
   },
   "keywords": [
diff --git a/sample/ImageSearch.js b/sample/ImageSearch.js
index 3a48630..69082bd 100644
--- a/sample/ImageSearch.js
+++ b/sample/ImageSearch.js
@@ -25,7 +25,7 @@ define([
             };
         },
 
-        search: function() {
+        search: function () {
             this.state.items = [[], [], []];
             this.total = 0;
             this.heights = [0, 0, 0];
@@ -34,24 +34,25 @@ define([
             this.loadMore();
         },
 
-        indexOfMin: function(array) {
-            var indexAndMin = _.reduce(array, function(accum, height, index) {
-                return (height < accum.min) ? { i: index, min: height } : accum;
+        indexOfMin: function (array) {
+            var indexAndMin = _.reduce(array, function (accum, height, index) {
+                /*eslint no-extra-parens:0*/
+                return (height < accum.min) ? {i: index, min: height} : accum;
             }, {i: -1, min: Number.MAX_VALUE});
             return indexAndMin.i;
         },
 
-        loadMore: function(done) {
-            done = done || function() {};
+        loadMore: function (done) {
+            done = done || function () {};
             if (!this.hasMore) {
                 done();
                 return;
             }
-            var url = 'https://ajax.googleapis.com/ajax/services/search/images?v=1.0&rsz=8&start=' + this.total + '&q=' + this.realTerm + "&callback=?";
+            var url = 'https://ajax.googleapis.com/ajax/services/search/images?v=1.0&rsz=8&start=' + this.total + '&q=' + this.realTerm + '&callback=?';
 
             var self = this;
             $.ajax({url: url, dataType: 'jsonp'})
-                .done(function(data){
+                .done(function (data) {
                     if (!data.responseData) {
                         self.hasMore = false;
                         done();
@@ -83,7 +84,7 @@ define([
                 });
         },
 
-        shouldComponentUpdate: function(nextProps, nextState) {
+        shouldComponentUpdate: function (nextProps, nextState) {
             return !_.isEqual(this.state, nextState);
         },
 
diff --git a/sample/InfiniteScroll.js b/sample/InfiniteScroll.js
index 8502e02..ed0366f 100644
--- a/sample/InfiniteScroll.js
+++ b/sample/InfiniteScroll.js
@@ -10,11 +10,11 @@ define([
         displayName: 'InfiniteScroll',
         gettingMore: false,
 
-        onLoadMoreFinished: function() {
+        onLoadMoreFinished: function () {
             this.gettingMore = false;
         },
 
-        onScroll: function(evt) {
+        onScroll: function (evt) {
             if (!this.props.onLoadMore || this.gettingMore) {
                 return;
             }
diff --git a/sample/main.js b/sample/main.js
index 01c596f..8a81773 100644
--- a/sample/main.js
+++ b/sample/main.js
@@ -1,5 +1,3 @@
-'use strict';
-
 requirejs.config({
 //    baseUrl: '/',
     paths: {
@@ -8,12 +6,13 @@ requirejs.config({
         react: '//cdnjs.cloudflare.com/ajax/libs/react/0.13.3/react-with-addons'
     },
     shim: {
-        lodash: { exports: '_' },
-        jquery: { exports: '$' },
-        react: { exports: 'React' }
+        lodash: {exports: '_'},
+        jquery: {exports: '$'},
+        react: {exports: 'React'}
     }
 });
 
 requirejs(['jquery', 'react', 'ImageSearch'], function ($, React, ImageSearch) {
-    React.renderComponent(ImageSearch(), $('#main').get(0));
+    'use strict';
+    React.renderComponent(ImageSearch(), $('#main').get(0)); //eslint-disable-line new-cap
 });
diff --git a/src/formatters/stylish.js b/src/formatters/stylish.js
index 857c11e..491865c 100644
--- a/src/formatters/stylish.js
+++ b/src/formatters/stylish.js
@@ -163,10 +163,10 @@ module.exports = function (results) {
                 }
             }
         ).split('\n').map(function (el) {
-                return el.replace(/(\d+)\s+(\d+)/, function (m, p1, p2) {
-                    return chalk.gray(p1 + ':' + p2);
-                });
-            }).join('\n') + '\n\n';
+            return el.replace(/(\d+)\s+(\d+)/, function (m, p1, p2) {
+                return chalk.gray(p1 + ':' + p2);
+            });
+        }).join('\n') + '\n\n';
     });
 
     if (total > 0) {
diff --git a/src/reactTemplates.js b/src/reactTemplates.js
index 90a0f4e..84a79b2 100644
--- a/src/reactTemplates.js
+++ b/src/reactTemplates.js
@@ -11,6 +11,7 @@ var rtError = require('./RTCodeError');
 var reactSupport = require('./reactSupport');
 var templates = reactSupport.templates;
 var utils = require('./utils');
+var util = require('util');
 var validateJS = utils.validateJS;
 var RTCodeError = rtError.RTCodeError;
 
@@ -138,8 +139,7 @@ function convertText(node, context, txt) {
 function generateInjectedFunc(context, namePrefix, body, params) {
     params = params || context.boundParams;
     var generatedFuncName = namePrefix.replace(',', '') + (context.injectedFunctions.length + 1);
-    var funcText = 'function ' + generatedFuncName + '(' + params.join(',');
-    funcText += ') {\n' + body + '\n}\n';
+    var funcText = util.format('function %s(%s) {\n%s\n}\n', generatedFuncName, params.join(','), body);
     context.injectedFunctions.push(funcText);
     return generatedFuncName;
 }
@@ -218,7 +218,7 @@ function generateProps(node, context) {
                 params = params.concat([evtParams.trim()]);
             }
             var generatedFuncName = generateInjectedFunc(context, key, funcBody, params);
-            props[propKey] = generatedFuncName + '.bind(' + (['this'].concat(context.boundParams)).join(',') + ')';
+            props[propKey] = util.format('%s.bind(%s)', generatedFuncName, (['this'].concat(context.boundParams)).join(','));
         } else if (key === 'style' && !utils.isStringOnlyCode(val)) {
             var styleParts = val.trim().split(';');
             styleParts = _.compact(_.map(styleParts, function (str) {
@@ -411,11 +411,11 @@ function convertHtmlToReact(node, context) {
         if (node.attribs[ifAttr]) {
             data.condition = node.attribs[ifAttr].trim();
         }
-        data.children = node.children ? utils.concatChildren(_.map(node.children, function (child) {
+        data.children = utils.concatChildren(_.map(node.children, function (child) {
             var code = convertHtmlToReact(child, context);
             validateJS(code, child, context);
             return code;
-        })) : '';
+        }));
 
         if (hasNonSimpleChildren(node)) {
             data.body = reactSupport.shouldUseCreateElement(context) ? tagTemplateCreateElement(data) : tagTemplate(data);
@@ -424,10 +424,9 @@ function convertHtmlToReact(node, context) {
         }
 
         if (node.attribs[scopeAttr]) {
-            var scopeVarDeclarations = _.map(data.innerScope.innerMapping, function (v) { return v; }).join('\n');
-            var functionBody = scopeVarDeclarations + 'return ' + data.body;
+            var functionBody = _.values(data.innerScope.innerMapping).join('\n') + 'return ' + data.body;
             var generatedFuncName = generateInjectedFunc(context, 'scope' + data.innerScope.scopeName, functionBody, _.keys(data.innerScope.outerMapping));
-            data.body = generatedFuncName + '.apply(this, [' + _.values(data.innerScope.outerMapping).join(',') + '])';
+            data.body = util.format('%s.apply(this, [%s])', generatedFuncName, _.values(data.innerScope.outerMapping).join(','));
         }
 
         // Order matters here. Each rt-repeat iteration wraps over the rt-scope, so
@@ -502,7 +501,7 @@ function convertRT(html, reportContext, options) {
 
     var context = defaultContext(html, options);
     utils.validate(options, context, reportContext, rootNode.root()[0]);
-    var rootTags = _.filter(rootNode.root()[0].children, {type: 'tag'});
+    var rootTags = _.filter(rootNode.root()[0].children, isTag);
     rootTags = handleSelfClosingHtmlTags(rootTags);
     if (!rootTags || rootTags.length === 0) {
         throw new RTCodeError('Document should have a root element');
diff --git a/src/utils.js b/src/utils.js
index f934040..2b07dde 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -30,23 +30,23 @@ function normalizeName(name) {
  * @return {boolean}
  */
 function isStringOnlyCode(txt) {
-    txt = txt.trim();
-    return txt.length && txt.charAt(0) === '{' && txt.charAt(txt.length - 1) === '}';
+    return /^\s*\{.*}\s*$/g.test(txt);
+    //txt = txt.trim();
+    //return txt.length && txt.charAt(0) === '{' && txt.charAt(txt.length - 1) === '}';
 }
 
 /**
- * @param children
+ * @param {Array.<string>} children
  * @return {string}
  */
 function concatChildren(children) {
     var res = '';
     _.forEach(children, function (child) {
-        if (child && child.indexOf(' /*') !== 0 ) {
-            res += ',' + child;
-        } else {
-            res += child;
+        if (child && child.indexOf(' /*') !== 0) {
+            res += ',';
         }
-    }, this);
+        res += child;
+    });
     return res;
 }