jknack / handlebars.java

Logic-less and semantic Mustache templates with Java
http://jknack.github.io/handlebars.java
Other
1.47k stars 383 forks source link

compiling templates takes a LONG time in android tablet #166

Closed benmonro closed 6 years ago

benmonro commented 11 years ago

I'm using Handlebars.java in an android project. I'm using the FileTemplateLoader and I am making use of the '{{#block}}' helper to render a second file inside the first. The process of compiling these 2 files is VERY slow. Compiling the first outer template takes 14.5 seconds and the inner template takes 33.6 seconds. here is a snipped of my code. Am I doing something wrong?

public void renderForm(String formName) throws IOException {

        TimingLogger timings = new TimingLogger("FormTimings", "FormRender");

        final File templatesDir = new File(context.getFilesDir().getAbsolutePath() + "/templates/");
        if (!templatesDir.exists()) {
            templatesDir.mkdirs();
        }
        File layoutFile = new File(templatesDir.getAbsolutePath() + "/formLayout.hbs");
        if (layoutFile.exists() == false) {
            FileUtils.copyInputStreamToFile(context.getAssets().open("web/templates/formLayout.hbs"), layoutFile);
        }

        timings.addSplit("files setup");

        Handlebars handlebars = new Handlebars(new FileTemplateLoader(templatesDir));

        timings.addSplit("handlebars loaded");

        handlebars.compile("formLayout"); //<-- takes 14 seconds

        timings.addSplit("formLayout compiled"); 

        Template home = handlebars.compile(formName); //<-- takes 33 seconds

        timings.dumpToLog();
}
jknack commented 11 years ago

yaik!

Did you see this https://github.com/jknack/handlebars.java/issues/135? In 0.10.0 I moved from parboiled to antlrv4, and in general the parsing/compile process has been improved and is in the order of ms.

So, what version of handlebars.java? can you share the templates you are trying to compile?

I will have a look.

benmonro commented 11 years ago

I'm using 0.12.0. I found a bunch of extra stuff in the 2nd form, so I removed that, which definitely helped a lot, but the formLayout.hbs can't change

here are my templates: _formLayout.hbs_

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="file:///android_asset/web/css/bootstrap.css">
    <link rel="stylesheet" href="file:///android_asset/web/css/bootstrap-responsive.css">

    <link rel="stylesheet" href="file:///android_asset/web/css/custom.css"/>
    <link rel="stylesheet" href="file:///android_asset/web/css/toggle-switch.css">
    <script src="file:///android_asset/web/js/jquery-1.8.3.min.js"></script>

    <script type="text/javascript" src="file:///android_asset/web/js/jquery.form.js"></script>
    <script src="file:///android_asset/web/js/bootstrap.js"></script>

    <script src="file:///android_asset/web/sigPad/jquery.signaturepad.min.js"></script>

    <script src="file:///android_asset/web/sigPad/json2.min.js"></script>

    <script type="text/javascript">

        function pageLoad() {
            $('.sigPad').signaturePad({defaultAction:"drawIt",lineTop:80});
            //activity.toast("form load complete");
        }

        function setVal(element, text) {
            $(element).val(text);
        }

        $(function(){
            $("input[type='date']").click(function() {
                activity.pickDate($(this).attr("id"));
            });

            $("input[type='time']").click(function() {
                activity.pickTime($(this).attr("id"));
            });
        });

        $.fn.serializeObject = function()
        {
            var o = {};
            var a = this.serializeArray();
            $.each(a, function() {
                if (o[this.name] !== undefined) {
                    if (!o[this.name].push) {
                        o[this.name] = [o[this.name]];
                    }
                    o[this.name].push(this.value || '');
                } else {
                    o[this.name] = this.value || '';
                }
            });
            return o;
        };

        function submitForm() {
//            if ($('input[name=radio-accept-route]:checked', '#form').val()) {
//                //var accept = $('input[name=radio-accept-route]:value', '#form').val();
//                //   activity.toast("accept: " + accept);
//
//                alert($("#form").formSerialize());
//
//                //activity.toast("before serialize");
//                //activity.toast( $('#form').formSerialize() );
//                activity.submitForm($('#form').formSerialize());
//                activity.toast("form info sent")
//            } else {
//                activity.toast("You must accept or reject this route.");
//            }
            //  alert($('input[name=radio-accept-route]:checked', '#myForm').val())
            // comment for a commit test
//

                activity.submitForm(JSON.stringify($('#messageForm').serializeObject()));
                activity.toast("form info sent")
        }

    </script>
    <style>
        .onoffswitch {
            position: relative; width: 100px;
            -webkit-user-select:none; -moz-user-select:none; -ms-user-select: none;
        }

        .onoffswitch-checkbox {
            display: none;
        }

        .onoffswitch-label {
            display: block; overflow: hidden; cursor: pointer;
            border: 0px solid #999999; border-radius: 0px;
        }

        .onoffswitch-inner {
            width: 200%; margin-left: -100%;
            -moz-transition: margin 0.3s ease-in 0s; -webkit-transition: margin 0.3s ease-in 0s;
            -o-transition: margin 0.3s ease-in 0s; transition: margin 0.3s ease-in 0s;
        }

        .onoffswitch-inner > div {
            float: left; position: relative; width: 50%; height: 30px; padding: 0; line-height: 30px;
            font-size: 14px; color: white; font-family: Trebuchet, Arial, sans-serif; font-weight: bold;
            -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
        }

        .onoffswitch-inner .onoffswitch-active {
            padding-left: 15px;
            background-color: #C2C2C2; color: #FFFFFF;
        }

        .onoffswitch-inner .onoffswitch-inactive {
            padding-right: 15px;
            background-color: #C2C2C2; color: #FFFFFF;
            text-align: right;
        }

        .onoffswitch-switch {
            width: 40px; margin: 0px; text-align: center;
            border: 0px solid #999999;border-radius: 0px;
            position: absolute; top: 0; bottom: 0;
        }
        .onoffswitch-active .onoffswitch-switch {
            background: #27A1CA; left: 0;
        }
        .onoffswitch-inactive .onoffswitch-switch {
            background: #A1A1A1; right: 0;
        }

        .onoffswitch-active .onoffswitch-switch:before {
            content: " "; position: absolute; top: 0; left: 40px;
            border-style: solid; border-color: #27A1CA transparent transparent #27A1CA; border-width: 15px 10px;
        }

        .onoffswitch-inactive .onoffswitch-switch:before {
            content: " "; position: absolute; top: 0; right: 40px;
            border-style: solid; border-color: transparent #A1A1A1 #A1A1A1 transparent; border-width: 15px 10px;
        }

        .onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
            margin-left: 0;
        }

    </style>
    <title></title>
</head>

<body>
<div class="ribbon-wrapper-green"><div class="ribbon-green">Preview</div></div>

<div id="pageContent" data-role="page">
    <div id="content" style="">
        {{#block "content"}}
            Loading...
        {{/block}}
    </div>
</div>

</body>
</html>

_formName.hbs_


<form id="messageForm" class="form-horizontal sigPad">

    <fieldset class="legend">
        <div id="legend" class="">
            <span class="">AAA</span>
        </div>
    </fieldset>

    <fieldset id="fieldset1" class="ember-view fieldset oneCol">

      <div id="ember638" class="ember-view controls formrow formheader" dropid="drop-0" draggable="true" data-original-title="" title="">

        <label class="control-label formheaderlabel">Form Header</label>

    </div>

    <div id="ember641" class="ember-view controls formrow" dropid="drop-1" draggable="true" data-original-title="" title="">

        <label class="control-label">Text Field</label>
        <input type="text" placeholder="placeholder" class="input-large autoid">

    </fieldset>
</form>
benmonro commented 11 years ago

wow. I moved my inline style & js into seperate files and now its taking 2 seconds... MUCH better, BUT. the 2nd form could still in theory have a larger file size. It seems that as the file size gets larger, the compiling takes a LOT longer... any suggestions?

benmonro commented 11 years ago

looks like minifying the HTML helps. Total time is 5-6 seconds to compile both templates... it'd be nice if I could shrink that down some more though. :)

jknack commented 11 years ago

do me a favor, share with me the full pages (the ones that where causing over 10secs of compile time), can you?

benmonro commented 11 years ago

the ones above are the ones that were taking 14 seconds. keep in mind, this is running on an android 2.3 tablet w/ a 1 GHz processor. If you copy & paste the content of the 2nd file a few times, you'll start to see the compile times jump up.

jknack commented 11 years ago

yea I see, my laptop process the formLayout file in 200ms so not sure how can I help :S

It will be great if you can tell me if the parser is consuming all the time or the file read. ANTLRv4 read all the file before parsing it.

benmonro commented 11 years ago

How can I tell that?

jknack commented 11 years ago

can you check how much does it take this line:

ANTLRInputStream stream = new ANTLRInputStream(reader);
benmonro commented 11 years ago

Hi there, sorry for the really long delay, got pulled onto other issues, I'm back now though. I added the call as you described, that is pretty quick, about 500ms for really big pages. Btw, I have pages even bigger than the one above, they are taking up to 85 seconds to render! Minifying the HTML seems to help a little, but that causes other issues which I'd like to avoid... Any suggestions you can give would be much appreciated.

jknack commented 11 years ago

I upgrade to ANTLR 4.1 were there are some performance improvements. Can you try with 1.1.0 release?

benmonro commented 11 years ago

we just upgraded to the 1.1.1 release. It's still very slow on android 2.3.3 with an 800MHz processor... any advice?