Goはじめた
先日、「みんなのGo言語」を購入。
買った。 pic.twitter.com/AuT3kryGmy
— りしあ (@lisia__) August 3, 2019
このお盆休みの9連休でやってやろうと思ってやり始めてます。
進めていくと、まずは「A Tour of Go」をやろうとのことなので、ちょっとずつ進めていきました。
一通り最後まで進めたはいいものの、まだまだ理解は追いついていません。
まだ慣れていないからっていうのもあるし、書いているうちに慣れるでしょう・・・。
それはそうと、Tour of GoのExercise難しくないですか?
僕のレベルが低いだけ?
解けたの2問しかない。
最初のforのやつと、mapのやつ。
forのやつも差がうんぬんの意味がわからなくてできてないし、
できそうだったフィボナッチもできなかった。
問題読んでも何をしたらいいのかサッパリで、自分のレベルの低さに嫌気がさしました。
こういった問題が解けないんだなと、改めて苦手を意識。
trackとかの問題も解くのが苦手で、同じ感じですね。
AtCoderなんかも同じ感じ。
これも数こなして慣れるしかないんでしょうか。
まぁ、さすがに克服したいので、少しずつやっていきたいと思います。
Tour of GoのExercise、自力で解きたいなぁ・・・。
VuexのcreateNamespacedHelpers、同名どうするよ
昨日書いた「VuexのcreateNamespacedHelpersでdispatchの記述を短くしたい」なんですが。
一つ考慮が漏れてました。
namespace
があることで同じ名前のアクション名でも問題なかったのが、あれをやると死にますね。
(よくよく考えたら当たり前)
例えば、それぞれのモジュールでステートを初期化するアクションがあるとすると・・・
// foo/types.js export const namespace = 'foo' export const RESET = 'RESET' // hoge/types.js export const namespace = 'hoge' export const RESET = 'RESET'
import * as fooTypes from '@/store/modules/Foo/types' import * as hogeTypes from '@/store/modules/Hoge/types' import { createNamespacedHelpers } from 'vuex' const { mapActions: mapActionsOfFoo } = createNamespacedHelpers(fooTypes.namespace) const { mapActions: mapActionsOfHoge } = createNamespacedHelpers(hogeTypes.namespace) // ... methods: { ...mapActionsOfFoo([fooTypes.RESET]), ...mapActionsOfHoge([hogeTypes.RESET]) }
この場合、同じRESET
がマッピングされてしまうので、結果的にはHoge
側がマッピングされてしまいます。
防ぐには、
FOO_RESET
とかHOGE_RESET
とか分けた名前にする(namespaceの意味とは)mapActions({ FOO_RESET: fooTypes.RESET })
みたいにマップするときに名前を変える
かなと思いますが、namespace
で得たものを自ら捨てている感じがして、なんとも言えない感じに。
記述量は減らせますが、一長一短ですね。
うーん・・・。
VuexのcreateNamespacedHelpersでdispatchの記述を短くしたい
初めてVuexを触ったとき、とくにnamespaceも使わずやってました。
ちなみにmapActions
は使わず、this.$store.dispatch
でしたい派。
this.$store.dispatch
の方がdispatch
してるわー!今dispatchしてるわー感があるので好き。
というのは嘘で、コード見たときに、「アクション叩いてる」っていう部分が、ぱっと見分かりやすかったってのがあります。
問題
namespaced: true
にしてみると、namespace + actionName
と書く必要がでてきます。
methods: { handleClickBefore(e) { this.$store.dispatch('actionName', payload) }, handleClickAfter(e) { this.$store.dispatch('namespace/actionName', payload) } }
こう見てみると、「そんな嫌か?」ってレベルに見えるんです。
typesを分ける
実際開発しだすと、直接文字列で指定することは少なくて、types.js
みたいなのをつくって、中にconst
でミューテーションとかアクション名を書いていきます。
export const namespace = 'File/' export const SET_FILE_LIST = 'SET_FILE_LIST' export const FETCH_FILE_LIST = ' FETCH_FILE_LIST'
こうすると、dispatchの部分は
import * as fileTypes from '@/store/modules/File/types' // ... methods: { handleClick(e) { this.$dispatch(fileTypes.namespace + fileTypes.FETCH_FILE_LIST) } }
このレベルだとまだマシですが、中にはPREFIXがついて長くなるアクション名がでてきます。
this.$dispatch(fooTypes.namespace + fooTypes.PREFIX_PREFIX_ACTION_NAME_FOR_XXX)
ここまでなると、さすがにdispatch
が良いとは言い辛い状況になってきました。
解決
createNamespacedHelpers
というのがVuexに用意されていることを知りました。
Vuex/modules
import { createNamespacedHelpers } from 'vuex' import * as fileTypes from '@/store/modules/file/types' const { mapActions: mapActionsOfFile } = createNamespacedHelpers(fileTypes.namspace) //... methods: { ...mapActionsOfFile([fileTypes.FETCH_FILE_LIST]), handleClick(e) { this[fileTypes.FETCH_FILE_LIST]() } }
結局mapActions
に屈したわけですが、思っていたほど見辛いこともなく、楽に書けるので良いかなといった具合です。
(Vuex噛んでいるところはthis[types.XXXX]
ってなるので、他とか区別できているので)
その他も
mapState
やmapGetteres
でmapState(namespace, [xxxx])
としていたのも同じく解決です。
また、複数のモジュールを使うときも明確になりますね。
import * as fileTypes from '@/store/modules/File/types' import * as userTypes from '@/store/modules/User/types' const { mapState: mapStateOfFile, mapGetters: mapGettersOfFile } = createNamespacedHelpers(fileTypes.namesace) const { mapState: mapStateOfUser, mapGetters: mapGettersOfUser } = createNamespacedHelpers(userTypes.namesace) //... computed: { ...mapStateOfFile(['fileList']), ...mapStateOfUser(['userList']), ...mapGettersOfFile(['imageList', 'pdfList']) }
みたいな具合で。
一つのモジュールしか使わないなら、import * as types from '@/store/modules/xxxx'
でいいんですけどね。
参考記事
vscodevimでやってる設定
VSCode使い始めて1年ほど。
結局Vimから乗り換えたというか、両方使ってる感じではあります。
というのも、このissueにあるように、行数が多いとかなりパフォーマンスが落ちてしまって、まともにコード書けなくなるんですよね・・・。
VSCodeVIM is unusable (incredibly slow) on larger files, especially in INSERT MODE #2216
そんな中でこれだけは設定してる!というのピックアップしておきます。
設定
自分はVimでLeaderをスペースに設定しているので、それを踏襲。
<Leader> h
で文頭、<Leader> l
で文末をよく使ってます。
最低限、これを入れるだけでかなり使い勝手がよくなりました。
むしろ、手が勝手にこれを打つのでないと厳しい...。
そこの設定はこんな感じ。
{ "vim.leader": "<space>", "vim.useSystemClipboard": true, "vim.normalModeKeyBindingNonRecursive": [ { "before": [ "leader", "h" ], "after": [], "commands": [ { "command": "cursorHome", "args": [] } ] }, { "before": [ "leader", "l" ], "after": [], "commands": [ { "command": "cursorEnd", "args": [] } ] } ] }
キーボードショートカット
もうひとつ、Uniteで,f
とかでファイラ開いてたのも似たような感じにしたくて、Shift + f
でクイックオープン開くようにしました。
Shift + f
はいろいろ問題あったのでやめました。。。
まずエクスプローラーでShilf + fすると、普通にFが入力されてしまうし、そもそもShift + f
潰すとFが入力できない()
Ctrl + , f
に変えました。ちょっと面倒かな。。。
こっちは基本設定→キーボードショートカットから、workbench.action.quickOpen
の設定を変えてください。
MacのデフォがCommand + p
なんですけど、片手で打ちやすいようにした感じです。
Ctrl + f
が良いんですけど、Ctrl + f
はVimのスクロールとバッティングするので避けました・・・。
あとは
fコマンドを使うとき、自分がいかにclever-f.vimに依存してるかが分かりました。
自然とf連打してしまう・・・。VSCodeでも似たようなことしたいなーなんかちょいちょい思ってます。
スクロールを連動させる
Qiitaなんかである入力エリアとプレビューエリアのスクロールが連動するやつ。
要件は違ったんですが、スクロール同期という点では同じだったのでやってみたので書いておきます。
単純に連動する
まずは単純に同じサイズの要素を連動させてみます。
単純な連動デモ
const areaA = document.getElementById('area-a') const areaB = document.getElementById('area-b') areaA.addEventListener('scroll', e => { const scrollTop = e.target.scrollTop areaB.scrollTo(0, scrollTop) })
同じサイズのA→Bと連動させるなら、AのスクロールイベントでscrollTop
をとって、BのscrollTo()
に放り込んであげるだけです。
サイズが違う要素を連動する
次にQiitaみたいな要素の大きさが異なる場合の連動を見ていきます。
サイズ違いの連動デモ
const areaA = document.getElementById('area-a') const areaB = document.getElementById('area-b') areaA.addEventListener('scroll', e => { const scrollMaxA = e.target.scrollHeight - e.target.clientHeight const scrollMaxB = areaB.scrollHeight - areaB.clientHeight const percent = e.target.scrollTop / scrollMaxA areaB.scrollTo(0, scrollMaxB * percent) })
さっきと異なるのがサイズが異なるので、何%スクロールしたのかを求めることが必要です。
まずはscrollHeight - clientHeight
で、どれだけスクロールできるのかをそれぞれ求めます。
次にAのscrollTop / scrollMaxA
で%を計算。
最後にBのscrollTo
にscrollMaxB * percent)
でスクロール量を放り込んであげて完成です!
相互連動させる
最後に相互に連動させる必要がある場合です。
相互連動デモ
const areaA = document.getElementById('area-a') const areaB = document.getElementById('area-b') function scrollA(e) { const scrollTop = e.target.scrollTop areaB.scrollTo(0, scrollTop) } function scrollB(e) { const scrollTop = e.target.scrollTop areaA.scrollTo(0, scrollTop) } areaA.addEventListener('scroll', scrollA) areaB.addEventListener('scroll', scrollB) areaA.addEventListener('mouseenter', e => { areaB.removeEventListener('scroll', scrollB) }) areaB.addEventListener('mouseenter', e => { areaA.removeEventListener('scroll', scrollA) }) areaA.addEventListener('mouseleave', e => { areaB.addEventListener('scroll', scrollB) }) areaB.addEventListener('mouseleave', e => { areaA.addEventListener('scroll', scrollA) })
ちょっと面倒な書き方してるかもしれないですが。。。
相互連動するとA→Bをしたときに、Bのスクロールイベントがトリガーされます。
デモぐらい単純な中身なら気にはなりませんが、たまーにズレたりします。
そこで、AをスクロールさせたときはBのイベントをトリガーしない。
BをスクロールしたときはAのイベントをトリガーしない。みたいなことが必要になります。
方法は
- どこからスクロールされているのかを明確にする
- そもそもイベント自体を消してしまう
どっちかだと思いますが、今回は後者です。
各要素にmouseenter
したら別要素のイベントをremoveEventListener
で削除。
mouseleave
したら別要素にイベントをaddEventListener
で付与しています。
Electronアプリを自動アップデートする
Electronのアプリの自動アップデートについて調べる機会があったので書いておきます。
いくつか方法があって
- Electronに元々入っている
autoUpdater
- electron-builder + electron-updater
- update-electron-app
今回は、electron-builder + electron-updaterを試してみました。
electron-builder + electron-updater
npm install electron-updater
Githubでやる場合、package.jsonはこんな感じで。
"build": { "publish": { "provider": "github", "owner": "owner", "repo": "reponame" } }
トークン求められるので、適宜Githubのトークン発行できるところからトークン発行しましょう。
.env
にGH_TOKEN=xxxxxx
の形で置いておけばOKです。
GH_TOKENがあるだけで、勝手にGitHub使われるっぽいですが・・・。
あとはビルドのオプションに--publish always
とかしとくと、ビルドする度にGithubのReleaseにビルドされたファイル上げてくれます。
それが嫌な場合はnever
とか、他はタグつけたときだけとか指定できます。
その他、自前のサーバとかに置く場合はこんな感じに。
"build": { "publish": { "provider: "generic", "url": "http://xxx" } }
(HTTPSじゃないとだめ、みたいな記事も見たけど、そうでもない?)
あとはurlで指定しているとこに、ビルドしてできたファイル群とlatest.yml、latest-mac.ymlを配置しておきます。
versionに-alpha、-betaあたりをつけると、alpha.yml、beta.ymlが作られます。
Vue CLI3
参考までにVue CLI3でプロジェクト作ってて、vue add electron-builder
してる場合はこんな感じです。
(この構成でやってます)
vue.config.jsに
pluginOptions: { electronBuilder: { builderOptions: { publish: { provider: 'generic', url: 'http://xxxxx' } } } }
そんなに変わらないですね。
コードの方
メインプロセスの方に各イベントごとに処理を記述していきます。
一旦↓ここを参考にしつつ、update-downloaded
のイベントだけ足してあげます。
electron-updater-example
よくあるアップデートがあったら再起動するかを聞いてくるやつにしたいので、
autoUpdater.on('update-downloaded', ({ version, files, path, sha512, releaseName, releaseNotes, releaseDate }) => { const detail = `${app.getName()} ${version} ${releaseDate}` dialog.showMessageBox( win, // new BrowserWindow { type: 'question', buttons: ['再起動', 'あとで'], defaultId: 0, cancelId: 999, message: '新しいバージョンをダウンロードしました。再起動しますか?', detail }, res => { if (res === 0) { autoUpdater.quitAndInstall() } } ) ) const min = 10 app.on('ready', () => { setInterval(() => autoUpdater.checkForUpdatesAndNotify(), 1000 * 60 * min) })
10分に一回ペースで見に行って、あれば聞いてくれます。
update-downloaded
にくるのはlatest.ymlに書いてあるもの。
何があるか分かりやすいようにしてます。
やってみて
思っていたよりも簡単にできました。
自前でアップデートがあるかを確認するAPIが必要?という情報で知識が止まっていたので...。
ng-japan2019に参加した
今年は初のカンファレンスはnj-japanになりました。
お仕事の方でAngularを触る機会があり、その辺から行くことは決めてました。
その後いろいろあって、やってたPJはなくなってしまって、同時にAngular触る機会はなくなったのですが・・・
会場はGoogleのTokyo Office。 こういうカンファレンスに参加すると、他社の中に入れる機会があるので楽しいですよね!
六本木ヒルズなんか普段入れませんから・・・。
今日だけヒルズぞく!!!
印象的だったのは、メトロノームの発表。
Angularとかに関わらず、自分で好きなように機能実装してみて、機能追加していって。。。
チュートリアル終わってから何したらいいか分からない人、実際めっちゃ多いと思いますし、
そういう人たちの参考になったことでしょう。
少なくとも、そうだよこれだよ!って僕は思いました。
本当ならスライドのまとめなんかもしたかったけど、誰かがやっている・・・?
ここ数年、カンファレンスには参加するようにしていて思うのが、「英語リスニングできない」問題。
正直、聞いていても内容入ってこなくて、感覚でしか聞けてないのが辛いです。
言語の壁が高い。
とはいえ、ツイッターの#ng-japan2019には助けられました。
タグ追ってれば誰かしら反応してるのでw
英語に関しては、どうにかこうにかしたいと思うけど、実際に行動に移すこともできず。
英語セッション、なんとなくでも意味理解しながら聞けたら楽しいんだろうなーと。
というような感じなので、セッションひとつひとつ細かくレポートはできないです。。。
みんなどうやって英語できるようになったの・・・?
本当に知りたい。
なんやかんや、ng-japanは参加してよかったです。
Angular個人的に触りたい欲は終わってからもあったので、その刺激になりました。
それと、TypeScript書いていこうと強く思いました。
社内でTypeScript書いてる人間はいないので、次はここで抜けていかないと。
NestJSも触ってみようかな?
キッカケは与えてもらってると思うので、少しずつやっていきます。