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.
Related
I have a simple PHP application branded to one company and it contains a few pages. The php pages are then compiled to static HTML using a Gulp plugin and the HTML files are then deployed to a production server.
I'm now looking to create a variation of this compiled application with new branding. It will just involve changing some of the colours and logo. Ideally I want to use the same codebase so I'm not duplicating code and work effort but just using conditions to replace the logo and stylesheet for each company. Each application should compile in to separate folders to be deployed.
Does anyone have any suggestions on how I can achieve this? Handlebars JS or some other templating tool perhaps?
If the application is written in PHP, I recommend Twig.
Extensible, easy-to-use and powerful.
Can be installed with composer :)
I think you are looking for something like very simple pipeline. I would recommend you to just write some shell script (or modify existing php script) with arguments (logo path, output directory) to make existing engine produce different output to different directory.
ok, I edited the post, to show the idea.
I was thinking about something like the following:
<?php
$logo = $argv[1]; //take commandline arguments
$name = $argv[2];
$dir = $argv[3];
mkdir($dir);
$path = $dir.'/template.html';
$template = '<img src="'.$logo.'" alt="logo"><h1>This is '.$name.' site</h1>'; //here you could run your templating engine with some names and paths replaced with variables
file_put_contents($path, $template);
Then, you can run this proof of concept script from your commandline like so php createTemplates.php company1.jpg company1 company1 and you will get template.html with company1.jpg logo and company1 headline in company1 folder.
I have no idea how does your templating engine work or how advanced it is, but for the simple use (few html pages) it should be enough.
I am currently working on cleaning up a little web app I've written in Mojolicious. As part of that cleanup I am separating out my javascript into the public directory from my html.ep files.
The problem I have though is I don't seem to be able to reference tag helpers any more, like 'url_for' or even referencing values in the stash such as '<% $stashvalue %>'.
Any idea's on how or if I can do this is very much appreciated.
cheers.
The stuff in the public directory is served statically, optimally by your webserver, not by Mojolicious or Plack, so that file does not get processed by Mojolicious, thus <% $stashvalue %> not meaning anything.
A solution would be to embed those parts of javascript that need to access server side variables in the mojo templates - rather ugly, but less code to be written.
Another one would be to make an ajax call from your javascript files, when they are loaded, and get the values sent by the server - more elegant, but more code to be written.
Another one that I can think of, would be to move those javascript files under a folder that gets processed by Mojolicious and include them parameterized - in your html.ep file that needs that js file, do :
<script type="text/javascript" src="http://example.com/url/served/by/mojo/?param1=<% $stashvalue %>¶m2=<% $stashvalue2 %>"></script>
And, in the controller that responds to /url/served/by/mojo/, render that js file, with the params replaced by the ones from the query. As an alternative, you could store/receive those params also on the session
As usually in Perl, there is more than one way to do it.
What I typically do is encapsulate most of my javascript in function calls or objects in pure javascript files. Then in my templates I include those pure javascript files and use the api that I built in those files from the template, interpolating the server-side variables into the arguments of the functions. You can peruse the code for Galileo to see several examples.
For example, see how this template passes stash values to this pure javascript file's functionality.
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've been reading about the module pattern, but everything I read assumes that the entire contents of the module will be in a single file. I want to have one file per class.
I've resorted to doing this at the top of every file:
if(window.ModuleName === undefined) { window.ModuleName = {}; }
ModuleName.ClassName = function () { ... }
But this allows files to be included without their dependencies, which is also annoying. For example, lets say there is ClassA which uses ClassB, and "ClassB.js" is left out of the HTML, then ClassA will throw up errors. As far as I'm aware Javascript lacks an import statement, so in this case I actually want everything to be in a single file.
I assume that large javascript projects are broken up into multiple files, so there has to be a way around this. How is it generally done? Is there some tool that will combine multiple class files into a single module file?
This is a big topic but let me explain as much as I can. Javascript requires that you have preloaded anything you intended to use, which is why your module pattern has all the "things" in the same file. But if you plan to separate them in different files then you have to manage it before using. I suggest the following approaches
Concatenate them before serving them in the server. For example in jsp, you can create a servlet that returns contenttype = "text/javascript", inside that servlet you can append all the scripts you need in one dynamically generated script then return it to the client.
In your ant or maven builds etc, there are configurations where in you can concatenate them the files you want together. This is a common practice therefore you should find many reference in the internet.
Lazy-load javascripts. This is my preferred way. I use Lazyload javascript library. Basically I declare the dependencies of certain codes much like "import" in Java, then before i call any of them i load their dependencies. This allows for optimized dependency loading without scripts redundancies. The problem is you need to write some fairly complicated scripts to do this.
Hope to help.
I'd like to split my views in Grails into 2 files a .gsp file and a .js file so that I get a cleaner Javascript separation from my views. So here's an example:
views/index.gsp
views/index.js
views/home/index.jsp
views/home/index.js
But when I simply add the index.js script reference like this:
<script src="index.js" type="text/javascript"></script>
all I get is a 404.
Does anyone knows how to deal with this?
A great benefit would be to have the ability to use view data inside the index.js file to produce the desired content.
Matthias.
Actually, it should be perfectly possible to serve a JS file (or any other file type) as a GSP from your grails-app/views/ directory. The only thing you have to do, is define a suitable URL mapping for those GSPs, e.g.:
"/javascript/home/index"(view:'/home/index.js')
With this URL mapping, you can put your JS code into grails-app/views/home/index.js.gsp (note the trailing .gsp) and you can use any grails tags in your JS source. To ensure that your JS is delivered with the correct content type, you may want to place
<%# page contentType="text/javascript"%>
at the beginning of your GSP.
Unfortunately, the createLink tag doesn't support link rewriting to views, but it should be easy to write your own tag to create those links.
Anyways, keep in mind that this won't have a very positive impact on your app's performance. It's usually better to have static JS files (and also serve them as static resources) while passing dynamic stuff as parameters to JS functions for example. This will also keep you from some headaches wrt. caching etc.
The idea is good, but Grails has this directory structure for a reason. The view folder is intended for a certain artifact type (views)..
You could clone your view folder structure under web-inf, but that gives you more work as I guess the idea behind this is to keep related files close together for convenience reasons.
Even though I'm not to excited about storing Javascript together with the view I loved Robert's idea of hooking into the build process by using build events to copy javascript sources into the right directory! If you decide to go down that road you might as well compress the sources while you're at it. ShrinkSafe is popular library.
I don't think you are allowed to access js inside views/
if you need to do that ... here is the trick
create your js and rename it with myjs.gsp (use "")
iniside _myjs.gsp type you js
... write down you js in here ...
inside you gsp (for example: index.gsp, view.gsp, etc)
type this tag to upload you js
Update 2:
Grails offer the possibility of hooking into the build lifecycle using custom events.
An event handler can be written which synchronises all JavaScript files under grails-app/views with the target folder of web-app/js.
Place the custom code in $PROJECT/scripts/Events.groovy. The PackagingEnd is a good target for the invocation, since it happens right after web.xml is generated.
eventPackagingEnd = { ->
// for each js file under grails-app/views move to web-app/js
}
Update
If you'd like the JavaScript files simply 'meshed' together, you can do that using symlinks, e.g.:
grails-app/views/view1/index.js -> webapp/js/view1/index.js
As far as I know, there is no way of forcing grails to directly serve content which is outside of web-app.
Alternatively, you can inline your JavaScript, but that can have performance implications.
JavaScript files belong under web-app/js.
Then you can reference them using <g:javascript src="index.js" />.