Windows10のマスターイメージを作ってみよう!(修羅の作成編)

新機種PC 「 Windows7??自分搭載してないっすよww 」

Windows10「 よろしくーwwwwww 」
私「ああああああああああああああああああああああああああ」


どうも、インフラ部門でコソコソ働いているダーオカです。
皆様の会社は、もうWindows10を導入していますでしょうか?
まだ、Windows7の場合は、そろそろ導入しなければYABAI状況に陥ってるはずです。

しかし、いざ導入になった際にWindows10のマスターイメージ作成は一癖も二癖もあり調査などに時間を取られてしまいますよね。

なので、今回の記事ではWindows10を展開するにあたりに必要なマスターイメージの作成方法を一部ご紹介したいと思います。

マスターイメージを作成する流れとしては大まかに以下の流れとなっております。
1. Windows10を新規インストール
2. ストアアプリの削除
3. デバイスのドライバやソフトウェアのインストール
4. マスターイメージを作成する際にやっていた方が良い8つの設定 (ざっくりしすぎですね・・・)
5. Sysprepを実行してマスターイメージ化

一連の流れで2と4が重要な箇所になりますので、こちらを紹介させていただきます。

ストアアプリを削除

Microsoft コンシューマーエクスペリエンスでインストールされたストアアプリを削除しましょう。
ストアアプリがインストールされている場合、Sysprep が出来ない仕様になっています。

https://blogs.technet.microsoft.com/askcorejp/2015/12/20/windows-10-1511-sysprep/

アプリを削除する以外での回避方法としては以下の方法があるそうです。

  • インターネット接続しないでマスターイメージを作成する。
  • 一時的にグループ ポリシーを適用して自動でインストールされる機能を制限する。

私は、マスターイメージが完成した際に全ての動作確認を行いたいので、ストアアプリの削除を選びました。

では、始めにWindows10にインストールされているアプリケーションを調べてみましょう。

PowerShellを起動し下記のコマンドを入力します。

Get-AppxPackage | Where IsFramework -eq $false | Select Name,PackageFullName

コマンドを入力すると現在インストールされているアプリケーションが出てきましたね。

f:id:AdwaysEngineerBlog:20170629102329j:plain

インストールされているアプリケーションを削除するコマンドは下記に記述します。

Get-AppxPackage (削除したいアプリケーション名)| Remove-AppxPackage  

例: CandyCrushSodaSagaを削除する場合

Get-AppxPackage king.com.CandyCrushSodaSaga | Remove-AppxPackage

ストアアプリ以外で初期に入っているアプリケーションも上記のコマンドで削除可能です。
業務では使用しないアプリケーションとストアアプリを削除していきましょう。

ここで注意していただきたいのは、ユーザーごとにアプリケーションがインストールされるため、複数のアカウントを使用する場合は各アカウントで削除する必要があります。
また、削除できないアプリケーションもあるため、その場合はグループポリシーで利用禁止にしましょう。

あと時間差でインストールされるアプリもあるため、10分放置か一回アプリケーションを起動してから実行した方がいいかもしれません ぐぬぬ・・

マスターイメージを作成する際にやっていた方が良い8つの設定

Windows10のマスターイメージを作成する際に細かな設定を行なっていきたいと思います。

1.エクスプローラーに表示されているOneDriveを削除する。(グループポリシーでも設定可能)

「レジストリ エディター」を起動し
HKEY_CLASSES_ROOT\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}にある System. IsPinnedToNameSpaceTreeの値を1から0に変更する。

2.PowerShellを使用し 「ときどきスタート画面におすすめを表示する」を無効にする。

Set-ItemProperty HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\ContentDeliveryManager -name SystemPaneSuggestionsEnabled -Value 0

3.PowerShellを使用し 「よく使われるアプリの表示」を無効にする。

Set-ItemProperty HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced -name Start_TrackProgs -Value 0

4.PowerShellを使用し 「Pre-staged app cleanup」を無効化する。

Schtasks.exe /change /disable /tn "\Microsoft\Windows\AppxDeploymentClient\Pre-staged app cleanup"

5.PowerShellを使用し 「高速スタートアップ」を無効化する。

Set-ItemProperty 'HKLM:\SYSTEM\ControlSet001\Control\Session Manager\Power\' -name HiberbootEnabled -Value 0

6.コマンドプロンプトを使用し 「スタートアップ修復」を無効化する。

bcdedit /set {default} recoveryenabled No
bcdedit /set {default} bootstatuspolicy ignoreallfailures

7.スタートメニューにソフトウェアを手動で登録する。

下記のファイルを開きショートカットを設置するとスタートメニューに表示されます。 Windows(C:) → ProgramData → Microsoft → Windows → スタートメニュー → プログラム ※初期設定ではProgramDataは隠しファイルになっていますので、表示させましょう

8.カスタマイズしたスタート画面を他のアカウントに使わせたい場合

PowerShellを管理者として実行して以下のコマンドを入力します。

① スタート画面の情報をエクスポートする。
Set-Location ($ENV:Userprofile + "\desktop")
Export-Startlayout –path Startmenu.xml
② デフォルトプロファイルにスタート画面をインポートする。
Set-Location ($ENV:Userprofile + "\desktop")
Import-StartLayout –LayoutPath Startmenu.xml –MountPath C:\

以上で設定は完了です。後はSysprepすればマスターイメージの作成完了です。

本来はWDSなどを織り交ぜて説明を書きたかったのですが、一つの記事に纏められなかったのでまたの機会にご紹介したいと思っております・・・。

従量課金のクラウドサービスにおいて利用料金を管理・把握したいと思ってた~GCP編~

はじめまして。入社2年目、インフラの植垣です。

前職は営業をしており、エンジニア未経験でアドウェイズに入社し日々奮闘しております。

皆さん、クラウドサービスの課金(料金)ってどのように管理・監視されてますか?

利用しているサービスやアカウント、プロジェクト数が少なければ、管理画面でたまに見るというのはあまり大変ではありませんが管理するものが増えるほど地味に大変だと思います。

またAmazon Web ServicesGoogle Cloud Platform(以後GCP)は従量課金制のため
こまめに確認してあげると意図していない料金が請求されることを防ぐことができると思います。

そんなこんなで最近はGCPに携わっているのでGCPの課金周りでやってみたことについて少し書こうと思います。

GCPの課金データのエクスポートについて

GCPは課金データを請求先アカウント毎にエクスポート設定をすることができます。
エクスポート先は

  • BigQuery
  • Cloud Storage

を指定することが可能で、BigQueryの場合は事前にデータセットの作成、Cloud Storageの場合はバケットの作成をしておく必要があります。

さて、エクスポートされた課金データをどうしましょう?
課金データなので、プロジェクト毎、リソース毎といった細かい粒度で現在の利用料金について知れたらいいですよね。

Google先生に聞いてみるとBigQuery + DatastudioBigQuery + BIツールといった記事は見るのですが
Cloud Storageの方の活用シーンがあまり見られません。

ふむふむ。何かできないかな?と思ったところ、Cloud Functionsでイベントドリブン的な事ができるなと思ったのでとりあえずやってみました。

f:id:AdwaysEngineerBlog:20170623113251p:plain

全体のフローはこんな感じです。

さあ、やっていきましょう。まずは事前準備があるのでやっていきます。(今回はその方法については記載しません)

  • 課金データをエクスポートするバケットの作成
  • 課金データのエクスポート設定(Cloud Storage)
  • 課金データのエクスポート設定時に設定したprefixをつけたファイルを同じバケットにアップロード
    • ファイル名: prefixがbillingの場合はbilling.json
    • ファイルの中身: {}

実装

さあ、実装していきましょう。 まずは今回必要なライブラリをpackage.jsonに記載します。

package.json

{
  "name": "billing-notify",
  "version": "0.0.1",
  "dependencies": {
    "google-cloud": "latest",
    "@google-cloud/storage": "latest",
    "@slack/client": "latest"
  }
}

次に通知に関する設定やできるだけjsファイルのコード変更を行わずに色々コントロールしたいと思ったので設定ファイルを作成しました。
今回通知先はslackにしたのでslack.json、コントロールするファイルをopt.jsonファイルとしました。

slack.json

{
  "token": token, // 取得したトークン
  "message": {
    "channel": channel, // 通知するチャンネル
    "text": null,
    "opt": { // 通知に関するオプション
      "username": username // 通知するユーザの名前
    }
  }
}

opt.json

{
  "project": プロジェクト名, // Cloud Functionsのトリガーとして設定しているバケットがあるプロジェクト
  "billingPrefix": prefix, // 課金データのエクスポート設定時のprefix
  "contact": ["slack", "message"] // 通知方法
}

後はindex.jsに全ての処理を記載すればいいのですが、ファイルを分ける事も可能です。
今回はあまりプログラムは長くないためindex.jsに全て処理を記述することにしました。

index.js

var optObj = require('./opt.json');
exports.billingNotify = function(event, callback) {
  var dateBillingFileName = event.data.name;
  var billingPrefix = optObj["billingPrefix"];
  var billingRegexp = new RegExp(billingPrefix + '-\\d{4}-\\d{2}-\\d{2}');
  var aggregateBillingFileName = billingPrefix + ".json";
  if (!dateBillingFileName.match(billingRegexp)){
    callback();
    return;
  }
  var gcs = storage({
    projectId: optObj["project"]
  });
  var bucket = gcs.bucket(event.data.bucket);
  var dateBillingFile = bucket.file(dateBillingFileName);
  
  dateBillingFile.exists(function(err, exists) {
    if(!exists) {
      console.log(dateBillingFileName + " is not found");
      callback();
      return;
    }
  });
  var buffer = new Buffer('');
  dateBillingFile.createReadStream()
    .on('data', function(chunk) {
      buffer = Buffer.concat([buffer, chunk]);
    })
    .on('end', function() {
      var dateBillingObj = JSON.parse(buffer);
      var aggregateBillingFile = bucket.file(aggregateBillingFileName);
      buffer = new Buffer('');
      aggregateBillingFile.createReadStream()
        .on('data', function(chunk) {
          buffer = Buffer.concat([buffer, chunk]);
        })
        .on('end', function() {
          var aggregateBillingObj = JSON.parse(buffer);
          aggregateBillingObj = aggregateBilling(aggregateBillingObj, dateBillingObj);
          
          aggregateBillingFile.save(JSON.stringify(aggregateBillingObj), { metadata: {contentType: 'application/json'} }, function(err) {
            if(err) {
              console.log("save err = " + err);
              callback();
            } else {
              notify(createNotifyObj(aggregateBillingObj, createNotifyMonths(dateBillingObj)));
              callback();
            }
          });
      });
    });
};
function aggregateBilling(aggregateBillingObj, dateBillingObj) {
  dateBillingObj.forEach(function(billingObj) {
    var month = billingObj.startTime.match(/\d{4}-\d{2}/)[0];
    var project = billingObj.projectName;
    var service = billingObj.lineItemId.match(/services\/(.*)$/)[1].split("/");
  
    if (!aggregateBillingObj[project]) {
      aggregateBillingObj[project] = {};
    }
    if (aggregateBillingObj[project][month]) {
      aggregateBillingObj[project][month]["sum"] += parseFloat(billingObj.cost.amount);
    } else {
      aggregateBillingObj[project][month] = {"sum": 0.0};
    }
    
    if (aggregateBillingObj[project][month][service[0]]) {
      aggregateBillingObj[project][month][service[0]]["sum"] += parseFloat(billingObj.cost.amount);
    } else {
      aggregateBillingObj[project][month][service[0]] = {"sum": 0.0};
    }
    if (aggregateBillingObj[project][month][service[0]][service[1]]) {
      aggregateBillingObj[project][month][service[0]][service[1]] += parseFloat(billingObj.cost.amount);
    } else {
      aggregateBillingObj[project][month][service[0]][service[1]] = parseFloat(billingObj.cost.amount);
    }
  });
  return aggregateBillingObj;
}
function createNotifyMonths(dateBillingObj) {
  var notifyMonths = [];  
  dateBillingObj.forEach(function(billingObj) {
    var month = billingObj.startTime.match(/\d{4}-\d{2}/)[0];
    if (notifyMonths.indexOf(month) < 0) {
      notifyMonths.push(month);
    }
  });
  return notifyMonths;
}
function createNotifyObj(aggregateBillingObj, notifyMonths) {
  var tmpJsonObj = JSON.parse(JSON.stringify(aggregateBillingObj));
  var notifyObj = {};
  Object.keys(tmpJsonObj).forEach(function(key) {
    var tmp = {};
    notifyMonths.forEach(function(month) {
      tmp[month] = tmpJsonObj[key][month]
    });
    notifyObj[key] = tmp;
  });
  return notifyObj;
}
function notify(notifyObj) {
  var contact = optObj["contact"];
  switch (contact[0]) {
    case "slack":
      var webClient = require('@slack/client').WebClient;
      var opt = require('./slack.json');
      var client = new webClient(opt["token"]);
      var notifyOpt = opt[contact[1]];
      switch (contact[1]) {
        case "message":
          client.chat.postMessage(notifyOpt["channel"], JSON.stringify(notifyObj, null, "\t"), notifyOpt["opt"],function(err, res) {
            if(err) {
              console.log("Error: ", err);
            }
          });
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }
}

後はデプロイするだけです。Cloud SDKでCloud Functionsをデプロイすると同じディレクトリにある全てのファイルをzipにまとめてデプロイしてくれるのでとても便利です。

gcloud beta functions deploy billingNotify --trigger-bucket bucketName --stage-bucket bucketName

後は課金データがCloud Storageにエクスポートされるとこんな感じで通知されます。

{
    プロジェクト名: {
        yyyy-mm: {
            "sum": 10,
            "big-query": { 
                "sum": 5,
                "ActiveStorage": 0,
                "Storage": 0,
                "StreamingInsertBytes": 5,
                "Analysis": 0
            },
            "app-engine": {
                "sum": 0,
                "OutgoingBandwidthJp": 0
            },
            "cloud-storage": {
                "sum": 10.5,
                "ClassARequestMultiRegional": 10.0,
                "StorageMultiRegionalUsGbsec": 0,
                "StorageRegionalJapanGbsec": 0.5
            }
        }
    },
    プロジェクト名: {
        yyyy-mm: {
          ・・・
        }
    }
}

さいごに

Cloud StorageにエクスポートされたデータをCloud Functionsを使って通知させることができました。
・・・・・ふむ。BigQueryにエクスポートできるのは便利だな、と正直思いました。
やはりBIツールと簡単に連携できるのがいいですよね。
Cloud Storageにエクスポートするのは、あくまでバックアップ的な意味合いに使われているのかなとやってみて思いました。
ただBIツールの画面をわざわざ開かなくても普段よく見るchatツールで手軽に見る事ができるのは便利ですよね。
単純に現在の利用額について知りたいという目的ならCloud Storage + Cloud Functionsの組み合わせもありだなと思いました。

それでは今回はこのあたりで失礼します。

Google Cloud Functionsで遊んでみる

こんにちは、久保田です。

最近、GoogleのCloud FunctionsでAPIを作りました。

作ったのはTODO管理のAPIで、ストレージはDataStoreを使いました。

Cloud FunctionsはGCP内のイベントはもちろん、Firebaseからも使える上に、エンドポイントも提供してくれるので幅広い使い方を楽しめそうです。
さらに、Cloud Functionsはローカルエミュレータもあり、開発もしやすかったです。

今回は僕が作ったAPIの一部分を例にしながら、CloudFunctionsの開発について書きます。

開発環境の用意

まずは開発環境を用意します。

Cloud Functionsは現在node.jsの6.9.1しか対応していないようですので、合わせておいた方がいいかと思います。

先述した通り、ローカルエミュレータというものがあり、ローカルでCloudFunctionsとほぼ同一の環境を用意し、コードを動かすことのできる環境を作ることができます。

なのでまずはローカルエミュレータの構築から行います。

github.com

とは言ってもnpmとかでできてしまいます。
構築が終わると、functionsコマンドが叩けるようになります。

その後はREADMEに書いてある通り、index.jsを作り、

$ functions start
$ functions deploy 関数名 --trigger-http 

これでhttp経由で動かすことのできる関数が完成です。
deployコマンドの関数名はindex.js内でexportしている関数名です。
あとはファイルを更新したら自動で更新されます。

最初のfunctionsコマンド実行時、gcloudコマンドがない場合はプロジェクトIDを聞かれますので、対象のプロジェクトIDを入力する必要があります。

※ エミュレータで動かすだけならばgcloudコマンドは必要ありませんが、GCPの他のリソースをCloud Functionsから触ったりする場合はcredentialが必要なので、gcloudコマンドを使って認証をしておいてください。

※ Dockerfileを作ったので、よかったら参考にしてください。

github.com

実装

開発環境は整ったので、どんどん実装していきます。
今回はDataStoreからデータを取得してくるところのみ言及します。

まずはpackage.jsonです。

{
  "name": "helloWorld",
  "version": "0.0.1",
  "dependencies": {
    "@google-cloud/datastore": "latest"
  }
}

次はデータの取得処理です。
DataStoreにサンプルデータを登録してある状態です。

exports.helloWorld = function helloWorld(req, res) {
  datastore = require('@google-cloud/datastore')({
    projectId: プロジェクトID
  });

  var q = datastore.createQuery('Todo');
  q.run(function(err, entities, info){
    console.log("=========");
    console.log(entities);
    console.log("=========");
    res.send(entities);
  })
}

データの取得だけならばこれでできます。

実装したら、deployして実行してみます。

$ functions deploy helloWorld --trigger-http 
$ functions call helloWorld

こうすると、DataStoreに登録してあるデータが返ってきます。
(ちなみcallで実行するとPOSTで実行されます。)

ExecutionId: a2be0798-e886-4cd8-854a-51cc1bea8178
Result: [ { tags: [ 1, 3 ],
    name: 'todo1',
    created: '2017-06-09T05:09:11.244Z' },
  { tags: [ 5, 7 ], name: 'todo2', created: 1497442628874 } ]

※ 今回のデータ構造として、Todoという種類にname, created, tagsというプロパティで構成されたエンティティが入っています。

ログも見れます。

$ functions logs read
2017-06-14T17:28:40.992Z - info: User function triggered, starting execution
2017-06-14T17:28:41.328Z - info: =========
2017-06-14T17:28:41.330Z - info: [ { created: 2017-06-09T05:09:11.244Z,
    tags: [ 1, 3 ],
    name: 'camp' },
  { name: 'コストコ', created: 1497442628874, tags: [ 5, 7 ] } ]
=========
2017-06-14T17:28:41.333Z - info: Execution took 339 ms, user function completed successfully

このままではあまり面白くないので、パラメータを受け取り絞り込みをしてみます。

exports.helloWorld = function helloWorld(req, res) {
  datastore = require('@google-cloud/datastore')({
    projectId: プロジェクトID
  });

  // functions call で実行するとPOSTになるため、req.bodyでパラメータを取得する。
  // curlなどで実行した場合はreq.queryになる。
  var q = datastore.createQuery('Todo').filter('name', req.body['name']);

  q.run(function(err, entities, info){
    console.log("=========");
    console.log(entities);
    console.log("=========");
    res.send(entities);
  })
}

実行時にパラメータを渡せます。jsonファイルからも渡せます。(その際のオプションは –file=filepath)

$ functions call helloWorld --data='{"name": "todo1"}'
ExecutionId: 2186b22d-0682-4106-91aa-b8b452958839
Result: [ { name: 'todo1',
    created: '2017-06-09T05:09:11.244Z',
    tags: [ 1, 3 ] } ]

できました。

あとはgcloud経由でもGUI経由でもデプロイしてみてください。

記事では取得しかしていませんが、CRUD操作はすべてしたので、他の処理はgithubをみてください。

github.com

Cloud Functionsのおかげで、GCPのリソースを組み合わせていけば、サーバーを構築せずに簡単なAPIが作れてしまいました。
皆さんも簡単なものを作りたいときはぜひ使ってみてください!

three.jsで誰でも簡単に宇宙を創造

ウェブブラウザ上で簡単に3D空間を再現し、 好きな惑星をつくって自分だけの宇宙を眺めませんか?

初めまして。2016年新卒入社のデザイナー、相原です。
入社後は暫くバナー制作をしていましたが、
去年の9月からフロントエンドユニットに異動して働いています。

最近、three.jsで私の大好きな宇宙をつくったので紹介します。
好きな惑星を好きな位置に置けるのでとても楽しいです。

three.jsとは

ウェブブラウザ上で3DCGを描画できる、JavaScriptライブラリです。
HTML5のcanvas要素、WebGLなどとの組み合わせが可能です。

対応ブラウザ

Firefoxをお使いの方は部分対応なのでお気をつけください。 f:id:AdwaysEngineerBlog:20170607190822p:plain

three.jsのダウンロード

まずは公式サイト左のdownloadリンクからダウンロードします。
ダウンロードファイル内の/build/ディレクトリからthree.min.jsを、作業する/js/ディレクトリへコピーする。
f:id:AdwaysEngineerBlog:20170607190923p:plain

HTMLの用意

HTMLはこれだけです。
これから記述していくJavaScriptはmain.jsとします。

<!DOCTYPE html>
<html>
  <head lang="ja">
    <meta charset="utf-8">
    <title>宇宙の創造</title>
    <style>
      canvas{width: 100%; height: 100%;}
    </style>
  </head>
  <body>
    <script src="js/three.min.js"></script>
    <script src="js/main.js"></script>
  </body>
</html>

three.js

まずmain.jsに下記のコードを記述します。

var width = window.innerWidth;
var height = window.innerHeight;
var fov = 100; //画角
var aspect = width / height; //撮影結果の縦横比
var near = 1; //撮影する一番手前
var far = 1000; //撮影する一番奥

var scene = new THREE.Scene(); //宇宙空間となる基本部分
var camera = new THREE.PerspectiveCamera(fov, width / height, near, far); //視点の設定
camera.position.z = 5;
var renderer = new THREE.WebGLRenderer(); //宇宙空間とする範囲の設定
renderer.setSize( width, height );
document.body.appendChild( renderer.domElement ); //宇宙の始まり、ビックバン

function render() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}
render();

表示確認をして、canvas全体が黒く表示されていれば問題ありません。
ビックバン成功です。
では惑星を産み出していきましょう。

まずはメイン、地球をつくっちゃいます。
render(); の上に記述してください。

var geometry_earth = new THREE.SphereGeometry(2,20,20,); //球体の設定
var texture_earth = new THREE.ImageUtils.loadTexture('https://earthobservatory.nasa.gov/Features/BlueMarble/Images/land_ocean_ice_2048.jpg'); //テクスチャの設定
var material_earth = new THREE.MeshBasicMaterial({
  map: texture_earth,
  color: 0xFFFFFF
});
var earth = new THREE.Mesh( geometry_earth, material_earth );
scene.add(earth); //宇宙空間へ地球の追加

また、地球は自転しているので、render処理の中に下記のコードを追記します。

function render() {
  requestAnimationFrame(render);
  earth.rotation.y += 0.002; // ※追記 自転させる
  renderer.render(scene, camera);
}

これで地球は完成です。
f:id:AdwaysEngineerBlog:20170607191101g:plain

同じ要領で太陽と月も置いてみました。
月と太陽の場所は earth.position.set(-3,0,2); と別で場所を設定しています。
f:id:AdwaysEngineerBlog:20170607191340p:plain

最後に星を散らしましょう。

var addRabomStar = function(){
  var geometry_star = new THREE.Geometry();
  for (i = 0; i < 900; i ++){
    var dod = new THREE.Vector3(Math.random() * 2000 - 1000,Math.random() * 2000 - 1000,Math.random() * 2000 - 1000);
    geometry_star.vertices.push(dod);
  }
  for(var i = 0; i < 5; i++){
    var material_star = new THREE.ParticleBasicMaterial({
      color: 0xFFFFFF,
      size: 1,
      blending: THREE.AdditiveBlending,
      transparent: true
    });
    var particles = new THREE.ParticleSystem(geometry_star, material_star);
    particles.rotation.set(Math.random() * 6,Math.random() * 6,Math.random() * 6);
    scene.add(particles);
  }
}
addRabomStar();

基本的にオブジェクトの作り方は同じで、
900個の星をランダムの場所に配置しています。
f:id:AdwaysEngineerBlog:20170607191357p:plain

これでザッと宇宙の完成です。

ちなみに、テクスチャはこちらのものを使用しています。

さいごに

3Dと聞くと少し難しく感じてしまいますが、
実際にやってみると今まで出来なかったことを実現出来てとても面白かったです。

今回は球体のみですが、他にも色々な形や動きをつけることが出来るので、
是非オリジナルの宇宙を創造してみてください。

私は近いうちに人工衛星でも打ち上げてみようかと思います。

Vue.jsでルーツ音楽診断ゲームを作ってみた

こんにちは。フロントエンドエンジニアの田渕です。
2015年4月に中途入社して早3年目です。
前職はWeb制作会社でディレクター兼マークアップエンジニアをしてました。

最近流行りのVue.jsを使ってちょっとした診断ゲームを作ったので紹介します。
まずは以下を実際に遊んでみてください。

ルーツ音楽診断

はい。趣味丸出しです。
ルーツ・ミュージックに興味を持ってくれる人が一人でも増えたらいいなと思います。

技術的な話

Vue.jsを使ったメリットは以下です。

  • ページ遷移を非同期でおこなえる
  • ページ遷移時にトランジション(アニメーション効果)をつけられる

Vue.jsでできることはまだまだありますが、Webサイトのページ遷移にちょっとした効果がついているだけでもそれっぽくなるかと思います。

実際に使ったものは以下です。

  • Vue.js(JavaScriptフレームワーク)
  • webpack(モジュールバンドラー)
  • pug(Node製テンプレートエンジン)
  • Sass(AltCSS)
  • babel(JavaScriptの次世代の標準機能のトランスパイル)
  • yarn(パッケージマネージャ)

パッケージは他にも使ってますが主要なものは大体こんな感じ。
現時点でのフロントエンド開発で比較的オーソドックスな組み合わせだと思います。
もちろん環境に合わせてそれぞれ違うものを導入するので、一例くらいに考えていただければと思います。

Vue.js

Vue.jsはページ単位、コンポーネント単位で管理できるので割りと気に入ってます。
pugとSassは効率的に書けて良い感じです。
babelは新規で作るなら使っていきたいですね。
Vue.jsのコンポーネントはこんな感じです。 GlobalHeader.vue

<template lang="pug">
  header.contentHeader.container
    p.contentHeader_title
      | ルーツ音楽診断
</template>
<style lang="scss">
.contentHeader {
  text-align: center;
  &_title {
    margin: 40px 0 70px;
    color: #fff;
    font-size: 38px;
    font-weight: bold;
    line-height: 1;
    text-shadow:
      -3px -3px 0 #222,
       3px -3px 0 #222,
      -3px 3px 0 #222,
       3px 3px 0 #222,
       4px 4px 0 #fff,
       5px 5px 0 #fff,
       6px 6px 0 #fff,
       7px 7px 0 #fff;
  }
}
</style>

vueファイルにHTML, CSS, JavaScriptをまとめて書けます。
今回はpugとSassを使うためlang属性で指定しています。
使いたいページや親コンポーネントにコンポーネントを入れることで、複数ページに同じようなコードが散乱することを回避できます。

Vue.jsを使うには大抵webpackを使うことになります。
webpackでいろんなファイルを一つにまとめます。vueファイルとかjsファイルとか。
Vue.jsを勉強していると思ったら、いつの間にかwebpackを勉強していた。な…何を言っているのかわからねーと思うが(ry
みたいな楽しいことになります。
元ネタがわからない人は「ありのまま今起こったこと」でぐぐってください。

トランスパイル言語

pug、Sass、babelはプロジェクトに合わせて選べば良いと思います。

  • Rubyでの開発だからpugではなくslim。
  • Node製で固めたいのでSassではなくStylus。
  • 型が欲しいのでbabelではなくTypeScript。

みたいな感じ。
実際の開発への導入だと、開発スピードやプロジェクトメンバー、好み等によって判断することが多いかと思います。
自分の周りの状況に合わせて勉強すると効率的ですね。

yarn

yarnはいいぞ。

さいごに

新しい技術や初めての技術に触れるのはとても楽しいですね。
今回一番テンション上がってたのは、コンテンツ内容を考えてる時でした。←
技術も楽しいですが企画も楽しいです。
いろんな技術を学んでいくことでエンジニアならではの企画を思いつくこともあると思います。
ただ技術を学ぶだけでなく、ぜひ何か新しいことができないか妄想しながら考えながら学んでみてください。

楽しくモノ作りしていきましょう。