Meteor is pretty amazing in that you can update the HTML files manually while developing locally and those changes take affect immediately when you save the file. I would like to take that same functionality and bring it to our deployed environment. The reason being that we would like to allow our client to make changes to the UI without having to redeploy the application or even know it's a Meteor app. They might add new fields to a list view, new fields to a form, change labels, etc.
Thus far, I've created a means for them to call a REST service using a DSL to describe those changes and save it in Mongo. Then we have an engine that will dynamically create the HTML templates to implement it. That all works great.
Next, I'm attempting to do a hot deploy of Meteor HTML files based off a subscription I have with the Meteor DB which stores things that could change on demand. Is it possible to update the Meteor client filesystem on the fly so I can achieve a hot deploy?
Doing the following on the server publish method results in an ENOENT: no such directory
error:
var result = decodeHTML(cheerio.html());
console.log(result);
// Output to file
fs.writeFile('../client/app/client/templates/request-base-template.html', result, function (err) {
if (err) {
console.log("error: " + err);
}
else {
console.log("File saved successfully");
}
});
Saving files to disk to expect "Hot code push reloads" is definitely a wrong way to go here.
Meteor provides file-watching in the development mode, and it will recompile your whole app and refresh the page in your browser, but this is made for the developer convenience and not for the run-time use by your application. In fact, file-watching is not even shipped when deployed in production.
But here is a way to implement your use-case. It would require some deeper understanding of what Meteor is doing behind the scenes for you.
First of all, you need to realize that Meteor compiles your templates (Spacebars templates) to its own JS DSL (HTMLJS) in the build time. Similar things happen to every structure-based templating, either you compile them in run-time or in build-time. Meteor does it in build-time to make things more efficient. You can read more about it in Meteor Manual, Blaze chapter;
The high-level point here is: if you have a template
<template name="bla">
Hello {{name}}!
</template>
.. it would be compiled to something like this:
Template.__define__("bla", (function() {
var view = this;
return [ "Hello ", Blaze.View(function() {
return Spacebars.mustache(view.lookup("name"));
}), "!" ];
}));
Got it? Great.
Now, you need to get this kind of templates from users and compile them into this JS-based DSL. You can do it with the built-in spacebars-compiler
package.
// on the server!
Meteor.startup(function () {
// imagine your template is actually coming from database or where you store your user-generated content
var template = "<p>Hello {{name}}!</p>";
console.log(SpacebarsCompiler.compile(template));
});
If you add spacebars-compiler
to your app and run this, it will print a nice compiled template. Here is a live demo: http://meteorpad.com/pad/4tHHAvjpcBQwLuN4K
Perfect, now ship this compiled template to the client in any form you want (through database, through a Meteor method or a REST API, it doesn't matter, just get the string to the client).
Once it is there, you can attach it anywhere you want!
One of the easier ways to do it is to register the template in JS code:
// on the client! pretend you got the compiledTemplate string from the server
var compiledTemplate = '(function() { var view = this; return HTML.P("Hello ", Blaze.View(function() {return Spacebars.mustache(view.lookup("name")); }), "!");})';
Template.__define__("myAwesomeTemplate", eval(compiledTemplate));
And then use things like UI.dynamic
to render it on the page. You can see a live demo here: http://meteorpad.com/pad/LQJuoooBQjSdJenfW
Would you agree that you are writing a customized cms system? If so, there are already a few cms systems in meteor.
I found it easy to extend an earlier version of http://azimuthc.ms/
They basically had your needs in mind when they wrote this.
(I am not connected to this project)