- 投稿日:2019-07-10T23:08:40+09:00
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を使っているので、簡単にアイコンで装飾できます。
環境設定
まずは開発環境を構築します。
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/reducersconst 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.jsexport const addUser = user => ({ type: 'ADD_USER', user: user })index.jsです。ユーザ登録のみの簡単な機能しかありませんが、redux-logger と redux-formを組み合わせているので、少し複雑かもしれません。
src/index.jsimport 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の大枠はantdのFormを利用しています。
- Formの子要素にはredux-formのField を利用しています。
- 更にFieldのcomponent属性にantdのInput(で作られたcomponent)を利用しています。
antdとredux-formを組み合わせについては、以下の記事も参照ください。
React UI library の antd について (3) - redux-formredux-formによるvalidateはシンプルなのでいいですね。
src/Register.jsimport 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 componentsrc/input.jsimport 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;実行結果
今回は以上です。
- 投稿日:2019-07-10T21:56:30+09:00
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
登録されているユーザープロフィールの取得(身長・体重・年齢なども)
- 投稿日:2019-07-10T21:08:29+09:00
【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 --versionFirebase 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.jsexports.ServerTime = functions.https.onRequest((request, response) => { var dt = new Date(); var delta = dt.getTime(); response.send({ data: String(delta) }); });バックエンドコードのデプロイ
ターミナルで次のコマンドを入力し、ログインします。
$ firebase loginログインしている状態で次のコマンドを入力し、デプロイを実行します。
$ firebase deployDeploy complete!と表示されたらデプロイ完了です。
ターミナルに出力されたProject ConsoleのURLを開き、Functionsからデプロイした関数を確認できます。XCodeプロジェクト側の実装
SDKのインストール
CocoaPodsからFirebaseFunctionsをインストールします。
podfileに次の行を追記します。pod 'Firebase/Functions'追記後ターミナルで次のコマンドを入力し、インストールを実行します。
$ pod installサーバ日時取得処理の実装
この記事ではサンプルとして、アプリ起動時にサーバ日時を取得しログ出力するよう実装します。
ViewController.swiftに次のコードを記述します。ViewController.swiftimport 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を掛けて秒に変換する必要があります。
- 投稿日:2019-07-10T19:40:58+09:00
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(値)
…シンボルの場合はSymbolDescriptiveString
(Symbol.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
すると例外が飛ぶような式を文字列に埋め込んで、なおかつその例外が飛ぶパスを、他の式展開で副作用の起きるかどうかまで想定したコードを書く、という場面も考えづらいので、実用的に差異が出る危険性は薄そうです(そもそも、式展開の中に副作用の伴う式を書くこと自体、そう多くないと思いますし)。
雛形になる文字列と、式展開された値をまとめて関数に投げられるような、タグ付きTemplate Literalもありますが、とりあえず本稿では触れません。 ↩
- 投稿日:2019-07-10T17:27:03+09:00
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
でそういうことをする機会はあまり無いでしょう。
- 投稿日:2019-07-10T17:17:33+09:00
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
コマンドを実行しています。
- 投稿日:2019-07-10T16:25:38+09:00
JSES6のクラスの基本をまとめてみる。part1
クラスについて
クラスとはオブジェクト(データ)を作成するための設計図
main.jsclass Data{ //クラス名は大文字で表記 }インスタンス
クラス内指定されたオブジェクトのこと,
newでインスタンスを指定するmain.jsclass Date{ } const data = new Data(); console.log(data);クラスに処理の仕方をなにも指定していないので、空のオブジェクトData{}が出力される
コンストラクター
インスタンスに処理を指定すためのもの、クラス内にconstructor(){}と記述する。
main.jsclass Date{ constructor(){ console.log("イチロー") //➀ } }; const data = new Data(); //➁ ➀が実行されるコンストラクターはインスタンスが読み込まれた瞬間に実行される。
まとめ
プロゲートで学んだクラスの基礎まとめてみました。
プロゲートから察してもらって構わないが、筆者である自分はまだプログラミング2か月の初心者で、自分の理解度向上のために記事を書いているので、参考には決してしないでほしい。
- 投稿日:2019-07-10T16:25:38+09:00
JS ES6のクラスの基本をまとめてみる。part1
クラスについて
クラスとはオブジェクト(データ)を作成するための設計図
main.jsclass Data{ //クラス名は大文字で表記 }インスタンス
クラス内指定されたオブジェクトのこと,
newでインスタンスを指定するmain.jsclass Date{ } const data = new Data(); console.log(data);クラスに処理の仕方をなにも指定していないので、空のオブジェクトData{}が出力される
コンストラクター
インスタンスに処理を指定すためのもの、クラス内にconstructor(){}と記述する。
main.jsclass Date{ constructor(){ console.log("イチロー") //➀ } }; const data = new Data(); //➁ ➀が実行されコンソール画面に"イチロー"と出力コンストラクターはインスタンスが読み込まれた瞬間に実行される。
まとめ
プロゲートで学んだクラスの基礎まとめてみました。
プロゲートから察してもらって構わないが、筆者である自分はまだプログラミング2か月の初心者で、自分の理解度向上のために記事を書いているので、参考には決してしないでほしい。
- 投稿日:2019-07-10T16:21:59+09:00
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
- 投稿日:2019-07-10T16:16:07+09:00
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歳です。
- 投稿日:2019-07-10T16:14:22+09:00
デザインスキル皆無のバックエンドエンジニアがポートフォリオ作ってみた
表題のとおりですが現在WEB制作現場に在籍していて主な業務内容はバックエンド実装というデザインスキルが乏しい私が試行錯誤しながらポートフォリオサイトを作成、公開するまでの道のりをここに記させて頂きます。
Links
Program
- HTML
- CSS
- JavaScript
Library&Framework
- itypedjs
- jQuery
- chartjs
- fakeloader
- jquery.matchheight
- SVG-Car-Drift-Loader
- materialize.css
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に直接コミットしているログがあるのは内緒です。。。)ワイヤーフレーム&仕様書の作成
正直に言います………
作成してません
理由としては
- 大体のイメージがあった(シンプルかつ単ページのサイト)
- ページ内の動きは調べて勉強がてら実装しようという甘い試み
ですが振り返るとある程度の実装内容を決めておかないと「あれもしたいこれもしたい状態」になりサイト完成が異常に延期されます。
また主にCSS JavaScriptの構造が乱れる原因になります。
上記の理由でこれからポートフォリオ作ってみようという方はある程度の実装内容を定めた上で作業される事をおすすめします。作業フロー
materializecssテンプレートを理解
フレームワークを使用する際にまずは独自の文章構造の理解から入ったほうが良いかと思いテンプレート内の記述を閲覧して慣れる事から始めました。
これによりmaterializecssに最初から搭載されているクラスの役割の理解やスムーズなレスポンシブコーディングが行えました。
大まかなレイアウトを決める
今回は大きく分けて
- TOP画面
- 自己紹介エリア
- スキルグラフエリア
- 制作物エリア
- コンタクトエリア で考えました。 あまりページの長さを長くしすぎるのは避けたかったので「お問い合わせフォーム」等は入れませんでした。
コーディング
各々のエリア内に入れる要素を考えながらコーディングを行いました。
特に気合を入れたのがTOP画面のタイプライターアニメーションです。ローディングアニメーション
↓
タイプライターアニメーション
↓
ナビをフェードイン
は気に入ってる動きです。不具合対応
実装しては検証して実装しては検証してと作業を行っていたのですがある程度作業が完了したあとにデバッグしてみると
レイアウトのズレやユーザビリティの低さが浮き出てきたのでGitHubでissue作成して1つずつマージしていきました。公開作業
事前準備で選定していたGitHubPagesで公開して完了です。
公開方法の選定振り返り
ポートフォリオ作成するに当たって「自分がどれくらいのスキルを有しているのか」や「今までの生き方」などの振り返りを行えました。
単純にポートフォリオという成果物、というだけではなく今後の課題や成長につながる経験が出来たと思います。
長々とご閲覧頂きありがとうございました。
- 投稿日:2019-07-10T16:04:14+09:00
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);
- 投稿日:2019-07-10T15:45:49+09:00
JavaScript~ファイルの分割
JavaScript~ファイルの分割
ファイルの分割
ファイル構成
root/ ├ animal.js ├ dog.js └ script.jsファイルの中身
animal.jsclass 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.jsclass 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();
- 投稿日:2019-07-10T15:37:44+09:00
【初学】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本格入門」(著:山田祥寛)を参考に学習しました。
- 投稿日:2019-07-10T15:28:20+09:00
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.jsclass 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.jsclass 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.jsclass 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();
- 投稿日:2019-07-10T15:14:01+09:00
超初心者が受けるJS社内勉強会:第3回
今回はconsoleでいろいろやってみよう!という会でした。
足したり引いたり、計算結果の確認が即座に出てきます。便利!
演算子について
四則演算
- 足し算
+
- 引き算
-
- 掛け算
*
(アスタリスク)- 割り算
/
(スラッシュ) 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
false123 < 456
true123 > 123
falsea >= b;
aがbと同じ、またはaがbよりも大きい場合にtruea == b;
同じかどうか。等しければtrue、等しくなければfalse'123' == '123'
true'123' == 123;
true どちらかが数値ならば文字列も数値としてみられるため。'123' === 123;
false=
を3つめにすると型の比較まで行う。a !== b;
aとbが等しくなければtrue。!=
は型まで比較しないいよいよ実践めいた事に入ってきました。
そろそろ脳が拒否反応を表しだしております。
- 投稿日:2019-07-10T14:59:29+09:00
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();
- 投稿日:2019-07-10T14:43:15+09:00
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}`); }
- 投稿日:2019-07-10T14:32:58+09:00
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.jslet number = 1; while (number<=100){ console.log(number); number += 1; }for文
sample.jsfor (let number = 1; number <= 100; number ++){ console.log(number); }
- 投稿日:2019-07-10T13:38:43+09:00
vueの基礎文法はJSES6の関数を用いたオブジェクトと似ている
javascriptの関数を用いたオブジェクト
index.html<div id=pro></div>main.jsconst 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か月の雑魚で、自分の理解度向上のためにやっているのであんまり参考にしないでいたただけると幸いです。
- 投稿日:2019-07-10T13:25:02+09:00
LINE Bot「コンパスパンダ(ver0)」
はじめに
数ヶ月前から黙々と開発していたLINE Bot「コンパスパンダ」が完成したのでまとめます。ソースコードや概要はこちらで公開しています。
概要や使い方に関する説明はリンク先のドキュメントにて記述しています。この記事では技術的なお話のみに絞ります。後、LTとかに使いたいのでスライド形式です。
システム図
システムの流れ
- 基本的にユーザーは赤矢印のようにLINE Botとのインタラクションのみでこのアプリを操作
- 位置情報の取得にはURLスキーム機能を用いて位置情報取得
- 呟きのテキストは専用フォームをLIFFで表示してそこから取得
- 取得した情報をLINE Botのサーバーを介してデータベースに保存
- 地図表示もLIFF上にてディスプレイ
利用技術(LINE Bot)
利用技術(Form)
利用技術(データベース)
利用技術(Map)
苦労したこと
位置情報と呟きの結びつけ
- Messaging APIにはステート管理の機能がない
- 無理やりステート管理をするには
- データベースから一々データを引っ張る
- Push通知を使う(BotBuilderが良さげ?)
- 何かしらの管理番号をトーク画面上に発行
- 今回は取っ付きやすい「3」の方法を選択
タイムスタンプを発行(一意となる管理番号がわりに)
FirestoreのDocumentを1つにまとめた
- Firestoreには呼び出し数に制限あり
- CollectionsではなくDocumentの数をカウント
- ネストを1つ深く
- 取り出す時が少し面倒
{ timestamp: { tweet : text, latitude: latitude, longitude: longitude } }
最後に
課題
- UIが使いにくすぎる
- 一度に位置と呟きを取得したい
- 会話の応答と呟きのDBへの保存の処理を同じLINE Botのサーバで処理している
- LIFFに任せるなど役割分担を整理したい
- DB用のサーバを立ててAPI化させたい
- 地図にテキストしか残せない
- 写真とかにも対応させたい
さらにやりたいこと
- 呟き内容のテキストを感情分析してポインターのアイコンに反映させる
- LINE Thingsと連携したサービス
とり会えず今ところ作れたのは最低限動くもの。ここから面白いサービスを作って行きたい。
- 投稿日:2019-07-10T08:21:59+09:00
shields.ioを使って技術系アイコンを量産した
概要
shields.ioを用いて技術系アイコンを量産しました。
とりあえず完成したのがこちらです。
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
これでスキルマップを作ってみたらいい感じになりました。
shields.ioについて
GitHubのREADMEでよく見かけるアレです。
shields.ioはSVG形式のバッジサービスです。カスタムバッジを作る
特徴的な機能の1つとして
URLのパターンでカスタムバッジを作ることができます。https://img.shields.io/badge/${subject}-${status}-${color}.svgsubject : バッジの左側に入る文言
status : バッジの右側に入る文言
color : 色Color
以下のようなものが用意されています。
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を参考になります。そして一例がこれです。
全部で数えたら648ありました。
おすすめアイコンを作った
おすすめしたいアイコンを作りました。
言語系
ライブラリ・フレームワーク
OS
ミドルウェア
エディタ・IDE
クラウド・他
参考
- 投稿日:2019-07-10T07:54:14+09:00
DockerHubで公開されているコンテナが安全か確かめてみた【人気のコンテナ上位800個!】
はじめに
Docker Hubに公開されているイメージはどの程度安全なのか、 Dockle
と Trivy
を利用して検証しました。
検証結果は、 https://containers.goodwith.tech/ に公開しています。結論
基本的にどのコンテナにも脆弱性はある!
人気が高いコンテナ/最近ビルドされているコンテナでも関係ない!ただ、Docker公式が用意しているコンテナは今のところ大丈夫。
より詳しいことを知りたい人は 操作方法 を見て、 https://containers.goodwith.tech/ を操作してみてください。操作方法
① ソートやフィルタが簡単にできます
※ Scoreは脆弱性のCVSSスコアなどを元にした参考値です。指標を一つに統一したかったので作りました。
ガチ勢の方々、怒らないでください & よりよい指標をつくるためのアドバイスをください。② Dockle, Trivy というカラムを選択すると、JSON形式で詳細な情報が表示されます
③ JSONのロードが遅いときは「JSON Detail」のリンクからダウンロードできます
※ netlifyを利用してるんですが、特に大きいJSONファイルの取得が遅いので、解決方法を知りたいです
何がチェックできるの?
CISベンチマークに沿っているかチェックできます。CIS(The Center for Internet Security)のセキュリティ専門家たちが発行している資料です。
簡単に言うと、Dockleの列ではイメージの設計が正しくされているか、Trivyの列では脆弱性のあるパッケージが使われていないかをチェックできます。
その他にも、パスワードが設定されていないユーザのチェックなど、Linuxの基礎的なセキュリティもチェックします。
ただし、すべてのコンテナで警告が出てしまうので、「latestタグはやめよう」「Content Trustを有効にしよう」の2項目は無視しています。
データの作り方
過去に記事にした Dockle
と Trivy
を利用しています。
対象のコンテナイメージに対してそれぞれスキャンしていき、結果を集計しました。なお800個のコンテナを平行処理して1時間掛かりませんでした。
- Dockle関連記事
- Trivy関連記事
なお、私はDockleの作者で、Trivyのメインコミッタの一人です。GitHub Starが増えると喜びます。
フロントエンドやホスト環境は?
メインで使っているライブラリは以下のものです。
Docker Meetup Tokyo #31のLTに間に合わせるべく、画面のベース作成1日というギリギリのスケジュールだったためCreate React Appを利用しました。
- Create React App
- ag-Grid : テーブル
├── public : JSONや画像など ├── src : ソースコード └── yarn.lockフォルダ構成は現在このようになっており、すべてnetlifyでホストされています。
ただ、ファイルサイズが大きくなるとnetlifyだと極端に遅くなります。
特に脆弱性の数が多いJSONデータのロードで顕著です。解決策があれば教えてください。脆弱性対策はどうすればいい?
ここや、この記事の後半でお伝えしたとおり、どのように向き合うかは、そのサービスの用途や求めるレベルによります。
ただ、Trivyで検出された脆弱性については、新しいOSにして新しいバージョンのパッケージを入れたら脆弱性は減るので、公開されているDockerfileを元に自らの手で書き直すことをおすすめします。
脆弱性についてより詳しいことが気になった人は、私も参加しているプロジェクト Vulsのチームが主催する 「既知の脆弱性はこう捌け!」系の勉強会に参加すると、体系的に学ぶ事ができます。
最後に
最初に、Docker公式が用意しているイメージが今のところ大丈夫と伝えました。
しかし、いつ脆弱性が入るのかはわからないので、ビルドごとにイメージのチェックすることをおすすめします。実例として、今年の5月まで公式が用意したAlpine LinuxのイメージにRootユーザのパスワードが設定されていないという脆弱性がありました。ローカルビルドの際に、すでにあるイメージを毎回参照していて、過去の脆弱性をそのまま使い続けている状況もありえます。ローカルでイメージを作成している人/コンテナのイメージをキャッシュから作成されている方は、特に一度スキャンすることをおすすめします。
なお、今後も https://containers.goodwith.tech/ に、ユーザーの入力したイメージ名からスキャンをするなど、機能追加していく予定です。 フッターにシェアボタン付けたので、シェアお願いします?
- 投稿日:2019-07-10T07:54:14+09:00
DockerHubで公開されているコンテナが安全か確かめてみた結果【人気のコンテナ上位800個!】
はじめに
Docker Hubに公開されているイメージはどの程度安全なのか、 Dockle
と Trivy
を利用して検証しました。
検証結果は、 https://containers.goodwith.tech/ に公開しています。結論
基本的にどのコンテナにも脆弱性はある!
人気が高いコンテナ/最近ビルドされているコンテナでも関係ない!ただ、Docker公式が用意しているコンテナは今のところ大丈夫。
より詳しいことを知りたい人は 操作方法 を見て、 https://containers.goodwith.tech/ を操作してみてください。操作方法
① ソートやフィルタが簡単にできます
※ Scoreは脆弱性のCVSSスコアなどを元にした参考値です。指標を一つに統一したかったので作りました。
ガチ勢の方々、怒らないでください & よりよい指標をつくるためのアドバイスをください。② Dockle, Trivy というカラムを選択すると、JSON形式で詳細な情報が表示されます
③ JSONのロードが遅いときは「JSON Detail」のリンクからダウンロードできます
※ netlifyを利用してるんですが、特に大きいJSONファイルの取得が遅いので、解決方法を知りたいです
何がチェックできるの?
CISベンチマークに沿っているかチェックできます。CIS(The Center for Internet Security)のセキュリティ専門家たちが発行している資料です。
簡単に言うと、Dockleの列ではイメージの設計が正しくされているか、Trivyの列では脆弱性のあるパッケージが使われていないかをチェックできます。
その他にも、パスワードが設定されていないユーザのチェックなど、Linuxの基礎的なセキュリティもチェックします。
ただし、すべてのコンテナで警告が出てしまうので、「latestタグはやめよう」「Content Trustを有効にしよう」の2項目は無視しています。
データの作り方
過去に記事にした Dockle
と Trivy
を利用しています。
対象のコンテナイメージに対してそれぞれスキャンしていき、結果を集計しました。なお800個のコンテナを平行処理して1時間掛かりませんでした。
- Dockle関連記事
- Trivy関連記事
なお、私はDockleの作者で、Trivyのメインコミッタの一人です。GitHub Starが増えると喜びます。
フロントエンドやホスト環境は?
メインで使っているライブラリは以下のものです。
Docker Meetup Tokyo #31のLTに間に合わせるべく、画面のベース作成1日というギリギリのスケジュールだったためCreate React Appを利用しました。
- Create React App
- ag-Grid : テーブル
├── public : JSONや画像など ├── src : ソースコード └── yarn.lockフォルダ構成は現在このようになっており、すべてnetlifyでホストされています。
ただ、ファイルサイズが大きくなるとnetlifyだと極端に遅くなります。
特に脆弱性の数が多いJSONデータのロードで顕著です。解決策があれば教えてください。脆弱性対策はどうすればいい?
ここや、この記事の後半でお伝えしたとおり、どのように向き合うかは、そのサービスの用途や求めるレベルによります。
ただ、Trivyで検出された脆弱性については、新しいOSにして新しいバージョンのパッケージを入れたら脆弱性は減るので、公開されているDockerfileを元に自らの手で書き直すことをおすすめします。
脆弱性についてより詳しいことが気になった人は、私も参加しているプロジェクト Vulsのチームが主催する 「既知の脆弱性はこう捌け!」系の勉強会に参加すると、体系的に学ぶ事ができます。
最後に
最初に、Docker公式が用意しているイメージが今のところ大丈夫と伝えました。
しかし、いつ脆弱性が入るのかはわからないので、ビルドごとにイメージのチェックすることをおすすめします。実例として、今年の5月まで公式が用意したAlpine LinuxのイメージにRootユーザのパスワードが設定されていないという脆弱性がありました。ローカルビルドの際に、すでにあるイメージを毎回参照していて、過去の脆弱性をそのまま使い続けている状況もありえます。ローカルでイメージを作成している人/コンテナのイメージをキャッシュから作成されている方は、特に一度スキャンすることをおすすめします。
なお、今後も https://containers.goodwith.tech/ に、ユーザーの入力したイメージ名からスキャンをするなど、機能追加していく予定です。 フッターにシェアボタン付けたので、シェアお願いします?
- 投稿日:2019-07-10T01:51:10+09:00
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" } });そこで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>うまく出力されました
参考url
Vue.js入門 #03:if構文とディレクティブ
Vue.js入門 #04:Vue.jsによる属性の書き換え
- 投稿日:2019-07-10T01:03:08+09:00
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.rbclass UsersController < ApplicationController def show @user = User.find(params[:id]) @sleeps = @user.sleeps.order('date DESC').includes(:user).limit(14).reverse end endhtml.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を学習している未経験エンジニアです。
記載内容に不備・不足があればご指摘いただけると幸いです。
至らぬ点ばかりですので、改善点がありましたらどんどんご指摘下さい!
- 投稿日:2019-07-10T00:58:02+09:00
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.jslet app=new Vue({ el:"#app2",//対象を<div id="app2"></div>とする。 data:{//ここdataでに処理のしかたをきめる。 message:"マサディアン" } });よって{{message}}にともすたが代入された出力結果はapp2