14 déc. 2014

Put your HTML, CSS and JS in a single file using Meteor

It could be a bit cumbersome to switch from your HTML template file to your JS logic to your CSS stylesheets. I consider that the method exposed hereafter isn't tailored for novice users. Still, it can help you understanding how Meteor works.

Actually, the method is quite simple. It all drills down to how the HTML files are generated using Blaze, the reactive UI. During the build process of your app, Meteor builds JS file out of your HTML template file and exposes / sends them to your clients. This method short-circuits the build process. If you write directly your HTML using Blaze, the reactive UI, you remove the HTML file. The second step is to use JS to write your CSS. Here, I use the CSSC package for Meteor.

Here is the results for an equivalent of the default Meteor  app.
You could think of it as a small component into a larger app.

And now, here is the code to create this small component. As promised, a single file, in CoffeeScript for brevity:
# Render the body when Meteor is ready
Meteor.startup Template.body.renderToDocument

# HTML
# ----
# Instantiate a main template
Template['main'] = new Template 'Template.main', ->
  # Return a table of DOM elements
  [
    # A 'p' tag with a reactive variable
    HTML.P 'Count ', Blaze.View => Spacebars.mustache @lookup 'count'
    # A 'button' tag
    HTML.BUTTON '+1'
  ]

# JS logic
# --------
# Declare a reactive variable
Session.set 'count', 0
# Expose the reactive variable to the template
Template.main.helpers 'count': -> Session.get 'count'
# Handle template events
Template.main.events
  'click button': (e,t) ->
    e.preventDefault()
    Session.set 'count', 1 + Session.get 'count'
# Add the template to the document's body
Template.body.addContent ->
  Spacebars.include @lookupTemplate 'main'

# CSS
# ---
# Instantiate a stylesheet
css = new CSSC
# Style the body and the text
css.add 'body',
  margin: CSSC.px 20
  backgroundColor: CSSC.navy
  color: CSSC.aqua
# Style the button
.add 'button',
  width: CSSC.px 50
  border: "#{CSSC.px 1} #{CSSC.maroon} solid"
  borderRadius: CSSC.px 3
  backgroundColor: CSSC.red
  color: CSSC.yellow

If you want to test it yourself, here is the set of required commands:
# Start by creating a simple app.
meteor create singlefile
cd singlefile
# Remove the Meteor's default app.
rm *
# We are going to focus only on the front.
# Our single file is being placed in the client directory.
mkdir client
# Add the necessary packages.
meteor add coffeescript pierreeric:cssc pierreeric:cssc-colors pierreeric:cssc-normalize
# Create your single file and start editing it.
touch client/main.coffee

At the beginning, it may look a bit weird. But this could be useful from time to time. Note that you can put some nice additions to this sample. For instance, instead of using the events helpers which will scan you DOM for the button, you could directly affect the click event logic when you are creating the button element. If you are looking for performances on some parts of your app, this could be an interesting technic.