More Related Content Similar to Walk on the Client Side - Chris Mountford (20) Walk on the Client Side - Chris Mountford2. A Walk on the Client Side
JavaScript Apps as Cross-Domain
Embeddable Components
CHRIS MOUNTFORD • SENIOR DEVELOPER • ATLASSIAN • @CHROMOSUNDRIFT
7. Legacy Profile
• Atlassian ID Single Sign-
On (SSO)
• Java, Spring, JSPs
• Full page forms
• Avatar experience
• test automation
• Ignores Atlassian Design
Guidelines (ADG)
8. Profile Card Design
• Identity Card design
• Client-side architecture
• Can be embedded in any
Atlassian application
• Transition path from
legacy profile application
10. ARCHITECTURE
CLOUD SERVICE BROWSER
PROFILE SERVER HOST APPLICATION - (e.g. BITBUCKET, JIRA)
Full Stack
REST
RESOURCES
BACKBONE /
UNDERSCORE
AUI SOY
PROFILE
JQUERY TEMPLATES
MICRO-SERVICES
REQUIRE.JS
& ALMOND OTHER
Scala, Java
JavaScript, LESS, Soy
13. ARCHITECTURE
Automated Testing
TESTING FRAMEWORKS
!
•Java
• JUnit
•Scala
•Specs2
•JavaScript
•Karma and PhantomJS
• Node.js
•Selenium with page objects
14. ARCHITECTURE
Security
• CSRF, XSS
• Cookies are domain-scoped
• http://id.foo.com/
• CORS
• Cross-Origin Resource Sharing
• request and response headers
• JSONP
• is always a security hole*
• never use this!
• Never trust client data
16. DEV LOOP
Working with JavaScript Modules
• Require JS
• Almond
• Node.js
• NPM
• Karma
• Soy and LESS
• Maven
19. DEPLOYMENT
Maven drives the build
• Maven
• Node.js & NPM
• Require JS and Almond
• Karma test runner
• PhantomJS
• Soy to JS Compiler
• LESS transformed to CSS
21. <!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Test profile embed</title>
<link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui.min.css" media="all">
<link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui-experimental.min.css" media="all">
<!--[if lt IE 9]><link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui-ie.min.css"
media="all"><![endif]-->
<!--[if IE 9]><link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui-ie.min.css"
media="all"><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.0/backbone-min.js"></script>
<script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui.min.js"></script>
<script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui-experimental.min.js"></script>
<script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui-soy.min.js"></script>
<!--[if lt IE 9]><script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui-ie.min.js"></script><![endif]-->
</head>
<body>
<div class="profile-card-container" data-base-url="https://id-stg1.atlassian.com/profile"></div>
<script src="https://id-stg1.atlassian.com/profile/pjs/embedded.js"></script>
<script>
AID.ProfileCard('.profile-card-container');
</script>
</body>
</html>
EMBEDDING
22. <!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Test profile embed</title>
<link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui.min.css" media="all">
<link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui-experimental.min.css" media="all">
<!--[if lt IE 9]><link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui-ie.min.css"
media="all"><![endif]-->
<!--[if IE 9]><link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui-ie.min.css"
media="all"><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.0/backbone-min.js"></script>
<script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui.min.js"></script>
<script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui-experimental.min.js"></script>
<script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui-soy.min.js"></script>
<!--[if lt IE 9]><script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui-ie.min.js"></script><![endif]-->
</head>
<body>
<div class="profile-card-container" data-base-url="https://id-stg1.atlassian.com/profile"></div>
<script src="https://id-stg1.atlassian.com/profile/pjs/embedded.js"></script>
<script>
AID.ProfileCard('.profile-card-container');
</script>
</body>
</html>
EMBEDDING
23. <!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Test profile embed</title>
<link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui.min.css" media="all">
<link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui-experimental.min.css" media="all">
<!--[if lt IE 9]><link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui-ie.min.css"
media="all"><![endif]-->
<!--[if IE 9]><link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui-ie.min.css"
media="all"><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.0/backbone-min.js"></script>
<script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui.min.js"></script>
<script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui-experimental.min.js"></script>
<script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui-soy.min.js"></script>
<!--[if lt IE 9]><script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui-ie.min.js"></script><![endif]-->
</head>
<body>
<div class="profile-card-container" data-base-url="https://id-stg1.atlassian.com/profile"></div>
<script src="https://id-stg1.atlassian.com/profile/pjs/embedded.js"></script>
<script>
AID.ProfileCard('.profile-card-container');
</script>
</body>
</html>
EMBEDDING
ROOT
ELEMENT
24. <!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Test profile embed</title>
<link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui.min.css" media="all">
<link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui-experimental.min.css" media="all">
<!--[if lt IE 9]><link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui-ie.min.css"
media="all"><![endif]-->
<!--[if IE 9]><link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui-ie.min.css"
media="all"><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.0/backbone-min.js"></script>
<script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui.min.js"></script>
<script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui-experimental.min.js"></script>
<script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui-soy.min.js"></script>
<!--[if lt IE 9]><script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui-ie.min.js"></script><![endif]-->
</head>
<body>
<div class="profile-card-container" data-base-url="https://id-stg1.atlassian.com/profile"></div>
<script src="https://id-stg1.atlassian.com/profile/pjs/embedded.js"></script>
<script>
AID.ProfileCard('.profile-card-container');
</script>
</body>
</html>
EMBEDDING
EMBED
SCRIPT
ROOT
ELEMENT
25. <!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Test profile embed</title>
<link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui.min.css" media="all">
<link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui-experimental.min.css" media="all">
<!--[if lt IE 9]><link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui-ie.min.css"
media="all"><![endif]-->
<!--[if IE 9]><link rel="stylesheet" href="//aui-cdn.atlassian.com/aui-adg/5.5.5/css/aui-ie.min.css"
media="all"><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.0/backbone-min.js"></script>
<script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui.min.js"></script>
<script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui-experimental.min.js"></script>
<script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui-soy.min.js"></script>
<!--[if lt IE 9]><script src="//aui-cdn.atlassian.com/aui-adg/5.5.5/js/aui-ie.min.js"></script><![endif]-->
</head>
<body>
<div class="profile-card-container" data-base-url="https://id-stg1.atlassian.com/profile"></div>
<script src="https://id-stg1.atlassian.com/profile/pjs/embedded.js"></script>
<script>
AID.ProfileCard('.profile-card-container');
</script>
</body>
</html>
EMBEDDING
EMBED API CALL
SCRIPT
ROOT
ELEMENT
27. Key takeaways: #atlassian
• Require.js: Build modular JavaScript, ship compact bundles.
• JSONP is always a security hole
• FYI: CDN FTW
• Karma is good for testing JavaScript. Testing JavaScript is good Karma.
@chromosundrift