React、Vue.jsを学ぶ前に「初めてのJavaScript」
「JavaScript」と聞くとどういうイメージを思い浮かべるでしょうか?
ぼくがプログラミングを始めたのは10数年前。
当時は「HTML + CSS + JavaScriptでWebサイトを作る!」みたいな入門書が並んでいたのを覚えています。要は初心者プログラマー向けってイメージでした。
それから6年ほどブランクを経て、Web業界に転身するんですが状況がガラリと変わってました。
2010年頃にNode.jsが登場し、サーバーサイドでもJavaScriptが利用できる。
フロントエンドとバックエンドで同じ言語を使える。そして、Backbone.js、Angular、React、Vue.jsなどJSフレームワークが続々と登場し衝撃と困惑を同時に味わいました。
業務はバックエンド開発が中心でしたので、JavaScriptを触る機会があってもググった知識でごまかしていました。
最近、アプリを作ろうとAngularを学ぶも文法がわからず挫折。
「昔のイメージのままじゃダメだな」って意識をアップデートし本書を手に取りました。
本書の対象者は?
下記に1つでも当てはまったら読む価値があります。
- これからWebサービスやアプリを開発したい
- React、Vue.js、AngularなどのJSフレームワーク触ったけど理解できなかった
- 書いた順番通りに動いてくれない
- 次の文を理解できない(1から書けない)
const o = { name: 'Julie', greetBackwards: function() { const getReverseName = () => { console.log(this); let nameBackwards = ''; for (let i = this.name.length - 1; i >= 0; i--) { nameBackwards += this.name[i]; } return nameBackwards; }; return `${getReverseName()} si eman ym ,olleH`; } }; console.log(o.greetBackwards());
JavaやPHP、Pythonを主に使用してますが、JavaScriptで苦しんだのが関数の文法と非同期処理。
上記の関数はES2015で導入されたアロー関数という表記法を利用しています。わかってしまえばなんてことないんですけどね。
また、思うように動かない理由は非同期処理を理解していないのが原因です。
プログラムは1行目から順番に処理されるというある種思い込みがありましたが、処理が完了するのを待たずに次の処理に移るので、それらを制御するための知識が必要となります。
ググった情報はあくまでも断片的な知識なので、一度包括的に学習するのをオススメします。
本書の評価は?
基礎的な知識は十分に網羅されており、本書を学習したことでVue.jsやAngularの学習スピードが向上しました。
また、サンプルが数多く載っておりほとんどがNode.jsで動作確認できるので、とりあえず写経してパッと動かしてみることができるので理解も早いです。
PDF形式であればコピペもしやすく、持ち運びもしやすいのでオススメです。
PDFでの購入はこちら。
※Kindleは参考書に向いてないと思ってるので、PDFで購入するようにしています。
学習後の理解度ですが、ぼくは本書を学習した総仕上げとして、Node.jsでSlackのリアクションを集計するツールを作成しました。
これくらい作れるって目安になるかと思います。
まとめ
フロントエンドを学ぶことは必須ではないですが、技術について発信したいならJavaScriptの基礎から学んでおいて損はないでしょう。
「ぼくはこんなサービス作りました!」ってわかりやすくアピールしやすいですからね。ではまた。
try〜catchしすぎて人生が前に進まない人
先日、TwitterのTLでこんなツイートを見かけました。
最近「会社員やりながらいつデザインしてるんですか!?」って耳タコで言われんねんけど…そんなん平日の仕事終わりと土日に決まってるやん!
— 上司ニシグチ (@a_design_link) August 5, 2018
その時間を捻出するためには…
①テレビを見ない
②残業せずに帰る
③会社の飲み会に行かない
この3つを徹底するだけで、多くの時間を生み出す事ができる!
ホントその通りだなって思います。
現状に満足できずどうすれば良いか聞かれますが、アドバイスされて実践し続ける人は少ないです。
たぶんこういう思考なんでしょう。
<?php try { 自己学習に励む(); } catch(Exception $仕事疲れた) { 飯食って寝る(); } catch(Exception $気分がのらない) { テレビ見る(); 飯食って寝る(); } catch(Exception $飲み会誘われた) { 気分転換が必要と解釈(); 朝まで飲む(); }
起業するような方はこんな感じですかね。
<?php try { $自己学習スレッド = new 自己学習に励むThread(); $自己学習スレッド->start(); $起業スレッド = 起業するThread(); $起業スレッド->start(); $セミナースレッド = セミナー開催(); $セミナースレッド->start(); $オンラインサロンスレッド = オンラインサロン開設Thread(); $オンラインサロンスレッド->start(); } // catch(Exception $仕事疲れた) { // 飯食って寝る(); // } // catch(Exception $気分がのらない) { // テレビ見る(); // 飯食って寝る(); // } // catch(Exception $飲み会誘われた) { // 気分転換が必要と解釈(); // 朝まで飲む(); // } finally { 社会に還元する(); }
かなり大雑把ですね笑
すごいと感じる人は物凄い努力して突き進んでるように思います。
良い意味で「猪突猛進」。
そして次から次へとチャレンジし、周りを巻き込み引き上げてもくれる。
まとめ
誘惑に抗わない人生は一見楽に見えますが、長い期間やりたくない仕事をすることになりかねないです。
そんな人生は苦痛でしょう。
人生40代で折り返しと言いますが、20代、30代と早いうちから知識や経験を積み重ねておくと豊かな人生になるのでは?
ではまた。
node.jsでSlackのリアクションを集計するツールを作ってみた
普段はWebのバックエンド開発をメインでやってます。
最近プライベートでWebサービスやDAppsの開発を始め、JavaScriptを扱う機会が多くググった知識だけでは戦えなくなって勉強し直しました。
一通り学習し終えたのでnode.jsでSlackのリアクションを集計するツールを作ってみました。
ざっくりとした仕様
以下のような仕様で開発しました。
- プログラムは定期的(1回/日)に実行
- 前日にリアクションされた絵文字を集計 ※publicチャンネルのみ
- 集計結果を降順でソート
- 結果を特定のチャンネルに送信
そもそもリアクションって何?って方はこちらへ。
必要なAPIを選定する
フローを簡単にまとめると
- 対象チャンネルを取得
- 各チャンネル内の会話(リアクション)を取得
- リアクションを集計→送信
となります。
1と2はAPIで取得する情報になります。
良さげなやつがありました。
channels.history method | Slack
channels.listで対象チャンネルを取得、取得したchannelコードをchannels.historyに引き渡しリアクションを取得します。
channels.historyを実行するとき取得期間を絞るため、oldestに前日0時0分、latestに当日0時0分を設定します。
※厳密にやると0時0分が重複するからダメかもしれない。
Slackにアプリを登録する
事前準備としてSlackにアプリを登録し、Botユーザを作成します。
詳しくはこちらへ。
channels.historyの実行にchannels:history readの権限が必要なので付与しておきましょう。
合わせてOAuth Access TokenとBot User OAuth Tokenが必要となるのでメモっておきます。
実装
必要なパラメータ(OAuth Access TokenとBot User OAuth Token、送信先チャンネル)は.envファイルに記載しています。
// load .env require('dotenv').config(); const SLACK_TOKEN = process.env.SLACK_TOKEN; const SLACK_BOT_TOKEN = process.env.SLACK_BOT_TOKEN; const SEND_CHANNEL = process.env.SEND_CHANNEL; const util = require('util'); const slack = require('slack'); const moment = require('moment-timezone'); const CronJob = require('cron').CronJob; function getChannels(oldest, latest) { return new Promise(function(onFulfilled, onRejected) { slack.channels.list({ token: SLACK_TOKEN }).then(response => { onFulfilled({ channels: response.channels.map(channel => channel.id), oldest: oldest, latest: latest }); }); }); } function getReactions(responses) { return new Promise(function(onFulfilled, onRejected) { reactions = []; const channels = responses.channels; const oldest = responses.oldest; const latest = responses.latest; let i = 0; channels.map(channel => { slack.channels .history({ token: SLACK_TOKEN, channel: channel, oldest: oldest, latest: latest }) .then(response => { response.messages.map(message => { if ('reactions' in message) { reactions = reactions.concat(message.reactions); } }); if (++i == channels.length) { onFulfilled(reactions); } }) .catch(error => { console.log('error!!'); }); }); }); } sortReaction = reactions => { // counter totalReaction = []; reactions.map(reaction => { name = ':' + reaction.name + ':'; if (name in totalReaction === false) { totalReaction[name] = 0; } totalReaction[name] += reaction.count; }); // convert for sort sortReaction = []; for (name in totalReaction) { sortReaction.push({ name: name, count: totalReaction[name] }); } sortReaction = sortReaction.sort((a, b) => { if (a.count > b.count) return -1; else if (a.count < b.count) return 1; else return 0; }); // create send message msg = ''; for (reaction of sortReaction) { msg += reaction.name + ' : ' + reaction.count + '\n'; } return msg; }; postMessage = () => { // oldest ※前日0時0分 oldest = moment() .subtract(1, 'days') .startOf('day'); latest = moment().startOf('day'); getChannels(oldest.unix(), latest.unix()) .then(getReactions) .then(reactions => { if (reactions.length === 0) { msg = 'Good Morning!! ' + oldest.format('M/D(ddd)') + 'のリアクションは・・・なしです。'; } else { msg = 'Good Morning!! ' + oldest.format('M/D(ddd)') + 'のリアクション集計しました。\n\n'; msg += sortReaction(reactions); } console.log(msg); slack.chat.postMessage({ token: SLACK_BOT_TOKEN, channel: SEND_CHANNEL, text: msg }); }); }; const job = new CronJob({ /* Seconds: 0-59 Minutes: 0-59 Hours: 0-23 Day of Month: 1-31 Months: 0-11 Day of Week: 0-6 */ cronTime: '0 0 9 * * *', // 毎日午前9時に送信 onTick: postMessage, start: false, timeZone: 'Asia/Tokyo' }); job.start();
正しく動けばこんな感じでBotユーザから送信されます。
GitHubにインストール手順をまとめているので、使ってみたい方はどうぞ。
まとめ
実は絶賛開発中の社内通貨プロジェクトで利用しようかなって考えてます。
当時はSlackを利用してなかったので、別のツールを利用してイイねのやり取りを行う予定でした。
社内のチャットツールをSlackに切り替えリアクションのやり取りが予想以上に活発なので、データを収集して活用する術を頭の中で妄想してます。
たぶん特定のリアクションを貰う(贈る)と通貨がもらえるような感じになりそうです。
ではまた。
経験年数で足切りされたくない人へ、スキルを偏差値化するマッチングサイトFindy
IT業界で企業がエンジニアの技量を図る基準と言えば、まず第一に経験年数でしょう。
転職サイトを見ると経験年数3年以上ないと足切りされるとこも多いですね。
経験年数3年の理由は?
理由1:ミスマッチの応募者を避けたい
ミスマッチの応募者が多いと、選考や面接に手間も時間もかかる。そのため、「1年やってればこのくらいはわかるはず」「3年以上と書けば素人はこないだろう」などの思惑で境界線を設定する。
理由2:以前の中途採用者から判断するしかない
年数を決めるのは採用予定部署の責任者などだが、中途採用者の経験年数とその後の活躍度を判断材料にすることが多い。つまり、「以前に採った『経験1年』は使えなかった」などの肌感覚で数字を出す。
理由3:広告スペースと広告費に限りがある
ほしい人材を詳細に説明すると、文章量が膨大になり、広告スペースに収まらなくなってしまう。また、広告費に上限があるので、ほしいスペースを確保できない場合もある。
引用元:https://next.rikunabi.com/tech/docs/ct_s03600.jsp?p=000052
あくまでも目安ということみたいです。
基準を満たしていない場合、どう捉えらばいいでしょう?
3人のコンサルタントは口をそろえて「年数が足りなくても応募すべき」という。しかし、無条件というわけではない。
「経験年数は通常8割までが許容量だと思います。経験3年以上という記載なら、2年半ですね。大切なのは、不足の2割を補うプラスアルファ。そこが強いことが条件ですが、6、7割でも可能な場合もあります」(佐藤氏)
「ただ部署にいただけの経験3年と、業務をみっちり学んだ経験2年では、スキルで後者が勝る場合もある。しかし、企業はその事実を知りませんから、まずは応募書類でアピールすべきです。 例えば、『経験は2年ですが、私が考える御社の業務展開に特化した、密度の濃い2年でした。なぜなら……』などと具体的に説明する。これは面接に進んだ場合のアピールにも使えます」(稲垣氏)引用元:https://next.rikunabi.com/tech/docs/ct_s03600.jsp?p=000052
何かアピールポイントが必要ということです。
そこでエンジニアに嬉しいサービスがFindy(ファインディ)です。
コードを偏差値化?
Findyはエンジニア向けのマッチングサイトです。
最大の特徴はGitHub連携でコードを偏差値化できる機能。
使い方はカンタンでGitHubアカウントでログインするだけ。
ぼくも使ってみました。
コードを書く1つの指標になるから良いね。それにしても偏差値ヒドイ。もっとコミットしなきゃ。
— まろえもん (@maroemon58) August 3, 2018
エンジニア向けスキル偏差値の診断結果、私の偏差値は、 Python 43.0、 PHP 42.0 でした。
あなたもスキル偏差値をチェックしよう! https://t.co/dW3bKS3KqV #findy #findyfreelance #スキル偏差値
なかなか手厳しいですね・・・。
フリーランス・副業の場合は偏差値50以上が案件紹介の条件となってます。
ただ、こんな注意書きも。
しかしながら、十分なスキルをお持ちの方でスキル偏差値を解析しきれない方がいる事を把握をしており、スキル偏差値以外にも新しい指標やプロフィール項目のチェックによる解析方法の追加を近いうちに実装の検討をしていきます。
会社では高い評価を得ているけどGitHubにコードを残していない人は、今後Findyでも同等の評価を得られるかも知れませんね。
欲を言えば点数の内訳を提示してもらえば改善しがいがあるのに・・・と思いました。
まとめ
これまで会社の仕事にフルコミットしてたので、世間へアピールする材料がないって焦ってる人もいるでしょう。
ぼくもその1人です。
転職するにしてもポートフォリオの提出を求められる時代ですので、エンジニアとして活躍するために普段からセルフブランディングを心がけたいですね。
ではまた。
FileZillaの設定を新しいMacに引き継ぐ方法
新しいMacBook Proを購入したので、せっせと必要なアプリをインストールしています。
FTPクライアントは旧Macで使用していたFileZilleを利用することにしたのですが、「もしかしてまた1からアクセス先を設定すんの?」と一瞬脳裏をよぎりました。
そんな面倒なことやってられないので、いろいろ調べてみたところ無事に引き継げたので設定方法をまとめます。
旧Macから設定ファイルをエクスポート
まずは旧MacのFileZillaを起動し、「ファイル > エクスポート」をクリックします。
「サイトマネージャーエントリをエクスポート」「設定をエクスポート」にチェックを入れ、「OK」をクリックします。
エクスポートするフォルダとファイル名を決めて、「保存」をクリックします。
エクスポートしたファイルが出力されたら、新Macの作業に移るのでファイルを転送しましょう。
新Macで設定ファイルをインポート
「ファイル > インポート」をクリックすると、読み込むファイルを聞かれるので転送したファイルを選択します。
インポート可能なデータが表示されるので、全部チェックし「OK」クリックすると完了です!
まとめ
設定自体は非常にカンタンに引き継げますが、ログイン時に必要な鍵ファイルなどは別途持ってこないといけないので、そこだけ気をつけましょう。 ※ユーザ名が一緒なら同じ場所に鍵を放り投げればいけるはずです。
ではまた。
【随時更新】WebエンジニアがMacBook Proを新調したのでインストールしたアプリを紹介する
MacBook Air 2015 11inchからMacBook Pro 2018 15inchに買い替えました。
ものすごく快適です。
旧Macから移行を行ったのですが、不要なゴミ(アプリ等)は入れたくなったので必要なアプリや設定を1から行いました。
OS設定
3本指ドラッグを有効にする
「システム環境設定 > アクセシビリティ > マウス/トラックパッド > トラックパッドオプション」を開き、「ドラッグを有効にする」にチェックし、「3本指のドラッグ」を選択します。
便利アプリ
Google日本語入力
MacOS標準で搭載されている日本語入力エンジン「日本語IM」は使いづらいので、Google日本語入力をインストールします。
キーボードの入力ソースも英数(Google)、ひらがな(Google)のみに変更しました。
※「システム環境設定 > キーボード > 入力ソース」から設定可能
Parallels Desktop
Windows環境を利用するための仮想環境アプリ。
Office 365
Mac標準のアプリで十分ですが、Windowsユーザとの互換性のため・・・。
お気に入りするまではないけど、とりあえずWebページを保存するアプリ。あとで読み返したいときに便利です。
Skitch
Mac定番のペイントアプリ。ブログ画像の注釈入れるのに重宝してます。
Be Focused
シンプルなタイマーアプリ。集中して作業したいときに重宝します。
Alfred 3
定番のランチャーアプリ。
OmniFocus 2
GTDというタスク管理術のためのアプリ。
ライセンスの移行方法についてはこちら。
BetterTouchTool
トラックパッドジェスチャーを拡張するアプリ。こちらもド定番です。
AppCleaner
アプリを削除する際に関連ファイルもまとめて削除してくれるアプリ。アンインストール時にゴミを残したくない場合は必須です。
Tunnelblick
OpenVPNクライアント。社外から社内ネットワークに接続するときに必要となるアプリです。※サーバの設定も必要。
ブラウザ
Web系の仕事をしているので、有名所は動作確認のため全てインストールしています。
Google Chrome
FireFox
SNS系アプリ
LINE
生活必須のSNSアプリ。
Skype
チャットアプリ。たまに仕事で使います。
TweetBot 3
Mac専用Twitterクライアント。有料ですが非常に使いやすくオススメです。
Slack
一般にも勢力を伸ばしつつあるチャットツール。使うのが楽しいアプリです。仕事で使っているので必須。
Discord
開発者コミュニティで使用しているチャットアプリ。
開発用アプリ
Xcode
アプリ開発はしないが何かと必要になるので一応。
Visual Studio Code
お気に入りの開発用エディタ。最近Atomから乗り換えました。
iTerm2
ターミナルアプリ。細かい設定は別途紹介するかもしれないです。
SourceTree
Gitクライアントアプリ。ターミナルやVScodeでGit操作することが多いですが一応入れておきます。
Homebrew
macOS 用パッケージマネージャー。
Nano Wallet
仮想通貨NEMのウォレット。ブロックチェーン開発で使用します。
NEM – Distributed Ledger Technology (Blockchain) » Downloads
FileZilla
FTPクライアント。もっとUIが洒落てれば100点なんですが・・・。でも、ミスったら死ぬので機能優先。
VirtualBox
仮想環境を作成するためのアプリ。プロジェクトごとに開発環境を分けたいときは必須。
Vagrant
こちらも仮想環境用。VirtualBoxとセットで使用します。
Sequel Pro
MySQL用DBクライアント。
PSequel
PostgreSQL用DBクライアント。
Git
$ brew install git
Python
$ git clone git://github.com/yyuu/pyenv.git ~/.pyenv $ git clone https://github.com/yyuu/pyenv-pip-rehash.git ~/.pyenv/plugins/pyenv-pip-rehash $ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc $ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc $ echo 'eval "$(pyenv init -)"' >> ~/.bashrc $ source ~/.bashrc $ pyenv install -l | grep anaconda3 $ pyenv install anaconda3-5.2.0 $ pyenv global anaconda3-5.2.0 $ echo 'export PATH="$PYENV_ROOT/versions/anaconda3-5.2.0/bin:$PATH"' >> ~/.bashrc $ source ~/.bashrc # 確認 $ python --version Python 3.6.5 :: Anaconda, Inc.
※詳細はこちら https://qiita.com/maroemon58/items/53977dc802c6373c027e
node.js
$ brew install nodebrew $ echo PATH="$HOME/.nodebrew/current/bin:$PATH" >> ~/.bashrc $ mkdir ~/.nodebrew $ mkdir ~/.nodebrew/src $ nodebrew install-binary v6.10.3 $ nodebrew use v6.10.3 # 確認 $ node -v v6.10.3 $ npm -v 3.10.10
※詳細はこちら https://qiita.com/maroemon58/items/e18ac7e80a20a3c764f8
bash_profile
Pythonのインストールで.bashrcに追記しましたが、MacOSではターミナル起動時に読み込まないので読み込むように.bash_profileに追記します。※ファイルがない場合は新規作成
$ vim ~/.bash_profile # 下記を追加 if [ -f ~/.bashrc]; then . ~/.bashrc fi
Ganache
DApps用のアプリです。Ganacheはローカル環境上にテスト用のプライベートチェーンを構築します。
Truffle
dApps開発のためのフレームワーク。
$ npm install -g truffle
DApps開発ギルドでデプロイしたアプリを1から作ってみる
先日、オオキマキさん(@ookimaki_JP)が主催するDApps開発ギルドの勉強会に参加してきました。
勉強会は2時間という限られた時間だったので、今回作ったアプリを復習がてら自分で1から作成してみました。
勉強会で行った内容はこちら。
それでは作ってみます。
開発環境
MacBook Pro(macOS High Sierra 10.13.6)
MetaMask 4.8.0
Ganache 1.2.1
$ npm -v 6.1.0 $ node -v v10.7.0 $ truffle version Truffle v4.1.13 (core: 4.1.13) Solidity v0.4.24 (solc-js)
環境構築が済んでいない方はこちらへ。
プロジェクト初期化
はじめにプロジェクト用のフォルダを作成し移動しましょう。
$ cd ~/Document $ mkdir ~/dapps $ mkdir ~/dapps/turotial/ $ cd ~/dapps/tutorial/
今回はtutorial
というフォルダで作業を行います。
プロジェクトフォルダに移動したら、truffleというフレームワークを初期化します。
$ truffle init Downloading... Unpacking... Setting up... Unbox successful. Sweet! Commands: Compile: truffle compile Migrate: truffle migrate Test contracts: truffle test
tutorial
直下にファイルが作成されていることを確認しましょう。
コントラクトを作成
contracts
フォルダの下にSimpleStore.sol
を作成します。
ファイルの中身は次のコードを記載します。
pragma solidity ^0.4.23; contract SimpleStore { string value; function set(string _value) public { value = _value; } function get() public view returns (string) { return (value); } }
Migrationsを作成
先ほど書いたコントラクトをデプロイするためのmigrationを作成します。
migrations
フォルダに2_deploy_contracts.js
を作成します。
ファイルの中身は次のコードを記載します。
var SimpleStore = artifacts.require('../contracts/SimpleStore.sol'); module.exports = function(deployer) { deployer.deploy(SimpleStore); };
ネットワーク設定
次にデプロイするネットワークを設定ファイルに追記します。
truffle.js
に次のコードを記載します。
module.exports = { // See <http://truffleframework.com/docs/advanced/configuration> // to customize your Truffle configuration! networks: { development: { host: '127.0.0.1', port: 8545, network_id: '*' } } };
host: 127.0.0.1
、port: 8545
という接続先はプライベートチェーンGanacheを指しています。
※Ganacheのポート番号を8545に変更しています。Ganacheの設定画面から変更可能です。
デプロイ
準備が整ったのでデプロイします。コマンドを実行する前にGanacheを起動しておきましょう。
$ truffle migrate Compiling ./contracts/Migrations.sol... Compiling ./contracts/SimpleStore.sol... Writing artifacts to ./build/contracts Using network 'development'. Running migration: 1_initial_migration.js Deploying Migrations... ... 0x55a8c1d05804136fb1670127c8bf4f08b6832a74a44e8a0006b8108ffb355d46 Migrations: 0x562f587d7241ca995b50476adbbdc4bf3b7fa75f Saving successful migration to network... ... 0xa1d9bb5b7594aea5b49ea110e2648dc5859c49c18b05aad555fab6c4dc2b6658 Saving artifacts... Running migration: 2_deploy_contracts.js Deploying SimpleStore... ... 0x4dd1bdb65839e6eaade2cb3a45b9d63fa403bf66f8609d014d54eb09eaf07c13 SimpleStore: 0x15a40f91de5f6797721266c6a6daf83758d10e00 Saving successful migration to network... ... 0xe1b4d2a0a3aba6861b6e2c79fa5285af636d04d2ce030a0fa85db53a250ac229 Saving artifacts...
SimpleStore: 0x15a40f91de5f6797721266c6a6daf83758d10e00
がコントラクトのアドレスになります。
重要なのでメモっておきましょう。※これって後で確認したいときどうするんでしょう?
無事にデプロイできたらbuild
というフォルダが作成されているはずです。
フロントアプリを作成
コントラクトがデプロイできたので、これを利用するためのフロントアプリを作成します。
tutorial
直下にsrc
フォルダを作成し、下記3つのファイルを追加していきます。
web3.min.js
は下ページから最新バージョンをダウンロードし、dist/web3.min.js
を所定の位置に配置します。
contract_abi.js
は新規に作成し、下記コードを記載しましょう。
変数の中身はbuild/SimpleStore.json
のabiから取ってきたものです。
var contractABI = [ { // build/SimpleStore.jsonのabiをコピペ constant: false, inputs: [ { name: '_value', type: 'string' } ], name: 'set', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function' }, { constant: true, inputs: [], name: 'get', outputs: [ { name: '', type: 'string' } ], payable: false, stateMutability: 'view', type: 'function' } ];
index.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>DApps Dev Guild Tutorial</title> <script language="javascript" type="text/javascript" src="./js/web3.min.js"></script> <script language="javascript" type="text/javascript" src="./js/contract_abi.js"></script> <script> var contract; var userAccount; function startApp() { var contractAddress = "0xdc30da2490373416e7bf7467bb297bae624287b4"; contract = new web3js.eth.Contract(contractABI, contractAddress); var accountInterval = setInterval(function () { web3.eth.getAccounts((error, accounts) => { if (accounts[0] !== userAccount) { userAccount = accounts[0]; } }); }, 100); } window.addEventListener('load', function () { // Checking if Web3 has been injected by the browser(Mist/MetaMask) if (typeof web3 !== 'undefined') { // Use Mist/MetaMask's provider web3js = new Web3(web3.currentProvider); } else { // Handle the case where the user doesn't have Metamask installed // Probably show them a message prompting them to install Metamask } // Now you can start your app & access web3 freely; startApp(); }); function set() { var _val = document.getElementById("val").value; contract.methods.set(_val) .send({ from: userAccount }) .on("transactionHash", function (txhash) { alert("Txhash: " + txhash); }) .on("receipt", function (receipt) { console.log(receipt); }) .on("error", function (error) { console.log(error); }); } function get() { contract.methods.get().call().then(function (_val) { alert(_val); }); } </script> </head> <body> <h1>DApps Dev Guild Tutorial</h1> <input type="text" name="val" id="val"> <input type="button" value="Set" onclick="set()"> <input type="button" value="Get" onclick="get()"> </body> </html>
MetaMaskにethを用意する
アプリを実行するためにはMetaMaskにethがないと利用できないので、Ganacheで用意されているアドレスをインポートしましょう。
適当なアドレスのshow keys
をクリックします。
プライベートキーが表示されるのでクリップボードにコピーします。
MetaMaskの人マークをクリックすると、アカウントメニューが表示されるのでImport Account
をクリックします。
先程コピーしたプライベートキーを入力し、Import
をクリックするとアカウントが追加されます。
動作確認
動作確認するためにlive-server(ローカルWebサーバ)を利用します。
導入されていない方はnpm install
でインストールしましょう。
$ npm install -g live-server
エディタのプラグインで提供されている場合もあるので、そっちを使っても大丈夫です。
src
フォルダに移動して実行します。
$ cd src $ live-server Serving "/Users/hoge/Document/dapps/tutorial/src" at http://127.0.0.1:8080 Ready for changes
Chromeでhttp://127.0.0.1:8080
にアクセスするとフロントアプリの画面が表示されます。
MetaMaskを立ち上げネットワークLocalhost 8545
を選択します。
実際に動かしてみます。
無事に動きました!お疲れ様でした!!
おまけ
ちょっと見た目が野暮ったいので、機能は変えずにデザインをオシャレにアレンジしてみます。
MaterializeというCSSフレームワークを利用します。
ファイルをダウンロードし、materialize.min.css
とmaterialize.min.js
を配置します。
index.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>DApps Dev Guild Tutorial</title> <script language="javascript" type="text/javascript" src="./js/web3.min.js"></script> <script language="javascript" type="text/javascript" src="./js/contract_abi.js"></script> <script language="javascript" type="text/javascript" src="./js/materialize.min.js"></script> <!--Import Google Icon Font--> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <!--Import materialize.css--> <link type="text/css" rel="stylesheet" href="./css/materialize.min.css" media="screen,projection" /> <script> var contract; var userAccount; function startApp() { var contractAddress = "0xdc30da2490373416e7bf7467bb297bae624287b4"; contract = new web3js.eth.Contract(contractABI, contractAddress); var accountInterval = setInterval(function () { web3.eth.getAccounts((error, accounts) => { if (accounts[0] !== userAccount) { userAccount = accounts[0]; } }); }, 100); } window.addEventListener('load', function () { // Checking if Web3 has been injected by the browser(Mist/MetaMask) if (typeof web3 !== 'undefined') { // Use Mist/MetaMask's provider web3js = new Web3(web3.currentProvider); } else { // Handle the case where the user doesn't have Metamask installed // Probably show them a message prompting them to install Metamask } // Now you can start your app & access web3 freely; startApp(); }); function set() { var _val = document.getElementById("val").value; contract.methods.set(_val) .send({ from: userAccount }) .on("transactionHash", function (txhash) { alert("Txhash: " + txhash); }) .on("receipt", function (receipt) { console.log(receipt); }) .on("error", function (error) { console.log(error); }); } function get() { contract.methods.get().call().then(function (_val) { alert(_val); }); } </script> </head> <body> <nav> <div class="nav-wrapper blue-grey "> <a href="" class="brand-logo">DApps Dev Guild Tutorial</a> </div> </nav> <div class="container"> <input type="text" name="val" id="val"> <div class="center"> <a class="waves-effect waves-light btn" onclick="set()"> <i class="material-icons left">file_upload</i>Set</a> <a class="waves-effect waves-light btn" onclick="get()"> <i class="material-icons right">file_download</i>Get</a> </div> </div> </body> </html>
まとめ
デプロイするまでDApps開発に敷居を高く感じていましたが、手順を教えてもらい一通りできるようになったので取っ掛かりは掴めたかなって感じです。 所々理解できていない部分もありますが、今は教えられたことを全部飲み込むフェーズにし、アプリの開発をドシドシやろうと思います。ではまた。