IE対応はそんなに大変じゃなさそう2020
幸いにも私のエンジニア人生ではこれまでIE対応を考えながらコードを書いたことがなかった。
しかし、新しい就職先ではIE対応は当たり前のように行われているという情報を耳にした。
IE対応を考えるとなると、CSSとJavaScriptになるわけだが、CSSではAutoprefixer、JavaScriptではpolyfilというブラウザ間の互換を保つ機能が存在する。
全体重をかけてこういう技術に乗っかる気満々であるが、polyfilの導入方法に加え、IE対応で困った時に参照しそうな情報くらいはまとめておこうと思う。
IEのシェアを確認
IE(11)非対応のJSメソッドたち
ありがたいことに先駆者達が記事にまとめてくれている。
IE非対応のJavascriptをまとめてみた
注意!IE11で使えない最新JavaScritコード(ES6) – console dot log
IE11 で使用できる・できない JavaScript の機能 | knooto
参照先に情報はまとまっているので、ここにはメソッド名を列挙するだけにとどめて置く。
- promise
- fetch
- arrow
- ParentNode, ChildNodeのメソッド
- intersection observer
- class
- find
- for-of
- include
- スプレッド構文
- テンプレートリテラル
- 関数の引数にデフォルト値を設定する
- 配列に対して複数の変数を一気に代入
- オブジェクトから変数に一気に代入
- Map(※配列のメソッドではない)
- Set
Vueでpolyfil
Vue CLIでプロジェクトを作成すれば@vue/babel-preset-appが対応している。
しかし散見する記事ではbabel-polyfillを使っているものも見受けられる。
設定方法は同じようだが設定がうまくいかなくて困ることがあればここら辺を参照しようと思う。
Browser Compatibility | Vue CLI
babel-polyfilはreactでもつかえるがreact-app-polyfilを使うのを結果としては同じであろうしstack overflowではreact-app-polyfillが推奨されている。
まぁここら辺は結果同じ1つのモジュールを使うにたどり着いていくのであろうが、深掘るつもりはない。
プロジェクトの作成時はコマンドラインを使うことを硬く心に誓うのみである。
とにかくpolyfil
CDNで機能ごとにpolyfilを入れる方法もある。
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/3.3.1/es6-promise.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.4/fetch.min.js"></script>
個人的にはCDNを使うべきポイントがわかっていないので存在するということだけ頭の片隅においておく。
最後に
実際にやったことがないから言えるということは100も承知なのだが、ここ数年でIE対応にかかる負荷が格段に少なくなってきたように感じる。(だからこそフロントエンドエンジニアに振り切ることに踏ん切りがついた)
Reactは2013年、Vueは翌年の2014年、さらに翌年の2015年にES6が使われるようになり、2020年の現時点では彼らが公の場に誕生して5年以上経っているわけでいよいよ成熟してきている。
かつてのようにフロントエンドエンジニアは細かいTipsを覚えている職人である必要はなくなってきたのが大変悦しく、デザイン設計の勉強をしてよりユーザーのために考える時間を創出できる、そんな仕事ぶりのフロントエンドエンジニアに私はなりたい。
ブラウザでデータを保存する方法○選!
なんてタイトルにしたが、選び取る以前に列挙する知識がない。
どんな選択肢があるのだろうか、5つくらいサイトを見た情報をまとめてみることにした。
Web Storage(Local Storage / Session Storage)
手始めに「ブラウザ データ 保存」で検索するとローカルストレージが検索にひっかかる。
やたらとローカルストレージでひっかかるがローカルストレージはWeb Storageの仕組みのうちの1つにすぎないらしい。
MDNに知識がまとまっていた。
Web Storage API - Web API | MDN
Web Storageはキーバリューのオブジェクトで2種類の仕組みを持つ。
SessionStorage
・セッション中に使用可能。オリジンごとに保存領域は分割されている。
= 同一オリジンのブラウザを全て閉じるまでデータが保存される。
・ストレージ制限は5MB
LocalStorage
・ブラウザを閉じてもデータは持続し、有効期限はない。
・ブラウザキャッシュをクリアすると消える。
・ストレージ制限は3つ
Cookie
・サーバーとデータをやり取り(セッション管理/ パーソナラライゼーション / トラッキング)する用途で使われる。
・制限は 4096bytes/domain 50cookies/domain(最大でも3000cookies)。
※ 制限に関しては情報が古いかもしれない。しかしてそう変わる技術でもないのかもしれない。
IndexedDB
https://developer.mozilla.org/ja/docs/Web/API/IndexedDB_API
・キーバリューのオブジェクト
・WebStorageよりも多くのデータを保存したい場合に有用。
IndexedDBよりもっとシンプルな使い勝手なのでこちらも検討してねと紹介されていたリストもあったのだが、(localForage / dexie.js / ZangoDB など)ECサイトでもつくる場合を除いてそんなに必要になるケースはないと思うので、この情報は頭の片隅に配置する。
Web SQL
https://www.w3.org/TR/webdatabase/
なんだこの公式ドキュメントは。読みにくいことこの上ないぞ。
と思ったらそれもそのはず、Web SQLは非推奨のようだ。
Vuex.Storeのコンストラクタオプションの中身を覗く
VuexをいじっていたらStoreのコンストラクタオプションにgetterの存在を確認した。
「お!getterなんてあるんかい!」と、getterを使ったことがなかったために妙なテンションになり、たまには特に目的を持たず一箇所深掘りしてみるか〜と思い至った次第である。
Vuex.Store コンストラクタオプション
getterがあるなんて他はなにがあるんじゃろと思い、getterから参照すると型定義は下記のようであった。
export interface StoreOptions<S> { state?: S | (() => S); getters?: GetterTree<S, S>; actions?: ActionTree<S, S>; mutations?: MutationTree<S>; modules?: ModuleTree<S>; plugins?: Plugin<S>[]; strict?: boolean; devtools?: boolean; }
各プロパティの説明はこちらのリファレンスに載っていた。
API リファレンス | Vuex
下の4つがよくわからないので調べがてらまとめてみた。
modules
Vuexでは大規模アプリケーションを考慮し、ストア全体を管理するルートストアの配下にストアを分割配置するという手段を提供してくれているらしい。
そこで登場するのがこちらのmoduleプロパティである。
具体例はこちらにあるが、💡Vuexには大きくなりすぎたStoreを分割する手段がある。ということだけとりあえず覚えておこう。
plugins
これ自体は単一の引数としてストアを受けつけるただの関数。
ミューテーションのコミットをトリガーとし、ログの取得やストアと外部データソースの同期などのために利用される。
具体的な例はこちらを見ると納得感が得られる。
💡DBにデータを保存したいときはpluginで行うということを覚えておきたい。
strict
なんとストアにstrictモードがあるらしい。
Vuex ストアを厳格モードにします。厳格モードでは、ミューテーションハンドラ以外で、 Vuex の状態の変更を行うと、エラーが投げられます。
なるほど、デフォでstrictモードにしたい。
devtool
特定の Vuex インスタンスに対して開発ツールをオン、またはオフにできる。
上記で紹介したpluginの機能を使ってvueは開発者ツールにVueの情報を出しているようだが、それを操作できる代物らしい。
おそらくお世話になることはないだろう。
ここ最近気分でブログに書き出しているが、ブログにまとめようと思える単位で新しいことを学ぶと理解しやすい気がする。
TypeScriptのプリミティブ型を拡張して便利メソッドを生やす
入力値が空であるかどうかを確認して、空だったらPOST処理を走らせたくない。
という要件は往往にして存在するわけで、Stringが空であるかどうかを返してくれるメソッドがありそうなもんだと思ったがこれがないのである。
そこで偉大なる先輩がStringなどプリミティブな型を拡張していたのを思い出す。
ちょうど下記記事の手法を採用して文字列が空であるかどうかを返すisBlankメソッドを実装した。
kakkoyakakko2.hatenablog.com
ここから得るべき教訓
TypeScriptはインターフェースのマージができる。
String*1を参照するとStringのインターフェースに飛ぶ。
interface String { toString(): string; charAt(pos: number): string; charCodeAt(index: number): number; concat(...strings: string[]): string; ・・・ }
こういった既存のインターフェースに自分が追加したいメソッドを宣言を追加することでTypeScriptのプリミティブ型を拡張できる。
declare global { interface String { isBlank(): boolean; } } String.prototype.isBlank = function () { if (this && this.length > 0) return false; return true; };
ESLintエラー
実装する際1つエラーにぶつかった。
エラーを出しているのはESLintさんだった。
String prototype is read only, properties should not be added
prototypeの参照先に飛ぶとこちらにもインターフェース定義があり、prototypeにはreadonly修飾子がついているので上記のエラーが生じたということである。
interface StringConstructor { new(value?: any): String; (value?: any): string; readonly prototype: String; fromCharCode(...codes: number[]): string; }
eslintの設定ファイルに下記記述を追加すると解消する。
'no-extend-native': 0
「拡張して便利メソッド生やしておきました!」なんていかにもできそうな人に見えてよいではないか。
*1:stringじゃないよ。頭文字は大文字だよ
.browserlistrc
.browserlistrcよ。お主はなんぞ
Vueの練習をしようとCLIでプロジェクトを作成したところ設定ファイル群に見慣れぬものがいる。
.browserlistrc
> 1% last 2 versions not dead
これについて知るために下記2つの記事を参考にした。
.browserslistrcで対象ブラウザを指定する - Qiita
CSSベンダープレフィックス-webkit-を今この瞬間に辞める為のAutoprefixerの導入 - Qiita
要するに
webサービスを提供する際に、ブラウザによって、そしてCSSプロパティによってベンダープレフィックスをつける必要がある。
私自身は今までブラウザ対応をしっかり行うWebサービスに従事していなかったため、あまり使ったことがない。
最近はそんなに必要ないんじゃないだろうか。と安易に考えつついざ要求されたらめんどくさそうな仕事であることは容易に推察できる。
これを解消するために Autoprefixer なるものが存在するらしい。
ちなみにそれまでの先人たちはCanI Useというサイトで対応ブラウザを確認していたらしい。しかしflexboxや transform を入力しても何も出てこなかった。
MDN web docsのCSSの項目にも対応ブラウザの記載があるのでなんだかんだこちらで検索した方が良さそうである。
transform - CSS: カスケーディングスタイルシート | MDN
話を戻すとAutoprefixerは最新のブラウザ実装状況をまとめたサイト「Can I use」の情報を使用し、必要なベンダープレフィックスのみを付与する為のツールであるということだ。
必要なベンダープレフィックスを指定をするために登場するのが.browserlistrcである。
AutoprefixerはGulp、webpack、などいくつか使う方法があり、指定ファイル、実行方法もコマンドラインで適応させるなどいくつかパターンあるようだが.browserslistrcは汎用的に対応できるようなのでこちらを使うようにするのが良さそうだ。
責任には明確な方が良いし探すときもすぐに見つけられるので私は設定ファイルはpackage.jsonにまとめないで個別にだしたい派だ。
特に気になったのはVS Codeの拡張機能「Autoprefixer」もしくは「Live Sass Compiler」を使うという方法だ。
ベンダープレフィックスってなに?自動で付与する方法とは? | Web Design Trends
GolangでGraphQLのクエリに添付したファイルをS3にアップロードする
GraphQLでファイルデータをアップロード
GraphQLサーバーには gqlgen を利用。
gqlgenが提供する型の1つである `Upload` を使う。
scalar Upload
https://gqlgen.com/reference/scalars/
@graphql.schema type Mutation { uploadFile(file: Upload): String }
goで処理を受け取る際の引数(resolver)の型には*graphql.Uploadを指定
func (r *mutationResolver) UploadFile(ctx context.Context, file *graphql.Upload) (*string, error) { // ... }
Uploadの中身は下記のとおり
type Upload struct { File io.Reader Filename string Size int64 ContentType string }
S3にアップロード
S3にアップロードするために aws-sdk-go が提供するs3managerを利用。
https://aws.amazon.com/jp/sdk-for-go/
バケット名とオブジェクトキー、アップロードするファイルをio.Reader型で渡す。
Upload.Fileをそのまま渡せる。
bucketName := "xxx-bucket" objectKey := "xxx-key" uploader := s3manager.NewUploader(sess) _, err = uploader.Upload(&s3manager.UploadInput{ Bucket: aws.String(bucketName), Key: aws.String(objectKey), Body: file, })
テスト
いつもはgqlgenが提供してくれるclientを使ってクエリを叩いてインテグレーションテストを行っていたのだがfileを正しく渡す方法がわからなくて断念した。
c := client.New(handler.GraphQL(graphql.NewExecutableSchema(graphql.Config{}))) targetFilePath := "./sample.txt" file, err := os.Open(targetFilePath) query := fmt.Sprintf(`mutation uploadFile { uploadFile(file: {file:%+v, fileName:"%s", size: %d, contenttype:"%s"}) }`, file, "fileName", 5, "contentType") c.Post(query, &resp)
解決策としてはファイルのアップロードに関してはaltairを使って手動テストすることにした。
https://altair.sirmuel.design/altair.sirmuel.design
左下のファイルを選択でFinderからファイルを選択できる。
枠線のAdd Filesをクリックすると複数ファイルの選択も可能。
ShellScript備忘録
確認用テンプレ
ファイル名: test.sh
実行: ./test.sh
#!/bin/sh export ENV=pro echo $ENV if [ $ENV == pro ]; then echo "ok!" else echo "ng...." fi