Response Optimizations too aggressive

21 views
Skip to first unread message

aw

unread,
Mar 4, 2010, 1:38:04 AM3/4/10
to Lift
After fielding calls as to why my UI doesn't look correctly on IE, I
discovered that Lift is doing an "optimization" in "production mode"
that is effectively breaking my application's compatibility for IE...

To get around IE6 deficiencies, I am leveraging JQuery. For example,
if I have a CSS style that uses attribute selectors, like
input[type=checkbox], IE6 ignores them, but I can get JQuery to apply
the style.

Since this JavaScript applies to IE only, I wrap them in comments
like:

<!--[if IE 6]> <script type="text/javascript" id="ie6fix"> ... </
script> <![endif]-->

Firefox and Chrome will ignore these, which is perfect, and only IE
will pay attention (and suffer the overhead).

All was working fine in dev, then came time to roll out to production
and I naturally specified -Drun.mode=production. Surprisingly,
"production mode" has an "optimization" that strips HTML comments from
the output. Generally, I think this is a great idea -- EXCEPT if we
have IE specific comments responding to an IE browser.

Is there a way to modify the optimization so that IE specific comments
are retained? Alternatively, can I simply disable this optimization
feature so that my IE users are OK?

How can I find out more about these "production mode optimizations"?
Is there a list?

I have drilled into Props.scala and I read it very carefully. I think
of my environments as Dev/QA/Prod, but I think this translates best to
Test/Staging/Production in Lift-speak. I am expecting that
"production mode optimizations" are applied to both Staging (aka QA)
as well as Production -- because I need to validate actual production
behavior.

Note that I am running 2.0-M2.

Ross Mellgren

unread,
Mar 4, 2010, 1:56:16 AM3/4/10
to lif...@googlegroups.com
There's a FactoryMaker in LiftRules that looks like it may do what you want -- try:

LiftRules.stripComments.default = () => false

-Ross

> --
> You received this message because you are subscribed to the Google Groups "Lift" group.
> To post to this group, send email to lif...@googlegroups.com.
> To unsubscribe from this group, send email to liftweb+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
>

Naftoli Gugenheim

unread,
Mar 4, 2010, 1:58:53 AM3/4/10
to lif...@googlegroups.com
I don't know the answer, but did you look through LiftRules to see if there's any setting about comments?

-------------------------------------

aw

unread,
Mar 4, 2010, 2:47:11 AM3/4/10
to Lift

On Mar 3, 10:56 pm, Ross Mellgren <dri...@gmail.com> wrote:
> There's a FactoryMaker in LiftRules that looks like it may do what you want -- try:
>
> LiftRules.stripComments.default = () => false
>
> -Ross

This looks promising. Alas: error: reassignment to val

(I'm not familiar with FactoryMaker.) I see that
LiftRules.stripComments is a val, not a var... It's unclear to me how
to override this.

Jeppe Nejsum Madsen

unread,
Mar 4, 2010, 3:36:58 AM3/4/10
to lif...@googlegroups.com
aw <ant...@whitford.com> writes:


[...]

> <!--[if IE 6]> <script type="text/javascript" id="ie6fix"> ... </
> script> <![endif]-->
>
> Firefox and Chrome will ignore these, which is perfect, and only IE
> will pay attention (and suffer the overhead).
>
> All was working fine in dev, then came time to roll out to production
> and I naturally specified -Drun.mode=production. Surprisingly,
> "production mode" has an "optimization" that strips HTML comments from
> the output. Generally, I think this is a great idea -- EXCEPT if we
> have IE specific comments responding to an IE browser.
>
> Is there a way to modify the optimization so that IE specific comments
> are retained? Alternatively, can I simply disable this optimization
> feature so that my IE users are OK?

Ross already described how to disable this, but this seems like a
genuine useful feature (to not remove some comments). Iircc, there are
other scenarios (such as AdWords) where you would like to keep the
some comments.

Not sure how to handle this in a general way though.

In this case You can also handle it server side: Req.isIE6

/Jeppe

Jeppe Nejsum Madsen

unread,
Mar 4, 2010, 3:43:15 AM3/4/10
to lif...@googlegroups.com


Ahh, think you have to do:

LiftRules.stripComments.default.set(() => false)

/Jeppe

aw

unread,
Mar 4, 2010, 3:50:18 AM3/4/10
to Lift
OK, I have disabled the stripping of comments:

LiftRules.stripComments.default.set( () => false )

It seems to work for me.


On Mar 4, 12:36 am, Jeppe Nejsum Madsen <je...@ingolfs.dk> wrote:


> aw <anth...@whitford.com> writes:
> >     <!--[if IE 6]> <script type="text/javascript" id="ie6fix"> ... </
> > script> <![endif]-->
>

> Ross already described how to disable this, but this seems like a
> genuine useful feature (to not remove some comments). Iircc, there are
> other scenarios (such as AdWords) where you would like to keep the
> some comments.
>
> Not sure how to handle this in a general way though.
>
> In this case You can also handle it server side: Req.isIE6
>
> /Jeppe

Obviously, it would be great to make the stripComments variable
session specific where I could leverage something like isIE. I do see
that FactoryMaker seems to have a session and request specific vending
concept, so this looks promising. I think the code that actually does
the comment stripping is in LiftMerge, so I'm thinking that that would
need to be enriched too. Ideally, I would like to see comments that
are not IE specific to be stripped. (I am unfamiliar with AdWords and
how they use comments.)

Sound like a ticket?

Thanks everybody for the quick help!

Timothy Perrett

unread,
Mar 4, 2010, 8:30:28 AM3/4/10
to lif...@googlegroups.com
Personally, I don't like this API. nearly everyone has problems with it as its totally not obvious. Perhaps i'll add some more comments to the definition.

Cheers, Tim

Naftoli Gugenheim

unread,
Mar 4, 2010, 9:56:54 AM3/4/10
to lif...@googlegroups.com
How about
LiftRules.stripComments.default.set( () => !Req.isIE)
etc.?

-------------------------------------

aw

unread,
Mar 4, 2010, 12:27:28 PM3/4/10
to Lift
On Mar 4, 6:56 am, Naftoli Gugenheim <naftoli...@gmail.com> wrote:
> How about
> LiftRules.stripComments.default.set( () => !Req.isIE)
> etc.?

Well, this doesn't quite work because I need a Req class instance, not
just the static object.
Also, to me, this determination is really at the Session level rather
than the Request level as I don't expect it to change. But of course
I don't have a Session.isIE field... What about Comet responses? I
have no Request in that scenario, but is it using the same code to
produce the xhtml?

I see that the Factory trait has a session-specific Maker and a
request-specific Maker, but it is unclear to me how I can get that
context. I require more guidance.

David Pollak

unread,
Mar 4, 2010, 12:50:19 PM3/4/10
to lif...@googlegroups.com
On Thu, Mar 4, 2010 at 9:27 AM, aw <ant...@whitford.com> wrote:
On Mar 4, 6:56 am, Naftoli Gugenheim <naftoli...@gmail.com> wrote:
> How about
> LiftRules.stripComments.default.set( () => !Req.isIE)
> etc.?

This is where Lift's FactoryMaker shines.  You can modify the behavior of stripComments on a request-by-request basis.  You can have a snippet called from your default template that tests the request and does:

LiftRules.stripComments.request.set(S.request.map(!_.isIE) openOr false)

But, as you point out, that means that CometActors will not get the right settings... so you can set the rule on a session-by-session basis:

LiftRules.stripComments.request.set(S.request.map(!_.isIE) openOr false)

If that's not enough, you could also do the following in Boot.scala:

object shouldStripComments extends SessionVar(S.request.map(!_.isIE) openOr false)

S.addAround(List(new LoanWrapper {
  def apply[T](f: => T): T = LiftRules.stripComments.doWith(shouldStripComments.is)(f)
}))
 
The above code wraps each request with access to the shouldStripComments Session Variable.

The above vomit of different options is more for the benefit of those that are confused by FactoryMaker and why it seems so complex... it's because it offers a ton of different flexibility.

Thanks,

David


Well, this doesn't quite work because I need a Req class instance, not
just the static object.
Also, to me, this determination is really at the Session level rather
than the Request level as I don't expect it to change.  But of course
I don't have a Session.isIE field...  What about Comet responses?  I
have no Request in that scenario, but is it using the same code to
produce the xhtml?

I see that the Factory trait has a session-specific Maker and a
request-specific Maker, but it is unclear to me how I can get that
context.  I require more guidance.
--
You received this message because you are subscribed to the Google Groups "Lift" group.
To post to this group, send email to lif...@googlegroups.com.
To unsubscribe from this group, send email to liftweb+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.




--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Surf the harmonics

Timothy Perrett

unread,
Mar 5, 2010, 2:29:12 PM3/5/10
to lif...@googlegroups.com
This really needs to go on the wiki! gold!

Cheers, Tim

aw

unread,
Mar 8, 2010, 1:26:26 AM3/8/10
to Lift

On Mar 4, 9:50 am, David Pollak <feeder.of.the.be...@gmail.com> wrote:

> On Thu, Mar 4, 2010 at 9:27 AM, aw <anth...@whitford.com> wrote:
> > On Mar 4, 6:56 am, Naftoli Gugenheim <naftoli...@gmail.com> wrote:
> > > How about
> > > LiftRules.stripComments.default.set( () => !Req.isIE)
> > > etc.?
>
> This is where Lift's FactoryMaker shines.  You can modify the behavior of
> stripComments on a request-by-request basis.  You can have a snippet called
> from your default template that tests the request and does:
>
> LiftRules.stripComments.request.set(S.request.map(!_.isIE) openOr false)
>
> But, as you point out, that means that CometActors will not get the right
> settings... so you can set the rule on a session-by-session basis:
>
> LiftRules.stripComments.request.set(S.request.map(!_.isIE) openOr false)

I don't see the difference. I presume that you meant to say:

LiftRules.stripComments.session.set(S.request.map(!_.isIE) openOr
false)

? Alas, neither version works. I get a syntax error:

[ERROR] ...\snippet\Hack.scala:31: error: value set is not a member of
net.liftweb.util.Maker[Boolean]
[INFO] LiftRules.stripComments.request.set(S.request.map(!_.isIE)
openOr false)
[INFO] ^
[ERROR] one error found

Seeing that request is really a RequestVar, I figure the mod is simple
(lose the .set), but:

[ERROR] ...\snippet\Hack.scala:31: error: value apply is not a member
of net.liftweb.util.Maker[Boolean]
[INFO] LiftRules.stripComments.request(S.request.map(!_.isIE)
openOr false)
[INFO] ^
[ERROR] one error found

Now I am puzzled because I actually do see a valid apply method for
Maker[Boolean] (see line 66 of Maker.scala).

So, what am I missing? I think I really want:

LiftRules.stripComments.session(S.request.map(!_.isIE) openOr
false)

I feel close, but no compile...

aw

unread,
Mar 11, 2010, 3:08:18 AM3/11/10
to Lift
I finally got something logical to compile:

LiftRules.stripComments.request.set( false )

But then it results in a 500 at runtime:

java.lang.ClassCastException: java.lang.Boolean cannot be cast to
scala.List
at
net.liftweb.http.provider.servlet.HTTPResponseServlet.addHeaders(HTTPResponseServlet.scala:
44)
at net.liftweb.http.LiftServlet.sendResponse(LiftServlet.scala:498)
at net.liftweb.http.LiftServlet.doService(LiftServlet.scala:187)
at net.liftweb.http.LiftServlet$$anonfun$doIt
$1$1.apply(LiftServlet.scala:75)
at net.liftweb.http.LiftServlet$$anonfun$doIt
$1$1.apply(LiftServlet.scala:75)
at net.liftweb.util.TimeHelpers$class.calcTime(TimeHelpers.scala:247)
at net.liftweb.util.Helpers$.calcTime(Helpers.scala:34)
at net.liftweb.util.TimeHelpers$class.logTime(TimeHelpers.scala:256)
at net.liftweb.util.Helpers$.logTime(Helpers.scala:34)
at net.liftweb.http.LiftServlet.doIt$1(LiftServlet.scala:74)
at net.liftweb.http.LiftServlet.service(LiftServlet.scala:82)
at net.liftweb.http.provider.HTTPProvider$$anonfun$service
$3.apply(HTTPProvider.scala:58)
at net.liftweb.http.provider.HTTPProvider$$anonfun$service
$3.apply(HTTPProvider.scala:58)
at net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:71)
at net.liftweb.http.URLRewriter$.doWith(Req.scala:549)

I don't understand how this stripComments is affecting headers.

I thought the end result would be something like:

LiftRules.stripComments.session.set( !S.ieMode )

But this results in a stack trace like:

Message: java.lang.ClassCastException: java.lang.Boolean cannot be
cast to net.liftweb.util.TimeHelpers$TimeSpan
net.liftweb.http.LiftMerge$class.merge(LiftMerge.scala:36)
net.liftweb.http.LiftSession.merge(LiftSession.scala:219)
net.liftweb.http.LiftSession$$anonfun$processTemplate
$1$2.apply(LiftSession.scala:483)
net.liftweb.http.LiftSession$$anonfun$processTemplate
$1$2.apply(LiftSession.scala:473)
net.liftweb.common.Full.map(Box.scala:334)
net.liftweb.http.LiftSession.processTemplate$1(LiftSession.scala:473)
net.liftweb.http.LiftSession$$anonfun$10$$anonfun$apply$34$$anonfun
$apply$37.apply(LiftSession.scala:527)
net.liftweb.http.LiftSession$$anonfun$10$$anonfun$apply$34$$anonfun
$apply$37.apply(LiftSession.scala:527)
net.liftweb.common.EmptyBox.or(Box.scala:378)
net.liftweb.http.LiftSession$$anonfun$10$$anonfun$apply
$34.apply(LiftSession.scala:526)
net.liftweb.http.LiftSession$$anonfun$10$$anonfun$apply
$34.apply(LiftSession.scala:526)
net.liftweb.util.StackableMaker$class.doWith(Maker.scala:104)
net.liftweb.http.Factory$FactoryMaker.doWith(Factory.scala:37)
net.liftweb.util.StackableMaker$class.doWith(Maker.scala:98)
net.liftweb.http.Factory$FactoryMaker.doWith(Factory.scala:37)
net.liftweb.http.LiftSession$$anonfun$10.apply(LiftSession.scala:525)
net.liftweb.http.LiftSession$$anonfun$10.apply(LiftSession.scala:520)
net.liftweb.common.EmptyBox.or(Box.scala:378)
net.liftweb.http.LiftSession.processRequest(LiftSession.scala:520)
net.liftweb.http.LiftServlet.net$liftweb$http$LiftServlet$
$dispatchStatefulRequest(LiftServlet.scala:265)
net.liftweb.http.LiftServlet$$anonfun$3.apply(LiftServlet.scala:177)
net.liftweb.http.LiftServlet$$anonfun$3.apply(LiftServlet.scala:177)
net.liftweb.http.S$.net$liftweb$http$S$$wrapQuery(S.scala:971)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$_nest2InnerInit$1$
$anonfun$apply$25.apply(S.scala:1111)
net.liftweb.http.S$.net$liftweb$http$S$$doAround(S.scala:908)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$_nest2InnerInit
$1.apply(S.scala:1109)
net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:71)
net.liftweb.http.S$.net$liftweb$http$S$$_nest2InnerInit(S.scala:1108)
net.liftweb.http.S$$anonfun$net$liftweb$http$S$$_innerInit$1$$anonfun
$apply$28$$anonfun$apply$29$$anonfun$apply$30$$anonfun$apply
$31.apply(S.scala:1134)
net.liftweb.util.ThreadGlobal.doWith(ThreadGlobal.scala:71)
net.liftweb.http.S$.withReq(S.scala:1143)

So, I remain puzzled...

Timothy Perrett

unread,
Mar 11, 2010, 4:15:04 AM3/11/10
to lif...@googlegroups.com
It must be:

LiftRules.stripComments.request.set(() => false)

Cheers, Tiim

David Pollak

unread,
Mar 11, 2010, 3:27:52 PM3/11/10
to lif...@googlegroups.com
On Thu, Mar 11, 2010 at 1:15 AM, Timothy Perrett <tim...@getintheloop.eu> wrote:
It must be:

LiftRules.stripComments.request.set(() => false)

He's got the correct syntax.

There's a deeper bug in the Factory/FactoryMaker code.  See https://liftweb.assembla.com/spaces/liftweb/tickets/418-factory-factorymaker-does-not-properly-assign-request-session-var-names
 

Jonathan Hoffman

unread,
Mar 11, 2010, 3:58:28 PM3/11/10
to lif...@googlegroups.com
I also discovered this feature unexpectedly in production and had a hard time tracking down the cause because of the config difference with Dev.

I am not sure if this feature has a strong use case given that lift already provides a <lift:ignore> tag that could be used to achieve the same effect more explicitly.

Besides the IE conditional case, which may be possible to address, there likely will be other creative uses of the comments which will surprise and confuse people.

- Jon

On Mar 4, 2010, at 1:38 AM, aw wrote:

David Pollak

unread,
Mar 11, 2010, 5:09:37 PM3/11/10
to Lift
Reply all
Reply to author
Forward
0 new messages