This article will focus on my six months in the mobile front end of the project to do some of the work done, mainly from the localstorage cache and version number management , modular , static resource rendering method Three aspects of the mobile phone Baidu in the front end of a year in the settlement of the solution, hope that the mobile development of all help.
Problems that existed a year ago
Perhaps because of the previous project rhythm tight, manpower shortage reason, part of Phper undertook the front-end work, so burst out some problems.
Rough fits.
From the first time in the factory to write code, the predecessor told the mobile page, so the static resources are embedded, that is written in script
and style
inside, the advantage is that the network situation is not good, reduce the HTTP request. Because 2G and other network instability, open an HTTP request, the consumption of mobile phone resources is huge, such as we in the cell phone signal is not good, access to the network, power consumption will increase sharply.
But with the popularity of 3G, even 4G, the actual statistics show that the mobile phone Baidu 2G users less than 30%, so the above mentioned 一刀切
scheme is inappropriate.
No rules.
The second problem is that there is no normative or modular problem. Everybody writes the code is the stream of consciousness , except all is uses zepto.js
, did not precipitate under the module. When you hit the code that you wrote before, it's all ctrl+c
+ ctrl+v
. This extensive way, although can temporarily solve the problem, but when the previous piece of code can not meet the needs of the time (such as the new version of the app release, the previous code needs to do compatibility and upgrade), need to traverse all the code, change, Trouble!
Highly-coupled work flow
The third problem is the front-end role problem, now the development of the group is separated from the front and back, using the Smarty template, because the product is Hybridapp, so more than the traditional front end, increase the client rd cost. The front end is almost all in the State of the Union and wait, followed by the back-end Smarty Data interface and client-side connection JS interface. Sometimes you have to wait for the interface to come out of the joint after the passage, to continue to write code, resulting in a waste of manpower. How to liberate the front-end manpower and solve the problem of the coupling of development is imminent.
Introducing FIS Solutions
FIS is a factory with a set of front-end integration solutions, from development, commissioning to packaging on-line all aspects are covered. With Jackie Chan eldest brother's words is: "Hold a try the mentality, and later found very dark very bright very soft ..." It is recommended for other teams, regardless of their use. ”
Fex There are many articles in the said FIS, I have also written a "FIS and fisp of the use of experience", so here is not redundant, directly focus on my FIS based on some of the solutions.
Solve the cost of joint adjustment
The first part of the highly coupled workflow, using the FIS Local union and Chrome extension to cut off the Phper, CRD and FE link line, to advance self-test, running ahead of the entire process.
FIS Local debugging
The local debugging functions of FIS can be used to solve phper and feer problems, such as simulating smarty template data, simulating Ajax interface and other functions. We will rewrite the rules and the analog data of the joint, respectively, server.conf
and write the test文件夹
About FIS Local joint work, not much to say, FIS official website document has detailed description
Chrome Extended Analog WebView interface
In order to solve the client injection JS interface method, we are implemented through the Chrome extension. Through Chrome's content script, before the page rendering before the simulation WebView JS, so that the page in the download rendering when the call JS interface will not error.
In addition to simulating the WebView interface, it also integrates the tools and debugging functions commonly used in the development of the mobile phone's Baidu app into this Chrome extension. The overall effect is as follows:
The development of the Chrome extension, met a lot of difficulties, finally through the data one by one solved, the entire tool development took a weekend time, followed by fragmented needs. The ability to automatically detect updates is also introduced because of the frequent updates.
Embedded static resources do Localstorage cache
Because of the reasons mentioned above, the static resources used in the page are embedded in the page, the way we call inline mode .
Inline mode each time the full amount of code is issued by the way the egg hurts, affecting the page speed. It is not difficult to think of later people have used the localstorage to cache the inline code, this rendering can be called: localstorage+inline
the way.
Mobile phone WebView to HTML5 localstorage do a good support, after our sampling statistics, mobile phone Baidu search results page users, about 76% support Localstorage. Well, do localstorage cache.
Localstorage Cache Solution
Now there are a lot of localstorage solution, is issued a version number of the config file each time, after the page loaded, take this config file with the cached Localstorage file check version number, found that there are updates, then two times pull new content, Then cache the new content and the new version number to Localstorage.
On the move, we want to avoid this two pull, so we use a cookie to store the version number information, such a visit, the HTTP request header will take the cookie to the backend, the backend directly determine the version number, and issued code.
The specific options are as follows:
- Use cookies to record Localstorage version number information
- On-line, through the packaging tool, all the files that need to be cached are computed in turn MD5 the sum of the values of string, and then the string takes MD5 as the version number
- When the user visits the page, the cookie is brought to the backend program to determine whether the two version numbers are equal, and if not equal, the full amount of code is issued.
- The front-end is responsible for judging localstorage support, write a specific cookie value, support write Localstorage version number
- Cookie expiration Time is one week
Of course, this solution is relatively simple, I believe that many mobile front-end teams are also in use, some people will say: "We all use the outside chain." "Before we say, our product network is more complex, only for 2G users to make a compromise
The problem with the solution above
After the line, because the page embedded JS and CSS are cached to localstorage, the page size is smaller, indeed the user access speed has been greatly improved. Well, it looks good ~
However, this is a one -size-fits-all solution:
- The business layer code is the same as the base Layer code level: the base layer code, like Zepto, which is updated once a year, is re-issued because of frequent changes in business logic code
- For a domain name only one page of the page is a good way, more pages, the public code is less
- For a version number, you cannot control all the page cache code, and the result is a constant trade-off of what is cached
Now maybe some children's shoes think, why not save a few version number of cookies, so that can not be more cache some code?
More cookies, HTTP request headers will become larger, HTTP request header is too large, will have a great impact on speed, when the total amount of cookies more than 800 bytes, the speed will be steep rise, plus we use the domain name many brothers team are in use, if let go of the development of the opening, the final will be out of hand.
PS: Participating in a speed optimization project years ago, one of the optimization methods is to reduce cookies, reduce the cookie in the request header, the speed of the slow network increased significantly!
OK, continue to explore ...
Localstorage Fine-grained caching
The Localstorage version number solution above is to put the MD5 value in a cookie, a MD5 value of 32 bits, even if using half also 16 bits, plus a cookie key, how also to 20 bytes above, we can use 20~100 bytes, Try to cache more cache file version number information?
So we started the work of Localstorage version number refinement.
- Comb the static resources that can be cached, divide the files into: the base layer, the general layer and the business logic layer, the main cache is the base layer and the general layer of code
- To specify the value format of the cookie, in order to cache more version number information, we no longer use MD5 to do version number information, but instead specify the following format: Ja-v_cb-v, that is, JA and CB represent the cached file name, keep two bits (J represents js,c for CSS, T represents the front-end JS template file, V for the version number, keep one, the version number is 36, when the version number to more than one, starting from 0 to re-record; According to the weekly online, the cookie time is one week, 36 version number can be used for our
- Manage files that need to be cached uniformly on one path
After doing so, it is to use the script cache file automatically update the version number, began to think of the way through the SVN hook, when there is a new CI, calculate the MD5 value, write a version number config file. On line, compare the config in the config and SVN, if not the same, the version number. But each time CI is done in a way and superfluous, slightly show the egg pain, the final plan is to do some work in the online script, not using SVN hook:
- Make a MD5 to the file under the cache file path and generate a map
- Go to the line to pull up the latest Version number config file, compared to the map generated by the first step, the version is raised
Localstorage Multi-dimensional cache
The solution above is not perfect enough to always feel that there is still less, so a multi-dimensional cookie version of the scheme.
We consider cookies to be stored in two dimensions: domain names and paths .
Example
Domain name a.baidu.com, there are three products: news, videos and novels, placed in three path:
- A.baidu.com/news
- A.baidu.com/video
- A.baidu.com/novel
Then news, videos and novels, each with their own common code, such as: Universal style, universal JS components. This allows us to specify the appropriate path when setting the cookie, then we can implement the multi-dimensional cache
Turn on the localstorage cache
In order to implement localstorage caching, we added FISLocalstorage
classes to handle cookies, issued cache code, modified the tags of the FIS extended smarty <%html%>
, added localstorage
attributes, that is, the following code can open the page cache:
<%html localstorage="true"%>//something~<%/html%>
Modular
In order to solve the problem of duplicate code, we began to combine FIS to do modularity, such as Seajs, Requirejs these cmd, AMD framework, is the post-loading, that is, what to pull what, belong to the asynchronous module. JS in order to implement the asynchronous module, and a lot of code in the processing module dependency relationship. On the move, we do not want this, we want to maintain the dependency of the module in the backend, when I require a module, I will follow the dependency, and then output.
I wrote a bdbox AMD specification's modular base library, then wrapped AMD's outer layer at FIS compile time, define
and could generate a load resource table when using <%widget%>
, <%require%>
and <%script%>标签内使用require
these smarty extended tags, Will dynamically maintain module dependencies through PHP.
About FIS Modular and static resource management, the factory FIS development Team students have an article on how to effectively manage the static resources of the site
Examples of modularity
Now the page to introduce moduleA
modules, and moduleA
rely on moduleB
and moduleC
, moduleB
and moduleC
have their own dependent modules, if not first output moduleB
and moduleC
the dependent module, directly execute moduleA
the define
function will be error, because moduleA
the state that the module depends on moduleB
and has moduleC
not yet reached ready
.
Sometimes even more complex dependencies:
At this time through the "How to efficiently manage the static resources of the site," said the FIS compiled after the module dependency table: map.json
, to do dynamic module dependency management.
By modifying the FIS compilation script to put the module dependency file content map.json
in, when using the smarty extension syntax tag, PHP will automatically read map.json
, and then the dependency parsing out, ahead of the Modulea-dependent modules were code>define
introduced before it, So the following two code notation:
"' Smarty
<%require name= "Common:bdbox/modulea"%> '
<% or%>
<%script%>
var Modulea = require (' Common:bdbox/modulea '); <%/script%>
```
The actual output of the HTML code is:
<script>Define(' Common:bdbox/moduleb ', function(){ A dependent module B });Define(' Common:bdbox/modulec ', function(){ A dependent module C });Define(' Common:bdbox/modulea ', function () { //module a< Span class= "PLN" > var C = Require ( ' Common:bdbox/modulec ' var B = Require ( ' Common:bdbox/modulea ' ); }); var Modulea = require< Span class= "pun" > ( ' Common:bdbox/modulea ' </SCRIPT>
For JS or CSS files that are not modules, if they are used <%require%>
, they are actively used file_get_contents
to read the content.
Q & A
- Why not just use Seajs and Requirejs?
- Too big, logically complex, not suitable for mobile pages
- Why not use the FIS own modjs, but the self-made wheel?
- Bdbox is not just an AMD library, it's an underlying library that maintains namespaces and tool classes
- Why is the name not a standard AMD specification?
- Named
common:bdbox/moduleA
, Common is a namespace, a project will be composed of many page modules (this module is the product template module, not the front-end module), through the namespace can quickly locate the corresponding Map.json, but the bdbox/moduleA
actual AMD module name
Static Resource Introduction mode
All of the above solutions for static resource management are optimized around a one -size-fits-all solution, without using the HTTP cache itself, in fact: in 3G, WiFi, or even 4G environments, the HTTP cache scheme is more user-friendliness and compatibility than localstorage+inline
the way to embed static resources is better.
And from the mobile phone Baidu Real user network type statistics, 3g+wifi has reached more than 75%, if you can combine with the wise team to provide IP speed library and the company's Cdn service, there will be a better solution, further, if you can according to the network type and user real network speed, free choice in localstorage+inline
It's better to switch between the CDN scheme. So we did it! A new way of rendering appears: CDN+combo
.
Again, before this rendering, comb the above mentioned nouns:
- Inline Mode : That is, all static resources are embedded into the page, the oldest one-size-fits-all solution
- Tag Mode : That is, the use of script and link tags, the introduction of the external chain JS and css,pc above commonly used, 2G full speed is not suitable
- localstorage+inline mode :
一刀切
an optimized version of the inline public static resources using HTML5 's Localstorage cache for local storage
- Cdn+combo mode : The use of tag mode, the external chain of resources, combined with CDN and HTTP cache cache, combo provide modular code of packaging and consolidation services
OK, go on. The modular Modulea module relies on Moduleb and Modulec, which, after the tag mode , will output the following HTML:
<script Src= "http://xxx/bdbox/moduleC.js" ></script> <script src= "http://xxx/bdbox/moduleB.js" ></script><script src= "http ://xxx/bdbox/modulea.js "></script><script > var Modulea = ' Common:bdbox/modulea ' </SCRIPT>
Such modular code is often the bottleneck of the Web page, because the modularity exists, resulting in more outside the chain! Below we need a Cdn+combo service to merge HTTP requests.
Because of the extended syntax of Smarty, which was generated before map.json
, we implemented a modular dependency back-end automatic processing dependency, and then chose the most reasonable output order. At this time we do not directly output the corresponding tag or inline content, but merge it into a combo service corresponding URL, unified output!
<script src="cdn-combo-server?file=bdbox/moduleC,bdbox/moduleB,bdbox/moduleA"></script>
Rendering Mode Intelligent Switching
How to change the rendering mode intelligently according to the user's network environment? I continue to transform the Smarty <%html%>
tags, add attributes rendermode
, through wise Speed library and mobile phone Baidu client to our network type, choose different Rendermode way:
<%If ($slow _network||$nettype==' 2G ') && $support _localstorage%> <% html rendermode= "inline" localstorage< Span class= "pun" >= "true" %><%<%html rendermode= "combo" %><%else %> <%html rendermode= "inline" %><%/if %>//... <%/HTML%>
Split Parent-Child templates
Above the scheme, if we go to the page to write code, change the scheme, think about the egg pain, so we split the parent-child template, from the framework itself, a module corresponding to a parent template, the other sub-template using Smarty extends tag to implement the inheritance relationship.
After the template is split, the child template is focused on doing business, the parent template focuses on the solution, but also facilitates sampling and statistics.
Other
- Specification, has collated the detailed coding specification and JS common coding problem;
- Introduce JSLint and Csshint to control the quality of the code
- Front-end documentation, add annotations to the JSDoc specification in JS code, and automatically generate front-end documents via JSDoc
Summarize
- FIS brings us a complete set of front-end inheritance solutions, which are the backbone of all solutions above
- The development process, through the tool to decouple, reduce the time of the joint adjustment, improve the front-end efficiency
- Parent-Child template splitting for a solution
- Reject a one-size-fits-all solution and do scalable solutions
- Finally, we put all of the above solutions in a separate front-end common module
Imagine, if 2015, users are using 4G, then we need to change the parent template Rendermode to rendermode="combo"
be able to cut all CDN+combo
the way to the rendering, which will reduce the amount of work AH:)
Mobile Baidu front-end engineering of the road