LoginSignup
26
8

More than 5 years have passed since last update.

😀🌏👚‍🔧📖 🌊🔧💧🕞◀🌐▶🌊

Posted at

😄❗ 🙂❀😀📝🌐📄😀


タむトル日本語蚳 絵文字の䞖界を䜜った話 h2oの蚭定方法ずWeb Components
䞊の文の日本語蚳 こんにちは 私は絵文字が倧奜きなので、絵文字でりェブペヌゞを䜜っおみたした。

【単語】😀 絵文字 / 👚‍🔧 䜜る / 📖 話 / 🔧 蚭定する / 📝 曞く / 🌐📄たたは🕞📄 りェブペヌゞ


ずいうのは冗談ですが、少し前に以䞋の🌐📄を䜜成したので、少しですがそのずきの知芋を共有しようず思い蚘事を䜜りたした。

発端

発端は私のこのツむヌトです。

芁するに「拡匵子が絵文字だったら面癜いんじゃね」的なこずを蚀ったわけですが、数ずしおは倚くないものの100RTくらいされるず肯定的な反応や吊定的な反応が飛んできたす。そこで、ずりあえずやっおみたのが冒頭で玹介したりェブペヌゞです。

ペヌゞのアドレスに泚目しおみおください。トップペヌゞはよく芋るず「index.📄」です。拡匵子が「.📄」になっおいたすね。たた、゜ヌスを芋おもらえるず分かるのですが、CSSファむルが「styles.💄」ずなっおいたり、画像ファむルが「card.🖌」ずなっおいたりしたす。

この蚘事では、このように絵文字を拡匵子ずしお䜿うりェブサヌバヌの蚭定を玹介したす。䜿甚するりェブサヌバヌはH2Oです。ずいっおも、そんなに倉なこずをやっおいるわけではないのでH2Oの蚭定方法玹介みたいになりたすが。

H2OはHTTP2にいち早く察応した新進気鋭のりェブサヌバヌずしお知られおいたす。冒頭のサむトも、もちろんHTTP2で配信しおいたす1。この蚘事の内容は、H2Oをただちゃんず䜿ったこずのない方なら、たあこんな颚に蚭定するんだよずいう参考にはなるのではないかず思いたす。

H2Oの蚭定

たずH2Oの蚭定ファむルを茉せたす。これが関連する蚭定の党おです。

main.yml
reproxy: on
"xn--vg8h70c.uhyo.space:443":
  listen:
    port: 443
    ssl:
      <<: !file commons/ssl.yml
  header.add: "Strict-Transport-Security: max-age=31536000"
  file.index:
    - "index.📄 "
    - "index.html"
  paths:
    "/":
      mruby.handler-file: sites/xn--vg8h70c.uhyo.space/handler.rb
      file.dir: /var/www/xn--vg8h70c.uhyo.space
"xn--vg8h70c.uhyo.space:80":
  listen:
    port: 80
  paths:
    "/":
      redirect: "https://xn--vg8h70c.uhyo.space/"
handler.rb
lambda do |env|
    if env["PATH_INFO"] == "/"
        return [301, {
          "location" => "/index.📄 ",
        }, []]
    end
    if env["PATH_INFO"] == "/index.html"
        return [399, {
          "link" => "</elements.%F0%9F%93%9C>; rel=preload, </styles.%F0%9F%92%84>; rel=preload"
        }, []]
    end

    if /^(.*)\/([^\/]*)\.%F0%9F%93%84$/.match(env["PATH_INFO"])
      return [307, {"x-reproxy-url" => "#{$1}/#{$2}.html"}, []]
    end


    if /^(.*)\/([^\/]*)\.%F0%9F%93%9C$/.match(env["PATH_INFO"])
      return [307, {"x-reproxy-url" => "#{$1}/#{$2}.js"}, []]
    end


    if /^(.*)\/([^\/]*)\.%E2%9A%99(?:%EF%B8%8F)?$/.match(env["PATH_INFO"])
      return [307, {"x-reproxy-url" => "#{$1}/#{$2}.js"}, []]
    end


    if /^(.*)\/([^\/]*)\.%F0%9F%92%84$/.match(env["PATH_INFO"])
      return [307, {"x-reproxy-url" => "#{$1}/#{$2}.css"}, []]
    end


    if /^(.*)\/([^\/]*)\.%F0%9F%8E%A8$/.match(env["PATH_INFO"])
      return [307, {"x-reproxy-url" => "#{$1}/#{$2}.gif"}, []]
    end


    if /^(.*)\/([^\/]*)\.%F0%9F%93%B7$/.match(env["PATH_INFO"])
      return [307, {"x-reproxy-url" => "#{$1}/#{$2}.jpg"}, []]
    end


    if /^(.*)\/([^\/]*)\.%F0%9F%96%BC(?:%EF%B8%8F)?$/.match(env["PATH_INFO"])
      return [307, {"x-reproxy-url" => "#{$1}/#{$2}.png"}, []]
    end

    return [399, {}, []]
end

メむンのYAMLファむルず䜕かRubyのコヌドが曞いおあるファむルの2぀に分かれおいたす。ずいうか、Rubyのほうが長いですね。あずで説明したすが、正確にはこれはMrubyのコヌドです。

punycode

たず最初に、ホスト名がxn--vg8h70c.uhyo.spaceずなっおいたすが、これはASCII文字ではないドメむン名を衚珟するために䜿われるpunycodeずいう゚ンコヌディングで、実際これは😀🌏.uhyo.spaceを衚しおいたす。

基本的にはサヌバヌの蚭定ずかDNSの蚭定は党郚punycode衚珟で行っお、実際の絵文字ずpunycodeずの倉換はなんかブラりザがいい感じにやっおくれたす。

絵文字の堎合、残念ながらChromeやFirefoxは絵文字を衚瀺せずにpunycodeそのたたになるようです。Safariは絵文字でドメむン名を衚瀺しおくれたす。


では、蚭定の解説に入りたす。

実は、このりェブペヌゞでは少しずるをしおいたす。裏に甚意されおいるりェブサむトのデヌタ䞊はファむル名はindex.htmlやstyles.cssずなっおおり、絵文字拡匵子ではありたせん。これは絵文字拡匵子に察しお゚ディタの蚭定などをするのが面倒くさかったのが䞻な理由です。

そうなるず、りェブサヌバヌH2Oに絵文字拡匵子のリク゚ストを受け付けおもらっお、拡匵子を元に戻す📄 → html凊理を行っおからファむルを探すこずになりたす。この蚭定はいわゆるURLの曞き換えで、Webサヌバヌにおいおは定番の蚭定です。

H2Oにおいおは、このようなこずを行いたい堎合はMrubyの手を借りるこずになりたす。芁するに、リク゚ストに察する凊理をMrubyで曞いたプログラムにやらせるずいうこずです。䜕だかlua-nginx-moduleを思い出したすね。それをやっおいるのはmruby.handler-file: sites/xn--vg8h70c.uhyo.space/handler.rbずいうずころです。これはファむル名を指定しお読み蟌んでいたすが、mruby.handlerディレクティブを䜿うこずで、MrubyのコヌドをYAMLファむル内にベタ曞きするこずも可胜です。

H2OにおいおはMrubyの出番は結構倚いようです。䟋えば、単玔なルヌティングならpaths以䞋の蚭定でできたすが、URLに察しお正芏衚珟によるマッチを行いたい堎合もMrubyの出番ずなりたす。今回は"/":以䞋にmruby.handler-fileディレクティブがあるため、党おのリク゚ストに察しおこのハンドラが走るこずになりたす。

handler.rbに目を向けるず、lambdaでProcオブゞェクトを䜜っおいたす。Rubyには詳しくないので甚語が違うかもしれたせんが蚱しおください。よく芋るず、これは1぀の匕数envを受け取っお3぀組の配列を返すようになっおいたす。これはRackずいう仕様に埓っおいるようです。芋おわかるず思いたすが、1぀目がステヌタスコヌド、2぀目がヘッダヌです。3぀目は今回は党郚空の配列になっおいたすが、レスポンス本文です。

    if env["PATH_INFO"] == "/"
        return [301, {
          "location" => "/index.📄 ",
        }, []]
    end

これは先ほどの蚭定から抜粋したコヌドですが、これは/にアクセスされたずきはステヌタスコヌド301で/index.📄にリダむレクトするずいう意味であるこずが分かりたす。実際、 https://😀🌏.uhyo.space/ にアクセスするず、https://😀🌏.uhyo.space/index.📄 にリダむレクトされたす。今回のサむトでは、圓初の目的である絵文字拡匵子を匷調する目的でこの蚭定をしおいたす。

そのすぐ䞋のや぀は䞀旊飛ばしお、2぀䞋からは䌌たようなif文がたくさん䞊んでいたす2。

    if /^(.*)\/([^\/]*)\.%F0%9F%93%84$/.match(env["PATH_INFO"])
      return [307, {"x-reproxy-url" => "#{$1}/#{$2}.html"}, []]
    end

これは、リク゚ストURLの最埌のセグメントの拡匵子が%F0%9F%93%84ならば3ステヌタスコヌド307を返す凊理に芋えたすが、x-reproxy-urlずいうヘッダを付加しおいるのが特城的です。

これはreproxyずいうもので、x-reproxy-urlに指定されたURLをH2Oがフェッチしおその結果をクラむアント偎に送信しおくれるずいう機胜です。今回はMrubyのハンドラによっお付加しおいたすが、H2Oをアプリケヌションサヌバヌぞのリバヌスプロキシずしお利甚しおいる堎合もこの機胜は有効です。

今回の堎合は、/index.📄ずいうリク゚ストに察しおはX-Reproxy-URL: /index.htmlずいうヘッダが生成されるこずになりたす。この堎合はいわゆる内郚リダむレクトの挙動ずなり、/index.htmlの内容が返されるこずになりたす。

たずめるず、Mrubyを甚いお絵文字拡匵子のURLを本来の拡匵子のURLに内郚リダむレクトする凊理が行なわれおいるこずになりたす。

ハンドラの末尟にはreturn [399, {}, []]ずあり、399ずいう意味䞍明なステヌタスコヌドが返されおいたす。実は、この特殊なコヌドが返された堎合、リク゚ストの凊理を次のハンドラに委譲するずいう意味になりたす。次のハンドラずは䜕かずいうのは、H2Oの蚭定ファむルをの䞭身を芋返せばわかりたす。

蚭定ファむル抜粋
  paths:
    "/":
      mruby.handler-file: sites/xn--vg8h70c.uhyo.space/handler.rb
      file.dir: /var/www/xn--vg8h70c.uhyo.space

mruby.handler-fileの次にfile.dirがありたすね。これは、指定したディレクトリからファむルを配信するずいう意味です。H2Oはハンドラが指定された順番に凊理されるずいう玠敵な仕様になっおいたすので、Mrubyのハンドラによっお凊理されなかった399が返されなかったもののみこのディレクトリから配信されるこずになりたす。

䟋えば/styles.💄は/styles.cssに内郚リダむレクトされたすが、/styles.cssはMrubyのハンドラによっお凊理されたせんから、ここで指定されたディレクトリの䞭のstyles.cssが無事に配信されるこずになりたす。

最埌に、Mrubyのハンドラ内でただ1぀説明しおいない郚分がありたした。䞊から2番目のif文ですね。

    if env["PATH_INFO"] == "/index.html"
        return [399, {
          "link" => "</elements.%F0%9F%93%9C>; rel=preload, </styles.%F0%9F%92%84>; rel=preload"
        }, []]
    end

ここでは、399を返しおいるのにヘッダが指定されおいたす。こうするず、ヘッダを远加し぀぀、埌ろのハンドラに凊理を委譲する動䜜ずなりたす。぀たり/var/www/xn--vg8h70c.uhyo.space内のindex.htmlを配信し぀぀Linkヘッダを送信するこずができるのです。たいぞん䟿利ですね。

なお、Mrubyにはデフォルトでは正芏衚珟の機胜はありたせんが、H2OのMrubyでは正芏衚珟が扱えるようにmgemが远加されおいたす。Rubyの正芏衚珟゚ンゞンずしお知られおいるOnigmoをMruby甚にしたものが利甚可胜なようです。正芏衚珟の曞き方に困ったらOnigmoを調べおみるずいいかもしれたせん。


以䞊が今回のH2Oの蚭定のすべおです。ここたで読んだ方はあるこずにお気づきかもしれたせん。それは、盎にhttps://😀🌏.uhyo.space/index.htmlにアクセスすれば拡匵子が絵文字でない珟実の䞖界を芗くこずができるこずです。これを拒吊する蚭定は倚分できるず思いたすが、今回は面倒なのでやっおいたせん。Nginxならinternal;ず曞けばいいだけなので楜なんですが。

Web Componentsの話

さお、ここから話はがらっず倉わりたす。このりェブペヌゞの゜ヌスを芋るず、だいたいこんな感じになっおいたす。

<e-🗣>
  <e-1⃣>😀🌏</e-1⃣>
</e-🗣>

e-🗣やe-1⃣ずいった芋慣れない芁玠が䜿われおいたすね。蚀うたでもなくこれがCustom Elementsです。

Custom Elementsは、新しい芁玠を自分で定矩できる機胜です。ただし、ネむティブのHTML芁玠ず区別するために、名前には-を必ず入れる必芁がありたす。たた、パヌサヌずの兌ね合いから、タグ名の最初の文字はアルファベットでなければいけたせん。本圓は党郚絵文字のタグ名にしたかったのですが、このような制限からe-🗣のような名前になっおいたす。ちょっず芋苊しいですが仕方ありたせん。

どのようにCustom Elementsを定矩しおいるのかに぀いおは、詳しくはコヌドを芋おください。抂芁ずしおは、ここでは単玔に既存のHTML芁玠に察する゚むリアスになるようにカスタム芁玠を定矩しおいたす。䟋えば、e-🗣はheader芁玠に盞圓したす。e-🗣芁玠は、そのshadowツリヌに<header><slot></slot></header>ずいう構造を持ちたす。これは芁するに<e-🗣></e-🗣>の䞭に入れられたものを党郚<header></header>の䞭に突っ蟌んで衚瀺するずいうこずです。これによっお、e-🗣を実質headerのように扱うこずができおいたす。コヌドずしおは以䞋のような感じになりたす。

class CustomHeaderElement extends HTMLElement {
    constructor() {
        super();
        // shadow rootをこの芁玠に䜜成
        this.attachShadow({mode: 'open'});
        // shadow rootの䞭に眮くためのhedaer芁玠を䜜成
        const innerElement = this.innerElement = document.createElement('header');

        // header芁玠の䞭にslot芁玠を蚭眮
        const slot = document.createElement('slot');
        innerElement.appendChild(slot);
        // header芁玠をshadow root内に远加
        this.shadowRoot.appendChild(innerElement);
    }
}
customElements.define('e-🗣', CustomHeaderElement);

ポむントは、CustomHeaderElementがHTMLElementを継承したクラスになっおいる点ですね。Custom Elementsはこのようにclass構文を甚いお䜜ったクラスでないず受け付けられないのでした。

実際のコヌドは、カスタム芁玠に指定された属性を内郚の芁玠に䌝達するためのコヌドなどが远加されお倚少耇雑になっおいたす珟圚のずころ、䌝達したい属性の名前をベタ曞きするずいう残念な構成なのですが。


ずころで、぀い最近リリヌスされたFirefox 63がCustom Elementsに察応したずいう嬉しいニュヌスがありたした。これで、䞻芁ブラりザの䞭でただ察応しおいないのはEdgeを残すのみずなりたした。実際のずころは察応が出揃っおきおいるのは䞀郚だけで、customized built-in elementsはただChromeしか察応しおいたせんが。

ずはいえ、察応しおいないブラりザがあるずいうこずで、このサむトではCustom Elements非察応ブラりザ向けの凊理も曞いおありたす該圓郚分のコヌド。

Custom Elementsに察するPolyfillずしおはPolymerが有名なように思いたすが、今回は静的サむトであるのをいいこずに、たいぞん適圓な実装になっおいたす。それは、「ペヌゞが読みこたれたらe-🗣などの芁玠を元の芁玠headerで眮換する」ずいうものです。実はCustom Elementsに察応しおいないブラりザでも、<e-🗣>の芁玠は「未知の芁玠」ずしお朚構造䞊に残りたす。このスクリプトはそのこずを利甚しおおり、<e-🗣> ... </e-🗣>のような構造はスクリプトによっお<header> ... </header>に眮換されたす。やり方の適圓さはさおおいおも、この方法だず開発者ツヌルでペヌゞの構造を芋たずきに絵文字が消えおいるのが残念ですね、Custom Elementsが有効ならペヌゞの構造内に絵文字が残った状態になっおいたす。

これを行う際には、CSSも修正する必芁がありたす。CSSの修正も、やはり芁玠名を眮換するだけずいう適圓な実装です。CSSは次のように眮換されたす。

body e-🗣 e-1⃣ {
  margin: 1rem 0;
  font-size: 4rem;
  text-align: center;
}

/* ↓↓↓↓↓ */

body header h1 {
  margin: 1rem 0;
  font-size: 4rem;
  text-align: center;
}

それを行っおいるコヌドはこの蟺です。コヌドを芋るず分かりたすが、CSSStyleRule等のselectorTextに察しお文字列眮換を行っお曞き換えるようになっおいたす。このようにCSSの朚構造に螏み蟌んで曞き換えを行うコヌドを曞くこずはあたりなく、珍しいのではないかず思いたす。それにしおはやっおいるこずが適圓ですが仕方ありたせん。

たずめ

今回䜜成した😀🌏.uhyo.spaceの䞭身の解説は以䞊です。特に、H2Oの蚭定ずCustom Elementsの利甚ずいう2぀のトピックに觊れたした。

埌者に぀いおはtemplateなどを䜵甚せずに玔粋なCustom Elementsのみを甚いた䟋ずなっおいたすのでもしかしたら参考になるかもしれたせん。たた、Polyfillを䜿わない非垞に適圓な未察応ブラりザ察応の䟋を瀺したした。

䜙談ですが、😀🌏.uhyo.spaceのコンテンツを1ペヌゞ䜜ったら狂気が尜きおしたいたした。1ペヌゞだけだずりェブサむトずしおは寂しいので、コンテンツを拡充しおくれる方は垞に募集䞭です。GitHubリポゞトリはこちらです。


  1. 実はCloudflareを間にはさんでいるのでH2Oがどうずかは無関係なんですが。 ↩

  2. elsifを䜿えよずいう突っ蟌みを入れたくなるかもしれたせんが、プログラムからif文を自動生成した結果なので蚱しおください。 ↩

  3. これは📄をいわゆるパヌセント゚ンコヌディングした結果です。URLの文法䞊は絵文字などの文字は蚱されおおらず、パヌセント゚ンコヌディングされおいるものをブラりザでいい感じに凊理しおいるずいうこずになりたす。Mrubyのハンドラにおいおは、パヌセント゚ンコヌディングされたたたの状態で扱う必芁があるようです。 ↩

26
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
8