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

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

Vue単一ファイルコンポーネントで共通のSCSSファイルを読み込む

どうもエンジニアのやまぐちです。

年末はビルドツールを触る機会が多かったため寝ても覚めてもWebpackな感じでした。 そんな中で単一ファイルコンポーネントでSCSS共通の変数やmixinを使う場合に少し悩んだので、 同じように苦労している方がいれば参考にしていただけたら幸いです。

https://github.com/webpack-contrib/sass-loader

ディレクトリ構成

ディレクトリ構成は以下で進めていきます。

/example
 ├ webpack.config.js
 ├ dist
 │ ├ app.js
 │ └ index.html
 └ src
  └ assets
   ├ script
   │ ├ app.js
   │ └ App.vue
   └ style
     ├ global.scss
     ├ _mixins.scss
     └ _variables.scss

/src/assets/style/global.scssでは、更に変数とMixinのファイルをimportします。

# global.scss

@charset "utf-8";

@import "_variables";
@import "_mixins";

単純に@import

styleの中で@importすれば読み込むことが可能です。

# App.vue

<template>...</template>
<script>...</script>

<style lang='scss' scoped>
@import "../style/global.scss";

h1 {
  @include font-size($font-md);
}
</style>

しかし、この方法だと各ファイルのstyleに@importを記述する必要があり、保守性も悪いため実用的ではありません。

vue-loaderで設定

vueファイル内でscssを使うためにvue-loaderのオプションにsass-loaderを設定していると思います。
このsass-loaderのオプションを更に設定することで共通のscssファイルを読み込むことができます。

# webpack.config.js

module.exports = {
  entry: './resorces/assets/script/app.js',
  output: {
    path: './dist',
    filename: '[name].js',
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            css: {
              loader: 'css-loader',
            },
            scss: {
              loader: 'sass-loader',
              options: {
                data: '@import "global.scss";',
                includePaths: path.resolve(__dirname, './src/assets/sass/'),
              }
            },
          },
        },
      },
      ...
    ],
    ...
  },
  ...
}

sass-loaderオプションのdataincludePathsを指定することにより共通のSCSSファイルを読み込むことができます。

  • dataにはstringが設定でき@importを記述することでビルドに読み込まれるvueファイル内に自動的に追加されます。
  • includePathsにはimportしたいファイルが格納されているパスを指定します。

上記の設定をすることで全ての.vueファイルのscssの記述で@importが必要なくなります。

もちろんこちらの設定はSCSSファイルをビルドする際にも使用できます。
(SCSSファイルのビルド時には起点となるファイルでimportすれば良いのであまり必要なさそうですが。。)

# App.vue

<template>...</template>
<script>...</script>

<style lang='scss' scoped>
h1 {
  @include font-size($font-md);
}
</style>

まとめ

Webpack側で上記の設定しておくことで単一ファイルコンポーネント側に余計な記述をしなくて済みました。 ただしwebpack.config.jsへ単純に記述してしまうとmoduleの中が冗長になってしまうので関数化するなどの対応をしたほうが良いと思いました。
頑張って調べたけれどもっと効率の良い方法などありましたらご教授お願いいたします!

必要最低限に理解する、ジェネリクスと共変・反変

こんにちは、アプリエンジニア見習い補佐代理のナカハシです。

最近Kotlinを勉強し始めて、読みやすくて書きやすい言語だなと思ったのですが、そこで出てきたジェネリクスの「変異」という機能で「うん?」となったので、改めてジェネリクス周りの初歩知識を整理することにしました。(そもそも型あり言語をちゃんと書くのも久しぶりだし...)

Kotlinを使って記事を書きますが、他の言語でも概念的にはだいたい同じですし超シンプルな記述でまとめていますので、Kotlin食わず嫌いの型も是非ご一読下さい。

そもそもジェネリクスがないといつ困るのか

続きを読む

Jestをvue-test-utilと組み合わせてスナップショットテストやってみた

フロンエンドエンジニアごーです。

vue-test-utilsのドキュメントを読んでいて、Jestというテストフレームワークが紹介されていたので、どんな機能があるのか試してみました。

Jestとは

Facebook社製の快適なJavascriptのテストを実現するためのフレームワーク。

Reactアプリケーションを含む全ての JavaScriptコードのテストに利用可能で、複雑な設定ナシで高速に動作する。

  • githubのstar: 13,840 (2017/12/04の時点で)
  • 2014年から開発が行われている

facebook/jest

続きを読む

ECSをより便利に使うためのポイント解説

nazoです。

kubernetesの勢いが強い昨今ですが、AWSではやはりECSが便利です。

ECSは簡単に使えるものの、より便利に使うにはいくつか抑えておくポイントがあります。今回はその点をいくつか紹介したいと思います。

前提知識

ECS

ECSには「クラスタ」「サービス」「タスク定義」という概念があります。

1つの「クラスタ」には複数の「サービス」が入り、「サービス」は「タスク定義」で定義されたタスクが起動、常駐します。

「クラスタ」には複数のEC2インスタンスが登録され、登録されているEC2インスタンスの中でサービスは起動します。どのEC2インスタンスがどのクラスタに登録されるかは、EC2内にいるecs-agentコンテナがクラスタに通知する仕組みになっています。通常はEC2のユーザーデータでクラスタ名を指定します。

ALB

ALBは、リスナーポートをターゲットグループに割り当てることができます。

リスナーポートが受けるプロトコルと、ターゲットグループから送り出すプロトコルは同一である必要はありません。ユーザー向けSSL認証をALBで完了させて後続ではHTTPで接続すると、内部ではSSL証明書を持つ必要がなくなります(SSL Termination)。ACM証明書と組み合わせると、メンテナンスフリーでSSL接続を行うことができます。

ALBとECS

ECSのサービスを作成する際に、どのターゲットグループ(CLBの場合はCLB自体)と連動させるかを指定することができます。サービスとターゲットグループの関連は1:1で、作成後に変更はできませんので、ターゲットグループを変更したい場合は一度サービスを削除する必要があります。ちなみにサービスを削除するには動作中のタスクを0にする必要があるので、基本的には変えないほうがいいでしょう。

サービスとターゲットグループが連動している場合、同時に「どのコンテナのポートをターゲットグループにマッピングするか」を指定することができます。タスク定義側でホストポートを0にしたものを指定することで、ホスト内でポートがランダムに割り当てられ、そのポートで自動的にALBと通信します。同一コンテナを同一ホストで複数動かす必要がある場合や、複数のWebサービスのコンテナを同一ホストで動かす必要がある場合などに、ポート番号が被らずにコンテナを立ち上げることができます。

続きを読む

メンテナブルなCSS管理

フロンエンドエンジニアごーです。

CSSを記述するにあたって常に気をつけないといけないのが、すべてのCSSクラスがグローバルネームスペースであるため、副作用の畏れが存在することです。

グローバルネームスペースの衝突を回避する方法としては、OOCSSSMACSSBEMといったクラスの命名規約があります。

これらはスタイル実装者が規約を遵守しているうちは問題ないですが、強制するものではないので大規模になるとスタイル定義の秩序は簡単に壊れてしまう可能性があり、非決定論的な解決に思えます。

そこで、クラス名が必ず衝突しない仕組みを実現するツールをいくつか学びCSSクラスの管理コストを軽減してみます。

利用ライブラリ

今回は開発環境のセットアップは割愛します。

以下のライブラリ使った開発環境を前提に説明していきます。

  • webpack3.x
  • style-loader
  • css-loader
  • sass-loader
  • vue-loader
  • Vue.js 2.x

単一ファイルコンポーネント(.vueファイル)を使ったscoped css

単一ファイルコンポーネント.vuestyle要素にscoped属性を持たせることで、HTML要素にユニークな名前のディレクティブが挿入されます。 要素に適用されるスタイルは、このディレクティブとクラス名で限定されたセレクタとして適用されます。

<template>
  <div>
    <button class="btn-red">ボタン</button>
    <button class="btn-green">ボタン</button>
    <button class="btn-blue">ボタン</button>
  </div>
</template>

<style lang="scss" scoped>
  .btn-red {
    background-color: red;
  }
  .btn-green {
    background-color: green;
  }
  .btn-blue {
    background-color: blue;
  }
</style>
続きを読む

ElasticsearchをMySQLと同期しつつ手軽に無停止アップデートする

nazoです。

Elasticsearchを運用する際に、マスタデータはMySQLで持ちたいという場合にどうやって同期をするかというのが問題になります。また、Elasticsearchはバージョンの互換性が厳しく、別バージョンをクラスタに混ぜることは基本的にできず、さらに辞書の更新などを行う場合はインデックスを全て更新しなくてはいけないなどの運用上の課題があります。

今回は社内向けに使っているElasticsearchを、これらの問題を解決しつつどのように運用するかを考えてみましたので、紹介したいと思います。

簡単に

MySQLとElasitcsearchの同期は go-mysql-elasticsearch を使います。 無停止のためのデータコピーは elasticsearch-dump を使います。

続きを読む

HTTP Live Streamingを試してみた

エンジニアのタナカです。

ライブ配信というとReal Time Streaming Protocol(RTSP)が有名ですが、 AbemaTVやFresh!といった最近のサービスでは、HTTP Live Streaming(HLS)というHTTPベースのプロトコルでライブ配信 を行っています。

従来のRTSPでは、転送プロトコルにUDPを使用することが多く、配信には専用のサーバーが必要でした。
ところが今回紹介するHLSならば、転送プロトコルにHTTPを使用し、ApacheやNginxといった一般的なサーバーを使って動画配信できるようになります。
また、HTTPベースなのでCDNも利用可能で、同時接続数を増やすのも容易なようです。

HTTP Live Streamingについては、こちらのサイトがわかりやすいので、ぜひ見てみてください。

did2memo.net

今回は、このHLSを使用してライブ配信の実験をしてみました。

概要

以下の要領でライブ配信が行えることを確認したいと思います。

  • リアルタイムの映像とエンコーダーに、動画ビュアーのVLCを利用する
  • エンコードされたものをHTTP Live Streaming ToolsでHLS形式に変換する
  • 変換されたものをApacheで配信する

環境

  • OS: Mac OSX/10.11.6(バージョンアップしなければ・・)
  • エンコーダー: VLC Player/2.2.6
  • HLSコンバーター: HTTP Live Streaming Tools(Apple Developer からダウンロード可能)
  • Webサーバー: Apache/2.4.18

実行コマンド

/Applications/VLC.app/Contents/MacOS/VLC -vv screen:// --intf=rc --sout="#transcode{vcodec=h264,samplerate=44100,vb=800,fps=25,acodec=mp4a,ab=128,height=480,width=640,scale=1}:standard{access=file,mux=ts,dst='-'}" | mediastreamsegmenter -f /Library/WebServer/Documents/stream -s 3 -t 30 -p

VLCにはデスクトップをキャプチャー、エンコードする機能があるのでそちらを利用しています。
エンコード結果をHTTP Live Streaming Toolsのコマンドmediastreamsegmenterに渡しています。
ファイルの出力先にはApacheのDocumentsディレクトリを指定しました。

実行結果

ファイル一覧

Library/WebServer/Documents/stream% ls -l
total 3256
-rw-r--r--  1 tanaka  wheel   213944 10 18 18:28 fileSequence0.ts
-rw-r--r--  1 tanaka  wheel  1309232 10 18 18:29 fileSequence1.ts
-rw-r--r--  1 tanaka  wheel   135168 10 18 18:29 fileSequence2.ts
-rw-r--r--  1 tanaka  wheel      151 10 18 18:28 prog_index.m3u8
/Library/WebServer/Documents/stream% 

指定したディレクトリ下にこのようなファイルが出力されます。

.m3u8ファイル

#EXTM3U
#EXT-X-TARGETDURATION:30
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:EVENT
#EXTINF:29.96593,       
fileSequence1.ts
#EXTINF:14.40000,       
fileSequence2.ts
#EXT-X-ENDLIST

このファイルがプレイリストです。 必要な動画ファイル(.ts)が複数指定されていて、対応ブラウザで開くと順番に動画ファイルが再生されます。 EXT-X-TARGETDURATION:30で30秒毎にプレイリストが更新されることが表されています。

Safariで確認

このファイルをApache経由で配信し、Safariで開くとこのように動画が再生されます。

f:id:tnuuu:20171018184200g:plain

まとめ

専用サーバーが必要だった時代に比べて、ライブ配信もだいぶ手軽に行えるようになりました。 ただし、対応ブラウザに注意が必要です。
PCのIEやChromeの場合はそのままでは再生できず、video.jsのようなライブラリが必要です。
スマホならSafariでもChromeでも再生可能です。