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
Electronによるアプリケーション開発事情2018 / builderscon2018
Search
h3poteto
September 07, 2018
Technology
9
9.9k
Electronによるアプリケーション開発事情2018 / builderscon2018
builderscon tokyo 2018『Electronによるアプリケーション開発事情2018』
h3poteto
September 07, 2018
Tweet
Share
More Decks by h3poteto
See All by h3poteto
EKS on Fargateは最高のJob基盤 / jawsug_bgnr
h3poteto
1
980
Kubernetes上で単発のジョブを実行するkube-jobというツールを作った / kubernetesmeetuptokyo22
h3poteto
6
8.2k
fluentdサーバをchefで構築するの辛かったけどDockerも別に救世主じゃなかった / tokyu ruby kaigi 12
h3poteto
0
4.6k
ECSのサービスをslack botでデプロイする // ecs-goploy
h3poteto
1
5.3k
まだRailsで消耗してるの?
h3poteto
7
4.8k
阿澄佳奈と昇竜拳
h3poteto
1
510
Other Decks in Technology
See All in Technology
生成AI活用の組織格差を解消する 〜ビジネス職のCursor導入が開発効率に与えた好循環〜 / Closing the Organizational Gap in AI Adoption
upamune
7
5.2k
OPENLOGI Company Profile
hr01
0
67k
KubeCon + CloudNativeCon Japan 2025 Recap
ren510dev
1
380
React開発にStorybookとCopilotを導入して、爆速でUIを編集・確認する方法
yu_kod
1
270
Backlog ユーザー棚卸しRTA、多分これが一番早いと思います
__allllllllez__
1
150
自律的なスケーリング手法FASTにおけるVPoEとしてのアカウンタビリティ / dev-productivity-con-2025
yoshikiiida
1
17k
ネットワーク保護はどう変わるのか?re:Inforce 2025最新アップデート解説
tokushun
0
210
AI専用のリンターを作る #yumemi_patch
bengo4com
5
4.3k
Delta airlines®️ USA Contact Numbers: Complete 2025 Support Guide
airtravelguide
0
340
2025 AWS Jr. Championが振り返るAWS Summit
kazukiadachi
0
110
ビズリーチが挑む メトリクスを活用した技術的負債の解消 / dev-productivity-con2025
visional_engineering_and_design
3
7.6k
いつの間にか入れ替わってる!?新しいAWS Security Hubとは?
cmusudakeisuke
0
120
Featured
See All Featured
Faster Mobile Websites
deanohume
307
31k
Embracing the Ebb and Flow
colly
86
4.7k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
60k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
34
3.1k
Designing for humans not robots
tammielis
253
25k
Agile that works and the tools we love
rasmusluckow
329
21k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
229
22k
Why You Should Never Use an ORM
jnunemaker
PRO
58
9.4k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
18
970
Facilitating Awesome Meetings
lara
54
6.4k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
6
300
Thoughts on Productivity
jonyablonski
69
4.7k
Transcript
ElectronʹΑΔΞϓϦ έʔγϣϯ։ൃࣄ 2018 builderscon tokyo 2018 @h3_poteto
ࣗݾհ • Akira Fukushimaʢౡ ໌ʣ • github: h3poteto • twitter:
h3_poteto • Mastodon: @
[email protected]
• ࣄɿterraform৬ਓ@scouty
એ
None
σεΫτοϓ͚ͷ MastodonΫϥΠΞϯτΛ ࡞͍ͬͯ·͢
None
ࠓ͜ͷΞϓϦέʔγϣ ϯΛࡐʹElectronͷΛ ͠·͢
None
એऴΘΓ
ࠓͷ • ElectronͰΞϓϦέʔγϣϯ࡞ΔͷϚδͰָ ͩΑʢͲΜͲΜָʹͳΓͭͭ͋Δ • ͰSNSͷΫϥΠΞϯτ࡞Δͷେม • ւ֎͔Βͷҙ֎ͳԠ͋ͬͨ • ΈΜͳMastodonͬͯ΄͍͠
ElectronͰΞϓϦέʔγϣϯ Λ։ൃ͢Δ
Electron? • ੲAtom-shellͱݺΕ͍ͯͨ • Chromium + Node.js • Windows/Mac/Linux͚ͷΞϓϦέʔγϣϯ ͕࡞ΕΔ
ͭ·Γ • දࣔ෦ϒϥβͳͷͰWebϑϩϯτΤϯ υͷٕज़Λ͑Δ • React.js/Vue.jsࡌͤΒΕΔ • SPAͰΞϓϦ͕࡞ΕΔ
vue-cliͰܗ͕࡞ΕΔ $ npm install -g vue-cli $ vue init simulatedgreg/electron-vue
\ whalebird
vue-cliͰͷܗ • webpackʹΑΔ։ൃ࣌ͷϏϧυઃఆ • auto-reload • ςετͷܗ
Electronͷجຊߏ • mainϓϩηε: όοΫάϥϯυδϣϒɼΞϓ ϦέʔγϣϯͷཧΛߦ͏ • rendererϓϩηε: jsΛ࣮ߦ͠html, cssΛϨϯ μϦϯά͢Δ
rendererϓϩηεଆΛͯ͢ SPAʹ͢Δ͜ͱ͕Մೳ ͜͜ͰReact.js/Vue.js͕͑ Δ
خ͍͜͠ͱᶃ React.js/Vue.js(Flux)ΛGUI ΞϓϦέʔγϣϯͰ͑Δ
iOS։ൃ͍ͯͨ͜͠Ζ • ViewController͕ແݶʹଠΔʂ • delegate͕ͦ͜Βதʹ…… • ϞσϧͲ͏͜͏ͱ͍͏ΑΓঢ়ଶը໘ભҠͷ ϩδοΫ͕େม
None
class SwipeViewController: UIViewController, SwipeViewDelegate, SwipeViewDataSource, UINavigationControllerDelegate, UITabBarControllerDelegate { func navigationController(_
navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { if (type(of: viewController) === SwipeViewController.self) { for i in 0 ..< self.streamList.count() { self.viewItems[i].fCellSelect = false } } } } ͛͢ʔ͍ͬͺ͍Delegateͯ͠Δ
React.js/Vue.sj(Flux)ʹ͢Δͱ • ࠩϨϯμϦϯάReact.js/Vue.jsͷ͕ͬ ͯ͘ΕΔ͜ͱ͕લఏ • delegateͱ͔ඞཁͳ͍ • Flux͕σʔλͷྲྀΕΛҰํʹͯ͘͠ΕΔ • GUIΞϓϦέʔγϣϯͳͷʹݟ௨͕͠ྑ͍
<toot :message="message" :filter="filter" :focused="message.uri === focusedId" :overlaid="modalOpened" @update=“updateToot" @delete=“deleteToot" @focusNext="focusNext"
@focusPrev="focusPrev" @selectToot="focusToot(message)"> </toot> focusToot (message) { this.focusedId = message.uri }
خ͍͜͠ͱᶄ ίϯτϦϏϡʔλ͕૿͑Δ
WhalebirdͷίϯτϦϏϡʔλ • ΄΅jsͷٕज़ͳͷͰjsք۾ͷਓ͕ίϯτϦ Ϗϡʔτ͍͢͠ʢ͜͜ͷϘϦϡʔϜ͕ଟ͍
خ͍͜͠ͱᶅ ΫϩεϓϥοτϑΥʔϜ
ΫϩεϓϥοτϑΥʔϜ • Windows/Mac/LinuxͰಉ͡ιʔεͷ··Ϗϧ υՄೳ • ͨͩ͠Ұ෦Mac͚ͷػೳ࣮͞Ε͍ͯ Δ
ྫ: Dockϝχϡʔ ϝχϡʔ༰͕ ΧελϚΠζՄೳ elecron-context-menu
خ͍͜͠ͱᶆ ΞΫςΟϒʹ։ൃ͞Ε͍ͯΔ
ElectronͷϦϦʔεׂͱ׆ൃ • v2.0.8 - 2018/08/23 • v2.0.7 - 2018/08/09 •
v2.0.6 - 2018/08/01 3.0.0४උத: v3.0.0-beta.8
ΞϓϦέʔγϣϯΛύοέʔ δϯάˍϦϦʔε
Let’s ElectronΈ͍ͨͳهࣄ ͍ͬͺ͍͋Δ͚ͲϦϦʔεʹ ؔ͢Δهࣄ͕΄ͱΜͲͳ͍
֮͑ͯ΄͍͜͠ͱ: electron-builder͕͋Εͩ ͍͍ͨղܾ͢Δ
• electron-packager • electron-builder ͱ͍͏ͷ͕͋Δ
electron-packager • webpackͰίϯύΠϧ͞ΕͨϑΝΠϧ܈ΛΞ ϓϦέʔγϣϯͱͯ͠·ͱΊΔ • جຊతʹ͜Ε͔ͬͯ͘͠Εͳ͍ • ίϚϯυϥΠϯ
electron-builder • ΞϓϦέʔγϣϯͷύοέʔδϯά • ূ໌ॻͷՃ • ֤छΠϯετʔϧՄೳͳϑΝΠϧܗࣜʹѹॖ ʢ.dmg, .deb, .rpm,
.exeʣ • package.jsonʹઃఆ͕ॻ͚Δ • ެࣜυΩϡϝϯτ͕๛: https://www.electron.build/
"build": { "productName": "Whalebird", "appId": "org.whalebird.desktop", "directories": { "output": "build"
}, "mac": { "icon": "build/icons/icon.icns", "target": [ "dmg" ], "category": "public.app-category.social-networking" },
͓͔͛ͰϦϦʔεܗ͕ࣜ๛ • AppStore(.pkg) • .dmg • .exe • .deb •
.rpm • .tar.bz2 • snapcraft (.snap)
ͪΐͬͱಛघͳઃఆྫ • ΞΠίϯ • ֎෦ϦιʔεʢԻʣ • ূ໌ॻ • MASʢMac App
Storeʣ
ΞΠίϯ • Mac/Windows: Ϗϧυ࣌ʹຒΊࠐΉ • Linux: Ұ෦main.jsͰ֎෦ϑΝΠϧΛࢦఆ • ը૾ϑΝΠϧasarѹॖ͞Ε͍ͯͯ෦ͷ ͷΛࢦఆՄೳ
"build": { "productName": “Whalebird", "files": [ "dist/electron/**/*", "build/icons/*" ], "mac":
{ "icon": "build/icons/icon.icns", "target": [ "dmg" ], "category": "public.app-category.social-networking" }, "win": { "icon": "build/icons/icon.ico", "target": "nsis" }, iconͷࢦఆ
mainWindow = new BrowserWindow({ titleBarStyle: 'hidden', useContentSize: true, icon: path.resolve(__dirname,
'../../build/icons/256x256.png') } BrowserWindowͷ ىಈΦϓγϣϯͰΞΠίϯΛࢦఆ
֎෦ϦιʔεͷಡΈࠐΈ • ԻϑΝΠϧΛಡΈࠐΈ͍ͨ߹͕͋Δ • asarѹॖͷϑΝΠϧಡΈऔΕͳ͍ • ϏϧυઃఆͰasarѹॖ͔Βআ֎͢Δඞཁ͕͋ Δ
"build": { "productName": "Whalebird", "appId": "org.whalebird.desktop", "directories": { "output": "build"
}, "extraResources": [ "build/sounds/*" ], "files": [ "dist/electron/**/*", "build/icons/*" ], ԻΛextraResources ʹࢦఆ
const soundBasePath = process.env.NODE_ENV === 'development' ? path.join(__dirname, '../../build/sounds/') :
path.join(process.resourcesPath, 'build/sounds/') const sound = path.join(soundBasePath, 'operation_sound01.wav') simplayer(sound, (err) => { if (err) log.error(err) }) ͜͜asar֎ͷϑΝΠϧΛ ࢦఆ͢Δඞཁ͕͋Δ
Mac༻ͷূ໌ॻ • Developer ID Installer • Developer ID Application electron-builderͳΒϏϧυ࣌ʹ
KeyChainAccessͷূ໌ॻΛ ࣗಈͰͯͯ͘ΕΔ
MAS͚ͩಛผѻ͍ • electron-builderͰCodeSign·ͰͰ͖ͳ͔ͬͨ • electron-packagerͰϏϧυޙɼࣗͰCodeSign • plistΛࣗͰॻ͘ඞཁ͕͋Δ • ͦΕΛApplication LoaderͰΞοϓϩʔυ͢Δ
• ͋ͱiTunes ConnectͰόʔδϣϯΞοϓ
#!/bin/zsh -f # Name of your app. APP="Whalebird" # The
path of your app to sign. APP_PATH="./packages/Whalebird-mas-x64/Whalebird.app" # The path to the location you want to put the signed package. RESULT_PATH="./packages/$APP.pkg" # The name of certificates you requested. APP_KEY="3rd Party Mac Developer Application: Akira Fukushima (HB4N6B2YVM)" INSTALLER_KEY="3rd Party Mac Developer Installer: Akira Fukushima (HB4N6B2YVM)" # The path of your plist files. CHILD_PLIST="./plist/child.plist" PARENT_PLIST="./plist/parent.plist" LOGINHELPER_PLIST="./plist/loginhelper.plist" FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks" # At first, rename app.asar.unpacked directory. # Because electron-builder does not store app.asar.unpacked directory. # I want to store unpacked files at the same directory as electron-builder. mv $APP_PATH/Contents/Resources/app.asar.unpacked/* $APP_PATH/Contents/Resources/ codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/ Electron Framework" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/ Libraries/libffmpeg.dylib" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/ Libraries/libnode.dylib" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/Contents/MacOS/$APP Helper" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper EH.app/Contents/MacOS/$APP Helper EH" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper EH.app/" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper NP.app/Contents/MacOS/$APP Helper NP" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper NP.app/" codesign -s "$APP_KEY" -f --entitlements "$LOGINHELPER_PLIST" "$APP_PATH/Contents/Library/LoginItems/$APP Login Helper.app/Contents/MacOS/$APP Login Helper" codesign -s "$APP_KEY" -f --entitlements "$LOGINHELPER_PLIST" "$APP_PATH/Contents/Library/LoginItems/$APP Login Helper.app/" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$APP_PATH/Contents/MacOS/$APP" codesign -s "$APP_KEY" -f --entitlements "$PARENT_PLIST" "$APP_PATH" productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH"
#!/bin/zsh -f # Name of your app. APP="Whalebird" # The
path of your app to sign. APP_PATH="./packages/Whalebird-mas-x64/Whalebird.app" # The path to the location you want to put the signed package. RESULT_PATH="./packages/$APP.pkg" # The name of certificates you requested. APP_KEY="3rd Party Mac Developer Application: Akira Fukushima (HB4N6B2YVM)" INSTALLER_KEY="3rd Party Mac Developer Installer: Akira Fukushima (HB4N6B2YVM)" # The path of your plist files. CHILD_PLIST="./plist/child.plist" PARENT_PLIST="./plist/parent.plist" LOGINHELPER_PLIST="./plist/loginhelper.plist" FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks" # At first, rename app.asar.unpacked directory. # Because electron-builder does not store app.asar.unpacked directory. # I want to store unpacked files at the same directory as electron-builder. mv $APP_PATH/Contents/Resources/app.asar.unpacked/* $APP_PATH/Contents/Resources/ codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/ Electron Framework" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/ Libraries/libffmpeg.dylib" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/ Libraries/libnode.dylib" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/Contents/MacOS/$APP Helper" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper EH.app/Contents/MacOS/$APP Helper EH" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper EH.app/" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper NP.app/Contents/MacOS/$APP Helper NP" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper NP.app/" codesign -s "$APP_KEY" -f --entitlements "$LOGINHELPER_PLIST" "$APP_PATH/Contents/Library/LoginItems/$APP Login Helper.app/Contents/MacOS/$APP Login Helper" codesign -s "$APP_KEY" -f --entitlements "$LOGINHELPER_PLIST" "$APP_PATH/Contents/Library/LoginItems/$APP Login Helper.app/" codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$APP_PATH/Contents/MacOS/$APP" codesign -s "$APP_KEY" -f --entitlements "$PARENT_PLIST" "$APP_PATH" productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH" codesignίϚϯυΛ͑ྑ͍
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://
www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.security.app-sandbox</key> <true/> <key>com.apple.security.application-groups</key> <string>HB4N6B2YVM.org.whalebird.desktop</string> <key>com.apple.security.files.user-selected.read-only</key> <true/> <key>com.apple.security.network.client</key> <true/> </dict> </plist>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://
www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.security.app-sandbox</key> <true/> <key>com.apple.security.application-groups</key> <string>HB4N6B2YVM.org.whalebird.desktop</string> <key>com.apple.security.files.user-selected.read-only</key> <true/> <key>com.apple.security.network.client</key> <true/> </dict> </plist> ͜͜Ͱ • ωοτϫʔΫΞΫηε • ϑΝΠϧΞΫηε ΛڐՄ͢Δ
͜ͷ͋ͱ৹͕ࠪ͋Δʂ
MAS݁ߏͭΒ͍
͜͜·Ͱͷ·ͱΊ • electron-builderϚδΜΓ • electron-builderͷਐา͕͍ͷͰ͜Εͬͱ ͚ؒҧ͍ͳ͍ • MAS͍ͭେม
MastodonͷΫϥΠΞϯτΛ ࡞Δ
ͳͥMastodonͷ ΫϥΠΞϯτΛ࡞Δͷ͔
σεΫτοϓ͚ͷ ΫϥΠΞϯτ͕ͳ͍ɼຊʹগͳ͍ • MstdnʢࣗͰjsonϑΝΠϧΛ༻ҙͯ͠token ΛೖΕΔʣ • The Desk • TsuruʢόΠφϦͷͳ͍ʣ
ͳ͍ͷͰ͋Ε ࣗͰͭ͘Ζ͏
Whalebirdͷίϯηϓτ • LinuxͰ͑ΔͷΛ • Slackʹ׳Ε͍ͯΔͷͰSlackΆ͍ݟͨ • γϣʔτΧοτͱʹ͔͘ଟ͘ ࠷ڧͷTwitterΫϥΠΞϯτ ઓ૪Λࢥ͍ग़͢
ॳ൛͕Ͱ͖ͨ
ւ֎͔ΒͷԠ
ʢӳޠαϙʔτ͔ͨ͠Β͔ʣ ࠷ॳւ֎͔ΒԠ͕
ϦϦʔεͯ͠࠷ॳͷҰिؒ
None
None
None
None
ྑ͍ʂ͚ͩͲElectron͔…… Έ͍ͨͳԠ͔Γ
ͦΜͳʹElectronͬͯධѱ ͍ͷʁ ຊͰ͋·Γฉ͔ͳ͔͚ͬͨͬͲ
ධͷѱ͞ • ϝϞϦফඅ͕ଟ͍ • SlackΛىಈ͢Δ͚ͩͰ500MBҎ্ϝϞϦΛ͍͔࣋ͬͯ ΕΔ • ࠷దԽ͞Εͯͳ͍ͷͰϝϞϦফඅ͕ଟ͍ • Javaͷํ͕͍ܰ
• node.js͕ݏ͍
ϝϞϦͱઓ͏
࠷ظ1GBҎ্ ͍͔࣋ͬͯΕͨ
Ͳ͜ͰϝϞϦΛ ফඅ͍ͯ͠Δͷ͔ʁ
ࢼͯ͠ΈΔ • StreamingΛࢭΊͨঢ়ଶͰ͍Ζ͍Ζ৮ͬͯΈΔ • StreamingΛࢭΊͨঢ়ଶͰ์ஔ ϝϞϦϦʔΫ͔ʁ
StreamingࢭΊ͍ͯΔͱ૿͑ ͳ͍ʂ ผʹϝϞϦϦʔΫ͍ͯ͠ΔΘ ͚Ͱͳ͍ʂ
StreamingʹΑΔϝϞϦফඅ • ຊΛ૿ͯ͠ΈΔʁ
StreamingʹΑΔϝϞϦফඅ • όοΫάϥϯυͰStreaming͢Δ͚ͩͰର ͯ͠ϝϞϦΛফඅ͠ͳ͍ʂ
͏গ͠ࢼ͢ • ྲྀͷ͍ΠϯελϯεͰ์ஔʢmikutterʣ • ྲྀͷ͍ΠϯελϯεͰ์ஔʢjpʣ
໌Β͔ʹྲྀ͕͍΄͏͕ ϝϞϦফඅ͕ଟ͍
͜Ε͠ϨϯμϦϯά ͳͷͰʁ
WhalebirdͷλΠϜϥΠϯඳը • Streaming͞ΕͨͷΛͯ͢htmlͱͯ͠දࣔ ͍ͯͨ͠ • ͭ·Γϒϥβͷ࣮ʹؙ͛ • FireFoxͰڊେϖʔδΛ։͍ͨΒॏ͍ ʢ͔ͩΒΈΜͳϖʔδωʔγϣϯ͢ΔΜͩ
None
ଞͲ͏͍ͯ͠Δͷ͔ʁ
iOSͷ߹ • UITableViewදࣔ͞Ε͍ͯΔ෦͔͠Ϩϯμ Ϧϯά͍ͯ͠ͳ͍ • ӅΕ͍ͯΔ·ͰؚΊͨεΫϩʔϧྔܭࢉ ͍ͯ͠Δ • εΫϩʔϧ͞Εͨࡍදࣔ͢Δલʹ༰Λ ϨϯμϦϯά
ਤ
දࣔ͞Ε͍ͯͳ͍෦ ϨϯμϦϯά͍ͯ͠ͳ͍
UITableViewController • cellForRowAt: ηϧͷதΛϨϯμϦϯά • heightForRowAt: ηϧͷߴ͞Λࢉग़ • estimatedHeightForRowAt: ະදࣔΛؚΊͯ
ηϧͷߴ͞Λࢉग़
ྲྀੴʹ͜ΕύΫΕͳ͍
ϙΠϯτɿ ඳը͢Δൣғݟ͍͑ͯΔ ෦͘Β͍Ͱे
ElectronͰͲ͏͢Δ͔ʁ • λΠϜϥΠϯΛͯ͢දࣔ͢ΔͷΛΊΔ • ࠷৽40݅ͷΈΛදࣔ͠ɼඞཁͰ͋Ε LazyLoading • StreamingͰߋ৽͞Εͨ߹ɼݹ͍ͷΛফ ͯ͠40݅ʹอͭ
None
εΫϩʔϧΠϕϯτΛͱʹ੍ޚͯ͠Δ
200MBΛΔʂ
ѹత͡Όͳ͍͔ʂ
ϙΠϯτɿ Vue.jsͷύϑΥʔϚϯεʹ ؾΛΔ
vue.jsͷύϑΥʔϚϯε • v-ifͱv-show • v-if: ସ࣌ʹhtml͕ੜ͞ΕϨϯμϦϯά͞ ΕΔ • v-show: ͡Ί͔ΒϨϯμϦϯά͞Ε͍ͯΔ
͕ɼdisplay: none͞Ε͍ͯΔ͚ͩ
v-ifͱv-show • v-ifͷସ࣌ϨϯμϦϯάίετഅࣛʹͳΒ ͳ͍ • ͔͠͠ɼඞཁͷͳ͍ͱ͜ΖΛv-showʹ͢Δͱ ͣͬͱϝϞϦΛফඅ͠ଓ͚Δ
͜͜ਖ਼ղ͕ͳ͍
࠷ۙͷWhalebird • ϝϞϦফඅ: 200MB ~ 500MB • 500MB͘Β͍·Ͱ͘ΔͱGC͞ΕͯϝϞϦফඅ ͕ҰؾʹݮΔ •
ը૾͕গͳ͍࣌ؒଳ͍ܰʂ ʢpawooͷਓ͝ΊΜͳ͍͞
࠷ۙͷWhalebird • ϕʔεʹͳ͍ͬͯΔElectronΛόʔδϣϯΞο ϓ͢ΔͱϝϞϦফඅ͕ݮΔ • ύϑΥʔϚϯεChromiumʹ߹ΘͤͯͲΜͲ Μྑ͘ͳΔ
͜ͷઌͷ࡞ઓ • ը૾ͷඇදࣔΦϓγϣϯ • τΡʔτ͕࿈ଓ͢Δ߹·ͱΊͯϨϯμϦ ϯάͰ͖ͳ͍͔ʁ
͓ӄ༷Ͱ࠷ۙͷԠྑ͍
APIΫϥΠΞϯτϥΠϒϥϦ Λࣗ࡞͢Δ
ॳmastodon-apiͱ͍͏ Node.jsͷϥΠϒϥϦΛར༻
͕ɼΤϥʔʹͳΔͱ͍͏ใࠂ ͕ͪΒ΄Β
mastodon-api • POSTύϥϝʔλΛbodyͰͳ͘urlύϥϝʔ λͱͯ͠ૹ৴͍ͯ͠Δ • Ұ෦αʔόͰͦΕΒ͕ڋ൱͞Ε͍ͯΔ ଞͷબࢶ͕ͳ͍
ͳ͍ͷͳΒࣗ࡞͠Α͏
None
megalodon • TypeScriptͰॻ͍ͨmastodonAPIΫϥΠΞϯ τϥΠϒϥϦ • Streaming࣮ࡁΈ • OAuthΞϓϦέʔγϣϯొ༻ϝιου༻ ҙ
public get<T>(path: string, params = {}): Promise<Response<T>> { return axios
.get<T>(this.baseUrl + path, { headers: { 'Authorization': `Bearer ${this.accessToken}` }, params }) .then((resp: AxiosResponse<T>) => { const res: Response<T> = { data: resp.data, status: resp.status, statusText: resp.statusText, headers: resp.headers } return res }) }
όάͬͯͨ߹ શ෦ࣗͰ࣏ͤΔ
ΠϯελϯεΛ ݐͯΔ͜ͱ͋Δ
ΠϯελϯεݪҼͷ͍߹Θͤ ଟ͍ • ϩάΠϯ͕Ͱ͖ͳ͍ • τΡʔτͰ͖ͳ͍ • Streaming͕ಈ͔ͳ͍ • ʑ……
࠷ۙ͋ͬͨ൵͍͠ࣄྫ • (mastodon͕͍ͬͯΔ)doorkeeper 4.3.0Ҏ ্ Ͱnative_redirect_uriʹؔ͢Δόά͕ࠞೖ • mastodon: doorkeeper ~>
4.4.1 • σεΫτοϓΞϓϦέʔγϣϯͰೝূ͕Ͱ͖ ͳ͘ͳΔ
͔֬ΊΔ&ϓϧϦΫΛग़͢ • खݩͰmastodonαʔόΛݐͯΔ: https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/ Development-guide.md • ࠶ݱͨ͠ • doorkeeperʹissueཱͯͨΓɼmastodonʹϓ
ϧϦΫΛૹͬͨΓ
None
ΫϥΠΞϯτ͚ͩͷͰͳ͍͜ͱ͕ଟ͍ͷͰɼ αΫοͱΠϯελϯεΛཱͯΒΕΔΑ͏ʹ ͓ͯ͘͠ͷॏཁ
·ͱΊ
ޭͨ͠ͳʔͱࢥ͏͜ͱ • ElectronͰ࡞ͬͨ͜ͱ • Vue.jsͱ͍͏બ • ӳޠݍͷྀ
ࣦഊͨ͠ͳʔͱࢥ͏͜ͱ • ͬͱૣ͘࡞ΕΑ͔ͬͨ • ͬͱૣ͘TypeScriptΛߟྀ͖ͩͬͨ͢ • megalodon(APIΫϥΠΞϯτ)ϝϯς͠ ͍͢ • దͳΦϒδΣΫτΛ͢͜ͱ͕ଟ͍
updateTimeFormat ({ dispatch, commit, state }, value) { const newGeneral
= Object.assign({}, state.general, { timeFormat: value }) const config = { general: newGeneral } ipcRenderer.send('update-preferences', config) ipcRenderer.once('error-update-preferences', (event, err) => { ipcRenderer.removeAllListeners('response-update-preferences') }) ipcRenderer.once('response-update-preferences', (event, conf) => { ipcRenderer.removeAllListeners('error-update-preferences') dispatch('App/loadPreferences', null, { root: true }) commit('updateGeneral', conf.general) }) }, actionͻͱ͔ͭ͠ҾΛऔΕͳ͍ mainͱͷ௨৴ipcͰߦ͏ ະͷΦϒδΣΫτ
શମతʹݟͯ • ElectronʢϦϦʔεํ๏ؚΊͯʣਐԽͯ͠ ͍ΔͷͰ͓͢͢Ί͍ͨ͠ • ϝϞϦফඅରࡦՄೳ • Vue.jsͰGUIΞϓϦέʔγϣϯ։ൃ͢Δͷྑ ͍
Mastodon͕ շదʹͳͬͨͷͰ TwitterΛݟΔ͜ͱ͕ݮͬͨ
͞Α͏ͳΒTwitter ΫϥΠΞϯτ