サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった...

58
サーバサイドなおじさんが SPAを趣味で 初めて作ってみて わかった n のこと(仮 ) 2015/07/11 関西Ruby会議06 無量井 健 (@muryoimpl) https://www.flickr.com/photos/bongonian/8534960933/

Transcript of サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった...

Page 1: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

サーバサイドなおじさんが SPAを趣味で初めて作ってみて わかった n のこと(仮)

2015/07/11 関西Ruby会議06

無量井 健(@muryoimpl)

https://www.flickr.com/photos/bongonian/8534960933/

Page 2: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

ここに提供

Page 3: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

自己紹介•無量井 健(むりょうい けん)

• 永和システムマネジメント 10ヶ月目

• Ruby関西, 関西Ruby会議04・05 etc

• :white_large_square: 改め :b::b::a:

Page 4: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

サーバサイドなおじさんが SPAを趣味で初めて作って始めてみて

わかった n のこと(仮) ハマった n のこと

2015/07/11 関西Ruby会議06

無量井 健(@muryoimpl)

https://www.flickr.com/photos/bongonian/8534960933/

Page 5: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

使った技術要素(server)Rails4.2 rails-api

jwt google-api-clientactive_model_serializers

pumahamlit

foremanbootstrap-sass poltergeist

Page 6: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

使った技術要素(client)React react-router

webpackjsUri

reqwest

cjsxunderscore

react-draggable

Page 7: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

https://www.flickr.com/photos/thomasletholsen/8719637939/

盛大にハマったり わかったりしたこと n 個を紹介します

Page 8: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

1

Page 9: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

とあるRubyistに 電車の中で

Page 10: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

“SPAという単語を 使うとモヒカンが現れて

炎上しますよ”

Page 11: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

((((;゚Д゚))))

https://www.flickr.com/photos/alvarez-tostado/363243449/

Page 12: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

SPAという単語は 用法・要領を守って 使いましょう

Page 13: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

2

Page 14: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

使った技術要素(client)React react-router

webpackjsUri

reqwest

pumacjsxunderscore

Page 15: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

使った技術要素 React• sprockets との共生を選択した(時間なくて)

• npm install react save-dev => package.json

• webpack で結合した js を//=require で固める

• loaders(coffeescriptの慣れでcjsx使用)

• webpack.config.js 書くだけでいけそう(安易)

• 実際foreman 実行だけで済むので楽だった

Page 16: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

使った技術要素 webpack

• 理由はreact-jade用のloaderがすでにあったから

•でも、開発開始当時、依存関係で入る react のバージョンが古かったので、react-jadeは今回お見送り🙏

Page 17: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

{ "name": "kpton", 中略 }, "dependencies": { "cjsx-loader": "^2.0.1", "coffee-loader": "^0.7.2", "coffee-script": "^1.9.2", "jsuri": "^1.3.1", "jsx-loader": "^0.13.2", "node-libs-browser": "^0.5.0", "react": "^0.13.3", "react-hot-loader": "^1.2.7", "react-router": "^0.13.3", "reqwest": "^1.1.6", "underscore": "^1.8.3", "webpack": "^1.9.7" } }

package.json

Page 18: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

var webpack = require('webpack'); var path = require('path'); var assetsPath = path.join(__dirname, 'app', 'assets', 'client');

module.exports = { // the base path which will be used to resolve entry points context: __dirname, // the main entry point for our application's frontend js entry: { main: [ 'webpack/hot/only-dev-server', path.join(assetsPath, 'main.cjsx') ] },

output: { path: path.join(__dirname, 'app', 'assets', 'javascripts'), // for Rails Assets Pipeline filename: "[name]-bundle.js" }, - 中略 - resolve: { extensions: ['', '.js', '.jsx', 'cjsx', '.coffee'] },

module: { loaders: [ {test: /\.jsx$/, loaders: ['jsx-loader', 'react-hot']}, {test: /\.coffee$/, loaders: ['coffee']}, {test: /\.cjsx$/, loaders: ['coffee', 'cjsx']},

webpack.config.js

entry point なファイルを 指定する

上が配置場所 下が固めた後のファイル名

loaderの対象とする拡張子

どの拡張子にどのloaderを 割り当てるか

Page 19: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

entry point な js

React = require 'react' Router = require 'react-router' routes = require './config/routes.cjsx'

Router.run routes, Router.HistoryLocation, (Handler) -> React.render(<Handler/>, document.body)

app/assets/client/main.js

Page 20: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

ここでRailsのお決まり!!! %html{lang: :ja} %head %meta… 中略 %title KPT = javascript_include_tag ‘client' %body

app/views/layouts/application.html.haml

ここに main.js 等React 使った js を固めている

Page 21: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

全く動かない❗

https://www.flickr.com/photos/alvarez-tostado/363243449/

Page 22: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

どうも main.jsの 手前に対象のDOMが

ないと 動かないらしい…

https://www.flickr.com/photos/alvarez-tostado/363243449/

Page 23: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

サンプルどおりの位置に配置する

!!! %html{lang: :ja} %head %meta… 中略 %title KPT %body = javascript_include_tag ‘client'

app/views/layouts/application.html.haml

ここに配置すると問題なく 動いた

Page 24: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

http://facebook.github.io/react/docs/tutorial.html

Reactのサンプル

Page 25: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

http://facebook.github.io/react/docs/tutorial.html

Reactのサンプル

位置関係、大事であった…

Page 26: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

Page 27: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

使った技術要素(server)Rails4 rails-api

jwt google-api-clientactive_model_serializers

pumahamlit

foremanbootstrap-sass poltergeist

Page 28: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

使った技術要素 poltergeist

• acceptance test を turnip でやろう

• 折角なので、wercker で CI してみよう

• thecaddy/node-ruby の boxを使ってみる

• ローカルで動いたし、おっしゃ push…

Page 29: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

謎のエラーを吐く

Capybara::Poltergeist::JavascriptError: One or more errors were raised in the Javascript code on the page. If you don't care about these errors, you can ignore them by setting js_errors: false in your Poltergeist configuration (see documentation for details).

TypeError: 'undefined' is not a function ( evaluating 'ReactElementValidator.createElement.bind( null, type )') TypeError: 'undefined' is not a function ( evaluating 'ReactElementValidator.createElement.bind( null, type )')

Page 30: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

ちょっと調べてみると poltergeist 1.x系 の問題らしい

https://www.flickr.com/photos/alvarez-tostado/363243449/

Page 31: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

https://www.flickr.com/photos/alvarez-tostado/363243449/

• https://github.com/teampoltergeist/poltergeist/issues/292

• 確かにローカルのphantomjsは 2.0.0 だった

• phantomjs2.0に対応していない環境もある

• facebook/react がpolyfillを用意しているらしい

• https://github.com/facebook/react/issues/945#issuecomment-39694748

phantomjs 1.9系は bind に対応していない

Page 32: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)
Page 33: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

ただ今認証周りの スタブが2回目実行時 に無反応になる問題に

直面中 (原因調査中)

https://www.flickr.com/photos/alvarez-tostado/363243449/

Page 34: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

Page 35: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

使った技術要素(server)Rails4 rails-api

jwt google-api-clientactive_model_serializers

pumahamlit

foremanbootstrap-sass poltergeist

Page 36: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

痛恨のコピペミス…

# 当初 rails-api を使っていなかったが導入してみた。 # API 用の親クラスを作成しようとした class ApiController < ActionController::API

# コピペをミスってActionController::APIに… include ActionController::Serialization end

Page 37: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

痛恨のコピペミス…

class BoardsController < ApiController

# client 側の js からの request があったので # 子クラスで render json を呼び出す def index render json: @current_user.boards end end

Page 38: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

痛恨のコピペミス…SystemStackError (stack level too deep): app/controllers/api_controller.rb:8:in `current_user' app/controllers/api_controller.rb:8:in `current_user' app/controllers/api_controller.rb:8:in `current_user' app/controllers/api_controller.rb:8:in `current_user' app/controllers/api_controller.rb:8:in `current_user' app/controllers/api_controller.rb:8:in `current_user' app/controllers/api_controller.rb:8:in `current_user' app/controllers/api_controller.rb:8:in `current_user' app/controllers/api_controller.rb:8:in `current_user' app/controllers/api_controller.rb:8:in `current_user' app/controllers/api_controller.rb:8:in `current_user' app/controllers/api_controller.rb:8:in `current_user' app/controllers/api_controller.rb:8:in `current_user' app/controllers/api_controller.rb:8:in `current_user'

これが 228 行続く……

Page 39: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

マシンのメモリ8G 食いきって

カーソルが挙動不審 になりました💦

https://www.flickr.com/photos/alvarez-tostado/363243449/

Page 40: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

OOM killer 発動! で

finish👼https://www.flickr.com/photos/alvarez-tostado/363243449/

Page 41: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

Page 42: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

使った技術要素(client)React react-router

webpackjsUri

reqwest

pumacjsxunderscore

Page 43: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

React 使ってみた所感• getInitialState, componentWillMount, componentDidMount などの役割は名前から イメージつきやすい感じする。FWレベル。

• render 内に、最上位のタグが1つしか書けないのが私は意外にひっかかった。component != partial

• やはり view とロジックは分けて書きたくなるのと、htmlの閉じタグを書きたくないでござる… react-jadeは開発 始めたときに対応している react が古くて諦めた。今は?

Page 44: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

top level は1つのみReact = require “react” module.exports = React.createClass render: -> ( <div className=“nav”> <p>あいうえおっすおっす</p> </div> <form className=“inline-form”> </form> )

Page 45: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

top level は1つのみReact = require “react” module.exports = React.createClass render: -> ( <div className=“nav”> <p>あいうえおっすおっす</p> </div> <form className=“inline-form”> </form> )

先に書かれているtop level のtagが render されない…

Page 46: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

partial とは違う…

Page 47: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

あと

Page 48: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

わかりにくい エラー・警告が 多い(気がする…)

Page 49: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

ReactMount: Root element has been removed from its original container. New container: null が大量に並ぶ

Page 50: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

react consoleみると、 同じ要素が2つできてる…

https://github.com/rackt/react-router/issues/600#issuecomment-73364948

Page 51: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

同じだ❗https://www.flickr.com/photos/alvarez-tostado/363243449/

※平日 深夜4時の出来事である…

Page 52: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

https://github.com/rackt/react-router/issues/600#issuecomment-74795259

Page 53: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

https://www.flickr.com/photos/alvarez-tostado/363243449/

Reactがrenderする前の関数で transitionすると 発生するみたい😱

Page 54: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

https://www.flickr.com/photos/alvarez-tostado/363243449/

transitionTo 辞めると

確かに黙った😷

Page 55: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

https://www.flickr.com/photos/thomasletholsen/8719637939/

まとめ

Page 56: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

https://www.flickr.com/photos/thomasletholsen/8719637939/

まとめ•n番煎じでした。

•ハマってみないと穴の深さはわからない

•まだ抜け出せてない穴がある

•涙の数だけ強くなれるよ…

Page 57: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

https://www.flickr.com/photos/thomasletholsen/8719637939/

無駄にハマらずに楽しく

開発できる人が増えると

いいなぁ

Page 58: サーバサイドなおじさんがSPAを趣味で初めて作ってみてわかった n のこと(仮)

EnjoyProgramming!