はじめに
スマホ用のSingle Page Applicationサイトを作る上での問題点と対応 とSinglePageApplicationにおける問題点と対応につづく第3弾としてRailsをつかったSPA(Single Page Application)のサイトSmartFXを運用している際に気づいたことについてまとめてみました。
開発環境のリロードに時間がかかる
理由
SPAは大量にJSのファイルが作成されるので、それをひとつひとつ読み込むのに時間がかかりすぎる。
対応
development環境でもjsをconcatさせる
config.assets.debug = false
デプロイ途中にブラウザアクセスすると画面が真っ白
理由
縮退でWebサーバに反映(ロードバランサからWebサーバを切り離して、切り離したWebサーバにdeployし、反映した後で再度ロードバランサに繋ぎなおすことで各Webサーバを更新する方法)した際に、htmlは最新のサーバ、jsが古いWebサーバに見にいってしまい、画面が表示されなくなる瞬間がある。
対応
asset_syncを使うことにより、assets compile後のファイルをS3に置くことでjsやcssがないエラーを回避できる。
1.Gemfileにgem asset_syncを追加しbundle install
2.下記を実行
rails g asset_sync:install --provider=AWS
3.下記ファイルを修正
AssetSync.configure do |config|
config.fog_provider = 'AWS'
config.aws_access_key_id = Access Key Id
config.aws_secret_access_key = Secret Access Key
config.fog_directory = Bucket Name
config.gzip_compression = true
config.fog_region = "ap-northeast-1"
end
4.下記ファイルを修正
config.action_controller.asset_host = "//#{Bucket Name}.s3.amazonaws.com"
参照(https://github.com/rumblelabs/asset_sync)
jsでimageのパスを書き込むとnot foundになる
理由
assetsはdigestがつくので、ファイルが更新される度にpassが変わる
対応
erbを使って、rubyの評価結果をjsの定義にする。
assets以外でも定義している定数もjsに変換することで定義箇所を一箇所にする。
ただし、定数を変更しても、definition.js.erb自体が変更していないとcompileし直されないので、その場合はコメントにrevisionなどを作って更新する。
//revision: 2
window.MyApp = {
assets:{
"no-image": "<%= asset_path("no-image.png") %>",
"logo": "<%= asset_path("logo.png") %>"
}
}
window.MyApp.Settings = <%= Settings.to_json.html_safe %>
画像をuploadするとCPUの負荷が100%になる
理由
サムネイル作成など、画像の圧縮処理の負荷が高い。
対応
クアイアント側で圧縮する。
html5のFile APIとcanvasを使えば、ブラウザでも画像を圧縮させることができ、通信量も減らせる。
@stomitaさんのMega pixel image rendering libraryを使えば簡単。
<form>
<input id="afile" type="file">
<input id="save" type="submit">
</form>
<canvas id="canvas1" style="display:none"></canvas>
class PhotoUpdateView extends Backbone.View
events:
"click #save": "save"
"change #file": "updatePhoto"
updatePhoto: (e)->
files = e.target.files
if files.length == 0
return
@mpImg = new MegaPixImage(files[0])
save: (e)->
fd = new FormData()
@mpImg.render(@$("#canvas1")[0], { maxWidth: 150, maxHeight: 150})
ctx = canvas.getContext('2d')
src = ctx.canvas.toDataURL('image/png', .9)
fd.append('photo', src)
$.ajax
url: /photos
type: "POST"
contentType: false
processData: false
data: fd
success: (obj) =>
alert("success")
error: (xmlHttpRequest, textStatus, errorThrown) =>
alert(xmlHttpRequest.responseJSON.message)
class Photo < ActiveRecord::Base
mount_uploader :image, PhotoUploader
class PhotosController < ApplicationController
def create
photo = Photo.new
file = Tempfile.new(['profile',".png"])
file.binmode
file.write Base64.decode64(params[:photo].sub!('data:image/png;base64,', ''))
photo.image = file
phto.save!
rescue => e
render :json => {:message => e.message}, :status => 400
ensure
file.close if file
file.unlink if file # deletes the temp file
end
end
turbolinkをoffにしたい
理由
SPAでは必要ない
対応
Gemfileから gem 'turbolink'を消し、application.jsの//= require turbolinks を削除
#まとめ
今回は、正直Single Page Applicationあんまり関係ないです。
なんとなく流れで。。