SECCON 2018 BeginnersCTF に参加しました(Write-up)

こんにちは、システム事業部の村田です。

5/26〜27に行われていた、SECCON 2018 BeginnersCTFに、弊社の有志で集まって参加しました。
Beginnersということで初心者向けの問題も多く、前回チャレンジしたSECCON 2017 Online CTFよりもある程度解けて楽しかったです。

が、やはりpwn、reversing系の問題は全くわかりませんでした・・・
次参加するときは、事前に少し勉強してみようと思います。

以下が、今回のスコアでした。 f:id:zenet-tech:20180528184942p:plain f:id:zenet-tech:20180528184953p:plain

470ポイントで206位、ちょっと頑張れば手が届く問題が多く、初心者の私としては非常にありがたかったです。

ここからは、それぞれ解答したメンバーにwrite upを書いてもらおうと思います。

[Warmup] Greeting(Web)

宮崎です。 管理者adminならフラグを表示してくれる問題でした。 ソースコードが記載されていたので読んでみると cookieにadminがいるかどうかで判断しているようでした。 postだと偽物にする仕様のようで、getで渡してあげると正解のようです。

フラグ => ctf4b{w3lc0m3_TO_ctf4b_w3b_w0rd!!}

[Warmup] Veni, vidi, vici(Crypto)

十島です。 こちらの問題はpart1、2、3の3つのファイルからフラグを探し出すというものです。 ファイルの内容は次の通りです。

# part1
Gur svefg cneg bs gur synt vf: pgs4o{a0zber

# part2
Lzw kwugfv hsjl gx lzw xdsy ak: _uDskk!usd_u

# part3
{ʎɥdɐɹɓ0ʇdʎᴚ :sı ɓɐlɟ ǝɥʇ ɟo ʇɹɐd pɹıɥʇ ǝɥ⊥

それぞれみて見ると、part3は逆さ文字ということに気がつきます。 置き換えて見ると以下のようになり、フラグの最後が取得できました。

# part3
{ʎɥdɐɹɓ0ʇdʎᴚ :sı ɓɐlɟ ǝɥʇ ɟo ʇɹɐd pɹıɥʇ ǝɥ⊥
=> The threird part of the flag is: Rypt0graphy}

part3の形式からpart1、part2も同様の形式だと判断できるので、 以下のようにアルファベットを入れ替えていきます。

# part1
   Gur svefg cneg bs gur synt vf: pgs4o{a0zber
=> The first part of the flag is: ctf4b{m0nore 

# part2
   Lzw kwugfv hsjl gx lzw xdsy ak: _uDskk!usd_u
=> The second part of the flag is: _cLass!cal_c 

フラグはctf4b{m0nore_cLass!cal_cRypt0graphy}となります。

てけいさんえくすとりーむず(Misc)

村田です。

問題のurlにncコマンドで接続すると、100問の計算問題を300秒以内に解答しろと言われます。 私は3桁の四則演算は3秒では解けないので、Rubyでscriptを作りました。

require 'socket'

TCPSocket.open("tekeisan-ekusutoriim.chall.beginners.seccon.jp", 8690) do |s|
  11.times{puts s.gets}
  100.times do
    puts s.gets
    calc = s.gets(' ').chop.to_i.send(s.gets(' ').chop, s.gets(' ').chop.to_i)
    puts calc
    puts s.gets(' ').chop
    s.print("#{calc}\n")
    s.flush
  end
  
  s.each_line { |line| puts line }
end

実行すれば無事100問解いてくれます。

(Stage.98)
1588
=
(Stage.99)
1727
=
(Stage.100)
566796
=
Congrats.
Flag is: "ctf4b{ekusutori-mu>tekeisann>bigina-zu>2018}"

Rubyの標準入出力をちゃんと使ったことがなかったので改行周りでちょっと時間かかりましたが、なんとか。。。

Streaming(Crypto)

スマートではないのですが、自分なりの解き方説明です。(五十島

コードを読むと変換した結果をencryptedに出力しているようなので、開いてみます。 普通に開いてもよくわからないので、バイナリで出力してみると・・・数字が出力できたのでビンゴ!

$ od -tu1 encrypted
0000000   206  30 101  12   6  95 148  58  87  73  29  23 245  23  89  63
0000020   156  64 157  74  25  49 141  38  62  81 253   3 206  82  86  22

フラグなので最初は、ctf4b{のはずなので・・・ [206, 30] でcを表しているはずと仮定する。 プログラムから頑張って逆算すると、cで使用したseedが「15741」とわかるので、あとはencode.pyを利用して逆算プログラムを作成します。

import os

class Stream:
    A = 37423
    B = 61781
    C = 34607
    def __init__():
        self.seed = 15741

    def __iter__(self):
        return self

    def next(self):
        self.seed = (self.A * self.seed + self.B) % self.C
        return self.seed

g = Stream()
mod = [148, 87, 29, 245, 89, 156, 157, 25, 141, 62, 253, 206, 86]
res = [ 58, 73, 23, 23, 63, 64, 74, 49, 38, 81, 3, 82, 22]

for i in range(0, len(mod), 1):
    a = res[i] * 256 + mod[i]
    flag_i = a ^ g.next()
    print flag_i
# => 27747 26413 26995 11621 24947 26988 31021 28786 25956 26979 29793 25196 25981

出力された数字を文字列に変換して、フラグが取得できました。 ctf4b{lcg-is-easily-predictable}

Gimme your comment(Web)

新規登録をするときに本文に以下を入れて投稿すると・・・フラグが取得できる。(五十島) 勝手にUser-Agentをformに入れてsubmitする処理です。

<script>
    $(document).ready(function () {
        var userAgent = window.navigator.userAgent.toLowerCase();
        $('.form-control').val(userAgent);
        $('form').submit();
    });
</script>

もっとスマートにできるといいのだけど、自分のレベルではこれが限界でした。

Vue.js + TypeScrptの環境構築(パート2)

こんにちは! システム事業部の村田です。

zenet-tech.hatenablog.com

の続きです

間違い等ありましたらコメント頂けると幸いです。


使う主なもの

  • Vue.js
  • TypeScript
  • webpack
  • yarn

また、執筆時の各versionは

  • Vue.js(2.5.13)
  • webpack(4.6.0)
  • yarn(1.6.0)
  • ts-loader(4.2.0)
  • vue-loader(14.2.2)
  • typescript(2.8.3)

です。 (part1よりvarsionが上がってます・・・part1の手順は同じく再現できているのでご了承ください)

TypeScript用のライブラリを追加 yarn add typescript ts-loader

tsconfig.jsonを生成

/node_modules/.bin/tsc --init

vue.js公式の推奨設定にしたがい最低限の設定を行います。

{
  "compilerOptions": {
    /* Basic Options */
    "target": "ES2015",
    "module": "es2015",
    /* Strict Type-Checking Options */
    "strict": true,
    /* Module Resolution Options */
    "moduleResolution": "node",
    "esModuleInterop": true
  }
}

webpack.config.jsをTypeScriptを支えるように更新します。

webpack.config.js

const path = require('path');

module.exports = {
  mode: 'development',
  // 拡張子をtsに
  entry: './src/index.ts',
  output: {
    path: path.join(__dirname, 'public'),
    filename: 'bundle.js'
  },
  devServer: {
    contentBase: 'public',
    port: 4000
  },
  resolve: {
    // 拡張子にtsを追加
    extensions: ['.ts', '.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  },
  module: {
    // TypeScriptのコンパイラを追加
    rules: [
      {
        test: /\.ts$/,
        loader: 'ts-loader'
      }
    ]
  }
};

これで、最低限.tsのファイルをコンパイルできるようになりました。

このままだと、vue.jsのsfcが使え無いので、そちらも使えるように更に追記します。

yarn add vue-loader vue-template-compiler

webpack.config.js

const path = require('path');

module.exports = {
  mode: 'development',
  entry: './src/index.ts',
  output: {
    path: path.join(__dirname, 'public'),
    filename: 'bundle.js'
  },
  devServer: {
    contentBase: 'public',
    port: 4000
  },
  resolve: {
    extensions: ['.ts', '.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  },
  module: {
    rules: [
      // .vueファイルをコンパイルするvue-loaderを指定
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.ts$/,
        loader: 'ts-loader',
        options: {
          // .vueファイルをtsとして監視するように追加
          appendTsSuffixTo: [/\.vue$/]
        }
      }
    ]
  }
};

また、.vueファイルの情報を定義したファイルを、.d.ts拡張子で定義します

vue.d.ts

declare module "*.vue" {
    import Vue from 'vue'
    export default Vue
}

現在はまだ、sfcを使ってい無いので、使うように変更します。

index.ts

import Vue from 'vue'
import App from './App.vue'

// App.vueを描画する様に変更する
new Vue({
  el: '#app',
  template: '<App/>',
  components: { App }
})

App.vue

<template>
  <div id="app">
    <h1>Hello Vue with ts</h1>
    <Sub/>
  </div>
</template>

<script>
// 出力するサブコンポーネントを定義
import Sub from './pages/Sub.vue'

export default {
    components: {
        Sub
    }
}
</script>

Sub.vue

<template>
  <div>
    <h2>sub commpornent</h2>
  </div>
</template>

この状態で、 yarn start して、localhost:4000にアクセスできれば成功です!

f:id:zenet-tech:20180421183245p:plain

お疲れ様でした!

Developer Summit 2018 に行ってきました

こんにちは。システム事業部の五十島です。

2月15・16日、ホテル雅叙園東京で行われたデブサミ2018に初参加してきました。
デブサミってなに?という方がいらっしゃるかもしれませんが、簡単に言うと「技術の祭典」ですね。
技術的な話や開発プロセスの話、マネージメント・・・エンジニアが自分らしく生きる生き方、などなどIT関連の話であればなんでもありのイベントです。
詳しくは↓のサイトをみてみてください。とても楽しい!・・・はず(自分的には楽しかったです)

event.shoeisha.jp

今回、聴いてきたのは以下の2つです。

カイゼン・ジャーニー 〜たった一人からはじめて、「越境」するチームをつくるまで〜

以下の書籍の内容をかいつまんで話していました。 www.shoeisha.co.jp

話の中で良いと思ったところは、「自分がまずは始めてみる」こと。 誰かを巻き込んで始めれることが一番いいのですが、簡単に行かない場合が多いと思います。
一人で朝会、一人でふりかえり、一人でタスクボード、一人でタスクマネージメント ...etc
一人だから無駄だということはなく、始めてみて確かに「良かった」と思えるところを周りに伝えてみる。 そして、巻き込んで一緒にやることが大切だと感じました。

属人化したフロントエンドのJavaScriptを、‘新規機能開発を止めずに’改善するために行った取り組みについて。及びその経過報告。

このセッションでは、以下二つの問題についての解決方法について話していました。

  1. 複数のファイルにまたがるための複雑さ => 複数のJSファイルから修正したい箇所を見つけるのが困難であった。
  2. DOMとイベントリスナーが離れすぎている => DOMを変更したがために、イベントが動作しなくなる。または、動的に作りすぎていて追えない。

1. について、Webpackを使ってファイルを一つにまとめて、修正を楽にするという試みを行う。
2.について、Reactを使ってDOMとイベントを同じファイルに書くようにした。

解決策を聞いて確かにそうすると分かりやすいとは思いましたが、自分としてはRailsのようなフロント側も含んだ場合の事例を少し聞きたかったと思いました。 (ちょっと残念)


今年も仕事は詰まっていたのですが、毎年泣く泣く諦めていたので、直前に「明日、デブサミ行ってきます」という暴挙にでてしまいました。
(注意:良い子の社員の皆様は事前に相談しましょう)

1日目の2コマしか聴くことができませんでしたが、大変有意義だったのでまた次も(夏サミ?)にもぜひ参加したいですね。

ちなみに弊社からは私以外にも2、3人は参加していたようです。

CSS Grid Layoutのすすめ(パート2)

こんにちは。システム事業部の五十島です。 前回の記事に引き続き CSS Grid Layoutのご紹介です。 前回はただ単に並べただけで、float: leftl; float: right とあまり大差がないように感じたと思いますが、 今回は任意の位置に表示する手法を説明していきます。

前回のおさらい

前回までは横を3等分に分割する設定を行いました。 各要素は1格子に収まる形なので、縦は自動的に2段になります。 前回のhtmlのdivタグにclass属性を付与するところから始まります。

ソースコード
gird.html

<div id="grid-main">
  <div class="grid1">要素1 </div>
  <div class="grid2">要素2</div>
  <div class="grid3">要素3</div>
  <div class="grid4">要素4</div>
  <div class="grid5">要素5</div>
</div>

grid.css

#grid-main {
  display: grid; /* grid layoutを指定 */
  grid-template-columns: 1fr 1fr 1fr; /* 3等分に分割 */
  grid-auto-rows: 100px;
}

表示結果 f:id:zenet-tech:20171219131657p:plain

基礎 その2

今回は以下のような順で説明していきます。

  • 横の配置を指定する
  • 縦の配置を指定する
  • z-indexを指定して、表示順序を入れ替える
  • 入れ子にしてみる

横の配置を指定する

まずは、「要素1」を横に伸ばして見ましょう。 以下のCSSを追記すると、画像のように「要素1」が横長になりました。 「要素2」は2段目に表示され、各要素がずれたような表示になります。

ソースコード

.grid1 {
  grid-column-start: 1;
  grid-column-end: 4;
}

表示結果 f:id:zenet-tech:20180226221448p:plain

grid-dolumn-startが要素の横の開始位置、grid-column-endが要素の終了位置を表しています。 開始・終了位置はブロック単位ではなく、グリッドの線になります。今回の場合は、横を3分割しているため、グリッドの横の線は4本になります。

以下のように「要素1」と「要素4」の横の開始・終了位置を変更すると、「要素4」は3列目の1行から表示されるようになります。 基本は、横の場合はどんどんずれていくイメージになります。

ソースコード

.grid1 {
  grid-column-start: 3;
  grid-column-end: 4;
}

.grid4 {
  grid-column-start: 1;
  grid-column-end: 3;
}

表示結果 f:id:zenet-tech:20180226221451p:plain

縦の配置を指定する

grid-row-startgrid-row-endで縦の配置を指定することができます。 「要素1」を左下に、「要素4」を右上に移動させるために以下のようにCSSを書き換えます。 特に位置指定していないものに関しては、順番に表示されていると思います。

ソースコード

.grid1 {
  grid-column-start: 3;
  grid-column-end: 4;
  grid-row-start: 2;
  grid-row-end: 4;
}

.grid4 {
  grid-column-start: 1;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 2;
}

表示結果 f:id:zenet-tech:20180219224230p:plain

また、重なるような配置のCSSを書いてみましょう。 「要素5」と「要素4」が、「要素3」と「要素1」が重なって見えます。 基本的には先に書かれたタグは後ろ、後から書かれたタグが手前に表示されるようになっています。

ソースコード

.grid1 {
  grid-column-start: 3;
  grid-column-end: 4;
  grid-row-start: 2;
  grid-row-end: 4;
}

.grid4 {
  grid-column-start: 1;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 2;
}

.grid3 {
  grid-column-start: 1;
  grid-column-end: 4;
  grid-row-start: 3;
  grid-row-end: 4;
}

.grid5 {
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 3;
}

表示結果 f:id:zenet-tech:20180219224234p:plain

z-indexで重なり制御

要素の重なりを制御したいときは、z-indexを指定しましょう。 要素1、4はz-index: 1、要素3、5はz-index: 0に設定すると、表示優先度が入れ換わりました。 ここまでくると、かなり自由にレイアウトが組めるのではないでしょうか。

ソースコード

.grid1 {
  grid-column-start: 3;
  grid-column-end: 4;
  grid-row-start: 2;
  grid-row-end: 4;
  z-index: 1;
}

.grid4 {
  grid-column-start: 1;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 2;
  z-index: 1;
}

.grid3 {
  grid-column-start: 1;
  grid-column-end: 4;
  grid-row-start: 3;
  grid-row-end: 4;
  z-index: 0;
}

.grid5 {
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 3;
  z-index: 0;
}

表示結果 f:id:zenet-tech:20180219225219p:plain

入れ子

ちなみにGrid Layoutは入れ子も可能です。 以下のコードをブラウザで表示してみると、「要素1」に「子要素」が入っていることがわかります。 結構簡単にGrid Layoutを入れ子にすることが可能です。

ソースコード
grid2.html

<div id="grid-main">
  <div class="grid1">要素1
    <div id="grid-sub">
      <div class="sub1">子要素1</div>
      <div class="sub2">子要素2</div>
      <div class="sub3">子要素3</div>
    </div>
  </div>
  <div class="grid2">要素2</div>
  <div class="grid3">要素3</div>
  <div class="grid4">要素4</div>
  <div class="grid5">要素5</div>
</div>

grid2.css

#grid-main {
  display: grid; /* grid layoutを指定 */
  grid-template-columns: 1fr 1fr 1fr; /* 3等分に分割 */
  grid-auto-rows: 100px;
}

.grid1 {
  grid-column-start: 3;
  grid-column-end: 4;
  grid-row-start: 2;
  grid-row-end: 4;
  z-index: 1;
}

.grid4 {
  grid-column-start: 1;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 2;
  z-index: 1;
}

.grid3 {
  grid-column-start: 1;
  grid-column-end: 4;
  grid-row-start: 3;
  grid-row-end: 4;
  z-index: 0;
}

.grid5 {
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 3;
  z-index: 0;
}

表示結果 f:id:zenet-tech:20180219231312p:plain

さいごに

今回のことができれば、結構なんでも応用がきくと思います。
Grid Layoutはかなり便利で、ブラウザごとの差異を気にすることがなく自由なレイアウトができることが魅力です。 (完全対応していないIEは除く)
もっとGrid Layoutのことを知りたい人は、Mozilla のドキュメントを読んでみることをお勧めします。 developer.mozilla.org

次回は、応用編で凝ったWebデザインを作ってみたいと思います。 ではでは

HTMLとjavascriptを利用し、アップロードする動画ファイルの再生時間をクライアント側で取得する方法

こんにちは。システム事業部の三浦です。

最近動画のアップロードをする入力フォームを作る機会がありました。

アップロード可能な動画ファイルの条件として、再生時間が300秒以内という条件がありました。(ファイル形式他諸々もチェックしましたが、今回は割愛します)

初めは、アップロードする動画ファイルをサーバサイドでffmpegを利用し解析し、duretionを取得してチェックするような実装を行いました。

しかし、この方法ではアップロードの時間を待たされた上、失敗するといったユーザビリティがとても悪いものになっていました・・・

「入力フォームの段階でjavascriptを利用して、再生時間をチェックしよう!」という方針になったのですが、
その方法で少しつまずくこととなったので、
最終的に完成した方法を簡略化し共有させていただきます。

以下のようなコードで実現可能です。(モダンな書き方でなくすみません・・・)

<!DOCTYPE html>
<html>
  <script type="text/javascript">

    // 動画の再生時間上限
    MAX_DURATION = 300

    window.onload = function() {
      // ファイル選択時のイベントを設定
      document.getElementById("movie-input").onchange = function(e){
        var file = e.target.files[0];
        // 選択されたファイルをチェック用のメソッドに渡す
        checkVideoDuration(file);
      }
    }

    // 再生時間チェック用メソッド
    var checkVideoDuration = function(file) {
      var video = document.createElement('video');
      var fileURL = URL.createObjectURL(file);
      video.src = fileURL;
      video.ondurationchange = function() {
        if(parseInt(this.duration) > MAX_DURATION) {
          alert("動画長さが" + MAX_DURATION + "秒を超えています。");
        } else {
          alert(this.duration);
        }
        URL.revokeObjectURL(this.src);
      };
      console.log("この部分は非同期処理");
    }

  </script>

  <head>
    <meta charset="utf-8">
    <title>動画時間チェック</title>
  </head>

  <body>
    <input type="file" id="movie-input" name="movie-input">
  </body>

</html>

処理の流れは以下のようになっています。

  1. アップロードされたファイルを、onchangeイベントで取得
  2. ファイルをURL.createObjectURLでローカルに展開、そのURLを取得
  3. 2で取得したurlを、videoタグのsrcに設定
  4. その後videoタグのondurationchangeイベントにて検知し、再生時間を表示
  5. ローカルに展開された動画をURL.revokeObjectURLで削除

※注意点

  • createObjectURLによりデータはメモリ上に展開されるため、ファイル容量によってはフリーズ等が起きる可能性もあります。
  • 上記の実装では、動画ファイル以外がアップロードされることは考慮していません。
  • MP4形式のファイル以外は確認していません。

このようにして、無事再生時間の取得に成功しました!! f:id:zenet-tech:20180129191544p:plain

以上です。

Vue.js + TypeScrptの環境構築(パート1)

あけましておめでとうございます!! システム事業部の村田です。

年末に友人と開発合宿と銘打って、だらだらと開発する会を行ったのですが、Vue.js + TypeScriptを使おう!ということで開発環境を整えました。
その際にかなーりハマりまくったので、やったこと・設定したことを、もう一度作成してまとめようと思います。

また、長くなるのでパートを分けさせていただきます。
この記事では、Vue.js、webpack、yarnを利用してHelloWorldを行うところまでを記載します。
なのでTypeScriptはまだ出てません(汗)ごめんなさい!

間違い等ありましたらコメント頂けると幸いです。


使う主なもの(予定)

  • Vue.js
  • TypeScript
  • webpack
  • yarn

また、執筆時の各versionは

  • Vue.js(2.5.13)
  • webpack(3.10.0)
  • yarn(1.3.2) です。

全体的な流れとして、

yarnを使ってVue.jsをwebpackで導入 | TIS NOTE

こちらの記事を参考に作業を進めました。もしうまくいかない方はこちらも見てみて下さい。


yarnのインストール

こちらの記事を参考にしました。

qiita.com

mac or linuxでnpmインストール済みであれば

$npm install -g yarn

macであれば

$brew install yarn

でインストールできます。


プロジェクト作成

適当なサンプルプロジェクトを作ります。

$mkdir vue_ts_sample
$cd vue_ts_sample

yarnを使うのでinitコマンドを実行します。

$yarn init

すると、色々な質問されるので、進めていきます。
今回はサンプルで動かすだけなので、基本すべてEnterで大丈夫です。
必要であればアプリケーションの説明や、privateの設定など適宜入力して下さい。
値を入力して進めると、生成されるpackage.jsonの値が変わります。
もちろん後から変更もできます。
package.jsonの各項目については、こちらの記事が詳しいです。

qiita.com

npm package.json 日本語版 取扱説明書

実行結果

yarn init v1.3.2
question name (vue_ts_sample):
question version (1.0.0):
question description:
question entry point (index.js):
question repository url:
question author:
question license (MIT):
question private:
success Saved package.json
✨  Done in 9.21s.

生成されるpackage.json

{
  "name": "vue_ts_sample",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT"
}

この生成されたファイルに先程設定しなかった内容を直接記載することも可能なので、必要な場合は個別で編集してください。


yarnを利用してライブラリの追加

動かすまで必要なライブラリをyarnで追加します。

$yarn add webpack webpack-dev-server vue

実行すると、package.jsonが更新され、yarn.lockが生成されます。

package.json

{
  "name": "vue_ts_sample",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "vue": "^2.5.13",
    "webpack": "^3.10.0",
    "webpack-dev-server": "^2.10.1"
  }
}

package.jsonに追加された項目と、yarn.lockは、ライブラリの依存性とバージョンを管理しています。
* package.jsonのdependenciesの項目内が使用するライブラリとそのバージョン
* yarn.lockが実際にインストールされたライブラリとバージョン

を示しています。(Rubyを書いている方であれば、bundlerのGemfileとGemfile.lockだと思えば良いと思います。) package.jsonのdependenciesは、

{
  "dependencies": {
    "パッケージ名": "バージョン"
  }
}

の形式で追加されます。バージョンの横にある、^の意味が知りたい方は、

qiita.com

こちらの記事が参考になります。

yarn.lockをgitの管理下におけば、他の人は

$yarn install

を実行することでパッケージのバージョンを合わせることができます。

もしyarn.lockを更新したい場合は、

$yarn update

でパッケージがアップデートされ、yarn.lockが更新されます。


Vue.js + Webpack + yarn(npm)でのHelloWorldまで

必要なパッケージのインストールが終わったら、いよいよwebpackを利用してサンプルページでアクセスします。
プロジェクト配下にwebpack.config.jsを作成します。

const path = require('path');

module.exports = {
  // エントリーポイントの設定
  // プロジェクトルートからの相対パスで指定する
  // webpackでまとめるファイルの起点となるファイルを置く。
  entry: './src/index.js',
  output: {
    // webpackでまとめられたファイルの出力先の設定
    // pathで指定したパスに、filenameで指定した名前で吐き出される。
    // path.joinは、引数の文字列をOS応じたパスの区切り文字で結合してくれる。
    // また、__dirnameはプロジェクトルートのパスを返してくれる。
    path: path.join(__dirname, 'public'),
    filename: 'bundle.js'
  },
  devServer: {
    // webpack-dev-serverで起動するファイルの置き場所
    // ここに一番最初に表示するhtmlファイルを置く
    contentBase: 'public',
    // 起動ポート。デフォルトは8080。
    // 他のアプリケーションとかぶるようであれば変更
    port: 4000
  },
  resolve: {
    alias: {
      // vueのコンパイラの指定。
      'vue$': 'vue/dist/vue.esm.js'
    }
  }
};

resolveの中のコンパイラの指定については、詳細はjp.vuejs.org を参照して下さい。動かすだけであればとりあえずおまじないとして書いておいて問題ありません。

また、起動用のコマンド、コンパイル用コマンドをpackage.jsonに追加します。

{
  "name": "vue_ts_sample",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    // コンパイルのコマンド
    // yarn build
    // で実行
    "build": "webpack",
    // サーバー起動コマンド
    // yarn start
    // で実行
    "start": "webpack-dev-server"
  },
  "dependencies": {
    "vue": "^2.5.13",
    "webpack": "^3.10.0",
    "webpack-dev-server": "^2.10.1"
  }
}

package.jsonのscriptは、

{
  "script": {
    "コマンド名": "実行コマンド"
  }
}

の形式で追加されます。 これで、

$yarn build

コンパイル

$yarn start

でwebpack-dev-serverが起動するようになります。

これでconfigファイルの準備は完了したので、htmlファイルとjsファイルを追加します。

public/index.html

<html>
<body>
  <!--
    Vue.jsが参照するのに使う名前をidに指定
    Vue.jsで渡すデータの名前を{{}}の中に指定
  -->
  <div id="app">
    {{ message }}
  </div>
  <!-- webpack.config.jsのoutputで指定した、出力されるjsファイルの名前を指定 -->
  <script src="bundle.js"></script>
</body>
</html>

src/index.js

import Vue from 'vue'

const app = new Vue({
  // htmlで指定したid
  el: '#app',
  // htmlで{{}}で指定した名前と、渡すデータ。
  data: {
    message: 'Hello world!'
  }
})

ここまででやっと準備完了です。

ディレクトリ構成はおそらく

vue-ts-sample
┣ node_modules
┣ public
┃  ┗ index.html
┣ src
┃  ┗ index.js
┣ package.json
┣ webpack.config.js
┗ yarn.lock

こんな感じになってるかと思います。

$yarn build

を実行してコンパイルを行います。すると、public配下にbundle.jsが生成されて、

vue-ts-sample
┣ node_modules
┣ public
┃  ┣ bundle.js
┃  ┗ index.html
┣ src
┃  ┗ index.js
┣ package.json
┣ webpack.config.js
┗ yarn.lock

ディレクトリ構成がこうなるかと思います。

yarn start

でサーバーを起動します。 ずらーっとログが出ますが、

webpack: Compiled successfully.

の文字が出れば起動成功です。

localhost:4000(ポートを変えている場合はそのポート)にアクセスし、「Hello world!」が見れれば完了です!
お疲れ様でした!

CSS Grid Layoutのすすめ(パート1)

2回目投稿のシステム事業部の五十島です。 開発などではまだまだ取り入れられないですが、個人的に Grid Layoutが熱いので幾つかのパートに分けてご紹介です。

CSS Grid Layoutとは

簡潔に言いますと、「グリッドという概念を取り入れてレイアウトがしやすくなりました」ということです。 これだとよくわからないのでもう少し詳しく説明しますと、格子状に区切った区画にCSSで要素の位置を指定することができる仕様です。

現状のブラウザ対応状況はこんな感じです。(2017/12現在)

f:id:zenet-tech:20171219123355p:plain *1

IEが完全に対応していないので、サポート終了するまでは使えないのが残念です。 今後に期待したいところですね。


基本編 その1

以下のようにhtmlとcssを記述するとGrid Layoutが設定されます。 display: grid;でGrid Layoutの開始を宣言しています。 一見、普通のdivの集合に見えますが、ちゃんとGrid Layoutが有効になっています。 (Chromeで開発コンソールを使用すると点線が出現している!Gridっぽい!!!)

ソースコード
<div id="grid-main">
  <div>要素1 </div>
  <div>要素2</div>
  <div>要素3</div>
  <div>要素4</div>
  <div>要素5</div>
</div>
#grid-main {
  display: grid; /* grid layoutを指定 */
}
表示結果

f:id:zenet-tech:20171219123747p:plain

もう少し格子状っぽいレイアウトにしてみましょう。 次のようにCSSを書き換えてみました。 grid-template-columns で横の分割数とそのサイズを指定できます。 今回はfrという残りの範囲全てという単位を使っていますが、pxや%指定も可能です。 *2 1frを3つ指定してるため、ここでは3等分に分割しています。 ちなみに、repeat()という繰り返しの記法を使えば、grid-template-columns: repeat(3, 1fr);と書くことも可能です。 ちょっとプログラムっぽいですよね。

ソースコード
#grid-main {
  display: grid; /* grid layoutを指定 */
  grid-template-columns: 1fr 1fr 1fr; /* 3等分に分割 */
}
表示結果

f:id:zenet-tech:20171219125104p:plain *3

今度は高さを指定してみましょう。 CSSは次のように書き加えます。 grid-auto-rowsを設定することで、行を任意の高さにすることが可能になります。 今回は、100pxとしてみました。

ソースコード
#grid-main {
  display: grid; /* grid layoutを指定 */
  grid-template-columns: 1fr 1fr 1fr; /* 3等分に分割 */
  grid-auto-rows: 100px;
}
表示結果

f:id:zenet-tech:20171219131657p:plain


次回について

今回の説明はここまでです。 次回は、格子を複数利用したレイアウトの指定を説明していきたいと思います。

*1:https://caniuse.com/

*2:https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout の「fr単位」を参照

*3:格子状になっていることの確認のため、別で枠線と色をつけています。