UUUM攻殻機動隊(エンジニアブログ)

UUUMのエンジニアによる技術ブログです

webサーバーとアプリケーションサーバーの関係を調べてみた

UUUMでエンジニアインターンをしている鷲見です。弊社では社内システムの一部をRailsを使って開発しています。なので今回はRailsで開発する上で必要な知識を一部書いてきます。

HTTP

私たちがwebページブラウザがwebサーバーに対してコンテンツを要求し、webサーバーは要求されたコンテンツをブラウザに対して返します。HTTPはこの一連のやりとりにおける通信のルール(プロトコル)です。この通信のルールが世界標準で決められているため、私たちはどの種類のブラウザであっても、世界中のどんなwebサーバーにもアクセスできるのです。

URI

URIとはwebに存在する情報を名前をつけて識別するためのルールのことです。URIを使うことでwebに存在する全ての情報は一意のもので表現することができるようになるます。HTTPはURIを使ってwebサーバーからほしいコンテンツを指定することができます。URIとURLの違いとしてはURIが情報の識別するルールに対し、URLがURIにのっとり情報の場所を示したものになります。

webサーバーとアプリケーションサーバー

webサーバー

webサーバーはブラウザからのコンテンツのリクエストを受け取り、ブラウザにレスポンスを返す役割のが役割です。このときのリクエストがHTML、CSS、画像ファイルのような更新しない限り同じ表示コンテンツを表示する静的なwebコンテンツだった場合、webサーバーが処理してレスポンスを返します。そしてクライアントごとで表示内容を変化させる処理が必要な動的なwebコンテンツの場合、webサーバーはアプリケーションサーバーへとリクエストを送ります。アプリケーションサーバーから返ってきた結果をレスポンスとして返します。webサーバーとして NginxとApacheなんかが有名です。

アプリケーションサーバー

アプリケーションサーバーは私たちが作ったRailsアプリケーションを動かしてくれるものです。webサーバーから送られてきたリクエストをアプリケーションサーバーからRailsアプリケーションに伝え、Railsアプリが処理した結果をwebサーバーに返します。ローカル環境下での開発の場合はPumaのようなRails用のアプリケーションサーバーのみを立てますが、本番環境ではwebサーバーをRailsアプリケーションの手前に置くことで、静的なコンテンツの処理を負担させることが多いです.RailsのアプリケーションサーバーとしてRainbows、Pumaなんかがあります。

Rack

RackはRuby製のフレームワークとアプリケーションサーバーの間に入り、互いをつなぐ役割をしてくれます。送られてきたHTTPのリクエストをサーバーはRackを使用しアプリにも理解できる形に変換して伝えてくれる。逆にアプリからのレスポンスはRackを通じてHTTPに変換されてサーバーに返ります。Rackを使用することでサーバーとフレームワークの組み合わせが自由になります。

全体の動き

ここまでのことをまとめるとブラウザから送られてきたリクエストをwebサーバーが受け取り、静的なwebコンテンツだった場合レスポンスをブラウザに返します。しかし、リクエストが動的なwebコンテンツの場合webサーバーでは処理せず、アプリケーションサーバーに送り、アプリケーションサーバーがRailsアプリにRackを通して伝えます。結果を先ほどとは逆の順番でブラウザに返します。

具体的に言うとブラウザからNginx、NginxからPuma、PumaからRackを通してRailsアプリに伝わります。レスポンスはこの逆の順序となります。

おわりに

プログラムは書いていけば理解が膨らみますが、知識関連はブログみたいに書かないと中々定着してくれないなーと常々思いましたー。

www.wantedly.com

ターミナルをインスタ映えするPokemonに変えよう!

こんにちは。2月入社の井上です。

今回のブログでは技術的なことではなく日常的な話題をしようと思うのですが、みなさんターミナルは何を使ってますか?

macデフォルトのターミナル、tmux、iTermなどなど、たくさんのターミナルがありますね。

日常用の僕のオススメはhyperです。

hyper.is

オススメの理由ですが、みなさんはターミナルに何を求めますか?

僕は✨✨インスタ映え✨✨です。

なんとこのhyper, ポケモンのpluginがあるんですよ!

f:id:iammyeye1:20190425123401p:plain

どうです??

インスタ映えじゃないですか??

hyperを導入してインスタ映え系エンジニアになっちゃいましょう!

hyperをインストールする

brew caskまたは公式サイトHyper™から入れちゃいましょう!

brew update
brew cask install hyper

hyper.jsを編集する

hyperをアプリケーションとして開くと、homeに.hyper.jsが生成されます。

そいつを編集しましょう。

vi .hyper.js

ファイルの下の方にプラグインの設定部分があるので、追加と書かれている部分を追記します。

    // for advanced config flags please refer to https://hyper.is/#cfg
    pokemon: 'random',   #追加
    pokecursor: 'false',   #追加
    unibody: 'false',  #追加
    poketab: 'true',   #追加
  },

  // a list of plugins to fetch and install from npm
  // format: [@org/]project[#version]
  // examples:
  //   `hyperpower`
  //   `@company/project`
  //   `project#1.0.1`
  plugins: ['hyper-pokemon'],  #追加

  // in development, you can create a directory under
  // `~/.hyper_plugins/local/` and include it here
  // to load it and avoid it being `npm install`ed
  localPlugins: [],

  keymaps: {
    // Example
    // 'window:devtools': 'cmd+alt+o',
  },
};

自分の.hyper.jsの設定はこれです!! gist:2e6c6953ff03c0f8c22c0392f2f76ef4 · GitHub

追加部分の簡単な説明

    pokemon: 'random' #壁紙のポケモンの種類を指定
    pokecursor: 'false',   #trueだとカーソルをポケモンにしてくれるらしい(僕の端末では動かなかったです)
    unibody: 'false',  #headerの部分の色を壁紙と揃えるか
    poketab: 'true',   #タブの部分でgifのポケモンアイコンを表示するか

使ってみる

そうすると、ポケモンのテーマがこんな感じで適用されるはずです!

f:id:iammyeye1:20190425125548p:plain

先ほどのセットアップでは、hyperの起動のたびにポケモンが変わる仕様になっています。

またcommand + Shift + u で、好きなタイミングでポケモンを変更することができます。

最高!!

今は関東地方のポケモンのみが壁紙になっているようですが、次に壁紙になる地方は投票で決めるっぽいです!!

## Vote the next Region

Vote for the Pokémon Region you want to see themes from next.<br/>
In essence, this poll will determine the creation order of all Pokémon Regions.<br/>
The poll will be kept alive until the project's completion, when all **600+** themes will be available.

投票状況↓

https://m131jyck4m.execute-api.us-west-2.amazonaws.com/prod/poll/01BMH8W2ETBFXQ9H6PSS0X9VZ8/Johto https://m131jyck4m.execute-api.us-west-2.amazonaws.com/prod/poll/01BMH8W2ETBFXQ9H6PSS0X9VZ8/Hoenn https://m131jyck4m.execute-api.us-west-2.amazonaws.com/prod/poll/01BMH8W2ETBFXQ9H6PSS0X9VZ8/Sinnoh https://m131jyck4m.execute-api.us-west-2.amazonaws.com/prod/poll/01BMH8W2ETBFXQ9H6PSS0X9VZ8/Unova https://m131jyck4m.execute-api.us-west-2.amazonaws.com/prod/poll/01BMH8W2ETBFXQ9H6PSS0X9VZ8/Kalos

以下に投票用リンクを貼っときます!!

ジョウト地方

ホウエン地方

シンオウ地方

イッシュ地方

カロス地方

終わりに

hyperは普通のターミナルですので、日常でターミナル使いたいな〜って思った時にポケモンのプラグイン入れてサクッと使ってみてください!!

ターミナルはhyper、君に決めた!




参考記事

Hyper Store - hyper-pokemon

爆速でターミナルをポケモンにする - Qiita


www.wantedly.com

RubyKaigi2019 に参加してきました

こんにちは、趣味エンジニアのめる(@c5meru)です!
UUUMに入社して1年と2ヶ月が経とうとしていますが、自分が入社した時、現場のエンジニアは5人くらいしか居なかったのに、いま数えてみたら現在22人もいるようで、そのスケールの違いに圧倒される日々を送っています。

さて、自分は先日、会社のカンファレンス参加制度を利用して RubyKaigi2019 に参加してきました。
今回が初めての RubyKaigi なので書きたいことがたくさんあるのですが、こちらのUUUMエンジニアブログでは、1日目に行われた、まつもとゆきひろさんのKeynoteでお話があった内容について書かせていただきたいと思います!

The Year of Concurrency by Matz

f:id:c5meg1012:20190420115628j:plain

  • Rubyは「だいたいのことにはいい」
  • チームやプロダクトが大きくなるとデメリットが見えてくる
  • 他の言語と比較して遅いのは、マルチコアを活用できていないから
  • Github cookpad Airbnb などもRubyを使っている
    • これらよりパフォーマンスを求められるサービスはあまりない
    • だから「十分に速い」とも言える
  • パフォーマンスが良くないっていう人もいるけど、特筆する例はTwitterの一件だけ
    • しかも古いバージョンであった1.8を使い続けていたケース
  • Rubyは今までも性能の改善を続けてきたし、Ruby3でも改善を進めている
    • Ruby3のポイント
      • 静的解析
      • パフォーマンス改善
      • Concurrency

静的解析

  • プロジェクトが大きくなってくるとテストのサイズや実行時間が長くなって苦痛になってくる
    • Matzはテスト嫌い、できれば書きたくない
    • DRYじゃないし
    • でも人類は間違いのないプログラムをまだ書けないから仕方がない
  • JSのTypescriptや、他の言語でもtype hintingがある
  • Matzは型宣言が嫌い、できれば書きたくない
    • DRYじゃないし
    • コンピュータに仕事させられてる感じがする
    • だからここは妥協したくない
    • なくてもプログラムを書くことはできるから
    • けどできるようにするために進めている
      • 型定義シンタックス .rbi
      • 静的型チェッカー
        • Stripe さんの Sorbet と soutaro さんの steep がある
        • rbiに対応できるように進めている
      • 型宣言を書かなくても型チェックができるように進めている
        • Gems で型定義ファイルを配布すれば、既存の型情報はカバーできるから

パフォーマンス改善

  • alibabaでもRubyは使われているらしい
  • メモリがボトルネック
    • なのでGC周りの改善、キャッシュの改善をすすめている
  • CPUもボトルネック
    • 昨年はMJITを導入、メリットもあったがデメリットも多くあった
    • Ruby2.6ではベンチマークで使っているファミコンエミュレータは2.8倍早くなる
      • RailsなどのWebアプリケーションは、たくさんメソッドがあってコンパイルする量が多くなるので遅くなる
      • PHP8のパフォーマンス改善も同様だそう

Concurrency / 並行性

  • IOボトルネック
  • 現状の Thread/Fiber にも課題を感じている
    • オブジェクトを今からイミュータブルにはできない、過去の経緯があり破壊的変更になってしまう
    • Guild(仮称)をつかう
      • ゲーム業界から反対が出た(このClass使ってるんだけど)
    • frozen objectのようなイミュータブルなものだけ送れるように
    • GuildはJSでいうwebworkersみたいなもの
    • Guildは慣れるまでは使いづらい、IOボトルネックを解消するにも使いづらさがある
    • シングルスレッドのNode.jsはどうしているのか
      • ノンブロッキングIO
      • V8のパフォーマンス
    • AutoFibers(仮称)でIOブロッキングを避けられるようにすすめている
      • Goはgoroutine
      • Elixirはprocess
    • Rubyはそういうのを当初考えていなかった、破壊的変更を避けるために、気をつけながら改善している

メンテナンス方針

  • 互換性を維持しながら改善するのは難しい
    • Ruby3、その先も、いろいろ改善してRubyをGreatにしたい
    • Frozen String Literalsは3.0がデフォルトにはまだできなかった
    • emacsからもってきた '?' literalsも、3.0では消せなかった
    • バッククオートも、3.0では消せなかった
    • キーワード引数は、3.0で変わる
      • もともと直感的でなくわかりづらいと思ってた
      • 静的型付けと相性が悪そう
      • 大きな非互換になる見込み
        • 2.7から警告を出すそう
    • numbered block parameter
      • すでに trunk では導入されているが、議論が続いている
      • まだやらない
    • パターンマッチング
      • 昨日 trunk にマージされた
  • Rubyは生き残らなければならない
    • わたしたちはRubyが好きだし
    • Rubyのプロダクトがすでにたくさんあるし
    • わたしたちはRubyでご飯食べてるし
      • でもみなさんは、JSでもPythonでも使ってもらっていいんですよ
      • わたしたちコミッターは、Rubyがなくなったら本当に困る
    • よりよい、よりたのしい、より生産的な言語に
      • Rubyを使うことがメリットになるように
    • たまに後悔するような実装もしてしまう
      • キーワード引数、Threadなど
      • ユーザーが多いから直しづらい
      • もう間違えないようにしなくては、と慎重にやっている
      • みなさんの意見をないがしろにしたくない
      • 決まってからでは変えられないので、決まる前にどんどん意見を言ってほしい
    • 最近はもどかしいけれど、Matz自身は設計だけ考えて、実装は他のコミッターにやってもらってる
      • Cが書ける人がいたらぜひ参加してほしい

その他

Keynoteの次のセッション「Ruby 3 Progress Report」では、上記よりもさらに踏みこんだ、Ruby3の開発進捗がお話しされました。
Matzさんとは対照的に、自分はテストも静的解析も好きなので(笑)、特に静的解析の仕組みは非常に興味深く、Ruby3が今から待ち遠しくなりました!
上記にもあったキーワード引数の破壊的変更では、この変更だけのために何度も何度も開発者会議が開かれたという話を聞いて、日頃わたしたちが使っているRuby(などのプログラミング言語)は、たくさんの方が時間をかけて作ってくださったものなんだな、ということを実感しました。ありがたや...!
また、RubyGemsのアカウント乗っ取りが多発しているという注意喚起もあり、RubyGemsアカウントを持っている方は、必ず2段階認証を設定してほしいということでした!

まとめ

セッション以外のことについては、個人ブログの方に書かせていただきましたが、全体的にお祭り感もあって非常に楽しいカンファレンスでした!
RubyKaigiをもっともっと楽しむには、Rubyのしくみを読んだり、(関連するセッションが多い)mrubyを押さえておいたり、英語力をがんばって高めておくと良いだろうな、と思ったので、今後参加される方は参考にしていただければと思います!


www.wantedly.com

GraphQLをはじめよう!

皆さんは普段、WEBでAPIを作っていますでしょうか? 最近はリッチなUIやスマートフォンアプリの開発が当たり前になってきたので、 APIを作ることが多いのではないでしょうか。

APIの開発を楽にするために、GraphQLを使ってみませんか?

現状のAPI開発の悩み

現在APIを作るときは、REST設計で開発を行うことが多いと思います。 実際開発中に以下のような悩みを持ったことはないでしょうか?

  • API多すぎ
  • 仕様がよく変わる
  • ドキュメントがメンテできない
  • もうRESTのAPI作るの飽きたよ…

そんなあなたにぜひGraphQLを! GraphQLを使えば楽しいAPI開発が待っているかも!

GraphQLって何?

答: A query language for your API. (出典: GraphQL )

以上です!(^o^)

……要するに、SQLみたいにクエリを書いて、サーバにリクエストして、 自分が欲しいデータを取って来たり、変更するということができるものです!

GitHub GraphQL API を試そう!

GraphQLがどういうものなのかを知るためには、GitHubが公開しているGraphQL APIを試してみるのがわかりやすいと思います。

そこで、GitHubのAPIを使ってGraphQLがどのようなものなのか試してみましょう!

GraphQL API Explorer | GitHub Developer Guide

上のURLにアクセスして、右上の Sign in With GitHub からログインしましょう。 ログインするとすぐに使用できるようになります。

f:id:m-suzukix:20190418192948p:plain

左上がクエリエディタになっていて、ここにサーバにリクエストするクエリを書いていきます。 右側は、サーバからのレスポンスが表示されます。

自分のアカウント情報を取得する

ではクエリエディタに下のものをコピーして貼り付けて、実行してみましょう!

  • クエリ
query {
  viewer {
    name
  }
}

実行は 再生ボタン みたいなのがあるので押すと実行されます。

f:id:m-suzukix:20190418192929p:plain

実行すると下の様なレスポンスが返ってくると思います。

  • レスポンス
{
  "data": {
    "viewer": {
      "name": "masa"
    }
  }
}

ここにさらに、アバターURLを取ってみましょう!

  • クエリ
query {
  viewer {
    name
    avatarUrl
  }
}
  • レスポンス
{
  "data": {
    "viewer": {
      "name": "masa",
      "avatarUrl": "https://avatars2.githubusercontent.com/u/47341025?v=4"
    }
  }
}

追加で登録してあるアバターのURLが取得できました!

このように自分が欲しい情報に合わせて、クエリを書くことでレスポンスを調整することができるのがGraphQLの特徴になります。 SQLのSELECT文をイメージしていただくと、わかりやすいのではないかと思います。

query とは?

ここで、先程からエディタに書いてたものは、どのような構造をしているのかを見ていきましょう。

まず query についてです。

query {
  viewer {
    name
  }
}

query はデータを取得するリクエストであることを示しています。 SQLではデータを取得する時に必ず SELECT を書くと思いますが、GraphQLでは必ず query を書くことになります。

この query の中には viewer という指定がありますが、 これは viewer というデータを返してくれというリクエストになります。

上の query をSQLで書くと下のような感じになります。

SELECT name FROM viewer

viewer の中身

viewer の中には nameavatarUrl など指定ができましたが、他にはどんなものが指定できるのか気になると思います。

これを調べるために、このAPIコンソールには便利なドキュメントビューワーが付属されています。

エディタの右端に Docs というボタンがあるので押すとドキュメントを見ることができます。

f:id:m-suzukix:20190418194312p:plain

開いたら、viewer を検索してみましょう!

f:id:m-suzukix:20190419114854p:plain

すると Query.viewer が出てくると思います。 これをクリックすると、詳細が見れます。

f:id:m-suzukix:20190419114914p:plain

認証中のユーザ情報が返ってくることがわかりました! その下に TYPEUser! というのがあるので、TYPEについて説明します。

Type

型の指定のことです。これはClassのようなものとイメージするとわかりやすいです。 ルールは以下のようになっています。

type 型名 {
  名前: 型
}

型を構成する Field を書くことができます。 先程の User! の中身を見てみましょう。

f:id:m-suzukix:20190419114936p:plain

FIELDS にどんなデータなのかの指定があります。 先程指定した name , avatarUrl だけ定義してみると下の形になります。

type User {
  name: String
  avatarUrl: URI!
}

後ろに ! があるのは NULL不許可 を示しています。 avatarUrl を指定すると必ず URI型 のデータが返ってきます。 URI型 もドキュメントからどんな型なのか見ることができます。URIの定義に則った文字列が返ってくることがわかると思います。

データを更新する

APIではデータを作成、更新、削除したりすることがありますが、 GraphQLではこれらは mutation で指定する形になります。

mutation {
  ここにどの操作を行うかを書く
}

リポジトリにスターを付けてみる

addStar というスキーマが用意されているので、これを使うとGitHubのリポジトリにスターを付けることができます。

まずドキュメントを使って仕様を確認してみましょう。

f:id:m-suzukix:20190419114952p:plain

Mutation.addStar が表示されます。

f:id:m-suzukix:20190419115002p:plain

ARGUMENTS に指定する引数が書かれています。 addStar には inputAddStarInput! が必須であるとわかります。 (AddStarInputの後ろに ! が付いているからです)

f:id:m-suzukix:20190419115012p:plain

AddStarInput の中身を見ていくと、starrableIdID型 で必須ということがわかります。 ID型 はGraphQLの組み込み型で、通常はbase64エンコードされた文字列が使われるようです。

このIDはリポジトリごとにユニークなものが振られています。 スターを付けるためには、このリポジトリのIDを取得する必要があります。

以下のクエリで取ってこれます。

query {
  viewer {
    repository(name: "pokemon") {
      id
    }
  }
}

このクエリは自分が所持しているリポジトリの名前が pokemon であるものを取得するものになります。

レスポンスは以下になります。

{
  "data": {
    "viewer": {
      "repository": {
        "id": "MDEwOlJlcG9zaXRvcnkxODAyNTUzNDk1="
      }
    }
  }
}

ここで取ってこれたIDを使います。 スターを更新する構文は以下になります。

mutation {
  addStar(input: { starrableId: "MDEwOlJlcG9zaXRvcnkxODAyNTUzNDk1=" }) {
    clientMutationId
  }
}

これを実行するとスターが付くかと思います! 仕様通りに addStar の引数に input: { starrableID: "ID" } の形式で指定を行っています。

GraphQLでは addStar のような構文でも 必ず返り値を指定する ことになっています。 しかし更新系のスキーマでは返り値が不要なこともあるかと思います。 そこで、clientMutationId という指定をすることで、NULL の返り値をレスポンスとして受け取ることができるようになっています。

このスキーマのレスポンスは以下の様になります。

{
  "data": {
    "addStar": {
      "clientMutationId": null
    }
  }
}

この他にも、スターを外したり、PullRequestにコメントを付けたりするスキーマなどが用意されています。 ドキュメントを調べて実際に使ってみると、GraphQLが何となくわかってくるかと思います。

実装するには

各プログラミング言語用のライブラリが用意されているので、これを使うことでGraphQLの実装を行うことができます。

Code | GraphQL

また、Applo EngineAWS AppSyn のようにGraphQLを使う環境が既に用意されていて、後はデータやスキーマを用意するだけで簡単に利用することができるサービスもあります。

まとめ

GitHubが公開しているGraphQLを使ったAPIのご紹介をしました。 GraphQLはまだまだWEB上で知見があまりなく、自分でGraphQLを作る時にどうやって実装して良いのか悩むことがあるかと思います。

そんな時には既に GitHubのAPIの仕様を参考にして開発してみるといい感じに実装ができるのではないかと思います!

www.wantedly.com

Webpackerについてちゃんと調べてみた

カイシャで唯一 Emacs を使ってる✨✨✨✨キラキラエンジニア✨✨✨のtakeokunnです。

ギョームで webpacker を使っているのですが、中のコードを読む機会があったのでせっかくだからまとめてみました✨✨✨✨✨


コードについて書く前に、そもそも Webpacker がどんな機能を提供しているか書く。

READMEによると:

Features
* webpack 4.x.x
* ES6 with babel
* Automatic code splitting using multiple entry points
* Stylesheets - Sass and CSS
* Images and fonts
* PostCSS - Auto-Prefixer
* Asset compression, source-maps, and minification
* CDN support
* React, Angular, Elm and Vue support out-of-the-box
* Rails view helpers
* Extensible and configurable

これ入れとけば最新のwebpack使えて諸々の設定省いて最新 javascript をいい感じにrailsに組み込める!って書いてある。すっごーい✨✨✨✨✨


Webpacker のコードを追ってみる。$ ./bin/webpack が実行されてから webpackbundle.js が生成されるまでを見ていく。

./bin/webpack:

#!/usr/bin/env ruby

ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
ENV["NODE_ENV"]  ||= "development"

require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", Pathname.new(__FILE__).realpath)

require "rubygems"
require "bundler/setup"

require "webpacker"
require "webpacker/webpack_runner"
Webpacker::WebpackRunner.run(ARGV)

諸々の設定をしたあと、Webpacker::WebpackRunner.run(ARGV) が実行されている。

lib/webpacker/webpack_runner.rb抜粋:

def run
  env = Webpacker::Compiler.env

  cmd = if node_modules_bin_exist?
    ["#{@node_modules_bin_path}/webpack"]
  else
    ["yarn", "webpack"]
  end

  if ARGV.include?("--debug")
    cmd = [ "node", "--inspect-brk"] + cmd
    ARGV.delete("--debug")
  end

  cmd += ["--config", @webpack_config] + @argv

  Dir.chdir(@app_path) do
    Kernel.exec env, *cmd
  end
end

ここではもともと引数で渡していたものを元に webpack のcommandを生成して、 Kernel.exec env, *cmd で実行をしている。

@webpack_config の定義元について調べてみる。

lib/webpacker/runner.rb抜粋:

def initialize(argv)
  @argv = argv

  @app_path              = File.expand_path(".", Dir.pwd)
  @node_modules_bin_path = ENV["WEBPACKER_NODE_MODULES_BIN_PATH"] || `yarn bin`.chomp
  @webpack_config        = File.join(@app_path, "config/webpack/#{ENV["NODE_ENV"]}.js")

  unless File.exist?(@webpack_config)
    $stderr.puts "webpack config #{@webpack_config} not found, please run 'bundle exec rails webpacker:install' to install Webpacker with default configs or add the missing config file for your custom environment."
    exit!
  end
end

Railsconfig/webpack/#{ENV["NODE_ENV"]}.js から取得している。

config/webpack/development.js:

process.env.NODE_ENV = process.env.NODE_ENV || 'development'

const environment = require('./environment')

module.exports = environment.toWebpackConfig()

toWebpackConfig の定義元はここ: https://github.com/rails/webpacker/blob/b041a1d3e53c55ad801654892c99f5ec4ff099f2/package/environments/base.js#L150-L165

entry, plugins, module, resolve などをまとめて webpack.config.js を吐き出している。

config/webpack/environment.js:

const webpack = require('webpack')
const { environment } = require('@rails/webpacker')

environment.loaders.get('sass').use.splice(-1, 0, { loader: 'resolve-url-loader' });

environment.plugins.prepend(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    jquery: 'jquery',
    Popper: ['popper.js', 'default']
  })
)

module.exports = environment

ここで webpack の設定を書く。

記述の仕方は公式ドキュメントにある: https://github.com/rails/webpacker/blob/master/docs/webpack.md

以上が Webpacker$ webpack --config webpack.config.js の一連の処理だ。


次にRailsとのつなぎ込みの部分を見ていく。

<%= javascript_pack_tag 'application' %>
<%= stylesheet_pack_tag 'application' %>

上記のようにlayout部分に記述するといい感じに bundle.js を読み込んでくれる。

javascript_pack_tag の定義元を読む。

lib/webpacker/helper.rb抜粋:

def javascript_packs_with_chunks_tag(*names, **options)
    javascript_include_tag(*sources_from_manifest_entrypoints(names, type: :javascript), **options)
end

def sources_from_manifest_entries(names, type:)
    names.map { |name| current_webpacker_instance.manifest.lookup!(name, type: type) }.flatten
end

current_webpacker_instanceWebpacker::Instance のインスタンスだ。

lib/webpacker/instance.rb抜粋:

class Webpacker::Instance
    def initialize(root_path: Rails.root, config_path: Rails.root.join("config/webpacker.yml"))
        @root_path, @config_path = root_path, config_path
    end
end

config/webpacker.yml を読み込んでいる。

current_webpacker_instance.manifest.lookup!(name, type: type) の処理を追ってみる。

lib/webpacker/manifest.rb抜粋:

class Webpacker::Manifest
    # Computes the relative path for a given Webpacker asset using manifest.json.
    # If no asset is found, returns nil.
    #
    # Example:
    #
    #   Webpacker.manifest.lookup('calendar.js') # => "/packs/calendar-1016838bab065ae1e122.js"
    def lookup(name, pack_type = {})
compile if compiling?

find(full_pack_name(name, pack_type[:type]))
    end

    # Like lookup, except that if no asset is found, raises a Webpacker::Manifest::MissingEntryError.
    def lookup!(name, pack_type = {})
lookup(name, pack_type) || handle_missing_entry(name)
    end

    def full_pack_name(name, pack_type)
        return name unless File.extname(name.to_s).empty?
        "#{name}.#{manifest_type(pack_type)}"
    end

    def find(name)
        data[name.to_s].presence
    end
end

この lookup! 部分でpath解決をしている。 webpack をしてない状態でrenderingした時に compile が走るのはこの部分が原因みたいだ。

webpack 側の output はどうなっているだろうか。

package/config.js抜粋:

const configPath = resolve('config', 'webpacker.yml')

const config = deepMerge(defaults, app)
config.outputPath = resolve(config.public_root_path, config.public_output_path)

config/webpacker.yml を元に output 先を指定している。

webpack 側も rails 側もお互い config/webpacker.yml を元にしてるためpathを解決することができる。


webpack のconfigを拡張していくとなると結構大変だけれども、特に弄らないなら導入も運用も楽で良いですね!

create-react-app のように eject 出来るように( webpack のみの運用)なってくれるともっと運用が楽になると思います。

へーしゃでは emacs を使うのが好きなエンジニアを切に募集しています✨✨✨✨✨✨✨

一緒にインスタ映えする emacs を作りましょう✨✨✨✨✨✨✨

View this post on Instagram

インスタ映えするemacs

@ takeokunnがシェアした投稿 -

詳しくはこちら

www.wantedly.com www.wantedly.com

今年も合宿にいきました!

こんにちは。2月入社でシステムユニット所属の井上です。

今日のテーマは合宿です!!

システムユニットでは年に2回、開発旅行合宿があります。

合宿ではテーマが設定されており、テーマに沿って自分の好きなプロジェクトの開発だったり、新技術の勉強などそれぞれが自由に研鑽します。

今回はその一環として2/22(金)~2/23(土)に、UUUM攻殻機動隊のエンジニア達で開発合宿に行ってきました。

今回の合宿場は、神奈川県の箱根にある「COLONY 箱根」でした。

施設紹介

企業の研修用の施設らしく広々としていました。また箱根名物の温泉もありました。

そしてラッキーなことに利用者は他におらず(!!)貸切りのような状態で利用することができました。

簡単に施設紹介をします。

お昼ご飯

f:id:iammyeye1:20190225192101j:plain
お昼ご飯

広間 

f:id:iammyeye1:20190225194458j:plain:h551:w681
広間

温泉

f:id:iammyeye1:20190225193734j:plain:h551:w681
温泉

訪問した施設はこちらです。

colony-hakone.com

開発合宿では何をしたのか?

ここからが本題ですが、今回の開発合宿のテーマは「自由開発」でした。

今回の合宿も前回に引き続き、それぞれが一つのプロダクトを開発しました。

お昼ご飯をいただいて2時ごろから雑談混じりで開発は始まり、次第にそれぞれの開発に集中していきました。

f:id:iammyeye1:20190225193857j:plain:h551:w681
開発風景

みんな自由に開発しています!

夕飯・温泉後

18時半の夕ご飯で一旦休憩。

f:id:iammyeye1:20190225192051j:plain
豪華な夕御飯

温泉に入るなど各自で休憩を挟みつつ開発を続けます。 温泉とマッサージ機は凶器ということも知りました。

f:id:iammyeye1:20190225193907j:plain
開発デスマーチ開発を楽しんでる様子

開発の合間の一枚です!

楽しそうな笑顔〜。

しかし開発が進まず5時ごろまで開発をしていた人も、、、

2日目

朝から豪華な食事をいただき、開発の最終調整と発表資料を作成して10時半から発表開始です。

僕は遅くまで起きていたので寝不足で食欲がなく、ご飯は2杯しか食べれませんでした、、、(美味しかったです)

f:id:iammyeye1:20190225192332j:plain
朝食

発表風景

最後にそれぞれが発表資料をスライドで作り、プロダクトのデモンストレーションなども交えながら発表しました!

f:id:iammyeye1:20190225193929j:plain
個人的に一番好きだったプロダクトを開発されたメルさんの発表

こんな感じで発表会が行われました。

発表では、技術的にはAWS, Rails, Lambda, bulma, dockerなど様々な分野に渡り、開発物も自分が欲しいプロダクト、業務効率改善用プロダクト、日頃の業務で関わることの少ないライブラリを試してみた開発など十人十色でした。

結果として幅広い分野の発表となり、非常に知的好奇心を刺激しあう発表でした。

まとめ

まず2日間に渡り開発に集中できる素晴らしい環境を整えてくださった施設の皆様ありがとうございました。

合宿全体に関してですが、まとまった時間を設けて勉強することのできる非常に貴重な機会でした。

発表を通じてそれぞれの成果や知識の共有をすることで、チーム全体で大きく成長できたのかなと思います。

また2日間一緒に過ごしたことでコミュニケーションが活発になったのも良かったと感じています。

個人的に非常に楽しかった合宿でした。

最後は集合写真でもって締めさせていただきます。

f:id:iammyeye1:20190225192239j:plain

また参加したい〜。

www.wantedly.com

すごいTerminal 楽しく学ぼう!

最近Terminalが楽しい takeokunn です。

社内勉強会の順番が回ってきたので、せっかくだから最近ハマってるterminalについて語っちゃおうかなーと思いスライドを作りました!

インスタ映えしちゃうterminalを創ってスタバでドヤ顔したいですね!

スタバといえば、木下ゆうかさんの動画!

↑チャンネル登録しよう

www.wantedly.com