Skip to content
This repository was archived by the owner on Apr 10, 2025. It is now read-only.

Commit f01252e

Browse files
jmarantzcrowell
authored andcommitted
Move lazyloader script load to end of head (or just before the first non-html
tag) rather than before the first image on the page. Also inserts the script pretty-much unconditionally (if we see the jquery slider script in head we don't bother, but merely having no images doesn't prevent script insertion).
1 parent d6d597e commit f01252e

File tree

3 files changed

+112
-49
lines changed

3 files changed

+112
-49
lines changed

net/instaweb/rewriter/lazyload_images_filter.cc

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "net/instaweb/rewriter/public/lazyload_images_filter.h"
2020

21+
#include "base/logging.h"
2122
#include "net/instaweb/htmlparse/public/html_element.h"
2223
#include "net/instaweb/htmlparse/public/html_name.h"
2324
#include "net/instaweb/htmlparse/public/html_node.h"
@@ -82,6 +83,8 @@ void LazyloadImagesFilter::StartDocumentImpl() {
8283
}
8384

8485
void LazyloadImagesFilter::EndDocument() {
86+
// TODO(jmaessen): Fix filter to insert this script
87+
// conditionally.
8588
driver()->UpdatePropertyValueInDomCohort(
8689
driver()->fallback_property_page(),
8790
kIsLazyloadScriptInsertedPropertyName,
@@ -90,6 +93,7 @@ void LazyloadImagesFilter::EndDocument() {
9093

9194
void LazyloadImagesFilter::Clear() {
9295
skip_rewrite_ = NULL;
96+
head_element_ = NULL;
9397
main_script_inserted_ = false;
9498
abort_rewrite_ = false;
9599
abort_script_inserted_ = false;
@@ -125,6 +129,22 @@ void LazyloadImagesFilter::StartElementImpl(HtmlElement* element) {
125129
if (noscript_element() != NULL) {
126130
return;
127131
}
132+
if (!main_script_inserted_ && head_element_ == NULL) {
133+
switch (element->keyword()) {
134+
case HtmlName::kHtml:
135+
case HtmlName::kLink:
136+
case HtmlName::kMeta:
137+
case HtmlName::kScript:
138+
case HtmlName::kStyle:
139+
break;
140+
case HtmlName::kHead:
141+
head_element_ = element;
142+
break;
143+
default:
144+
InsertLazyloadJsCode(element);
145+
break;
146+
}
147+
}
128148
if (skip_rewrite_ == NULL) {
129149
if (element->keyword() == HtmlName::kNoembed ||
130150
element->keyword() == HtmlName::kMarquee) {
@@ -171,8 +191,13 @@ void LazyloadImagesFilter::EndElementImpl(HtmlElement* element) {
171191
}
172192
return;
173193
}
194+
if (head_element_ == element) {
195+
InsertLazyloadJsCode(NULL);
196+
head_element_ = NULL;
197+
}
174198
if (abort_rewrite_) {
175-
if (!abort_script_inserted_ && main_script_inserted_) {
199+
if (!abort_script_inserted_ && main_script_inserted_ &&
200+
num_images_lazily_loaded_ > 0) {
176201
// If we have already rewritten some elements on the page, insert a
177202
// script to load all previously rewritten images.
178203
HtmlElement* script = driver()->NewElement(element, HtmlName::kScript);
@@ -281,9 +306,22 @@ void LazyloadImagesFilter::EndElementImpl(HtmlElement* element) {
281306
}
282307

283308
void LazyloadImagesFilter::InsertLazyloadJsCode(HtmlElement* element) {
284-
if (!driver()->is_lazyload_script_flushed()) {
309+
if (!driver()->is_lazyload_script_flushed() &&
310+
(!abort_rewrite_ || num_images_lazily_loaded_ > 0)) {
285311
HtmlElement* script = driver()->NewElement(element, HtmlName::kScript);
286-
driver()->InsertNodeBeforeNode(element, script);
312+
if (element != NULL) {
313+
driver()->InsertNodeBeforeNode(element, script);
314+
} else if (driver()->CanAppendChild(head_element_)) {
315+
// insert at end of head.
316+
driver()->AppendChild(head_element_, script);
317+
} else {
318+
// Could not insert at end of head even though we just saw the end of head
319+
// event! Should not happen, but this will ensure that we insert the
320+
// script before the next tag we see.
321+
LOG(DFATAL) << "Can't append child to <head> at the </head> event!";
322+
main_script_inserted_ = false;
323+
return;
324+
}
287325
StaticAssetManager* static_asset_manager =
288326
driver()->server_context()->static_asset_manager();
289327
GoogleString lazyload_js = GetLazyloadJsSnippet(

net/instaweb/rewriter/lazyload_images_filter_test.cc

Lines changed: 66 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ class LazyloadImagesFilterTest : public RewriteTestBase {
9090
TEST_F(LazyloadImagesFilterTest, SingleHead) {
9191
InitLazyloadImagesFilter(false);
9292

93-
ValidateExpected("lazyload_images",
93+
ValidateExpected(
94+
"lazyload_images",
9495
"<head></head>"
9596
"<body>"
9697
"<img />"
@@ -114,7 +115,9 @@ TEST_F(LazyloadImagesFilterTest, SingleHead) {
114115
"<img src=\"1.jpg\" onload=\"blah();\" />"
115116
"<img src=\"1.jpg\" class=\"123 dfcg-metabox\" />"
116117
"</body>",
117-
StrCat("<head></head><body><img/>"
118+
StrCat("<head>",
119+
GetLazyloadScriptHtml(),
120+
"</head><body><img/>"
118121
"<img src=\"\"/>"
119122
"<noscript>"
120123
"<img src=\"noscript.jpg\"/>"
@@ -125,7 +128,6 @@ TEST_F(LazyloadImagesFilterTest, SingleHead) {
125128
"<marquee>"
126129
"<img src=\"marquee.jpg\"/>"
127130
"</marquee>",
128-
GetLazyloadScriptHtml(),
129131
GenerateRewrittenImageTag("img", "1.jpg", ""),
130132
"<img src=\"1.jpg\" pagespeed_no_defer />"
131133
"<img src=\"1.jpg\" data-src=\"2.jpg\"/>",
@@ -167,16 +169,16 @@ TEST_F(LazyloadImagesFilterTest, Blacklist) {
167169
ValidateExpected(
168170
"lazyload_images",
169171
input_html,
170-
StrCat("<head></head><body>"
171-
"<img src=\"http://www.1.com/blacklist.jpg\"/>",
172+
StrCat("<head>",
172173
GetLazyloadScriptHtml(),
173-
StrCat(
174-
GenerateRewrittenImageTag(
175-
"img", "http://www.1.com/img1", ""),
176-
GenerateRewrittenImageTag(
177-
"img", "img2", ""),
178-
GetLazyloadPostscriptHtml(),
179-
"</body>")));
174+
"</head><body>"
175+
"<img src=\"http://www.1.com/blacklist.jpg\"/>",
176+
GenerateRewrittenImageTag(
177+
"img", "http://www.1.com/img1", ""),
178+
GenerateRewrittenImageTag(
179+
"img", "img2", ""),
180+
GetLazyloadPostscriptHtml(),
181+
"</body>"));
180182
EXPECT_EQ(3, logging_info()->rewriter_info().size());
181183
ExpectLogRecord(0, RewriterApplication::NOT_APPLIED, true, false);
182184
ExpectLogRecord(1, RewriterApplication::APPLIED_OK, false, false);
@@ -210,16 +212,16 @@ TEST_F(LazyloadImagesFilterTest, CriticalImages) {
210212
ValidateExpected(
211213
"lazyload_images",
212214
input_html,
213-
StrCat("<head></head><body>"
214-
"<img src=\"http://www.1.com/critical\"/>",
215+
StrCat("<head>",
215216
GetLazyloadScriptHtml(),
216-
StrCat(
217-
GenerateRewrittenImageTag(
218-
"img", "http://www.1.com/critical2", ""),
219-
"<img src=\"critical3\"/>"
220-
"<img src=\"", rewritten_url, "\"/>",
221-
GetLazyloadPostscriptHtml(),
222-
"</body>")));
217+
"</head><body>"
218+
"<img src=\"http://www.1.com/critical\"/>",
219+
GenerateRewrittenImageTag(
220+
"img", "http://www.1.com/critical2", ""),
221+
"<img src=\"critical3\"/>"
222+
"<img src=\"", rewritten_url, "\"/>",
223+
GetLazyloadPostscriptHtml(),
224+
"</body>"));
223225
EXPECT_EQ(4, logging_info()->rewriter_info().size());
224226
ExpectLogRecord(0, RewriterApplication::NOT_APPLIED, false, true);
225227
ExpectLogRecord(1, RewriterApplication::APPLIED_OK, false, false);
@@ -252,14 +254,16 @@ TEST_F(LazyloadImagesFilterTest, CriticalImages) {
252254
TEST_F(LazyloadImagesFilterTest, SingleHeadLoadOnOnload) {
253255
options()->set_lazyload_images_after_onload(true);
254256
InitLazyloadImagesFilter(false);
255-
ValidateExpected("lazyload_images",
257+
ValidateExpected(
258+
"lazyload_images",
256259
"<head></head>"
257260
"<body>"
258261
"<img src=\"1.jpg\" />"
259262
"</body>",
260-
StrCat("<head></head>"
261-
"<body>",
263+
StrCat("<head>",
262264
GetLazyloadScriptHtml(),
265+
"</head>"
266+
"<body>",
263267
GenerateRewrittenImageTag("img", "1.jpg", ""),
264268
GetLazyloadPostscriptHtml(),
265269
"</body>"));
@@ -271,31 +275,36 @@ TEST_F(LazyloadImagesFilterTest, SingleHeadLoadOnOnload) {
271275
// not an onload attribute added by PageSpeed.
272276
TEST_F(LazyloadImagesFilterTest, NoLazyloadImagesWithOnloadAttribute) {
273277
InitLazyloadImagesFilter(false);
274-
ValidateExpected("lazyload_images",
278+
ValidateExpected(
279+
"lazyload_images",
275280
"<head></head>"
276281
"<body>"
277282
"<img src=\"1.jpg\" onload=\"do_something();\"/>"
278283
"</body>",
279-
"<head></head>"
280-
"<body>"
281-
"<img src=\"1.jpg\" onload=\"do_something();\"/>"
282-
"</body>");
284+
StrCat("<head>",
285+
GetLazyloadScriptHtml(),
286+
"</head>"
287+
"<body>"
288+
"<img src=\"1.jpg\" onload=\"do_something();\"/>"
289+
"</body>"));
283290
}
284291

285292
// Verify that lazyload_images gets applied on image elements that have an
286293
// onload handler whose value is CriticalImagesBeaconFilter::kImageOnloadCode.
287294
TEST_F(LazyloadImagesFilterTest, LazyloadWithPagespeedAddedOnloadAttribute) {
288295
InitLazyloadImagesFilter(false);
289-
ValidateExpected("lazyload_images",
296+
ValidateExpected(
297+
"lazyload_images",
290298
StrCat("<head></head>"
291299
"<body>"
292300
"<img src=\"1.jpg\" onload=\"",
293301
CriticalImagesBeaconFilter::kImageOnloadCode,
294302
"\"/>"
295303
"</body>"),
296-
StrCat("<head></head>"
297-
"<body>",
304+
StrCat("<head>",
298305
GetLazyloadScriptHtml(),
306+
"</head>"
307+
"<body>",
299308
GenerateRewrittenImageTag("img", "1.jpg", ""),
300309
GetLazyloadPostscriptHtml(),
301310
"</body>"));
@@ -314,8 +323,8 @@ TEST_F(LazyloadImagesFilterTest, MultipleBodies) {
314323
"<script></script>"
315324
"</body>",
316325
StrCat(
317-
"<body>",
318326
GetLazyloadScriptHtml(),
327+
"<body>",
319328
GenerateRewrittenImageTag("img", "1.jpg", ""),
320329
GetLazyloadPostscriptHtml(),
321330
StrCat(
@@ -337,8 +346,8 @@ TEST_F(LazyloadImagesFilterTest, NoHeadTag) {
337346
"<body>"
338347
"<img src=\"1.jpg\" />"
339348
"</body>",
340-
StrCat("<body>",
341-
GetLazyloadScriptHtml(),
349+
StrCat(GetLazyloadScriptHtml(),
350+
"<body>",
342351
GenerateRewrittenImageTag("img", "1.jpg", ""),
343352
GetLazyloadPostscriptHtml(),
344353
"</body>"));
@@ -367,8 +376,8 @@ TEST_F(LazyloadImagesFilterTest, CustomImageUrl) {
367376
"<body>"
368377
"<img src=\"1.jpg\" />"
369378
"</body>",
370-
StrCat("<body>",
371-
GetLazyloadScriptHtml(),
379+
StrCat(GetLazyloadScriptHtml(),
380+
"<body>",
372381
GenerateRewrittenImageTag("img", "1.jpg", ""),
373382
GetLazyloadPostscriptHtml(),
374383
"</body>"));
@@ -382,7 +391,8 @@ TEST_F(LazyloadImagesFilterTest, DfcgClass) {
382391
"<img src=\"1.jpg\"/>"
383392
"</div>"
384393
"</body>";
385-
ValidateNoChanges("lazyload_images", input_html);
394+
ValidateExpected("DfcgClass",
395+
input_html, StrCat(GetLazyloadScriptHtml(), input_html));
386396
}
387397

388398
TEST_F(LazyloadImagesFilterTest, NivoClass) {
@@ -393,7 +403,8 @@ TEST_F(LazyloadImagesFilterTest, NivoClass) {
393403
"</div>"
394404
"<img class=\"nivo\" src=\"1.jpg\"/>"
395405
"</body>";
396-
ValidateNoChanges("lazyload_images", input_html);
406+
ValidateExpected("NivoClass",
407+
input_html, StrCat(GetLazyloadScriptHtml(), input_html));
397408
}
398409

399410
TEST_F(LazyloadImagesFilterTest, ClassContainsSlider) {
@@ -404,13 +415,16 @@ TEST_F(LazyloadImagesFilterTest, ClassContainsSlider) {
404415
"</div>"
405416
"<img class=\"my_sLiDer\" src=\"1.jpg\"/>"
406417
"</body>";
407-
ValidateNoChanges("lazyload_images", input_html);
418+
ValidateExpected("SliderClass",
419+
input_html, StrCat(GetLazyloadScriptHtml(), input_html));
408420
}
409421

410422
TEST_F(LazyloadImagesFilterTest, NoImages) {
411423
InitLazyloadImagesFilter(false);
412424
GoogleString input_html = "<head></head><body></body>";
413-
ValidateNoChanges("lazyload_images", input_html);
425+
ValidateExpected("NoImages", input_html,
426+
StrCat("<head>", GetLazyloadScriptHtml(),
427+
"</head><body></body>"));
414428
EXPECT_EQ(0, logging_info()->rewriter_info().size());
415429
}
416430

@@ -440,7 +454,8 @@ TEST_F(LazyloadImagesFilterTest, LazyloadDisabledWithJquerySlider) {
440454
"<img src=\"1.jpg\"/>"
441455
"</body>";
442456
// No change in the html.
443-
ValidateNoChanges("lazyload_images", input_html);
457+
ValidateExpected("JQuerySlider", input_html,
458+
StrCat(GetLazyloadScriptHtml(), input_html));
444459
}
445460

446461
TEST_F(LazyloadImagesFilterTest, LazyloadDisabledWithJquerySliderAfterHead) {
@@ -451,7 +466,15 @@ TEST_F(LazyloadImagesFilterTest, LazyloadDisabledWithJquerySliderAfterHead) {
451466
"<script src=\"jquery.sexyslider.js\"/>"
452467
"<img src=\"1.jpg\"/>"
453468
"</body>";
454-
ValidateNoChanges("abort_script_inserted", input_html);
469+
GoogleString expected_html = StrCat(
470+
"<head>",
471+
GetLazyloadScriptHtml(),
472+
"</head>"
473+
"<body>"
474+
"<script src=\"jquery.sexyslider.js\"/>"
475+
"<img src=\"1.jpg\"/>"
476+
"</body>");
477+
ValidateExpected("abort_script_inserted", input_html, expected_html);
455478
}
456479

457480
TEST_F(LazyloadImagesFilterTest, LazyloadDisabledForOldBlackberry) {

net/instaweb/rewriter/public/lazyload_images_filter.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@
1919
#ifndef NET_INSTAWEB_REWRITER_PUBLIC_LAZYLOAD_IMAGES_FILTER_H_
2020
#define NET_INSTAWEB_REWRITER_PUBLIC_LAZYLOAD_IMAGES_FILTER_H_
2121

22+
#include "net/instaweb/htmlparse/public/html_element.h"
2223
#include "net/instaweb/rewriter/public/common_filter.h"
24+
#include "net/instaweb/rewriter/public/rewrite_driver.h"
25+
#include "net/instaweb/rewriter/public/rewrite_options.h"
2326
#include "net/instaweb/util/enums.pb.h"
2427
#include "net/instaweb/util/public/string.h"
2528

2629
namespace net_instaweb {
2730

28-
class HtmlElement;
29-
class RewriteDriver;
30-
class RewriteOptions;
3131
class StaticAssetManager;
3232
class Statistics;
3333

@@ -121,6 +121,8 @@ class LazyloadImagesFilter : public CommonFilter {
121121
// If non-NULL, we skip rewriting till we reach
122122
// LazyloadImagesFilter::EndElement(skip_rewrite_).
123123
HtmlElement* skip_rewrite_;
124+
// Head element - preferred insertion point for scripts.
125+
HtmlElement* head_element_;
124126
// Indicates if the main javascript has been inserted into the page.
125127
bool main_script_inserted_;
126128
// Indicates whether we should abort rewriting the page.

0 commit comments

Comments
 (0)