What are the best practices for structuring a large Meteor app with many HTML template files? [closed]
Asked Answered
N

14

165

In all the examples (leaderboard, wordplay, etc.) they have one single HTML template file. Is there some large open source Meteor project with many different HTML template files we can use as a best practice example? Doesn't seem practical to put everything a large app needs all in one template file.

Neckcloth answered 12/4, 2012 at 11:50 Comment(3)
meteor is new stuff ,I havenot find anything related best practise about this .I also expect some guildline about thisKerbela
Have you read the part about Structuring your application in the manual? There is some explanation about the scanning and concatenating of HTML files.Caramelize
Meteor official guide suggests a very cool file structure. Check here: guide.meteor.com/structure.html#javascript-structurePurpose
P
16

Lump it all together! From the docs:

> HTML files in a Meteor application are treated quite a bit differently
> from a server-side framework. Meteor scans all the HTML files in your
> directory for three top-level elements: <head>, <body>, and
> <template>. The head and body sections are seperately concatenated
> into a single head and body, which are transmitted to the client on
> initial page load.
> 
> Template sections, on the other hand, are converted into JavaScript
> functions, available under the Template namespace. It's a really
> convenient way to ship HTML templates to the client. See the templates
> section for more.
Plott answered 13/4, 2012 at 22:22 Comment(9)
This is the poster's concern though. Lumping is ok, but you can see what happens with Asana - it requires a load screen while it downloads > 1MB of client code. That's not acceptable for a lot of sites. We're going to see if we can't maybe do some of the loading piecemeal after main screen load, but I'm skeptical right now. I think its going to need to be a feature to break things up a bit.Uterus
This answer is the #1 result in google but it's credibly outdated. Other, future visitors like me; look below!Garda
As of 1.1.0.2, the simple todo app they demo transfers 1.7MB of files when you hard reload with browser cache removed. This is unacceptable for a lot of use cases out there. :/ Things are much improved once the assets are cached, but on the first load, it's pretty brutal.Versus
Idea: use webpack, make bundles for things, lazy load them when needed.Angrist
yes Asana takes some time to load. Asana is also an incredibly well-done, reactive app in which users created 175 million tasks in 2014. Apps that load faster aren't always better. It takes a moment for apps to start up on your phone too. People will get used to it.Puzzlement
@MaxHodges: Re: "Apps that load faster aren't always better": Ceteris paribus, they are.Compline
@Compline Hence his use of the words "aren't always".Multiangular
@dudewad: I don't think so. He seems to be saying that increased speed is not always an improvement; at least, he doesn't seem to be claiming that Asana's strengths depend in any way on its relative slowness.Compline
'lib' is now 'imports' guide.meteor.com/structure.html#example-app-structureBuhr
L
275

As in the unofficial meteor faq, I think it pretty much explains how to structure a large app:

Where should I put my files?

The example apps in meteor are very simple, and don’t provide much insight. Here’s my current thinking on the best way to do it: (any suggestions/improvements are very welcome!)

lib/                       # <- any common code for client/server.
lib/environment.js         # <- general configuration
lib/methods.js             # <- Meteor.method definitions
lib/external               # <- common code from someone else
## Note that js files in lib folders are loaded before other js files.

collections/               # <- definitions of collections and methods on them (could be models/)

client/lib                 # <- client specific libraries (also loaded first)
client/lib/environment.js  # <- configuration of any client side packages
client/lib/helpers         # <- any helpers (handlebars or otherwise) that are used often in view files

client/application.js      # <- subscriptions, basic Meteor.startup code.
client/index.html          # <- toplevel html
client/index.js            # <- and its JS
client/views/<page>.html   # <- the templates specific to a single page
client/views/<page>.js     # <- and the JS to hook it up
client/views/<type>/       # <- if you find you have a lot of views of the same object type
client/stylesheets/        # <- css / styl / less files

server/publications.js     # <- Meteor.publish definitions
server/lib/environment.js  # <- configuration of server side packages

public/                    # <- static files, such as images, that are served directly.

tests/                     # <- unit test files (won't be loaded on client or server)

For larger applications, discrete functionality can be broken up into sub-directories which are themselves organized using the same pattern. The idea here is that eventually module of functionality could be factored out into a separate smart package, and ideally, shared around.

feature-foo/               # <- all functionality related to feature 'foo'
feature-foo/lib/           # <- common code
feature-foo/models/        # <- model definitions
feature-foo/client/        # <- files only sent to the client
feature-foo/server/        # <- files only available on the server

Find out more: Unofficial Meteor FAQ

Lobeline answered 23/10, 2012 at 21:35 Comment(10)
IMHO this is better than accepted answer. I will try it now.Climactic
for server, where should Meteor.startup locate?Climactic
Since 0.6.0, you are far better off avoiding that mess and running your app entirely out of smart packages. I go into a bit more detail in this blog post: matb33.me/2013/09/05/meteor-project-structure.htmlEaster
anyone have a clue where to put the mobile-config.js?Radiator
Thanks for the answer and the link to the unofficial-faq (I'm new in meteor's world), what do they mean by "common code from someone else" ?Thanks!Avenue
where should we put Meteor.subscribe? thanks :)Jetpropelled
appjitsu maintains a fairly comprehensive meteor best practices sample app on github that I have used to help structure some of my apps. It puts into practice what @Easter suggests with his blog post.Evocative
@Jetpropelled meteor subscribe goes in the on created for the template requiring the subscription in template.js.Faxon
@piedpiper meteor startup server stuff goes in environment.jsFaxon
As for meteor 1.3, I would say this is outdated due to ES6 module import. See meteor guide article on application structure: guide.meteor.com/structure.htmlGink
A
36

I agree with yagooar, but instead of:

client/application.js

Use:

client/main.js

main.* files are loaded last. This will help ensure that you do not have any load order issues. See the Meteor documentation, http://docs.meteor.com/#structuringyourapp, for more details.

Ailina answered 29/5, 2013 at 15:12 Comment(0)
T
26

Meteor was designed so you structure your app pretty much any way you want to. So if you don't like your structure, you can just move a file to a new directory, or even split one file into many pieces, and to Meteor its pretty much all the same. Just note the special treatment of client, server, and public directories as specified in the main documentation page: http://docs.meteor.com/.

Just lumping everything together in one HTML fill will certainly not emerge as a best practice.

Here's an example of one possible structure: in one of my apps, a discussion forum, I organize by module or "page type" (home, forum, topic, comment), putting .css, .html, and .js file for each page type together in one directory. I also have a "base" module, which contains common .css and .js code and the master template, which uses {{renderPage}} to render one of the other modules depending on the router.

my_app/
    lib/
        router.js
    client/
        base/
            base.html
            base.js
            base.css
        home/
            home.html
            home.js
            home.css
        forum/
            forum.html
            forum.js
            forum.css
        topic/
            topic.html
            topic.js
            topic.css
        comment/
            comment.html
            comment.js
            comment.css

You could also organize by function

my_app/
    lib/
        router.js
    templates/
        base.html
        home.html
        forum.html
        topic.html
        comment.html
    js/
        base.js
        home.js
        forum.js
        topic.js
        comment.js
    css/
        base.css
        home.css
        forum.css
        topic.css
        comment.css

I hope some more specific best practice structures and naming conventions do emerge though.

Tanishatanitansy answered 11/7, 2013 at 17:4 Comment(5)
This is my favorite answer. One of my favorite things about Meteor is that you can structure your files in a way that works for you.Yamen
I like this answer. I've been doing it the first way.Corpulent
related things should be close proximity to each other. My answer is like yours but backwards.Puzzlement
1.3 zapped lib in favor of imports guide.meteor.com/structure.html#example-app-structureBuhr
i don't see value in naming multiple files with a feature name like "topic". Now if you want to change the feature name to "category" you have to change multiple filenames. Just organize them under a single folder called "topic" and name them generically: events.js, views.html, styles, css, routes.js, etc. see my answer for more.Puzzlement
P
16

Lump it all together! From the docs:

> HTML files in a Meteor application are treated quite a bit differently
> from a server-side framework. Meteor scans all the HTML files in your
> directory for three top-level elements: <head>, <body>, and
> <template>. The head and body sections are seperately concatenated
> into a single head and body, which are transmitted to the client on
> initial page load.
> 
> Template sections, on the other hand, are converted into JavaScript
> functions, available under the Template namespace. It's a really
> convenient way to ship HTML templates to the client. See the templates
> section for more.
Plott answered 13/4, 2012 at 22:22 Comment(9)
This is the poster's concern though. Lumping is ok, but you can see what happens with Asana - it requires a load screen while it downloads > 1MB of client code. That's not acceptable for a lot of sites. We're going to see if we can't maybe do some of the loading piecemeal after main screen load, but I'm skeptical right now. I think its going to need to be a feature to break things up a bit.Uterus
This answer is the #1 result in google but it's credibly outdated. Other, future visitors like me; look below!Garda
As of 1.1.0.2, the simple todo app they demo transfers 1.7MB of files when you hard reload with browser cache removed. This is unacceptable for a lot of use cases out there. :/ Things are much improved once the assets are cached, but on the first load, it's pretty brutal.Versus
Idea: use webpack, make bundles for things, lazy load them when needed.Angrist
yes Asana takes some time to load. Asana is also an incredibly well-done, reactive app in which users created 175 million tasks in 2014. Apps that load faster aren't always better. It takes a moment for apps to start up on your phone too. People will get used to it.Puzzlement
@MaxHodges: Re: "Apps that load faster aren't always better": Ceteris paribus, they are.Compline
@Compline Hence his use of the words "aren't always".Multiangular
@dudewad: I don't think so. He seems to be saying that increased speed is not always an improvement; at least, he doesn't seem to be claiming that Asana's strengths depend in any way on its relative slowness.Compline
'lib' is now 'imports' guide.meteor.com/structure.html#example-app-structureBuhr
C
14

For everybody who's Googling on this topic:

The em command line tool (by EventedMind, the guys behind the Iron Router) is very helpful when rigging a new Meteor App. It will create a nice file/folder structure. If you already work on an app and want to re-organize it, just set up a new project with em and you can use it for inspiration.

See: https://github.com/EventedMind/em

And here: https://stackoverflow.com/questions/17509551/what-is-the-best-way-to-organize-templates-in-meteor-js

Cullan answered 6/5, 2014 at 23:14 Comment(2)
Note: this has been replaced with iron-cli (same author). See: github.com/iron-meteor/iron-cliAegrotat
Yes, 'em' has been renamed iron-cli, same tool.Cullan
I
11

I think the file structure from the Discover Meteor Book is really good and a solid start.

/app: 
 /client
   main.html
   main.js
 /server 
 /public
 /lib
 /collections
  • Code in the /server directory only runs on the server.
  • Code in the /client directory only runs on the client.
  • Everything else runs on both the client and server.
  • Files in /lib are loaded before anything else.
  • Any main.* file is loaded after everything else.
  • Your static assets (fonts, images, etc.) go in the /public directory.
Itin answered 14/2, 2014 at 19:20 Comment(0)
P
10

Create packages

Of course not everything fits in this approach, but in large apps you'll have a lot of functionalities that can be isolated. Anything separable and reusable fits in packages, the rest goes in the usual directory structure, as mentioned in other answers. Even if you don't make packages to avoid the overhead, structuring the code in a modular manner is a good idea (see these suggestions)

Meteor allows a fine-grained control over how you load your files (loading order, where: client/server/both) and what the package exports.

I especially find very handy the easy way to share the logic between the related files. Say, for example, you wanna make some util function and use in different files. You just make it "global" (without the var) and Meteor will wrap it in the namespace of the package, so it will not pollute the global namespace

Here's the official doc

Phreno answered 4/11, 2014 at 10:38 Comment(0)
G
6

After a while out from meteorjs coding, I'm happy to have some spare time to devote to building a fairly complex online game. App structure has been one of my first concerns, and it looks like several very good programmers have championed the package-only method of structuring an app, which allows you to loosely couple functionally distinct packages. There are other advantages to the approach, and 2 very good articles explaining the approach can be found here:

http://www.matb33.me/2013/09/05/meteor-project-structure.html http://www.manuel-schoebel.com/blog/meteorjs-package-only-app-structure-with-mediator-pattern

Gerlachovka answered 5/4, 2014 at 1:36 Comment(0)
P
6

We have a large project (probably one of the largest Meteor project anyone has built to date as it was in full-time development for 1.5 years). We use the same set of filenames in each view. It's very consistent and helps us quickly navigate to exactly what we are looking for:

  • events.js
  • helpers.js
  • templates.html
  • routes.js
  • styles.less
  • etc.

Looks like this in a project:


       ├── consolidationRequests
       │   ├── events.js
       │   ├── helpers.js
       │   ├── routers.js
       │   └── templates.html
       ├── customerSpoof
       │   └── routers.js
       ├── dashboard
       │   ├── events.js
       │   ├── helpers.js
       │   ├── onDestroyed.js
       │   ├── onRendered.js
       │   ├── routers.js
       │   └── templates.html
       ├── emailVerification
       │   ├── events.js
       │   ├── helpers.js
       │   ├── routers.js
       │   └── templates.html
       ├── loading
       │   ├── styles.css
       │   └── templates.html
       ├── mailbox
       │   ├── autoform.js
       │   ├── consolidationRequestConfirmation
       │   │   ├── events.js
       │   │   ├── helpers.js
       │   │   ├── onCreated.js
       │   │   ├── onRendered.js
       │   │   └── templates.html
       │   ├── events.js
       │   ├── helpers.js

Related templates are just stored together in the same file. Contents of view/order/checkout/templates.html shown collapsed here:

<template name="orderCheckout"></template>

<template name="paymentPanel"></template>

<template name="orderCheckoutSummary"></template>

<template name="paypalReturnOrderCheckout"></template>

We use subfolders when views get complex with lots of parts:

       ├── cart
       │   ├── addItem
       │   │   ├── autoform.js
       │   │   ├── events.js
       │   │   ├── helpers.js
       │   │   ├── onRendered.js
       │   │   ├── routers.js
       │   │   ├── styles.less
       │   │   └── templates.html
       │   ├── checkout
       │   │   ├── autoform.js
       │   │   ├── events.js
       │   │   ├── helpers.js
       │   │   ├── onRendered.js
       │   │   ├── routers.js
       │   │   └── templates.html
       │   └── view
       │       ├── autoform.js
       │       ├── deleteItem
       │       │   ├── events.js
       │       │   ├── helpers.js
       │       │   └── templates.html
       │       ├── editItem
       │       │   ├── autoform.js
       │       │   ├── events.js
       │       │   ├── helpers.js
       │       │   └── templates.html
       │       ├── events.js
       │       ├── helpers.js
       │       ├── onDestroyed.js
       │       ├── onRendered.js
       │       ├── routers.js
       │       ├── styles.less
       │       └── templates.html

We also develop with WebStorm, an extremely powerful and flexible editor for Meteor development. We find it immensely helpful when searching and organizing our code and working productively. Webstorm view

Happy to share details on request.

Puzzlement answered 26/8, 2015 at 9:27 Comment(7)
Please consider adding a comment if you think this answer can be improved.Puzzlement
Great post. Question: After all this time with meteor, you still recommend it for large projects, like an ecommerce? Or consider using a framework that may give you more "autonomy" as LoopBack or even Happi.Hadden
we love Meteor and do all new develop in it. Unfortunately I'm not familiar enough with LoopBack or Happi to have an opinion.Puzzlement
LoopBacks focus on end-to-end rest APIs make it sound like a traditional web development framework (like RoR). RoR got REST API right, but we feel Meteor got realtime right.Puzzlement
Thanks for the feedback. You organized the server side for features too?Hadden
There are a lot of boilerplates available in the market. Most of the users preferred to carry their own way. Someone has done the hard work too: medium.com/things-i-did-and-learned-today/…Heterozygous
thanks, I'll write about including the approach we took! I feel it's better to keep related files together, as we are doing and those approaches are not.Puzzlement
H
5

Use iron-cli scaffolding CLI. Does make things very easy.

https://github.com/iron-meteor/iron-cli

once installed. use iron create my-app to create a new project. It will create the following structure for you. You can also use this on existing projects. use iron migrate in project directory.

my-app/    
 .iron/    
   config.json    
 bin/    
 build/    
 config/    
   development/    
     env.sh    
     settings.json    
 app/    
   client/    
     collections/    
     lib/    
     stylesheets/    
     templates/    
     head.html    
   lib/    
     collections/    
     controllers/    
     methods.js    
     routes.js    
   packages/    
   private/    
   public/    
   server/    
     collections/    
     controllers/    
     lib/    
     methods.js    
     publish.js    
     bootstrap.js
Higdon answered 21/7, 2015 at 8:50 Comment(2)
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes.Gittern
@Gittern Shoutout to say that the answerer did edit his post. It now includes the essential data needed for the issue at hand.Rambo
V
4

I am following the mattdeom boilerplate format, which already includes the iron router & Model (Collection2) . See below :

client/                 # Client folder
    compatibility/      # Libraries which create a global variable
    config/             # Configuration files (on the client)
    lib/                # Library files that get executed first
    startup/            # Javascript files on Meteor.startup()
    stylesheets         # LESS files
    modules/            # Meant for components, such as form and more(*)
    views/              # Contains all views(*)
        common/         # General purpose html templates
model/                  # Model files, for each Meteor.Collection(*)
private/                # Private files
public/                 # Public files
routes/                 # All routes(*)
server/                 # Server folder
    fixtures/           # Meteor.Collection fixtures defined
    lib/                # Server side library folder
    publications/       # Collection publications(*)
    startup/            # On server startup
meteor-boilerplate      # Command line tool
Vibrant answered 17/6, 2015 at 10:48 Comment(0)
S
3

There are a lot of different approaches to structuring your app. For example if you have a router and different page templates, and inner each page template your have many page parts and so on, I would structure it depend on the semantics from higher > lower level..

For Example:

client
  views
    common
      header
        header.html
        header.js
        header.css
      footer
        footer.html
        footer.js
        footer.css
    pages
      mainPage
        mainPage.html
        mainPage.js
        mainPage.css
        articles
          articles.html
          articles.js
          articles.css
        news
          news.html
          news.js
          news.css
     ...

Of course, you could put your news templates in the common folder, as you could use your news template on different pages.

I think it's the best you structure your app in a way you are comfortable with.

I wrote a little app here: http://gold.meteor.com And it's so small, I use only one html file and only one template.js file.. :)

I hope it helps a little bit

Steapsin answered 5/1, 2014 at 13:51 Comment(1)
i don't see value in naming multiple files with a feature name like "articles". Now if you want to change the feature name to "posts" you have to change filenames. Just organize them under a single folder called "articles" and name them "events.js", views.html, styles, css, etc. see my answer for more.Puzzlement
I
3

There's a new class on Evented Mind called Setting Up Meteor Projects that addresses this but also talks about project configuration and setting up your development environment.

From the Application Structure video in the class: Meteor doesn't have a very strong opinion about how your application should be structured but here are some rules:

1) Load order - Meteor goes to the deepest location in the file directory first and processes the files in alphabetical order

2) client and server are special folders that Meteor recognizes

Our structure looks like this:

both/
    collections/
        todos.js
    controllers/
        todos_controller.js
    views/
        todos.css
        todos.html
        todos.js
    app.js - includes routes
client/
    collections/
    views/
        app.js
server/
    collections/
    views/
        app.js
packages/
public/

The todos_controller extends RouteController, something that comes with Iron Router.

The em tool mentioned above is also getting a big update right now and should be much better and available at: https://github.com/EventedMind/em

Immersionism answered 12/2, 2015 at 22:46 Comment(2)
what's views inside /server/views/?Signore
i don't see value in naming multiple files with a feature name like "todos". Now if you want to change the feature name to "tasks" you have to change 5 files names. Just organize them under a single folder called "todos" and name them "events.js", views.html, styles, css, etc. see my answer for more.Puzzlement
C
2

I am also looking for best practices to enhance and scale my apps through a well conceived architecture. All of the above mentioned practices work for small to medium size apps but will fail when you work in a bigger team. There are several ways I have tried:

1) I followed this strategy: https://github.com/aldeed/meteor-autoform to scale and reuse templates. The author has a very good idea on component and field design. I am currently implementing it because the community developed 36 packages that cover almost every case and I can use TypeScript to be type safe during the development phase.

<template name="autoForm">
  {{#unless afDestroyUpdateForm this.id}}
  {{! afDestroyUpdateForm is a workaround for sticky input attributes}}
  {{! See https://github.com/meteor/meteor/issues/2431 }}
  <form {{atts}}>
    {{> Template.contentBlock ..}}
  </form>
  {{/unless}}
</template>

Here is a good blog post on how to do it: http://blog.east5th.co/2015/01/13/custom-block-helpers-and-meteor-composability/ as well as here: http://meteorpedia.com/read/Blaze_Notes

2) This one looks so promising but hasn't been updated lately. It is a package written in coffee script called. Blaze Components (https://github.com/peerlibrary/meteor-blaze-components) for Meteor are a system for easily developing complex UI elements that need to be reused around your Meteor app. You can use them in CoffeeScript, vanilla JavaScript and ES6. The best thing is, components are OOP. Here is one of their examples:

class ExampleComponent extends BlazeComponent {
  onCreated() {
    this.counter = new ReactiveVar(0);
  }

  events() {
    return [{
      'click .increment': this.onClick
    }];
  }

  onClick(event) {
    this.counter.set(this.counter.get() + 1);
  }

  customHelper() {
    if (this.counter.get() > 10) {
      return "Too many times";
    }
    else if (this.counter.get() === 10) {
      return "Just enough";
    }
    else {
      return "Click more";
    }
  }
}

ExampleComponent.register('ExampleComponent');

{{> ExampleComponent }}

3) I like types and transpiler that tell me where and when something will go wrong. I am using TypeScript to work with Meteor and found the following repository: https://github.com/dataflows/meteor-typescript-utils it seems like the creator tried to accomplish an MVC approach.

class MainTemplateContext extends MainTemplateData {
    @MeteorTemplate.event("click #heybutton")
    buttonClick(event: Meteor.Event, template: Blaze.Template): void {
        // ...
    }

    @MeteorTemplate.helper
    clicksCount(): number {
        // ...
    }
}

class MainTemplate extends MeteorTemplate.Base<MainTemplateData> {
    constructor() {
        super("MainTemplate", new MainTemplateContext());
    }

    rendered(): void {
        // ...
    }
}

MeteorTemplate.register(new MainTemplate());

<template name="MainTemplate">
    <p>
        <input type="text" placeholder="Say your name..." id="name">
        <input type="button" value="Hey!" id="heybutton">
    </p>
    <p>
        Clicks count: {{ clicksCount }}
    </p>

    <p>
        <ul>
            {{#each clicks }}
                <li> {{ name }} at <a href="{{pathFor 'SingleClick' clickId=_id}}">{{ time }}</a></li>
            {{/each}}
        </ul>
    </p>
</template>

Unfortunately, this project is not maintained or actively developed.

4) and I think that was mentioned already, you can scale using packages. That requires a good abstract way of thinking. It seems to work for Telescope: https://github.com/TelescopeJS/Telescope

5) meteor-template-extension – provides various ways of copying template helpers, event handlers and hooks between templates, allowing code reuse; a downside is that all copying has to be taken care by a developer, often again and again, which becomes problematic as codebase grows; moreover, without a clearly defined API community cannot build and share components

6) Flow Components – Flow Components are closer to React in the API design while Blaze Components are keeping familiar concepts like data contexts and template helpers; Flow Components on the other hand still use template-based event handlers while Blaze Components make them class methods so it easier to extend or override them through inheritance; in general Blaze Components seems to be more OOP oriented; Flow Components are not yet officially released (text credits for #5 and #6 https://github.com/peerlibrary/meteor-blaze-components#javascript-and-es6-support)

Number 2 and 3 need some getting used too, but you'll gain development speed over time. Number four lets you build and test components to make your code more stable. Number three comes with the advantage of full type safety of Typescript, which is a huge plus when you develop in a team with poor documentation. However, I am currently porting number two to TypeScript because I feel very comfortable to work with it and I don't have to tweek the compiler package to make it work with Meteor when I am not using Gulp.

It is still hard to find the right way to work with Meteor. You need to figure it out for yourself, otherwise you end up with a nicely arranged folder structure, but you have no clue where everything is. Happy coding.

Cholecyst answered 15/9, 2015 at 23:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.