I'm starting in javascript development, and did a simple project with node.js as a rest API and a client using backbone, everything look perfectly till I want to get my templates out of my js.
I found different approaches, some of them with some time (like one year old) but I can't understand which one could be better:
A .js file with a var with the html code
pros -> easy to load, easy to pass to underscore to compile it.
cons -> scape every single line.
app.templates.view = " \
<h3>something code</h3> \
";
load template:
template: _.template(app.templates.view)
External template in Underscore
Use require.js to load with text plug-in.
pros -> load different templates as needed.
cons -> I don't like the approach to put everything inside a "loader" function...
define(["TemplateEngine", "text!templates/template.html"], function(...
RequireJS: Loading modules including templates and CSS
A function that loads the templates with an AJAX petition.
pros -> You can load the template that you need and adds local storage posibilities.
cons -> Seems that I have to merge all my templates into one file for production environments.
function() {
var templateLoader = {... $.get calls ...}
Best way to asynchronously load underscore templates
And a Jquery plug-in for template loading that I really liked but it seems that it didn't go to release?
http://api.jquery.com/jQuery.template/
It seems that require is the best approach, but maybe I'm missing something, I do wan't to make things as clean as possible since I'm in the learning/having fun phase :D
Any good article or github project with a good structure or any light on this will be appreciated.
Thanks.
Excuse any major spelling mistake, not an English speaker :)
--EDIT--
found some interesting videos to understand how to start and wrap things with require.js
http://www.youtube.com/watch?v=VGlDR1QiV3A
http://www.youtube.com/watch?v=M-wjQjsryMY
I would recommend using require.js with text plugin. Mixing html templates as strings in javascript variable is bad idea, as well as using something like <script type="text/template"></script>.
Here is one very good series on backbone.js which covers template loading and project build as well: http://dailyjs.com/2012/11/29/backbone-tutorial-1/. Github project is also provided there.
Require is a good option from the ones you listed.
Is there a reason you haven't considered simply:
Storing templates in the pages that use them as <script type='text/template'> nodes?
Storing templates as text (non-JS) files and loading them via XHR on pages that use them?
Related
I'm trying to update the javascript on a large scale, php/codeigniter based website. It has many, many php partials for code being loaded onto certain pages, but only one footer, header. Most of the partials have inline script tags in them for loading javascript. This needs to be fixed and because the site is very modular with components being used multiple times across pages, require.js seems like a pretty good solution.
So, it's instantiate javascript, we typically do this.
<script type="javascript" src="../js/scriptname.js">
<script type="javascript">
DP.scriptname.init(parameters)
</script>
I'd like to get away from this and just have a have a single entry point for the js using require.
My question is this: what's the best way to instantiate javascript for certain pages using require? Do I need I need to continue including my scripts in the partial and then do something like writing a require module for that specific page and then wrap it all in my data-main script like this? We're planning on using Backbone and Marionette as well, but I won't be able to use the Backbone router to do anything like setting hash URLs. Should I use the URLs to instantiate my require modules perhaps?
Ok, hope someone can help. My experience has typically been in building single page websites. This is different. Thanks
Cam
Well, if I understand your question correctly, you can use Require JS in such way.
First of all, write a config in which you can describe mapping between module names and concrete files. For example:
requirejs.config({
baseUrl: 'js/modules' // by default load any module using this path
});
After that you should refactor your existing module and adjust it to the AMD format (see http://requirejs.org/docs/whyamd.html)
As a result of this step you will have something like this (let's say in file 'js/modules/scriptname.js'):
// module has the same name as the file, which contains it - "scriptname"
define(function () {
// define the module value by returning a value
return function () {};
});
And as a final step you can refactor your inline script and use this module in such way:
<script type="javascript">
// when we place name of the module as a first argument of the "define"
// function, Require JS find file that contains it and load it asynchronously
define(["scriptname"], function (scriptname) {
// "scriptname" now contains value that we recieve from the module definition
scriptname.init(parameters);
});
</script>
Hope this helps.
Note. My solution based on this section of official Require JS documentation: http://requirejs.org/docs/api.html#jsfiles
This question seems to come up a lot, so I'll point you to some resources that may help:
How does RequireJS work with multiple pages and partial views? - https://stackoverflow.com/a/10816983/617615
Modular HTML components with RequireJS - http://simonsmith.io/modular-html-components-with-requirejs/
Example RequireJS-based project that has multiple pages that share a common set of modules - https://github.com/requirejs/example-multipage
I use require.js to do lazy loading for a Javascript app. I would love to switch to a meteor stack but right now it looks like Meteor sends the whole app (all the templates) through on the initial load. Has anyone had success with require.js and meteor or any other implementation?
You're asking different questions, but certainly they are connected. The first is about loading additional javascript code into your meteor app. Of course you can use thing like requirejs. This should work fine supposing your lazy code is located in the public directory of your meteor project. However, my experience is that requirejs goes mad when the contents of public gets updated often, so for example in the development environment. Maybe it's a matter of customizing the library, but I would rather recommend using some lightweight homebrewed package. Look here, if you need some inspiration.
The second question is about lazy template definition. Each template consists of two parts. The first is its html code, written in handlebars syntax, the second is all the javascript code which you write to define how your template should behave (e.g. helpers, event handlers). The second part is easy, as long as we assume that we already know how to load the lazy code (see the above paragraph) and the template, lets call it myLazyTemplate, is already defined, so basically speaking Template.myLazyTemplate is not undefined. So how to achieve the latter?
To dynamically define a new template you'll need to call
Template.__define__(name, raw_func)
on the client. So the last question is "what is raw_func?". This is a compiled version of your html code which is normally created automatically on the server and then sent down the wire to the client when the app gets loaded (look here to see how it's done in meteor). But we want to do it dynamically, right?
So the idea is to compile the template code manually with a help of the Handlebars.to_json_ast routine. You can feed it with your template html code, and the output is some javascript array that can be sent to the client anytime by the method we've already talked about. The last thing you need to do is to call Handlebars.json_ast_to_func on the client, using the data sent from the server as the only argument. The output produced by Handlebars.json_ast_to_func is the raw_func you can use to produce myLazyTemplate template.
I'm aware that this is only a rough idea, not the whole solution to your problem. I hope this will help you to figure out the final solution on your own.
I'm using underscore template engine for an backbone application. As of now I have over 15 templates in the <head>. Its getting hard to maintain. So far, most of the solutions I seen to manage templates ended up needing them to be js files. That's also a headache, I prefer them to be html files for editing purposes.
I took a look at requirejs and not sure if I need that since it kinda revolves around a more modular approach that I can't say I'm using at the moment (although I will soon).
What will be the best way to manage templates and load/cache them as needed?
Personally we needed a robust solution at my company, so we went with:
Require.js - for module loading
Handlebars - for more powerful templating than Underscore can offer
HBS - an excellent require plug-in from Alex Sexton that handles bringing compiled templates in via Require
With this setup I can keep all of my templates in their own file, and then to use them I have files like this:
define(['template!path/to/someTemplate'], function(someTemplate) {
var MyNewView = BaseView.extend({template: someTemplate});
$('body').append(new MyNewView().render().el);
}
(and as you might guess we have a base Backbone view called BaseView which uses the view's template property to render the view).
Now, all that being said, if you don't need such a robust setup then Require may not be for you. In that case I would do the following:
Put all of your templates in to one or more HTML files; wrap them in script tags, like so:
<script id="dummyTemplate" type='text/template'>
<span>I'm a template!</span>
</script>
Write some code on your server-side to include those HTML files in the main HTML file you send to the client
Write a function which takes a template ID, gets the text of that element, compiles it in to a template, and returns that template (maybe cache the compiled templates if you want ... of course, with Underscore templates I don't think you even need compiling, so you can skip all that).
Use your function to access your templates: $("#something").html(templateFunc('dummyTemplate').template())
This will allow you to store your templates in html files (for syntax coloring), but still access them conveniently in JS. You can also divide your templates between as many files as you want, as long as you can write include logic to bring them in.
If you do opt for Require though, definitely check out the HBS plugin. And if you haven't looked at Handlebars templates yet, you might want to; they're far more powerful than Underscore ones (but like any good templating system, don't allow for too much logic).
Not sure what you mean by it being unmaintainable. Is it just a long list?
You don't need to keep your templates in the head. They can be at the bottom of your body as well. They just need to be defined before you try to use them.
One thing you might look into, depending on the server technology you are using would be to separate your templates into a different HTML file and include it at runtime.
I was trying to convince a fellow co-worker into using Mustache/Hogan in the front-end of a project and I proposed the following:
Having a templates.js file, which could roughly look like this:
var tpl_alert = '<div class="alert">{{msg}}</div>';
var tpl_welcome = '<p class="user-{{type}}">Welcome, {{name}}</p>';
...
Then, we would include templates.js and use the corresponding tpl in the Mustache/Hogan.js rendering.
My proposal was turned down, since we're hardcoding html templates into js variables.
Is this really that bad? Which are other alternatives to this?
To answer your question, putting your templates in javascript variables inside a static JavaScript file makes it difficult to maintain your templates. You need to worry about string escaping whenever you want to make a simple change. And 1 syntax error will crash your app.
However, putting all your templates in a single JavaScript file is the fastest way to load your templates.
Your alternatives are:
Storing your templates in seperate files and generating the static template.js file as a prebuild step.
Loading your html template files async through AJAX into javascript variables.
Using a library like Require.js that will load your templates asynchronously as needed into variables.
My preferred way of doing this is to create a separate template file that can be loaded dynamically in development and baked into pure js for production.
Specifically I use eco templates (I wouldn't recommend them unless you're familiar with coffee script) and Stitch for node.js. Stitch supports custom engines tied to file extensions, so when it finds an eco file in my project directory it compiles it into a Javascript function. I can now include that function in any other part of my application using the stitch provided require function using the original path of the eco file. So if the template resided in src/views/listItem.eco I would run var listItemView = require('views/listItem'); to fetch it and use it like this
var html = listItemView({item: items[i]});
$someElement.html(html);
You could use require.js instead of stitch if course, or any other similar framework.
Ok, I've read a lot of information about the new Asset Pipeline for Rails 3.1 and I couldn't find a proper answer to my doubt.
I was loading my .js files according to the view#action I was rendering, on demand. I was doing this to prevent incorrect bindings and to load small .js files.
candidate_opportunities#index
$(".sortable_drag_n_drop").sortable({
update: function(event, ui) {
$.post('/candidate_opportunities/sort', $(this).sortable('serialize'));
},
handle: 'span'
});
candidate_companies#index
$(".sortable_drag_n_drop").sortable({
update: function(event, ui) {
$.post('/candidate_companies/sort', $(this).sortable('serialize'));
},
handle: 'span'
});
$(".sortable_drag_n_drop").disableSelection();
What is the best solution now?
Should I change my bindings and let Sprockets compile all my .js files using //=
require_tree . ?
Or should I try to load my
.js according to my views, so I don't end up with a huge
application.js?
If you are updating this to the pipeline you have several options. You should probably take the way the pipeline should work into account in deciding.
Broadly speaking, the aim of he pipeline is to join all your JS into one file and minfy/compress it. The point in doing this is reduce the number of requests per page, and to allow far-future headers to be set so that the resource is cached at the browser or somewhere in a transparent proxy/cache.
On to the options.
1. The same as you do now.
You could keep doing the same thing as you do know. I presume that you are using the rails helpers to add these view JS files in the main layout file. You could keep doing the same with the pipeline, however you must add all the files you use to the precompile array:
config.assets.precompile += ['candidate_opportunities.js', 'candidate_companies']
The assets must be in assets/javascripts but there is no need to add them to the manifest file as you are adding each on individually.
It is highly recommended that you stick with the Rails defaults for the pipeline and precompile assets for production.
The downside is an extra request on those pages, but this is only an issue if the app is under high load.
2. The Asset Pipeline Way (TM)
To do this with the pipeline you would need to move these files into assets/javascripts and require_tree as you say.
The issue in your case is that the JS snippets target the same class (but with a different post URLs), so this is not going to work. And with require_tree the order of the files might not be what you want.
A new 3.1 app generates files for views (I think), but the expectation is that they will target unique attributes (from a site perspective) in the markup, because all the files get included in the application.js
To get around the problem of JS clashes. I would suggest that you refactor the JS snippet so that it is more generic. You could use a data-post-url attribute on the sortable object:
<ul class="sortable_drag_n_drop" data-post-url="/candidate_opportunities/sort">
and then collect the url in your JS.
Not only is that DRYer, but you have less overall JS and can fully use the pipeline as intended.
I'm frustrated on Rails asset pipeline. Maybe not the whole asset pipeline thing but the way Rails organize javascript is really not logical.
As of now, Rails has a separate javascript file per controller. Which is somewhat good in terms of logical organization. But then the asset pipeline compresses all those files into one big js file. So basically your js files are well organized but then they are loaded all at once, resulting to variable clashes, function clashes, other code clashes and other unexpected behavior. Because what we really want as developers is a simple way to execute or load a page specific javascript.
One famous approach is to just include a specific javascript file per page. Yes, that will work, but we are not using the performance boost given by the asset pipeline if we are requesting different javascript files per page.
My solution is to create an javascript object that holds all the page-specific functions then fetch and execute them once the matching controller-action pair is executed by Rails. Something like this:
PageJs = {};
PageJs["users/new"] = function(){
alert("I will be called when users/new action is executed");
};
Basically, that's the core idea. Well I've implemented that idea and created a gem for it. Checkout Paloma, and see how you can logically organize your js files and execute page-specific javascript without complex setups.
Here's an example on how Paloma is used:
Javascript file:
Paloma.callbacks['users/new'] = function(params){
// This will only run after executing users/new action
alert('Hello New Sexy User');
};
Rails controller:
def UsersController < ApplicationController
def new
#user = User.new
# No special function to call,
# the javascript callback will be executed automatically
end
end
That's just a quick example, but it has lot more to offer, and I'm sure it can solve your problem. Easily.
Thank You!