- 投稿日:2019-02-26T23:47:37+09:00
Vue Cli 3で作ったコンポーネントライブラリをnpmで公開する
自己紹介
@coppieee
https://coppieee.com
フリーランスプログラマ
Vue.js、TypeScript、Serverless、Cordovaとかやってます。
Vue.js コンポーネントライブラリを作成しました
Vue.jsでMaterial DesignしたくてVuetifyやVue Materialとかライブラリを触ってみたけど、
CSSなどいろいろカスタマイズし辛い。
なのでMaterial Designの勉強も兼ねて、Material Designの自作ライブラリを作りnpmに公開しました。
npm公開作業は結構簡単にできたのでnpm publishの方法を共有します。
npmで公開したもの
Vuterial
Material Designするための Vue.js コンポーネントライブラリ。
Materail Conponents for Webを使って実装してる。https://github.com/coppieee/vuterial
https://coppieee.github.io/vuterial/
サンプル(ドキュメントページ)
コンポーネントをnpm publish して公開する手順
- Vue CLI 3でプロジェクトを作成
- build設定
- package.json設定
- npmjsにサインアップ
- npm publish
Vue CLI 3でプロジェクトを作成
ライブラリを作成する場合もWebアプリと作るのと同様にVue CLIから作成します。
$ npm i -g @vue/cli $ vue create your-library-name特にライブラリ用に特殊な設定は必要ないので自分の好きなように設定しよう。
ライブラリ名は名前が被ってないかnpmjs.comでチェックしておきましょう。
Build設定
ライブラリのビルドは
vue-cli-service
にライブラリ生成用のビルドオプションがあるのでそれを使う。$ vue-cli-service build --target lib --name your-library-name ./lib-main.jsそれを
package.json
のscripts
にbuild-bundle
など適当な名前で設定しておくといいでしょう。package.json{ "scripts":[ "serve": "vue-cli-service serve", "build": "vue-cli-service build", "build-bundle": "vue-cli-service build --target lib --name your-library-name ./src/lib-main.js", ... ] }
Build結果
$ npm run build-bundle
./distフォルダに以下のファイルが出力される
./distyour-library-name.common.js your-library-name.common.js.map your-library-name.css your-library-name.umd.js your-library-name.umd.js.map your-library-name.umd.min.js your-library-name.umd.min.js.mapjsとcssを生成してくれる。
WebPackなどで使う場合はcommon.js、ブラウザで直接読み込む場合はumd.jsを使うことになる。
ライブラリの生成まで一つのコマンドでしてくれるVue CLI 3ってすげー。
ライブラリの実装例
今回はVue プラグインとして使う設定をしている。
ライブラリ使用者はVue.use(libraryName)
の形式で使うことになる。以下一例。lib-main.jsimport { mdcChip } from './components/mdc-chip.vue' import { mdcCard } from './components/mdc-card.vue' import { mdcButton } from './components/mdc-button.vue' // ... export default const YourLibraryName = { install(Vue, options){ const components = { mdcButton, // <mdc-button/> として使える mdcCard, // <mdc-card/> として使える // ... } for(const [name,c] of Object.entries(components)){ Vue.component(name,c) } }, }
package.jsonの設定
package.json{ "name": "your-library-name", "version": "0.1.0", "main":"dist/your-library-name.common.js", // エントリーポイント "unpkg": "./dist/your-library-name.umd.min.js", // CDN用(オプション) "jsdelivr": "./dist/your-library-name.umd.min.js", //CDN用(オプション) "typings":"dist/types/index.d.ts", //typescript用型ファイル(オプション) "license": "MIT", "author": "your name", "files": [ "dist" // npm publish 対象のフォルダ ], "dependencies": {}, // distのみ公開の場合はdependenciesの中は空でOK "peerDependencies": { // 依存しているライブラリ(オプション) "vue": "^2.6.6", "vue-router": "^3.0.2" }, "private": false, ... }npm publishに必要な設定はmainにエントリーポイントのパス設定と、filesでnpm にアップする対象を設定する。
privateをfalseに。
dependenciesにはdistだけを公開する場合は何も書かなくていい。
必要最低限の設定はそれだけであとはオプション。ちなみに以下のファイルは、filesに指定しなくても自動的にアップされる。
- package.json
- README
- CHANGELOG
- LICENSE / LICENCE
unpkgとjsdelivrはCDN配布用で、設定するとそれぞれ
https://unpkg.com/your-library-name@latest
https://cdn.jsdelivr.net/npm/your-library-name@latest
というURLでjsファイルにアクセスできるようになる。
htmlのscriptタグのsrcで直接読み込む方式だ。他にもいろいろ設定があるけど、githubに公開されてるvueとかvuetifyとかのpackage.jsonを見てみると参考になる。
npm login
ビルドの設定が終わったら次はいよいよnpmに公開する作業だ。
npm用のアカウントを作成してから、コンソールでログインする。npm サインアップ
npm login
$ npm login
npm publish
$ npm run build-bundle $ npm publish
npm 公開完了
https://www.npmjs.com/package/your-package-name
のようなURLで公開確認できる。https://www.npmjs.com/package/vuterial
npm install example
npm に公開できたらプロジェクトを作成してnpm installしてみよう。
$ vue create my-project $ cd vmy-project $ npm i your-library-name
ライブラリをimport
ライブラリをimportしてVue.use()で設定する。
また、cssも使う場合は別途import。main.jsimport Vue from 'vue' import YourLibraryName from 'your-library-name' import 'your-library-name/dist/your-library-name.css' Vue.use(YourLibraryName)
まとめ
Vue コンポーネントをnpmに公開する場合もVue CLI 3を使うと簡単。
- 投稿日:2019-02-26T23:41:11+09:00
Re:ゼロから始めるポートフォリオ開発【Vue.js】
概要
Web初心者がVue.jsでポートフォリオを作ってみた
2019/2/26 レスポンシブ対応してないので注意準備
作成物
まずコンポーネントを作ろう
とりあえず全ページ共通で使用するものをコンポーネントとして用意すればいいっしょ?
という軽い気持ちで作成。ヘッダー
Header.vue<template> <div> <header class="header"> <router-link to="/">Top</router-link> <router-link to="/about">About</router-link> <router-link to="/career">Career</router-link> <router-link to="/portfolio">Portfolio</router-link> <router-link to="/contact">Contact</router-link> </header> </div> </template>ページタイトル(画面毎に文言が変わるためpropsを設定)
Pagetitle.vue<template> <div class="pagetitle"> <p> {{pagetitle}} </p> </div> </template> <script> export default{ name:'pagetitle', props:{ pagetitle:{ type:String, default:'' } } } </script>ヘッダーは画面によって文言やデザインが変わる必要は無いのでApp.vueに記載
App.vue<template> <div id="app"> <Header></Header> <router-view/> </div> </template> <script> import Header from '@/components/Header' export default{ name:'header', components:{ Header } } </script>ページの作成
HTMLとCSSでページを作成する。
作成したページタイトルコンポーネントに引数を入れて呼び出す。トップ画面
Top.vue<template> <div class="top"> <Pagetitle pagetitle='Top'></Pagetitle> <p id="text">Doragon's Portfolio</p> </div> </template> <script> import Pagetitle from '@/components/Pagetitle.vue' export default{ name:'top', components:{ Pagetitle } } </script>Router
作成したページをRouterに設定。
router.jsimport Vue from 'vue' import Router from 'vue-router' import Top from './pages/Top.vue' import About from './pages/About.vue' import Career from './pages/Career.vue' import Contact from './pages/Contact.vue' import Portfolio from './pages/Portfolio.vue' Vue.use(Router) export default new Router({ mode: 'history', base: process.env.BASE_URL, routes: [ { path: '/', name: 'top', component: Top }, { path: '/about', name: 'about', component: About }, { path: '/career', name: 'career', component: Career }, { path: '/portfolio', name: 'portfolio', component: Portfolio }, { path: '/contact', name: 'contact', component: Contact } ] })main.jsにrouterの宣言を忘れずに。
main.jsimport Vue from 'vue' import App from './App.vue' import router from './router' Vue.config.productionTip = false new Vue({ router, render: h => h(App) }).$mount('#app')作成したポートフォリオを公開する
今回はgithub pagesにデプロイする。
ソースコードを公開する代わりに無料でwebページを公開してくれる優しいやつ。vue.config.jsをディレクトリ直下に作成
このままbuildすると/dist直下にビルドファイルが作成されてしまう。
github pagesでは/docs直下のものが公開対象となるため設定を変更する。vue.config.jsmodule.exports = { baseUrl: process.env.NODE_ENV === 'production' ? '/portfolio/' : '/', outputDir: 'docs', };コマンドラインでビルドを行う
$npm run buildgithub
/docs直下にビルドされたファイルが作成された事を確認した後、masterにpush。
githubのsettingを以下のようにする。
反映まで少し時間がかかるので注意
せっかちな人は以下の記事を参考にしてください。
https://qiita.com/shge/items/ac20f45c9e8e0b4f33cc一言
レスポンシブ対応がまだ出来ていないので後々やります・・・。
SASSも使いたかったけど、全く使っていない・・・。
HTMLとCSSとJSはまだまだ初心者レベルなので修行が必要だと痛感した。
Node.jsも勉強してwebに強くなりたい。参考文献
https://qiita.com/plus_kyoto/items/a01578b782f17f573510
https://qiita.com/shge/items/ac20f45c9e8e0b4f33cc
- 投稿日:2019-02-26T15:49:30+09:00
vue.js 超超超初心者向け用語とかmemo
初心者の自分がvueをやろうとして初心者向けの本を読んでも分からない単語でつまづくことがあったので、自分の経験を踏まえて分からなかった箇所をメモしていく。
Vue.jsとは
Vue.js:https://jp.vuejs.org/v2/guide/
双方向データバインディング(リアクティブ)な設計で実装する、MVVM(Model-View-ViewModel)モデルを起用したjsフレームワークです。
・大規模開発
・アプリ開発
・SPA
等複雑なページを効率良く、煩雑にならないように構築する手助けをしてくれます。MVVMとは
設計思想のひとつ。
他にはMVC等がある。
(中級者以上向けだと思うので、初心者の段階ではふんわりと、設計の概念と思っていれば良いかと)基本フロー
1. ページにVue.js本体を読み込む
vue.js本体を読み込むとVueオブジェクトが生成される(グローバル変数Vueが生成される)。
2. jsファイルにVueインスタンスを記述する(DOMをマウントする)
指定したhtml要素に対応するインスタンスを生成する。
インスタンスはこんな感じでnew Vueで作成するやつ↓new Vue({ el: 'html element', data: { }, method(){ }, })↑のhtml elementの箇所がvueで操作する範囲になります。
※vue操作はデータバインディングで使う範囲なので、それ以外は普通のノーマルなjsでDOMを操作します。
Vueインスタンスについて:https://jp.vuejs.org/v2/guide/instance.html3. Vueインスタンスにオプションを記述する
指定したhtml要素内でvue.jsを操作できるようになります。
オプションの種類:https://jp.vuejs.org/v2/api/#%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3-%E3%83%87%E3%83%BC%E3%82%BF4. コンポーネントやmixinや色んな技術で拡張していく
用語
用語 説明 グローバル変数Vue Vue.js本体を読み込んだときに生成されるオブジェクト。 Vueインスタンス Vue.jsで構築するに当たってまず最初に生成するコンストラクタ。 コンストラクタ オブジェクトを生成するための関数。(例 new Vueで作ったVueインスタンス オプションオブジェクト Vueインストラクタを生成するときに指定するオプション。 コンポーネント 再分化したモジュール郡。再利用できるモジュールにそれぞれ機能を分けて管理することで、プロジェクト内の見通しと開発効率を上げる。 Mastache {{}}←コレ。Vue.jsで使用するテンプレート構文です。データをMastacheで囲むとテキストとして展開されます。 ディレクティブ v-show、v-if、v-on、...等、v-から始まるデータバインディングをするための記述。 プリコンパイル 事前にブラウザが取り込みやすいようにjsのコンパイルをしておくのでパフォーマンスが良い。 JustInTimeコンパイル(JIT) webページを初期表示するときに、ブラウザ側でjsをコンパイルするのでプリコンパイルより反応が遅い。 単一ファイルコンポーネント SFC(single file component)と省略される。template、script、cssをひとつのファイルにまとめた記述方法。 その他メモ
コンポーネント
記述方法としては2パターンある。
・Vueオブジェクトを拡張してグローバルに登録する記述方法
・オブジェクトを作成してvueインスタンスに登録する方法Vueオブジェクトを拡張してグローバルに登録する方法
Vue.component('my-component', { // オプション })オブジェクトを生成してvueインスタンスに登録する方法
//コンポーネントオブジェクト var component = { //オプション } //↑このコンポーネントオブジェクトを↓vueインスタンスに登録する new Vue({ components:{ 'component':Component } });気づいたことがあったら追記していきます
- 投稿日:2019-02-26T15:49:30+09:00
Vue.js 超超超初心者向け用語とかmemo
初心者の自分がvueをやろうとして初心者向けの本を読んでも分からない単語でつまづくことがあったので、自分の経験を踏まえて分からなかった箇所をメモしていく。
Vue.jsとは
Vue.js:https://jp.vuejs.org/v2/guide/
双方向データバインディング(リアクティブ)な設計で実装する、MVVM(Model-View-ViewModel)モデルを起用したjsフレームワークです。
・大規模開発
・アプリ開発
・SPA
等複雑なページを効率良く、煩雑にならないように構築する手助けをしてくれます。MVVMとは
設計思想のひとつ。
他にはMVC等がある。
(中級者以上向けだと思うので、初心者の段階ではふんわりと、設計の概念と思っていれば良いかと)基本フロー
1. ページにVue.js本体を読み込む
vue.js本体を読み込むとVueオブジェクトが生成される(グローバル変数Vueが生成される)。
2. jsファイルにVueインスタンスを記述する(DOMをマウントする)
指定したhtml要素に対応するインスタンスを生成する。
インスタンスはこんな感じでnew Vueで作成するやつ↓new Vue({ el: 'html element', data: { }, method(){ }, })↑のhtml elementの箇所がvueで操作する範囲になります。
※vue操作はデータバインディングで使う範囲なので、それ以外は普通のノーマルなjsでDOMを操作します。
Vueインスタンスについて:https://jp.vuejs.org/v2/guide/instance.html3. Vueインスタンスにオプションを記述する
指定したhtml要素内でvue.jsを操作できるようになります。
オプションの種類:https://jp.vuejs.org/v2/api/#%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3-%E3%83%87%E3%83%BC%E3%82%BF4. コンポーネントやmixinや色んな技術で拡張していく
用語
用語 説明 グローバル変数Vue Vue.js本体を読み込んだときに生成されるオブジェクト。 Vueインスタンス Vue.jsで構築するに当たってまず最初に生成するコンストラクタ。 コンストラクタ オブジェクトを生成するための関数。(例 new Vueで作ったVueインスタンス オプションオブジェクト Vueインストラクタを生成するときに指定するオプション。 コンポーネント 再分化したモジュール郡。再利用できるモジュールにそれぞれ機能を分けて管理することで、プロジェクト内の見通しと開発効率を上げる。 Mastache {{}}←コレ。Vue.jsで使用するテンプレート構文です。データをMastacheで囲むとテキストとして展開されます。 ディレクティブ v-show、v-if、v-on、...等、v-から始まるデータバインディングをするための記述。 プリコンパイル 事前にブラウザが取り込みやすいようにjsのコンパイルをしておくのでパフォーマンスが良い。 JustInTimeコンパイル(JIT) webページを初期表示するときに、ブラウザ側でjsをコンパイルするのでプリコンパイルより反応が遅い。 単一ファイルコンポーネント SFC(single file component)と省略される。template、script、cssをひとつのファイルにまとめた記述方法。 その他メモ
コンポーネント
記述方法としては2パターンある。
・Vueオブジェクトを拡張してグローバルに登録する記述方法
・オブジェクトを作成してvueインスタンスに登録する方法Vueオブジェクトを拡張してグローバルに登録する方法
Vue.component('my-component', { // オプション })オブジェクトを生成してvueインスタンスに登録する方法
//コンポーネントオブジェクト var component = { //オプション } //↑このコンポーネントオブジェクトを↓vueインスタンスに登録する new Vue({ components:{ 'component':Component } });気づいたことがあったら追記していきます
- 投稿日:2019-02-26T14:45:09+09:00
Nuxt.js/Vue.jsでJSONPを取得する
前準備
プロジェクトに
vue-jsonp
をインストールします。
vue-jsonp - npmyarn add vue-jsonppluginsの設定、およびnuxt.config.jsでの設定
~/plugins/vue-jsonp.jsimport Vue from 'vue'; import VueJsonp from 'vue-jsonp'; Vue.use(VueJsonp);nuxt.config.js省略 plugins: ['~/plugins/vue-jsonp'], 省略この設定をし、再度ローカルサーバを立ち上げるコマンドを打てば
this.$jsonp
が使えるようになります。static配下のローカルjsonpにアクセスするサンプルコード
$jsonpの第二引数のObjectのcallbackNameにはjsonp側の関数名を指定すればOKです。
他に渡すパラメータが必要な場合は第二引数のObjectに一緒に入れちゃいましょう。
一緒に入れてあげるとリクエストURLにクエリパラメータが自動で付いてアクセスしてくれます。コンポーネントasync mounted() { const url = '/jsonp/test.js'; const json = await this.$jsonp(url, { callbackName: 'getData' }); console.log(json); }static/jsonp/test.jsgetData({ data: 'sample' })参考リンク
- 投稿日:2019-02-26T13:33:34+09:00
Vue.js のカスタムディレクティブの使い方とフック関数のタイミングを理解する
はじめに
Vue.js(2.6.7)のカスタムディレクティブに関しての備忘録です。
そもそもディレクティブとは?
テンプレートに記述できる
v-
から始まる属性のこと。様々なディレクティブが存在し、属性値に応じた DOM 操作ができる。
以下は DOM 操作の例。
- 要素の表示制御
- データバインディング
- イベントリスナのアタッチ
ディレクティブの利用例
以下は
v-show
(値に応じて要素のstyle.display
プロパティを変更するディレクティブ)の利用例。<div id="app"> <h1 v-show="ok">Hello!</h1> </div>const vm = new Vue({ el: '#app', data: { ok: true } }); // `ok`を`false`にすれば、`<h1 v-show="ok">Hello!</h1>`は非表示になる。 // vm.$data.ok = false;See the Pen Vue.js v-show by soarflat (@soarflat) on CodePen.
data
のok
がtrue
の場合、<h1>Hello!</h1>
は表示され、false
の場合、<h1 style="display:none;">Hello!</h1>
となり表示されない。この他にも様々なディレクティブが存在する。詳細は公式ドキュメントを参照。
カスタムディレクティブとは?
自作したディレクティブ、もしくは自作したディレクティブを登録できる機能(仕組み)のこと。
カスタムディレクティブを利用することで、属性の付与もしくは属性値の変化に伴う DOM 操作を定義できる。
なぜカスタムディレクティブを利用するのか(カスタムディレクティブの使い所)
前述の通り、
v-show
は値に応じてstyle.display
プロパティを変更しているだけなので、この DOM 操作は自前でも定義できる。しかし、ディレクティブという仕組みを利用することで、それぞれのコンポーネント(Vue インスタンス)に「値に応じて
style.display
プロパティを変更する DOM 操作」を定義せずとも、共通の DOM 操作が可能になる。そのため、複数のコンポーネント(Vue インスタンス)で独自の DOM 操作を共通化したい場合、カスタムディレクティブを定義する。
カスタムディレクティブの利用例
以下は、
v-focus
というカスタムディレクティブを定義する例。ページを読み込む(Vue インスタンスをマウントする)と
input
要素に自動でフォーカスが当たるようにする。Vue.directive('focus', { inserted(el) { el.focus(); } });
inserted
はカスタムディレクティブと紐付いた要素が親 Node に挿入された時に呼ばれるフック関数。引数el
には親 Node に挿入された要素が渡される。カスタムディレクティブと要素を紐付けるためには、以下のように定義した
v-focus
を付与する。<input v-focus>今回の場合、この
input
要素が親 Node(今回の場合はbody
要素)に挿入された時にinserted
が呼び出され、引数el
に挿入されたinput
要素が渡される。実際に動作するコードは以下の通り。
<input id="input" v-focus>Vue.directive('focus', { // `el`に`input`要素が渡されるので、それにフォーカスを当てる inserted(el) { el.focus(); } }); new Vue({ el: '#input' });See the Pen Vue.js CustomDirective example by soarflat (@soarflat) on CodePen.
ローカルディレクティブに登録する
directives
オプションを利用すれば、コンポーネント毎にカスタムディレクティブを登録できる。<input id="input" v-focus>new Vue({ el: '#input', directives: { focus: { inserted(el) { el.focus(); } } } });フック関数
前述の
inserted
を含め、カスタムディレクティブでは以下のフック関数を利用できる。
bind
: カスタムディレクティブが初めて対象の要素に紐付いた時に1度だけ呼ばれる。inserted
: カスタムディレクティブと紐付いた要素が親 Node に挿入された時に呼ばれる。update
: 紐付いた要素を抱合しているコンポーネントの VNode が更新される度に呼ばれる(子コンポーネントが更新される前に呼ばれる)。componentUpdated
: 紐付いた要素を抱合しているコンポーネントの VNode と子コンポーネントの VNode が更新された時に呼ばれる。unbind
: 紐付いた要素からディレクティブが取り除かれた時に呼ばれる。それぞれのフック関数が呼ばれるタイミングを理解する
以下は全てのフック関数が呼ばれるサンプル。
<div id="app"> <h1 v-message v-if="message">{{ message }}</h1> <button @click="update">update</button> <button @click="remove">remove</button> <button @click="init">init</button> </div>Vue.directive('message', { bind(el) { console.log('bind'); console.log('el.parentNode(bind)', el.parentNode); }, inserted(el) { console.log('inserted'); console.log('el.parentNode(inserted)', el.parentNode); }, update(el) { console.log('update'); console.log('el.innerHTML(update)', el.innerHTML); }, componentUpdated(el) { console.log('componentUpdated'); console.log('el.innerHTML(componentUpdated)', el.innerHTML); }, unbind(el) { console.log('unbind'); } }); new Vue({ el: '#app', data: { message: 'Hello Vue!' }, methods: { update() { this.message = 'Hello React!'; }, remove() { this.message = ''; }, init() { this.message = 'Hello Vue!'; } } });See the Pen Vue.js Hook Functions(Custom Directives) by soarflat (@soarflat) on CodePen.
それぞれのフック関数がどのタイミングで呼ばれるのかは、以下の通り。
- ページロード時(Vue インスタンスを生成時):
bind
、inserted
- 「update」ボタンをクリック時:
update
、componentUpdated
- 「remove」ボタンをクリック時:
unbind
- 「init」ボタンをクリック時(「remove」ボタンをクリックした後):
bind
、inserted
ページロード時(Vue インスタンスを生成時)
bind
とinserted
が呼ばれて以下がコンソール出力される。// bind // el.parentNode(bind) null // inserted // el.parentNode(inserted) <div id="app">…</div>
inserted
は親 Node に挿入された時に呼ばれるため、parentNode
(<div id="app">…</div>
)が存在する。「update」ボタンをクリック時
this.message
が"Hello React!"
になる。
update
とcomponentUpdated
が呼ばれて以下がコンソール出力される。// update // el.innerHTML(update) Hello Vue! // componentUpdated // el.innerHTML(componentUpdated) Hello React!
update
が呼ばれた時点では、子コンポーネントの VNode({{ message }}
)は更新されていないため、el.innerHTML
の結果は"Hello Vue!"
。
componentUpdated
が呼ばれた時は、子コンポーネントの VNode も更新された後のため、el.innerHTML
の結果は"Hello React!"
。「remove」ボタンをクリック時
this.message
が""
になる。今回紐付けをした要素は
v-if="message"
を付与しており、このタイミングで<h1 v-message v-if="message">{{ message }}</h1>
が破棄されunbind
が呼ばれる。// unbind
「init」ボタンをクリック時(「remove」ボタンをクリックした後)
this.message
が"Hello Vue!"
になる。
<h1 v-message v-if="message">{{ message }}</h1>
が再生成され、bind
とinserted
が呼ばれて以下がコンソール出力される。// bind // el.parentNode(bind) null // inserted // el.parentNode(inserted) <div id="app">…</div>フック関数に渡される引数
el
以外にも複数の引数が渡される。詳細は公式ドキュメントを参照。終わり
間違いがあれば、ご指摘いただけると幸いでございます。
- 投稿日:2019-02-26T02:09:38+09:00
Vue.jsのフレームワーク
はじめに
まずVue.jsに取り組もうと思った理由としては,友人とのプロジェクトの際にフロント開発をVue.jsを用いて開発していこうという話になったからである.名前は聞いたことはあるけど,使ったことはないし,jQueryとの違いも理解していないため,そこもとりあえず抑えていけるようにしていきたい.
また今回の課題の一つとしてはVue.jsのフレームワークである,"ElementUI"と"Vuerify"についても調べていき,今回の実装に関してどちらを用いるかまで検討していきたい次第である.Vue.jsについて
まずjQueryはセレクタ操作に特化したものであるため,HTMLの一部を少し弄る分には十分すぎる機能を持っている(そこまでしっかり使ったことはないため,そんな感じなのか,みたいなイメージです笑).ただし,複数UIを連携させる場合などは,セレクタ操作であるため同期の面で困難が生じる.簡単な処理をする分には,低コストでの実装できるため,そこまでこだわる必要もないイメージを感じた.
次に肝心のVue.jsについてだが,仮想DOMを構成することにより,JSとHTMLを紐づけている様子.したがって,データ変更に対して勝手に表示するようになるため同期させる処理を書かなくてもよくなる.更新が多いページや状態管理が頻繁に起こるページなどに向いている.
実際のコーディングの違い
実際のコーディングがどうなるのか,簡単なもので考えていく.
jQuery
HTML<div> Hello <span id="message">World</span> ! <button id="update">change</button> </div>JavaScript$(document).on('click', '#update', function() { $('#message').text('jQuery') })変更する部分をタグで囲むことによって,そこにJavaScriptを適用するようにしている.
Vue.js
HTML<div id="app"> Hello {{ message }} ! <button @click="update">change</button> </div>JavaScriptnew Vue({ el: '#app', data: { message: 'World' }, methods: { update() { this.message = 'Vue.js' } } })変化させたい部分を変数として持っておく.
@click="式・メソッド"
とかくと,jQueryの$(element).on('click', ...)
と同じ動きをする.まとめ
Vue.jsについてはもう少し詳しく調べる必要がある.とりあえずはVue.jsの公式ページに記載.
フレームワーク
本題としてフレームワークである"Element"もしくは"Vuetify"のどちらかを用いたい.
したがって,まずはフレームワークについてまとめるElement
フレームワークの一つであり,昔から使われているもの.コンポーネントを定義し,HTMLに記述することで利用することができる.コンポーネントにより,機能とUIを分離・再利用できるようになる.
導入
vue-cl
を使ってVue.jsをプロジェクトの準備をする.まずはグローバルにてvue-cl
をインストールする.
npm install -g vue-cli
webpackベースのプロジェクトを作成する.
vue init webpack my-project
最終的に,
./my-project/
ディレクトリが作成され、Vue.jsがインストールされる.
そのままプロジェクトに含まれるパッケージ群もインストールしておく.
cd my-project
npm install次に,待望のElementをインストールする.
npm install element-ui -S
これで利用可能となるため,
my-project/src/main.js
以下でElementを読み込み日本のロケールをセット,ElementのCSSをを読み込む.import Vue from 'vue' import ElementUI from 'element-ui' import locale from 'element-ui/lib/locale/lang/ja' import 'element-ui/lib/theme-default/index.css' import App from './App' Vue.use(ElementUI, {locale}) new Vue({ el: '#app', template: '<App/>', components: { App } })ここまでで準備が整ったため,
my-project/src/App.vue
でコンポーネントを利用することでElementを使うことができる.まとめ
簡単な機能などは,特に苦労することなく実装することができそうである.
Vuetify
マテリアルデザインが浸透してきた現在でこそ,Vuetifyも最近使われてきている.VuetifyはVue.jsで使われるマテリアルデザインをベースとしたCSSのフレームワークである.ちなみに,同様のものとしてVue Materialもあるようだが,どうやらVuetifyの方がドキュメントの見やすさの点で優れている様子.
まとめ
どうやら,マテリアルデザインが主流となってきている現状,どうやらVuetifyの方がよく使われるそうである.
引き続きそれぞれの利点や実際に使って見た感想などを見ていきたいところである.
- 投稿日:2019-02-26T00:09:44+09:00
TruffleでDappを作る + VueとTypeScript
自分の備忘録としてDappの作り方の手順をまとめてみました。
最近やり始めたので間違いもあるかもしれません。ご承知ください。環境構築
solidityのインストール
$ brew install soliditytruffleのインストールとプロジェクトの作成
$ npm install -g truffle $ mkdir project && cd project $ truffle init $ vue create front
vue create
時にtypescriptを選択します。*****現状の環境*****
$ node -v v11.9.0 $ npm -v 6.5.0 $ vue -V 3.3.0 $ solc --version solc, the solidity compiler commandline interface Version: 0.5.3+commit.10d17f24.Darwin.appleclang $ truffle version Truffle v5.0.3 (core: 5.0.3) Solidity v0.5.0 (solc-js) Node v11.9.0* macOS Mojave version10.14
truffleプロジェクトの構造
上記に従ってプロジェクトの作成を行うと、以下のような構造を持つディレクトリが作られます。
-----contracts |---migrations |---test |---truffle-config.js |---frontディレクトリの構造を理解するために、Dapp開発の流れを説明します。
Dapp開発の手順
- contractディレクトリにsolファイルを作成してコントラクトコードを書く。
- migrationディレクトリにデプロイのためのjsファイルを作成。
- testディレクトリにコントラクトコードをテストするファイルを作成。
- ganacheの導入
- terminalでtruffle migrateを行い、プライベートチェーン上にコントラクトをデプロイ
- フロント側でweb3.jsの設定を行う
- metamaskの導入
- 動作確認
contractディレクトリにsolファイルを作成してコントラクトコードを書く。
solファイルはsolidityで書かれたファイルのことです。このファイルにコントラクトを書き込んでいきます。
コントラクトはブロックチェーンのネットワーク上で利用できるアカウントであり、このコントラクト上で実行されるコードをコントラクトコードと呼びます。
ここではブロックチェーンに関する解説は省きますが、ブロックチェーンのネットワークには送金などを行うアカウントとコードとして実行されるアカウントが存在し、Dappでは後者を利用しています。// Dogs.sol pragma solidity ^0.5.0; contract Dogs { // 犬のインスタンスを作っていきます struct Dog { uint id; string name; } // mappingはいわゆる連想配列のこと。ここではuint(id)をDogインスタンスに割り当てている。 mapping(uint => Dogs) public dogs; // Dogインスタンスを格納 uint public dogsCount; // インスタンス作成時のidとして利用(毎インスタンス生成時に+1していく) constructor() public { // 初期インスタンス生成 createProgress("pochi"); } function createProgress(string memory _name) private { dogsCount++; dogs[dogsCount] = Dog(dogsCount, _name); } }migrationディレクトリにデプロイのためのjsファイルを作成。
migrationディレクトリには、deployのためのファイルを作成します。
// migration/2_deploy_contract.js let Dogs = artifacts.require("./Dogs.sol"); module.exports = function(deployer) { deployer.deploy(Dogs); };上記のようにファイルを作成し、以下のコマンドを実行すると、contractsディレクトリに作成されたコントラクトをブロックチェーン上にデプロイします。
$ truffle migrate
また、今後開発を行なっていく上で、一度デプロイしたコントラクトコードを修正したいと思うことがあると思います。
その時は以下のコマンドを実行して新しいコントラクトコードでデプロイし直します。$ truffle migrate --resetrailsをやったことがある人であれば、db:migrate:resetと同じような感じで考えていただければ良いと思います。
testディレクトリにコントラクトコードをテストするファイルを作成。
migrate --resetでやり直せるにしても、ブロックチェーンにデプロイされたものは修正が効かず、それゆえに改竄不可能性を持つわけですが、そうなるとバグや予想しない動作を含むものをデプロイするわけにはいきません。
こういった不具合を未然に防ぐためにもコントラクトコードのテストを行う方が良いです。
テストはsolidityでもjavascriptでも書くことができます。// 飽くまで例です // jsの場合 const Dogs = artifacts.require("./Dogs.sol"); contract("Dogs", function(accounts) { it("initializes with a dog", function() { return Dogs.deployed().then(function(instance) { return instance.dogsCount(); }).then(function(count) { assert.equal(count, 1); // solファイルのconstructorで作成したデフォルトのインスタンス }); }); });ganacheの導入
ganacheはプライベートチェーン上に自動的に模擬アカウントを作成してくれるツールです。
以下のリンクからインストールできます。
https://truffleframework.com/ganacheganacheを起動させてからコントラクトコードをプライベートチェーンにデプロイしてあげると、ganacheで生成されたアカウントがマイニングを行なってくれるので、すぐにコントラクトコードを実行できるようになります。
terminalでtruffle migrateを行い、プライベートチェーン上にコントラクトをデプロイ
ganacheを起動させた状態で、且つ、contractsディレクトリにsolidityファイル、migrationsディレクトリにdeploy用のjsファイル(testのファイルはここでの動作に影響はありませんが、soldityファイルにエラーがあればデプロイができなくなります)があることを確認してください。
その上で次のコマンドを実行してください。$ truffle migrate 1_initial_migration.js ====================== Replacing 'Migrations' ---------------------- > transaction hash: 0xc3006c7464bb1e931d818226170e743976ca068ce15c92c0ad074f6a2685f71c > Blocks: 0 Seconds: 0 > contract address: 0x8bBDf86104324ff2bA12d34F4D9D38eEe9e83748 > account: 0x0f85Ddf6555a85e7bfb107faD34Fc13DF63475A4 > balance: 99.92727632 > gas used: 284908 > gas price: 20 gwei > value sent: 0 ETH > total cost: 0.00569816 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.00569816 ETH 2_deploy_contract.js ==================== Replacing 'Dogs' ------------------ > transaction hash: 0xb2e38fc03105dc5089418a24ede9f54559ca78264ce2ab9753f521e2338ee50f > Blocks: 0 Seconds: 0 > contract address: 0x1EEB22378Ae20b4c18179E46F9C89D11B1f8Aa57 > account: 0x0f85Ddf6555a85e7bfb107faD34Fc13DF63475A4 > balance: 99.90698292 > gas used: 972636 > gas price: 20 gwei > value sent: 0 ETH > total cost: 0.01945272 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.01945272 ETH Summary ======= > Total deployments: 2 > Final cost: 0.02515088 ETHデプロイができれば上記のようになります。
他の方法でデプロイができていることを確認するには、
$ truffle console
でtruffleのコンソールに入って、以下のようにコントラクトコードを実行してみることができます。
$ truffle console truffle(ganache)> Dogs.deployed().then(function(dogs) { app = dogs }) undefined truffle(ganache)> app.dogs(1).then(function(d) { dog = d }) undefined truggle(ganache)> dog[1] 'pochi'
Dogs.deployed().then(function(dogs) { app = dogs })
の部分で、appにdogsコントラクトを渡し、そのappを使って、app.dogs(1)
のように、コントラクトコード上に定義したmappingにidを渡して該当のインスタンスを抜き出します。
最後にdog = d
の部分で抜き出したインスタンスを変数に格納し、最後にそれの[1]番目の要素、つまりnameを参照しています。このように名前を参照することができればデプロイできている証拠です。
次にフロント側の設定を行なっていきます。フロント側でweb3.jsの設定を行う
それでは今度はフロント側を実装していきます。
ここではvue.jsとtypescriptを使っていきます。まず、vue createでプロジェクトを作成してください。
作成時にtypescriptを利用する選択を行なってください。
cssもcssプリプロセッサを使うことで楽に記述できるようになるのでおすすめです。$ vue create frontend
プロジェクトが作成されれば、中に入ってweb3とtruffle-contractのモジュールをインストールします。
$ npm install --save-dev web3@1.0.0-beta.37 truffle-contractここではweb3のバージョンを指定していますが、私の環境ではweb3だけでnpm installすると、このあと紹介するmetamaskというツールを利用した時にエラーが発生したので、これはその対処として行なっています。
vueとtypescriptの説明は行わないので、コンポーネントのファイルに書くブロックチェーンとやりとりするためのコードを解説します。
el-系のinputタグやbuttonタグはelementUIをインストールすると利用できるようになります。非常に使いやすいのでお勧めです。
https://element.eleme.io/#/en-US*templateにはpugを利用しています。
npm install --save-dev pug pug-plain-loader
で使えます。<template lang="pug"> #Contract .list(v-for="dog in dogs") p {{ dog.name }} .form el-input(v-model="name") el-button(@click="createDog") 作成 </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator' import Web3 from 'web3' import TruffleContract from 'truffle-contract' import artifacts from '../../../build/contracts/Dogs.json' // デプロイするとbuild/contracts配下に作成されます。 import $ from 'jquery' const Dogs = TruffleContract(artifacts) @Component({ components: { Dogs } }) export default class ProgressChainIndex extends Vue { private ownAddress: string = "" private name: string = "" private dogs: Array<object> = [] created() { if (typeof web3 !== 'undefined') { web3 = new Web3(web3.currentProvider) } else { console.warn('No web3 detected.') web3 = new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:7545')) } Dogs.setProvider(web3.currentProvider) web3.eth.getCoinbase().then((account) => { this.ownerAddress = account Dogs.defaults({ from: account }) }); } beforeMount() { // ここでブロックチェーン上に記録されたデータを取得して画面上に表示する let dogsInstance let self = this Dogs.deployed().then(function(instance) { dogsInstance = instance return dogsInstance.dogsCount() }).then(function(dogsCount) { for (let i = 1; i <= progressId; i++) { // ブロックチェーン上のdogインスタンスを一つ一つ拾ってきて、そのidとnameをまとめたオブジェクトを作成、配列dogsに格納する dogsInstance.progresses(i).then(function(dog) { self.dogs.push({ id: dog[0], name: dog[1] }) }) } }).catch(function(err) { console.warn(err) }) } createDog() { // ブロックチェーンのコントラクトコードにインスタンスを記録 let self = this Dogs.deployed().then(function(instance) { return instance.createProgress( self.name, { from: self.ownerAddress }) }).catch(function(err) { console.error(err) }) } } </script>このコンポーネントを好きなように親コンポーネントに組み込んであげてください。
metamaskの導入
metamaskはブラウザとブロックチェーンを繋げるツールです。
このツールが実行されていれば、先ほどのコード上でweb3を認識することができます。
https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn?hl=jaアプリケーションの実行
上記のようにコードを作成し、vueのディレクトリで
npm run serve
を行います。
localhost:8080を開き、コンポーネントで配置したinputにdogの名前を入力して、作成ボタンを押します。
すると、ブロックチェーンへのアクセスを承認するか拒否するかの選択が表示されるので、承認ボタンを押しましょう。
承認後、作成したインスタンスをブラウザ上に反映させるためには一度リロードを行う必要があります。また、ここでエラーが発生するようであれば、コードに何らかの原因があるか、ganacheやmetamaskの問題が考えられます。
ganacheの再起動やmetamaskでアカウントのリセットを行うと改善されることがあるので、その辺を確認してみましょう。以下の動画は非常に参考になります。実際に動かしながら説明しているのでこのページを読むより楽かもしれません。
https://www.youtube.com/watch?v=3681ZYbDSSk