From Hacker to Developer

From Hacker to Developer

Developing with Webpack, Babel, and React

C43978727926bed201399816f7efb45d?s=128

Joseph Chiang

October 01, 2015
Tweet

Transcript

  1. FROM HACKER 
 TO PROGRAMMER Developing with Webpack,Babel, and React

    @josephj6802 1 Oct 2015
  2. Hacker? Probably Worse… Inefficient or dirty works Sadly especially for

    front-end code
  3. Tag Soup in JS if (inlineTileOptions['show_sharing'] === "1") { //

    Inline Sharing Buttons var tileSharing = $('<div class="tile-sharing"><a class="tile-sharing-expand js-expand-tile- sharing stackla-icon-share" onclick="Widget.expandInlineSharingTool(th var tileShareButtons = $('<ul class="tile-sharing-expanded"></ul>'); tileSharing.append(tileShareButtons); item.append(tileSharing); ! var shareText = t['share_text'] ? t['share_text'].replace(/["']/g, '\\$&') : ''; ! if (t['source'] != 'facebook') { tileShareButtons.append('<li><a data-tile-id="' + t['_id'] + '" class="tile-share-button facebook" title="Share via Facebook" onclick="Widget.facebookShare(th } ! tileShareButtons.append('<li><a data-tile-id="' + t['_id'] + '" class="tile-share-button twitter" title="Share via Twitter" onclick="Widget.twitterShare(this)"><d ! if (t['image']) { tileShareButtons.append('<li><a data-tile-id="' + t['_id'] + '" class="tile-share-button pinterest" title="Share via Pinterest" onclick="Widget.pinterestShare } ! tileShareButtons.append('<li><a data-tile-id="' + t['_id'] + '" class="tile-share-button gplus" title="Share" onclick="Widget.googleShare(this)"><div class="share ! tileShareButtons.append('<li><a data-tile-id="' + t['_id'] + '" class="tile-share-button email" title="Email a friend" onclick="Widget.emailShare(this)"><div clas ! ! } Difficult to read and maintain
  4. Tag Soup in View Difficult to read and maintain

  5. CSS/JS Tags Impossible to remove no longer used scripts No

    Dependency
  6. Environments Too many environments Feature Detection Browser Support Hacks Responsive

  7. Copy Paste fluid.js fluid-horizontal.js base_waterfall.js base_carousel.js auto.js main.js carousel.js slideshow.js

    base_billboard.js base_feed.js base_slideshow.js 80% duplicated code (~1500 lines) * 11 Widget Code Once we start, it’s difficult to refactor
  8. Prototype-based Class Everyone has their own implementation Stackla.createClass(); Widget =

    (function () {})(); function StacklaWidgetNode() {}
  9. Global Variables Global variables and function names are an incredibly

    bad idea. The reason is that every JavaScript file included in the page runs in the same scope. If you have global variables or functions in your code, scripts included after yours that contain the same variable and function names will overwrite your variables/functions.
  10. Stoyan Stefanov The few man-hours spent writing the code initially

    end up in man-weeks spent reading it. Getting Worse
  11. Eliminate the hacking As a developer, we always seek for

    good methodologies, patterns, or better technologies to make our code to be maintained easier. “A bug could be fixed within 10 mins by a newbie, but a good developer is willing spend 4 hours to make it better.”
  12. Happy Developer! when using right tools & code become less

    messy
  13. Universal loader for all static assets Ability to write next-generation

    JS Lead and change the world of front-end app development Foundation Accelerator App New Web Development Stacks
  14. Universal Loader Foundation

  15. JS Module Before Webpack AMD <script/> Make use of global

    variables Ease of define dependencies No dependencies Load modules asynchronously No compile needed by default Ease of define dependencies Always need to compile Synchronous loading by a single file (via global) define(['./a', './b'], function (a, b) {! }); var Acl = require('js/acl/acl.js');
  16. Package Management CSS Preproccessors JS Module Loaders JS Transpiler Build

    Tools
  17. https://www.flickr.com/photos/juhansonin/3141561416/ You’ll need… Not fun… A lot of plug-ins and

    some hacks..
  18. Package Management CSS Preproccessors JS Module Loaders JS Transpiler Build

    Tools less-loader sass-loader coffee-loader ts-loader Support ALL JS STATIC 
 Modules Webpack Dev Server
  19. // app/media/js/admin/terms/term-manage.jsx! ! 'use strict';! ! var React = require('react'),!

    $ = require('jquery'),! LogMixin = require('common/log-mixin'),! TermPanel = require('./term-panel'),! TermList = require('./term-list'),! History = require('exports?window.History!history.js/native.history'),! queryString = require('query-string'),! Cookies = require('js-cookie');! ! module.exports = {! // ...! }; Define Dependencies app/vendor/webpack/node_modules/ app/media/js/ app/media/components/
  20. var History = require('exports?window.History!history.js/native.history');! ! History.Adapter.bind(window, 'statechange', that.handleHistoryChange); Global Module

    require('history.js/native.history');! ! window.History.Adapter.bind(window, 'statechange', that.handleHistoryChange); Not Good Better exports?window.History!history.js/native.history loader loader options (query) separator module path
  21. JS Transpilers var Tagla = require('coffee!./tagla.coffee'); var Stepper = require('ts!./stepper.js');

  22. CSS Preprocessors require('!style!css!sass!admin/acl/acl.scss'); require('!style!css!less!bootstrap/nav.less');

  23. CSS Preprocessors Wait! Are you writing CSS in JS? require('!style!css!sass!admin/acl/acl.scss');

    app/media/js/admin/acl/acl.js • The stylesheet will be injected into HTML with <style> tag • The images inside will be converted to Data URIs. Define dependencies between JS and CSS
  24. Code Splitting fluid-embed.js
 (required) when layout = portrait or landscape

    Load extra assets conditionally lightbox.js
 (optional)
  25. Dev Server Incremental build instead of full build

  26. • Module Loader / Dependencies • Ability to load all

    kinds of assets • High performance • Often replaces grunt or gulp
  27. Using the future of JS, Today! Accelerator

  28. Package Management CSS Preproccessors JS Module Loaders JS Transpiler Build

    Tools sass-loader coffee-loader ts-loader Support ALL Modules Webpack Dev Server babel-loader less-loader
  29. Why Babel? All transpilers are trying to *fix* JavaScript language

    These transpilers have obvious influence on the ES6/ES2015 standard. However browser support is not ready yet
  30. Why Babel? Babel is another transpiler which let you to

    use latest JS Babel keeps sync with ECMAScript Ability to customise the stage or options you want use.
  31. var: Function-scoped Let & Const function f() {! var obj

    = {a: 1, b: 2, c: 3}; ! for (var i in obj) {! // okay! console.log(i); ! } ! // okay ! console.log(i);! }! f(); let: Block-scoped function f() {! var obj = {a: 1, b: 2, c: 3}; ! for (let i in obj) {! // okay! console.log(i); ! } ! // error - i is undefined ! console.log(i);! }! f(); const: Block-scoped function a() {! const DURATION = 100;! {! // output 100! console.log(DURATION);! }! }! ! function b() {! const DURATION = 100;! {! // error "DURATION" is read-only! DURATION = 200;! } ! }! ! function c() {! const DURATION = 100;! {! // ok ! const DURATION = 200;! console.log(DURATION); // output 200! } ! }! Single-assigment
  32. `Template String` // This is what I prefer to do!

    var list = ['<ul>',! ' <li>Buy Milk</li>',! ' <li>Be kind to Pandas</li>',! ' <li>Forget about Dre</li>',! '</ul>'].join(''); ES5 // This doesn't work! var list = '<ul>! <li>Buy Milk</li>! <li>Be kind to Pandas</li>! <li>Forget about Dre</li>! </ul>';! // This does, but urgh… ! var list = '<ul>\! <li>Buy Milk</li>\! <li>Be kind to Pandas</li>\! <li>Forget about Dre</li>\! </ul>'; // This is the most common way, and urgh, too…! var list = '<ul>' +! ' <li>Buy Milk</li>' +! ' <li>Be kind to Pandas</li>' +! ' <li>Forget about Dre</li>' +! '</ul>'; ES6 // This works!! var list = `<ul>! <li>Buy Milk</li>! <li>Be kind to Pandas</li>! <li>Forget about Dre</li>! </ul>`;! http://christianheilmann.com/2015/08/28/es6-for-now-template-strings/
  33. `Template String` ES5 - String + Variables var avatar =

    '<div class="avatar">' +! ' <a href="' + avatarLink + '" target="_blank" class="avatar-profile">' +! ' <div class="avatar-place-holder">' +! ' <img src="/media/images/avatar-mask.png" alt="' + avatarAltText + '" />' +! ' </div>' +! ' <img src="' + getAvatarUrl(t.avatar, t.source) + '" alt="' + avatarAltText + '" />' +! ' </a>' +! '</div>'; var avatar = `<div class="avatar">! <a href="${avatarLink}" target="_blank" class="avatar-profile">! <div class="avatar-place-holder">! <img src="/media/images/avatar-mask.png" alt="${avatarAltText}" />! </div>! <img src="${getAvatarUrl(t.avatar, t.source)}" alt="${avatarAltText}" />! </a>! </div>`; ES6 - String + Variables The ${} construct can take any JS expression that returns a value
  34. class Widget extends Stackla.Base {! constructor(options) {! super(options);! ! this.domain

    = options.domain || null;! this.list_url = `/widget/api/${this.guid}! ?filter_id=${this.filter_id}! &domain=${this.domain}! &page=1! &ttl=1`; ! }! render(el) {! super.render();! }! static getInstances() {! // ...! }! } Classes ES6 - Single convenient declarative form
  35. Module https://babeljs.io/docs/learn-es2015/#modules

  36. Arrow https://babeljs.io/docs/learn-es2015/#arrows-and-lexical-this

  37. Summary • Unlike CoffeeScript, it’s something you must learn and

    use in the future. • Just like PHP4 v.s. PHP5 • Makes my code more legible (ex. class) • develop much faster (ex. less vague, type safety)
  38. App Build UI & APPs

  39. Why so Popular? Google Trend http://reactkungfu.com/2015/07/big-names-using-react-js/ Big Brands using React.js

  40. • Rethink best practices • JSX - Template in JavaScript?

    • CSS in JS - Inline style in JavaScript? • Easy to learn • Embracing Functional Programming • One-way data flow model • Impacting different areas • ImmutableJS, GraphQL Why so Popular?
  41. Package Management CSS Preproccessors JS Module Loaders JS Transpiler Build

    Tools sass-loader Support ALL Modules Webpack Dev Server babel-loader less-loader built-in support for React JSX
  42. Abstraction <button class="st-btn ! st-btn-danger ! st-btn-solid ! st-btn-md”>! Delete!

    </button> <Button kind="danger" ! size="medium" ! solid>Delete</Button> Button New Way Using Class Names Using React.js Old Way Legible & Less Guessing
  43. f <Button kind="danger" size="large" solid>Delete</Button> button.jsx exports default class Button

    extends React.Component {! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! }; this.props.size this.props.kind this.props.solid this.props.children Load CSS Just CSS class name manipulation render() is the only required method in React component import React from 'react';! import cx from 'classnames';! import 'stackla-uikit/scss/_button'; render() {! let that = this,! props = that.props,! className,! node;! ! className = cx('st-btn',`st-btn-${kind}`, {! 'st-btn-disabled': props.disabled,! 'st-btn-solid': props.solid,! 'st-btn-md': (props.size === 'medium'),! 'st-btn-sm': (props.size === 'small'),! 'st-active': props.active,! }, props.className);! ! return <button {...props} className={className}>{props.children}</button>! } The calculated class names Properties
  44. f State import React from 'react';! import Button from './button';!

    const data = [! {text: 'Danger', kind: 'danger', size: 'large', solid: false, active: true},! {text: 'Success', kind: 'success', size: 'medium', disabled: true, solid: true},! {text: 'Info', kind: 'info', disabled: true, solid: true},! {text: 'Default', kind: 'default', size: 'large', disabled: true, active: false}! ];! exports default class App extends React.Component {! constructor() {! this.offset = 0;! }! componentDidMount() {! setInterval(() => {! this.offset = (data.length >= this.offset + 1) ? 0 : this.offset + 1;! this.setState(data[this.offset]);! }, 500);! }! render() {! let state = this.state;! return ! <Button ! kind={state.kind} ! size={state.size} ! solid={state.solid} ! active={state.active}>! {state.text}! </Button>;! }! }; app.jsx React.render(<App>, document.getElementById('app')); Mockup Data Whenever the state changes, the render() will be invoked For Button component, whenever my property changes, the Button#render() will be invoked
  45. <StyleChooser/> <StylePreview/> <Breadcrumbs/> <Panel/> <WidgetsNew/> <Button/> <Button/> Only outmost component

    is stateful Others are stateless, only accept properties
  46. <StyleChooser/> <StylePreview/> <Breadcrumbs/> <Panel/> <WidgetsNew/> <Button/> <Button/> Only outmost component

    is stateful Others are stateless, only accept properties WidgetsNew StyleChooser StylePreview widgetTypes selectedWidget render() render() render() <StyleChooser widgetTypes= /> widgetTypes <StyleChooser selectedWidget= /> selectedWidget Top-down Rendering JSX diffs and apply changes to DOM
  47. UI = f(state) Update UI by changing state object Philosophy

  48. Sebastian Markbåge DOM as a Second-class Citizen https://www.youtube.com/watch?v=Zemce4Y1Y-A

  49. A Tool to Build Our Toolbox Only ourselves knows what

    we want, picking up technologies for right abstraction is crucial. No single library can fulfil our need. Can we build an app without a single DOM element?
  50. Abstraction for Different Targets • React.js in Browser • JSX

    ➡ DOM • react-canvas in Browser • JSX ➡ Canvas • react-isomorphics in Server • JSX ➡ HTML • react-native in iOS • JSX ➡ UIKit • react-native in Android • JSX ➡ android.view
  51. Ambitious Abstraction In Browser, React/JSX relies on slow DOM API.

    Goal Ask WebGL/GPU to use React directly Now
  52. ➡ ➡ ➡ ➡ ➡ Getting Better & Mature ➡

    ➡ ➡ ! ! !
  53. ➡ ➡ ➡ ➡ ➡ Getting Better & Mature ➡

    ➡ ➡ ! ! ! Will these tools go out of fashion in the following 18 months? POSSIBLY! However, everything is becoming 
 more mature and future-compatible We developers just need to choose right tools to do improvements
  54. Feel blessed with I feel much more solid to write

    UI now. Not a hacker but a programmer! $IFFST