Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Stimulus × Jest × Direct Upload × Image Fluxで カ...
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Masayoshi Tokumoto
June 29, 2019
Technology
1
370
Stimulus × Jest × Direct Upload × Image Fluxで カオスなJS環境と画像アップロード機能を改善しつつユーザーの投稿率を上げた話
沖縄で開催されたハッカーズチャンプルー2019でLTをした時の資料です
Masayoshi Tokumoto
June 29, 2019
Tweet
Share
More Decks by Masayoshi Tokumoto
See All by Masayoshi Tokumoto
プロダクト・人・チームをいい感じにするためのシステム思考
sasumasa
0
65
RxJS と Netflix から学ぶリアクティブプログラミング
sasumasa
0
46
GraphQL を完全に理解する
sasumasa
0
43
キャパを超えた大型プロジェクトから学んだこと
sasumasa
0
1.5k
RailsエンジニアがStimulus + 生JSだけで約半年のプロジェクトを終えた今思うこと
sasumasa
0
340
IKUSEI on Rails
sasumasa
2
1.9k
文系から半年でRuby(Sinatra, Rails)を学んだら人生変わった@沖縄Ruby会議02
sasumasa
9
19k
Other Decks in Technology
See All in Technology
複数クラスタ運用と検索の高度化:ビズリーチにおけるElastic活用事例 / ElasticON Tokyo2026
visional_engineering_and_design
0
160
AI時代の「本当の」ハイブリッドクラウド — エージェントが実現した、あの頃の夢
ebibibi
0
120
AI時代のSaaSとETL
shoe116
1
150
Lambda Web AdapterでLambdaをWEBフレームワーク利用する
sahou909
0
130
OSC仙台プレ勉強会 AlmaLinuxとは
koedoyoshida
0
170
Postman v12 で変わる API開発ワークフロー (Postman v12 アップデート) / New API development workflow with Postman v12
yokawasa
0
130
進化するBits AI SREと私と組織
nulabinc
PRO
0
180
非情報系研究者へ送る Transformer入門
rishiyama
11
7.5k
Cortex Code CLI と一緒に進めるAgentic Data Engineering
__allllllllez__
0
280
Claude Codeが爆速進化してプラグイン追従がつらいので半自動化した話 ver.2
rfdnxbro
0
540
Sansanでの認証基盤内製化と移行
sansantech
PRO
0
460
フロントエンド刷新 4年間の軌跡
yotahada3
0
340
Featured
See All Featured
Building the Perfect Custom Keyboard
takai
2
710
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
350
Building a Modern Day E-commerce SEO Strategy
aleyda
45
8.9k
Test your architecture with Archunit
thirion
1
2.2k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
1.9k
Embracing the Ebb and Flow
colly
88
5k
Navigating Weather and Climate Data
rabernat
0
140
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
5.9k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
200
What does AI have to do with Human Rights?
axbom
PRO
1
2k
How Software Deployment tools have changed in the past 20 years
geshan
0
32k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
140
Transcript
Stimulus × Jest × Direct Upload × Image FluxͰ ΧΦεͳJSڥͱը૾ΞοϓϩʔυػೳΛ
վળͭͭ͠ϢʔβʔͷߘΛ্͛ͨ ·͞ʢ@Masah201707ʣ
ࣗݾհ • ·͞ʢ@Masah201707ʣ • גࣜձࣾΈΜͳͷΣσΟϯάʢ18ଔʣ • ͪΐͬͱॻ͚Δ • Ruby/Rails/JavaScript/Stimulus •
͜Ε͔Βͪΐͬͱॻ͚Δ • React/Go • ͓ञͱ͓ण࢘ͱֶͼʹͳΔٕज़ͷ͕͋Ε͍͍ͩͨͤ
ΈΜͳͷΣσΟϯάͱ • ʮ݁ࠗࣜͷຊΛ͑ΔʯͨΊͷαʔϏε • ϝΠϯίϯςϯπʹ݁ࠗࣜʹؔ͢Δޱίϛɾ࣮ࡍͷඅ༻໌ࡉͳͲ͕͋Δ
ͬͨ͜ͱ Ϣʔβʔߘը૾ͷ ΞοϓϩʔυͷΈΛม͑Δ
Γ͍ͨ͜ͱ • jQueryΛ٫͍ͨ͠ʢͻͲ͍ίʔυͷւ͕͕͓ͬͯ Γɺςετͮ͠Β͍ʣ • ϢʔβʔΛ͍ؒͨͤΔ͜ͱͳ͘࠷େ10ຕͷը૾ ΞοϓϩʔυΛ࣮ݱ͍ͤͨ͞ • Ϣʔβʔ͕Ξοϓϩʔυͨ͠ը૾Λ৭ʑͳίϯςϯπ Ͱ͏ͨΊʹ৭ʑͳαΠζʹม͍ͨ͠
Γ͍ͨ͜ͱ • jQueryΛ٫͍ͨ͠ʢͻͲ͍ίʔυͷւ͕͕͓ͬͯ Γɺςετͮ͠Β͍ʣ • ϢʔβʔΛ͍ؒͨͤΔ͜ͱͳ͘࠷େ10ຕͷը૾ ΞοϓϩʔυΛ࣮ݱ͍ͤͨ͞ • Ϣʔβʔ͕Ξοϓϩʔυͨ͠ը૾Λ৭ʑͳίϯςϯπ Ͱ͏ͨΊʹ৭ʑͳαΠζʹม͍ͨ͠
ղܾࡦ Stimulus + Jest
Stimulus • Basecamp͕ࣾग़͍ͯ͠Δʮ߇͑Ίͳ৺ʯΛ࣋ͬͨϑ ϨʔϜϫʔΫ • HTMLͱJavaScriptΛdataଐੑͰܨ͙ • HTMLΛݟΔ͚ͩͰͲͷΑ͏ͳৼΔ͍Λ͢Δͷ͔͕Θ͔Δ • ಉ͡తͷίʔυΛάϧʔϓԽͤ͞ΔͷͰɺࣗͷίʔυ͕
ʮJavaScriptͷւʯʹຒΕΔͷΛ͙ • DOMͷϥΠϑαΠΫϧΛཧ͢Δ
Jest • FacebookJavaScriptςετπʔϧ • Reactͱͷੑߴͦ͏ • ಋೖָ͕ͦ͏ʢZero Configurationʣ • RSpecΈ͍ͨͰॻ͖ํʹ͠Έ͕͋Δ
const sum = require('./sum'); test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); });
Γ͍ͨ͜ͱ • jQueryΛ٫͍ͨ͠ʢͻͲ͍ίʔυͷւ͕͕͓ͬͯ Γɺςετͮ͠Β͍ʣ • ϢʔβʔΛ͍ؒͨͤΔ͜ͱͳ͘࠷େ10ຕͷը૾ ΞοϓϩʔυΛ࣮ݱ͍ͤͨ͞ • Ϣʔβʔ͕Ξοϓϩʔυͨ͠ը૾Λ৭ʑͳίϯςϯπ Ͱ͏ͨΊʹ৭ʑͳαΠζʹม͍ͨ͠
͜Ε·Ͱͷը૾Ξοϓϩʔυ ΦϦδφϧը૾ͱ αϜωΠϧΛΞοϓϩʔυ • αϜωΠϧը૾ͷ࡞ • EXIFใͷमਖ਼ 1ຕͣͭը૾ΛΞοϓϩʔυ Amazon EC2
Amazon S3
S3ͷDirect Upload ॺ໊͖ͭURLΛ dataଐੑͱͯ͠ηοτ ෳͷը૾Λ ඇಉظͰΞοϓϩʔυ access_key_idͱ secret_access_keyΛऔಘ ̍ ̎
̏ Amazon EC2 Amazon S3 IAM
Γ͍ͨ͜ͱ • jQueryΛ٫͍ͨ͠ʢͻͲ͍ίʔυͷւ͕͕͓ͬͯ Γɺςετͮ͠Β͍ʣ • ϢʔβʔΛ͍ؒͨͤΔ͜ͱͳ͘࠷େ10ຕͷը૾ ΞοϓϩʔυΛ࣮ݱ͍ͤͨ͞ • Ϣʔβʔ͕Ξοϓϩʔυͨ͠ը૾Λ৭ʑͳίϯςϯπ Ͱ͏ͨΊʹ৭ʑͳαΠζʹม͍ͨ͠
ैདྷͷߏ • ը૾มͷ͘͠Έ • ϦαΠζɾΫϩοϓɾը࣭ͷௐΩϟογϡػೳΛඋ͑Δ
ैདྷͷߏ • ɿӡ༻͕ൃੜ • ϛυϧΣΞͷߋ৽ΞϥʔτରԠ
S3ͷDirect Upload ॺ໊͖ͭURLΛ dataଐੑͱͯ͠ηοτ ෳͷը૾Λ ඇಉظͰΞοϓϩʔυ access_key_idͱ secret_access_keyΛऔಘ ̍ ̎
̏ Amazon EC2 Amazon S3 IAM &9*'ใΛ मਖ਼͍ͯ͠ͳ͍
ImageFluxͱ ̍ຕͷը૾Λͱʹը૾ͷ֦େॖখɺΓൈ͖ɺ߹ͳͲͰσ όΠεʹ࠷దԽ͞Εͨը૾Λ؆୯ʹੜ͠ɺߴ͔ͭߴ࣭Ͱ ৴͢ΔαʔϏε
ImageFluxར༻ޙͷߏ ը૾ॲཧΛ·ΔͬͱImageFluxʹ͓ͤ͢Δ͜ͱ Ͱը૾पΓͷӡ༻͔Βղ์͞ΕΔ
݁Ռ • ը૾ͷߘ 1.7ഒ • 30595ຕˠ52622ຕ ϦϦʔεޙ4ϲ݄ͷ૯ը૾ߘΛલಉ݄ͱൺֱ • मਖ਼֦ுʹڧ͍ઃܭʹͳͬͨ
ࣦഊஊ
Vanilla JSͷDOMੜ _createThumbnailField(data) { const thumbnailFieldList = document.querySelector(`.js_${this.category}-thumbnail-field-list`) const thumbnailFieldWrapper
= document.createElement('div') thumbnailFieldWrapper.dataset.controller = 'string-counter' thumbnailFieldWrapper.dataset.target = 'thumbnail-field.item' thumbnailFieldWrapper.dataset.stringCounterMax = 20 thumbnailFieldWrapper.className = 'post-pictures-attachments' const thumbnailFieldBackground = document.createElement('div') thumbnailFieldBackground.className = 'os1-container-background' thumbnailFieldBackground.classList.add('-background-color-gold') thumbnailFieldBackground.classList.add('-margin-bottom-M') const hiddenObjectKey = this.createHiddenObjectKey(data.objectKey) const hiddenCategory = this.createHiddenCategory() const hiddenContentType = this.createHiddenContentType('review') this._createReviewThumbnailField({ data, thumbnailFieldBackground, hiddenObjectKey, hiddenContentType, hiddenCategory, }) thumbnailFieldWrapper.appendChild(thumbnailFieldBackground) thumbnailFieldList.appendChild(thumbnailFieldWrapper) }
_createThumbnailField(data) { const thumbnailFieldList = document.querySelector(`.js_${this.category}-thumbnail-field-list`) const thumbnailFieldWrapper = document.createElement('div')
thumbnailFieldWrapper.dataset.controller = 'string-counter' thumbnailFieldWrapper.dataset.target = 'thumbnail-field.item' thumbnailFieldWrapper.dataset.stringCounterMax = 20 thumbnailFieldWrapper.className = 'post-pictures-attachments' const thumbnailFieldBackground = document.createElement('div') thumbnailFieldBackground.className = 'os1-container-background' thumbnailFieldBackground.classList.add('-background-color-gold') thumbnailFieldBackground.classList.add('-margin-bottom-M') const hiddenObjectKey = this.createHiddenObjectKey(data.objectKey) const hiddenCategory = this.createHiddenCategory() const hiddenContentType = this.createHiddenContentType('review') this._createReviewThumbnailField({ data, thumbnailFieldBackground, hiddenObjectKey, hiddenContentType, hiddenCategory, }) thumbnailFieldWrapper.appendChild(thumbnailFieldBackground) thumbnailFieldList.appendChild(thumbnailFieldWrapper) } Vanilla JSͷDOMੜ THIS IS ZIGOKU
ϦΞϧDOMͰԾʢతʣDOM 1. ςϯϓϨʔτΛViewϑΝΠϧʹஔ͍͓ͯ͘ 2. MutationObserverͰಛఆͷHTMLཁૉΛࢹ 3. ը૾ΞοϓϩʔυޙʹඞཁͳใΛͦͷHTMLཁૉͷ attributesͱͯ͠ηοτ 4. MutationObserver͕Ԡ͠ɺςϯϓϨʔτͷCloneʹͦ
ΕͧΕͷΛೖΕͨͷΛAppend
ՆͷΠϯλʔϯγοϓ ։࠵͠·͢ʂ
ΈΜͳͷΣσΟϯά ՆͷΠϯλʔϯ in ԭೄ ࣌ɿ8݄22ɾ23ʢ༧ఆʣ ձɿླྀٿେֶֶ෦ ࣮ࡍͷαʔϏεʹػೳΛՃͯ͠ RubyͱRailsͷجຊΛֶ΅͏ʂ ৄ͘͠connpass (https://mwed.connpass.com/)
Ͱ 21ଔ͚
͋Γ͕ͱ͏͍͟͝·ͨ͠