20190710のJavaScriptに関する記事は27件です。

redux-form (6) - ユーザ登録

redux-form (1) - Simple Form Example
redux-form (2) - Synchronous Validation Example
redux-form (3) - Field-Level Validation Example
redux-form (4) - Submit Validation Example
redux-form (5) - Initialize From State
redux-form (6) - ユーザ登録


ReactでForm componentを作るときに、とても便利なredux-formの説明です。

redux-formの概説についてはまず以下の記事を参考にしてください。

redux-form (1) - Simple Form Example

今回は少し実用を意識して、ユーザ登録を実装します。UIコンポネントを作成するためにantdを使います。
React UI library の antd について (1) - Button

ユーザ登録

画面イメージ

画面イメージです。antdを使っているので、簡単にアイコンで装飾できます。

image.png

環境設定

まずは開発環境を構築します。

yarn create react-app antd-demo
cd antd-demo
yarn add redux react-redux redux-form redux-logger antd

念のため、package.jsonを掲載しておきます。

package.json
{
  "name": "antd-demo",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "antd": "^3.20.0",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-redux": "^7.1.0",
    "react-scripts": "3.0.1",
    "redux": "^4.0.1",
    "redux-form": "^8.2.4",
    "redux-logger": "^3.0.6"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

ソースコード

ユーザの配列を保持する Redux state を定義します。ユーザを追加するだけの簡単なものにします。

src/reducers
const users = (state = [], action) => {
  switch (action.type) {
    case 'ADD_USER': // *** userを追加
      return [
        ...state,    // *** 分割代入、stateに追加
        {
          email: action.user.email,
          name: action.user.name,
          password: action.user.password
        }
      ]
    default:
      return state
  }
}

export default users

これもユーザを追加するactionだけを定義します。

src/actions.js
export const addUser = user => ({
  type: 'ADD_USER',
  user: user
})

index.jsです。ユーザ登録のみの簡単な機能しかありませんが、redux-loggerredux-formを組み合わせているので、少し複雑かもしれません。

src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { createStore, combineReducers, applyMiddleware } from 'redux'
import { reducer as reduxFormReducer } from 'redux-form'
import logger from 'redux-logger'
import Register from './Register'
import users from './reducers'
import { addUser } from './actions'

const dest = document.getElementById('root')
const reducer = combineReducers({
  users,
  form: reduxFormReducer
})
const store = createStore(
    reducer,
    applyMiddleware(logger)
)

const showResults = values =>
  new Promise(resolve => {
    setTimeout(() => {
      // simulate server latency
      console.log(`submitted:${JSON.stringify(values, null, 2)}`)
      store.dispatch(addUser(values));
      resolve()
    }, 500)
  })

// redux-formを使っているのでProviderは必要
let render = () => {
  ReactDOM.hydrate(
    <Provider store={store}>
      <Register onSubmit={showResults} />
    </Provider>,
    dest
  )
}

render()

ユーザ登録画面の構築には、antdとredux-formを組み合わせて作っているので、少し複雑です。

  • Register componentの大枠はantdFormを利用しています。
  • Formの子要素にはredux-formField を利用しています。
  • 更にFieldのcomponent属性にantdInput(で作られたcomponent)を利用しています。

antdとredux-formを組み合わせについては、以下の記事も参照ください。
React UI library の antd について (3) - redux-form

redux-formによるvalidateはシンプルなのでいいですね。

src/Register.js
import React from 'react';
import PropTypes from 'prop-types';
import { Form, Icon, Button } from 'antd';
import { Field, reduxForm } from 'redux-form';
import renderInput from './input';
import 'antd/dist/antd.css';

import './style.css';

const RegisterForm = props => {
  const { handleSubmit, pristine, submitting, message } = props;

  return (
    <Form onSubmit={handleSubmit} className="form-register-containers">
        <h1 className="center">
          ユーザ登録
        </h1>
        <Field
          name="email"
          hasFeedback
          component={renderInput}
          disabled={submitting}
          label="メールアドレス"
          placeholder="メールアドレス"
          prefix={<Icon type="mail" style={{ color: 'rgba(0,0,0,.25)' }} />}
        />
        <Field
          hasFeedback
          type="password"
          name="password"
          component={renderInput}
          disabled={submitting}
          label="パスワード"
          placeholder="パスワード"
          prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
        />
        <Field
          hasFeedback
          type="password"
          name="confirmPassword"
          component={renderInput}
          disabled={submitting}
          label="確認用パスワード"
          placeholder="確認用パスワード"
          prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
        />
        <Field
          hasFeedback
          name="name"
          component={renderInput}
          disabled={submitting}
          label="お名前"
          placeholder="お名前"
          prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
        />
        <Form.Item className="center">
          <Button
            type="primary"
            htmlType="submit"
            className="btn-submit"
            disabled={pristine || submitting}
          >
            ユーザ登録
          </Button>
        </Form.Item>
        {!!message && <p className="caption-invalid">{message}</p>}
    </Form>
  );
};

// redux-formのvalidate
const validate = values => {
  const errors = {};
  if (!values.email) {
    errors.email = 'Required';
  } else if (
    !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)
  ) {
    errors.email = 'Invalid email address';
  }

  if (!values.password) {
    errors.password = "Password can't be blank";
  }

  if (!values.confirmPassword) {
    errors.confirmPassword = "Confirm password can't be blank";
  }

  if (
    values.password &&
    values.confirmPassword &&
    values.password !== values.confirmPassword
  ) {
    errors.confirmPassword = "Confirm password didn't match";
  }

  if (!values.name) {
    errors.name = "Name can't be blank";
  }

  return errors;
};

RegisterForm.propTypes = {
  pristine: PropTypes.bool,
  message: PropTypes.string,
  submitting: PropTypes.bool,
  handleSubmit: PropTypes.func,
};

export default reduxForm({
  form: 'register-form',
  validate,
})(RegisterForm);

以下がrenderInput componentのソースです。propsを展開して、inputやrestを取り出していることに注目してください。そのままInput componentに展開されます。特に(1)input object (redux-form) はvalueを含んでおり、(2)Input (antd component) のvalue属性の値としてそのまま適用されます。このvalueはactionによりRedux stateにbindされています。またrestにはprefixが含まれており、そのままアイコン情報が展開されます。
(1) Redux-form Fieldのinput object
(2) Antd Input component

src/input.js
import React from 'react';
import { Form, Input } from 'antd';

const newComponent = props => {
  const { input, meta, hasFeedback, label, ...rest } = props;
  const hasError = meta.touched && meta.invalid;

  return (
    <Form.Item
      label={label}
      help={hasError && meta.error}
      hasFeedback={hasFeedback && hasError}
      validateStatus={hasError ? 'error' : 'success'}
    >
      <Input {...input} {...rest} />
    </Form.Item>
  );
};

export default newComponent;

実行結果

redux-formのエラーメッセージ
image.png

登録時の redux-logger のログ
image.png

今回は以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

fitbitアプリでできることを調べてみた

fitbit APIリファレンスより、Device APIをひととおり調べてみた。
APIバージョンは3.1。

Accelerometer

加速度

Barometer

気圧計

Body-presence

fitbitを装着しているかどうか

Clock

時計機能
時・分・秒単位でtickイベントをとることも

Device

fitbitデバイスのモデルやバージョン、スクリーンサイズなどを取得

Display

ディスプレイの状態、ON/OFFや明るさなどを取得・制御できる

Document

画面のいろいろなイベントの取得、SVG制御など

Exercise

エクササイズ情報へのアクセスや、状態の制御
ランニング、サイクリング、水泳など

Geolocation

位置情報

Gyroscope

ジャイロ情報。fitbitの姿勢(角度)

Haptics

バイブ制御

Heart-rate

心拍数を取得

Messaging

スマホ側のコンパニオンアプリと通信

Orientation

地磁気センサーによる向きの取得

Power

バッテリー情報(残量や充電状況)の取得

System

システム情報取得のほか、他のアプリの起動もできそう

User-activity

活動時間、消費カロリー、移動距離、上った階数、歩数それぞれの現在値と、1日の目標値を取得

User-profile

登録されているユーザープロフィールの取得(身長・体重・年齢なども)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【iOS】 Cloud Functions for Firebaseを使ってアプリにサーバ日時取得処理を追加する

はじめに

ライセンスの期限チェックやゲームの時間チート対策など、端末の日時ではなくサーバの日時が欲しいケースがあります。
Google Firebaseの1機能であるCloud Functions for Firebaseを使うことで、容易にサーバ日時取得処理をアプリに追加できます。

Cloud Functions for Firebaseとは

アプリなどの環境から、Googleクラウド上にデプロイしているバックエンドコードを実行することができる機能です。
毎月200万回、処理時間100万秒、トラフィック容量5GBまでであれば無料で利用できます。2019/7/10現在

前提条件

この記事を利用するにあたり、次の状態を前提とします。
- 処理を追加するXcodeプロジェクトが存在する
- Google Firebase上にプロジェクトを作成し、Xcodeプロジェクトに導入している
- XcodeプロジェクトにCocoaPodsからFirebaseを導入している
- Xcodeプロジェクトで、Firebaseの初期化処理を実装している

CocoaPodsを使っていない場合など環境が異なる場合は、記事の該当部分について適宜対応してください。

環境の構築

上の項目から順番にインストールしていきます。
すでにインストール済みの場合、スキップして次の項目に移ってください。

Node.jsとnpmのインストール

Node.js公式サイトにアクセスし、インストーラーをダウンロードしインストールします。
インストール後ターミナルで次のコマンドを入力し、バージョン情報を得られたらインストール完了です。

$ node --version
$ npm --version

Firebase CLIのインストール

ターミナルで次のコマンドを入力し、Firebase CLIをインストールします。

$ npm install -g firebase-tools

バックエンド用プロジェクトの作成

管理しやすい場所(Xcodeプロジェクトフォルダの直下など)に適当なフォルダを作成します。(以降バックエンドフォルダ)

$ mkdir FirebaseFunctions

ターミナルで作成したフォルダに移動し、次のコマンドを入力します。

$ firebase init

実行するといくつか選択項目が表示されるので、次の値を選択します。
- 利用する機能:Functions: Configure and deploy Cloud Functions
- デフォルトのFirebaseプロジェクト:作成したFirebaseプロジェクトを選択します
- 言語:JavaScript
- ESLintを利用するか:好みで選択します。単純な機能を実装するため、Nで問題ありません
- 今すぐ依存関係をインストールするか:Y
以上の手順でバックエンドフォルダ直下にファイル一式が作成されます。

バックエンドコードの記述

サーバ日時を取得するためのコードを記述します。
バックエンドフォルダ/functions/index.js に次のコードを追加します。

バックエンドフォルダ/functions/index.js
exports.ServerTime = functions.https.onRequest((request, response) => {
    var dt = new Date();
    var delta = dt.getTime();
    response.send({
        data: String(delta)
    });
});

バックエンドコードのデプロイ

ターミナルで次のコマンドを入力し、ログインします。

$ firebase login

ログインしている状態で次のコマンドを入力し、デプロイを実行します。

$ firebase deploy

Deploy complete!と表示されたらデプロイ完了です。
ターミナルに出力されたProject ConsoleのURLを開き、Functionsからデプロイした関数を確認できます。

XCodeプロジェクト側の実装

SDKのインストール

CocoaPodsからFirebaseFunctionsをインストールします。
podfileに次の行を追記します。

pod 'Firebase/Functions'

追記後ターミナルで次のコマンドを入力し、インストールを実行します。

$ pod install

サーバ日時取得処理の実装

この記事ではサンプルとして、アプリ起動時にサーバ日時を取得しログ出力するよう実装します。
ViewController.swiftに次のコードを記述します。

ViewController.swift
import FirebaseFunctions

class ViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let functions = Functions.functions()
        functions.httpsCallable("ServerTime").call { result, error in
            if let error = error {
                debugPrint(error.localizedDescription)
            } else {
                if let data = result?.data as? String {
                    let ms = UInt64(data) ?? 0
                    let timeInterval = TimeInterval(ms) * 0.001
                    let date = Date(timeIntervalSince1970: timeInterval)
                    debugPrint("サーバ日時: \(date.description(with: Locale.current))")
                } else {
                    debugPrint("受信データなし")
                }
            }
        }
    }
}

実行し、次のようなログが出力されれば成功です。

"サーバ日時: Wednesday, July 10, 2019 21:02:43 Japan Standard Time"

メモ

サーバ日時はミリ秒で得られる為、Date型に変換する際は0.001を掛けて秒に変換する必要があります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

concatだらけになるtemplate literal

Babelで変換されたあとのコードを見ると、一見無駄にも思えるコードが生成されていたのですが、実はそれが必要だった、というお話です。

Template Literalとは

ES5までのJavaScriptでは、文字列を合成するには「1つ1つ+演算子で連結していく」「Array.prototype.joinで連結する」などの手法があったのですが、どちらの方法にしてもどのような構造の文字列ができるか、分かりづらいものでした。

ES6では、他言語のように文字列途中で式展開ができる、Template Literalが登場しています1。引用符として`...`を使い、式展開はその途中に${...}と書くという、他言語と比べてもそこまで違和感のない記法となっています。

Babelでの変換結果

で、例によってIEは非対応なので(MDN)、IEを切り捨てられない環境ではBabelでの変換が必要となります。この変換を行う@babel/plugin-transform-template-literalsでは、通常モードとlooseモードの2通りの変換が選べます。

// 変換前
const a = `${foo}-${bar}-${baz}`;

// 通常モード
var a = "".concat(foo, "-").concat(bar, "-").concat(baz);

// looseモード
var a = foo + "-" + bar + "-" + baz;

多くの人は、looseモードの方の結果を想像していたことでしょう。

ここまで長くなる理由

.concatによる文字列変換

JavaScriptで一般に思いつく「文字列への変換」といえば、以下の2つかと思います。

  • String(値)による文字列変換
  • '' + 値として、暗黙の変換を活用する

これらは、以下のような動作をします。

  • String(値)…シンボルの場合はSymbolDescriptiveStringSymbol.prototype.toString())を返して、それ以外のときはToString抽象操作を行う(ES2019 §21.1.1.1
  • 文字列連結の演算…ToPrimitive抽象操作を行ってから、ToString抽象操作を行う(ES2019 §12.8.3.1

というように、挙動が異なっています。

一方で、Template Literalに埋め込んだ式は、ToString抽象操作により文字列に変換されるため(ES2019 §12.2.9.6)、上のどちらとも異なっています。そこで登場するのがString.prototype.concatで、これは引数に対してToStringのみを行う仕様となっていますので(ES2019 §21.1.3.4)、仕様どおりの動作を実現させるために文字列変換と連結に.concatを使用するようになっています。

なお、文字列連結とconcatで挙動が違うオブジェクトは以下のようなものです(プリミティブはToPrimitiveで変化しないので、差異はありません)。

  • [Symbol.toPrimitive].toString()と違う結果を返すオブジェクト
  • [Symbol.toPrimitive]がなく、.valueOf().toString()と異なる文字列表記になるプリミティブを返すオブジェクト

なお、Date.valueOf().toString()の結果が異なりますが、別途で[Symbol.toPrimitive]を用意してあるため、文字列連結しても.valueOf()の値が出てくることはありません。

複数の.concat

ここまでで.concatを使う意味については説明してきましたが、「それなら''.concat(foo, "-", bar, "-", baz)でもいいんじゃないか?」と思ってしまうかもしれません。

ということで、Template Literalの処理を見返してみると、与えられた式展開の式1つ1つに対して、式の評価、ToStringを行っては文字列連結、というように進んでいきます。一方で、メソッドを呼ぶ場合、メソッドの引数はすべてメソッドの実行前に評価されてしまいます。つまり、ここで評価順が違ってきます。

.concatを複数にすることで、1つ目の式の評価、ToStringが終わってから2つ目の式の評価に移るというように、評価順序まで正確に同じものとするようになっています。

もっとも、この両者で違ってくるシナリオとしては、

  • ToStringすると例外が飛ぶような式が前の方に入っていたときに、後の式の評価で生じる副作用が起きるか起きないかの違い
  • 前の方の式についてToStringが副作用を持ち、それが後の式の評価やToStringの結果に影響を及ぼす場合

が考えられますが、ToStringが副作用を持つオブジェクトを作っても極めて使いにくいでしょうし、ToStringすると例外が飛ぶような式を文字列に埋め込んで、なおかつその例外が飛ぶパスを、他の式展開で副作用の起きるかどうかまで想定したコードを書く、という場面も考えづらいので、実用的に差異が出る危険性は薄そうです(そもそも、式展開の中に副作用の伴う式を書くこと自体、そう多くないと思いますし)。


  1. 雛形になる文字列と、式展開された値をまとめて関数に投げられるような、タグ付きTemplate Literalもありますが、とりあえず本稿では触れません。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Monaco Editorでprettierをフォーマッタとして登録する

技書博では東京ラビットハウスというサークルでEffective React Hooksという本を出そうと執筆中のerukitiです。今回はその執筆過程ででてきたものを記事にしています。

Monaco Editor で CMD/CTRL + S をセーブっぽい挙動にする - Qiitaと関連する記事なのですが、タイトルの通りです。

Monaco Editorにフォーマッタを登録する

monaco.languages.registerDocumentFormattingEditProvider('javascript', {
  async provideDocumentFormattingEdits(model) {
    const prettier = await import('prettier/standalone')
    const babylon = await import('prettier/parser-babylon')
    const text = prettier.format(model.getValue(), {
      parser: 'babel',
      plugins: [babylon],
      singleQuote: true,
      tabWidth: 2
    })

    return [
      {
        range: model.getFullModelRange(),
        text
      }
    ]
  }
})

monaco.languages.registerDocumentFormattingEditProviderを呼び出して、フォーマットするコールバックを登録するだけです。

babylonは、Babelのパーサーの以前の名前です。そのため、{parser: 'babel'}を指定するのですが、プラグインの名前は未だにprettier/parser-babylonというのが解せないですが、そういうものです。たぶん。

ここで登録するプロバイダ関数は、編集履歴を配列に入れて返す物です。{range: model.getFullModelRange()}によってエディタのテキスト全体を、変換済みのtext でリプレースするというものです。

もちろん、rangeを別のものにすれば、特定の範囲を削除、置換したり、追記したりすることができますが、インクリメンタルパーサーの仕組みとかを使っていれば話は別かもしれませんが、FormattingEditProviderでそういうことをする機会はあまり無いでしょう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Monaco Editor で CMD/CTRL + S をセーブっぽい挙動にする

技書博では東京ラビットハウスというサークルでEffective React Hooksという本を出そうと執筆中のerukitiです。今回はその執筆過程ででてきたものを記事にしています。

Monaco Editor使ってますか?VSCodeのエディタ部分を切り離して公開されているOSSのエディタです。(というか、元々はMonacoが先に公開されていたような記憶)

Aceとか、ウェブアプリケーションに組み込めるテキストエディタモジュールは色々とありますが、Monacoは頑張ればIntelliSenseを組み込んだりもできます。

Monacoの使い方自体は他の記事なりなんなりをご覧ください。

CMD/CTRL+Sにコマンドを登録する

さて、ウェブアプリにエディタを組み込んだときに問題となるのが、「ついついクセでCMD/CTRL+Sを押してしまう」という現象です。CyberDojoとかでもついついCMD+Sを押して、ウェブページの保存をしてしまいそうになることありませんか?僕はあります。

editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S, () => {
  editor.getAction('editor.action.formatDocument').run()
  console.log('saved')
})

editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.Key_S, コールバック関数)で、色々なアプリケーションでセーブに割り当てられているショートカットキーを押したときに実行するコマンドを登録できます。

この事例では、エディタのテキストを整形する editor.action.formatDocumentコマンドを実行しています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JSES6のクラスの基本をまとめてみる。part1

クラスについて

クラスとはオブジェクト(データ)を作成するための設計図

main.js
class Data{   //クラス名は大文字で表記

}

インスタンス

クラス内指定されたオブジェクトのこと,
newでインスタンスを指定する

main.js
class Date{

}
 const data = new Data();
console.log(data);

クラスに処理の仕方をなにも指定していないので、空のオブジェクトData{}が出力される

コンストラクター

インスタンスに処理を指定すためのもの、クラス内にconstructor(){}と記述する。

main.js
class Date{
    constructor(){
     console.log("イチロー") //➀
 }
};
 const data = new Data();  //➁ ➀が実行される

コンストラクターはインスタンスが読み込まれた瞬間に実行される。

まとめ

プロゲートで学んだクラスの基礎まとめてみました。
プロゲートから察してもらって構わないが、筆者である自分はまだプログラミング2か月の初心者で、自分の理解度向上のために記事を書いているので、参考には決してしないでほしい。

  

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JS ES6のクラスの基本をまとめてみる。part1

クラスについて

クラスとはオブジェクト(データ)を作成するための設計図

main.js
class Data{   //クラス名は大文字で表記

}

インスタンス

クラス内指定されたオブジェクトのこと,
newでインスタンスを指定する

main.js
class Date{

}
 const data = new Data();
console.log(data);

クラスに処理の仕方をなにも指定していないので、空のオブジェクトData{}が出力される

コンストラクター

インスタンスに処理を指定すためのもの、クラス内にconstructor(){}と記述する。

main.js
class Date{
    constructor(){
     console.log("イチロー") //➀
 }
};
const data = new Data();  //➁ ➀が実行されコンソール画面に"イチロー"と出力

コンストラクターはインスタンスが読み込まれた瞬間に実行される。

まとめ

プロゲートで学んだクラスの基礎まとめてみました。
プロゲートから察してもらって構わないが、筆者である自分はまだプログラミング2か月の初心者で、自分の理解度向上のために記事を書いているので、参考には決してしないでほしい。

  

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

NuxtとStorybookで.sassを使う

Parcelばっかり書いてて久しぶりのWebpackに戸惑った。

ちゃんとindentedSyntax指定しないと<style lang='sass'>指定でもエラーが出る。

webpack.config.js
// 略
config.module.rules.push({
  test: /\.sass$/,
  loaders: [
    'style-loader',
    'css-loader',
    {
      loader: 'sass-loader',
      options: {
        indentedSyntax: true
      }
    },
  ],
})
//略

参考にさせていただいたサイト

Nuxt.jsへのStorybookの導入と、Sassの変数や共通CSSを読めるようにする設定 - tacamy--blog

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript~コールバック関数の基礎

JavaScript~クラスの基本

コピペして使ってください。
ES6を対象としています。

コールバック関数

sample.js
//関数の定義
const greet = () => {
  console.log("Hello");
};

const call = (callback) => {
  console.log("コールバック関数の呼び出し");
  callback();
};

//関数の呼び出し
call(greet);
(出力結果)
コールバック関数の呼び出し
Hello

コールバック関数(引数つきの関数を渡す)

sample.js
//関数の定義(コールバック時に引数を渡す)
const call = (callback) => {
  callback("John", 14);
};

//関数の呼び出し(関数を引数にもつ)
call((name, age) => {
  console.log(`${name}${age}歳です。`);
});
(出力結果)
Johnは14歳です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

デザインスキル皆無のバックエンドエンジニアがポートフォリオ作ってみた

表題のとおりですが現在WEB制作現場に在籍していて主な業務内容はバックエンド実装というデザインスキルが乏しい私が試行錯誤しながらポートフォリオサイトを作成、公開するまでの道のりをここに記させて頂きます。

Links

LINK
GitHub

Program

  • HTML
  • CSS
  • JavaScript

Library&Framework

Tools

事前準備

コーディングフレームワークの選定

1からコーディングするのは作業日数的な問題等があったのでまずフレームワークの選定から入りました。
色々探してみた結果Bootstrapかmaterialize.cssで迷いました。
どちらもシンプルな実装が可能でポートフォリオサイトに最適なので、かなり悩んだのですがBootstrapは過去に実装経験があったので今回はmaterialize.cssを選択しました。

公開方法の選定

ポートフォリオサイトなので外部に公開しなければ自己満足で終わってしまうと思い

  • GitHubPages
  • Netlify
  • Heroku
  • レンタルサーバー
  • AWS

上記5つで考えた結果コード管理をGitHubで行う予定だったのでそのままGitHubPagesを採用しました。
(GitHubPagesでポートフォリオ公開しているエンジニア様が多かったってのもあります。)
公開方法に関しては下記の記事参考にさせて頂きました。
GitHub Pages を使った静的サイトの公開方法が、とても簡単になっていた

バージョン管理フローの選定

GitHubを普段から使用していたので大まかなフローは
ローカルで作業->リモートにpush
だったのですが
未経験がWeb系転職成功したいならgithubでissue管理して開発しよう
を読みましてどうせならbranch切ってissue管理しようと試みました。
正確には作業中盤からissue管理を行いましたが、Gitにおけるプルリクエストに関する理解が深まり大変良い経験が出来ました。
(諸々の事情でmasterに直接コミットしているログがあるのは内緒です。。。)

Qiita01.png

ワイヤーフレーム&仕様書の作成

正直に言います………
作成してません
理由としては

  • 大体のイメージがあった(シンプルかつ単ページのサイト)
  • ページ内の動きは調べて勉強がてら実装しようという甘い試み

ですが振り返るとある程度の実装内容を決めておかないと「あれもしたいこれもしたい状態」になりサイト完成が異常に延期されます。
また主にCSS JavaScriptの構造が乱れる原因になります。
上記の理由でこれからポートフォリオ作ってみようという方はある程度の実装内容を定めた上で作業される事をおすすめします。

作業フロー

materializecssテンプレートを理解

フレームワークを使用する際にまずは独自の文章構造の理解から入ったほうが良いかと思いテンプレート内の記述を閲覧して慣れる事から始めました。

テンプレート置き場

Qiita02.png

これによりmaterializecssに最初から搭載されているクラスの役割の理解やスムーズなレスポンシブコーディングが行えました。

大まかなレイアウトを決める

今回は大きく分けて

  • TOP画面
  • 自己紹介エリア
  • スキルグラフエリア
  • 制作物エリア
  • コンタクトエリア で考えました。 あまりページの長さを長くしすぎるのは避けたかったので「お問い合わせフォーム」等は入れませんでした。

コーディング

各々のエリア内に入れる要素を考えながらコーディングを行いました。
特に気合を入れたのがTOP画面のタイプライターアニメーションです。

Qiita03.gif

ローディングアニメーション

タイプライターアニメーション

ナビをフェードイン
は気に入ってる動きです。

不具合対応

実装しては検証して実装しては検証してと作業を行っていたのですがある程度作業が完了したあとにデバッグしてみると
レイアウトのズレやユーザビリティの低さが浮き出てきたのでGitHubでissue作成して1つずつマージしていきました。

公開作業

事前準備で選定していたGitHubPagesで公開して完了です。
公開方法の選定

振り返り

ポートフォリオ作成するに当たって「自分がどれくらいのスキルを有しているのか」や「今までの生き方」などの振り返りを行えました。
単純にポートフォリオという成果物、というだけではなく今後の課題や成長につながる経験が出来たと思います。
長々とご閲覧頂きありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript~配列の基本

JavaScript~配列の基本

コピペして使ってください。
ES6を対象としています。

配列に追加(pushメソッド)

sample.js
//配列の定義
const characters = ["a", "b", "c"];
// pushメソッドを使って配列の最後尾に追加
characters.push("d");

配列の繰り返し処理(forEachメソッド)

sample.js
//配列の定義
const characters = ["a", "b", "c"];
// forEachメソッドを使って、配列charactersの中身をすべて出力
characters.forEach((character)=>{
  console.log(character);
});

条件にあう1つ目の要素を取り出す(findメソッド)

sample.js
//配列の定義
const numbers = [1, 3, 5, 7, 9];

// findメソッドを使って3の倍数を見つける
const foundNumber = numbers.find((number)=>{
  return number%3===0;
});
console.log(foundNumber);

条件にあう全ての要素を取り出す(filterメソッド)

sample.js
//配列の定義
const characters = [
  {id: 1, age: 14},
  {id: 2, age: 5},
  {id: 3, age: 100}
];

// charactersから20歳未満を取り出す
const underTwenty = characters.filter((character)=>{
  return character.age<20;
});
console.log(underTwenty);

新しい配列をつくる(mapメソッド)

sample.js
//配列の定義
const names = [
  {firstName: "Kate", lastName: "Jones"},
    {firstName: "John", lastName: "Smith"},
    {firstName: "Denis", lastName: "Williams"},
    {firstName: "David", lastName: "Black"}
];

// 定数namesにmapメソッドを使って新しい配列を作る
const fullNames = names.map((name)=>{
  return name.firstName + name.lastName;
});
console.log(fullNames);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript~ファイルの分割

JavaScript~ファイルの分割

ファイルの分割

ファイル構成

root/
 ├ animal.js
 ├ dog.js
 └ script.js

ファイルの中身

animal.js
class Animal {
}
// Animalクラスをエクスポート
export default Animal;
dog.js
// Animalクラスをインポート
import Animal from "./animal";

class Dog extends Animal {
}
// Dogクラスをエクスポート
export default Dog;
script.js
// Dogクラスをインポート
import Dog from "./dog";

//スクリプト処理を記載

名前つきエクスポート

ファイル構成

root/
 ├ animal.js
 ├ dog.js
 ├ dogData.js
 └ script.js

ファイルの中身

animal.js
class Animal {
}
// Animalクラスをエクスポート
export default Animal;
dog.js
// Animalクラスをインポート
import Animal from "./animal";

class Dog extends Animal {
}
// Dogクラスをエクスポート
export default Dog;
dogData.js
//Dogクラスをインポート
import Dog from "./dog";

//定数dog1, dog2を設定
const dog1 = new Dog("A");
const dog2 = new Dog("B");

//定数dog1, dog2をエクスポート
export {dog1, dog2};
script.js
//定数dog1、dog2をインポート
import {dog1, dog2} from "./dogData";

//スクリプト処理を記載
dog1.something();
dog2.something();
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【初学】JavaScriptのクラスって?メソッドって?

最近JavaScriptを触り初めてまず驚いたのが、
CやC#とクラスやらコンストラクタやらがなんか違う!という部分でした。
実際何がどう違うのか、今日少し勉強したのでまとめてみます。
※間違ってる部分あるかもしれません。ビシバシ指摘いただけるとありがたいです。

まずクラスを作ってみる。

//C#
class test(){
}
//JavaScript
var Test = function(){};

私にとって馴染みのあるのは上の方なんですが、なんとJavaScriptでは
関数にクラスの役割を与えているらしいです。
だからこのTestクラスはちゃんとインスタンス化が可能です。

//JavaScript
var test = new Test();

メソッドはどうなってるの?

//C#
class test(){
   public void cat(){
      Console.Write("にゃーん");
   }
}
//JavaScript
var test(){
   this.getName = function(){
      return "ミャオ";
   }
}

メソッドっていうか、値が関数なだけでやん!プロパティですやん!って思いましたが、
JavaScriptではこれがメソッドを担っているらしいです。

コンストラクターでの定義以外に、あとからメソッドを追加することもできます。

//JavaScript
var Test = function(name){
this.name = name;
}
var test = new Test('irico');
test.intro = function(){
   return this.name + 'です。';
}

console.log(test.intro());  //「iricoです。」と表示される

なので、同じクラスから作られたインスタンスでも、持っているメンバーが違う、ということがありえます。

他にもメンバーを削除(delete)したり、削除や追加を行わないようにする (seal)ことも可能です。

var Test = function(name){
   this.name = name;
   type = "fish";
}
var test = new Test('irico');

console.log(test.intro());  //iricoです。
delete test.intro;         //削除
console.log(test.type);   //こっちは残ったまま
Object.seal(this);     //コンストラクターの末尾に追加すると保護される

コンストラクターを関数として呼べちゃう

関数をコンストラクターとして使っている以上。そのまま関数として使ってしまうことができます。

var Test = function(name){
   this.name = name;
};

var test = Test('irico');     //直接呼び出し
console.log(test);   //undefined
console.log(name);   //irico
console.log(test.name);  //エラー

use strictにしていると動かないので注意です。
これだとオブジェクトが生成されず、一行目は未定義になっていますね。
二行目はthisの為にグローバルオブジェクトから参照されています。

対策

関数として呼び出された場合は、thisがグローバルオブジェクトを示すので、それを逆手にとって、
thisがグローバルの時、コンストラクターを呼び出す、という解決方です。なるほど。

var Test = function(name){
   if(!(this instanceof Test)){
      return new Test(name);
   }
   this.name = name;
}

※「[改定新版]モダンスタイルによる基盤から現場での応用まで JavaScript本格入門」(著:山田祥寛)を参考に学習しました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript~クラスの基本(インスタンス、コンストラクタ、メソッド、継承)

JavaScript~クラスの基本

コピペして使ってください。
ES6を対象としています。

クラスの定義

sample.js
//クラスの定義
class Animal { 
}
//インスタンスの生成
const animal = new Animal();

コンストラクタの定義

sample.js
//クラス内にコンストラクタを定義
class Animal {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

//引数を渡して、インスタンスを生成
const animal = new Animal("ポチ", 8);

console.log(`名前: ${animal.name}`);
console.log(`年齢: ${animal.age}`);

メソッドの定義

sample.js
class Animal {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }  
  greet() {
    console.log("こんにちは");
  }
  info(){
    console.log(`名前:${this.name}`);
    console.log(`年齢:${this.age}`);
  }  
}

const animal = new Animal("ポチ", 8);
animal.greet();
animal.info();

クラスの継承

sample.js
class Animal {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }  
  greet() {
    console.log("こんにちは");
  }
  info(){
    this.greet();
    console.log(`名前:${this.name}`);
    console.log(`年齢:${this.age}`);
  }    }
}

// Animalクラスを継承してDogクラスを定義
class Dog extends Animal {
  //独自のメソッドを追加できる
    getHumanAge() {
    return this.age*7;
  }
}

//継承元のメソッドを使用できる
const dog = new Animal("ポチ", 3);
dog.info();
//独自のメソッドを使用できる
const humanAge = dog.getHumanAge();
console.log(`人間年齢:${humanAge}`);

オーバーライド

sample.js
class Animal {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  greet() {
    console.log("こんにちは");
  }
  info() {
    this.greet();
    console.log(`名前は${this.name}です`);
    console.log(`${this.age}歳です`);
  }
}

class Dog extends Animal {
  //constructorを追加
  constructor(name, age, breed) {
    super(name, age);
    this.breed = breed;
  } 
  info() {
    this.greet();
    console.log(`名前:${this.name}`);  
    console.log(`犬種:${this.breed}`);  
    console.log(`年齢:${this.age}`);
    const humanAge = this.getHumanAge();
    console.log(`人間年齢:${humanAge}`);
  } 
  getHumanAge() {
    return this.age * 7;
  }
}

const dog = new Dog("ポチ", 8, "チワワ");
dog.info();

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

超初心者が受けるJS社内勉強会:第3回

今回はconsoleでいろいろやってみよう!という会でした。
aaa.png

足したり引いたり、計算結果の確認が即座に出てきます。便利!

演算子について

四則演算

  • 足し算 +
  • 引き算 -
  • 掛け算 *(アスタリスク)
  • 割り算 /(スラッシュ) 0で割ることができない。0を使うことが内容にする。
  • 剰余  %(割り算のあまり)例:7%3; → 1 ・・・7を3で割ったら1余る、という結果。

計算の優先順位が決まっている

掛け算割り算が優先される
- 2+3*4 =14
- (2+3)+4 =9
- ((2+3)*4) =20
- (3+5)*20%(8-2) =4

文字列演算

  • 'abc' + 'def';
    • 文字列の結合
      例:'123' + '456' //123456 ※123+456=579ではない
  • parseInt('123') + parseInt('456') //579
    • parseInt とは、文字列を整数に変換するJavaScriptのグローバル関数の事。
  • '123'*1 + '456' *1 //579
    • 文字列の数字に1をかけると数値になる。JSが勝手に解釈するらしい。

多様な文字列の結合

  • 123 + '' + 456 //123456
  • '123' + 456 //123456
  • 123 + '456' //123456!

    • +で文字列を結合している

比較演算

if , for 必ず2つの値を比較。3つ以上は、分けてやる。

  • 123 > 456 false
  • 123 < 456 true
  • 123 > 123 false
  • a >= b;  aがbと同じ、またはaがbよりも大きい場合にtrue
  • a == b;  同じかどうか。等しければtrue、等しくなければfalse
  • '123' == '123' true
  • '123' == 123; true どちらかが数値ならば文字列も数値としてみられるため。
  • '123' === 123; false =を3つめにすると型の比較まで行う。
  • a !== b; aとbが等しくなければtrue!= は型まで比較しない

いよいよ実践めいた事に入ってきました。
そろそろ脳が拒否反応を表しだしております。 :head_bandage:

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptの関数定義と呼び出し

JavaScriptの基本

コピペして使ってください。
ES6を対象としています。

関数

sample.js
//関数定義
const hello = function(){
  console.log("こんにちは!");
}
//関数の呼び出し
hello();

//アロー関数
const greet = ()=>{
  console.log("こんばんは!");
}
greet();

引数、戻り値

sample.js
//引数の指定
const add = (number1, number2) => {
  console.log(number1+number2);  
};
add(5,7);

//戻り値の指定
const half = (number) => {
  return number/2;
};
const result = half (130);
console.log(`130の半分は${result}です`);

オブジェクトと関数

sample.js
//関数を含むオブジェクトの作成
const animal = {
  name: "ポチ",
  greet: ()=>{
    console.log("こんにちは");
  }
}

//プロパティの値、関数の呼び出し
console.log(animal.name);
animal.greet();
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptの配列とオブジェクト(基礎)

JavaScriptの基本

コピペして使ってください。
ES6を対象としています。

配列

sample.js
//配列の宣言
const animals = ["dog", "cat", "pig"];
//配列の要素を取得
console.log(animals[0]);

//配列の繰り返し
for (let i = 0; i < animals.length; i++) {
  console.log(animals[i]);
}

オブジェクト

sample.js
//オブジェクトの宣言
const character = {name: "John", age: 22};
//オブジェクトの要素を取得
console.log(character.name);

オブジェクトの要素をもつ配列

sample.js
//オブジェクトの要素をもつ配列の宣言
const characters = [
  {name: "John", age: 22},
  {name: "Kevin", age: 23}
];
//要素を取得
console.log(characters[0]);
console.log(characters[1].name);

//繰り返し処理
for (let i=0; i<characters.length; i++) {
  const character = characters[i];
  console.log(`名前:${character.name}`);
  console.log(`年齢:${character.age}`);    
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptの基礎~変数宣言、if、switch、while、forなど

JavaScriptの基本

コピペして使ってください。
ES6を対象としています。

変数・定数とテンプレートリテラル

sample.js
//コメント

//コンソール出力
console.log("Hello World");

//変数の宣言(再宣言、再代入可)
let name = "John";
//定数の宣言(再宣言、再代不可)
const name = "John";

//テンプレートリテラル(文字列と変数の連結)
const name = "John";
console.log(`こんにちは、${name}さん`);

if文

sample.js
//if文
const age = 12;
if (age >= 20) {
  console.log("私は20歳以上です");
}  else {
  console.log("私は20歳未満です");
}
//aとbが等しい
console.log(age===12);
//aとbが異なる
console.log(age!==12);

switch文

:sample.js
const rank = 5;

switch (rank) {
  case 1:
    console.log("金メダルです!");
    break;
  case 2:
    console.log("銀メダルです!");
    break;
  case 3:
    console.log("銅メダルです!");
    break;
  default:
    console.log("メダルはありません");
    break;    

}

while文

sample.js
let number = 1;

while (number<=100){
  console.log(number);
  number += 1;
}

for文

sample.js
for (let number = 1; number <= 100; number ++){
  console.log(number);
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vueの基礎文法はJSES6の関数を用いたオブジェクトと似ている

javascriptの関数を用いたオブジェクト
index.html
<div id=pro></div>
main.js
const pro={
  data:()=>{
    document.write("イチロー");
  }
};
pro.data();
vueの基礎構文
index.html
<div id="app">  //vueを指定したいときはappをつける
   <p>{{message}}/p> //{{message}}にイチローと実行する
</div>
main.js;
const app=new Vue({
    el:"#app",
    data:{
     message:"イチロー"
     }
});

こんな感じで結構似ているので、vueを勉強する前にprogateのI~IVはやっておきたいところ

-ちなみに著者はプログラミング2か月の雑魚で、自分の理解度向上のためにやっているのであんまり参考にしないでいたただけると幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LINE Bot「コンパスパンダ(ver0)」

はじめに

数ヶ月前から黙々と開発していたLINE Bot「コンパスパンダ」が完成したのでまとめます。ソースコードや概要はこちらで公開しています。
概要や使い方に関する説明はリンク先のドキュメントにて記述しています。この記事では技術的なお話のみに絞ります。後、LTとかに使いたいのでスライド形式です。


システム図

tweet.jpg


システムの流れ

  1. 基本的にユーザーは赤矢印のようにLINE Botとのインタラクションのみでこのアプリを操作
  2. 位置情報の取得にはURLスキーム機能を用いて位置情報取得
  3. 呟きのテキストは専用フォームをLIFFで表示してそこから取得
  4. 取得した情報をLINE Botのサーバーを介してデータベースに保存
  5. 地図表示もLIFF上にてディスプレイ

利用技術(LINE Bot)


利用技術(Form)


利用技術(データベース)


利用技術(Map)


苦労したこと


位置情報と呟きの結びつけ

  • Messaging APIにはステート管理の機能がない
  • 無理やりステート管理をするには
    1. データベースから一々データを引っ張る
    2. Push通知を使う(BotBuilderが良さげ?)
    3. 何かしらの管理番号をトーク画面上に発行
  • 今回は取っ付きやすい「3」の方法を選択

タイムスタンプを発行(一意となる管理番号がわりに)

tweet.jpg


FirestoreのDocumentを1つにまとめた

  • Firestoreには呼び出し数に制限あり
    • CollectionsではなくDocumentの数をカウント
  • ネストを1つ深く
    • 取り出す時が少し面倒
{
  timestamp: {
    tweet : text,
    latitude: latitude,
    longitude:  longitude
  }
}

最後に


課題

  • UIが使いにくすぎる
    • 一度に位置と呟きを取得したい
  • 会話の応答と呟きのDBへの保存の処理を同じLINE Botのサーバで処理している
    • LIFFに任せるなど役割分担を整理したい
    • DB用のサーバを立ててAPI化させたい
  • 地図にテキストしか残せない
    • 写真とかにも対応させたい

さらにやりたいこと

  • 呟き内容のテキストを感情分析してポインターのアイコンに反映させる
  • LINE Thingsと連携したサービス

とり会えず今ところ作れたのは最低限動くもの。ここから面白いサービスを作って行きたい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

shields.ioを使って技術系アイコンを量産した

概要

shields.ioを用いて技術系アイコンを量産しました。

とりあえず完成したのがこちらです。
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
skills.png

これでスキルマップを作ってみたらいい感じになりました。

shields.ioについて

https://shields.io/

GitHubのREADMEでよく見かけるアレです。
shields.ioはSVG形式のバッジサービスです。

カスタムバッジを作る

特徴的な機能の1つとして
URLのパターンでカスタムバッジを作ることができます。

https://img.shields.io/badge/${subject}-${status}-${color}.svg

subject : バッジの左側に入る文言
status : バッジの右側に入る文言
color : 色

Color

以下のようなものが用意されています。

color.png

16進数形式で指定することも可能です。

カスタムスタイル

いくつかのスタイルが用意されています。

?style=plastic&logo=appveyor

?style=flat&logo=appveyor

?style=flat-square&logo=appveyor

?style=for-the-badge&logo=appveyor

?style=popout&logo=appveyor

?style=popout-square&logo=appveyor

?style=social&logo=appveyor

simpleicons

バッジではいくつかのアイコンが使えます。
これについてはsimpleiconsを参考になります。

https://simpleicons.org/

そして一例がこれです。

 2019-07-08 1.41.11.png

全部で数えたら648ありました。

おすすめアイコンを作った

おすすめしたいアイコンを作りました。

言語系

 2019-07-08 23.38.15.png

ライブラリ・フレームワーク

 2019-07-08 23.38.46.png

OS

 2019-07-08 23.39.28.png

ミドルウェア

 2019-07-08 23.39.50.png

エディタ・IDE

 2019-07-08 23.40.09.png

クラウド・他

 2019-07-08 23.40.25.png

参考

shields.ioで技術系のアイコンをたくさん作ってみる

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerHubで公開されているコンテナが安全か確かめてみた【人気のコンテナ上位800個!】

はじめに

Docker Hubに公開されているイメージはどの程度安全なのか、 Dockle starsTrivy stars を利用して検証しました。
検証結果は、 https://containers.goodwith.tech/ に公開しています。

page.png

結論

基本的にどのコンテナにも脆弱性はある!
人気が高いコンテナ/最近ビルドされているコンテナでも関係ない!

ただ、Docker公式が用意しているコンテナは今のところ大丈夫。
より詳しいことを知りたい人は 操作方法 を見て、 https://containers.goodwith.tech/ を操作してみてください。

操作方法

① ソートやフィルタが簡単にできます

header-2.png

※ Scoreは脆弱性のCVSSスコアなどを元にした参考値です。指標を一つに統一したかったので作りました。
ガチ勢の方々、怒らないでください & よりよい指標をつくるためのアドバイスをください。

② Dockle, Trivy というカラムを選択すると、JSON形式で詳細な情報が表示されます

clickable-2.png

③ JSONのロードが遅いときは「JSON Detail」のリンクからダウンロードできます

jsondetail-2.png

※ netlifyを利用してるんですが、特に大きいJSONファイルの取得が遅いので、解決方法を知りたいです

何がチェックできるの?

CISベンチマークに沿っているかチェックできます。CIS(The Center for Internet Security)のセキュリティ専門家たちが発行している資料です。

slide17

簡単に言うと、Dockleの列ではイメージの設計が正しくされているか、Trivyの列では脆弱性のあるパッケージが使われていないかをチェックできます。

その他にも、パスワードが設定されていないユーザのチェックなど、Linuxの基礎的なセキュリティもチェックします。
original-checkpoint-comparison.png

ただし、すべてのコンテナで警告が出てしまうので、「latestタグはやめよう」「Content Trustを有効にしよう」の2項目は無視しています。

データの作り方

過去に記事にした Dockle starsTrivy stars を利用しています。
対象のコンテナイメージに対してそれぞれスキャンしていき、結果を集計しました。なお800個のコンテナを平行処理して1時間掛かりませんでした。

なお、私はDockleの作者で、Trivyのメインコミッタの一人です。GitHub Starが増えると喜びます。

フロントエンドやホスト環境は?

reactnetlify.png

メインで使っているライブラリは以下のものです。
Docker Meetup Tokyo #31のLTに間に合わせるべく、画面のベース作成1日というギリギリのスケジュールだったためCreate React Appを利用しました。

├── public : JSONや画像など
├── src : ソースコード
└── yarn.lock

フォルダ構成は現在このようになっており、すべてnetlifyでホストされています。
ただ、ファイルサイズが大きくなるとnetlifyだと極端に遅くなります。
特に脆弱性の数が多いJSONデータのロードで顕著です。解決策があれば教えてください。

脆弱性対策はどうすればいい?

ここや、この記事の後半でお伝えしたとおり、どのように向き合うかは、そのサービスの用途や求めるレベルによります。

ただ、Trivyで検出された脆弱性については、新しいOSにして新しいバージョンのパッケージを入れたら脆弱性は減るので、公開されているDockerfileを元に自らの手で書き直すことをおすすめします。

脆弱性についてより詳しいことが気になった人は、私も参加しているプロジェクト Vulsのチームが主催する 「既知の脆弱性はこう捌け!」系の勉強会に参加すると、体系的に学ぶ事ができます。

最後に

最初に、Docker公式が用意しているイメージが今のところ大丈夫と伝えました。
しかし、いつ脆弱性が入るのかはわからないので、ビルドごとにイメージのチェックすることをおすすめします。実例として、今年の5月まで公式が用意したAlpine LinuxのイメージにRootユーザのパスワードが設定されていないという脆弱性がありました。

ローカルビルドの際に、すでにあるイメージを毎回参照していて、過去の脆弱性をそのまま使い続けている状況もありえます。ローカルでイメージを作成している人/コンテナのイメージをキャッシュから作成されている方は、特に一度スキャンすることをおすすめします。

なお、今後も https://containers.goodwith.tech/ に、ユーザーの入力したイメージ名からスキャンをするなど、機能追加していく予定です。 フッターにシェアボタン付けたので、シェアお願いします?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerHubで公開されているコンテナが安全か確かめてみた結果【人気のコンテナ上位800個!】

はじめに

Docker Hubに公開されているイメージはどの程度安全なのか、 Dockle starsTrivy stars を利用して検証しました。
検証結果は、 https://containers.goodwith.tech/ に公開しています。

screencast24.gif

結論

基本的にどのコンテナにも脆弱性はある!
人気が高いコンテナ/最近ビルドされているコンテナでも関係ない!

ただ、Docker公式が用意しているコンテナは今のところ大丈夫。
より詳しいことを知りたい人は 操作方法 を見て、 https://containers.goodwith.tech/ を操作してみてください。

操作方法

page.png

① ソートやフィルタが簡単にできます

header-2.png

※ Scoreは脆弱性のCVSSスコアなどを元にした参考値です。指標を一つに統一したかったので作りました。
ガチ勢の方々、怒らないでください & よりよい指標をつくるためのアドバイスをください。

② Dockle, Trivy というカラムを選択すると、JSON形式で詳細な情報が表示されます

clickable-2.png

③ JSONのロードが遅いときは「JSON Detail」のリンクからダウンロードできます

jsondetail-2.png

※ netlifyを利用してるんですが、特に大きいJSONファイルの取得が遅いので、解決方法を知りたいです

何がチェックできるの?

CISベンチマークに沿っているかチェックできます。CIS(The Center for Internet Security)のセキュリティ専門家たちが発行している資料です。

slide17

簡単に言うと、Dockleの列ではイメージの設計が正しくされているか、Trivyの列では脆弱性のあるパッケージが使われていないかをチェックできます。

その他にも、パスワードが設定されていないユーザのチェックなど、Linuxの基礎的なセキュリティもチェックします。
original-checkpoint-comparison.png

ただし、すべてのコンテナで警告が出てしまうので、「latestタグはやめよう」「Content Trustを有効にしよう」の2項目は無視しています。

データの作り方

過去に記事にした Dockle starsTrivy stars を利用しています。
対象のコンテナイメージに対してそれぞれスキャンしていき、結果を集計しました。なお800個のコンテナを平行処理して1時間掛かりませんでした。

なお、私はDockleの作者で、Trivyのメインコミッタの一人です。GitHub Starが増えると喜びます。

フロントエンドやホスト環境は?

reactnetlify.png

メインで使っているライブラリは以下のものです。
Docker Meetup Tokyo #31のLTに間に合わせるべく、画面のベース作成1日というギリギリのスケジュールだったためCreate React Appを利用しました。

├── public : JSONや画像など
├── src : ソースコード
└── yarn.lock

フォルダ構成は現在このようになっており、すべてnetlifyでホストされています。
ただ、ファイルサイズが大きくなるとnetlifyだと極端に遅くなります。
特に脆弱性の数が多いJSONデータのロードで顕著です。解決策があれば教えてください。

脆弱性対策はどうすればいい?

ここや、この記事の後半でお伝えしたとおり、どのように向き合うかは、そのサービスの用途や求めるレベルによります。

ただ、Trivyで検出された脆弱性については、新しいOSにして新しいバージョンのパッケージを入れたら脆弱性は減るので、公開されているDockerfileを元に自らの手で書き直すことをおすすめします。

脆弱性についてより詳しいことが気になった人は、私も参加しているプロジェクト Vulsのチームが主催する 「既知の脆弱性はこう捌け!」系の勉強会に参加すると、体系的に学ぶ事ができます。

最後に

最初に、Docker公式が用意しているイメージが今のところ大丈夫と伝えました。
しかし、いつ脆弱性が入るのかはわからないので、ビルドごとにイメージのチェックすることをおすすめします。実例として、今年の5月まで公式が用意したAlpine LinuxのイメージにRootユーザのパスワードが設定されていないという脆弱性がありました。

ローカルビルドの際に、すでにあるイメージを毎回参照していて、過去の脆弱性をそのまま使い続けている状況もありえます。ローカルでイメージを作成している人/コンテナのイメージをキャッシュから作成されている方は、特に一度スキャンすることをおすすめします。

なお、今後も https://containers.goodwith.tech/ に、ユーザーの入力したイメージ名からスキャンをするなど、機能追加していく予定です。 フッターにシェアボタン付けたので、シェアお願いします?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vue.jsのディレクティブをまとめてみました。part1

v-if

qiita.html
<div id="app">
        <p v-if="error">エラーです</p>
    </div>
 <script src="https://cdn.jsdelivr.net/npm/vue"></script>
 <script>
let app=new Vue({
    el:"#app",
    data:{
        error:true//falseにすると画面に'エラーです'が表示されなくなる
    }
});
</script>

v-bind

{{}}マスタッシュ記号を、html属性の中に出力できないために使われる。

index.html
<div id="app">
        <p class="{{error_class}}">{{error_class}}</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
 <script>
   let app=new Vue({
  el:"#app",
  data:{
      error_class:"error"
  }
});

この状態だと出力されない2019-07-10.png

そこでv-bindをつかう

index.html
 <div id="app">
        <p v-bind:class="error_class">エラーです</p>
        <img v-bind:src="img_src">
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
 <script>
   let app=new Vue({
  el:"#app",
  data:{
      error_class:"abc",
      img_src:"img01.png"
  }
});
    </script>

うまく出力されました
2019-07-10 (1).png
参考url
Vue.js入門 #03:if構文とディレクティブ
Vue.js入門 #04:Vue.jsによる属性の書き換え

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsのcontrollerからjavascriptに対して変数を渡す

About

railsからjavascriptに対して変数を渡す方法の一つについて記載しています。
html.erbファイル内にscriptタグでjavascriptを書いた場合に変数を渡せる方法です。

Environment

この記事ではmacbook(unix)にインストールしたruby 2.5.1p57, Rails 5.2.3を使用しています。

変数の渡し方

controller内での変数の定義

まずは変数をcontroller内で定義します。
今回は配列を渡してみます。

sleeps_controller.rb
class UsersController < ApplicationController

  def show
    @user = User.find(params[:id])
    @sleeps = @user.sleeps.order('date DESC').includes(:user).limit(14).reverse
  end
end

html.erbで変数を受け取る

ここからは力技です。参考までにamchartsのスクリプトを拝借しています。
他に良い方法があると思いますので、最終手段くらいに思っていただければと思います。
また、良い方法がある方、コメントいただけると幸いです。

show.html.erb
<!-- Chart code -->
<script>
    //略
    // Add data
    var sleepings = '<%= @sleeps %>'
    // 以下略
</script>

この様にすることで、javascriptの変数として、文字列を渡すことができます。
ただし、ここで注意しなくてはいけないのが、あくまで javascript側には文字列が渡されるだけ、ということです。

そのため、以下の様に文字列を分解して、配列に変換しています。
文字列の[]をそれぞれ置換の要領で削除し、カンマでsplitし、配列化します。

show.html.erb
<!-- Chart code -->
<script>
    //略
    // Add data
    var sleepings = '<%= @sleeps %>'.replace(/\[/g, "").replace(/\]/g, "").split(',');
    // 以下略
</script>

これでjavascriptにrailsのcontrollerから値を渡す事ができます。
...ゴリ押し感が否めないですが。

最後に

ここまでゴリ押し感が強いものを共有するべきか悩みましたが、同じ様な悩みを抱えている方が少しでもいらっしゃれば、その方の助けになるかもと思い書きました。
さらに良い方法がありましたら、是非教えてください!

筆者について

TECH::EXPERTにて4月よりruby, railsを学習している未経験エンジニアです。
記載内容に不備・不足があればご指摘いただけると幸いです。
至らぬ点ばかりですので、改善点がありましたらどんどんご指摘下さい!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vue.jsの基本をアウトプットしてみた。

qiita.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vue.js tomosta</title>
</head>
<body>

  <div id="app1">
        {{message}}
    </div>
    <div id="app2">
        {{message}}
    </div>
   <!--app1かapp2にマサディアンと出力したい-->
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script src="main.js"></script>
</body>
</html>

app1とapp2の{{message}}どっちにマサディアンが出力されたのか

qiita.js
 let app=new Vue({
    el:"#app2",//対象を<div id="app2"></div>とする。
    data:{//ここdataでに処理のしかたをきめる。
        message:"マサディアン"
    }
});

よって{{message}}にともすたが代入された出力結果はapp2

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む