Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Polymer Power Tools

Addy Osmani
September 20, 2015

Polymer Power Tools

We'll cover the new tools now available to help you build with Polymer in production including Polymer Starter Kit, Vulcanize, Crisper, Polyup, Polylint, PolyGit, web-component-tester, our docs and code viewer tools and much more!

Video: https://www.youtube.com/watch?v=LMqM4PfrFxs

Presented at Polymer Summit 2015.

Addy Osmani

September 20, 2015
Tweet

More Decks by Addy Osmani

Other Decks in Programming

Transcript

  1. Today we’ll take an in-depth look at Polymer tooling. We’ll

    cover tools for creating elements & apps, setting up a build process, keeping your projects lean and a few new tools for improving your developer productivity.
  2. But..before that, a quick story. A few weeks ago I

    was visiting Japan. A place that’s really big on automation - the idea of solving repetitive tasks with tools & systems. They’ve really taken this concept to a whole other level. One example of this is the idea of parking a bike.
  3. Now, Polymer Summit being in Amsterdam, you may be familiar

    with the number of bikes here. There are many. Statistically speaking, I’m pretty sure every person in Amsterdam owns 3 million bikes. Parking bikes is a hard problem.
  4. Japan has solved this problem using the ECO Cycle -

    an automated system that has a giant robotic arm that pulls down your bike and parks it for you underground. If this is the first time you’ve seen that, you’re probably wondering.. what type of crazy Matrix sorcery is this?!. This is automation saving us time. Why is automation important for webapp developers?
  5. If you want to be fast, you have to give

    up the things keeping you slow.
  6. Obviously, we can’t automate everything. If we did we would

    be out of a job. Japan has struck a balance between automation and where manual craftsmanship still has its place. At my hotel, they would include a paper crane with meals. Someone manually crafted this origami each time rather than automating it with a machine.
  7. I thought..Hey, I can JavaScript. Surely folding paper can’t be

    all that hard. I’m going to make a paper crane! And, well. The TL;DR is that I’m no longer allowed back in Japan.
  8. The JavaScript tooling ecosystem has a huge number of existing

    tools available. If you’ve used Polymer & Web Components a while, you may have run into few places where running these tools against HTML can be tricky. Things like linting. Good news is that tooling for these problems is getting better.
  9. Build Test Lint Serve CSP CDN 127.0.0.1 git </> The

    New Polymer Toolbox¬ Images: Dreamstime.
  10. Let’s walk through tools for: Writing Reusable elements Automatically porting

    elements to Polymer 1.0 Unit Testing elements Adding elements to apps Productionising apps ~ Vulcanize, Crisper, PolyBuild, PolyLint, PolyGit (CDN) Bonus tools for your workflow
  11. <head> <script src=“../webcomponentsjs/webcomponents-lite.js"> </script> <link rel="import" href=“../iron-component-page/iron-component-page.html"> </head> <body unresolved>

    <iron-component-page></iron-component-page> </body> </html> <seed-element> index.html API docs Images: Google Powered by Hydrolysis
  12. <html> <head> <script src=“../../webcomponentsjs/webcomponents-lite.js"> </script> <link rel="import" href="../seed-element.html"> </head> <body

    unresolved> <seed-element></seed-element> </body> </html> <seed-element> demo/index.html Your demo
  13. <link rel="import" href="../polymer/polymer.html"> <!-- An element providing a solution to

    no problem in particular. --> <dom-module id="seed-element"> <template> <style> ... </style> </template> </dom-module> <script> Polymer({ is: 'seed-element', properties: { <seed-element> seed-element.html Your element Images:JSConf
  14. <!-- An element that translates text to emoji! Example: <emoji-text

    text="Cats love eating donuts!”></emoji-text> @demo demo/index.html --> <dom-module id="emoji-text"> <template> <style>:host { display: block; }</style> <div id=“output"></div> </template> </dom-module> <script> Polymer({ is: 'emoji-text', properties: { text: { type: 'String', notify: true, observer: '_textChanged' } }, _textChanged: function() { ... } textToEmoji: function() { ... } }); </script> <emoji-text> seed-element.html > emoji-text.html Images: Polymer
  15. $  npm  install  -­‐g  bower   $  bower  install  

    > Before we forget, install our dependencies
  16. $  npm  install  -­‐g  polyserve   $  cd  seed-­‐element  

    $  polyserve   Starting  Polyserve  on  port  8000     Serving  components  from  bower_components > Simple server for using components locally $  polyserve  -­‐p  9999 > Customise port number
  17. #  Navigate  back  to  your  development  directory   $  cd

     ..   #  git  clone  the  Polymer  tools  repository   $  git  clone  git://github.com/Polymer/tools.git   #  Create  a  temporary  directory  for  publishing  your  element  and  cd  into  it   $  mkdir  temp  &&  cd  temp   #  Run  the  gp.sh  script.   $  ../tools/bin/gp.sh  <username>  emoji-­‐text   #  Finally,  clean-­‐up  your  temporary  directory  as  you  no  longer  require  it   $  cd  ..   $  rm  -­‐rf  temp > Deploy? Publish to GitHub pages with gp.sh
  18. <polymer-element name='emoji-text' attributes='text'> <template> <style>:host { display: block; }</style> <div

    id='output' on-tap='{{_showOriginalText}}'></div> </template> <script> Polymer({ textToEmoji: function(str) { }, _showOriginalText: function() { }, … }); </script> </polymer-element> <emoji-text> 0.5
  19. HTML Transformations <polymer-element name='my-elem'> <dom-module id='my-elem'> <template repeat='{{x, i in

    xs}}'> <template is='dom-repeat' items='{{xs}}' as='{{x}}' index-as='{{i}}'> <template if='{{x}}'> <template is="dom-if" if="{{x}}">
  20. <dom-module id='emoji-text'> <style>:host { display: block; }</style> <template> <div id='output'

    on-tap='_showOriginalText'></div> </template> <script> Polymer({ is: 'emoji-text', properties: { text: { notify: true } }, textToEmoji: function(str) { }, _showOriginalText: function() { }, ... }); </script> </dom-module> 1.0
  21. $  npm  install  -­‐g  web-­‐component-­‐tester   $  wct > Test

    your Web Components Images: Mocha & Chai projects.
  22. <html> <head> <meta charset="utf-8"> <script src="../../webcomponents-lite.js"></script> <script src=“../../web-component-tester/browser.js"> </script> </head>

    <body> <script> // Load and run all tests (.html, .js): WCT.loadSuites([ 'basic-test.html' ]); </script> </body> </html> test/index.html
  23. <emoji-text text=“top gun”></emoji-text> <script> suite('emoji-text tests', function() { var emojiText

    = document.querySelector(‘emoji-text’); test('Defines the "text" property', function() { assert.equal(emojiText.text, 'top gun'); }); test('Converts text to emoji', function() { emojiText.textToEmoji(); assert.include(emojiText.innerHTML, ''); assert.include(emojiText.innerHTML, ''); }); }); </script> test/basic-test.html
  24. $  wct  -­‐l  chrome > only run tests in chrome

    $  wct  -­‐p > keep browsers alive after test runs $  wct  test/some-­‐file.html > test only the files you specify Testing #protips
  25. Let’s walk through building a quick app that builds on

    the <emoji-text> element. Something that clearly has a niche in the market.
  26. <emoji-quiz-card> <dom-module id="emoji-quiz-card"> ... <emoji-text text=“{{question}}"> </emoji-text> <paper-input required pattern="{{questionPattern}}"

    value="{{answer}}" error-message="OMG NO!" label="Enter your answer"> </paper-input> <paper-button on-tap=“validate"> Submit Answer ... Images: EmojiLib
  27. <emoji-quiz-questions> ready: function() { this.items = [ 'princess diaries', 'back

    to the future', 'sound of music', 'ghost ship', 'china town', 'evil dead', 'money ball']; } Images: EmojiLib
  28. <emoji-quiz-category> <neon-animated-pages id="pages" selected="0"> <x-cards-list> <div class="horizontal layout"> <emoji-quiz-category title="Music"

    emoji="music"></emo <emoji-quiz-category title="Movies" emoji="movies"></e </div> <div class="layout horizontal"> <emoji-quiz-category title=“Knowledge" theme="red" emo <emoji-quiz-category title="Books" theme="green" emoji </div> </x-cards-list> <x-card> <emoji-quiz-questions category="movies"></emoji-quiz-ques </x-card> <x-card> <emoji-quiz-questions category="music"></emoji-quiz-quest </x-card> … </neon-animated-pages>
  29. $  npm  install  —g  gulp  bower  &&  npm  install  &&

     bower  install   > Install tooling & PSK dependencies Node 0.12+
  30. $  npm  install  -­‐g  vulcanize   $  vulcanize  emoji-­‐app.html  >

     build.html   > Reduce an app & its dependents into one file.
  31. $  vulcanize  -­‐-­‐inline-­‐scripts  emoji-­‐app.html     > Inline scripts and

    Imports > Inline Polymerized stylesheets $  vulcanize  -­‐-­‐inline-­‐css  emoji-­‐app.html
  32. $  npm  install  -­‐g  crisper   $  crisper  -­‐-­‐source  index.html

     -­‐-­‐html  build.html  -­‐-­‐js  build.js   > Split inline scripts from HTML for CSP
  33. vulcanize  -­‐-­‐inline-­‐css  -­‐-­‐inline-­‐scripts  -­‐-­‐strip-­‐comments  index.html  |   polyclean  |  crisper

     -­‐-­‐html  index.build.html  -­‐-­‐js  index.build.js   Rather than this.. $  npm  install  -­‐g  polybuild   $  polybuild  index.html     Just do this:
  34. PolyBuild with Gulp! var gulp = require('gulp'); var polybuild =

    require('polybuild'); gulp.task('build', function() { return gulp.src('index.html') .pipe(polybuild()) .pipe(gulp.dest('.')); }); Images: Gulp
  35. $  polybuild  —maximum-­‐crush  index.html > MAXIMUM CRUSH! JS MINIFIED ||

    whitespace removed https://www.flickr.com/photos/stigster/4574486940/
  36. $ polylint sample/imports/ bind-to-class.html sample/imports/bind-to- class.html:12:5 The expression [[myVars]] bound

    to the attribute 'class' should use $= instead of =. <span class=“[[myVars]]"> I love styling with Polymer! </span> ❌ <span class$=“[[myVars]]"> I love styling with Polymer! </span> ✅
  37. $ polylint sample/imports/bound- variables-declared.html sample/imports/bound-variables- declared.html:12:11 Property myVar not found

    in 'properties' for element 'bound- variables-declared' <dom-module id="bound-variables-declared"> <template> <span>[[myVar]]</span> ❌ <span>{{myVars}}</span> ✅ </template> </dom-module> <script> Polymer({ is: 'bound-variables-declared', properties: { myVars: { type: String, value: 'Hello linter!' } } }); </script>
  38. $ polylint sample/imports/computed- binding.html sample/imports/computed- binding.html:13:11 Computed Binding using property

    'notAFunction', which is not a function for element'computed- binding' <dom-module id="computed-binding"> <template> <span>{{notAFunction(myVars)}}</span> ❌ <span>[[isAFunction(myVars)]]</span> ✅ </template> </dom-module> <script> Polymer({ is: 'computed-binding', properties: { myVars: { type: String, value: ‘Hey big linter!' } }, isAFunction: function() { return ''; }, notAFunction: 3 }); </script>
  39. <base href="http://polygit.org/polymer+:master/components/"> <link href="polymer/polymer.html" rel="import"> Control orgs, branches & versions

    Default org, specific version: paper-button+v1.0.2 Default org, master branch: polymer+:master Different org, specific component: super-gif+sjmiles+*
  40. gravatar-photo.html <dom-module id="gravatar-photo"> <template> <img src$="[[url]]"> </template> </dom-module> <script src=“src/gravatar-photo.js"></script>

    <script> Polymer({ is: 'gravatar-photo', .. attached: function () { this.url = window.gravatar.url(this.email, { s: this.size }); } }); </script> Polymer + https://github.com/polymerlabs/gravatar-photo var gulp = require("gulp"); var browserify = require("gulp-browserify"); gulp.task("build", function () { gulp.src("gravatar-photo.js") .pipe(browserify()) .pipe(gulp.dest("build")) }); src/gravatar-photo.js window.gravatar = require("gravatar"); gulpfile.js <gravatar-photo email="[email protected]" size="400"></gravatar-photo>
  41. gravatar-photo.html <dom-module id="gravatar-photo"> <template> <img src$="[[url]]"> </template> </dom-module> <script src=“src/gravatar-photo.js"></script>

    <script> Polymer({ is: 'gravatar-photo', .. attached: function () { this.url = window.gravatar.url(this.email, { s: this.size }); } }); </script> Polymer + https://github.com/polymerlabs/gravatar-photo var gulp = require("gulp"); var browserify = require("gulp-browserify"); gulp.task("build", function () { gulp.src("gravatar-photo.js") .pipe(browserify()) .pipe(gulp.dest("build")) }); src/gravatar-photo.js window.gravatar = require("gravatar"); gulpfile.js <gravatar-photo email="[email protected]" size="400"></gravatar-photo>
  42. gravatar-photo.html <dom-module id="gravatar-photo"> <template> <img src$="[[url]]"> </template> </dom-module> <script src=“src/gravatar-photo.js"></script>

    <script> Polymer({ is: 'gravatar-photo', .. attached: function () { this.url = window.gravatar.url(this.email, { s: this.size }); } }); </script> Polymer + https://github.com/polymerlabs/gravatar-photo var gulp = require("gulp"); var browserify = require("gulp-browserify"); gulp.task("build", function () { gulp.src("gravatar-photo.js") .pipe(browserify()) .pipe(gulp.dest("build")) }); src/gravatar-photo.js window.gravatar = require("gravatar"); gulpfile.js
  43. // Transpile all JS to ES5. gulp.task('js', function () {

    return gulp.src(['app/{elements,scripts}/**/*.{js,html}']) .pipe($.sourcemaps.init()) .pipe($.if('*.html', $.crisper())) // Extract JS from .html files .pipe($.if('*.js', $.babel())) .pipe($.sourcemaps.write('.')) .pipe(gulp.dest('.tmp/')) .pipe(gulp.dest('dist/')); }); ES6 support via { "preset": "google", "esnext": true } Images: BabelJS, JSCS. Optional
  44. Support for the new Chrome for Android Splashscreen When a

    webapp is launched from the Homescreen, this themes the white screen you see until the renderer has something to show.