tekitoumemo’s diary

.NET CoreとVue、Angularなどの技術ブログを書いています。みんなの洋楽ランキングを運営しています。

App Service on Linuxが安くなった

去年のMicrosoft Build 2019でApp ServiceのFreeプラン(無料)が発表されました。それと同時にキャンペーン価格としてLinuxのBasicプラン(コア1、RAM1.75G、STORAGE 10G)が2020年1月まで1500円/月 程度となりましたが、謎に全くアナウンスが無い状態でキャンペーンが2020年7月まで延長となりました。そして今月、キャンペーンが終了かと思いきや、通常の料金として1500円/月 となったようです。ただ、期限なしですが「キャンペーン価格」と書いてあるのでいきなり値上げする可能性も0ではないかと思いますが、いまのところ安く利用出来ます。Basicプランであればherokuより安い!


azure.microsoft.com

買ってよかったもの【2020年上半期】

今年はコロナで不況になって節約気味なのであまり大きな買い物してない(してる)。皮肉なことに、不況ながらもフリーランスになった中で一番働いてるので前半後半比較したくて書いてみた。

Macbook Pro

tekitoumemo.hatenablog.com

¥267,080

やっぱこの金額出してもこれ買ってよかったなと思う。僕はマウス、キーボード、外部ディスプレイを使わない主義なので、そこらのUXが極まってるmacでよかったかなと思ってる。最近WSL2が出てWindowsも最高らしいのでインターフェース重視で選ぶならSurfaceでもよかったかも。

体重計

www.amazon.co.jp

¥3,299

マジ太り過ぎやばいので買った。自粛期間意識したら五キロ痩せた。まだデブだけど(笑)

手袋

¥1,480

www.amazon.co.jp

原チャクソ寒いので買った。速攻ほつれたけど、雨風割としのげるからよかった。中型以降はこんなんじゃだめだけどね。

ワークマン イージス

¥6,800


workman.jp

あまりカッコよくないけど、ものの30分ぐらいであれば原チャ程度はしのげる。首元や地味な配慮がうれしい。

AirPods Pro

¥27,800

www.apple.com

結婚記念日に嫁からもらった。ノイキャンすごい。地味に充電が持つのがいい。でも高すぎ。

ASUS Zenfone Live (L1)

¥18,180

www.amazon.co.jp

iphone10 max持ってたけど壊しちゃったので、ローン終わるまでのしのぎで。この値段だから許せる。

ルーター

¥9,980

www.amazon.co.jp

自宅が3LDKの70平米以上あるので寝室や納戸まで全然届かなくなった。結局これ買っても気持ちよくなった程度。

Kindle Fire HD 10

¥15,980

www.amazon.co.jp

車で娘がぐずるので、娘用に買った。ネトフリとyoutubeしか使わないので普通にコスパ最高だった。

タブレットを車載にするやつ

¥1,666

www.amazon.co.jp

うちのチャイルドシートが360度回転するやつなので前向き後ろ向きにも付けられるようにこれを買った。えぐい安いけどかなりよい。

ノートPCを縦置きするやつ

¥4,090

www.amazon.co.jp

wifi届かない問題で書斎でネットが届かないので基本リビングで仕事してる。ダイニングテーブルに置くために買った。まぁよいって感じ。

トルクレンチ

¥3,890

www.amazon.co.jp

太ってきたし、運動がてらタイヤぐらいは自分で変えようと思い購入。工賃と同じぐらいの値段なので体力的な面を考えると得はない。

OLYMPUS ミラーレス一眼カメラ

¥99,240

www.amazon.co.jp

娘をちゃんと撮りたくて購入。購入してから単焦点レンズというものがないとオシャレに取れないと気づく。

¥32,598

www.amazon.co.jp

意外に高かった。

中継機

¥3,579

www.amazon.co.jp

ネットが届かない問題が完全に解消された。よくよく調べてみるとルーター隠したくてこれを買ったんですが、遮るものがあると電波くそになるらしいのでこれが原因でした。まぁ中継機でチャラなのでまぁ良いでしょう。

レイバン

¥ 21,800

japan.ray-ban.com

単純にカッコつけたいから購入。梅雨だとマジつける機会ない。

思ったほど、お金使ってないな。

HTMLCanvasElement.toBlobくそ遅い

developer.mozilla.org

3072 x 1920 とかでかい解像度のcanvasをBlobに変換するとクソ遅い。

canvas.toBlob((blob) => {
  // Do something
})

callbackつらいのでPromise化

new Promise((resolve) =>
  canvas.toBlob((blob) => resolve(blob))
)

でも遅いので結局自前

function toBlob(base64) {
  const bin = atob(base64.replace(/^.*,/, ''))
  const buffer = new Uint8Array(bin.length).map((_, i) => (bin.charCodeAt(i)))
  return new Blob([buffer.buffer], {
    type: 'image/jpeg',
  })
}

OffscreenCanvasだとちょっと早い。toBlobはノンブロッキングっぽいのでビデオ止めると早くなる(なった)

.NET CoreアプリをGitHub ActionsでAzureにデプロイした

mygkrnk.com

個人サービスをkuduデプロイからGitHub Actionsへ、.NET Core2.2から3.1に上げた。
NET Coreバージョンアップは別の記事で書く。

kuduとは

Azure Webサイトで利用されているGitデプロイエンジン。要はオープンソースのCIなのだが、非常に使い勝手が悪い、というか結局シェルスクリプトゴリゴリなのであまり恩恵がない上、github上で連携出来ないのでAzure portalを見に行かなければならず非常に不便だった。さらに.NET Coreを使う上で大きな問題がある

github.com

.NET Coreを使う上でのkuduの問題点

kuduはホスティング上でビルドするのでホスティング環境が整ってないとビルドが出来ないことがある。AppServiceではnodeは8(記憶上だと)と古く、.NET Coreで言えばビルドするために必要なdotnet cliが使えない(厳密には使えるが最新のバージョンをサポートしてない)。dotnet cliSDKに含まれてるのでAzureのサービス上でビルド出来ないのだ。AppServiceなど3.1のruntimeはあるのにビルド出来ずにバージョンが上げれず、いつSDKがリリースされるのか告知も無い。そのようなことがあり継続的なバージョンアップが出来ないと判断し、GitHub Actionsに移行した。あと、MSがgithubを買収したところからkudu廃止してGitHub Actionsに移行する方向で進んでそう。

GitHub Actionsを選んだ理由

無料枠多すぎ、Microsoftひいきしすぎ(ドキュメント豊富)、期待感すごい。

ワークフローを作る

[new workflow]から.NET Coreを選択。
f:id:tekitoumemo:20200416232820p:plain

[set up this workflow]をクリックするとテンプレートが表示される。2020/4時点はこれ↓

name: .NET Core

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Setup .NET Core
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 3.1.101
    - name: Install dependencies
      run: dotnet restore
    - name: Build
      run: dotnet build --configuration Release --no-restore
    - name: Test
      run: dotnet test --no-restore --verbosity normal

以下、テンプレから変えたところ。

checkout

git submodulesを使ってるリポジトリだったのでcheckout@v1を選択。submodulesをv2で実現するのはちょっと面倒なので。

+    - uses: actions/checkout@v1
+      with:
+        submodules: true
-    - uses: actions/checkout@v2

submodulesでsshだと取得出来ないのでhttpsに変更した。
.gitmodules

[submodule "library/DapperSlackOff"]
 path = library/DapperSlackOff
+ url = https://github.com/ikuosaito1989/DapperSlackOff.git
- url = git@github.com:ikuosaito1989/DapperSlackOff.git
setup-dotnet
    - name: Setup .NET Core
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 3.1.100
    - name: Install dependencies
      run: dotnet restore
    - name: Build
      run: dotnet publish "{path}" --configuration Release -o hoge

テストは作ってないので削除。

コードフォーマッター
.NET Coreではdotnet formatというフォーマッタがある。prittierとか使ってるとちょっとしょぼいように感じるが、無いよりましなので追加する。
github.com

導入は下記参照。
.NET ローカル ツールの使い方 - Qiita

マニフェストファイルがないとdotnet toolコマンドが有効にならないので注意

    - name: Restore Tool
      run: dotnet tool restore
    - name: Check code format 
      run: dotnet format --check --dry-run

--checkはフォーマットせずチェックする仕組みで--dry-runは失敗したときに0以外の終了コードを返すオプション。

webapps-deploy

Azureにデプロイするためのworkflows。

デプロイするための認証情報を取得する必要があるので[発行プロファイルの取得]を押下。githubのSecretにてダウンロードしたファイルを以下で貼り付け。packageはdotnet publishで出力したディレクトリを指定する。
f:id:tekitoumemo:20200417120113p:plain

- uses: azure/webapps-deploy@v1
   with:
     publish-profile: ${{ secrets.publish_profile }}
     package: './hoge' 
masterにpushされたら自動デプロイする
push:
    branches: [ master ]

f:id:tekitoumemo:20200417120808p:plain

AppServiceの設定

AzureのUIが違うかもしれないが、、
[デプロイセンター]からgithubを押下
f:id:tekitoumemo:20200417121303p:plain

github actionsを選択
f:id:tekitoumemo:20200417121350p:plain

リポジトリをよしなに入力。ワークフローはさっきつくったので[既存のワークフロー定義を使用して構成する]を選択。新規で作ると勝手にコミットされるので、僕は嫌いです。
f:id:tekitoumemo:20200417122057p:plain

完了したらあとはpushしてワークフロー流したらデプロイ完了。ちなみにたまにコンフリクト起こしてデプロイ失敗するので、リトライすれば大体成功する。

個人サービス公開して二年経ったので振り返る

去年の振り返り ※この記事は振り返りの続きです。
tekitoumemo.hatenablog.com

このブログに何度も登場してるサービスですが、2018年の4/1に公開してから二年経ったので振り返ります。

結論から言うと、

うまく周ってます、黒字になりました!

2019/5 投稿が少しずつ利用される

SEOが全くうまくいかなかったこの時期。投稿機能を使ってもらった効果によって自分の中で一定の基準(1万PV)に達していたので、続けてライターのイチオシ曲を投稿出来る機能を作成。
f:id:tekitoumemo:20200410215917p:plain
これが全然うまくいかず(笑)後述するレビュー機能と類似機能になってしまい、近々削除する予定。このときは高まっていて勢いで作ってしまった。技術的にもサービス的にもなにもうまくいかず、ただただ負債になってしまった。勢いに乗っているときこそ冷静に。

2019/6 各ページにページビューを追加

そこそこまともなPV数になってきたので、ページビュー数を追加。なぜこれを追加したかというと、会員投稿のモチベーションを下げたくなかったから。1万程度だと、赤字なので会員に還元するわけにもいかず、どの方法で記事を書くモチベーションをあげられるかずっと考えていた。結果的に「こんなにみてる人がいるんですね!」と喜びの声もいただき、さらにその影響か不明だが、PVが多いページが多く閲覧される傾向がでてきた。

2019/8 アドセンス停止

adsenseから不正なクリックを検出したとのことで1ヶ月停止をうける。正直自分で何回か押しちゃってたし、心当たりありまくりなので自戒。adsenseすごいね、そこまで激しいクリックしたつもりないけど、わかっちゃうんだねー。8月は17000PVとそこまで大きくないのであまり影響なかったのも救いだったけど、いろんな壁乗り越えてきたからそこまで焦らず冷静にいられた。
f:id:tekitoumemo:20200410230600p:plain

2019/9 レビュー機能追加

f:id:tekitoumemo:20200411120221p:plain
7月から実装開始したレビュー機能をリリースした。この時期は子どもが生まれたり鬼のように忙しかったのでほとんど手がつけられず、2ヶ月もかかってしまった。さらにこのときフロントエンドフレームワークに葛藤があり、機能の大半をSSRで済むような画面である以上はJQueryなどライトにかけるスクリプトの方が生産性が上がるのではないか?と思い、JQueryで実装した。結果的に40行程度のjsファイルで完結したが、可読性が著しく低下し、変更に弱いコードが出来上がってしまった。JQueryはDOMを加工した物をデータと見立てて、そのデータを加工しDOMに戻す作業なので、本質のコード以外にやることが多くて結果的に可読性が著しく低下するということがわかった。さらに3大フロントエンドフレームワークアンチパターンとして王道なDOM操作をバンバンやるので、疑心暗鬼になりながらでも後戻り出来ず、モチベーションが低下し、個人サービスとしては最悪なコンディションになることがわかった。このレビューに関しては、あまり使ってもらえてはないがライト会員の利用率は比較的高いなという印象。

2019/10 パフォーマンス改善&バージョンアップ

tekitoumemo.hatenablog.com
全ては過去に書いたブログに書いてあるが、完全にパフォーマンス対策した。画像の最適化から圧縮、遅延ロードまで。結果的にめちゃくちゃよくなって、実際のユーザー体験も向上したと思う。バージョンアップと同じでいつかはやりたいなぁと思ってたので、一旦落ち着いたこの時期に出来てよかった。
さらに.Net Coreを2.2へ、Reactを16.8へとあげた。

2019/11 ~ 12 なにもせず

ここらへんは仕事でいろいろあったり、からだ壊して入院したりとそれどころじゃない状況。たまーにバグ直したりする程度で主にNuxtの学習がてらプロフィールサイト作ったり、他のところに時間を費やしていた。PVも8月あたりから2~3万を一定を保つ感じで推移していて、特に何もやる必要がないなと感じていた。昨年は変動が大きかったりといろいろ戸惑ったけど、どんな状況でも怖くなくなったことがでかいと思う。12月は過去最高レベルのPVを記録。
f:id:tekitoumemo:20200411003535p:plain

2020/01 アクセスが右肩上がり

f:id:tekitoumemo:20200411005444p:plain
SEOが順調に上がって約8万PVを記録。2019年のSEOはずっと調子よかったものの、順位が数位上がるだけでこの効果。初めて黒字化達成。1月はグラミー賞もあり、新年で新しい情報を知りたいユーザーが多かったことが重なった。この考察は以前のブログに書いた。
tekitoumemo.hatenablog.com
一番よかったのが、会員に還元出来たこと。過去にキャンペーンとして還元したことあるが、会員が書いてくれた記事をみたユーザーが広告を踏んで得た利益を会員に還元するといった循環が出来たことが何よりも嬉しい。黒字になった部分を全て還元してるので結果的にトントンだが、確実に誰かが必要としているサービスに育ったと実感した。

2020/02 初の10万PVを達成

f:id:tekitoumemo:20200411005639p:plain
昨年の約24倍。昨年1万PVいったときの高揚感はなく、サイト設立当初に計画していたアクセス数と同じような結果がでたなーという感じで冷静だった。昨年の7月にはいつかこの結果になるだろうという確信を持っていたと思う。実際に想定アクセス数が15万〜20万と書いてあるし、なんとなく書き残してるってことはそれなりの自信があったのだろう。
tekitoumemo.hatenablog.com
この月からパートナープログラムを試験的に開始した。投稿の仕組み的に大量のユーザーが書くことがないので得た利益分をうまく回せている。まだ手動だけど、拡大するようであれば今後スケーリングさせる。

2020/03 引き続き10万PV達成

f:id:tekitoumemo:20200411112441p:plain
2月よりは少し落ちてしまったけど平均3000PVはあるので安定したと思う。4月の緊急事態宣言が発表されてからアクセス数が増加しているので、この状況下でたくさんの人にみてもらえ、不安を払拭してくれたらこんなに嬉しいはない。ただ、アクセス数は上昇しているが、モチベーションが下がっていてもう1ヶ月以上更新せず。もともと想定していたアクセス数に近づいたというのとそろそろ限界だろうなというところが見えてきた。おそらくもう少し順位が上がっても30万PVが限度だろうなと思う。モチベーションが下がったとはいえ、利益は出て、多くのユーザーに閲覧されているので今年はバージョンアップやリファクタ、デザインの変更等ユーザー体験が向上するところに重きを置くだろう。


結果的には成功。adsenseの広告収入をユーザーに全還元して他の収入でインフラ代になれば最高かなと思ってるので最後に


広告掲載について | みんなの洋楽ランキング


マジで広告募集してるので連絡ください!!

VeeValidateで一括検証+スクロールするmixins

v3ではValidationObserverが追加され、一括検証が楽になった(v2知らない😇)
一括検証+エラーの要素にスクロールできれば嬉しいはずなので、そのmixinsを書く。
スクロールはお任せで、vue-scrolltoとかいいんじゃないかしら。

page/hoge.vue

<ValidationObserver ref='observer'>
    <ValidationProvider/>
    <ValidationProvider/>
</ValidationObserver>

<script>
import Validate from '~/mixins/validate'
export default {
    mixins: [ Validate ],
    methods: {
        async onSubmit() {
            if (!await this.validateAll()) {
                // Do something
            }
        }
    },
}
</script>

mixins/validate.js

export default {
  methods: {
    async validateAll() {
        const result = await this.$refs.observer.validate()
        const ref = Object.values(this.$refs.observer.refs)
                .filter((ref) => ref.errors.length > 0)[0]
        // refに対してスクロールやらなんやら
        return result
    }
}