I think you’re right about the added Jade frustration. I’m trying to embrace the new React direction, but I really don’t want to have to go back to vanilla HTML… it feels like the dark ages.
Same here, my XHTML days are long gone. You could decide to use CoffeScript, that gives really nice React templates: see https://medium.com/@chetcorcos/shindig-react-js-coffeescript-c79d01197203#.n92cdftmp
(thanks to @ccorcos)
I tried @ccorcos pure CoffeeScript solution a few weeks ago. It is very clever but IMHO it is not as convenient as the jade syntax. You have to write className
everywhere and it has the same level of indentation as the tags it contains, I don’t have a good feeling about that…
Class and is annoying no so I’ve been using react-hyperscript lately. Plus it’s compatible with other vdom libraries
No easy to setup Jade implementation is a stopper in React for me too.
And my Blaze templates are shorter than many React examples and open source apps I’ve seen, so the “React forces you to write a lot smaller components” argument is not my case.
I just found this old Sashko quote…
By the way I tried Vue instead of React but Jade templates are not working “out of the box” inside components : http://forum.vuejs.org/topic/2098/meteor-1-3-and-vue/8
Does anyone have any success with the ‘react-jade’ package in Meteor 1.3 final or does the Sashko quote mean there is currently no solution for using Jade with React on the client?
I haven’t tried, but this should work fine now in Meteor 1.3:
In proj root:
$ npm install --save react-jade
In your files:
import React from 'react';
import jade from 'react-jade';
var TodoList = React.createClass({
render: jade`
ul
each item in this.props.items
li= item
`
});
along with the rest of the examples from https://github.com/pugjs/react-jade.
I tried but I get this error on the client when importing jade from ‘react-jade’:
modules.js:52242TypeError: fs.realpathSync is not a function. (In 'fs.realpathSync(path.join(path.dirname(__filename), file))', 'fs.realpathSync' is undefined)
My NPM package.json consists of: meteor-node-stubs, react, react-dom and react-jade.
@morganpattens I had the same error in issue 6035.
fs
module is server only so on client it is replaced by an empty shell stub. What Sashko said seems to be the only solution.
By the way I switched to Meteor + webpack + Vue and now I can use jade and coffeescript and everything I want inside my Vue single file components instead of obeying facebook’s jsx syntactic diktat.
Weird… Jade (or Pug as it’s now called) and React are two of the most popular things in Node land: 10,000+ and 39,000+ stars on Github respectively. Still, few people seem to be interested in joining the two?
I am a big fan of Jade… err Pug… wtf, but I stopped wishing for react-jade after a while because my render code fits on one page. I went scouring for my largest compoent and found this:
export const CharCreation = ({
player,
onCompleted,
onCancelled,
onChangeName,
onChangeGender,
onSetDifficulty,
onChangeAttribute
}) => (
<div className="ui middle aligned center aligned grid">
<div className="ui one column">
<div className="ui stacked vertical segment">
<div className="ui vertical segment">
<div className="ui labeled fluid input">
<div className="ui label">Character name:</div>
<input
type="text" name="name" placeholder="What word did your mother utter as you came kicking and screaming into this world?"
onChange={(e) => onChangeName(e.target.value)}
value={player.name}
/>
</div>
</div>
<Attributes attributes={player.attributes} onChangeAttribute={onChangeAttribute}/>
<div className="ui vertical segments">
<div className="ui vertical segment">Character Gender</div>
<div className="ui vertical segment">
<Gender gender={player.gender} onChangeGender={onChangeGender}/>
</div>
</div>
<GameDifficulty difficulty={player.difficulty} setDifficulty={onSetDifficulty}/>
<div className="ui button primary" onClick={() => onCompleted(player)}>Ok</div>
<div className="ui button" onClick={onCancelled}>Cancel</div>
<div className="ui button">View Icon</div>
<div className="ui button">Help</div>
</div>
</div>
</div>
);
That’s my biggest component and it’s 37 lines. Whilst I agree that Jade… f**k, Pug, would make it much prettier to the eye, cognitively, it almost makes no difference.
When I was doing blaze pages, the typical html -> jade transformation would be something like 400 lines to 200 lines and that takes alot of the cognitive load off traversing the nested elements, but with react, it’s not a big difference.
Here’s the Attributes component (27 lines):
const Attributes = ({attributes, onChangeAttribute}) => (
<div>
{
_.map(attributes, function (attribute, i) {
let attrName = attribute.name;
return (
<div className="ui segments" key={i}>
<div className="ui segment left aligned">
<h4 className="ui header">{attrName}:</h4>
<div className="ui indicating progress" data-percent={attribute.value}>
<div className={`bar test-${attrName}-bar`} style={{width:attribute.value+'%', minWidth:0}}></div>
<div className={`label test-${attrName}-description`}>{getAttributeDescription(attrName, attribute.value)}</div>
</div>
{attrName !== "Available" ?
buttons(onChangeAttribute, attrName) : ''}
</div>
</div>
)
})
}
</div>
);
Game difficulty (19 lines):
const GameDifficulty = ({
difficulty,
setDifficulty
}) => {
return (
<div className="four ui buttons">
{difficultyLevels.map(function (level, i) {
return (
<div
className={classNames('ui icon button', {active:difficulty === level.level}) }
onClick={() => setDifficulty(level.level)}
key={i}>
<div><i className={level.icon} /></div>
<label>{DifficultyLevel[level.level]}</label>
</div>
);
}, this)}
</div>
)
};
Gender (19 lines):
const Gender = ({
gender,
onChangeGender
}) => (
<div className="equal width column">
<div className="ui large buttons">
<div className={classNames("ui labeled icon button", {active:gender === 'male'})}
onClick={() => {onChangeGender('male');}}>
<i className="large male icon"/>
Male
</div>
<div className="or"></div>
<div className={classNames("ui labeled icon button", {active:gender === 'female'})}
onClick={() => {onChangeGender('female')}}>
<i className="large female icon"/>
Female
</div>
</div>
</div>
);
All together it renders this page:
http://cotwmtor.meteorapp.com/new
Not the prettiest but a fair amount of interactions for 65 lines of render code that I can look at/debug separately.
So I think people haven’t been focused on this because Jade solves a problem of templates and React doesn’t have templates.
IMHO jsx files syntax is the worst thing that happened to computer science since PHP.
Because I had to refactor my code for Meteor 1.3 anyway, I decided to switch from React to the amazing Vue (+webpack). Now I can use ultra-readable single file components with all the pre-processors I want, with hot reloads and all.
Good luck debugging/maintaining jsx spaghetti code all, jade/pug or not.
With all due respect @mordrax, I think that’s actually an example of how I not want my code to look like. Also, in my opinion, the size of the components do not depend on the chosen templating language. One can easily break up their app in small components independent of what templating language is used (although React enforces this more unlike Blaze).
@laurentpayot: yes Vue.js is very nice, but it’s not mentioned in the guide or tutorial (sadly). Mindshare / community is a big factor too - I wonder if it will still be actively developed in a few years.
Currently I’m testing to use React with Coffeescript the “Chet Corcos” way. It looks quite nice IMHO and features Jade style indenting. Step 2 of the Meteor tutorial would look like this (just a snippet). I’ll publish the full tutorial in React - Coffeescript when I finish it.
class Task extends Component
render: ->
li {}, @props.task.text
Task.propTypes =
task: PropTypes.object.isRequired
class App extends Component
getTasks: ->
[
{ _id: 1, text: 'This is task 1' }
{ _id: 2, text: 'This is task 2' }
{ _id: 3, text: 'This is task 3' }
]
renderTasks: ->
@getTasks().map (task) =>
Task key: task._id, task: task
render: ->
div className: 'container',
header {},
h1 {}, "Todo List"
ul {}, @renderTasks()
For the options being at the same level as the content, I circumvent this by putting the options on the same line as the tag / component:
div className: 'container', id: 'main',
h1 {}, "This is a header"
Hmm, with Hyperscript you lose the className but you’ll have a “h” on every line. What’s the lesser evil? Both are still no Jade…
@ccorcos why is the above way not compatible with other vdom libraries?
Wow, after a second look, Vue.js sure looks like a game changer! I’ve decided to dive into that and research if it’s the best solution for me (and my team). Its decisions are so much more logical to me than React! I also see it has more stars on Github than Angular and Ember, so I think it’s here to stay. Big thumbs up to Evan You and its team!
@morganpattens An easy way to start using Vue + webpack (to get single files components): https://iamlawrence.me/more-vue-and-meteor
What I’m using to integrate Vue to Meteor: https://github.com/almini/vue-meteor
Look em up: