Template and code in same file for Meteor, why not?


#1

It’s really not convenient to switch between files when creating components for an app.

For component we have usually code with some template, some helpers, onRendered/onCreated hooks and events.

<template name="myComponent">
  <a href="#">Click me <i class="tooltipped fa fa-square" data-toggle="tooltip" data-placement="top" title="{{whateverTheTooltipShoudSay}}"></i></a>
</template>

Template.myComponent.onRendered(function() {
  this.$('.tooltipped').tooltip();
})

Template.myComponent.events({
  'click a': function() {
     // Some code here
  }
});

After trying ReactJS and their .jsx approach I started ask myself why not to put all of them in one file? Everything what is in <template name"">...</template> it’s HTML, other parts are JS. It shouldn’t be hard to create parser which would separate such file into two automatically, but it would be much easier to edit code while working with small components.

What’s your thought?


#2

I don’t remember the name right now, but I think someone put out a package that enables just this, or at least showed a proof of concept.

One issue though is syntax highlighting in your text editor. I’m not sure Sublime Text would be smart enough to know where the HTML ends and where the JavaScript starts?


#3

I made a package that does this numtel:template-from-string


#4

I agree that putting the two languages (one for the logic, and one for the view) into the same file, even if it still sounds silly to a lot of experienced developers, is an attractive idea especially when you start to think in term of UI “components”. For those who are not convinced by this, I recommended watching the infamous Rethinking best practices talk by Pete Hunt from the ReactJS team, in which he’s explaining what we really mean when we say that we want “separation of concerns”.

So then if you decide to merge these two languages in one file you can have different approaches. One would be to create a new language, aka JSX, which is basically a mix of JavaScript and HTML that provide a convenient way for JavaScript functions to return HTML elements. One drawback here being that if you want to use any other language combination (coffeescript, typescript, purescript, jade) you have to create a new compiler for this new language combination.

As @numtel pointed out, ES6 template string come to the rescue here. Ideally we shouldn’t even call something like Template.fromString but instead use a template string language prefix:

class myComponent {
  whoiam() {
    return 'World';
  }

  renderFunction() {
    return html`
      <h1>Hello #{world}</h1>
    `;
  }
}

In the example above you could replace the html word by jade for instance.

One other approach is the one you took @chompomonim in the OP, which is using the view language (HTML, Jade) as the “root” language. This is also the road RiotJS took with the slight difference that they wrap the JavaScript code in a script tag:

<h1>Hello #{whoiam}</h1>

<script>
  this.whoiam = function() {
    return 'World';
  };
</script>

I tend to think that this second approach would work pretty well with Blaze.

Merging the component logic and view in the same file could also be an opportunity to re-consider where you define event handling. The Blaze 2 proposal could allow us to define events without css selector matching by defining them with the template language instead of using an “event map” — this is also what ReactJS and other do.

I’m genuinely curious what others think of this. In the meantime if you are using Sublime Text and want a quick way to switch between a template view and its associated logic I can’t recommend enough using the “Jump to definition” shortcut provided by Slava’s plugin. Also if you are using coffeescript+jade, Pierre-Éric created a package to use them in a single file (is this still maintained?).


#5

I honestly don’t see any reason to put multiple languages into one file unless it gives you language benefits.

For example: in JSX, there is actually a benefit of mixing up of XML and JS - you can reference components and classes just like any other JS variables. This is quite powerful and clearly useful - aliasing, scoping, transformations. All of those become simpler and more familiar with JSX as opposed to a pure-template language like Spacebars.

But putting Spacebars, a templating language designed to look as close to regular HTML as possible, doesn’t benefit from being at the same file as JS or even CSS. I think rather then putting things into one file, just keep 3 relative files in the same folder (a component called “whoami” would have files whoami/whoami.html, whoami/whoami.js whoami/whoami.less). If your text editor is not good enough to switch between these 3 files easily, I would recommend you extending your text editor ;). In Vim, I have no problems writing mappings to switch between 3 of these, in Sublime, I would probably write a plugin.