Project - Channel Page

Abstract

What have I done in this project?

  • Developed and maintained 60+ channel pages of JD.COM.
  • Optimized the loading time of page to less than 1.5 seconds.
  • Reduced 50% of the development time for each page.
  • Updated the technology stack from jQuery (2015 - 2018) to React + ES6 (2018 - 2019).

Introduction

I have developed and maintained over 60 channel pages of JD.COM in 4 years. The channel pages show the products and activities for each category and guide users to purchase products. Their entries are mostly located on the first screen of the home page. A channel page usually contains several sections:

  • the common header and footer of the page
  • the first screen which has a category and a slide for different activities’ images
  • some lists for hot sale products
  • some coupons for the category
  • some floors for subcategories which use different styles (tabs, slides, etc.) to show the information
  • the list for recommended products

Even though the channel pages have a familiar structure, each page has its individual UI and feature, it was designed in different styles. There are 3 examples:

image

hk.jd.com | art.jd.com | fashion.jd.com

Development Process

Old time

When I began to develop the channel page as a rookie, there was already an old development process. As a frontend developer, I just need to write a static page with HTML and CSS (Sass) and some basic interaction with JavaScript (jQuery) based on the UIs and UXs, then I would give the page to the backend developers who put the real data on the page, and then they deployed the final page online. It seemed like the frontend developer only developed part of the page, but we had to keep communicating with the backend developers the whole development stage and answered their questions about the page. It was inefficient.
image

New CMS

So we started to change the development process. The backend developers build a new Content Management System (CMS) which used by the frontend developers and operators. When we finished the static page, we should split the whole page to several floors and add them into the system. If we want to access the data recorded by the operators, we also had to change the HTML to some smarty type sentences. Then the system builds the whole real page and deploy it. We can see that the backend developers are free, but frontend developers have much more things to do. Even though we can save the floor as template, it still increased our workload, and the total development time was not reduced (about 10 days).
image

Reduce the process time

Then I have to think about save our time. As a frontend developer, I am familiar with the JavaScript template, not the smarty. So we don’t need to write the smarty template, we can write a JS template and put the data in JSON, then we can render the whole floor. In this way, we can write the template directly, it really reduce the development time (3 - 5 days).
image
Some example code:
template

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
(function(window){
window.channelData = window.channelData || {};
window.channelData['floor-x'] = {
background: [Json Data],
title: [Json Data],
pic:[Json Data],
portal_floor_id:'x'
};
})(window);
</script>
<div class="channel-floor" data-path="x" >
<script type="text/trimpath">
<div class="w">
<p>Floor Content need data.</p>
</div>
</script>
</div>

render

1
2
3
4
5
const floor = $('.channel-floor');
const id = floor.data('path');
const data = window.channelData["floor-" + id];
const template = floor.find('[type="text/trimpath"]').html();
floor.html(template.process(data));

Optimization

There are several points to optimize.

Optimize structure

Since we print all the data to the HTML, the structure looks a little unclear and the page code is too long. So we use a new system to get the data by APIs and we put the template code into the JS file of each floor. Then the whole page is small and clear, it is better for SEO.
The floor structure is like that:

1
2
3
4
5
6
7
// Floor HTML
<script type="text/javascript">(function (window) {
window.channelData = window.channelData || {};
window.channelData['floor-name'] = { dataID: 'xxx' };
}(window));</script>
<div class="floor" data-channel="channel-name" data-version="1.0.0" data-tpl="name" data-path="name">
</div>
1
2
3
4
5
6
// Floor template.js
define(function(require, exports, module) {
exports.tpl = function() {
return 'Floor Template';
}
});
1
2
3
4
5
6
// Floor interaction.js
define(function(require, exports, module) {
exports.init = function(floor) {
// Some interaction code
};
});

Lazyload

After we divide the floor code, we build a main.js to load each floor asynchronously. When the screen scroll to the floor, we use the data-attribute of the floor to get the path of the template and data and then render it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// main.js
floorEl.lazyload({
onChange: function(obj) {
seajs.use([widgetPath, widgetTplPath], function(floor, floorTpl) {
// get data with ajax
$.ajax({
url: 'xxx',
dataType: "jsonp",
success: function(floorData) {
// render template
obj.html(floorTpl.tpl().process(floorData))
// init floor interaction
floor.init(obj, template);
}
})
});
}
})

In this way, we can reduce 10+ js requests and 100+ image requests when the user open the page.

Optimize image

There are hundreds of images on the channel page, so if we can reduce the size of image, the page will load faster. Except image lazyload, we use the webp image if the browser supports it. Then each image can be reduced by 25% - 75%.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// check webp support
const supportsWebp = ({ createImageBitmap, Image }) => {
if (!createImageBitmap || !Image) {
return Promise.resolve(false);
}
return new Promise(resolve => {
const image = new Image();
image.onload = () => {
createImageBitmap(image)
.then(() => {
resolve(true);
})
.catch(() => {
resolve(false);
});
};
image.onerror = () => {
resolve(false);
};
image.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=';
});
};

What’s more, we deliver the image requests to different image server equally, so that we can get more images at one time.

After that, the loading time of page is under 1.5 seconds.