I'm using the updated documentation for Assemble.js and am having a hard time getting a clear picture of how to use Partial includes within subfolders using Handlebars.
The only meaningful reference I've found to partial config in assemblefile.js is in the deprecated gulp-assemble doc site.
Assemble.io isn't helpful since it's not up-to-date with the latest github repo.
Here's my assemblefile.js:
'use strict';
var assemble = require('assemble');
var app = assemble();
var streamRename = require('stream-rename');
var markdown = require('helper-markdown');
app.helper('markdown', require('helper-markdown'));
app.task('load', function(callback) {
app.partials(['templates/partials/*.hbs']);
app.pages(['templates/*.hbs']);
callback();
})
app.task('assemble', ['load'], function() {
return app.toStream('pages')
.pipe(app.renderFile())
.pipe(streamRename({extname:'.html'}))
.pipe(app.dest("./"));
});
app.task('default', ['assemble']);
module.exports = app;
My file structure:
root
---/templates
------index.hbs
------/partials
---------myPartial.hbs
When I try to invoke the partial from index.hbs with:
{{> partials/myPartial.hbs}}
The assemble task generates this error:
The partial partials/myPartial.hbs could not be found
How do I include Handlebars partials within subdirectories with a simple Assemble build?
Just use the stem of the partial filename:
{{> myPartial }}
There's also a built-in helper called partial that attempts to find the partial by the key (like myPartial) or other properties like path (partials/myPartial.hbs)
{{partial 'myPartial'}}
More information about how the templates work together can be found in the templates readme. These docs are also linked to from the assemble readme.
Related
I'm trying to rewrite my website(Pug+Express) in Sapper(sveltejs). I'm a beginner in sveltejs , so kindly excuse if my question may come out really naive.
I have a template.json file that contains all the static data of my website. In the expressjs version I do const template = require('template.json') and render the page using pug template something like this
router.get('/:pageName', function(req, res, next) {
res.render('pages/About', {template: template})
What would be an equivalent version of achieving this in sveltejs/sapper?
So far I did an import template from 'template.json' in app/server.js file.
Then what? Since the sapper-template is using polka instead of express, I'm confused how to get it right.Any suggestions?
You'd put that data in the pages (i.e. components in routes) that use it:
<!-- routes/index.html -->
<h1>{{title}}</h1>
<script>
import data from './_template.json';
export default {
data() {
return {
title: data.title
};
}
};
</script>
Note that I've added an underscore to _template.json, to hide the file from the router — you could also just place the JSON file outside the routes directory.
You can use Express instead of Polka; just npm install express and replace every occurrence of polka in app/server.js with express.
I understand that Pug does not support dynamic includes or extends in templates. Ie
extend path/to/template
works but not
extend #{dynamic_path_to_template}
Is there a workaround (however convoluted) that will allow the same goal of modifying the template used by a view at runtime
Context: My use case is that I am developing an npm module and the template being used to extend other views is located inside the module. After the module is published and installed, the path will be defined (ie. node_modules/my_module/path/to/template) but during the development phase, I need to just be able to "npm link" to the module and have the templates work. I also would prefer not to hard code the links so I can publish the same code as tested.
I had this issue aswell and found this question while searching for a solution. My solution is similar to Nikolay Schambergs Answer, but i thought i should share it.
I've created a function that renders templates by giving it a path and passed it to the options object. Maybe it helps in your case aswell
const includeFunc = (pathToPug, options = {}) => {
return pug.renderFile(pathToPug, options); //render the pug file
}
const html = pug.renderFile('template.pug', {include: includeFunc});
and then use it as followed in your template:
body
h1 Hello World
|!{include(dynamicPugFilePathFromVariable)}
There is no way to do this for now, but you can work out your application architecture without dynamic extends.
Possible solution #1
Make a layout.jade that conditionally include multiple layouts:
layout.jade:
if conditionalVariable
include firstLayout.jade
else
include otherLayout
In your view, extend layout.jade, and define conditionalVariable in the controller (true/false):
view.jade:
extends layout
block content
p here goes my content!
Possible solution #2
Pass configurations to the layout
- var lang = req.getLocale();
doctype html
block modifyLayout
split the project into multiple entrances, each entrance extends the layout and passes its different configs, and includes different things in different blocks
extends ../layout
block modifyLayout
- var lang = "en" //force language to be en in this page.
block body
include my-page-body
Possible solution #3
use something like terraform which uses pug as its rendering engine, but it enables you to use dynamic partials like this
!= partial(dynamicFileFromVariable)
It works!
First, set res.locals middleware.
middlewares/setResLocals.js
const pug = require('pug')
const path = require('path')
module.exports = function(req, res, next) {
res.locals.include = (pathToPug, options = {}) => { // used for imitate includ pug function
return pug.renderFile(pathToPug, options); //render the pug file
}
res.locals.__PATH__ = path.join(__dirname, '../')
next()
}
server/index.js
app.use(require('../middlewares/setResLocals'))
file.pug
|!{include(`${__PATH__}/${something}`)}
In order to do dynamic include, you will have to use Unescaped String Interpolation, inserting pug contents that are pre-compiled before your main .pug file inside your route. In other words it works as follows:
1) Some .pug files are pre-compiled into HTML
2) The HTML gets fed into another .pug file compilation process
Here's an example how to do it
Inside your router file (routes.js or whatever)
var pug = require('pug')
var html = []
var files = ['file1','file2'] // file names in your views folders
let dir = path.resolve(path.dirname(require.main.filename) + `/app/server/views/`)
//dir is the folder with your templates
app.get('/some-route', (req,res) => {
for (let n = 0; n < files.length; n++) {
let file = path.resolve(dir + '/' + files[n] + `.pug`)
fs.access(file, fs.constants.F_OK, (err) => {
if (!err) {
html.push(pug.renderFile(file, data))
if (n === files.length - 1) {
res.render('dashboard', {html})
}
}
else {
res.status(500).json({code:500,status:"error", error:"system-error"})
}
})
}
})
Inside your desired .pug file:
for item in html
.
!{item}
The example above is specific to my own use case, but it should be easy enough to adapt it.
I know, this is a bit late for answering. But I found a possibility suitable for my purpose by this bit of information from the pug docs:
If the path is absolute (e.g., include /root.pug), it is resolved by
prepending options.basedir. Otherwise, paths are resolved relative to
the current file being compiled.
So, I provide most of my pug modules by relative paths and the stuff I want to exchange dynamically is organised in pug files of the same name but in different folders (think theme) and include them by absolute paths . Then I change the basedir option to dynamically choose a set of pug files (like choosing the theme).
May this help others, too.
I am precompiling my templates into JS using gulp-handlebars but I am having trouble getting custom handlebars helpers to also precompile. Does anyone know if there is any support/way to precompile custom helper methods?
I noticed that gulp-handlebars can use a specific handlebars library, essentially overriding its default. So, by just creating my own module and registering some helpers, and feeding that into the handlebars call, things are working locally.
// helpers.js
var handlebars = require('handlebars');
handlebars.registerHelper('upper', function(str){
return str.toUpperCase();
});
module.exports = handlebars;
And then in the gulpfile (something like this):
var handlebars = require('./src/js/helpers.js');
gulp.task('handlebars', function(){
gulp.src('src/html/*.html')
.pipe(gulp_handlebars({handlebars: handlebars})) // override library here
});
If you're using Browserify and optionally watchify and need the output to be a commonjs style module, gulp-defineModule will use a require('Handlebars') in the compiled template file.
This negates any registered helpers that you had passed into gulp-handlebars custom library option (see above). Here is an example of the output file we don't want:
// template.js
var Handlebars = require("handlebars");
module.exports = Handlebars.template({"compiler":[7,">= 4.0.0"]...
1: To fix this, create a helpers.js file that requires the handlebars library, adds the helpers, and then exports the library. Use gulp-defineModule's require option to pass in the handlebars library with the helpers like so:
.pipe(defineModule('node', {
require: {
Handlebars: '../helpers'
}
})
)
this will produce:
// template.js
var Handlebars = require("../helpers");
module.exports = Handlebars.template({...
Note that the relative path will be from the outputfile, and be careful on prod where filepaths may change.
2: Another way is to use gulp-wrap to define the module exactly how you want it. Something like:
.pipe(wrap('module.exports = function(Handlebars) {return Handlebars.template(<%= contents %>) }'))
then in main-js:
var Handlebars = require('./helpers');
var template = require('./template)(Handlebars);
After the latest release of EmberJS v1.9.0 I am trying to move from Handlebars to HTMLbars. What I am finding very challenging is lack of documentation.
I am trying to implement very simple helpers.
For example take this handlebars helpers:
HTML
<div id="main"></div>
<script type="text/x-handlebars" data-template-name="index">
{{logIt test}}
<h1>{{test}}</h1>
</script>
JS
App = Ember.Application.create({
rootElement: '#main'
});
App.IndexRoute = Ember.Route.extend({
setupController: function(controller){
controller.set('test', 'mytest');
}
});
Ember.Handlebars.registerHelper("logIt", function(something) {
console.log(something);
});
Js Fiddle: http://jsfiddle.net/sisir/p463q2L8/
How do I convert it to htmlbars?
As of Ember 1.13, there are two APIs: http://emberjs.com/blog/2015/06/12/ember-1-13-0-released.html#toc_new-ember-js-helper-api
The simplest and more common syntax is now this:
export default Ember.Helper.helper(function(params, hash) {
return params.join(' ');
});
Helpers receive two arguments: params are the ordered params passed to a helper, and hash contains the key-value options, for example title="Mr.".
As of Ember 1.10.0, this question is solved by doing Ember.HTMLBars.makeBoundHelper(theHelperFunction).
Edit: since Ember 1.13.6 (July 31, 2015), using this is flagged as deprecated.
DEPRECATION: Using Ember.HTMLBars._registerHelper is deprecated. Helpers (even dashless ones) are automatically resolved. [deprecation id: ember-htmlbars.register-helper]
I believe you can just use Ember.Handlebars.helper which is what is in the latest emberjs guides. This jsbin uses htmlbars and it works. This is the helper in the jsbin
AppLogItHelper = Ember.Handlebars.helper("logIt", function(something){
console.log(something);
});
If you are using ember-cli it will auto generate one for you but that uses Ember.Handlebars.makeBoundHelper which doesn't work in the jsbin but works in my ember-cli app.
Very an important novelty is HTMLBars have subexpression! Since Ember 1.10+ was switched to HTMLBars and you should use Ember.HTMLBars.makeBoundHelper instead Ember.Handlebars.registerHelper. But you can still use Ember.Handlebars.registerHelper from Ember 1.10.1 version
New approach:
App.XEqHelper = Ember.HTMLBars.makeBoundHelper(function(params, hash, options, env) {
return params[0] === params[1];
});
it call from templates as:
{{#if (x-eq order 'delivery_order')}}
Need a delivery
{{/if}}
I have a marionette project, and I have my main js file which looks like:
define(["marionette", "handlebars"], function(Marionette, Handlebars){
...
});
Now I want to make a structure of my big app. So I would like to separate the content of this function to different files. So how can I do something like:
define(["marionette", "handlebars"], function(Marionette, Handlebars){
include routes.js
include menu/model.js
include menu/views.js
...
});
I think require.js can help me, but I don't know how. Any ideas?
To require a file in the AMD structure (like the one you describe), you can give the path to the file in the array and get the exported value as argument of the callback like this.
define(
[
"marionette",
"handlebars",
"routes",
"menu/model",
"menu/views"
],
function(Marionette, Handlebars, Routes, Model, MenuView){
// ...
});
Since this is a very basic thing in AMD, you should really read the documentation of Require.JS (here) and explanation about AMD modules (like this one). You will find lot of information about the AMD structure, etc
If you prefer, browserify lets you to load front-end javascript modules using the require syntax. It looks like this.
// library includes
var Marionette = require('backbone.marionette');
var handlebars = require('handlebars');
// custom includes
var routes = require('./routes.js');
var models = require('./menu/models.js');
var views = require('./menu/views.js');
var App = new Marionette.Application();
It includes modules recursively and there is less code. It implements the Common.js format so it looks and feels the same as node.js.