├── .gitignore
├── .travis.yml
├── test
├── fixtures
│ ├── js
│ │ ├── fixture-jsx.js
│ │ └── fixture.js
│ ├── jsx
│ │ ├── fixture.jsx
│ │ └── nested
│ │ │ └── fixture-js.jsx
│ └── browserify
│ │ └── module.jsx
├── expected
│ ├── default_options
│ ├── extension_option
│ ├── vanilla_js
│ ├── multiple_jsx_files
│ └── browserify
├── browserify_test.js
├── transformers_test.js
└── react_test.js
├── main.js
├── .jshintrc
├── lib
└── transformers.js
├── LICENSE-MIT
├── package.json
├── tasks
└── react.js
├── Gruntfile.js
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | tmp
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 0.10
4 |
--------------------------------------------------------------------------------
/test/fixtures/js/fixture-jsx.js:
--------------------------------------------------------------------------------
1 | (function(greeting) {
2 | return greeting;
3 | })(
Howdy
);
4 |
--------------------------------------------------------------------------------
/test/expected/default_options:
--------------------------------------------------------------------------------
1 | (function(greeting) {
2 | return greeting;
3 | })(React.createElement("p", null, "Howdy"));
4 |
--------------------------------------------------------------------------------
/test/fixtures/js/fixture.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Plain JS file
3 | */
4 |
5 | (function(greeting) {
6 | return greeting;
7 | })('Howdy
');
8 |
--------------------------------------------------------------------------------
/test/fixtures/jsx/fixture.jsx:
--------------------------------------------------------------------------------
1 | var FixtureComponent = React.createClass({
2 | render: function() {
3 | return (
4 | Howdy
5 | );
6 | }
7 | });
8 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Module Dependencies
3 | */
4 |
5 | var Transformers = require('./lib/transformers.js');
6 |
7 | /**
8 | * Exports
9 | */
10 |
11 | module.exports = Transformers;
12 |
--------------------------------------------------------------------------------
/test/expected/extension_option:
--------------------------------------------------------------------------------
1 | var FixtureComponent = React.createClass({displayName: "FixtureComponent",
2 | render: function() {
3 | return (
4 | React.createElement("p", null, "Howdy")
5 | );
6 | }
7 | });
8 |
--------------------------------------------------------------------------------
/test/fixtures/browserify/module.jsx:
--------------------------------------------------------------------------------
1 | var ModuleComponent = React.createClass({
2 | render: function() {
3 | return (
4 | Module
5 | );
6 | }
7 | });
8 |
9 | module.exports = ModuleComponent;
10 |
--------------------------------------------------------------------------------
/test/fixtures/jsx/nested/fixture-js.jsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Plain JS File with .jsx extension
3 | */
4 |
5 | var FixtureComponent = React.createClass({
6 | render: function() {
7 | return 'Howdy
';
8 | }
9 | });
10 |
--------------------------------------------------------------------------------
/test/expected/vanilla_js:
--------------------------------------------------------------------------------
1 | /**
2 | * Plain JS File with .jsx extension
3 | */
4 |
5 | var FixtureComponent = React.createClass({displayName: "FixtureComponent",
6 | render: function() {
7 | return 'Howdy
';
8 | }
9 | });
10 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "curly": true,
3 | "eqeqeq": true,
4 | "immed": true,
5 | "latedef": true,
6 | "newcap": true,
7 | "noarg": true,
8 | "sub": true,
9 | "undef": true,
10 | "boss": true,
11 | "eqnull": true,
12 | "node": true
13 | }
14 |
--------------------------------------------------------------------------------
/test/expected/multiple_jsx_files:
--------------------------------------------------------------------------------
1 | var FixtureComponent = React.createClass({displayName: "FixtureComponent",
2 | render: function() {
3 | return (
4 | React.createElement("p", null, "Howdy")
5 | );
6 | }
7 | });
8 |
9 | /**
10 | * Plain JS File with .jsx extension
11 | */
12 |
13 | var FixtureComponent = React.createClass({displayName: "FixtureComponent",
14 | render: function() {
15 | return 'Howdy
';
16 | }
17 | });
18 |
--------------------------------------------------------------------------------
/test/browserify_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Transformers = require('../lib/transformers');
4 | var fs = require('fs');
5 |
6 | exports.transformers = {
7 | setUp: function(done) {
8 | done();
9 | },
10 | source_js: function(test) {
11 | test.expect(1);
12 |
13 | var actual = fs.readFileSync('tmp/browserify/module.js').toString();
14 | var expected = fs.readFileSync('test/expected/browserify').toString();
15 |
16 | test.equal(actual, expected, 'JSX should be compiled by browserify');
17 | test.done();
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/test/expected/browserify:
--------------------------------------------------------------------------------
1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 0.10.0"
27 | },
28 | "scripts": {
29 | "test": "./node_modules/.bin/grunt"
30 | },
31 | "dependencies": {
32 | "react-tools": "^0.13.0",
33 | "through": "~2.3.6"
34 | },
35 | "devDependencies": {
36 | "grunt": "~0.4.5",
37 | "grunt-browserify": "~3.5.0",
38 | "grunt-cli": "~0.1.13",
39 | "grunt-contrib-clean": "~0.6.0",
40 | "grunt-contrib-jshint": "~0.11.0",
41 | "grunt-contrib-nodeunit": "~0.4.1"
42 | },
43 | "peerDependencies": {
44 | "grunt": "~0.4.2"
45 | },
46 | "keywords": [
47 | "gruntplugin",
48 | "react",
49 | "jsx"
50 | ]
51 | }
52 |
--------------------------------------------------------------------------------
/test/react_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | exports.react = {
6 | setUp: function(done) {
7 | done();
8 | },
9 |
10 | default_options_js: function(test) {
11 | test.expect(1);
12 |
13 | var actual = grunt.file.read('tmp/js/fixture.js');
14 | var expected = grunt.file.read('test/fixtures/js/fixture.js');
15 |
16 | test.equal(actual, expected, 'should leave vanilla JS alone');
17 | test.done();
18 | },
19 |
20 | default_options_jsx_as_js: function(test) {
21 | test.expect(1);
22 |
23 | var actual = grunt.file.read('tmp/js/fixture-jsx.js');
24 | var expected = grunt.file.read('test/expected/default_options');
25 |
26 | test.equal(actual, expected, 'should convert JSX into JS');
27 | test.done();
28 | },
29 |
30 | extension_option_js_as_jsx: function(test) {
31 | test.expect(1);
32 |
33 | var actual = grunt.file.read('tmp/jsx/nested/fixture-js.js');
34 | var expected = grunt.file.read('test/expected/vanilla_js');
35 |
36 | test.equal(actual, expected, 'should convert even vanilla JS');
37 | test.done();
38 | },
39 |
40 | extension_option_jsx: function(test) {
41 | test.expect(1);
42 |
43 | var actual = grunt.file.read('tmp/jsx/fixture.js');
44 | var expected = grunt.file.read('test/expected/extension_option');
45 |
46 | test.equal(actual, expected, 'should convert JSX into JS');
47 | test.done();
48 | },
49 |
50 | multiple_jsx_files: function(test) {
51 | test.expect(1);
52 |
53 | var actual = grunt.file.read('tmp/multiple_jsx_files.js');
54 | var expected = grunt.file.read('test/expected/multiple_jsx_files');
55 |
56 | test.equal(actual, expected, 'should convert JSX into JS');
57 | test.done();
58 | }
59 | };
60 |
--------------------------------------------------------------------------------
/tasks/react.js:
--------------------------------------------------------------------------------
1 | /*
2 | * grunt-react
3 | * https://github.com/ericclemmons/grunt-react
4 | *
5 | * Copyright (c) 2013 Eric Clemmons, contributors
6 | * Licensed under the MIT license.
7 | */
8 |
9 | 'use strict';
10 |
11 | module.exports = function(grunt) {
12 |
13 | var transform = require('react-tools').transform;
14 |
15 | grunt.registerMultiTask('react', 'Compile Facebook React JSX templates into JavaScript', function() {
16 | var done = this.async();
17 |
18 | var options = this.options();
19 | grunt.verbose.writeflags(options, 'Options');
20 |
21 | if (this.files.length < 1) {
22 | grunt.verbose.warn('Destination not written because no source files were provided.');
23 | }
24 |
25 | grunt.util.async.forEachSeries(this.files, function(f, nextFileObj) {
26 | var destFile = f.dest;
27 |
28 | var files = f.src.filter(function(filepath) {
29 | if (!grunt.file.exists(filepath)) {
30 | grunt.log.warn('Source file "' + filepath + '" not found.');
31 | return false;
32 | } else {
33 | return true;
34 | }
35 | });
36 |
37 | if (files.length === 0) {
38 | if (f.src.length < 1) {
39 | grunt.log.warn('Destination not written because no source files were found.');
40 | }
41 |
42 | // No src files, go to next target. Warn would have been issued above.
43 | return nextFileObj();
44 | }
45 |
46 | var compiled = [];
47 | grunt.util.async.concatSeries(files, function(file, next) {
48 | grunt.verbose.writeln('[react] Compiling ' + file.cyan + ' --> ' + destFile.cyan);
49 |
50 | try {
51 | compiled.push(transform(grunt.file.read(file), options));
52 | } catch (e) {
53 | grunt.event.emit('react.error', file, e);
54 | grunt.fail.warn(e);
55 | } finally {
56 | next();
57 | }
58 | }, function () {
59 | grunt.file.write(destFile, compiled.join(grunt.util.normalizelf(grunt.util.linefeed)));
60 | grunt.verbose.writeln('[react] File ' + destFile.cyan + ' created.');
61 | nextFileObj();
62 | });
63 |
64 | }, done);
65 | });
66 | };
67 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | /*
2 | * grunt-react
3 | * https://github.com/ericclemmons/grunt-react
4 | *
5 | * Copyright (c) 2013 Eric Clemmons, contributors
6 | * Licensed under the MIT license.
7 | */
8 |
9 | 'use strict';
10 |
11 | module.exports = function(grunt) {
12 |
13 | // Project configuration.
14 | grunt.initConfig({
15 | jshint: {
16 | all: [
17 | 'Gruntfile.js',
18 | 'tasks/*.js',
19 | '<%= nodeunit.tests %>'
20 | ],
21 | options: {
22 | jshintrc: '.jshintrc'
23 | },
24 | },
25 |
26 | // Used for testing the transformer
27 | browserify: {
28 | options: {
29 | transform: [ require('./main').browserify ]
30 | },
31 | module: {
32 | src: 'test/fixtures/browserify/module.jsx',
33 | dest: 'tmp/browserify/module.js'
34 | }
35 | },
36 |
37 | // Before generating any new files, remove any previously-created files.
38 | clean: {
39 | tests: ['tmp']
40 | },
41 |
42 | // Configuration to be run (and then tested).
43 | react: {
44 | single_js_files: {
45 | files: {
46 | 'tmp/js/fixture.js': 'test/fixtures/js/fixture.js',
47 | 'tmp/js/fixture-jsx.js': 'test/fixtures/js/fixture-jsx.js'
48 | }
49 | },
50 | single_jsx_files: {
51 | files: {
52 | 'tmp/jsx/fixture.js': 'test/fixtures/jsx/fixture.jsx',
53 | 'tmp/jsx/nested/fixture-js.js': 'test/fixtures/jsx/nested/fixture-js.jsx'
54 | }
55 | },
56 | multiple_jsx_files: {
57 | files: {
58 | 'tmp/multiple_jsx_files.js': ['test/fixtures/jsx/fixture.jsx', 'test/fixtures/jsx/nested/fixture-js.jsx']
59 | }
60 | },
61 | dynamic_mappings: {
62 | files: [
63 | {
64 | expand: true,
65 | cwd: 'test/fixtures',
66 | src: ['**/*.js'],
67 | dest: 'tmp/dynamic_mappings/js',
68 | ext: '.js'
69 | },
70 | {
71 | expand: true,
72 | cwd: 'test/fixtures',
73 | src: ['**/*.jsx'],
74 | dest: 'tmp/dynamic_mappings/jsx',
75 | ext: '.js'
76 | }
77 | ]
78 | }
79 | },
80 |
81 | // Unit tests.
82 | nodeunit: {
83 | tests: ['test/*_test.js']
84 | },
85 |
86 | });
87 |
88 | // Actually load this plugin's task(s).
89 | grunt.loadTasks('tasks');
90 |
91 | // These plugins provide necessary tasks.
92 | grunt.loadNpmTasks('grunt-browserify');
93 | grunt.loadNpmTasks('grunt-contrib-jshint');
94 | grunt.loadNpmTasks('grunt-contrib-clean');
95 | grunt.loadNpmTasks('grunt-contrib-nodeunit');
96 |
97 | // Whenever the "test" task is run, first clean the "tmp" dir, then run this
98 | // plugin's task(s), then test the result.
99 | grunt.registerTask('test', ['clean', 'react', 'browserify', 'nodeunit']);
100 |
101 | // By default, lint and run all tests.
102 | grunt.registerTask('default', ['jshint', 'test']);
103 |
104 | };
105 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [DEPRECATED] grunt-react
2 |
3 | [](https://travis-ci.org/ericclemmons/grunt-react)
4 | [](https://david-dm.org/ericclemmons/grunt-react)
5 | [](https://david-dm.org/ericclemmons/grunt-react#info=devDependencies&view=table)
6 |
7 | > Grunt task for compiling [Facebook React](http://facebook.github.io/react/)'s JSX templates into JavaScript.
8 |
9 | It also works great with `grunt-browserify`!
10 |
11 | - - -
12 |
13 | ## DEPRECATION NOTICE
14 |
15 | On **June 12th, 2015**, the React team has deprecated `JSTransform` and `react-tools`, which this project uses:
16 | > http://facebook.github.io/react/blog/2015/06/12/deprecating-jstransform-and-react-tools.html
17 |
18 | Please use [`grunt-babel`](https://github.com/babel/grunt-babel) instead.
19 |
20 | - - -
21 |
22 | ## Getting Started
23 | This plugin requires Grunt `~0.4.0`
24 |
25 | If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:
26 |
27 | ```shell
28 | npm install grunt-react --save-dev
29 | ```
30 |
31 | Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
32 |
33 | ```js
34 | grunt.loadNpmTasks('grunt-react');
35 | ```
36 |
37 | ## The "react" task
38 |
39 | ### Overview
40 | In your project's Gruntfile, add a section named `react` to the data object passed into `grunt.initConfig()`.
41 |
42 | ```js
43 | grunt.initConfig({
44 | react: {
45 | single_file_output: {
46 | files: {
47 | 'path/to/output/dir/output.js': 'path/to/jsx/templates/dir/input.jsx'
48 | }
49 | },
50 | combined_file_output: {
51 | files: {
52 | 'path/to/output/dir/combined.js': [
53 | 'path/to/jsx/templates/dir/input1.jsx',
54 | 'path/to/jsx/templates/dir/input2.jsx'
55 | ]
56 | }
57 | },
58 | dynamic_mappings: {
59 | files: [
60 | {
61 | expand: true,
62 | cwd: 'path/to/jsx/templates/dir',
63 | src: ['**/*.jsx'],
64 | dest: 'path/to/output/dir',
65 | ext: '.js'
66 | }
67 | ]
68 | }
69 | },
70 | })
71 | ```
72 |
73 | ### Options
74 |
75 | These options are passed to react-tools.
76 |
77 | #### options.extension
78 | Type: `String`
79 | Default value: `js`
80 |
81 | Extension of files to search for JSX-syntax & convert to JS.
82 |
83 | #### options.ignoreMTime
84 | Type: `Boolean`
85 | Default value: `false`
86 |
87 | Speed up compilation of JSX files by skipping files not modified since last pass.
88 |
89 | #### options.harmony
90 | Type: `Boolean`
91 | Default value: `false`
92 |
93 | Turns on JS transformations such as ES6 Classes.
94 |
95 | #### options.sourceMap
96 | Type: `Boolean`
97 | Default value: `false`
98 |
99 | Append inline source map at the end of the transformed source
100 |
101 | Turns on JS transformations such as ES6 Classes.
102 |
103 | #### options.es6module
104 | Type: `Boolean`
105 | Default value: `false`
106 |
107 | Allows use of ES6 module syntax. This option does not affect ES6 transformations enabled or disabled by options.harmony.
108 |
109 | - - -
110 |
111 | ### Recommended Usage
112 | Writing your applications in CommonJS format will allow you to use [Browserify](http://browserify.org/) to
113 | concatenate your files. Plus, with `grunt-react`, your templates will be converted from JSX to JS *automatically*!
114 |
115 | First, install `grunt-browserify` to your project:
116 |
117 | ```shell
118 | npm install grunt-browserify --save-dev
119 | ```
120 |
121 | Second, register `grunt-browserify` in your Gruntfile:
122 |
123 | ```js
124 | grunt.loadNpmTasks('grunt-browserify');
125 | ```
126 |
127 | Finally, add the following task to your Gruntfile:
128 |
129 | ```js
130 | browserify: {
131 | options: {
132 | transform: [ require('grunt-react').browserify ]
133 | },
134 | app: {
135 | src: 'path/to/source/main.js',
136 | dest: 'path/to/target/output.js'
137 | }
138 | }
139 | ```
140 |
141 | You've successfully concatenated your JSX & JS files into one file!
142 |
143 | - - -
144 |
145 | ### Usage Examples
146 |
147 | #### Recommended Options
148 |
149 | I recommend naming your React Components with the `.jsx` extension:
150 |
151 | ```js
152 | /**
153 | * @jsx React.DOM
154 | */
155 |
156 | var MyComponent = React.createClass({
157 | ...
158 | render: function() {
159 | return (
160 | Howdy
161 | );
162 | }
163 | });
164 | ```
165 |
166 | Then, set your Gruntfile to use:
167 |
168 | ```js
169 | grunt.initConfig({
170 | react: {
171 | files: {
172 | expand: true,
173 | cwd: 'path/to/jsx/templates/dir',
174 | src: ['**/*.jsx'],
175 | dest: 'path/to/output/dir',
176 | ext: '.js'
177 | }
178 | },
179 | })
180 | ```
181 |
182 | This will output the following:
183 |
184 | ```js
185 | /**
186 | * @jsx React.DOM
187 | */
188 |
189 | var MyComponent = React.createClass({displayName: 'MyComponent',
190 | render: function() {
191 | return (
192 | React.DOM.p(null, "Howdy")
193 | );
194 | }
195 | });
196 | ```
197 |
198 | ## Troubleshooting
199 |
200 | If you encounter a file compilation error, you can run `grunt --verbose` to see specifics about each file being transformed.
201 |
202 | ## Contributing
203 | In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/).
204 |
205 | ## Release History
206 |
207 | - v0.12.2
208 | + Move verbose logging to `grunt --verbose` ([#53](https://github.com/ericclemmons/grunt-react/pull/53))
209 |
210 | - v0.12.1
211 | + Fix issue with Browserify ([#46](https://github.com/ericclemmons/grunt-react/pull/49))
212 |
213 | - v0.12.0
214 | + Update all `dependencies` & `devDependencies`
215 |
216 | - v0.11.0
217 | + Update `react-tools` to `v0.13.0` ([#45](https://github.com/ericclemmons/grunt-react/pull/45))
218 |
219 | - v0.10.0
220 | + Update `react-tools` to `v0.12.0` ([#40](https://github.com/ericclemmons/grunt-react/pull/40)).
221 | (See release notes: http://facebook.github.io/react/blog/2014/10/28/react-v0.12.html)
222 |
223 | - v0.9.0
224 | + Continue compilation despite error. ([#31](https://github.com/ericclemmons/grunt-react/pull/31))
225 | - v0.8.4
226 | + Add support for `harmony` via additional options. ([#32](https://github.com/ericclemmons/grunt-react/pull/32))
227 | - v0.8.3
228 | + Update to `react-tools` at `^v0.11.0` ([#33](https://github.com/ericclemmons/grunt-react/pull/33))
229 | - v0.8.2
230 | - Emit `react.error` for Growl & other notifications ([#23](https://github.com/ericclemmons/grunt-react/pull/23))
231 | - v0.8.1
232 | - Throw a proper error when React fails ([#25](https://github.com/ericclemmons/grunt-react/pull/25))
233 | - v0.8.0
234 | - Update to React v0.10.0 ([#27](https://github.com/ericclemmons/grunt-react/pull/27))
235 | - v0.7.0
236 | - Update to React v0.9.0 ([#24](https://github.com/ericclemmons/grunt-react/pull/24))
237 | - v0.6.0
238 | - Task changes to allow for flexible file options as found in the `grunt-contrib-*` projects.
239 | - Taking hints from `grunt-contrib-less` to allow for compiling single files separately, dynamic mappings and combining.
240 | - Removed `extension` option as this is determined by flexible file matching now.
241 | - Removed MT time ignoring, this can be easily done with the `grunt-newer` plugin.
242 | - Errors are ignored and skipped by default to match how other grunt plugins work.
243 | - v0.5.2
244 | - `grunt.fail` instead of throwing an error ([#11](https://github.com/ericclemmons/grunt-react/pull/11))
245 | - v0.5.1
246 | - Add file name to errors ([#15](https://github.com/ericclemmons/grunt-react/pull/15))
247 | - v0.5.0
248 | - Update to `react-tools` `~v0.5.0`
249 | - v0.4.1
250 | - Add logging to make it easier catch errors, thanks to @lorefnon ([#5](https://github.com/ericclemmons/grunt-react/pull/5))
251 | - v0.4.0
252 | - Update to react-tools ~0.4.0, thanks to @Agent-H ([#3](https://github.com/ericclemmons/grunt-react/pull/3))
253 | - v0.3.0
254 | - No longer uses `bin/jsx`, thanks to @petehunt ([#2](https://github.com/ericclemmons/grunt-react/pull/2))
255 | - Add `ignoreMTime` option
256 | - v0.2.0
257 | - Add `require('grunt-react').browserify()` and `require('grunt-react').source()` for compiling within Node
258 | - v0.1.0
259 | - Initial release
260 |
261 |
262 | [](https://bitdeli.com/free "Bitdeli Badge")
263 |
--------------------------------------------------------------------------------