New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
webpack: Use handlebars-loader to handle frontend templates. #12667
Conversation
static/js/templates.js
Outdated
+ ". If you are developing a new feature, this likely " | ||
+ "means you need to add the file static/templates/" | ||
+ name + ".handlebars"); | ||
for (var i = 0; i < template_paths.length; i += 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can do this or add the path to all the references to settings/widgets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoa. I didn’t realize webpack has special support for require()
on computed strings like that, but yes, apparently it’s smart enough to parse that computation, find all the *.handlebars
files within static/templates
, compile them, and bundle them into a map for runtime dispatch. Wouldn’t have been my first plan but I guess it works!
We don’t want to catch exceptions from rendering here, so the (arg)
should be lifted outside the try…catch
. And using require.context
might help webpack generate slightly more efficient code:
var template_context = require.context('../templates', true, /\.handlebars$/);
var template_paths = ['./', './settings/', './widgets/'];
exports.render = function (name, arg) {
for (var i = 0; i < template_paths.length; i += 1) {
var template;
try {
template = template_context(template_paths[i] + name + '.handlebars');
} catch (_e) {
continue;
}
return template(arg);
}
throw new Error('Cannot find template ' + name + '.handlebars anywhere '
+ 'under the static/templates/ folder.');
};
(Edit: require.context
doesn’t work in the Node tests, so skip that part.)
I think I’d be in favor of adding explicit paths for settings and widgets so as to reduce the amount of magic here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the only reason we didn't have explicit paths for rendering settings/foo.handlebars
was because the old system didn't support naming things that way. So I think passing e.g. settings/foo.handlebars
into .render
is the right approach over doing a loop here.
7102b39
to
88fbe99
Compare
@@ -16,7 +16,7 @@ import "blueimp-md5/js/md5.js"; | |||
import "clipboard/dist/clipboard.js"; | |||
import "string.prototype.codepointat/codepointat.js"; | |||
import "winchan/winchan.js"; | |||
import "handlebars/dist/handlebars.runtime.js"; | |||
import "handlebars/dist/cjs/handlebars.runtime.js"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the story with this change? Are those two both files in the module, or what?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When importing the module without explicitly specifying the path, ie import "handlebars/runtime";
, webpack actually resolve it to handlebars/dist/cjs/handlebars.runtime.js
. Also after adding handlebars-loader, the original Handlebars from handlebars/dist/handlebars.runtime.js
can't find the templates anymore for some reason.
Also is there a reason why we specify the exact file we import instead of just giving the name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In some cases, it makes a difference because whatever/dist/whatever.js
adds itself to the global window
namespace while whatever
is a module that expects to be used the way modules are supposed to be used. We have lots of code that pulls things from window
but we should migrate to the module style whenever it’s convenient. In this case, go with handlebars/runtime
if you can; that’s the documented way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the window
hack is a mess but solved the problem of being able to migrate most asset stuff into webpack. If we can do import handlebars/runtime
, that'd be great.
// Tell webpack not to explicitly require these. | ||
knownHelpers: ['if', 'unless', 'each', 'with', | ||
'partial', 'plural', 'eq', 'and', 'or', 'not', | ||
't', 'tr'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the story with this list? Does it need to be synchronized with some list elsewhere in the codebase?
If so we should add comments in both places making clear the need to sync the lists, and I'd be curious to know what the exception is if we do it wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are the helpers defined in templates.js combined with the ones we originally passed to handlebars in compile-handlebar-templates line 33. This is to let webpack know these helpers are defined at run time and don't try to require them when bundling. Nothing will happen if these list is not correct, handlebar-loader just have to do more guessing work.
I'll add some comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK.
And remove the compile-handlebars-templates system.
88fbe99
to
94fccc3
Compare
Removed the loop and lifted the |
Awesome, I'm going to test-deploy this on chat.zulip.org and merge it if it works, since the remaining comments seem like things we can do as follow-ups. |
Seems to work in production, so merged, thanks @tommyip! I do think it's still worth looking at whether we can do something nicer for our third-party packages with #12667 (comment). |
We already use webpack expose-loader to attach a lot of our libraries to |
No, see, this isn’t about consistency vs. inconsistency, it’s about right vs. wrong. Attaching everything to |
Yeah, that's why I said
which I am already in the process of doing (as well as other stuff to give webpack and editors better information) What I mean by consistency is the way we configure our third party library is inconsistent. Some library such as moment is attached to window as a side effect ( |
This bug is introduced in zulip#12667.
This bug is introduced in #12667.
As of commit 8c199fd (zulip#12667) this file is no longer generated. Handlebars compile errors are raised as webpack errors. Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
As of commit 8c199fd (zulip#12667) this file is no longer generated. Handlebars compile errors are raised as webpack errors. Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
As of commit 8c199fd (zulip#12667) this file is no longer generated. Handlebars compile errors are raised as webpack errors. Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
And remove the compile-handlebars-templates system.