How to merge multiple html files into one with brunch.js - backbone.js

I'm using underscore.js for my templates which are stored in multiple separate XXX_tpl.html files inside sections similar to:
<script type="text/x-template" id="tpl_XXX">
<h1>hi</h1>
</script>
Which I am then using inside backbone.js views as follows:
render: function () {
this.$el.html($('#tpl_XXX').text());
}
I am now using brunch.js build tool which nicely outputs all my libs/js/css code into several optimized files but I am having issue with managing / organizing my templates. How do I make brunch.js build tool to append all *_tpl.html files at the end of index.html? All the examples I am seeing online show how to use brunch.js to merge templates into .js files but I don't yet understand how that works (the templates are a mix of html/js and I lose both access by ID and syntax formatting/highlighting when storing templates in .js files).
Q1. If what I'm doing is right (multiple templates in multiple different .tpl.html files all appended at the end of index.html when built) then how do I make build.js merge all of that?
Q2. If what I'm doing isn't right, what's a better approach to:
have multiple templates that are organized and easily managed
not create additional http requests to pull / all compiled into a single file
have easy access from backbone.js models
want to achieve syntax highlighting in my IDE for the template markup (i.e. no JS string concatenations, etc)

Nice question, but I don't know if you understood how underscore templates should work precisely. Let's try to clear that up first.
Template compilation
An underscore template source is any text with interpolated code. For example:
var myTemplateString = "hello: <%= name %>";
When you want to use that template, you need to compile it into a function first. What? Here's how it works:
var myTemplateFunction = _.template(myTemplateString);
This creates a myTemplateFunction which contains your template logic. In a very simplified, pseudo-code way, you can expect myTemplateFunction to work somewhat like this:
function (context) { return "hello: " + context.name };
So, now you understand why you can call this function and produce a string!
myTemplateFunction({name: 'moe'}) // hello: moe
Using compiled templates
OK, but why do you need to compile it previously? Why not always call directly:
_.template(myTemplateString)({name: 'moe'})
Because compilation can be CPU-intensive. Therefore, it's much faster to use a pre-compiled template. You should not force the user's browser to do it! You should do it for him!
Delivering compiled templates
By now, you understand you don't care about delivering the text of your functions to your client, only the compiled template functions. There are many ways to accomplish that.
Brunch has a bunch of plugins for pre-compiled templates, but apparently none for underscore: http://brunch.io/plugins.html
You can use webpack and it's EJS template loader.
Your code would look something like this:
var myTemplateFunction = require('./template.html')
console.log(myTemplateFunction);
You can also use Grunt and it's underscore template task: grunt-contrib-jst.
Whichever you choose, they will all work similarly: they'll compile your template into a function and you'll be able to use that function. Personally, I recommend learning webpack!

Related

How to uglify an angular project using grunt?

I'm trying to deploy a meanjs project but can't seem to figure out how to minify,concat&uglify the project using grunt.
What I've found out so far :
Need to run concat -> ngAnnotate -> uglify (else code won't run)
need to concat in dependency order (else it won't run)
With this logic I've managed to create a single 'uglified' version of the relevant 3rd party libraries (node modules), but I'm unable to do the same for the modules I've written.
I've tried using concat tools that are supposed to reorder the files according to dependencies (grunt-concat-in-order, grunt-concat-dependencies, grunt-concat-deps) but nothing helped. Just errors of missing modules/declarations.
I've tried reordering the js files that should be concatenated, and each time something else is missing and the site loads partially (at best).
reordering the files according to the order they appear in the compiled header doesn't help.
Is there something that concats Angular files according to their dependencies or or a general logic in which I should reorder them?
Thanks.
FOUND IT!
apparently JS and Angular are flexible with missing ';' in the end of module/directive declarations.
I've went through the entire code and added missing ';' in the appropriate places.
For example:
angular.module('core').filter('xyz', [function() {
.....
}])
Finally can go to sleep.
*original post:
Angular module().factory() is not a function after concat (gulp) (cheers to Max Yari)
The first thing to check is that you actually use the DI pattern everywhere in your code as the function parameters will be replaced during uglification and thus won't be resolved let anymore.
ControllerName.$inject = ['component']
Or
angular.module('module')
.controller(['module', function (module) { /*... */}) ;
When you've done that, check if you may explicitly specify file order like this (pseudo code):
['module1_decl_file.js','module2_decl_file.js', '*.js','**/*.js']

Using ngSanitize to allow some html tags

I have an insecure string from the user that I want to display.
I want a few html-tags like < strong > (without spaces) to work.
All other html should be displayed like it was typed in (that is < should be replace with & lt; and so on)
I'm pretty sure I can use ngSanitize to do this but I can't figure out how.
$compileProvider allows you to set up sanitization "whitelists" for HREF and SRC URLs:
app.config(function($compileProvider) {
var imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
$compileProvider.imgSrcSanitizationWhitelist(imgSrcSanitizationWhitelist);
});
However, the whitelists for "safe" tags are hard-coded and can't be changed the same way. You can see the list here in the source:
https://github.com/angular/angular.js/blob/master/src/ngSanitize/sanitize.js#L186
There is an open request to enhance this functionality:
https://github.com/angular/angular.js/issues/5900
But it has not been completed (yet).
In the meantime, you have a few options:
"Fork" the project and adjust ngSanitize to suit your purposes. Most people don't like to "hack core" in this way, but it's the whole point of Open Source to be able to do things like this. This module doesn't change so much that it would be that hard to keep it relatively up to date as you develop your project.
Live with the list defined there. Most of the time you find that this list is actually pretty good, and it's just that IMG or A HREF tags are broken. That's not because the tag is filtered - that's because THOSE are white-listed separately, and you can use the technique above to accept specific URLs into each of those tags as "safe".
By the way, there is now a possibility.

Sublime Text 2: Different language highlighting based on context? (a la Webstorm)

I was watching some videos on Egghead.io about AngularJS. The creator of the videos uses Webstorm (and, I believe, works for them). One feature I noticed is that he can set different syntax highlighting within different scopes or quotation marks. So, in code like the following (from an AngularJS directive)
return {
template: '<div>something</div>',
// ^^^ these guys ^^^
}
...he can get the inside of the quotation marks to highlight as HTML.
I use Sublime Text 2, and am fairly wedded to it. Is there an existing feature/plugin for Sublime that could handle a case like this? If not, is something like this technically possible using the Sublime Text 2 API?
I don't think it's built in, but it's certainly possible. I've been doing some work with graphviz and wanted to do something similar. Labels can be generated with html like syntax. Anyways, I played around with the .tmLanguage file and added a new pattern to match the context where html like entries were valid (I look for label = <). The patterns I used for the captures aren't that good, but it works for fine for me. This give me the following, which I think is similar to what you are looking for.
I don't know anything about AngularJS, so I can't help you with anything specific to that, but it is certainly possible. Note that in the image below, the last <table></table> are just to show that highlighting doesn't occur there.
Edit:
Forgot to include this in the original post, but here is my updated tmLangauage file. That first pattern is what I added(link). I used PlistJsonConverter to go from JSON to plist, then saved the file as .tmLanguage. Hope this helps.
#skuroda is right, I implemented #skuroda's code with an additional plugin to easily edit HTML within an AngularJS directive JS file. The result is HTML syntax highlighting within a directive JS file and additional functionality to remove string related delimiters while editing templates.... Sublime AngularJS HTML Template Plugin

Writing EJS View helpers

I have a rails-backbone project that generates jst.ejs templates.
I'd like to include some view helpers within there, but I'm having a helluva time figuring out how to include either EJS or JST functions into that template file. If anyone could offer a very quick explanation of how to include a very basic function so that it can be read by an ejs.jst template I'd be very appreciative.
I've tried hacking into JST & EJS, plus just using bare javascript functions, but nothing is bringing any joy. Example attempt below:
Example:
# helpers.js.coffee
console.log('yes, this file is being called from the app')
helloWorld: () ->
console.log "Hello, world!"
# app/assets/javascripts/backbone/templates/project/new.jst.ejs
<%= helloWorld() %>
(Returns uncaught referenceError)
Any ideas appreciated. Cheers.
You might need to attach that to window, since coffeescript puts closures () around each .coffee file. A good example of how to deal with scoping issues is any popular js/coffee utility, like underscore.js. He uses var root = this and exports to conform to CommonJS practices and get his _ function out into the world where it can be used globally.
The book CoffeeScript: Accelerated JavaScript Development has a chapter (chapter 4) on this very topic, as well as it's just a damn good book on CoffeeScript. It explains a lot of where the modern world is at javascript-wise.

ExtJS MVC, dynamic loading and i18n

I would like to translate my ExtJS application in different languages. My issue is that I'm using ExtJS MVC framework, and most of my JS files are downloaded dynamically by the framework itself.
The ideal solution (that I thought of) would be to have an extra option in the Ext.Loader (or in my Ext.app.Application) that would define the language to use, and depending on this to automatically download such file as "a.MyClass.fr.js" after loading my "a.MyClass.js" (which would contain an Ext.apply, overriding my string resources). That's probably not available in the ExtJS framework at the moment.
The alternative solution I can see, is to perform a trick on the server-side. First, a cookie would be created on the client, to set to the language. On the server-side, I could catch all the requests to JS files, then if a cookie is set (='fr' for example), I'd combine the requested JS file (MyClass.js) with its i18n's friend (MyClass.fr.js) dynamically on the server and return the result. That would work, but it's really tricky because it implies other things (caching...).
Maybe the best way is to implement the first behavior I described in the ExtJS framework myself...
What do you think? I'm looking for a really clean and neat way of doing it! Thanks :)
I recently struggled with the same problem.
Finding a clean way to do this was quite a challenge - most alternatives were either..
1) Duplicate your code base per locale (WTH)
2) Download localized files overriding each of your components (Maintenance hell? What about the poor translators?)
3) Use/generate a static file containing translations and refer to it (All languages are downloaded? Extra build step to generate it? How do you keep them in synch?)
I tried to get the best of all worlds and ended up with a utility class responsible for:
1) Loading the ExtJS translation files (which basically apply overrides to extjs base components)
2) Loading a locale specific property resourcebundle (specifying which locale to load) from the server.
3) Prototyping String with a translate() method which queries the loaded store (containing the message bundle from the server) and returns the translation based on the value of the string.
This is the gist of things:
Bundle & prototyping:
localeStore.load({
callback : function(records, operation, success) {
// Define translation function (NB! Must be defined before any components which want to use it.)
function translate() {
var record = localeStore.getById(this.valueOf()) ;
if(record === null) {
alert('Missing translation for: ' + this.valueOf()); // Key is not found in the corresponding messages_<locale>.properties file.
return this.valueOf(); // Return key name as placeholder
} else {
var value = record.get('value');
}
return value;
}
String.prototype.translate = translate;
callback.call(); // call back to caller(app.js / Ext.Application), loading rest of application
}
});
As an example from a view:
this.copyButton = Ext.create('Ext.button.Button', {
disabled: true,
text: 'DOCUMENT_LIBRARY_MENU_COPYTO_BUTTON'.translate(),
action: 'openCopyDialog'
});
Bundle on the server (mesages_en.properties):
DOCUMENT_LIBRARY_MENU_COPYTO_BUTTON=Copy file
etc..
Pros:
No-fuss code, 'Your_key'.translate() makes it easy to read and aware that this is a localized string
None/little maintenance overhead (Keeping an override file for each locale? Jesus..)
You only load the locale you need - not the whole shabang.
If you really want to, you could even have your own translation for the ExtJS locale files in the same bundle.
You could write unit tests to ensure that all bundles contain the same keys, thus avoiding orphaned translations later
Cons:
Synchronous - the store must be loaded before your main app starts. I solved this by adding a callback from the utility class which was called once all texts were loaded.
No real-time population of texts.. though I didn't want to make my users overload the server either :P
So far my approach has worked out pretty well for my requirements.
Site load isn't noticeably slower and the bundles (containing ~200 keys/values per bundle) measure out at ~10kb during load.
There is currently no solution so I decided to create my own hack/addon on the Ext.Loader. I uploaded the code on GitHub: https://github.com/TigrouMeow/extjs-locale-loader. It's exactly what I needed and I really hope it will help others as well!
You should first complete your development phase and build your project or use ext-all.js file to I18s translate your UI
see: http://docs.sencha.com/ext-js/4-0/#!/example/locale/multi-lang.html
The appropriate language modifier script (/ext/local/ext-lang-xxx.js) needs to be loaded after ext is loaded (including dynamically loaded classes). In the example above, I would have probably used Ext.Loader.loadScriptFile but they eval a downloaded one directly. The only other thing is that your classes need to be built in different languages or you just use variables and reference the lang-specific variable file.
you could also use a variable in the Loader paths:
var lang='fr';
Loader
{
paths:
{
'Ext': '.',
'My': './src/my_own_folder'+'/'+lang
}

Resources