Updated fork of dalgard:jade, compatible with imports and local packages

Hi there,
There’s been a couple of posts here and dalgard:jade users have probably noticed the issues related to caching and building; imports not working and templates not found in local packages. The issues are related to the fork being off an old point in time of mquandalle:jade with the 0.9 build system and despite dalgard’s best intentions hasn’t been kept up to date, so we decided as a christmas gift to publish it as a useable package from our local fork with the master updates merged in.

Just meteor add pacreach:jade to try it out.

Package on Atmosphere: https://atmospherejs.com/pacreach/jade

You can use it as a drop-in replacement for dalgard:jade. I’ve tested imports and local packages and both seem to work fine. Our company is quite invested in Meteor, Blaze and ViewModel and we enjoy using Jade, so we have an interest to keep things up to date if PRs are your fancy. Github is at https://github.com/pac-reach/meteor-jade/.

Happy holidays!

3 Likes

Thank you very much for this package! I am trying to use the Jade, Stylus, CoffeeScript trio with Blaze and Bootstrap and it is great news that someone took care of merging the lastest versions of mquandalle:jade and dalgard:jade. I have tried pacreach:jade it on my few toy apps and it seems to work very well!

Is your company using CoffeeScript? If so how do you deal with current pending Meteor bug https://github.com/meteor/meteor/issues/8138 which prevents source maps to be generated for CoffeeScript source code files not located at the top level of the app folder? This prevents one to leverage tools such as WebStorm, VSCode and Google Chrome Dev Tools, to debug any CoffeeScript Meteor app that goes beyond not absolutely trivial demos in which all files can remain at the top-level of the folder app structure.

I have started to study the Blaze ViewModel last week. It seems to be a fairly thick layer that requires a number of other packages and makes debugging more difficult than plain Blaze since one has to track exceptions root causes inside the viewmodel function call stack. So for its use to make up for this additional debugging complexity, it must allow writing much more concise code. But I am not sure I understand what it does beyond just grouping the helpers and event handlers of a given Blaze template into an single object instead of two function lists.

Could you share your insights on what led your company to adopt the viewmodel instead peerlibrary:blaze-componennts or just plain Blaze with the conventions described in:

Also, what router do you use with the ViewModel? The flow router?

Thanks!

No, we’re developing in vanilla.

We wrote the initial version of our medium-sized application in pure Blaze. The amount of code needed to achieve certain things wasn’t very fun, you end up repeating yourself a lot, and the syntax to make some things happen is awkward (var template = Template.instance(); in every helper, etc.) We looked at components but personally I feel MVC is kind of awkward in a free-form language like JavaScript. A lot of our code is structured in plain old JavaScript objects which fits ViewModel’s MVVM approach. Basically you write a lot less code in ViewModel once you get your head wrapped around it well, and making reactive dependencies is a lot clearer.

For us the value goes way beyond that. You can reuse and feed helpers into each other, write less confusing dependencies (by using this.foo.value and this.foo.depend() instead of this.foo()), share and inherit data effortlessly between views… ViewModel also gives freedom to structure your views as you see fit which fits us - you can use parent/child inheritance, finds, or just write your own references in whatever state controller you like depending on what the correct approach for any component should be. We also use signals and have extended several things for ViewModel as well and have written our own completely custom form components for Blaze/VM.

We use both FlowRouter and iron:router (several applications), with meteorhacks:subs-manager and ccorcos:subs-cache for subscriptions.

1 Like

Does your package allow for inclusion of templates named with a hyphen, eg:
+detailsPane-noCalls
dalgard:jade throws on it:
=> Errors prevented startup:


   While building the application:
   components\detailsPane\client\detailsPane.jade: Jade syntax error:
   Expected identifier, number, string, boolean, null, or a sub expression
   enclosed in "(", ")"
   {{>detailsPane-noCalls }}
   ^
   <runJavaScript-58>:73:14: Cannot read property 'head' of undefined
   (compiling components/detailsPane/client/detailsPane.jade) (at
   fileModeHandler)

I woud’ve tested it myself but i’m still on meteor 1.1 and it fails miserably when I add your package…

This is from the React docs but it applies equally well to the Blaze version:

Is it just syntactic sugar?

Syntactic sugar is nice but it’s far from being what reduces your code the most. It’s all the ceremonies, complex patterns, and runarounds you don’t have to deal with anymore. To give an example, one of the UI boogeymen is state that is shared between two or more components. The two most common ways of dealing with this situation are:

  1. Let components reference one another so they can get the state they need. The problem here is that you want to share a banana but you end up sharing the gorilla holding the banana, and keeping track of the entire gorilla tribe.

  2. Store the entire state of the application in a central place. You no longer need to keep track of the gorillas, but now you need a jeep, a machete, and know your way through the entire jungle just to share a banana.

ViewModel takes the simple approach of only sharing the state that needs to be shared. Components don’t reference one another, you keep the shared state to a minimum, and components are explicit about which state can be modified by someone else. It works like this:

First define a container for the state that needs to be shared

ViewModel.share({
  house: {
    address: ''
  }
})

In this case the container is ‘house’ and the state to share is ‘address’.

Now you can declare that a component will share the house properties with other components:

ComponentA({
  share: 'house',
  render() {
    <input b="value: address" />
  }
})
ComponentB({
  share: 'house',
  render() {
    <div b="text: address" />
  }
})

Now components A and B have access to the same address and nothing else. You use them as normal and treat address as just another property of the components.

Someone once responded with “big deal, you’re just doing a simpler version of the singleton service pattern of Angular”… to which I responded “Yes! that is exactly what I’m doing!”