ASP.NET Core で小さく Sass と ES6 を使う
「小さく」と書いた理由には、その対比として Webpack のような Node のエコシステムを使った手法を置いている。つまり、そちらを「大掛かり」としている。
フロントエンドエンジニア不在の現場でフロントと向き合う
ASP.NET Core 関連のブログ等を読んでいたり、ASP.NET Core の SPA サポートをみていても、おそらく大きな流れとしては Node を素直に利用して、フロントはフロントの文化の中で開発しようというものに見える。
一方で、React / Vue などを使ったフロントエンド開発は、ASP.NET (MVC or WebForm) + jQuery の開発を主とする組織においてはハードルが非常に高い。
「勉強すれば」という声も聞こえてきそうだが、現実としてそういう組織は開発リソースも潤沢ではないため、学習しながら開発というのは難しく(しかも全く別分野のものを!)、当然フロントエンドエンジニアを採用するということも難しい。
ほとんど言い訳ではあるが、こういう背景があるという前提がある。
それでも JS / CSS の開発をアップデートしたい
SPA とまでいかなくとも、UI / UX に関する事業としての要望は上がっていくので、jQuery や普通の JavaScript を使うにしても、少しでも開発生産性を上げるようにしたい。
というところで、今回は最低限として以下を目指す。
- JS/CSS のライブラリ管理できる(npm は使わない)
- ES6 が使える(それ以上は望まない。でもアロー関数や class ぐらいは使いたい。)
- Sass/Scss が使える
ライブラリ管理 Libman
Client-side library acquisition in ASP.NET Core with LibMan | Microsoft Docs
今回の要望を満たすのにちょうどいい。
dotnet tool も提供されている。
> dotnet tool install microsoft.web.librarymanager.cli
以下のようなコマンドでインストールができる。wwwroot
内のどこに配置するかも決められる。
> dotnet libman install jquery
インストールされたものは libman.json
に記録されるため、それがある状態であれば以下で復元ができる。
> dotnet libman restore
ES6 / Sass の導入
- NuGet Gallery | BuildWebCompiler 1.12.405
- GitHub - madskristensen/WebCompiler: Visual Studio extension for compiling LESS and Sass files
Compilation of LESS, Scss, Stylus, JSX, ES6 and (Iced)CoffeeScript files
README の上記を見てもらって分かる通り、いくつかの形式をサポートしている。ただ、nuget の最終更新日 (2019 年で止まっている)を見てもらっても分かる通り、あまり活発ではなく、ES6 以上の対応は望めない。よって、さらにモダンな JS を使いたい場合は Webpack を使うしか無い。(TypeScript 等も当然そちらになる)
WebCompiler には以下のように dotnet tools も存在している。
GitHub - excubo-ag/WebCompiler
ただ、今回は極力開発体験として、IDE から実行ボタンを押せば済むだけにしたかったので MSBuild と連携して実行してくれる BuildWebCompiler
の方を選択した。
以下が設定ファイルであるが、単に対応関係を書けばいいだけである。dotnet tools の方はフォルダ指定もできるので、この辺の設定を省略できるので、現場によっては dotnet tools を選んでもいいだろう。
[ { "outputFile": "wwwroot/css/site.css", "inputFile": "wwwroot/css/site.scss" }, { "outputFile": "wwwroot/js/site.js", "inputFile": "wwwroot/js/site.es6" } ]
上記を見て分かる通り、ES6 の場合は .es6
拡張子にしておく。(ここは例えば .es6.js
とかにしてもいいが、IDE 側でうまくツリー表示してくれなかったので、素直に es6 にした)
bundler の導入
JS / CSS を bundle (及び minify )したいので、そちらも導入する。(WebCompiler でも minify はできるが、こちらでまとめて行うのであえてしていない)
- Bundle and minify static assets in ASP.NET Core | Microsoft Docs
- NuGet Gallery | BuildBundlerMinifier 3.2.449
こちらは Microsoft Docs に紹介があるので、詳細はそちらに譲るが、bundleconfig.json
にまとめるファイルと出力ファイルを定義するだけなので迷う部分はない。
こちらも、MSBuild と連携してビルド時に実行してくれるため、開発体験としては、SCSS や ES6 を修正すると、ビルド時に CSS / JS への変換と、ファイルの bundle, minify をしてくれる感じになる。
当然、開発中は bundle と minify はいらないので、その辺は Release ビルド時だけ実行するように最適化できるとなお良さそうではある。
(テンプレートを使っている場合) bootstrap sass を使う
Sass を利用するようになったので、せっかくなので bootstrap sass を利用する。以下のように bootstrap.scss
を用意し、lib
配下の bootstrap には sass フォルダもあるので、そこから必要なものだけインポートする。MVC テンプレートを使った場合の最低限だと以下のようになると思う。
@import '../lib/bootstrap/dist/scss/functions'; @import '../lib/bootstrap/dist/scss/mixins'; @import '../lib/bootstrap/dist/scss/variables'; @import '../lib/bootstrap/dist/scss/root'; @import '../lib/bootstrap/dist/scss/reboot'; @import '../lib/bootstrap/dist/scss/grid'; @import '../lib/bootstrap/dist/scss/navbar'; @import '../lib/bootstrap/dist/scss/utilities'; @import '../lib/bootstrap/dist/scss/type';
これを利用すれば、bootstrap.min.css
を利用するよりサイズを削減できる。
_Layout.cshtml で分離させる
<environment names="Development,Docker"> <link rel="stylesheet" href="~/css/bootstrap.css" /> <link rel="stylesheet" href="~/css/site.css" /> </environment> <environment names="Staging,Production"> <link rel="stylesheet" href="~/css/bootstrap.min.css" asp-append-version="true" /> <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" /> </environment>
Microsoft Docs にも書いてあるが、同じようにする。(Sass で最低限だけ入れているので CDN からは読んでいない)
IDE 上でどう見えているか
Rider での表示であるが、minify されたファイルも含めてツリー表示される。
最後に
今回の構成だと、JS のテストを書いたりというところまではいけていないし、おそらくは既存 jQuery / CSS での開発をちょっと便利にするぐらいにはなると思う。
なんとか Webpack を導入しつつも、既存の Web Form の開発者がそれを意識せずに開発できるようにというところを目指したかったが、おそらく綻びもでてしまうし、そこで開発体験が悪くなっても仕方がないので、フロントエンドの知見や人員が少しでも増えたところでという折り合いをつけようとしている感じ。
コード
GitHub - dany1468/aspnetcore_es6_sass
参考
- ASP.NET Core Web アプリプロジェクトで、Node.js 使わずに Sass (SCSS) をコンパイルする : @jsakamoto
- ASP.NET Coreでプロジェクト内のcssやjsファイルをminifyする - shuhelohelo’s blog
他に検討したもの
以下はもう少し検討しても良かったのですが、Microsoft Docs で BuildBundlerMinifier が紹介されており、導入に関して説明がしやすいだろうというのがあったためというのが大きいです。
Cloud Build で Secret Manager で展開した環境変数を Docker の build-arg に渡す
Cloud Build で Secret Manager から接続情報を取得し、Github Packages の nuget feed からパッケージを復元する - dunno logs
先日上記のように Cloud Build で Secret Manager から取り出した値を環境変数として展開し、後続のビルドステップで利用するということをしましたが、 docker build
するケースもあったのでついでに。
もはや Secret Manager は関係ない。
今回のファイル
Dockerfile
FROM alpine ARG GITHUB_USER="test" ARG GITHUB_TOKEN="token" RUN echo $GITHUB_USER
alpine にしてますが、環境変数が渡されてるか知りたいだけなので、そこに意図はないです。
cloudbuild.yaml
steps: - name: gcr.io/cloud-builders/gcloud entrypoint: bash args: - -c - | gcloud secrets versions access --secret=github-access-token latest > /workspace/build_vars - name: 'gcr.io/cloud-builders/docker' entrypoint: 'bash' args: - -c - | source /workspace/build_vars docker build --build-arg GITHUB_USER=$$GITHUB_USER --build-arg GITHUB_TOKEN=$$GITHUB_TOKEN .
Secret Mangar からの読み出しは変わってません。
docker build の部分が今回のポイントです。
以下に記述があるのですが、 $
一つだと、Cloud Build の変数置換機能で期待通り評価されないので、 $$
としています。
Substituting variable values | Cloud Build Documentation
これでうまくいきます。
少し思うこと
Cloud Build には Substitution があって、外から値を与えられるのでそこに Secret Manager から値を渡せると嬉しいのだけどなぁと思いつつ、Sustitution の値はビルドログにもガッツリ残るしそこは微妙なのかもと。
KMS で暗号化した値を Substitution に渡して、それを中で復号するというのも検討してみたんですが、結局こちらに落ち着きました。
参考リンク
Cloud Build で Secret Manager から接続情報を取得し、Github Packages の nuget feed からパッケージを復元する
準備
cloudbuild 用のサービスアカウントに Secret の読み出し権限を付与
シークレット マネージャーの使用 - Cloud Build
- Cloud Console で IAM ページを開きます。
- プロジェクトを選択し、[開く] をクリックします。
- 権限の表で、末尾が @cloudbuild.gserviceaccount.com のメールアドレスを見つけて、鉛筆アイコンをクリックします。
- Secret Manager Secret Accessor ロールを追加します。
UI を日本語にしていると、「Secret Manager のシークレットアクセサー」のように出るかもしれません。
nuget config の用意
本当は dotnet new nugetconfig
と dotnet nuget add source
で nuget.confg も Cloud build の実行時に作ってしまいたかったのですが、add source の方の -u, -p
が手元うまく機能しなかったので、nuget.config をあらかじめ用意する方法にしました。
<?xml version="1.0" encoding="utf-8"?> <configuration> <packageSources> <!--To inherit the global NuGet package sources remove the <clear/> line below --> <clear /> <add key="nuget" value="https://api.nuget.org/v3/index.json" /> <add key="github" value="https://nuget.pkg.github.com/%GITHUB_OWNER%/index.json" /> </packageSources> <packageSourceCredentials> <github> <add key="Username" value="%GITHUB_USER%" /> <add key="ClearTextPassword" value="%GITHUB_TOKEN%" /> </github> </packageSourceCredentials> </configuration>
環境変数から読むようにします。
- Configuring dotnet CLI for use with GitHub Packages - Github Docs
- Using environment variables - Microsoft Docs
Github Package への接続情報を用意
上述のように環境変数で接続情報を nuget.config に渡すため、利用しやすいように今回は最初から環境変数に設定できる形にしておきます。
export GITHUB_TOKEN=xxxx export GITHUB_USER=xxxx export GITHUB_OWNER=xxxx
⚠ あるあるですが、Windows の場合は CRLF ではなく LF で保存するのを忘れずに。
シークレットとして登録
シークレットマネージャーの使用のリンク先に以下のようなステップが書いてあるのでその通りにしていきます。今回はシークレットの名前を github-access-token
とします。
- Cloud Console の [シークレット マネージャー] ページに移動します。
- [シークレット マネージャー] ページで、[シークレットを作成] をクリックします。
- [シークレットの作成] ページの [名前] に「secret-name」と入力します。
- [シークレット値] フィールドにデータを入力します。
- [リージョン] セクションは変更しません。
- [シークレットを作成] ボタンをクリックします。
cloudbuild.yml の用意
リポジトリルートに配置します。
steps: - name: gcr.io/cloud-builders/gcloud entrypoint: bash args: - -c - | gcloud secrets versions access --secret=github-access-token latest > /workspace/build_vars - name: mcr.microsoft.com/dotnet/sdk:3.1 entrypoint: bash args: - -c - | source /workspace/build_vars dotnet nuget list source dotnet restore
上記は一応 dotnet nuget list source
で Github Packages の feed の設定ができているか見ていますが、設定が環境すれば消して大丈夫です。環境変数への設定がうまくできていれば、 https://nuget.pkg.github.com/%GITHUB_OWNER%/index.json
の環境変数部分が、置き換わった状態でログに表示されるはずです。
プロジェクトの用意
このままでは、何も restore するものがないので、Github Packages の nuget feed に登録し、それを参照するプロジェクトを追加してください。
実行
今回は Cloud Source Repository にリポジトリを作成し、そことビルドトリガーを組み合わせて試しました。
restore が失敗しなければ成功です。
最後に
「Secret Manager Secret Accessor ロール」は開発者に付与してしまうと、中が見えてしまうので管理者だけが見えるようにしておきます。
その他参考
畑の冬支度
先日ほおずきトマトの冬支度を終わらせましたが、今度は全体的にです。
冬支度の基本は「地表を露出させない」の一点です。これは日差しの強い夏、霜の降りる冬の両方にいえることですが、どちらも地表が露出していると土にダメージがきます。
特に冬は雑草も生えにくいのでしっかりと。
借りてる畑の方
before
after
もう枯れそうだったつるむさきを撤去し、笹をかぶせてしまいます。冬はこの部分はもう使わないことにしました。
白菜はまるめてしまいます。
地表が露出している部分には、廃菌床(しいたけを育てるもの)が借りてる農園にはたくさんあるので、それをひたすら手で崩してまいていきます。これが結構骨が折れます。。
近づくとこんな感じ。わかりにくいですが、レタス等の周りは もみがら か おがくず をかけています。
フェンス際に植えている豆系の下も同様に。
写真ではわからないですが、豆の下には麦も植えていて、芽がでてきています。麦はもうすぐ踏みます。(踏まないと大きくならないみたい。。)
ちなみに麦は食用というわけではなく、大きくなったらそのまま倒して夏には同様に地表を隠してくれるものになるでしょう。
自宅
自宅は一回雑草対策で黒マルチで覆いつくした後、すこしずつまた拡げていっている。
自宅には、おがくずはもちろん、廃菌床なんかないので、ひたすら桜の木から落ちてくる落ち葉を崩したりして地表を覆っています。
こっちはレタスだけ。かなりぎゅうぎゅう。
こっちはレタスとスイスチャード。スイスチャードはこの調子だと、、、、うーん。
その他
冬は選定の季節なので、最近は朝の 30 分でもとにかく庭の木を切って回ってます。
ただ、木は切ってもそのまま捨てられるわけじゃないので、小さくして処分できるサイズまで整えていくのが大変。なんか一年中それやってる気がする。
今年の Advent Calendar
職業柄か Advent Calendar と聞くと、Qiita やらでたくさんの人が毎日(交代で)ブログを書くことみたいなイメージだったけど、今年は子供と一緒にやってみることにした。(これまでもディズニーのとかやるチャンスはあったけど、タイミングが合わずにスルー)
Lego Frends Advent Calendar
たぶん 10 月ぐらいには買うだけ買っておいて、棚の最上部に隠しておいてようやくお披露目された。ちょうどいいのでその日に家のツリーも出した。
開けると数字が書いた窓のある感じになっている。カレンダーなので順番かと思っていたけど、そうじゃなかった。
さっそく、保育所から帰ってきた娘に「このカレンダーはな」と簡単に説明し、「1」の窓を開けてもらった。
1 はエマでしたね。
クリスマスといっても
山を降りて街のモールとかにいけばキラキラしてるけど、日常ではそんなクリスマスムードを感じるものもなく、娘は保育所のクリスマス会の準備とかしてるけど、自宅だと「なにすればいいんだろう」とか悩みがちでしたが、一つクリスマスっぽいことができてよかった。
レゴフレンズ
Netflix で見つけてから娘はちょいちょいアニメは観てるけど、実際レゴ製品もたくさんあってこちらもちょいちょい買ってる。(といっても、まだ大物は娘は作れないので小さいのばかりだけど)
さっきのエマを見てもらって分かる通り、フレンズのレゴは脚が長い。そして、座ったポーズの時に穴が空いてないので座った状態でジョイントさせることができない。よって、乗り物とかも立ち乗り前提で設計されていて、それはそれでよくできている。
フレンズのパーツはとにかく可愛いものが多いので、一緒に作っていても昔のレゴしか知らない人間としては驚かされることが多くて楽しい。
妻と娘の成果発表的なもの
この 1 ヶ月ぐらいで、妻と娘、それぞれの日頃の成果を目の当たりにできた。
娘の成果
秋になり、運動会 (10月)と生活発表会 (11月)の 2 つが一ヶ月のスパンを置いて実施されるという「先生大丈夫なの?」的なスケジュールで開催された。
COVID-19 の影響もあり、運動会は保護者は一人、生活発表会も二人まで、加えて親参加の競技等は無しという形で開催された。(保護者は二人で十分ではないかという説もあるが、田舎は当然祖父母もくるのである)
運動会では、背が学年で一番小さいながらに競技でも奮闘を見せていたが、ダンスになると、小さい体を大きく動かし、キビキビと動いていて、親バカとしても「最高に良かった」という感じだったが、運動会後も他のお母様達から「〇〇ちゃんすごかったー」と褒めていただき誇らしかった。
生活発表会は、年中・年長での合同楽器演奏、年中だけでの劇(10分ぐらい)、手話での演奏の三本立てだった。
劇は「大きなかぶ」だったが、なんとなく娘や先生から、誰も先頭でかぶの種を蒔いたりする役をやりたがらないから、うちの娘が引き受けたというのを聞いていて、こちらもドキドキしていたが、(美女と野獣の)ベルのドレスを着てでてきた娘は、体育館のステージを左右いっぱいに使い、最初のダンスを踊りきり、種を蒔き、かぶを引っ張り、二人目を呼ぶところまで堂々とやりきっていた。
人数が 6 人しかいないクラスなので、間をもたせるために、全員が好きなキャラクターになりきって、登場時に 1,2 分踊るという感じだった。子どもたちでそうしたいと発案したらしい。
二人目、三人目と出てくる最中も、みんなが全員の踊りを覚えているのか、バックダンサー的に踊っていて、可愛らしかった。
発表会後にも、「女優か!」「独壇場だった」など親バカを加速させる感想を他の保護者からもらい、親としても照れつつも、誇らしい気持ちだった。もちろん、どの子も素晴らしかったし、娘は先陣きって踊っていたため印象に残った部分が多かったということだろうが、先頭を引き受けた娘は褒めるべきところだろうと思う。
僕としてはどの年齢のどの子を見ていても顔がほころぶ以外の感想がなく、正直楽しませていただいた。1 歳の子が、音楽なってるのにただ直立してるのとか、可愛すぎてずっと見ていられる。
楽しそう
年齢的に照れも出てくるし、単純にその行為が楽しいと思えるかというのもあると思うが、娘は全体的にずっと楽しそうにダンスをしたり役を演じたりするのが印象的だった。もちろん家で練習をしている時も楽しそうだったし、当日が近づくにつれて「恥ずかしいーーーーー」とか言ってるが、全然恥ずかしそうにしてないところも含めて、とにかくそれを披露するのが楽しくて仕方ないんだろうと思う。
妻とも話していたが、僕ら夫婦もある程度小さい頃はなんでも卒なくこなす方ではあったけど、それを「楽しんで」やれていたかというと、あまりそういう記憶はなくて、楽しそうにできる娘のそういう部分は伸ばしていける環境を作ってあげたいなと思った。
ちょうど面談の時期だった
ちょうど昨日、先生と妻で個別の面談があって最近の状況を聞く機会があった。
今年は 3, 4, 5 月の自粛期間中に保育所にいけない時期があったりで、その後クラスメイトとうまくいかない時期がたまにあり、登校拒否する日も数日あるなど心配なこともあったが、先生からのフィードバックは安心できるものだったし、次第にこちらの心配も小さくなってはいっていた。
昨日の面談でも、自粛時期で登所する子が減った時期に保育所で不安定になっていた子もいたけど、それも落ち着いてきて最近は本当にいいチームワークのクラスになっているということで、安心した。
実際、今週は月曜は風邪で欠席していたのだが、火曜の朝に連れて行くと、教室の前につくと中から「〇〇ちゃん今日は来た!」とぞろぞろクラスの子が出てきてくれて嬉しかった。
妻の成果
まず、ここまで娘が育ってくれたことは妻の成果であることは間違いなく、今回はそれ以外の話。
妻は、出産後から少しずつ趣味でイヤリングを作り始め、最初は自分に気に入るものが売っていないから自分用に作っていたが、次第に minne 等で売り始め、1 年ぐらいして初期投資(機材など)分は利益を出し、バイトや娘の習い事の送り迎えもしながら、制作・販売を続けている。
習い事の送り迎えといっても、田舎にはそういう場所が無いので、近くの街まで行くので、結局往復で 3, 4 時間はかかるし、週に 1 度ではない。 販売はオンラインと、バイト先や町内の一部のお店。
町内のギフトカタログに載る
こういう町単位のギフトカタログというのが一般的かどうかは分からないが、そういう取り組みがあるらしい。そこにこの冬号から妻のアクセサリーがラインナップされていた。
原則町民向けで、カタログも紙媒体は町民にしか配られないため、たまたまオンラインで見つけない限りは町外の人の目に触れることはないと思う。
彼女自身の成果
妻自身も、このカタログでなんらか売上を期待しているわけではなさそうだし、超高齢化の進む町民向けのカタログでの注文は少ないかもしれない。
一方で、こういうクリエイター的な活動をしている人は町内にも少なくない中で、ラインナップされたことは大きな成果だと思う。
きっと、そこには、バイト先のコーヒー豆焙煎所に置いてもらっていることで、そこでのお客さんや、町民に認知されていることもあると思うし、実際町内で買ってくれている人も多い中でそこでの満足度が高かったこともあると思う。(このカタログは商工会が出しているが、町内での評判等も加味されているはず)
なにより、彼女の人柄や態度も影響しているのではないかと思う。
我が家と町のつながり
僕が日中自宅で仕事してることや、それほど町内のイベントに積極的に参加しないので、僕と街のつながりは濃くない。飲食店ぐらいだろうと思う。
その中で、妻は町内の中心地にある場所でバイトをしていたり、こうして町内の人の手にとってもらえるようなものを販売していることもあり、彼女が我が家と町をつないでくれている。僕が認知されていなくても、隣にいる妻が認知されているので僕はその恩恵に預かれている。
妻や娘の成果を目の当たりにして僕は
自分は相変わらず前に進めていないな、その日暮らしになっているなと反省している。何かを自分の行きたい方向に積み重ねられていない。
数日前も40代なかばのプログラマー的な話題があったが、いろいろ意見あるだろうけど、自分は数年後の自分を見ているようだった。
二人にはいい刺激をもらったので、自分もがんばっていきたいと思ったのであった。
ほおずきトマトの冬支度
今年はなぜか間違えて普通のミニトマトではなく、ほおずきトマトの種を蒔いてしまっていた。
しかも今年は春先が 2 月なのに暖かく、3 月寒く、4 月になぜか雪が降るみたいな謎の気候で苗にできるまで時間がかかり、結局夏の間に育ちきらず「あーー、失敗したなぁ」と思っていた。
ちなみに、ほおずきトマトは僕もたぶん初めて食べたが、以下のようなもの。
写真前面に写っているのは、借りている畑のオーナーが片手間で育てていたほおずきトマトを成功例としてもらったもので、私は写真の奥の方にうつっている、半分ぐらいのサイズの状態にしか育てられなかった。
味は甘酸っぱくてとても美味しい、本当に美味しい。トマトと言って出されても信じられないかもしれない。溶かしたチョコをつけて食べたりもするらしくデザートである。
越冬させる
借りている畑では、例年トマトは越冬させないのだが(というか、僕はそもそもトマトが越冬できることを知らなかった)、ほおずきトマトは例外で越冬させるということを教えてもらい、そろそろ霜も降り始める時期なので越冬の準備を始めた。
枝の刈り込み
刈り込み前の写真を取り損ねたので、文字での表現になってしまうが、育ちきらなかったといってもトマトなので枝は 横縦 1 m 前後まで広がっている。それを以下のようにいくつかの元気そうな節だけ残して刈り込む。
指導されながら、「ほんとに?ほんとに?」と聞きながら切っていったが、大丈夫かってぐらい小さくした。
オーナーのほおずきトマトは僕より身長が高くなっていたが、越冬のためこれに近い部分まで刈り込んでしまうらしい。
布団をかける
保温のために、大量のもみがら、その外に笹の葉、最後にビニールの順に覆っていく。
ビニールは一旦手近にあった透明のものにしたが、また黒マルチを切って付け替えるかも。
これで冬支度完了
来年が楽しみ
越冬が無事成功すれば、春にはまた枝が伸びていって、夏には甘酸っぱい実が食べられるかもしれない。
トマト系は自分が不精なのもあって、ミニトマトぐらいしか成功させられていないので余計に期待が高まる。