SNS を絶つために StayFocusd っていう Chrome 拡張を使い始めた
これ
気がついたら、すぐにアドレスバーに「twitter」と入力するので、SNS 中毒を治すために StayFocusd という Chrome 拡張を使い始めた。
指定したドメインの1日あたりのトータル閲覧時間を設定できる。時間を超えたら「仕事してんじゃないの?」っていう煽りページが表示される。正直、イラッとする。
けっこうよくできていて、一度、閲覧が制限された後に、解除しようと制限がリセットされる時間を現在時刻からすぐ後の時間にしようとしても「OK。明日以降はその時間に解除するよ」というメッセージが表示されて防がれる。ぶっちゃけアンインストールすればいいんだけど、「お前さんそこまで自制心ないのか」という心の声が聞こえるので、アンインストールする気持ちが起きない。
なかなかいいツールだな、と思ったんだけど、イケてないところもけっこうある。
- Chrome 拡張からスクリプトが挿入されるので、それがレンダリングをブロックして、ページが表示されるのが遅くなった
- サジェストされたドメインに amazon.com があって、制限された後に AWS のコンパネが開けなくなってしまった (サブドメを許可リストに追加すればいいんだけど、制限が解除されるまで追加できない)
- 上と同じで Twitter の API ドキュメントページが開けなくなってしまった
- 指定したドメインのトータルの閲覧時間ではなく、ドメイン毎に閲覧時間を設定できるようにしたい
- 毎日決められた時間に制限をリセットされるのではなく、制限された数時間後に制限を解除する、ような仕様にしてほしい。数時間に一回程度は開きたい
自分で作ってみてもいいんだけど、もし良い Chrome 拡張を知っていたら、教えてください。
13デイズを観た
WOWOW で放送してたので作業しながら観た。
- 出版社/メーカー: ギャガ
- 発売日: 2017/12/02
- メディア: Blu-ray
- この商品を含むブログを見る
小学生の頃、金曜ロードショーでやってたのを一度観たんだけど、政治的な駆け引きが当時の自分には難しくてあまり面白く感じなかった。歳を取ってから見ると面白かった。
一番おもしろかったのは、物語の開始直後、航空写真でミサイルが確認され、ケネディ兄弟と主人公のオドネルが初手を迫られるシーンだった。 彼らは、対応策を考えるために、各省の精鋭数名からなる機関を立ち上げる。その判断を下す際のやりとりで以下のような意図や思惑が見えた。
- 不確実性が高い状況においては、人数を増やせば増やすほど意思決定に時間がかかり、かつ、得られる結論もとんがった部分のない平凡なものでまとまってしまう
- 大統領の顔色を伺わないように、機関のミーティングには、必要なとき以外、大統領を呼ばない。これは心理的安全の確保に繋がる
その後は、後のケネディ暗殺の黒幕が軍部であることを匂わせるような演出があったり、ケネディ(兄)のカリスマ性に酔って酔って酔いまくってください、というかんじだった(あんまりちゃんと観てなかった)。
WebComponent を Vue コンポーネントツリーの末端として使う
JSフレームワークの末端がWebComponentsになるのか、なれるのか、検証してみた - Qiita の記事を読んで、Vue だとどうなるかな、と思って軽く検証した。自分の手に馴染んているのが Vue というだけの理由で、決して React dis ではないです( React は React で、そのうちいいかんじの仕組みが入るような気がする )。
結論、問題なく使えると思う。
そもそも WebComponent を末端で利用するモチベーションは?
現状、CSS フレームワーク、UI フレームワークがあり、そのフレームワークをラップして View フレームワーク( React
, Vue
, Angular
)のコンポーネントとして提供するライブラリをよく見かける( react-xxx
とか vue-xxx
みたいなの )。こういったライブラリの組み合わせは、UI フレームワークの数を M, View フレームワークの数を N とすると M * N の組み合わせになる。
各 View フレームワーク向けに 1 から UI フレームワークをコンポーネント化して、このようなライブラリを提供するのは効率が悪い。
また、View フレームワークの機能や仕様の差があるため致し方ない部分もあるが、提供されるコンポーネントの I/F が統一感のないものになってしまう。
これらの問題は、再利用可能な単位で WebComponent( Custom Element )を定義すれば、解決するような気がする。View フレームワークから直接利用してもよいし、そのコンポーネントを View フレームワークのコンポーネントしてラップしたライブラリを提供する場合でも、以前ほどのコストはかからず、フレームワーク間である程度統一された I/F になる。
ここでの WebComponent は、Python でいう アプリケーション・サーバーとフレームワークの間を取り持つ WSGI、Ruby でいう Rack のような立ち位置に近い。
Vue で WebComponent を使う
WebComponent で独自の要素を定義して使う。独自の要素といっても、普通の a
や button
といった要素と同じ I/F なので属性で値を渡して、要素の中で発生したことはイベントを通して知ればよい。
次の様なクリックされたらカスタムイベント my-click
を発火する WebComponent ( Custom Element ) を定義しておいて、
import { html, render } from '/node_modules/lit-html/lib/lit-extended.js'; const template = props => html` <style> :host { display: block; } </style> <div> <button on-click="${props.onClick}">${props.text}</button> </div> `; export default class MyButton extends HTMLElement { static get observedAttributes() { return ['text']; } constructor() { super(); this._shadowRoot = this.attachShadow({mode: 'open'}); } connectedCallback() { this.render(); } attributeChangedCallback() { this.render(); } render() { const text = this.getAttribute('text'); render(template({ text, onClick: this.onClick, }), this._shadowRoot); } onClick() { this.dispatchEvent(new CustomEvent("my-click", {bubbles: true, composed: true})); } } window.customElements.define('my-button', MyButton);
Vue のコンポーネントで以下のように使う。
import Vue from '/node_modules/vue/dist/vue.esm.browser.js'; Vue.component('home', { data() { return { value: 0, }; }, mounted() { setInterval(() => { this.value += 1; }, 1000); }, methods: { onClick() { console.log('onClick', this.value); }, }, template: ` <my-button v-bind:text="value" v-on:my-click="onClick"></my-button> `, });
v-bind
ディレクティブで、カウントしている値を text
属性の値としてバインディングして、v-on
ディレクティブで
my-button
コンポーネントから発火される my-click
イベントをハンドリングする。
Vue でのイベントハンドラの扱い
v-on
ディレクティブは、カスタムイベントを含む DOM イベントをハンドリングすることができる( 細かいけど、Vue コンポーネントの場合は Vue の持っているイベント機構で発火されたイベントもハンドリングできる )。
このディレクティブが肝で、React と違って、イベントハンドラの関数をコンポーネントに渡す必要がない(渡すこともできるが、あえてそうする必要がない)。
なので、WebComponent ( Custom Element ) へ関数を渡すことを考えなくてもよい。
最初に書いたモチベーションの場合、WebComponent を書く人間と、それを使う人間が分かれることがほとんどになるので、
WebComponent は、自身を使おうとしている View フレームワークや、それが関数を渡そうとしていること、あるいは関数を渡すための仕掛けについて、関心を持つべきではないし、コンポーネント自体の再利用性も鑑みると関数を引き渡すことは諦めたほうがいいのではないかと思う。将来的に双方で関数を渡したい・受け取りたいニーズが高まれば別。
WebComponent でのイベントリスナーの扱い
DOM 操作したくないので button 要素のクリックのイベントハンドラの管理も含め lit-extended
でだいぶ楽をしたが、extended ではない lit-html
( addEventListener
)を使う場合はこんなかんじになる。
import { html, render } from '/node_modules/lit-html/lit-html.js'; const template = props => html` <style> :host { display: block; } </style> <div> <button>${props.text}</button> </div> `; export default class MyButton extends HTMLElement { static get observedAttributes() { return ['text']; } constructor() { super(); this._shadowRoot = this.attachShadow({mode: 'open'}); this._shadowRoot.addEventListener('click', (e) => { if (e.target.tagName === 'BUTTON') { this.onClick(); } }); } connectedCallback() { this.render(); } attributeChangedCallback() { this.render(); } render() { const text = this.getAttribute('text'); render(template({ text, onClick: this.onClick, }), this._shadowRoot); } onClick() { this.dispatchEvent(new CustomEvent("my-click", {bubbles: true, composed: true})); } } window.customElements.define('my-button', MyButton);
button
要素にイベントリスナーを登録すると lit-html
が要素を差し替えることを考慮して(この例では考えなくていいかもだが)、適切なフックで都度 addEventListener
, removeEventListener
を呼ぶ必要がある。そこで、shadowRoot
に対してイベントリスナーを登録し、イベントを発生された要素に応じて、カスタムイベントを発火させるようにする。
shadowRoot
に登録するイベントリスナーが分岐だらけになりそうな気もするのだけど、コンポーネントの責務さえしっかり決まっていればさほど問題にならないような気がする。コンポーネントの状態管理が複雑になるのは、また別の問題。
正直、この例だったら lit-html
を使わず DOM API でも実装できるが、実際にコンポーネントを作ろうとしたら、もう少し複雑なものになって DOM API ではつらくなり lit-html
を使うことになると思うので試した。
色々書いたけれども、Vue では WebComponent が普通に使えると思うので、今のうちから各種 CSS フレームワーク、UI フレームワークの WebComponent( Custom Element )を定義したライブラリを作っておけば、後で重宝されるかもしれないですね。
マネー・ショート を観た
観た。
- 出版社/メーカー: パラマウント
- 発売日: 2017/02/08
- メディア: Blu-ray
- この商品を含むブログ (1件) を見る
サブプライム住宅ローン危機の発生を予測し、事前に空売り(実際は空売りではないんだけど)することで巨額の利益をあげた男たちの物語。実際のモデルがいる。
邦題の「華麗なる大逆転」や黄色いパッケージから、アウトロー達がウォール街のエリートたちに一泡吹かせる痛快ストーリーかと思ったが、全くそんなことはない。 そこにあるのは、アウトローたちの心の葛藤である。
彼らの全てが喜々としてトレードしたわけではない。世界経済の崩壊が起こることを確信し、このような事態を招いた連中への怒り、絶望といった負の感情を噛み締めながらトレードするのである。
物語の終盤では、自分たちの成功が、多数の人々が職・資産を失い露頭に迷う先にあることを自覚し、良心の呵責に苛まれる。また、危機がはじまり、いざ売り抜こうとする際に「ここで売って巨額の利益を上げたら、自分たちが一番憎んでいた連中と同じになるのではないか」と苦悩する。
スティーヴ・カレル、クリスチャン・ベール、 ブラッド・ピットの徹底的な役作り、巧みな演技がこれらの心の葛藤を見事に描いている。特にスティーヴ・カレルの演技が表情・声のひとつひとつの変化のレベルで良かった。また機会があったら見たい。
デヴィッド・リンチ:アートライフ を観た
観た。
不気味で、得体の知れないデヴィッド・リンチの発想はどこから生まれるのか。彼の生い立ちや絵の創作活動を通して探る作品。
彼が語る過去のエピソードに合わせて、彼の版画作品が映される。幼い頃の恐怖体験、住んでいた住居、フィラデルフィアの工業地帯、彼の創造力の源泉が過去にあることが分かる。ひとつひとつの作品に過去の体験に基づく物語があるのだ。
数日前に、ヒカリエでやっていたデヴィッド・リンチの版画展に行ってきたのだけど、正直、作品からそういった背景を掴み取ることがまったくできなかった。この映画を観た後に行けば、彼の過去の物語を思い浮かべながら作品を鑑賞できるかもしれない。
フィラデルフィアの風景の映像やそのときの暮らしぶりの話は、イレイザーヘッドを観たことがある人にとって、たまらないものに違いない。廃墟、差別主義、モノクロ、子供が生まれたばかりの夫婦の生活。あの不気味な映画は、その頃のリンチの心象を映像にしたものだ、ということがしっくりくる。
Vue.js で特定のプロパティを変更の追跡の対象外にする
きっかけ
とある案件で、とあるサードパーティの SDK を利用していた。その SDK が提供するコンストラクタから生成したインスタンスを Vue.js のインスタンスのデータとして扱おうとしたら、Security Error のような例外が投げられて困った。 (回避するために、インスタンスのデータとして扱わないように試みたのだけど、致し方ない理由で諦めた)
原因
Vue.js では、データの変更を追跡するためにプロパティを getter/setter に上書きする。ココらへんの話は リアクティブの探求 — Vue.js が詳しい。この上書きの処理はプロパティがオブジェクトの場合は掘り下げて再帰的に行われる。おそらく問題の起きたインスタンスでは、セキュリティの観点からこういった処理を防ぐ機構が入っていたのだと推測。すごいね。
解決
これまた公式ドキュメントなのだけど、Object.freeze
で追跡の対象外にできることを知ったので以下のようなコードを書いた(
Vue インスタンス — Vue.js )。
const foo = new ThirdpartyFoo(); const container = { foo, }; const vm = new Vue({ data() { return { container: Object.freeze(contianer), }, }, }); vm.container.foo;
はじめ foo 自体を Object.freeze
したのだけど、foo のメソッド呼び出しに伴うプロパティの変更ができなくなってしまった。そこで、容れ物のオブジェクトを用意して、元のオブジェクトを包むことにした。こうすることで、foo のプロパティの getter/setter への上書きは防ぎつつ、これまで通り foo のメソッドを呼び出すことができる。
これまで特に意識せず、様々なオブジェクトを Vue のインスタンスのデータとして扱っていたのだけど、変更を追跡する必要がない、オブジェクトのプロパティの階層が深い( getter/setter への上書きのコストが高い )オブジェクトは Object.freeze
で追跡の対象外にしてよいかもしれない。
個人サイトを nuxt で書き換え、netlify で公開するようにした
追記: 2018/03/28
唯一イケてなかったのは、netlify のビルドタスクを実行する環境の Node のバージョンが古いこと。async/await が使えず、プリレンダリングに失敗してしまった。これは、しょうがないので、dist もバージョン管理対象にした。
NODE_VERSION
環境変数をセットすることで、async/await が使える Node.js でビルドできた。Continuous Deployment | Netlify
経歴や職歴が書かれた個人サイト https://www.kitak.info に久しぶりに手をいれた。
元々、サイトジェネレーターの hugo を使ってサイトを生成し、VPS で公開していたのだけど、nuxt で書き換え、netlify で公開するようにした。以下、それぞれに関する個人メモ。
nuxt
プリレンダリングの機能があることを知って、前々からサイトジェネレーターとして使ってみたい気持ちがあった。
記事を markdown で書いていたので、プリレンダリング時に markdown から HTML を生成した。既存の markdown をレンダリングする Vue のライブラリは、slots や mounted hook を利用したクライアントサイドで実行する制約のあるものがほとんどだったので、実装は単純なのだけど、こんなかんじ( https://github.com/kitak/www.kitak.info-nuxt/blob/6af6c36755e75f98e641f614a18109f70f53a1d9/components/MdArticle.vue )の markdown-js をラップした Vue コンポーネントを用意した。別にクライアントサイドでレンダリングしてもよいのだけど、事前にレンダリングしておいたほうが表示が早いだろうという気持ちの問題。
/
にリクエストがきたときに /about
と同じ内容を表示したかった(内部リダイレクトしたかった)。nuxt では pages ディレクトリの構造 = ルーティングの設定なので、リダイレクト先のコンポーネントをそのまま返すようなコンポーネントを用意すればよい( www.kitak.info-nuxt/index.vue at 6af6c36755e75f98e641f614a18109f70f53a1d9 · kitak/www.kitak.info-nuxt · GitHub )。
netlify
作成したサイトを配信するために netlify を利用することにした。静的ファイルの配信に特化したサービス。総じてよかった。今回、自分が利用した機能については無料プランの枠で収まっている。
- 管理画面が使いやすい
- CDN で配信してくれる
- 独自ドメインのSSL証明書を Let’s Encrypt で取得してくれる
- パス毎にカスタムヘッダーの指定ができる
- (使っていないけど)SPA の Prerendering をしてくれる
- (使っていないけど)特定のパスだけ api に proxy できる。SPA の場合、ページと api の origin が同じになるので CORS でハマることがなくなる
唯一イケてなかったのは、netlify のビルドタスクを実行する環境の Node のバージョンが古いこと。async/await が使えず、プリレンダリングに失敗してしまった。これは、しょうがないので、dist もバージョン管理対象にした。