38
Modularize JavaScript with RequireJS Minh Hoang TO August 8, 2013

Modularize JavaScript with RequireJS

Embed Size (px)

Citation preview

Page 1: Modularize JavaScript with RequireJS

Modularize JavaScript with RequireJS

Minh Hoang TO

August 8, 2013

Page 2: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Agenda

1 Performance Problem

2 Problem Analysis

3 JavaScript Code Organizing

4 RequireJS Library

5 RequireJS Integration

Minh Hoang TO Modularize JavaScript with RequireJS

Page 3: Modularize JavaScript with RequireJS
Page 4: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Bad User ExperienceNumerical Reports

Slow Login Page

Open login form of Dagens Nyheter (http://dn.se) or browse for the firsttime to

https://auth.dn.se/login?appId=dagensnyheter.se

Minh Hoang TO Modularize JavaScript with RequireJS

Page 5: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Bad User ExperienceNumerical Reports

Low PageSpeed Scores

Figure 1: PageSpeed scores of https://auth.dn.se/login?appId=dagensnyheter.se

Minh Hoang TO Modularize JavaScript with RequireJS

Page 6: Modularize JavaScript with RequireJS
Page 7: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Firebug TimelineFundamental CausesInitiative Idea

Firebug Timeline

Figure 2: Loading timeline on all resources

Figure 3: Loading timeline on JavaScript resources

DOMContentLoaded time: 7.6s

Load main.js time: 5s

Minh Hoang TO Modularize JavaScript with RequireJS

Page 8: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Firebug TimelineFundamental CausesInitiative Idea

Blocking JavaScript

Browser loads the entire main.js file (314.4KB) before rendering DOM content

Figure 4: Blocking main.js

Minh Hoang TO Modularize JavaScript with RequireJS

Page 9: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Firebug TimelineFundamental CausesInitiative Idea

Too Sequential Loading

main.js = jquery + jquery-ui + some jquery plugins + business code of DN

→ Should find one way to load library parts in parallel

Minh Hoang TO Modularize JavaScript with RequireJS

Page 10: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Firebug TimelineFundamental CausesInitiative Idea

Initiative Idea

Organize JavaScript code into modules with loose dependencies so that theyare eligible to deferred, lazy and parallel loading

Minh Hoang TO Modularize JavaScript with RequireJS

Page 11: Modularize JavaScript with RequireJS
Page 12: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Common JavaScript StyleInnovative JavaScript Style

Math Functions

Minh Hoang TO Modularize JavaScript with RequireJS

Page 13: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Common JavaScript StyleInnovative JavaScript Style

Math Functions - Drawbacks

Blocking and sequential load of JavaScript resources:

Browser loads square.js and fourthPower.js too early

Evaluation of fourthPower.js requires function declared in square.js,sequential load is inevitable

→ See if new JavaScript code styles help?

Minh Hoang TO Modularize JavaScript with RequireJS

Page 14: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Common JavaScript StyleInnovative JavaScript Style

Asynchronous Module Definition

Provide resource containing factory method of R, denote this resource as F (R),instead of providing directly resource R

F (R) holds:

Name of module R

Names of dependency modules of R

Factory method that generates R

Minh Hoang TO Modularize JavaScript with RequireJS

Page 15: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Common JavaScript StyleInnovative JavaScript Style

Math Functions - AMD Modules

Figure 5: squareAMD module defined in squareAMD.js

Figure 6: fourthPowerAMD module defined in fourthPowerAMD.js

Minh Hoang TO Modularize JavaScript with RequireJS

Page 16: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Common JavaScript StyleInnovative JavaScript Style

AMD - Valuable Features

Browser evaluation of F (R) does not trigger evaluation of R, thatheavy-weight work could be deferred

F (R1),F (R2), . . . ,F (Rk ) have no inter-dependencies at evaluation timeeven if R1,R2, . . . ,Rk do → ideal for parallel loading

Minh Hoang TO Modularize JavaScript with RequireJS

Page 17: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Common JavaScript StyleInnovative JavaScript Style

Math Functions - Use of AMD Modules

Figure 7: Use AMD modules in AMD style

Execution of require block triggers:

Resolution1 of squareAMD and fourthPowerAMD modules

Execution of callback method on completing module resolutionsquareAMD and fourthPowerAMD are wired to sq and fp, respectively.

1Full explanation on resolution is given in RequireJS slides

Minh Hoang TO Modularize JavaScript with RequireJS

Page 18: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Common JavaScript StyleInnovative JavaScript Style

Inversion of Control

Inversion of Control pattern applied to JavaScript

Use of AMD requires JavaScript loader library2 which:

Manages lazy (on demand) and parallel loading of factory resourcesF (R1),F (R2), . . . ,F (Rk )

Invoke factory methods with proper execution order

Provides naming service for modules

2RequireJS is such a library

Minh Hoang TO Modularize JavaScript with RequireJS

Page 19: Modularize JavaScript with RequireJS
Page 20: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

General InformationHow To Use RequireJS

General Information

http://requirejs.org

JavaScript file and module loader library

Supports Asynchronous Module Definition

Minified size: 14.7KB

Minh Hoang TO Modularize JavaScript with RequireJS

Page 21: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

General InformationHow To Use RequireJS

Math Functions

Figure 8: Math Functions example illustrates use of RequireJS

Minh Hoang TO Modularize JavaScript with RequireJS

Page 22: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

General InformationHow To Use RequireJS

Module Resolution

For each module name appears in array parameter, RequireJS looks upassociated module object

FOUND:Assign module object to corresponding parameter of callback function

NOT FOUND:Generate script block loading JavaScript file named ${module name}.jsLooks up dependencies of AMD module declared in ${module name}.js andinvoke factory methodPut return object into a map structure with key ${module name}Assign return object to corresponding parameter of callback function ofrequire block

Minh Hoang TO Modularize JavaScript with RequireJS

Page 23: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

General InformationHow To Use RequireJS

RequireJS Configuration Variable

Provide flexible mapping between AMD module and URL of JavaScriptresource containing module definition

Figure 9: Configuration variable in case squareAMD and fourthPowerAMD module definitions aredeclared in /js/square_amd.js and /js/fourthPower_amd.js

Minh Hoang TO Modularize JavaScript with RequireJS

Page 24: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

General InformationHow To Use RequireJS

Math Functions - Firebug View

Figure 10: Firebug shows that script blocks loading module are added programmatically

Minh Hoang TO Modularize JavaScript with RequireJS

Page 25: Modularize JavaScript with RequireJS
Page 26: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Legacy JavaScriptNew JavaScriptAchievementsExtensions

Serviceplus - main.js

Content varies with application (DN,DI ,Expressen, . . .)

/main.js?appId=name_of_requested_application

Average size: ≥ 300KBCommon structure: jQuery + jQuery Plugins + business code of application

→ Better JavaScript code organization:

Serviceplus provides jQuery, jQuery Plugins as AMD modules

Business code part of main.js is moved into callback function of requireblock

Minh Hoang TO Modularize JavaScript with RequireJS

Page 27: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Legacy JavaScriptNew JavaScriptAchievementsExtensions

Serviceplus - AMD Modules

Serviceplus provides popular JavaScript libraries in form of AMD modules:

jQuery

jQuery UI

Other jQuery Plugins

Minh Hoang TO Modularize JavaScript with RequireJS

Page 28: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Legacy JavaScriptNew JavaScriptAchievementsExtensions

Serviceplus - jQuery

jQuery module = Minified jQuery wrapped in define block

Figure 11: jQuery AMD module, jQuery.noConflict() is used to avoid conflict with other jQueryversions

Minh Hoang TO Modularize JavaScript with RequireJS

Page 29: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Legacy JavaScriptNew JavaScriptAchievementsExtensions

Serviceplus - jQuery UI

jQuery UI module = Minified jQuery UI wrapped in define block

Figure 12: jQuery UI AMD moduleMinh Hoang TO Modularize JavaScript with RequireJS

Page 30: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Legacy JavaScriptNew JavaScriptAchievementsExtensions

Serviceplus - RequireJS Configuration Variable

Declares mapping between Serviceplus AMD modules and URLs ofJavaScript resources

Merged to RequireJS library to save one HTTP request

Minh Hoang TO Modularize JavaScript with RequireJS

Page 31: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Legacy JavaScriptNew JavaScriptAchievementsExtensions

Serviceplus - New main.js Structure

New main.js = Business code part of main.js wrapped in require block

Figure 13: main.js of an application using jQuery and jQuery UI

Minh Hoang TO Modularize JavaScript with RequireJS

Page 32: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Legacy JavaScriptNew JavaScriptAchievementsExtensions

Faster Login Page

http://account.qa.newsplus.se/login?appId=dagensnyheter.se

Minh Hoang TO Modularize JavaScript with RequireJS

Page 33: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Legacy JavaScriptNew JavaScriptAchievementsExtensions

PageSpeed Scores

Figure 14: PageSpeed scores of http://account.qa.newsplus.se/?appId=dagensnyheter.se

Minh Hoang TO Modularize JavaScript with RequireJS

Page 34: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Legacy JavaScriptNew JavaScriptAchievementsExtensions

PageSpeed Suggestion

Figure 15: No significant issue on JavaScript resource from PageSpeed suggestions

Minh Hoang TO Modularize JavaScript with RequireJS

Page 35: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Legacy JavaScriptNew JavaScriptAchievementsExtensions

Firebug Timeline

Figure 16: Firebug report on JavaScript resource loading

DOMContentLoaded time: 1.88s

Big JavaScript resources jquery, jquery-ui and jquery-custom are loaded inparallel

Minh Hoang TO Modularize JavaScript with RequireJS

Page 36: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Legacy JavaScriptNew JavaScriptAchievementsExtensions

WebPageTest Result

Figure 17: WebPageTest result shows parallel load of large JavaScript resources and sharp reductionon DOMContentLoaded time

Minh Hoang TO Modularize JavaScript with RequireJS

Page 37: Modularize JavaScript with RequireJS

Performance ProblemProblem Analysis

JavaScript Code OrganizingRequireJS Library

RequireJS Integration

Legacy JavaScriptNew JavaScriptAchievementsExtensions

Extensions

Refine Serviceplus AMD modules

Extend relevant server-side functionalities

Minh Hoang TO Modularize JavaScript with RequireJS

Page 38: Modularize JavaScript with RequireJS