äž»ãªæ ¹æ
æ°ããã¢ãã€ã«ãµã€ãã§äœæ¥ããŠããéãå€ããµã€ãã®éçºçµéšããããŸããã ãããã®æçŽãæžããŠããæç¹ã§ã¯ããŸã http://ostrovok.ru/mã§å ¥æã§ããã¯ãã§ãã ãã©ã®ãããã®æéæ©èœãããã¯ããããŸããã å€ããµã€ãã¯éåžžã«ç°¡åã«æ©èœããŸããã 圌ã¯äžè¬çãªOTAãããžã§ã¯ãã«äœãã§ãããããã«å¿ããŠãåãããã¯ãšã³ãïŒDjangoïŒãæšæºã¡ãã£ã¢ãžã§ãã¬ãŒã¿ãŒãã·ã³ãã«ãªHTMLãã³ãã¬ãŒãïŒãµãŒããŒåŽïŒãã¢ã³ããŒã¹ã³ã¢ã®ããã€ãã®JavaSciptãã³ãã¬ãŒããSCSSãããã³éåžžã®JavaSciptã䜿çšããŸãã ç§ãã¡ã¯çããã100åçµéšããŸãããããã¯ãã¹ãŠéåžžã«éå±ã§ãã
æ°ãããµã€ããéçºããåã«ã次ã®ã¿ã¹ã¯ãè¡ããŸããã
- ãµã€ããæ°ãããã¶ã€ã³ã«ããåæã«ãã®æ°ãããã¶ã€ã³ãã©ã®ããã«æ©èœãããããããŠä»åŸã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã«äœ¿çšãã䟡å€ããããã©ããã確èªããŸãã
- ãã®ãµã€ãã¯ãiPhoneããã³Android 2.xã4.xãããã©ã«ãã®ãã©ãŠã¶ãŒã§æ£åžžã«æ©èœããã¯ãã§ãã
- å€ãæ©èœã«ã¯ãªãæ°ããæ©èœãããã€ãè¿œå ããŸãã ããšãã°ãããã«åã§ãã£ã«ã¿ãªã³ã°ããããã«ããæ°ã«å ¥ãã«è¿œå ããŸãã ãã¡ããã倧èŠæš¡ãªãµã€ããå®å šã«ã³ããŒããã¹ãã§ã¯ãããŸããã
- 楜ããé¢çœãããŠãã ããã
æŽå²çã«ããµã€ãã¯åžžã«ã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã®èšèšã§éçºãããŠããããã®èšèšã¯ãã®äžã«å±éãããŠããŸãã ãã®ãããªå®éšã®ããã§ãã ãããŠãããã§ã®ãã¶ã€ã³ã¯ãŸã£ããæ°ãããã©ããã§ããïŒiOS 7ã¹ã¿ã€ã«ããã¡ãã·ã§ããã«ïŒïŒã ãããã£ãŠãè²ããããŠå®éã«å€èŠ³ã島ã®ä»ã®éšåãšãããã«ç°ãªãããšã«é©ããªãã§ãã ããã
ååã®ããã«ãOTAã«äŸåããããããŸããã§ããã ããã«ãç§ã¯ãã®ãµã€ãã§äžäººã§äœæ¥ããŸããããDjangoãæããããšã¯ãŸã£ããé¢çœããããŸããããOTAéçºè ã®1人ãåžžã«æ°ãæ£ããããšã¯æ±ºããŠé¢çœããããŸããã ã ããç§ã¯æµ·è³ã®ããã«èããããšã«ããŸããã Ostrovokã«ã¯ãã¢ãã€ã«ãµã€ãã«å¿ èŠãªã»ãšãã©ã®æ©èœãã«ããŒããã¢ãã€ã«APIãæ¢ã«ãããŸãã ãã¹ã¯ããããµã€ãããAPIã®ãã®éšåãè¿œå ãããšãããªãè¯ã解決çãåŸãããŸãã ãããç§ãéžãã ã¢ãããŒãã§ãã
ç§ã¯NodeJSãåºç€ãšããŠåããŸããã ç§ã¯ãã€ããã£ãŠã¿ããã£ãã ãã¬ãŒã ã¯ãŒã¯ã¯ExpressJSã§ãSinatraã«éåžžã«ãã䌌ãŠããŸãïŒããã«ã¡ã¯RubyïŒïŒã ãŠãŒã¶ãŒã»ãã·ã§ã³ãå®æœããå¿ èŠããããããRedisã¯äžå¯æ¬ ã§ãã éåžžãããå°ãªãJavaScriptãå°å·ããã«ã¯CoffeeScriptã䜿çšããŸããã ãã³ãã¬ãŒãã®å Žåã¯JadeããCSSã®å Žåã¯Stylusã䜿çšããŸããã ãã¡ãã·ã§ã³ãµã€ããå¿ èŠã§ãæºåž¯é»è©±ã§ã¯é床ãå€§å¹ ã«åäžãããããšãã§ãããããsinglepageã¯ãã¹ãŠãè¡ãããšã«ããŸããã æåã¯SpineJSã䜿çšããããšãèããŸãããã圌ã®ã³ãã¥ããã£ã¯ããã»ã©å€§ãããªãã®ã§ãBackboneãLo-DashãZeptoãªã©ã®å€å žçãªæã§ãã
ã¢ã»ããã®ã¢ã»ã³ããªãå°ã工倫ããå¿ èŠããããŸããã ã¬ãŒã«ã®ããã«ããã¹ãŠãèªåçã«ã¯ãŒã«ã«ãããã ã¢ã»ããã©ãã¯ã¯éåžžã«åªãããœãªã¥ãŒã·ã§ã³ã§ããããšãå€æããJSãCSSãããã«ã¯Jadeãã³ãã¬ãŒããçµã¿ç«ãŠãäœæ¥ãå®å šã«åŒãåããŸããã ãã¡ããã圌ã¯ãã³ãã¬ãŒããããªã³ã³ãã€ã«ããæ¹æ³ãç¥ã£ãŠãããæå®ãããåå空éã«å ¥ããŸãïŒapp.templatesãéžæããŸããïŒã 圌ã¯ãŸããCoffeeScriptãšèŠä»¶ã·ã¹ãã ãããªã³ã³ãã€ã«ãããšããé çã®çš®ãåãã2ã€ã®ãªãã·ã§ã³ãæäŸããŸããSnocketsïŒSprocketsïŒãšãRequireJSã䜿çšããåŸæ¥ã®NodeJSããŒãžã§ã³ïŒBrowserifyïŒã§ãã ãã ããNodeJSã¯æ°ãããã®ãªã®ã§ãåé¡ããããŸããã
- ãµãŒããŒã®èµ·åæã«çµ±èšãã³ã³ãã€ã«ãããŸãã ãã¡ã€ã«å
ã®äœããå€æŽãããŸãã-ãµãŒããŒãåèµ·åããŠãã ããã çç£äžåé¡ã¯ãããŸããããéçºäžã¯ç¹ã«äŸ¿å©ã§ã¯ãããŸããã nodemonãã€ã³ã¹ããŒã«ããããšã§è§£æ±ºããŸããã ããã«ãCakefileã§ç°¡åãªåœä»€ãèšè¿°ãããµãŒããŒãèµ·åããã ãã§ååã§ãïŒäŸïŒ `cake dev`ïŒã ãããŠåé¡ãããŸããã
- Staticsã¯ã³ã³ãã€ã«ãããŸããããã£ã¹ã¯ã«åãŸããŸããã Asset-Rackã¯ãã¹ãã£ã³ã°ïŒAmazon S3ãªã©ïŒã«ãã¡ã€ã«ãã¢ããããŒãã§ããŸãããããšãã°nginxãä»ããŠèªåã§ãã¡ã€ã«ãæäŸãããå Žåã¯ãåµé çã§ãªããã°ãªããŸããã
compressAsset = (filename, contents)-> console.log("[#{(new Date()).toUTCString()}] #{logPrefix} Compressing asset #{filename}.gz") zlib.gzip(contents, (e, buffer) -> fs.writeFile(filename + '.gz', buffer)) generateAssets = -> for asset in assets.assets filename = __dirname + '/public' + asset.url.replace('.', "-#{asset.md5}.") if not fs.existsSync(filename) console.log("[#{(new Date()).toUTCString()}] #{logPrefix} Saving asset #{filename}") fs.writeFileSync(filename, asset.contents, encoding: 'utf-8') compressAsset(filename, asset.contents) assets.on('complete', -> generateAssets() unless config.is_dev
å°èšïŒ
- ããã¯ãšã³ããšããã³ããšã³ãã¯1ã€ã®èšèªã§æžãããŠããŸãã 1ã€ã®ã³ãŒãã¹ã¿ã€ã«ã§ãåããã¡ã€ã«ãæ¥ç¶ããããšãã§ããŸãã ããšãã°ãããŒã¿æ€èšŒããã³ãã«ããŒãã³ãã¬ãŒãã ããŠãè¿œå ã®ããŒãã¹ãšããŠ-ããã³ããšã³ããã³ããŒã¯ããã¯ãšã³ãã³ãŒããèªãã§ãäœãèµ·ãã£ãŠããããç解ã§ããŸãã
- ãã³ãã¬ãŒããšããã°ã Jadeã¯ãã¯ã©ã€ã¢ã³ããšãµãŒããŒã®äž¡æ¹ã§äœ¿çšã§ããŸãã ç§ã®å Žåã1ã€ã®layout.jadeããã¹ãŠã®ããŒãžã«æ¥ç¶ããŸãã ãã ããå¿ èŠã«å¿ããŠãããã¯ãšã³ãã§ããŒãžãçæããããšã«ããã絶察ã«ä»»æã®ããŒãžãæäŸã§ããŸãã ãã¡ããæ£ããããŒã¿æ§é ãã¹ãããããŸããããå©äŸ¿æ§ã¯æããã§ãã
- ã¹ã¿ã€ã©ã¹ã¯åã«ç¥ã§ãã Jadeãã³ãã¬ãŒããã¹ã¿ã€ã©ã¹ãã¡ã€ã«ã«å®å šã«ã³ããŒããããããäžèŠãªãã®ããã¹ãŠåé€ããŠãã¹ã¿ã€ã«ãèšè¿°ã§ããŸãã ãããWebã®èšèšæ¹æ³ã§ãã
- ããã¯ãšã³ããããã³ããšã³ããã©ãã§ãç°¡åã§ããããããJSONæ§æã
ãã¡ãã·ã§ããã«ã§è¥ã ããã楜ãããªãããã«ã¿ã¹ã¯ã決ããŸããã
ä»çµã¿
ãããžã§ã¯ãèªäœã®ç·šææ¹æ³ã«ã€ããŠå°ã説æããŸãã åçã¯åã®èšèã«å€ããïŒ
BackboneãšCoffeeScriptã®éçºã®è©³çŽ°ã«ã¯è§ŠããŸããã ããã«ã€ããŠäœåãã®èšäºãæžãããŠããŸãã ã¢ãžã¥ãŒã«ã®æ§é ã«ã€ããŠç°¡åã«èª¬æããŸããäžè¬çã«ã¯ãç§ããã£ãããã«ã倢äžã«ãªããªãããã«ããŸãã
æããã«ãBackboneã«ã¯ã³ã¬ã¯ã·ã§ã³ãã¢ãã«ããã¥ãŒããããŸãã å¥ã®ãã©ã«ãã«å ¥ããŸãã ã¢ãžã¥ãŒã«ãå¿ èŠã§ããã ãããã¯ãç§ãã©ã®ããŒãžã«ããŠããåžžã«å¿ èŠãªãã®ã§ãã ãããã¯ã¢ããªã±ãŒã·ã§ã³ã®éå§æã«ããŒããããããšãã°ããã¥ãŒãå¥ã®ããŒãžã«ç§»åãããšãã«ããã«ç Žæ£ããããšãã«ã¢ã³ããŒããããªããªããŸãã äžéšã®ã¢ãã«/ã³ã¬ã¯ã·ã§ã³ïŒããšãã°ã[çµäº]ãã¿ã³ãã¯ãªãã¯ãããšãã®äºçŽã®ãªã¹ãïŒãšåæ§ã ç§ã®ã¢ãžã¥ãŒã«ã¯ãã¢ãŒãã«ãŠã£ã³ããŠããµã€ãããŒãé»è©±ã®ç©ççãªäœçœ®ã«é¢ããæ å ±ãªã©ã§ãã
æçµçã«ãããã¯ç§ã®ã¡ã€ã³app.coffeeãã¡ã€ã«ã®å€èŠ³ã§ãïŒ
#= require ../../data/app.config.js #= require ../helpers.js #= require app.utils.js #= require_tree modules #= require router.coffee #= require_tree models #= require_tree collections #= require_tree views app = _.extend(@app, Backbone.Events) # ... # Layout modules app.size = new app.modules.Size() # Data modules app.geo = new app.modules.Geo() app.user = new app.modules.User() app.analytics = new app.modules.Analytics() # Modals and extra views app.overlay = new app.modules.Overlay() app.modal = new app.modules.Modal() # Router relies heavily on stuff above app.router = new app.Router() # ... Backbone.history.start(pushState: true, hashChange: false)
ããã¯ãããã¯ãšã³ãã§ã䜿çšãããhelpers.jsã§ãã require_treeãä»ããŠãã©ã«ããŒãæ¥ç¶ãããšãåã ã®ãã¡ã€ã«ã®æ¥ç¶ã«ã€ããŠèããããšã¯ã§ããŸããããèªã¿èŸŒã¿é åºã¯ãããä¿èšŒããªããããä»ã®ã¯ã©ã¹ïŒããšãã°ãviewïŒããç¶æ¿ããå¿ èŠãããå Žåã¯è¿œå ã®requireãè¡ãå¿ èŠããããŸãã ãã®ãããªã¿ã¹ã¯ã¯ãããŸããã§ããããBackbone.history.startãåŒã³åºããŸã§ã«ãã·ã¹ãã ã®ãã¹ãŠã®ã¢ãžã¥ãŒã«ãšã³ã³ããŒãã³ãã¯æ¢ã«ã¡ã¢ãªã«ãã£ããããã«ãŒã¿ãŒã¯ãã®ä»äºãã³ãŒã«ãã¥ãŒãªã©ãå®è¡ã§ããŸããã
ã¹ã¿ã€ã©ã¹ã«ã€ããŠå°ã説æããŸãã SASSã«éåžžã«äŒŒãŠããŸãããå€ãã®è¿œå æ©èœããããŸãã æããã«ãèå¥ããŒã¹ã§ãã ããã«ãããã¯ã©ã¹åã®å ±ééšåã«ç ©ããããããšããªããªããŸãã ããããç§ãã¡ã¯çé·ãéãããèŠãŠããŸãããããã¯éå±ã§ãã CSSã«ãŒã«ã®å€ãå€æ°ãšããŠäœ¿çšã§ããã®ã¯ã©ãã§ããïŒ
.my-awesome-block width: 100px height: 100px margin: (@width / 2) auto line-height: @height
æªããªãã ãã³ããŒãã¬ãã£ãã¯ã¹ã®ãµããŒãã¯ã©ãã§ããïŒ ç§ãã¡ã¯ã²ã©ã競äºã®äžçã«äœãã§ããŸãã 幞ãã次ã®ããã«ãªããŸãã
.my-awesome-block box-sizing: border-box transition: all .2s ease
ã¹ã¿ã€ã©ã¹èªäœã¯ãèªåãæã£ãŠããããã¯ã¹ã€ã³ã調ã¹ãåãååã®ããããã£ãèŠã€ãããšã眮æãå®è¡ããŸãã ãããã£ãŠãå¢çç·ã®ååŸïŒã¡ãªã¿ã«trueïŒã®ããã«ããã³ããŒãã¬ãã£ãã¯ã¹ãå ¥åããå¿ èŠããªããªã£ãå Žåã1ã€ã®ããã¯ã¹ã€ã³ãåé€ããã ãã§ãæ®ãã®ãã¡ã€ã«ãéãããšããã§ããŸããã ããããããŸããããããã§å°æ¥çŽ100åã®ç¯çŽãã§ããããã«æããŸãã ããŠãç§ã®app.stylãã©ã®ããã«èŠãããã®å°ããªäŸïŒ
@import 'config' @import 'includes/reset.css' @import 'includes/fonts.css' @import 'includes/mixins' @import 'plugins/iswipe' @import 'plugins/zepto.sidebarify' @import 'plugins/zepto.calendar.css' @import 'plugins/zepto.input.numselect.css' @import 'plugins/zepto.listselect.css' @import 'plugins/zepto.textarea_autogrow' @import 'partials/partial_date' @import 'partials/partial_spinner' // ...
æ··åã€ã³ããŒããåé¡ã§ã¯ãªãããšãããããŸããã çŸæç¹ã§ã®å¯äžã®æ¬ ç¹ã¯ãmixinãåŒã³åºãããã«åŒæ°ãå¿ èŠãªããšã§ãã ããããªããã°ããã®åŒã³åºãã¯æ©èœããŸããã§ããããæ¢ã«ä¿®æ£ãããŠããŸããã ç§ã¯ãã®ããã«æžããŠããŸãïŒ
html, body // lol! noselect plz body, select, input, button, textarea color: #4b5c66 font: normal 14px Helvetica, Arial, sans-serif line-height: 1.4em //...
ã¹ã¿ã€ãªã³ã°ã§ã¯ãåžžã«ã¯ã©ã¹ã®ã¿ã䜿çšããŠã·ã¹ã®éªæªãªç¹ç°æ§ãæã¡è² ãããã¯ã©ã¹ã亀差ããªãããšã146ïŒ ä¿èšŒããããã«ãSMACSSã¢ãããŒãã䜿çšããŸããã ãŸãããŸãã¯ããã§ã¯ãªãããéåžžã«äŒŒãŠããŸãã ããŒãžã®æ§é ã«é¢é£ãããã©ã³ãžã·ã§ã³äžã«å€æŽãããªããã®ã¯ãã¹ãŠãæ¥é èŸlïŒã¬ã€ã¢ãŠãïŒã§è¡ããŸããã ãŸããpïŒããŒãžïŒãbïŒãããã¯ïŒããŒãžå ã®ãããã¯ãªã©ããããŸãã èŠçŽ ãèŠçŽ ã«ãã¹ããããŠããå Žåããã®ã¯ã©ã¹ã¯èŠªã®ååã®äžéšãç¶æ¿ããŸãã ç¶æ¿ãããªãå ŽåããããŸãããã«ãŒãã¯ã©ã¹ã¯åžžã«ç¶æ¿ãããŸãã ã¹ã¿ã€ã«ã®äŸã次ã«ç€ºããŸãã
.p-awesomepage .pa-header // styles .pah-soopermenulink color: hotpink .pa-content // styles .pa-loading // styles .pa-title // styles
ãã®ããŒã¯ã¢ããã®å ŽåïŒ
.p-awesomepage header.pa-header wow, header! .pa-content .pa-title my awesome title .pa-loading .pa-title loading is being loaded
ãã®ã¢ãããŒããšã¹ã¿ã€ã©ã¹ã®ã«ãŒã«ã®ãã¹ããçµã¿åãããå ŽåïŒäž»ãªããšã¯ã·ããããªãããšã§ããããããªããšãåºå£ã§ãœãŒã»ãŒãžãåºãŸãïŒã亀差ç¹ã¯ãããŸããã
ãžã§ã€ãã«ã€ããŠã¯äœãèšãããšã¯ãããŸããã ããã¯éåžžã«ãã³ãã¬ãŒããšã³ãžã³ã§ãã ã¹ãªã ã䜿çšãã人ã¯åãã§ãã ãµããŒãã«ã¯ã€ã³ã¯ã«ãŒããšããŒã·ã£ã«ãå«ãŸããŸãã äžè¬çãªhelpers.jsãã¡ã€ã«ãä»ããŠãã«ããŒãæããŸããã ç¬èªã«ç»é²ããããšãã§ããŸããã ããšãã°ããã§ã«æã£ãŠããïŒããŒã¯ããŠã³ã
å±éã«ã€ããŠå°ã
éçºã®éçºæ¹æ³ã«é¢ãããã¹ãŠãããã«ç解ã§ããå Žåã¯ãããã§å°ãèããªããã°ãªããªãå±éãå±éããæ¹æ³ã瀺ããŸãã ã¬ãŒã«ã«ã€ããŠã¯ãcapistranoã®ãããª9999999ãœãªã¥ãŒã·ã§ã³ããã§ã«çºæãããŠããŸããããããŸã§ã®ãšãããããŒãã§æ©èœãããã®ãèŠã€ããããšãã§ããŸããã§ããã
ç§ã¯ã次ã®ããšãè¡ããcake deployããšããã±ãŒãã®æ瀺ãæ倧éã«æŽ»çšããããã«ããã¹ãVPSã決å®ããŸããã
task 'update', '[VPS]: Update current state with new from repo', -> console.log('[Cake]: Pulling updates from repo') exec('git pull', (error, stdout, stderr) -> unless error console.log('[Cake]: Installing npm packages') exec('npm install', (error, stdout, stderr) -> unless error console.log('[Cake]: Restarting forever') # exec('forever restartall') exec('killall forever') exec('killall nodejs') console.log('[Cake]: Cleaning up old assets') exec('find ./public/assets -regextype posix-egrep -regex ".*\.(js|css|gz|gzip)$" -delete') exec('cake forever') sendMail() else console.warn("[Cake]: Installation failed with error: #{error}") ) else console.warn("[Cake]: Update failed with error: #{error}") ) task 'deploy', '[DEV]: Deploy current repo state to dev VPS', -> console.log('[Cake]: Connecting to VPS mobota@mobota-dev.ostrovok.ru && running update') exec('ssh mobota@mobota-dev.ostrovok.ru \'cd /var/www/mobota && cake update\'', (error, stdout, stderr) -> if error console.warn("[Cake]: Deploy failed with error: #{error}") else console.log('[Cake]: Deployed!') )
å®çšŒåç°å¢ã«ããŒã«ã¢ãŠãããããã«ãDenis Orlihinã¯debianããã±ãŒãžãã»ããã¢ããããŸããã teamcityã®é è骚ã¯æ©èœããã¢ã»ã³ããªã®åã«ãã¹ããå®è¡ããŸãã ãšãŠããã£ãããã 詳现ã¯ãäŒãããŸãããããããã圌ãäœããã®åœ¢ã§äŒããã§ãããã
ãã¹ããšããã°ã ããããã³ããšã³ãã§ãããååãšããŠéåžžã«æ laãªã®ã§ãç§ã¯éåžžãã¹ããæžããŸããã ãããããµãŒãããŒãã£ã®APIã«äŸåããå¿ èŠããããããããã§ã¯çµ±åãã¹ããæ¬åœã«å¿ èŠã§ããã mocha + chaiJSã®ãã¹ããäœæããŸããã éåžžã«ã·ã³ãã«ã§äŸ¿å©ããããŠæãéèŠãªã®ã¯åªããã¬ããŒã¿ãŒã§ãïŒ
ïŒç§ã¯å ¬åã«åº§ã£ãŠããã®ã§ãã€ã³ã¿ãŒãããã¯è¶ é«éã§ã¯ãªãããã¹ãã¯èœã¡ãŸããïŒ
ããã¯ãã¹ãŠéåžžã«èå³æ·±ãã§ãããã¢ãã€ã«éçºã«ã€ããŠã¯ã©ãã«ãããŸããã
ãããŠç¢ºãã«ãããã¯æãéèŠãªããšã®ããã®æéã§ãããã æ¬æ Œçãªãã©ãŠã¶ãšæ¯èŒããŠãã¢ãã€ã«ããã€ã¹çšã«éçºããéã«æ°ã¥ããéãã¯äœã§ããã äžåºŠã«è€æ°ã®ãã©ãããã©ãŒã ã§äœæ¥ããå¿ èŠããããåãã©ãããã©ãŒã ã«ã¯ç¬èªã®åé¡ãããããšãèãããšãããã»ã©åçŽã§ã¯ãªãããšãããããŸãã æšå¹Žããç¶æ³ã¯ããã»ã©å€ãã£ãŠããªããšèšããã äž»ãªåé¡ã¯ã2çªç®ã®ããŒãžã§ã³ã®Androidæºåž¯é»è©±ãš4代ååã§ãã iOSã§ã¯ãå¥è·¡ããããŸããããã¹ãŠãã¯ããã«ç°¡åã§ãã
ãŸããåé¡ã«é¢ãã詳现ã äžéšã¯éåžžã«æçœã§ãããç¹°ãè¿ããŸãã ããã€ãã¯ç§ã«ãšã£ãŠåããŠã®ããšã§ãããã€ãŸããä»ã®èª°ãã«åœ¹ç«ã€å¯èœæ§ããããŸãã
- ãã¬ãŒããã¯ãªãã¯ããŸãã 300msã®ã¯ãªãã¯é
延ã«ã€ããŠã¯èª°ããç¥ã£ãŠããŸãã ãµã€ãäžã®éåžžã®ãªã³ã¯ã®ã¯ãªãã¯ã¯ãã¯ãªãã¯åŸçŽ300ããªç§ã§åŠçãããŸãã ããã¯ããããå®éã«ã¯ã¯ãªãã¯ã§ãããä»ã®ãžã§ã¹ãã£ãŒã§ã¯ãªãããšãç解ããããã«å¿
èŠã§ãã ããŸããšããŠãã¿ããã¹ã¿ãŒãã€ãã³ããªã¹ããŒããªã³ã¯ã«è¿œå ããããšãããšããããã ããŒãžã®ã³ã³ãã³ããæ¢ã«å€æŽãããŠããå Žåã§ããæ£ç¢ºã«300ããªç§åŸã«åãé åã§ãŽãŒã¹ãã¯ãªãã¯ããŸãã ãŸããAndroid 2ã§ã¯ãŸã£ããå¥ã®ããŒãžã§çºçããŸãã ãã®åé¡ã«ã¯ããã€ãã®è§£æ±ºçããããŸãã Googleã®ããã«ããããã®ãŽãŒã¹ãã¯ãªãã¯ããã£ããããããã®ç¬åµçãªã¹ããŒã ãèæ¡ã§ããŸãã ãŸãã¯ãååãšããŠãªã³ã¯ãæåŠããŠã€ãã³ããã¯ãªãã¯ããã ãã§ãã ç§ã®å Žåã2çªç®ã®ãªãã·ã§ã³ãéžæããŸããã Zeptoã«ã¯ããã®ããã ãã®ã«ã¹ã¿ã ã¿ããã€ãã³ãããããŸãããå£ããŠããŸãã ãœãªã¥ãŒã·ã§ã³ãäœæããŸãããããããGitHubã«æçš¿ããŸãã
- 網èäžã®ãŒãããåçã çŸåšãpixel-ratio> 1.5ã®ããã€ã¹ãå¢ããŠããŸããã€ãŸããä»®æ³ãã¯ã»ã«ããšã«ããã€ãã®ç©çãã¯ã»ã«ããããŸãã ãã®ãããªããã€ã¹ã§ç»åããŒãããªãããã«ããã«ã¯ãç»åãæ°å倧ããã¢ããããŒãããŠæ¡å€§çž®å°ããã°ååã§ãã é
延ã®ã¢ãããŒãã¯ãåžžã«å€§ããªç»åãšã¹ã±ãŒã«ïŒèæ¯ãµã€ãºã®FTWïŒãã¢ããããŒãããããšã§ãã
- é·ç§»/å€æã䌎ãããŒããŠã§ã¢ã¢ã¯ã»ã©ã¬ãŒã·ã§ã³ã¢ãã¡ãŒã·ã§ã³ã ããã§ã¯ãã¹ãŠãæããã§ããããã«èŠããã®ã§ãããããå Žæã§translateãŸãã¯translate3dã䜿çšããŠãã ããã å®éãããã§ã¯ãããŸããã ãŸããGPUã䜿çšããŠãã¹ãŠã®ããããã£ãé«éåããããã§ã¯ãããŸãããããããããã§ãã äœçœ®ãéæ床ãªã© 第äºã«ãAndroid 2ã«ã¯ãã¢ãã¡ãŒã·ã§ã³åããããããã¯ã®åšæçãªã¡ãã€ãããã¯ãªã¹ãã¹ããªãŒãã®åºçŸãããã³äžè¬çãªãã¬ãŒãã®åœ¢ã§ã®translate3dã«é¢ããé倧ãªåé¡ããããŸãã ããŠãGPUã¬ã€ã€ãŒäžã«ãããããã¯ãåã¬ã³ããªã³ã°ããå¿
èŠãããå ŽåãiOSã«ã¯åé¡ããããŸãã ããšãã°ãç§ã®ãµã€ãã«ã¯ãµã€ãããŒãããããã©ãã°ããããšãã§ããŸãããŸããã¯ãªãã¯ããã ãã§ã¢ãã¡ãŒã·ã§ã³åãããŸãã ã¯ãŒã«ãªããšã«ãå Žæã¯ã»ãšãã©ãããŸããããã¢ãã¡ãŒã·ã§ã³ã§ã¯ä»ã®ã©ãã«ãèŠãããšããããŸããã ããããåé¡ã¯ãã³ã³ãã³ããGPUã«è»¢éãããšãäžéšã®ããŒãžã«ç§»åãããšãã¡ãã€ããå§ãŸãããã©ãŠã¶ããããæç»ããŠGPUã«å床ãããããããŸã§ãç»é¢ãã0.5ç§éæ¶ããŸãã å·Š/äžã䜿çšããããšã«æ»ããªããã°ãªããŸããã§ããã ããã«ã翻蚳ã䜿çšããŠã©ããã«åŒãåºããããããã¯ã«ãã€ãã£ãéžæèŠçŽ ã衚瀺ãããšãAndroid 2ã§ã¯å®å
šã«æ©èœããªããªããŸãã çæããŠãã ããïŒããããããŠã³ãªã¹ãã¯ããããã¯ãå
ã
ç»é¢ã«è¡šç€ºãããŠããå Žæã§ã¯ãªããå
ã®å Žæã«è¡šç€ºãããŸãïŒã
- åºå®äœçœ®ã ç§ãè©ŠããŸããã ãªãŒããŒãããŒïŒã¹ã¯ããŒã«ã䜿çšãããšãç¶æ³ã¯æ¹åãããããã§ãããããfixedãªã¬ã€ã¢ãŠãã®åºå®èŠçŽ ã®åé¡ã解決ããå¿
èŠããããŸãã ååæ¢ãããšããiOSã§ãªãŒãã³ããŒããŒãã䜿çšããŠåæç»ããŠãããŸããããŸããã§ããã
- Android 2ã¯JSON.parseïŒnullïŒã§çŽ æŽãããåäœãããŸãã 解æããåã«æååãæ€èšŒããŠãã ããã ãããŠåœŒã¯ãããã¹ãã·ã£ããŠã§ããã¹ããå®å
šã«ã¬ã³ããªã³ã°ããæ¹æ³ãç¥ããŸããã ãã€ãããŒã·ã§ã³ãæ©èœããªãå Žåããããäžéšã®æåãé£ã³å»ãå ŽåããããŸãã ç§ã¯ãã€ãããïŒ
.android2 * text-shadow: none !important;
å€ãã®æéãšç¥çµãç¯çŽããŸãã
- ãŠã£ã³ããŠã®åäœã«ã¯ããã€ãã®éãããããŸãã ãŸããã¹ã±ãŒã«ãéåžžã«ç°¡åã«å€æŽã§ããŸããããã¯ã倧èŠæš¡ãªãã©ãŠã¶ãŒã§ã¯ã»ãšãã©è¡ãããŸããã èŠæš¡ãæ¡å€§ããããšããå§ãããŸãã人çã楜ã«ãªããŸãã 次ã®ããã«ãªããŸãã
meta(name="viewport", content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no")
ãŸãã ã¢ãã€ã«ã®html5boilerplateã¡ãœããpreventZoomïŒïŒã確èªããå¿ èŠããããŸãã ããã¯å€§ãã«åœ¹ç«ã¡ãŸãã ãšã«ãããããããããããã®ã¯ãŒã«ãªãã®ããšãããšãã§ããŸãã
ç»é¢ã®é«ã/å¹ ã®æ±ºå®ã«åé¡ãããå¯èœæ§ããããŸãã Android / iOSã®åçã«ã¯äžè²«æ§ããããŸããã ç¹ã«ãAndroidã¯äžè¬ã«ãå®éã®2åã®å¹ ãšé«ãããããšèšããŸãã å¯èœãªéãCSSã䜿çšããããšããå§ãããŸãããæ¬åœã«ãããå Žåã¯ã次ã®ããã«ã§ããŸãã
class Size _min_width: 320 _min_height: 416 _iOS_toolbar_height: 44 _android_delay: 300 constructor: -> @width = null @height = null if $.os.ios app.dom.win.on('orientationchange load', @orientationChange) else app.dom.win.on('orientationchange resize load', => window.setTimeout(@orientationChange, @_android_delay) ) @orientationChange() orientationChange: => prevWidth = @width prevHeight = @height if $.os.ios and not window.orientation @width = window.screen.availWidth @height = window.screen.availHeight - @_iOS_toolbar_height else @width = app.dom.win.width() @height = app.dom.win.height() @width = Math.max(@_min_width, @width) @height = Math.max(@_min_height, @height) if @width isnt prevWidth or @height isnt prevHeight app.trigger('size:resize', width: @width height: @height )
ã³ã³ãã³ã/ãŠã£ã³ããŠã®é«ãã®æ±ºå®ãå€ãã®åéºãæåŸ ããŠããã®ç¹ã§ã¢ãã€ã«ãã©ãŠã¶ã¯éåžžã«ã¯ãŒã«ã§ããããã«ã¹ã¯ãªãŒã³ã§äœããããããšã¯æ®éã§ããããªãŒããŒã¬ã€/ã¢ãŒãã«ã§ã¯ç°¡åã§ã¯ãããŸããã
- ç¹ã«é·æéäœãèŠæ±ãããŠããªãå Žåããããã¯ãŒã¯èŠæ±ã¯éåžžã«é
ããªããŸãã ã¯ãšãªã®äžŠååãè¯ãèãã§ã¯ãªããããããŸããããã®ãã¡ã®1ã€ã¯ç°¡åã«å€±æããå¯èœæ§ããããçµå±ã®ãšãããããã¯é«éã§ã¯ãããŸããã ç§ã¯ãçŽ æŽãããçãã§ããã€ãã®ãªã¯ãšã¹ããããããšããŸãã ïŒæ倧ã¯500kb-1mbæ倧ã§ãããã¢ãã€ã«éä¿¡ã®ãŸãŸã§ãïŒã ããŸãããããã§ãã DOMã䜿çšããæäœ-åã話ã ããã€ã¹ãéåžžã«ç©éããªã®ã§ããã¹ãŠãéåžžã«é
ããªããŸãã ç¹ã«Androidã§ã¯ã圌ãã®åé¡ãäœãªã®ãããããŸããã æ°ãã4ã§ããåãiPhone 4Sã倱ããŸãã äžè¬ã«ãéåžžã®ã«ãŒã«ãããã§æ©èœããŸã-ãªã¯ãšã¹ããšã°ã«ãŒãã®æžã蟌ã¿/èªã¿åããå°ãªããªããŸãã
- Android 4ã®ä»¥åã®ããŒãžã§ã³ã¯History APIããµããŒãããŠããŸããã ã€ãŸããBackboneã§ã¯ãéåžžã®ç¶æ
æŽæ°ã®ä»£ããã«ããã·ã¥ã䜿çšããå¿
èŠããããŸãã æ°ããããŒãžã§ã³ã¯ãã§ã«ãã¹ãŠããµããŒãããŠããã¯ãã§ãããAndroid 2ã¯åžžã«ãµããŒãããŠããã®ã§ãæ°ã«ããŸããã§ããã
- ããŒãžãäžã«ã¹ã¯ããŒã«ããŠã³ã³ãã³ããå€æŽãããšãAndroidã¯ã¹ã¯ããŒã«äœçœ®ãå
ã®äœçœ®ã«æ»ããŸããã æ°ããã³ã³ãã³ãã®é«ãã«å¿ããŠãç®ã«èŠããåé¡ãããå ŽåããããŸãã
- ç»é¢ã®ã©ããã«é£ãã§ããpositionïŒabsoluteã®ãããã¯ãããå Žåã¯ãé«ããããã»ã©å€§ãããªãããšã確èªããŠãã ããã ããã§ãªãå ŽåãããŒãžã«ãç©Žãã衚瀺ããããããããããããçšåºŠã®é«ããå ããŠãããã®ããã«èŠããŸãã iOSã®å®éã
- iOSã§å
šç»é¢è¡šç€ºãè¡ãå Žåã¯ãã«ãŒãèŠçŽ ã®1ã€ã®é«ããå®éã®ç»é¢ã®é«ãã«èšå®ããå¿
èŠããããŸãã ããããªããšãã©ããªã«äžçæžåœè©Šã¿ãŠããã¹ããŒã¿ã¹ããŒã¯ã©ãã«ãè¡ããŸããã é«ãïŒ100ïŒ
ãæ£åžžã«æ©èœããŸããã
- 芪ãããã¯ã«ãªãŒããŒãããŒïŒã¹ã¯ããŒã«ãäœçœ®ã®åïŒçµ¶å¯Ÿãããå ŽåãAndroidã§ã®ã¬ã³ããªã³ã°æã«åé¡ãçºçããå¯èœæ§ããããŸãã ãªãŒããŒãããŒãç¡å¹ã«ããããšã«ãã£ãŠã®ã¿è§£æ±ºãããŸãïŒã¹ã¯ããŒã«ã
äžè¬ã«ãéçºã¢ãããŒãã¯ãéåžžã«åŒ±ããã·ã³äžã®å€§èŠæš¡ãµã€ãã§ã®äœæ¥ã«äŒŒãŠããŸãã ããããªãŒãšããã»ããµ/ã¡ã¢ãªã®ãªãœãŒã¹ãéåžžã«éãããŠããããšãå¿ããŠã¯ãªãããå®éã®ããã€ã¹ã®ããã©ãŒãã³ã¹ãåžžã«ç¢ºèªããŠãã ããã ãã¡ãããããã¯ãã¹ãã«äœ¿çšã§ããããã€ã¹ã«åºã¥ããç§ã®å人çãªçµéšã§ãã ç§ã¯ããã€ãã®ç¹ã§ééã£ãŠãããããããŸããã
ãã¹ã¯ãããã®ãã©ãŠã¶ãšã¯ç°ãªããã¢ãã€ã«ã®éçºããŒãã¹ïŒ
- ããã€ã¹ã¯ãã¬ãŒãããããŠããŸããããŸã ææ°ã®ãã®ã§ãããå€ãããµããŒããããŠããŸãã ããã¯ãããŒãã¬ãŒã /ãã©ã³ãžã·ã§ã³ããã³ææ°ã®JavaScriptãªã©ã«ããã¢ãã¡ãŒã·ã§ã³ãæå³ããŸãã
- ãã©ãããã©ãŒã ã¯3ã€ã ãã§ãã iOSã¯åç¬ã§éåžžã«ããŸãæ©èœããŸãããããã°ã«ã¯ãSafariã®éçºè
ããŒã«ã䜿çšããããšããå§ãããŸãã ããã«æªãããšã«ãAndroidã§ãã©ãŠã¶ãã°ãadbã³ã³ãœãŒã«ã«åºåãããã®ã¯ã»ãšãã©ãããŸããããããã§ã2ã€ã®ãã©ãããã©ãŒã ãšåæ§ã®ãã©ãŠã¶ãšã³ãžã³ãããããŸããã å€ãã®ãã³ããŒãã¬ãã£ãã¯ã¹ã«ã€ããŠå¿ããããšãã§ããŸãã
- æ°ããããã¡ãã§éã¶ã®ã¯ãã€ãé¢çœãã§ãã ãŸããã¢ãã€ã«ãµã€ãã¯ãã€ãã£ãã¢ããªãšããŠã©ããããããå°ãªããšãããŒã ã¹ã¯ãªãŒã³ã«è¿œå ã§ããŸãã çŽ æŽãããã
ãããã«
ç§ãã¡ã¯éçºè ã«ãªãããã«çŽ æŽãããæéãéãããŠããŸãã ã¢ã€ãã¢ãé ã«æµ®ãã³ããããç°¡åã«å®è£ ã§ããŸãã æ®ãã®äººã ã¯ã圌ãã«ãšã£ãŠå®çŸã§ããªãã¢ã€ãã¢ã§çããŠããŸãã ãããã£ãŠãã³ãŒããèšè¿°ããŠNodeJSã䜿çšããŠãã ãããè¿ éã䟿å©ãéåæããããŠè¥è ã§ãã ãããŠãæåãå ¥åããã®ã§ã¯ãªããã¢ã€ãã¢ãæãã€ãã®ã«ãã£ãšæéãããããŸãã
GitHubã®ãµã€ãããäœããæçš¿ãããšæããŸããèªåã§ãããèŠãŠäœ¿çšããããšãã§ããŸãã çãããé 匵ã£ãŠãã ããã