Writing a massive javascript app

  • View

  • Download

Embed Size (px)


GSK 2014

Hojoon ParkSr. Software EngineerLinkedInwww.linkedin.com/in/justindoitWriting a massive javascript app12Over the last 3 years,Single Page Application (BackboneJS, AngularJS)Template System(Handlebars, Dust.LI)Web Framework (SugarAPIFramework, Java Play Framework)Unit Test (JasmineJS, SinonJS)SugarCRM BackboneJS, PHP API Framework

23AgendaWeb FrameworksSingle Page ApplicationCase StudyPerformance TuningDemo Single Page ApplicationResources/Assets ManagementWhat is MVC Front-end FrameworkCase Study: AngularJSCase Study: BackboneJSPerformance TuningDebuggingMemory LeakDemo3

4Avoid spaghetti code in Front-end developmentToo much copy/pasteToo much 3rd party recoursesHard to debug the errors

45Web Frameworks, recommend?PlaySpringRuby on RailsYiiNode.JS



56Case Study: BackboneJS on PHPPure SPAMetadata ManagerData Manager

67Case Study: BackboneJS on Java PlayHybrid Web Applicationsbt-concat, sass compilerModel Hierarchy

78Case Study: AngularJS on Java PlayPure SPAGrunt BuilderLess compiler by Grunt

89What is SPA (Single Page Application)?RoutingAngular RouteProvider / Backbone RouterMVC FrameworkModels as the single sourceViews observe model changesMinimized DOM dependent-codeAsset Packaging

Asset Packaging (or more descriptively, packaging code for the browser)910SPA (Single Page Application)Cons.Pros.SEO OptimizationNo longer server side loading(Read data thru AJAX)Higher Risk, Higher Reward(Memory Leak)Client/Server code partitioningLarge File SizeNo Page Refresh1011Consideration for SPAResources/Assets ManagementJS/CSS compressorTemplate compilerAdditional: LESS/SASS compiler

1112Why Asset Management is important?Continuously growing JS/CSS resourcesDuplicated JS files / version inconsistency

1213Sync vs. AsyncSyncAsyncControllerWeb framework(Compiler plugin, AssetManager)Front-end Tools(Require.JS, Inject.JS)Pros.No delay on clickLazy LoadCons.Longer loading timeLoading on click1314Anatomy: Directory(1)

By Resource Type1415Anatomy: Directory(2)By Feature

1516Asset Packaging: Play Frameworksbt-concat pluginJavascriptMinifierCompiler

1617Asset Packaging: Yii FrameworkAssetManager

1718Build asset packages without web frameworkResources/Assets ManagementJS/CSS compressorTemplate compilerAdditional: LESS/SASS compilerBuild System


Package Manager

Bower1819Metadata ManagerSort the dependent modules FlexListView

extends: ListViewListView


extends: ListViewRecordListView

Extends: FlexListViewListView


extends: ListViewDashableListView

extends: ListViewRecordListView

Extends: FlexListView 19 /** * Sorts components in the order they should be declared as classes. This is required since a parent * widget class must likewise be declared before a child that depends on it. * @param {String} type Metadata type e.g. field, view. layout * @param {Array} components List of modules * @param {String} module Module name * @return {Array} Sorted components */ _sortControllers : function(type, components, module) { var updated = {}, nameMap = {}, entries = {}, updateWeights = function(entry){ var controller = entry.controller;

// Here we decrement the weight of any extended components. Note, that if sorting platform // specific components (e.g. portal), and one "extends from" a base component, that parent // will have already been declared since _sortControllers first gets called with base components if (_.isObject(controller) && _.isString(controller.extendsFrom) && entries[controller.extendsFrom] && !updated[controller.extendsFrom]) { // Negative weights as we want to load those first entries[controller.extendsFrom].weight--; updated[controller.extendsFrom] = true; updateWeights(entries[controller.extendsFrom]); } };

// Start by creating a mapping from short name to final class name and precompiling all the controllers that are strings _.each(components, function(entry, name) { if (entry.controller) { var controller = entry.controller, className = (module || "") + app.utils.capitalizeHyphenated(name) + app.utils.capitalize(type);

nameMap[className] = name;

if (_.isString(controller)) { try { controller = eval("[" + controller + "][0]"); } catch (e) { app.logger.error("Failed to eval view controller for " + className + ": " + e + ":\n" + entry.controller); } } entries[className] = { type : name, controller : controller, weight: 0 }; } });

//Next calculate all the weights _.each(entries, function(entry){ updated = {}; updateWeights(entry); });

return _.sortBy(entries, "weight"); },20Metadata Manager: cont.Implementation

.20Great Design patterns are reusable, modular expressions of whats going on in your code.

They allow you to communicate to other developers simply by the way you code,in addition to being easily maintainable themselves21

Why Patterns?A joy is not to be attached deeply cause attachement brings suffer2122Software design patternsFactorySingletonMVCStrongly OOPMixinEvent DrivenJS event based async

Front-end also follows software design patterns2223Object Oriented ProgrammingCode Reuse and recyclingDesign BenefitsMore features, same amount of timeListViewFlexListViewSubPanelListViewDashableListViewRecordListViewSelectionListView 23Mixin pool24Decorator: Mixin (plugin)RecordListView

extends: ListViewErrorDecorationEditableMergeDuplicatesCreateViewAuditFindDuplicatesTooltipListViewMergeDuplicateViewTimeagoActivityStreamView2425BackboneJS: Life-cycle of View ComponentInitializeBind eventsRendertemplateUnbind eventsDisposeWatchersRegisterTriggerUnregister

Angular $watch 2526AngularJS: Life-cycle of scopeCreationWatcher registrationModel mutationMutation observationScope destruction

Angular $watch 26He who binds himself to a joyDoes the winged life destroy;But he who kisses the joy as it fliesLives in eternity's sun rise.27William Blake

A joy is not to be attached deeply cause attachement brings suffer2728Performance tuningRemove duplicate listenersWatcher optimizationBackbone: _events stackAngular: $__watchers in $digest cycleHow many watchers will be incurred?


Dont blame browser2930Memory ManagementDispose safe

InitializeBind eventsRenderUnbind eventsDisposeWatchersRegisterTriggerUnregister (incognito) !3031Memory Management: cont.Catch while unit testing

(incognito) !3132DebuggingFirebugChrome developer toolNetwork filteringRecordingProfilerLocal Storage in resources tab3233Unit TestJasmine, Karma, SinonTravis CISelenium WebDriver