Is template compiled on router?

I’m starting with Framework7 after reading the docs to my best capacities, and searching for hours to try to understand this topic about routes/templates.
Let’s take the following example, from the “official starter templates” page

  {
path: '/page-loader-template7/:userId',
async: function (routeTo, routeFrom, resolve, reject) {
	app.request.post('http://someurl/userdata.php',
			{
				user_id: routeTo.params.userId
			},
			function (data) {
	    		resolve( 
					{
					templateUrl: './pages/page-loader-template7.html'
					},
					{
					context: {
					  user: data,
					}
					});
	    	},
	    	null,
	    	'json'
	);
	
}

},

So far so good. That works. But, here, it says:

Template7 is fast and you can make it even faster in your apps. The slowest part (but still very fast in T7) in compilation/rendering process is the compilation from string to pure JS function when you do Template7.compile(). So don’t compile the same templates multiple times, one time will be enough:

And here, it says (on the description of the templateUrl route property):

Load page content from url via Ajax, and compile it using Template7

So, i came up with this:

  {
path: '/page-loader-template7/:userId',
async: function (routeTo, routeFrom, resolve, reject) {
	app.request.post('http://someurl/userdata.php',
			{
				user_id: routeTo.params.userId
			},
			function (data) {
	    		resolve( {
	    			template: compiled_template(data)
	    		});
	    	},
	    	null,
	    	'json'
	);
	
}

},

That also works, but it requires that the template be defined in the same file as the routes, which is kind of unscalable and awkward.

So, questions:

  1. Using the first, suggested, way, is the template really compiled every time we navigate to the route, making it slow, as they recommend NOT to do?
  2. Using the second, own, way, is there some way i can put the template (even component, eventually) in a separate file?

Thanks!

=> 1. yes, every time.
=> 2.

resolve({template:compiled_template(data)});

is equivalent to

Template7.compile(Template7.compile()({}))({});

so it is actually slower
it will be better if you do this:

resolve({template:compiled_template},{context:data});

and this condition will be in use by F7 core:

else {
  // Supposed to be function
  html = options.template(component);
}

so it will NOT get compiled every time (never by router)
it is only render every time

framework7.js:4763

// Render template
function render() {
  var html = '';
  if(options.render) {
    html = options.render();
  } else if(options.template) {
    if(typeof options.template === 'string') {
      try {
        html = Template7.compile(options.template)(component);
      } catch(err) {
        throw err;
      }
    } else {
      // Supposed to be function
      html = options.template(component);
    }
  }
  return html;
}
var html = render();

Hi! Thanks for your answer.
I was trying to understand it and follow the code you point me to, but now i’m getting

(post withdrawn by author, will be automatically deleted in 24 hours unless flagged)

Can you, please, tell me what it means? Can i see your answer again?

i thought you are using componentUrl
my meastake

Thanks anyway. Didn’t get to grasp the idea but looked promising. :slight_smile:

{
  path:'/page-loader-template7/:userId',
  async:function(routeTo,routeFrom,resolve,reject){
    app.request.json('http://some-endpoint/',function(data){
      resolve({template:compiled_template},{context:data});
    });
  }	
}

Thanks again! I’ll try this and let you know.
However, as far as i can see, this is very similar to the second way of the two i’ve posted, except instead of

resolve( {
    			template: compiled_template(data)
    		});

you suggest

resolve({template:compiled_template},{context:data});

Which actually is your first suggestion on the previuos answer.

Which leads me to ask: Does that difference alone prevent f7 to recompile the template every time?

There is difference between two.

  1. This:

Actually pointless as you already passing rendered by Template 7 string as a template again. So router will try to compile it again. In this case, when you do compilation and template rendering on your own, it is better to pass it as just a content:

resolve({
  content: compiled_template(data)
});

As @plpl said, it is better to use:

resolve({template:compiled_template},{context:data});

Does that difference alone prevent f7 to recompile the template every time?

No, because you already compiled template manually and store it in compiled_template variable.

Using the second, own, way, is there some way i can put the template (even component, eventually) in a separate file?

You can put them in single file in global templates object:

// templates.js
window.templates = {
  item_template: ...,
  catalog_template: ...,
};

And later when you need them you can just reference for templates.item_template

So cool! Thanks a lot! Both of you have been of great help.
On the weekend i was reading the source of framework7, and now i can understand and implement your ideas much better than when i first asked this question.

This, for instance, is really clear now. Thanks, again, both of you.

As for this:

I solved it in a slightly different way. I put the templates in a plain file (with arbitrary .tpl extension), between

<script type="text/template7" id="kkk" ... tags

tags.
Then, on app:init, i load (Framework7.request.get()) that file, compile each template, save them to variables for later use without recompilation needed, and only passing the corresponding parameters. This way, i get the little burden of having to Framework7.request.get() the file, but i can write the templates more clearly than inside an object, as the counterpart of the convenience your suggestion has (include the .js file with the templates object directly in the html of your index page)
I think it’s a slight difference, but considered mention it in case it can be useful or more comfortable to some one reading this post.

Back on the important, thanks again to both of you.

the code need to be clear to you
not to the engine

here is an idea (for prod)
how to save time to your engine

-1 open console
-2 type this:

var tmpl='<div class="page">\
            <div class="navbar">\
              <div class="navbar-inner sliding">\
                <div class="title">{{title}}</div>\
              </div>\
            </div>\
            <div class="page-content"></div>\
         </div>';
// compile
Template7.compile(tmpl);

-3 click/copy the output
-4 paste in app.js

window.templates = {
  page_template:(function(ctx_1, data_1, root) {
    function isArray(arr){return Array.isArray(arr);}
    function isFunction(func) {return(typeof func === 'function');}
    function c(val, ctx) {
      if(typeof val !== "undefined" && val !== null) {
        if(isFunction(val)) { return val.call(ctx); } else return val;
      } else return "";
    }
    root = root || ctx_1 || {};
    var r = '';
    r += '<div class="page"><div class="navbar"><div class="navbar-inner sliding"><div class="title">';
    r += c(ctx_1.title, ctx_1);
    r += '</div></div></div><div class="page-content"></div></div>';
    return r;
  })
};
//then you can use it like this:
window.templates.page_template({title:"my title"});

or in component/componentUrl

//componentUrl.html
/* remove template tag */
<!--template></template-->
/* leave only the script */
<script>
return { 
  template:(function(ctx_1, data_1, root) {
    function isArray(arr){return Array.isArray(arr);}
    function isFunction(func) {return(typeof func === 'function');}
    function c(val, ctx) {
      if(typeof val !== "undefined" && val !== null) {
        if(isFunction(val)) { return val.call(ctx); } else return val;
      } else return "";
    }
    root = root || ctx_1 || {};
    var r = '';
    r += '<div class="page"><div class="navbar"><div class="navbar-inner sliding"><div class="title">';
    r += c(ctx_1.title, ctx_1);
    r += '</div></div></div><div class="page-content"></div></div>';
    return r;
  }),  
  data:function(){
    return {
      title: 'my title'
    };
  }
}
</script>

I dont understand this.