In a large Wicket application with many components, you may run into the problem of sending duplicate Javascript code to the browser. In this best case, this will just make the UI feel more sluggish, and in the worst, can result in hard to debug bugs.
A Wicket application I work on has lots of different UI elements, such as date pickers, file uploads, footables, select2 dropdowns, input masks, etc. A client-side script runs to initialize them and needs to be re-executed when Wicket re-renders forms and panels. The initialization script is relatively expensive and is often executed multiple times when many different Wicket components need to be re-rendered and each request to be re-initialized.
Custom AjaxRequestTarget
Instead of trying to deal with duplicate Javascript code appended to the target on the client-side, we can prevent it from getting to the browser in the first place.
We need to implement a custom AjaxRequestTarget provider. Unfortunately, the default AjaxRequestHandler class is not flexible enough to override, so we have to completely replace it. The actual changes that need to be made are small. You can see the whole class here. Let’s take a look at the parts that have to change:
update = new XmlPartialPageUpdate(page) {
...
@Override
protected void writeNormalEvaluations(final Response response, final Collection<CharSequence> scripts) {
writeEvaluationsDeDupe(response, "evaluate", scripts);
}
@Override
protected void writePriorityEvaluations(Response response, Collection<CharSequence> scripts) {
writeEvaluationsDeDupe(response, "priority-evaluate", scripts);
}
private void writeEvaluationsDeDupe(final Response response, String elementName, Collection<CharSequence> scripts) {
if (scripts.size() > 0) {
Collection<CharSequence> distinct = scripts.stream().distinct().collect(Collectors.toList());
if(distinct.size() > 0) {
StringBuilder combinedScript = new StringBuilder(1024);
for (CharSequence script : distinct) {
combinedScript.append("(function(){").append(script).append("})();");
}
writeEvaluation(elementName, response, combinedScript);
}
}
}
...
};
We override the functionality of XmlPartialPageUpdate to strip out the duplicate strings before writing them to the response. To use our new DeDupeAjaxRequestHandler, we just need to register it in our WebApplication:
public void init() {
...
setAjaxRequestTargetProvider(new DeDupeAjaxRequestTargetProvider());
...
}
private static class DeDupeAjaxRequestTargetProvider implements Function<Page, AjaxRequestTarget> {
@Override
public AjaxRequestTarget apply(Page components) {
return new DeDupeAjaxRequestHandler(components);
}
}