SlideShare uma empresa Scribd logo
1 de 46
Baixar para ler offline
Modern Web Conf 2015
ReactJS and Webpack
for Rails
Tse-Ching Ho
2015-05-16
@tsechingho
何澤清
❖ 紅寶⽯石商⼈人 Rubiest
❖ 鐵道⼯工⼈人 Rails worker
❖ ⿈黃碼科技 創辦⼈人 Goldenio founder
❖ ⽣生物資訊 Bioinformatics
❖ 資料視覺化 Infographics
Javascript
http://www.animen.com.tw/FilesUpload/BNS/131022_17_001.jpg
⼀一入某圈深似海
http://i0.sinaimg.cn/gm/2014/0707/U4511P115DT20140707184058.jpg
suffered by it’s chaos
Javascript
after 5 years fighting
Javascript Modules
❖ Why modules?
❖ Definition & Dependency References
❖ Synchronous/Asynchronous Module Definition
❖ Nested dependencies
❖ CommonJS vs. RequireJS
❖ ECMAScript 6
Factory function module
// my_module.js
var myModule = (function (my, $) {
my.publicMethod = function () {
$('.events').fadeIn();
};
return my;
}(myModule || {}, jQuery));
window.myModule = myModule;
// app.js
myModule.publicMethod();
CommonJS module
// my_module.js
var $ = require(‘jquery');
exports.myModule = function () {
var my = {};
my.publicMethod = function () {
$('.events').fadeIn();
};
return my;
};
// app.js
var myModule = require(‘my_module');
myModule.publicMethod();
RequireJS module
// my_module.js
define(['jquery'] , function ($) {
var my = {};
my.publicMethod = function () {
$('.events').fadeIn();
};
return my;
});
// app.js
var myModule = require('my_module');
myModule.publicMethod();
ECMAScript 6 module
// my_module.js
module myModule {
import $ from 'jquery';
export var my = {
publicMethod: function () {
$('.events').fadeIn();
}
}
}
// app.js
import myModule from ‘my_module';
myModule.publicMethod();
NodeJS Ecosystem
❖ In My Opinion
❖ Feature:
❖ npm
❖ package.json
❖ webpack
❖ Past:
❖ bower
❖ grunt, gulp
❖ browserify
Webpack
❖ Webpack Dev Server
❖ Hot Module Replacement (HMR)
❖ webpack.config.js & CLI
❖ Multiple entry points
❖ Loaders
❖ Plugins
Module style of webpack
require('../component.less');
var Foo = require('app/shared/foo');
var template = require('raw!./tmpl.mustache');
module.exports = Foo.extend({
template: template,
...
});
webpack.config.js
http://webpack.github.io/docs/configuration.html
// client/webpack.rails.config.js
const path = require('path');
module.exports = {
context: __dirname,
entry: ['./assets/javascripts/App', './scripts/rails_only'],
output = {
filename: 'client-bundle.js', // '[name].bundle.js'
path: '../app/assets/javascripts/generated'
},
externals: { jquery: 'var jQuery' },
resolve: {
root: [path.join(__dirname, 'scripts'),
path.join(__dirname, 'assets/javascripts'),
path.join(__dirname, 'assets/stylesheets')],
extensions: ['', '.js', '.jsx', '.coffee', '.scss', '.css',
'.webpack.js', '.web.js', ‘config.js']
},
module: {
loaders: [
{ test: /.coffee$/, exclude: /node_modules/, loader: 'coffee-loader' },
{ test: /.jsx$/, exclude: /node_modules/, loader: ‘babel-loader' },
{ test: /.js$/, exclude: /node_modules/, loader: ‘babel-loader' },
{ test: require.resolve('jquery'), loader: ‘expose?jQuery' },
{ test: require.resolve('jquery'), loader: ‘expose?$' }
]
}
};
Entry point script
// App.jsx
import $ from 'jquery';
import React from 'react';
import CommentBox from './components/CommentBox';
$(function onLoad() {
function render() {
if ($('#content').length > 0) {
React.render(
<div>
<CommentBox url='comments.json' pollInterval={5000}/>
<div className='container'>
<a href='http://modernweb.tw/'>
<h3 className='open-sans-light'>
<div className='logo'/> Modern Web conf 2015
</h3>
</a>
</div>
</div>,
document.getElementById('content')
);
}
}
render();
$(document).on('page:change', () => { render(); });
});
Transpiler
❖ CoffeeScript
❖ React JSX transpiler
❖ ES6 transpiler
❖ Sass transpiler
ReactJS
mostpowerfuljavascriptframework?
Why react ?
❖ view components
❖ virtual dom engine
❖ data api to view philosophy
CoffeeScript Style
// components/cart_modal.js.coffee
{div, h3, a} = React.DOM
CartModal = React.createClass
propTypes:
lang: React.PropTypes.string.isRequired
mixins: [
window.cartLifeCycle
window.cartStorage
window.cartManipulation
]
render: ->
React.DOM.div
className: 'cart'
React.DOM.h3 null, @state.i18n.cart_title
React.DOM.div
className: 'cart-body'
window.CartForm
url: '/cart'
redirect: true
items: @state.items
total: @state.total
actions: true
lang: @props.lang
React.DOM.a
className: 'close-reveal-modal'
'x'
window.CartModal = CartModal
HTML layout
// index.html
<!DOCTYPE html>
<html>
<head>
<title>Hello React</title>
<script src="express-bundle.js"></script>
</head>
<body>
<div id="content"></div>
</body>
</html>
Entry Point
// App.jsx
import $ from 'jquery';
import React from 'react';
import CommentBox from './components/CommentBox';
$(function onLoad() {
function render() {
if ($('#content').length > 0) {
React.render(
<div>
<CommentBox url='comments.json' pollInterval={5000}/>
<div className='container'>
<a href='http://modernweb.tw/'>
<h3 className='open-sans-light'>
<div className='logo'/> Modern Web conf 2015
</h3>
</a>
</div>
</div>,
document.getElementById('content')
);
}
}
render();
$(document).on('page:change', () => { render(); }); // turblolinks
});
Components
// components/CommentBox.jsx
import React from 'react';
import CommentForm from './CommentForm';
import CommentList from './CommentList';
import CommentStore from '../stores/CommentStore';
import FormStore from '../stores/FormStore';
import CommentActions from '../actions/CommentActions';
const CommentBox = React.createClass({
displayName: 'CommentBox',
propTypes: {
url: React.PropTypes.string.isRequired,
pollInterval: React.PropTypes.number.isRequired
},
getStoreState() {
return {
comments: CommentStore.getState(),
form: FormStore.getState()
};
},
getInitialState() {
return this.getStoreState();
},
...
});
export default CommentBox;
Components
const CommentBox = React.createClass({
...
componentDidMount() {
CommentStore.listen(this.onChange);
FormStore.listen(this.onChange);
CommentActions.fetchComments(this.props.url, true);
setInterval(CommentActions.fetchComments,
this.props.pollInterval,
this.props.url,
false);
},
componentWillUnmount() {
CommentStore.unlisten(this.onChange);
FormStore.unlisten(this.onChange);
},
onChange() {
this.setState(this.getStoreState());
},
render() {
return (
<div className="commentBox container">
<h1>Comments { this.state.form.ajaxSending ? 'SENDING AJAX REQUEST!' : '' }</h1>
<CommentForm formData={this.state.form.comment}
url={this.props.url}
ajaxSending={this.state.form.ajaxSending} />
<CommentList comments={this.state.comments.comments} />
</div>
);
}
});
Life cycle of view component
http://facebook.github.io/react/docs/component-specs.html
Flux
https://github.com/facebook/flux
Flux
❖ Bridge
❖ views components
❖ web apis
❖ Implementations
❖ ALT.js
client/
assets/
javascripts/
actions/
components/
common/
session/
stories/
dispatcher/
stores/
utils/
app.jsx
routes.jsx
Stores
// stores/CommentStore.js
import alt from '../FluxAlt';
import React from 'react/addons';
import CommentActions from '../actions/CommentActions';
class CommentStore {
constructor() {
this.comments = [];
this.errorMessage = null;
this.bindListeners({
handleFetchComments: CommentActions.FETCH_COMMENTS,
handleUpdateComments: CommentActions.UPDATE_COMMENTS,
handleUpdateCommentsError: CommentActions.UPDATE_COMMENTS_ERROR,
handleAddComment: CommentActions.ADD_COMMENT
});
}
handleFetchComments() {
return false;
}
...
}
export default alt.createStore(CommentStore, 'CommentStore');
Actions
// FluxAlt.js
import Alt from 'alt';
const alt = new Alt();
export default alt;
// actions/CommentActions.js
import alt from '../FluxAlt';
import CommentsManager from '../utils/CommentsManager';
class CommentActions {
fetchComments(url, displaySpinner) {
this.dispatch(displaySpinner);
CommentsManager.fetchComments(url)
.then((comments) => this.actions.updateComments(comments),
(errorMessage) => this.actions.updateCommentsError(errorMessage));
}
...
}
export default alt.createActions(CommentActions);
// utils/CommentsManager.js
import $ from 'jquery';
const CommentsManager = {
fetchComments(url) {
return $.ajax({ url: url, dataType: ‘json' });
},
...
};
export default CommentsManager;
Rails
10 years old
NOT old fashion!
Assets Management
❖ download from source into vendor/assets
❖ use a ruby gem including a rails engine
❖ use bower and configure rails
❖ use the bower-rails gem
❖ use rails-assets.org
http://www.codefellows.org/blog/5-ways-to-manage-front-end-assets-in-rails
Rails Asset Pipeline
❖ Module Definition
❖ Factory function module
❖ CommonJS module
❖ RequireJS module
❖ Transpiler: coffeescript
❖ package bundler: sprockets
React on Rails
The simple way
❖ sprockets
❖ react-rails
❖ require.js / browserify-rails
❖ coffee-react (cjsx)
3 common ways
❖ Use React inside of Rails with react-rails
❖ React/Flux front end app within Rails
❖ webpack or browserify
❖ Separated Rails API and React/Flux front end app
http://www.openmindedinnovations.com/blogs/3-ways-to-integrate-ruby-on-rails-react-flux
1st Class JavaScript Citizen
❖ NPM Package Manager
❖ ES6 (Harmony)
❖ Using Modules
❖ React.js
❖ JS in server side
❖ Gemified JavaScript
❖ CoffeeScript
❖ Globals on window
❖ React-rails
Hybrid is Good
ES6 + Webpack + React + Rails
Package manager win - win
http://www.railsonmaui.com/blog/2014/10/02/integrating-webpack-and-the-es6-transpiler-into-an-existing-rails-project/
http://www.railsonmaui.com/blog/2014/10/02/integrating-webpack-and-the-es6-transpiler-into-an-existing-rails-project/
Assets bundle frontend - backend
Webpack in Rails
app/
assets/
images/
javascripts/
generated/
client-bundle.js
application.js
stylesheets/
application.sass
config/
webpack/
development.config.js
production.config.js
client/
assets/
images/
javascripts/
stylesheets/
node_modules/
scripts/
rails_only.jsx
webpack_only.jsx
index.html
npm-shrinkwrap.json
package.json
server.js
webpack.hot.config.js
webpack.rails.config.js
.gitignore

.buildpacks
package.json
Procfile
Procfile.dev
Client Side Development
❖ foreman start as rails@3000, webpack-dev@4000
❖ adjust client/server.js for json api of webpack
❖ modify jsx and sass files under client/assets
❖ save files and watch realtime replacement @4000
❖ create json api of rails and verify @3000
❖ deploy with Sprockets
Sprockets long lives
❖ Hybrid is good
❖ webpack for modularity
❖ sprockets for integration (replaced by webpack?)
❖ Assets caching/fingerprinting is easy for non-js views
❖ helpers are still helpful: asset_path, javascript_include_tag
❖ jquery_ujs is still powerful
❖ assets:webpack task works well for deploy
Bad ways for Sprockets
❖ only app/views/layouts/application.html.slim
❖ the layout applies only compiled application.js file
❖ the compiled application.js bundles all files under 

app/assets/javascripts/**/**.js.coffee
❖ dependencies describe in every files
❖ javascript_include_tag would be used in each views for
vendor libraries only
Good ways for Sprockets
❖ many app/views/layouts/xxx.html.slim
❖ each layout applies a compiled xxx.js file
❖ each compiled xxx.js file bundles folders under 

app/assets/javascripts/xxx/**/**.js.coffee
❖ dependencies describe in xxx.js file
❖ javascript_include_tag would be used in each views for
home brewed bundles
Summary of React on Rails
❖ use require.js for legacy javascript codes
❖ use browserify-rails for legacy javascript codes
❖ use react-rails for dynamic components of views
❖ use ES6, Webpack and ReactJS for next feature
⼀一入某圈深似海
http://i0.sinaimg.cn/gm/2014/0707/U4511P115DT20140707184058.jpg
suffered by it’s chaos
References
❖ http://addyosmani.com/writing-modular-js/
❖ http://www.openmindedinnovations.com/blogs/3-ways-to-
integrate-ruby-on-rails-react-flux
❖ http://www.railsonmaui.com/blog/2014/10/02/integrating-
webpack-and-the-es6-transpiler-into-an-existing-rails-project/
❖ https://github.com/justin808/react-webpack-rails-tutorial
❖ http://clarkdave.net/2015/01/how-to-use-webpack-with-rails/
❖ http://fancypixel.github.io/blog/2015/01/28/react-plus-flux-
backed-by-rails-api/

Mais conteúdo relacionado

Mais procurados

[Final] ReactJS presentation
[Final] ReactJS presentation[Final] ReactJS presentation
[Final] ReactJS presentation
洪 鹏发
 

Mais procurados (20)

[Final] ReactJS presentation
[Final] ReactJS presentation[Final] ReactJS presentation
[Final] ReactJS presentation
 
React - Start learning today
React - Start learning today React - Start learning today
React - Start learning today
 
Introduction to ReactJS
Introduction to ReactJSIntroduction to ReactJS
Introduction to ReactJS
 
Intro to React
Intro to ReactIntro to React
Intro to React
 
React js
React jsReact js
React js
 
React JS: A Secret Preview
React JS: A Secret PreviewReact JS: A Secret Preview
React JS: A Secret Preview
 
ReactJS presentation
ReactJS presentationReactJS presentation
ReactJS presentation
 
Understanding Facebook's React.js
Understanding Facebook's React.jsUnderstanding Facebook's React.js
Understanding Facebook's React.js
 
React render props
React render propsReact render props
React render props
 
ReactJs
ReactJsReactJs
ReactJs
 
Reactjs
Reactjs Reactjs
Reactjs
 
React workshop
React workshopReact workshop
React workshop
 
An Overview of the React Ecosystem
An Overview of the React EcosystemAn Overview of the React Ecosystem
An Overview of the React Ecosystem
 
Rest web service_with_spring_hateoas
Rest web service_with_spring_hateoasRest web service_with_spring_hateoas
Rest web service_with_spring_hateoas
 
Workshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionWorkshop 19: ReactJS Introduction
Workshop 19: ReactJS Introduction
 
ReactJS for Beginners
ReactJS for BeginnersReactJS for Beginners
ReactJS for Beginners
 
Introduction to React JS
Introduction to React JSIntroduction to React JS
Introduction to React JS
 
Intro to React
Intro to ReactIntro to React
Intro to React
 
React-JS Component Life-cycle Methods
React-JS Component Life-cycle MethodsReact-JS Component Life-cycle Methods
React-JS Component Life-cycle Methods
 
React & Redux
React & ReduxReact & Redux
React & Redux
 

Semelhante a 20150516 modern web_conf_tw

Semelhante a 20150516 modern web_conf_tw (20)

Frontin like-a-backer
Frontin like-a-backerFrontin like-a-backer
Frontin like-a-backer
 
MeetJS Summit 2016: React.js enlightenment
MeetJS Summit 2016: React.js enlightenmentMeetJS Summit 2016: React.js enlightenment
MeetJS Summit 2016: React.js enlightenment
 
Intro to Laravel 4
Intro to Laravel 4Intro to Laravel 4
Intro to Laravel 4
 
Vue js and Dyploma
Vue js and DyplomaVue js and Dyploma
Vue js and Dyploma
 
MeasureCamp IX (London) - 10 JavaScript Concepts for web analysts
MeasureCamp IX (London) - 10 JavaScript Concepts for web analystsMeasureCamp IX (London) - 10 JavaScript Concepts for web analysts
MeasureCamp IX (London) - 10 JavaScript Concepts for web analysts
 
React native by example by Vadim Ruban
React native by example by Vadim RubanReact native by example by Vadim Ruban
React native by example by Vadim Ruban
 
React & The Art of Managing Complexity
React &  The Art of Managing ComplexityReact &  The Art of Managing Complexity
React & The Art of Managing Complexity
 
Patterns Are Good For Managers
Patterns Are Good For ManagersPatterns Are Good For Managers
Patterns Are Good For Managers
 
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
 
Universal JS Web Applications with React - Luciano Mammino - Codemotion Rome ...
Universal JS Web Applications with React - Luciano Mammino - Codemotion Rome ...Universal JS Web Applications with React - Luciano Mammino - Codemotion Rome ...
Universal JS Web Applications with React - Luciano Mammino - Codemotion Rome ...
 
Building and deploying React applications
Building and deploying React applicationsBuilding and deploying React applications
Building and deploying React applications
 
Introduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress DevelopersIntroduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress Developers
 
L2 Web App Development Guest Lecture At University of Surrey 20/11/09
L2 Web App Development Guest Lecture At University of Surrey 20/11/09L2 Web App Development Guest Lecture At University of Surrey 20/11/09
L2 Web App Development Guest Lecture At University of Surrey 20/11/09
 
Ditching JQuery
Ditching JQueryDitching JQuery
Ditching JQuery
 
Adding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsAdding a modern twist to legacy web applications
Adding a modern twist to legacy web applications
 
Developing ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller PatternDeveloping ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller Pattern
 
Vue JS @ MindDoc. The progressive road to online therapy
Vue JS @ MindDoc. The progressive road to online therapyVue JS @ MindDoc. The progressive road to online therapy
Vue JS @ MindDoc. The progressive road to online therapy
 
lecture5
lecture5lecture5
lecture5
 
lecture5
lecture5lecture5
lecture5
 
Rails is not just Ruby
Rails is not just RubyRails is not just Ruby
Rails is not just Ruby
 

Mais de Tse-Ching Ho (9)

Ruby on bioinformatics
Ruby on bioinformaticsRuby on bioinformatics
Ruby on bioinformatics
 
Webconf2013
Webconf2013Webconf2013
Webconf2013
 
Ajax nested form and ajax upload in rails
Ajax nested form and ajax upload in railsAjax nested form and ajax upload in rails
Ajax nested form and ajax upload in rails
 
mongodb-introduction
mongodb-introductionmongodb-introduction
mongodb-introduction
 
devise tutorial - 2011 rubyconf taiwan
devise tutorial - 2011 rubyconf taiwandevise tutorial - 2011 rubyconf taiwan
devise tutorial - 2011 rubyconf taiwan
 
Rails-3-app-auto-generator-20100817
Rails-3-app-auto-generator-20100817Rails-3-app-auto-generator-20100817
Rails-3-app-auto-generator-20100817
 
model.search: customize your own search logic
model.search: customize your own search logicmodel.search: customize your own search logic
model.search: customize your own search logic
 
The Power of Rails 2.3 Engines & Templates
The Power of Rails 2.3 Engines & TemplatesThe Power of Rails 2.3 Engines & Templates
The Power of Rails 2.3 Engines & Templates
 
ruby e-commerce
ruby e-commerceruby e-commerce
ruby e-commerce
 

Último

Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 

Último (20)

Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 

20150516 modern web_conf_tw

  • 1. Modern Web Conf 2015 ReactJS and Webpack for Rails Tse-Ching Ho 2015-05-16
  • 2. @tsechingho 何澤清 ❖ 紅寶⽯石商⼈人 Rubiest ❖ 鐵道⼯工⼈人 Rails worker ❖ ⿈黃碼科技 創辦⼈人 Goldenio founder ❖ ⽣生物資訊 Bioinformatics ❖ 資料視覺化 Infographics
  • 6. Javascript Modules ❖ Why modules? ❖ Definition & Dependency References ❖ Synchronous/Asynchronous Module Definition ❖ Nested dependencies ❖ CommonJS vs. RequireJS ❖ ECMAScript 6
  • 7. Factory function module // my_module.js var myModule = (function (my, $) { my.publicMethod = function () { $('.events').fadeIn(); }; return my; }(myModule || {}, jQuery)); window.myModule = myModule; // app.js myModule.publicMethod();
  • 8. CommonJS module // my_module.js var $ = require(‘jquery'); exports.myModule = function () { var my = {}; my.publicMethod = function () { $('.events').fadeIn(); }; return my; }; // app.js var myModule = require(‘my_module'); myModule.publicMethod();
  • 9. RequireJS module // my_module.js define(['jquery'] , function ($) { var my = {}; my.publicMethod = function () { $('.events').fadeIn(); }; return my; }); // app.js var myModule = require('my_module'); myModule.publicMethod();
  • 10. ECMAScript 6 module // my_module.js module myModule { import $ from 'jquery'; export var my = { publicMethod: function () { $('.events').fadeIn(); } } } // app.js import myModule from ‘my_module'; myModule.publicMethod();
  • 11. NodeJS Ecosystem ❖ In My Opinion ❖ Feature: ❖ npm ❖ package.json ❖ webpack ❖ Past: ❖ bower ❖ grunt, gulp ❖ browserify
  • 12. Webpack ❖ Webpack Dev Server ❖ Hot Module Replacement (HMR) ❖ webpack.config.js & CLI ❖ Multiple entry points ❖ Loaders ❖ Plugins
  • 13. Module style of webpack require('../component.less'); var Foo = require('app/shared/foo'); var template = require('raw!./tmpl.mustache'); module.exports = Foo.extend({ template: template, ... });
  • 14. webpack.config.js http://webpack.github.io/docs/configuration.html // client/webpack.rails.config.js const path = require('path'); module.exports = { context: __dirname, entry: ['./assets/javascripts/App', './scripts/rails_only'], output = { filename: 'client-bundle.js', // '[name].bundle.js' path: '../app/assets/javascripts/generated' }, externals: { jquery: 'var jQuery' }, resolve: { root: [path.join(__dirname, 'scripts'), path.join(__dirname, 'assets/javascripts'), path.join(__dirname, 'assets/stylesheets')], extensions: ['', '.js', '.jsx', '.coffee', '.scss', '.css', '.webpack.js', '.web.js', ‘config.js'] }, module: { loaders: [ { test: /.coffee$/, exclude: /node_modules/, loader: 'coffee-loader' }, { test: /.jsx$/, exclude: /node_modules/, loader: ‘babel-loader' }, { test: /.js$/, exclude: /node_modules/, loader: ‘babel-loader' }, { test: require.resolve('jquery'), loader: ‘expose?jQuery' }, { test: require.resolve('jquery'), loader: ‘expose?$' } ] } };
  • 15. Entry point script // App.jsx import $ from 'jquery'; import React from 'react'; import CommentBox from './components/CommentBox'; $(function onLoad() { function render() { if ($('#content').length > 0) { React.render( <div> <CommentBox url='comments.json' pollInterval={5000}/> <div className='container'> <a href='http://modernweb.tw/'> <h3 className='open-sans-light'> <div className='logo'/> Modern Web conf 2015 </h3> </a> </div> </div>, document.getElementById('content') ); } } render(); $(document).on('page:change', () => { render(); }); });
  • 16. Transpiler ❖ CoffeeScript ❖ React JSX transpiler ❖ ES6 transpiler ❖ Sass transpiler
  • 18. Why react ? ❖ view components ❖ virtual dom engine ❖ data api to view philosophy
  • 19. CoffeeScript Style // components/cart_modal.js.coffee {div, h3, a} = React.DOM CartModal = React.createClass propTypes: lang: React.PropTypes.string.isRequired mixins: [ window.cartLifeCycle window.cartStorage window.cartManipulation ] render: -> React.DOM.div className: 'cart' React.DOM.h3 null, @state.i18n.cart_title React.DOM.div className: 'cart-body' window.CartForm url: '/cart' redirect: true items: @state.items total: @state.total actions: true lang: @props.lang React.DOM.a className: 'close-reveal-modal' 'x' window.CartModal = CartModal
  • 20. HTML layout // index.html <!DOCTYPE html> <html> <head> <title>Hello React</title> <script src="express-bundle.js"></script> </head> <body> <div id="content"></div> </body> </html>
  • 21. Entry Point // App.jsx import $ from 'jquery'; import React from 'react'; import CommentBox from './components/CommentBox'; $(function onLoad() { function render() { if ($('#content').length > 0) { React.render( <div> <CommentBox url='comments.json' pollInterval={5000}/> <div className='container'> <a href='http://modernweb.tw/'> <h3 className='open-sans-light'> <div className='logo'/> Modern Web conf 2015 </h3> </a> </div> </div>, document.getElementById('content') ); } } render(); $(document).on('page:change', () => { render(); }); // turblolinks });
  • 22. Components // components/CommentBox.jsx import React from 'react'; import CommentForm from './CommentForm'; import CommentList from './CommentList'; import CommentStore from '../stores/CommentStore'; import FormStore from '../stores/FormStore'; import CommentActions from '../actions/CommentActions'; const CommentBox = React.createClass({ displayName: 'CommentBox', propTypes: { url: React.PropTypes.string.isRequired, pollInterval: React.PropTypes.number.isRequired }, getStoreState() { return { comments: CommentStore.getState(), form: FormStore.getState() }; }, getInitialState() { return this.getStoreState(); }, ... }); export default CommentBox;
  • 23. Components const CommentBox = React.createClass({ ... componentDidMount() { CommentStore.listen(this.onChange); FormStore.listen(this.onChange); CommentActions.fetchComments(this.props.url, true); setInterval(CommentActions.fetchComments, this.props.pollInterval, this.props.url, false); }, componentWillUnmount() { CommentStore.unlisten(this.onChange); FormStore.unlisten(this.onChange); }, onChange() { this.setState(this.getStoreState()); }, render() { return ( <div className="commentBox container"> <h1>Comments { this.state.form.ajaxSending ? 'SENDING AJAX REQUEST!' : '' }</h1> <CommentForm formData={this.state.form.comment} url={this.props.url} ajaxSending={this.state.form.ajaxSending} /> <CommentList comments={this.state.comments.comments} /> </div> ); } });
  • 24. Life cycle of view component http://facebook.github.io/react/docs/component-specs.html
  • 26. Flux ❖ Bridge ❖ views components ❖ web apis ❖ Implementations ❖ ALT.js client/ assets/ javascripts/ actions/ components/ common/ session/ stories/ dispatcher/ stores/ utils/ app.jsx routes.jsx
  • 27. Stores // stores/CommentStore.js import alt from '../FluxAlt'; import React from 'react/addons'; import CommentActions from '../actions/CommentActions'; class CommentStore { constructor() { this.comments = []; this.errorMessage = null; this.bindListeners({ handleFetchComments: CommentActions.FETCH_COMMENTS, handleUpdateComments: CommentActions.UPDATE_COMMENTS, handleUpdateCommentsError: CommentActions.UPDATE_COMMENTS_ERROR, handleAddComment: CommentActions.ADD_COMMENT }); } handleFetchComments() { return false; } ... } export default alt.createStore(CommentStore, 'CommentStore');
  • 28. Actions // FluxAlt.js import Alt from 'alt'; const alt = new Alt(); export default alt; // actions/CommentActions.js import alt from '../FluxAlt'; import CommentsManager from '../utils/CommentsManager'; class CommentActions { fetchComments(url, displaySpinner) { this.dispatch(displaySpinner); CommentsManager.fetchComments(url) .then((comments) => this.actions.updateComments(comments), (errorMessage) => this.actions.updateCommentsError(errorMessage)); } ... } export default alt.createActions(CommentActions); // utils/CommentsManager.js import $ from 'jquery'; const CommentsManager = { fetchComments(url) { return $.ajax({ url: url, dataType: ‘json' }); }, ... }; export default CommentsManager;
  • 29. Rails 10 years old NOT old fashion!
  • 30. Assets Management ❖ download from source into vendor/assets ❖ use a ruby gem including a rails engine ❖ use bower and configure rails ❖ use the bower-rails gem ❖ use rails-assets.org http://www.codefellows.org/blog/5-ways-to-manage-front-end-assets-in-rails
  • 31. Rails Asset Pipeline ❖ Module Definition ❖ Factory function module ❖ CommonJS module ❖ RequireJS module ❖ Transpiler: coffeescript ❖ package bundler: sprockets
  • 33. The simple way ❖ sprockets ❖ react-rails ❖ require.js / browserify-rails ❖ coffee-react (cjsx)
  • 34. 3 common ways ❖ Use React inside of Rails with react-rails ❖ React/Flux front end app within Rails ❖ webpack or browserify ❖ Separated Rails API and React/Flux front end app http://www.openmindedinnovations.com/blogs/3-ways-to-integrate-ruby-on-rails-react-flux
  • 35. 1st Class JavaScript Citizen ❖ NPM Package Manager ❖ ES6 (Harmony) ❖ Using Modules ❖ React.js ❖ JS in server side ❖ Gemified JavaScript ❖ CoffeeScript ❖ Globals on window ❖ React-rails
  • 36. Hybrid is Good ES6 + Webpack + React + Rails
  • 37. Package manager win - win http://www.railsonmaui.com/blog/2014/10/02/integrating-webpack-and-the-es6-transpiler-into-an-existing-rails-project/
  • 40. Client Side Development ❖ foreman start as rails@3000, webpack-dev@4000 ❖ adjust client/server.js for json api of webpack ❖ modify jsx and sass files under client/assets ❖ save files and watch realtime replacement @4000 ❖ create json api of rails and verify @3000 ❖ deploy with Sprockets
  • 41. Sprockets long lives ❖ Hybrid is good ❖ webpack for modularity ❖ sprockets for integration (replaced by webpack?) ❖ Assets caching/fingerprinting is easy for non-js views ❖ helpers are still helpful: asset_path, javascript_include_tag ❖ jquery_ujs is still powerful ❖ assets:webpack task works well for deploy
  • 42. Bad ways for Sprockets ❖ only app/views/layouts/application.html.slim ❖ the layout applies only compiled application.js file ❖ the compiled application.js bundles all files under 
 app/assets/javascripts/**/**.js.coffee ❖ dependencies describe in every files ❖ javascript_include_tag would be used in each views for vendor libraries only
  • 43. Good ways for Sprockets ❖ many app/views/layouts/xxx.html.slim ❖ each layout applies a compiled xxx.js file ❖ each compiled xxx.js file bundles folders under 
 app/assets/javascripts/xxx/**/**.js.coffee ❖ dependencies describe in xxx.js file ❖ javascript_include_tag would be used in each views for home brewed bundles
  • 44. Summary of React on Rails ❖ use require.js for legacy javascript codes ❖ use browserify-rails for legacy javascript codes ❖ use react-rails for dynamic components of views ❖ use ES6, Webpack and ReactJS for next feature
  • 46. References ❖ http://addyosmani.com/writing-modular-js/ ❖ http://www.openmindedinnovations.com/blogs/3-ways-to- integrate-ruby-on-rails-react-flux ❖ http://www.railsonmaui.com/blog/2014/10/02/integrating- webpack-and-the-es6-transpiler-into-an-existing-rails-project/ ❖ https://github.com/justin808/react-webpack-rails-tutorial ❖ http://clarkdave.net/2015/01/how-to-use-webpack-with-rails/ ❖ http://fancypixel.github.io/blog/2015/01/28/react-plus-flux- backed-by-rails-api/