一発ネタですが、意外と直感的じゃないので。
/(a|b|c)/
上の正規表現は、キャプチャをあとで使わない場合、以下と同じです
/a|b|c/ /(?:a|b|c)/
ただし、前後になにかくっついている場合はもちろん異なります。
/(a|b|c)x/ /a|b|cx/ // これとは同じでない
一発ネタですが、意外と直感的じゃないので。
/(a|b|c)/
上の正規表現は、キャプチャをあとで使わない場合、以下と同じです
/a|b|c/ /(?:a|b|c)/
ただし、前後になにかくっついている場合はもちろん異なります。
/(a|b|c)x/ /a|b|cx/ // これとは同じでない
記事で紹介した内容をリポジトリにあげてあります。よろしければ参考にしてください。
たったこれだけでカレントディレクトリのpublicフォルダを公開するウェブサーバーを建てられます。
$ docker run -d -p 8080:80 -v $PWD/public:/usr/share/nginx/html:ro nginx
しかし、単にサーバーを立てるだけならわざわざ docker を使わずにもっと短くできます((python -m http.server 8080 ./public
で代用できます))。せっかく Nginx を使うのですから、設定ファイルを使いたいですよね。設定ファイルをマウントするには次のようにします。
$ docker run -d -p 8080:80 -v $PWD/public:/usr/share/nginx/html:ro \ -v $PWD/nginx.conf:/etc/nginx/nginx.conf:ro \ -v $PWD/conf.d:/etc/nginx/conf.d:ro nginx
しかし、これだけでは立ち上がる Nginx の prefix が /etc/nginx
になってしまうので、prefix を /usr/share/nginx
にして起動します。
$ docker run -d -p 8080:80 -v $PWD/public:/usr/share/nginx/html:ro \ -v $PWD/nginx.conf:/etc/nginx/nginx.conf:ro \ -v $PWD/conf.d:/etc/nginx/conf.d:ro nginx nginx -p /usr/share/nginx -g 'daemon off;'
さらに --restart=always
を付ければ再起動後も自動で立ち上がるようになります。
上のコマンドを docker-compose.yml で書くと次のようになります。
version: '3' services: web: image: nginx:alpine ports: - 8080:80 volumes: - ./public:/usr/share/nginx/html:ro - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./conf.d:/etc/nginx/conf.d:ro command: nginx -p /usr/share/nginx -g 'daemon off;'
これなら restart: always
をつけることで再起動後も自動で立ち上がるようにできます。
あとは docker-compose.yml と同階層でdocker-compose up -d
を実行するとサーバーが立ち上がります。
ネットワークをたててその中で完結させたい場合は以下のようにすると簡潔です。
$ docker create network -d bridge my-network $ docker run -d -p 8080:80 -v $PWD/public:/usr/share/nginx/html:ro \ --net my-network \ -v $PWD/nginx.conf:/etc/nginx/nginx.conf:ro \ -v $PWD/conf.d:/etc/nginx/conf.d:ro nginx \ nginx -p /usr/share/nginx -g 'daemon off;'
docker-compose.yml を使うと以下になります。
version: '3' services: web: image: nginx:alpine ports: - 8080:80 volumes: - ./public:/usr/share/nginx/html:ro - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./conf.d:/etc/nginx/conf.d:ro command: nginx -p /usr/share/nginx -g 'daemon off;' networks: default: external: name: my-network
external で指定してあるのは、このコンテナでネットワークを立ててしまうと、このコンテナを起点に依存関係ができてしまうためです。ネットワークを作るかわりに external で既存のネットワークを使えば、このコンテナは他のコンテナの起動状況に関わらず立ち上げることができます。また、他のコンテナもこのコンテナの起動状況に依存せずに済みます。
他のコンテナは、外部とはこのリバースプロキシを介して通信できるので、ports
の代わりにexpose
でポートをネットワーク内に公開するだけで良いです。
3 時間くらいハマったのでメモしておきます。
以下のようなコードを書いたら、変数が上書きされてうまくいきませんでした。
location /private { auth_request /auth/is_logged_in; resolver 127.0.0.11; set $upstream_server private; proxy_pass http://$upstream_server; } location = /auth/is_logged_in { resolver 127.0.0.11; set $upstream_server auth_server; proxy_pass http://$upstream_server; internal; }
上の設定では、/private の proxy_pass が/auth/is_logged_in のステータスがいくつかに関わらず常にhttp://private
ではなくhttp://auth_server
となります。なんということでしょう…Nginx の変数の仕様は複雑怪奇ですね。
そもそも同じ変数名にしなければ良いです。
location /private { auth_request /auth/is_logged_in; resolver 127.0.0.11; set $private_server private; proxy_pass http://$private_server; } location = /auth/is_logged_in { resolver 127.0.0.11; set $auth_server auth_server; proxy_pass http://$auth_server; internal; }
定数を定義できればこんな問題も起きなかったはずです。定数がほしいですね。
というか、評価順が直感的でなくて厄介です。動作から推察するに、おそらく次のような評価順です。
private
になるauth_server
になる直感的には「auth_requestが評価されたらただちにログイン判定」になりそうなものですが。なんじゃこりゃ…
混乱しがちだったのでまとめました。
ウェブアプリケーション開発においては、本番環境で不要なパッケージをインストールせずに済むからです。npm には dependencies に書かれたパッケージのみインストールする機能があるので、これを使ってインストール時間を短くできます。
また、本番環境に不要なものを置くのはセキュリティの観点から良くありません。
ライブラリ開発ではウェブアプリケーション開発と比べて、devDependencies の意味合いがやや異なります。devDependencies には、配布パッケージに含めるべきでないパッケージを書きます。ウェブアプリケーション開発ではビルド時間が縮むくらいの違いでした。しかし、ライブラリ開発では配布パッケージに含まれるか否かに関わるので、使い分けがとても重要です。
大抵、本番環境ではリポジトリをクローンしてきてビルドをするだけです。そのため、ESLint や Prettier は本番環境で使わないものは devDependencies に書きます。反対に、本番環境でも使いたいものは dependencies に書きます。
ただし、TypeScript には注意してください。TypeScript は build でも test でも使います。そのため、TypeScript関連のパッケージは一概に dependencies、devDependencies のどちらに含まれるか断定できません。一例をあげます。
実は、わざわざ本番環境でクローン&ビルドせずとも、開発環境でビルドしたものをそのまま本番環境へデプロイできます*1。この場合、そもそも本番環境でパッケージのインストールをしないので、そこまで使い分けを意識する必要はありません。
ただし、CI/CDをしている場合は注意が必要です。この場合は結局、本番環境でクローン&ビルドしているのと変わりません。そのため、上で紹介したように dependencies と devDependencies を使い分ける必要があります。
ライブラリ開発の場合は多少異なりますが、考え方としてはほぼ同じです。
ビルド関連ツールも devDependencies に含まれる点が異なっています。
まず、ウェブアプリケーション開発とライブラリ開発に大別されます。
*1:というより、本番環境でビルドせずに済むので、できることなら開発環境でデプロイできるようにするべきです
Defx.nvim には floating window を使ったイカしたプレビュー機能があります。しかし、何も設定をしていないと、defx を閉じたあともプレビューウィンドウは残ります。この記事は autocmd を活用してプレビューをうまく消そうという記事です。
Defx.nvim のウィンドウを閉じると同時にプレビューウィンドウを閉じるには、ウィンドウが閉じたことを検知する必要があります。ウィンドウが閉じたときに発火するイベントはいくつかあります。
Defx は独自に DefxClosed のようなイベントを発火しないので、これらを使わなければなりません。今回はBufHidden を使います。
BufHidden が発火したときに pclose (プレビューウィンドウを閉じるコマンド)を実行すればやりたいことが実現できます。
(BufLeave ではプレビューウィンドウを開いたタイミングにも発火するのでうまくいきません。また、BufEnter は defx のウィンドウが閉じられたのかを検知できません)
autocmd BufHidden \[defx\]* pclose
これで defx#do_action('quit')
などで閉じればプレビューウィンドウも消えます。
あまりに記事のボリュームが少ないので、ついでに全く関係ない Tips をいくつか盛っておきます。
Defx はデフォルトでは現在のディレクトリを表示します。しかし、プロジェクトルート(.gitなどのある位置)で開いたほうが便利ですよね?というわけで、 DefxProjectFile()
という関数を作りました。といってもほとんど fzf のリポジトリにある ProjectFiles を参考に書いただけですが。
nnoremap <silent> ,f :Defx `system('git rev-parse --show-toplevel 2> /dev/null')[:-2]` -search=`expand('%:p')`<CR>
quit をしてもファイラーウィンドウが残ってしまうのが嬉しいことはほとんどないので、ファイラーウィンドウのみになったら quit を実行するようにしてみました。
function! s:previewWindowOpened() abort for nr in range(1, winnr('$')) if getwinvar(nr, "&pvw") == 1 return 1 endif endfor return 0 endfunction autocmd WinEnter \[defx\]* if winnr('$') == 1 || winnr('$') == 2 && <SID>previewWindowOpened() | quit | endif
WinEnter が発火したとき、 defx のウィンドウのみ、あるいは defx ウィンドウとプレビューウィンドウのみだったら終了します。
previewWindowOpened関数はこちらを参考にして、一部動かなかった箇所を修正しています。