d e e p d i v e o n h o w a r c g i s a p i f o r j av as...

51
Deep Dive on How ArcGIS API for JavaScript Widgets Were Built Matt Driscoll – JC Franco – @driskull @arfncode 1/51

Upload: others

Post on 15-Oct-2019

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Deep Dive on How ArcGIS API forJavaScript Widgets Were BuiltMatt Driscoll –

JC Franco –

@driskull

@arfncode

1/51

Page 2: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

AgendaPrerequisitesHow we got hereOur developmentlifecycleWidget development tipsTools we useResourcesQ & A

1/51

Page 3: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Prereqs: Accessor esri/core/AccessorAccessor SDK

Building Classes Using Accessor and theArcGIS API for JavaScript

1/51

Page 4: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Prereqs: TypeScriptLeverage ES6 (syntactic sugar)InterfacesTypingconst and let vs var() => {} vs bind or this-binding utilityTypeScript SetupUsing TypeScript with ArcGIS API forJavascript

1/51

Page 5: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

How we got here3.x

Dojo DijitDijit ThemesLogic tied to UI

4.xAbstracted & framework independentViewModels

1/51

Page 6: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Why?Framework independentEasily customizable themesResponsive designRedesigned Widget API

Consistent with core API

1/51

Page 7: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Our development lifecycleHow do we go about developing widgets?

1/51

Page 8: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development lifecycleAPI designKickoff UI/UX designDevelop ViewModelDevelop ViewWrite testsPull requestAPI merge!!!

1/51

Page 9: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development lifecycle: API DesignWidget developer writes objective for widget

Widget dev defines API in markdownView & ViewModel

PropertiesMethodsEvents

Sample code snippetsDemosQ & A

API reviewed and tweakedJS doc written and approved

Sample

1/51

Page 10: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development lifecycle: ViewModelFriendly, consistent namingPublic methods

Return typesArguments

Public propertiesMake sure no view/UI logic

1/51

Page 11: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development lifecycle: ViewResearch DOM structure needed for widget

Layout containers neededUsing proper semantic tags for nodes

CSS lookup object used in render()Accessible, Aria roles present if necessaryProperties, events, methods aliased as necessaryMake sure no API logic

1/51

Page 12: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development lifecycle: StylesClasses neededBEM naming of classes4x Widgets can use flexbox for layout

1/51

Page 13: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development lifecycle: UI/UX DesignMeeting with our creative labDiscuss needs, APICollaborate on design and tweak markup asnecessaryReceive mockup/wireframes/assets/SassImplement design

1/51

Page 14: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development lifecycle: TestsMake sure we have tests that hit all the APIUnit, integration, functional, screenshot testsMethods are tested with all options and returntypesAssert properties behave as expected whenmodifiedScreenshot testsTest early

1/51

Page 15: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development lifecycle: Pull RequestAll the code changes done in a git branchPR is opened with all changes and tests includedPR is reviewed and testedAPI build is successfulMerge!

1/51

Page 16: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips

1/51

Page 17: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: API DesignHow things can be done differently in 4 compared to3

LeverageCollectionAccessor

View properties instead of eventsRead-only properties

Promises for async operationsSupport modules

Offloading logic where appropriate. Moremodular.

1/51

Page 18: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()Hiding nodes

render() { const childNode = this.childVisible? < return ( <div>{childNode}</div> ); }

1/51

Page 19: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()Reusing classes

const CSS = { root: "example", part: "example__part", disabled: "example--disabled" };

1/51

Page 20: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()Toggling classes

render() { const dynamicClasses = { [CSS.disabled]: this.isDisabled }; return ( <div classes={dynamicClasses}>...</ ); }

1/51

Page 21: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()class cannot change between renders

render() { const rootClass = someCondition ? CSS.foo : CSS.bar; // throws error - cannot change class return ( <div class={rootClass}>...</div> ); }

1/51

Page 22: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()Use join to apply multiple classes

render() { return ( <div class={join(CSS.root, CSS.button, CSS.shadow)}>...</ ); }

1/51

Page 23: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()Toggle styles (similar to classes)

render() { const dynamicStyles = { "x": getX(), "y": getY() }; return ( <div styles={dynamicStyles}>...</div ); }

1/51

Page 24: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()Attributes are not removed between render calls

render() { const tabIndex = this.focusable ? 0 : // `tabIndex` attribute will get rendered when value is falsy return ( <div tabIndex={tabIndex}>...</div> ); }

1/51

Page 25: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()String templates!

render() { return ( <div class={CSS.root}>`Hello, ${this ); }

1/51

Page 26: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()Distinguishable children

render() { // children are NOT dynamically added/removed, `key` is NOT needed return ( <div> <div>foo</div> <div>bar</div> </div> ); }

1/51

Page 27: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()Distinguishable children

Note: key can be a string, number or object

render() { const foo = this.showFoo? <div key="foo" const bar = this.showBar? <div key="bar" // children are dynamically added/removed, `key` IS needed return ( <div> {foo} {bar} </div> ); }

1/51

Page 28: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()Storing data on attributes

render() { return ( <div onclick={this._handleClick} data-lucky-numbers={luckyNumbers()}> ); } private _handleClick(event: MouseEvent) { const node = event.currentTarget as Element; const luckyNums = node.getAttribute("data-lucky-numbers" console.log(`Today's lucky numbers are: ${luckyNums}`);}

1/51

Page 29: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()Binding

render() { return ( <div class={CSS.base}> <div onclick={this._logThis}>this <div bind={this} onclick={this._logThis}>this </div> ); }

1/51

Page 30: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()DOM events

render() { return ( <div class={CSS.base}> <img onclick={this._handleClickEvent} /> </div> ); } private _handleClickEvent(event: MouseEvent) { // do something with event }

1/51

Page 31: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()Real nodes

Markup in render() is virtualNeed to store reference to actual node withafterCreate or afterUpdate

private _realNode: Element = null; render() { return ( <div afterCreate={this._storeThisNode}>...</div>; ) } private _storeThisNode(node: Element): this._realNode = node; }

1/51

Page 32: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()accessibleHandler

render() { return ( <div onclick={this._doSomething} onkeydown={this._doSomething} /> ); } @accessibleHandler() private _doSomething(): void { // ... }

1/51

Page 33: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()Close childless node tags for conciseness

render() { return ( <div> <div class={CSS.childless} /> </div> ); }

1/51

Page 34: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: render()Keep render manageable by extracting pieces asit grows

render() { return <div>{this._renderContent()}</} private _renderContent(): any { return ( <div> <h1>{this.title}</h1> {this._renderItems()} </div> ); }

1/51

Page 35: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: ViewModelsRethinking APIs

More collectionsMore AccessorsView properties instead of eventsRead-only properties

Support modulesOffloading logic where appropriate. Moremodular

Autocasting

1/51

Page 37: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Widget Theming: SassCSS preprocessorVariables@mixin (group statements)@include - (use mixins)@import - (split up files)@extend - (inheritance)More power!

1/51

Page 38: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Sass InstallInstalling grunt­sass

$ npm install --save-dev grunt-sass

1/51

Page 39: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Widget BEM: Block Element Modifier

Methodology to create reusable componentsUses delimiters to separate block, element,modifiersProvides semantics (albeit verbose)Keeps specificity lowScopes styles to blocks

BEM

/* block */ .example-widget {} /* block__element */ .example-widget__input {} .example-widget__submit {} /* block--modifier */ .example-widget--loading {} /* block__element--modifier */ .example-widget__submit--disabled {}

1/51

Page 40: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Development tips: Styling withinViewCSS lookup object

Lookup referenced in JSX

const CSS = { base: "my-widget", title: "my-widget__title" };

<div class={CSS.base}/> <h1 class={CSS.title}>Hello world</h1</div>

1/51

Page 41: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Our ToolsIDEsTasksTestingOther

1/51

Page 42: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Tools: IDEsMultiple flavors

Visual Studio CodeWebStorm

Pluginsand more...

1/51

Page 43: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Tools: TasksNode/npmInstalling GruntCompile TS/Sass

1/51

Page 45: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Other toolsBesides an IDE and browser dev tools...

SourceTreeTerminalGitHub EnterpriseSlack :DA handful of browsersCoffee

1/51

Page 46: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Additional Resources4x widget snippetsJavaScript Sessions at DevSummitDocumentation ­ 4.3

1/51

Page 47: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Find this on GitHubGitHub Code

1/51

Page 48: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Please Take Our Survey!1. Download the Esri Events app and go to

DevSummit2. Select the session you attended3. Scroll down to the "Feedback" section4. Complete Answers, add a Comment, and Select

"Submit"

1/51

Page 49: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

Questions?

1/51

Page 50: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

1/51

Page 51: D e e p D i v e o n H o w A r c G I S A P I f o r J av aS ...proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_252.pdf · W id g e t d e v e l o p e r w r it e s o

1/51