- 投稿日:2019-12-22T23:59:17+09:00
Vuexの状態定義を抽出してやる!
なぜ?
SPAで開発してると状態管理が大変になり、参照したい状態がどこにあるか探すのが大変。
そこで、状態のみを抽出して構造化したら全体像を把握できて探すのが楽になるのでは?
と思いやってみます。どうやって?
AST(Abstract Structure Tree)を使って、静的構文解析をして状態を抽出します。
とりあえず、モジュールは考えないでやってみる。環境
- Node.js(v10.15.3)
- babylon(6.18.0)
- @babel/traverse(7.4.3)
想定するファイルと構成
store/index.jsimport Vue from 'vue'; import Vuex form 'vuex'; Vue.use(Vuex); const store = new Vuex.Store({ state: { account: {} }, getters: {}, mutations: {}, actions: {} });期待する出力
state.json{ 'root': { 'account': {} } }状態を抽出するコード
extract-state.jsconst fs = require('fs') const babylon = require('babylon') const traverse = require('@babel/traverse').default const IsParentState = Symbol('IsParentState') const ast = babylon.parse(fs.readFileSync('./store/index.js', 'utf8'), {sourceType: 'module'}) const state = { 'root': {} } const visitor = { ObjectExpression: { enter(nodePath) { // 親ノードがオブジェクトのプロパティかつ、キーがstate if (nodePath.parent.type === 'ObjectProperty' && nodePath.parent.key.name === 'state') { nodePath[IsParentState] = true } }, exit(nodePath) { // state(Vuex)キーのvalueを評価して、出力用のstate.rootのvalueとする if (nodePath[IsParentState]) { const { value } = nodePath.evaluate() Object.assign(state.root, value) } } } } traverse(ast, visitor) console.log(state)実行
node extract-state.js結果
{ root: { account: {} } }store/index.jsimport Vue from 'vue'; import Vuex form 'vuex'; Vue.use(Vuex); const store = new Vuex.Store({ state: { account: {}, isSignIn: false }, getters: {}, mutations: {}, actions: {} });で実行すると、
{ root: { account: {}, isSignIn: false } }となる。
今後の課題
- stateがショートハンドで初期化されてる場合、抽出できない
- stateキーがあるオブジェクトすべてを対象としてしまってるので正しく抽出できない場合がある
- モジュールの状態が抽出できてない
モジュールの状態が抽出できないと目的達成できないですが、時間切れなので
また別の機会に解決したいと思います。
- 投稿日:2019-12-22T21:57:49+09:00
Vue.jsで帳票印刷したい
Vue.jsを利用したWebシステムで帳票印刷する必要がありました。
方法がいくつかあり、検討した知見を紹介します。背景
- フロントはVue.jsを利用したSPA
- 指定条件を入力しビジネスの統計情報を画面表示する
- 集計、グラフを伴う
- 統計画面上の「印刷」ボタンを押下すると帳票印刷 or PDFダウンロードする
- ビジネスレポートは複数ページに渡る
- 数値の集計表、グラフなどを伴う
- ヘッダ/フッタなどの体裁はこだわらない
また、画面ページ上の統計情報と印刷ページ上の統計情報は同じ情報であり、
開発コスト低減のために可能であれば、集計表、グラフなどの画面表示用コンポーネントを流用して帳票をレイアウトしたい状況です。方式検討
実現方式は以下のように複数考えられますが、
最終的には「ブラウザの印刷機能でPDF保存」させる方法を採用しました。
- サーバサイドでPDFファイルを生成
- テンプレートPDFを元に差し込み
- PDF生成エンジンを利用
- 独自レイアウト方式型
- HTML+CSSでレイアウト型
- headlessブラウザのレンダリング/印刷機能を利用
- クライアントサイドでPDFファイルを生成
- PDFファイルを生成するJSライブラリ利用
- 独自レイアウト型
- HTML+CSSでレイアウト型
- Domを元にCanvas化し、Canvas画像をPDFに貼り付ける
- クライアントサイドでブラウザの印刷機能でPDF保存 ←採用
- レイアウトはHTML+CSS
- Mediaクエリで印刷用CSS定義
以下、検討の際に考慮した観点について補足します。
定形雛形に差し込み vs ページ記述
例えば、「領収書印刷」などの用途のような、以下の条件のようなものは
- 1枚ペラもの
- 定型フォーマット
- 所定の位置に 宛名、金額 が記載できればOK
定形のテンプレートPDFを作成しておき、宛名、金額など一部のテキストに必要な値を差し込む方式が適していると言えます。
本要件は比較的ボリュームの多いビジネスレポートであり、以下のような特性があるため、テンプレート形式を取りにくいと考えました。
- ページ数は不定
- 長文は改ページして複数ページをまたぐ
- グラフ、表が含まれる
レイアウト方式
独自方式
このとき、どのようにレイアウトをPDF化するか、という問題がありますが、
PDF生成エンジン・ライブラリによっては、独自のレイアウト指定が必要なものがあります。以下はPDF生成ライブラリpdfkit の例です。
テキストだけなら良いですが、表やグラフをこれで描画するのは骨が折れそうです。pdfkitの例const PDFDocument = require('pdfkit'); // Create a document const doc = new PDFDocument; // Pipe its output somewhere, like to a file or HTTP response // See below for browser usage doc.pipe(fs.createWriteStream('output.pdf')); // Embed a font, set the font size, and render some text doc.font('fonts/PalatinoBold.ttf') .fontSize(25) .text('Some text with an embedded font!', 100, 100); // Add an image, constrain it to a given size, and center it vertically and horizontally doc.image('path/to/image.png', { fit: [250, 300], align: 'center', valign: 'center' });HTMLでレイアウト
独自レイアウト方法が大変なので、
慣れたHTML+CSSでレイアウト指定が可能なものがありますが、
カスタムCSSが利用しづらいなどの注意点ががあるようです。ブラウザの印刷機能でPDFレンダリング
ChromeやFirefox, Safariなど人気のあるモダンブラウザでは
印刷機能でPDFとして保存する機能を備えており、
そのレンダリング性能も信頼できると言って良いでしょう。Mediaクエリを利用して印刷用CSSを定義し、
印刷する際のコンテンツサイズ指定、不要な画面サイドのナビやボタン類を非表示にするなどの制御が可能です。フォント
PDF生成エンジン/ライブラリによってはデフォルトで日本語フォントを扱えないものが多いようです。
pdfkit, pdfmake(内部でpdfkitを利用)などはフォント埋め込みのための事前処理や設定が必要なようです。特に、クライアントサイドでPDFを生成する場合は埋め込み用フォントを事前生成するという方法以外に、
Domとして日本語表示したイメージをあえて画像化してPDFに埋め込む、という方法もあります。日本語コンテンツのボリュームによっては、多くの画像が埋め込まれるため、(フォント埋め込みの場合よりも)PDFのサイズは大きくなるかもしれません。
改ページ
複数ページにまたがるPDFの場合は改ページ位置を制御したいかもしれません。
PDF生成エンジン、ライブラリを利用する場合は、そのエンジンの改ページ制御方法に倣う必要があります。ブラウザの印刷機能でPDFを生成する場合もMediaクエリで改ページの制御が可能です。
一方、フォントの問題のためにコンテンツを画像化してPDFに貼り付けている場合は改ページ制御が煩わしいかもしれません。
その他のデザイン・体裁のコントロール
特に、ブラウザの印刷機能を利用してPDFファイルを作成する場合、
クライアントユーザの設定によって生成されるPDFが異なるため、
デザイン・体裁的にコントロール、画一化することは難しいのが現状です。
- 用紙サイズ、向き、マージン
- 背景画像の有無
- ヘッダ・フッタの有無
- URL, ページタイトル, 作成日
主要なモダンブラウザのデフォルトで利用した際に
文章の中身が読めれば良く、ヘッダ・フッタなどにはこだわらなくて良い、
という今回の要件では許容できると判断しました。処理の負荷 (サーバサイド/クライアントサイド)
不特定多数のユーザが利用するシステムであり、
サーバ負荷を抑えたいため、可能であればクライアント側でPDFを生成したいと考えました。デバッグのしやすさ
ブラウザの印刷機能を利用する場合は、デバッグの際に、印刷用CSSと画面表示用CSSを合わせて置けばレイアウト確認は楽々ですね。
ブラウザのデベロッパーツールも活用できるので、ルーラを表示したり、画面を見ながら微調整を試すことも容易です。PDF生成エンジン/ライブラリの場合はデバッグは大変かも。
Vue.js での実装例
<template> <div class="sheets"> <div> <el-button type="primary" @click="handlePrint">印刷</el-button> ※PDFで保存したい場合は印刷ダイアログで「PDF保存」を指定してください </div> <div class="sheet"> <h2>帳票サンプル</h2> <h3>テーブルを印刷する</h3> <el-table :data="list" border fit> <el-table-column label="ID" prop="id" align="center" width="80px"> <template slot-scope="scope"> <span>{{ scope.row.id }}</span> </template> </el-table-column> <el-table-column label="Title" min-width="150px"> <template slot-scope="{row}"> <span>{{ row.title }}</span> </template> </el-table-column> <el-table-column label="Author" width="110px" align="center"> <template slot-scope="scope"> <span>{{ scope.row.author }}</span> </template> </el-table-column> </el-table> </div> <div class="sheet"> <h3>改ページのテスト</h3> 2ページ目 </div> </div> </template> <script> export default { data() { return { list: null } }, created() { this.getList() }, mounted() { this.fetchData() }, methods: { getList() { // APIからデータ取得する想定 this.list = [ { id: 1, author: 'John Due', title: 'Hello, world' }, { id: 2, author: '太郎', title: 'あいうえお かきくけこ' } ] }, fetchData() { document.title = 'タイトルをいい感じに設定する' setTimeout(() => { this.$nextTick(() => { this.handlePrint() }) }) }, handlePrint() { window.print() } } } </script> <style lang="scss" scoped> .sheet { page-break-after: always; } /* hide in print */ @media print { .sheets > :not(.sheet) { display: none; } } /* for preview */ @media screen { /* mm単位で指定しているけど、vueコンポ側はpx単位なので、無理にmmにしなくてもいいかも。解像度の違いでハマるかも */ .sheet { width: 200mm; min-height: 296mm; /* 設定しなくてもいいかも。あまり印刷画面に似せすぎると、些細な違いがバグに見えてしまう */ margin: 5mm; padding: 5mm; background: white; box-shadow: 0 .5mm 2mm rgba(0,0,0,.3); } } </style> <style lang="scss"> /* for preview */ @media screen { BODY { background: #eee; } } </style>Vueで実装した帳票プレビュー画面
Webシステムで帳票印刷機能を実行すると、プレビュー画面を表示するようにしています。
画面上部にある「印刷」ボタンは、メディアクエリにて画面表示の場合のみボタン表示して、印刷時には非表示にしています。あえて、印刷プレビューっぽく見えるようにグレー背景、縦ページ、ドロップシャドウなどを設定していますが、ブラウザの印刷ダイアログでもプレビュー表示されるので、無くて良いかも。
ブラウザの印刷ダイアログ
Chromeの印刷ダイアログの例。
デフォルトではWebページタイトルがPDFファイル名になるので、印刷直前にWebページタイトルを切り替えるように実装しておきます。
参考
- 投稿日:2019-12-22T21:57:49+09:00
Javascriptで帳票印刷したい
Vue.jsを利用したWebシステムで帳票印刷する必要がありました。
方法がいくつかあり、検討した知見を紹介します。背景
- フロントはVue.jsを利用したSPA
- 指定条件を入力しビジネスの統計情報を画面表示する
- 集計、グラフを伴う
- 統計画面上の「印刷」ボタンを押下すると帳票印刷 or PDFダウンロードする
- ビジネスレポートは複数ページに渡る
- 数値の集計表、グラフなどを伴う
- ヘッダ/フッタなどの体裁はこだわらない
また、画面ページ上の統計情報と印刷ページ上の統計情報は同じ情報であり、
開発コスト低減のために可能であれば、集計表、グラフなどの画面表示用コンポーネントを流用して帳票をレイアウトしたい状況です。方式検討
実現方式は以下のように複数考えられますが、
最終的には「ブラウザの印刷機能でPDF保存」させる方法を採用しました。
- サーバサイドでPDFファイルを生成
- テンプレートPDFを元に差し込み
- PDF生成エンジンを利用
- 独自レイアウト方式型
- HTML+CSSでレイアウト型
- headlessブラウザのレンダリング/印刷機能を利用
- クライアントサイドでPDFファイルを生成
- PDFファイルを生成するJSライブラリ利用
- 独自レイアウト型
- HTML+CSSでレイアウト型
- Domを元にCanvas化し、Canvas画像をPDFに貼り付ける
- クライアントサイドでブラウザの印刷機能でPDF保存 ←採用
- レイアウトはHTML+CSS
- Mediaクエリで印刷用CSS定義
以下、検討の際に考慮した観点について補足します。
定形雛形に差し込み vs ページ記述
例えば、「領収書印刷」などの用途のような、以下の条件のようなものは
- 1枚ペラもの
- 定型フォーマット
- 所定の位置に 宛名、金額 が記載できればOK
定形のテンプレートPDFを作成しておき、宛名、金額など一部のテキストに必要な値を差し込む方式が適していると言えます。
本要件は比較的ボリュームの多いビジネスレポートであり、以下のような特性があるため、テンプレート形式を取りにくいと考えました。
- ページ数は不定
- 長文は改ページして複数ページをまたぐ
- グラフ、表が含まれる
レイアウト方式
独自方式
このとき、どのようにレイアウトをPDF化するか、という問題がありますが、
PDF生成エンジン・ライブラリによっては、独自のレイアウト指定が必要なものがあります。以下はPDF生成ライブラリpdfkit の例です。
テキストだけなら良いですが、表やグラフをこれで描画するのは骨が折れそうです。pdfkitの例const PDFDocument = require('pdfkit'); // Create a document const doc = new PDFDocument; // Pipe its output somewhere, like to a file or HTTP response // See below for browser usage doc.pipe(fs.createWriteStream('output.pdf')); // Embed a font, set the font size, and render some text doc.font('fonts/PalatinoBold.ttf') .fontSize(25) .text('Some text with an embedded font!', 100, 100); // Add an image, constrain it to a given size, and center it vertically and horizontally doc.image('path/to/image.png', { fit: [250, 300], align: 'center', valign: 'center' });HTMLでレイアウト
独自レイアウト方法が大変なので、
慣れたHTML+CSSでレイアウト指定が可能なものがありますが、
カスタムCSSが利用しづらいなどの注意点ががあるようです。ブラウザの印刷機能でPDFレンダリング
ChromeやFirefox, Safariなど人気のあるモダンブラウザでは
印刷機能でPDFとして保存する機能を備えており、
そのレンダリング性能も信頼できると言って良いでしょう。Mediaクエリを利用して印刷用CSSを定義し、
印刷する際のコンテンツサイズ指定、不要な画面サイドのナビやボタン類を非表示にするなどの制御が可能です。フォント
PDF生成エンジン/ライブラリによってはデフォルトで日本語フォントを扱えないものが多いようです。
pdfkit, pdfmake(内部でpdfkitを利用)などはフォント埋め込みのための事前処理や設定が必要なようです。特に、クライアントサイドでPDFを生成する場合は埋め込み用フォントを事前生成するという方法以外に、
Domとして日本語表示したイメージをあえて画像化してPDFに埋め込む、という方法もあります。日本語コンテンツのボリュームによっては、多くの画像が埋め込まれるため、(フォント埋め込みの場合よりも)PDFのサイズは大きくなるかもしれません。
改ページ
複数ページにまたがるPDFの場合は改ページ位置を制御したいかもしれません。
PDF生成エンジン、ライブラリを利用する場合は、そのエンジンの改ページ制御方法に倣う必要があります。ブラウザの印刷機能でPDFを生成する場合もMediaクエリで改ページの制御が可能です。
一方、フォントの問題のためにコンテンツを画像化してPDFに貼り付けている場合は改ページ制御が煩わしいかもしれません。
その他のデザイン・体裁のコントロール
特に、ブラウザの印刷機能を利用してPDFファイルを作成する場合、
クライアントユーザの設定によって生成されるPDFが異なるため、
デザイン・体裁的にコントロール、画一化することは難しいのが現状です。
- 用紙サイズ、向き、マージン
- 背景画像の有無
- ヘッダ・フッタの有無
- URL, ページタイトル, 作成日
主要なモダンブラウザのデフォルトで利用した際に
文章の中身が読めれば良く、ヘッダ・フッタなどにはこだわらなくて良い、
という今回の要件では許容できると判断しました。処理の負荷 (サーバサイド/クライアントサイド)
不特定多数のユーザが利用するシステムであり、
サーバ負荷を抑えたいため、可能であればクライアント側でPDFを生成したいと考えました。デバッグのしやすさ
ブラウザの印刷機能を利用する場合は、デバッグの際に、印刷用CSSと画面表示用CSSを合わせて置けばレイアウト確認は楽々ですね。
ブラウザのデベロッパーツールも活用できるので、ルーラを表示したり、画面を見ながら微調整を試すことも容易です。PDF生成エンジン/ライブラリの場合はデバッグは大変かも。
Vue.js での実装例
<template> <div class="sheets"> <div> <el-button type="primary" @click="handlePrint">印刷</el-button> ※PDFで保存したい場合は印刷ダイアログで「PDF保存」を指定してください </div> <div class="sheet"> <h2>帳票サンプル</h2> <h3>テーブルを印刷する</h3> <el-table :data="list" border fit> <el-table-column label="ID" prop="id" align="center" width="80px"> <template slot-scope="scope"> <span>{{ scope.row.id }}</span> </template> </el-table-column> <el-table-column label="Title" min-width="150px"> <template slot-scope="{row}"> <span>{{ row.title }}</span> </template> </el-table-column> <el-table-column label="Author" width="110px" align="center"> <template slot-scope="scope"> <span>{{ scope.row.author }}</span> </template> </el-table-column> </el-table> </div> <div class="sheet"> <h3>改ページのテスト</h3> 2ページ目 </div> </div> </template> <script> export default { data() { return { list: null } }, created() { this.getList() }, mounted() { this.fetchData() }, methods: { getList() { // APIからデータ取得する想定 this.list = [ { id: 1, author: 'John Due', title: 'Hello, world' }, { id: 2, author: '太郎', title: 'あいうえお かきくけこ' } ] }, fetchData() { document.title = 'タイトルをいい感じに設定する' setTimeout(() => { this.$nextTick(() => { this.handlePrint() }) }) }, handlePrint() { window.print() } } } </script> <style lang="scss" scoped> .sheet { page-break-after: always; } /* hide in print */ @media print { .sheets > :not(.sheet) { display: none; } } /* for preview */ @media screen { /* mm単位で指定しているけど、vueコンポ側はpx単位なので、無理にmmにしなくてもいいかも。解像度の違いでハマるかも */ .sheet { width: 200mm; min-height: 296mm; /* 設定しなくてもいいかも。あまり印刷画面に似せすぎると、些細な違いがバグに見えてしまう */ margin: 5mm; padding: 5mm; background: white; box-shadow: 0 .5mm 2mm rgba(0,0,0,.3); } } </style> <style lang="scss"> /* for preview */ @media screen { BODY { background: #eee; } } </style>Vueで実装した帳票プレビュー画面
Webシステムで帳票印刷機能を実行すると、プレビュー画面を表示するようにしています。
画面上部にある「印刷」ボタンは、メディアクエリにて画面表示の場合のみボタン表示して、印刷時には非表示にしています。あえて、印刷プレビューっぽく見えるようにグレー背景、縦ページ、ドロップシャドウなどを設定していますが、ブラウザの印刷ダイアログでもプレビュー表示されるので、無くて良いかも。
ブラウザの印刷ダイアログ
Chromeの印刷ダイアログの例。
デフォルトではWebページタイトルがPDFファイル名になるので、印刷直前にWebページタイトルを切り替えるように実装しておきます。
参考
- 投稿日:2019-12-22T19:14:15+09:00
Vue x Bootstrap Vue x Netlifyでさくっと作るTrello風アプリ
はじめに
こんにちは!
Mikatus株式会社でインフラエンジニアっぽいようなことをしている福田です。
最近フロントエンド領域に興味があり、デザインやJavaScriptの勉強をしています。
インフラネタにしようか迷ったのですが、今回はjavaScriptだけで動く簡単なアプリを作ってみました。開発経緯
今や知らない人は少ないかもしれませんが、Trelloというのはタスク管理ウェブアプリケーションです。
https://trello.com/home私は業務タスクだけでなく、家事タスクもTrelloを使って管理しています。
私はTrelloにおいて、タスクがドラックアンドドロップで移動できる部分が好きなので、この部分を自分で実装してみたいと思ったのが今回Trello風アプリを作ろうと思ったきっかけです。
こんなの作った
Trello風アプリ
はい、名前の通りTrelloっぽいアプリです。
機能としては以下。
- リストを作成できる
- リストの中にタスクを作成できる
- タスクをドラッグアンドドロップで移動できる
コード
https://github.com/pistachiyoda/practice-trello-like-app使用技術
- Vue.js
- Vue.Draggable
- Bootstrap Vue
- Netlify
致命的なバグ(実装間に合わんかった)
- リストの移動ができない
- リストの削除ができない
- タスクの削除もできない
- ブラウザをリロードしたら作ったリスト・タスクは消える
- 背景をサンタクロースから変更できない
- 空欄でもリスト・タスクが作成できちゃう(フォームバリデーション実装してない)
などなど…
目標だったドラッグアンドドロップでのタスク移動の部分は実装できた(といってもライブラリを使ってしまったので、実装できたと言っていいのかという葛藤…)のですが、細かいと部分はもっと詰めていかないといけません。
ちょっとずつ修正したり機能追加してみようと思います。振り返り
実際に動くものを作るのは楽しいし勉強になりますね。
flexboxやgrid systemについて復習するいい機会になりました。アプリのデプロイが終わった後の満足感にやられて記事の執筆に全く身が入らなかったため、アウトプット前提のアプリを開発する場合は開発と執筆を並行して実施したほうがいいなと思いました。
- 投稿日:2019-12-22T18:18:10+09:00
v-modelの使い方と双方向データバインディング
フォーム入力バインディング
フォーム(
input要素
,select要素
,textarea要素
など)の入力値 / 選択値をvueインスタンス
のdataを同期させる 「双方向データバインディング」を行うにはv-model
ディレクティブを使用する。index.html<div id="app"> <input v-model="message"> <p>{{ message }}</p> </div>vue.jsnew Vue ({ el: '#app', data: { message: '' } })
v-modelディレクティブ
は次の2つの処理を一つにまとめています。
(1) データバインディングで、要素のvalue属性(値)を更新するv-bind:value="message"(2) イベントハンドリング(イベントが発生したときに呼び出される処理)で、受け取った値をデータに代入
入力フォームにユーザが入力
↓ inputイベントが発生
this.message = event.target.valueで値を得られる。
messageプロパティの値が変更されます。DOM要素へのデータバインディングと、要素から取得したデータをリアクティブデータに反映させるこの2つの処理を自動化した構文が
v-model
ラジオボタン
ラジオボタンのデフォルトの値の方は文字列
index.html<div> <span>性別:</span> <label> 男性 <input type="radio" value="male" v-model="form.sex"> </label> <label> 女性 <input type="radio" value="female" v-model="form.sex"> </label> <p>性別: {{ getRadioValue }}</p> </div>vue.jsdata: { return { //省略 form: { sex: '', }, } },
value属性
の値がバインディングされるので female / male のどちらかが
data
の中のsex
プロパティへ代入されます。セレクトボックス
index.html<div> <select v-model="form.selected"> <option disabled value="">--選択してください--</option> <option>A</option> <option>B</option> <option>C</option> <option>D</option> </select> </div>【 単数選択 】
vue.jsdata: { return { //省略 form: { selected: '' }, } },【 複数選択 】
vue.jsdata: { return { //省略 form: { selected: [] }, } },チェックボックス
チェックボックスのデフォルト値の値の型は
Boolean
index.html<div> <label> <input type="checkbox" v-model="form.checked"> 20際以上です </label> </div>vue.jsdata: { return { //省略 form: { checked: true }, } },
- 投稿日:2019-12-22T17:56:01+09:00
Vue.jsで入力フォームにバリデーションをつける
はじめに
この記事はVue#2アドベントカレンダーの23日目です?
アドベントカレンダー初参加の@yakumomutsukiです。
当初は「vue-cliを使わなくてもできるvueを使った開発」を考えていたのですが、書いているうちにただのWebpackの説明になってしまったので、実務であるあるなお悩みを書いてみようと思いました。バリデーション + 入力フォーム
フロントエンドの開発において、フォーム周りのバリデーションの設計は比較的悩みどころかなあと思います。zipというプロパティにたいして、watchを使ってバリデーションを張るか、computedを使うか、このあたりは実装者によってさまざまあると思います。
さまざまあるなかでの「私はこう実装した」という一例をご覧ください。
App.vue<template> <div id="app"> <div class="container"> <form> <div class="form-row"> <div class="form-group col-md-6"> <label for="email">メールアドレス(必須)</label> <input id="email" required type="email" class="form-control" :class="formError.email.className" name="email" placeholder="メールアドレスを入力してください" @change="e => update(e)" :value="formState.email" /> <span>{{ formError.email.errorMessage }}</span> </div> <div class="form-group col-md-6"> <label for="password">パスワード(必須)</label> <input id="password" required type="password" class="form-control" :class="formError.password.className" name="password" placeholder="パスワード" @change="e => update(e)" :value="formState.password" /> <span>{{ formError.password.errorMessage }}</span> </div> </div> <div class="form-row"> <div class="form-group col-md-4"> <label for="zip">郵便番号(必須)</label> <input id="zip" required type="text" class="form-control" :class="formError.zip.className" name="zip" placeholder="1000000" maxlen="7" @change="e => update(e)" :value="formState.zip" /> <p>{{ formError.zip.errorMessage }}</p> </div> <div class="form-group col-md-4"> <label for="state">都道府県(必須)</label> <select id="state" class="form-control" :class="formError.state.className" :value="formState.state" @change="e => update(e)" required > <option value="" selected>選択してください</option> <option value="tokyo">東京</option> <option value="osaka">大阪</option> </select> <p>{{ formError.state.errorMessage }}</p> </div> <div class="form-group col-md-4"> <label for="city">市区町村(必須)</label> <input id="city" required type="text" class="form-control" :class="formError.city.className" name="city" placeholder="千代田区" @change="e => update(e)" :value="formState.city" /> <p>{{ formError.city.errorMessage }}</p> </div> </div> <div class="form-group"> <label for="address1">住所1(必須)</label> <input id="address1" required type="text" class="form-control" :class="formError.address1.className" name="address1" placeholder="秋葉原1-1-1" @change="e => update(e)" :value="formState.address1" /> <p>{{ formError.address1.errorMessage }}</p> </div> <div class="form-group"> <label for="address2">住所2</label> <input id="address2" type="text" class="form-control" name="address2" placeholder="秋葉原ビル1F" @change="e => update(e)" :value="formState.address2" /> </div> <button class="btn btn-primary" @click="registration">登録する</button> </form> </div> </div> </template> <script> const errorBase = { errorMessage: "", className: "" }; const patterns = { password: /^(?=.*?[a-zA-Z])(?=.*?\d)[a-zA-Z\d]{8,16}$/, zip: /^[0-9]{7}$/, phoneNumber: /^[0-9]{10,11}$/ }; import isEmail from "validator/lib/isEmail"; import isMatch from "validator/lib/matches"; export default { name: "App", data() { return { formState: { email: "", password: "", zip: "", state: "", city: "", address1: "", address2: "" }, formError: { email: { ...errorBase }, password: { ...errorBase }, zip: { ...errorBase }, state: { ...errorBase }, city: { ...errorBase }, address1: { ...errorBase }, address2: { ...errorBase } } }; }, methods: { /** * 値が更新されたらupdateメソッドが呼ばれる * formStateの値を更新したら、バリデーションを実行 * @param e HTMLElement */ update(e) { const { name, value } = e.target; this.formState[name] = value; this.formError[name] = { ...errorBase }; this.validate(name); }, /** * バリデーションを行います * 未入力チェックが必要な場合は、第2引数にfalseを指定する * @param name * @param allowBlank */ validate(name, allowBlank = true) { const formVal = this.formState[name]; // 未入力チェックをする場合 if (!allowBlank && !formVal) { this.formError[name] = { errorMessage: "未入力です", className: "error" }; return; } // メールアドレス if (name === "email" && formVal && !isEmail(formVal)) { this.formError[name] = { errorMessage: "メールアドレスに誤りがあります", className: "error" }; return; } // パスワード if ( name === "password" && formVal && !isMatch(formVal, patterns.password) ) { this.formError[name] = { errorMessage: "パスワードに誤りがあります", className: "error" }; return; } // 郵便番号 if (name === "zip" && formVal && !isMatch(formVal, patterns.zip)) { this.formError[name] = { errorMessage: "郵便番号に誤りがあります", className: "error" }; } }, /** * 登録処理を行います * バリデーションで引っかかった場合は、登録処理を行えません */ registration() { for (let [key] of Object.entries(this.formState)) { // バリデーションを行わないのはcontinueで抜けておく if (key === "address2") { continue; } // バリデーションを実行 this.validate(key, false); } let isValid = true; for (let [key] of Object.entries(this.formError)) { // エラーメッセージがない場合にはtrueになる isValid = !this.formError[key].errorMessage ? isValid : false; } if (isValid) { window.alert("登録に成功しました"); } else { window.alert("入力不備があります"); } } } }; </script> <style> .error { background-color: #ffecec !important; } </style>お気づきになりましたでしょうか。
このコードはwatchもcomputedも使っておりません。しかし、formStateとfromErrorの各プロパティのキー名を同じにしておくことで、updateメソッドからvalidateメソッドに同じキー名を渡して、バリデーションをかけることができています。update(e) { const { name, value } = e.target; this.formState[name] = value; this.formError[name] = { ...errorBase }; this.validate(name); },引数として受け取ったHTMLElementから、
const { name, value } = e.target;
のように分割代入して、nameとvalueを受け取り、formStateに値を設定、fromErrorの初期化して、もう一度バリデーションという流れになっています。おわりに
書いていて思ったのですが、別にVueじゃなくてJavaScriptのテクニック感集ですね...。v-modelやwatch、computedは使わなくてもバリデーションはできますというお話でした。
明日のアドベントカレンダーは@kacky917さんです!!?
- 投稿日:2019-12-22T17:20:58+09:00
Vue.jsのtemplateの中でURLとかの文字列をフィルタで置き換えする方法
タイトルからすごく直感的に分かりづらいタイトル!
【本記事の目的】
vue.jsの中で、文字列の中の一部をフィルターで変更したい!
(phpでいうところのstr_replace)【前置き】(長いので飛ばしてもokです)
laravelでは画像データを投稿すると、デフォルトでpublicに保管されます。
それを実際に表示させるには画像をシンボリックリンクでstorage側で表示させる事を推奨されています。
参考:https://qiita.com/koru1893/items/1d2f522e20744b03e3adでもそれをlaravel経由のvue.jsで表示させようとするとうまくいかず。
vue.jsの中でimgタグの参照urlをpublic→storage に置き換える
という作業にハマったのでメモです。**publicだと読み込めず、storageだと読み込める状態です。
なお、php(view)でそのデータを読み込むだけなら
str_replaceで画像のurlを変数にして置き換えて、imgタグの読み込み先として指定すれば行けます。//$image_urlがdbから持ってきたurl情報。urlの一部を置き換えるということ。 $image_url = str_replace('public/', 'storage/', $image_url);phpのview内でやる方法で完了しているじゃん!て思うんですが、
vue.jsとか使って非同期でdb上のURL文字列を取ってくる場合、img参照用のURLをjsファイル内で(今回の場合vue.jsん中で)差し替える必要があります。
やっと本題
カスタムフィルタを作りました!
(※vue.jsのフィルタ機能は今は自作しないとダメぽい。vue.1系はフィルタのメソッドあったぽいです。なんで削除されたんだろう?)filtersの中に、
「public」という文字列を「..storage」に置き換える
「replace」という処理を作りました。
(置き換え前、置き換え先のコードはもちろん任意です。)vue.js<script> export default { props:['hoge'], data:function(){ return{ (略) } }, mounted(){ (略) }, filters:{ //カスタムフィルタ。こんな感じ! replace:function(val){ return val.replace("public", "../storage"); } }, } } </script>replaceのフィルタは準備できました。
あとはtemplateの中で、フィルタします!
(※vue.jsの中では {{ フィルタしたいデータ|フィルタの処理名 }} という書き方でフィルタリングできます。マスタッシュ!)vue.js<template> (略) <img :src="image_url | replace('public','../storage')" alt=""> (略) </template>これで、urlのなかの一部を置き換えられます。
公開サイト側でソースをみると、下記のようになります。フィルタなしの結果
<img src="public/post_images/hoge.jpg">フィルタありの結果
<img src="../storage/post_images/hoge.jpg">これできちんと画像が公開サイトで読み込めました。やった!
参考:https://www.itsolutionstuff.com/post/how-to-replace-string-in-vue-jsexample.html
- 投稿日:2019-12-22T17:20:58+09:00
【Laravel】 Vue.jsのtemplateの中で文字列置き換えする方法【フィルタ】
タイトルからすごく直感的に分かりづらいタイトル!
【前置き】
まず、larabelでは投稿した画像はpublicに保管されてしまうんですが
それを実際に表示させるには画像をシンボリックリンクでstorage側で表示させないといけません。
参考:https://qiita.com/koru1893/items/1d2f522e20744b03e3ad
で、本記事でやりたいことは
vue.jsの中でimgタグの参照urlをpublic→storage に置き換える
という作業。php(view)でそのデータを読み込むだけなら
str_replaceで画像のurlを変数にして置き換えて、imgタグの読み込み先として指定すれば行けます。//$image_urlがdbから持ってきたurl情報。urlの一部を置き換えるということ。 $image_url = str_replace('public/', 'storage/', $image_url);
本題
長くなりましたが本題。
vue.jsで文字列置き換え、前述のreplace的なことをやろうとして「フィルタが良さそう!」
となったんですが、いい感じのreplace処理がない!
参考情報調べても少しややこいreplaceばかり出てきたけど、簡単そうな方法がありました。
参考:https://www.itsolutionstuff.com/post/how-to-replace-string-in-vue-jsexample.html調べるのに少し時間かかったので、備忘録を兼ねて。
やろうとしたこと
- コントローラーでDBから取得したデータを
- view に持ってきて、そこからvue.jsに受け渡す。
- vue.js内で受け取ったデータのimage出力するときに、url情報を一部書き換えたい(書き換えたい理由は[前提]参照)
1.2は割愛。この辺りが参考になるかもです!
3でやった方法。
カスタムフィルタで特定のコードをreplaceしたい!
※vue.jsのフィルタ機能は今は自作しないとダメぽい(vue.1系はフィルタのメソッドあったぽいです。なんで削除されたんだろう)filtersの中に、
「public」という文字列を「..storage」に置き換える
「replace」というフィルタを作りました。vue.js<script> export default { props:['hoge'], data:function(){ return{ (略) } }, mounted(){ (略) }, filters:{ //カスタムフィルタ。こんな感じ! replace:function(val){ return val.replace("public", "../storage"); } }, } } </script>replaceのフィルタは準備できました。
あとはtemplateの中で、フィルタします!
vue.jsの中では
{{ フィルタしたいデータ|フィルタの処理名 }}
という書き方でフィルタリングできますvue.js<template> (略) <img :src="image_url | replace('public','../storage')" alt=""> (略) </template>これで、urlのなかの一部を置き換えられます。
公開サイト側でソースをみると、下記のようになります。フィルタなしの結果
<img src="public/post_images/hoge.jpg">フィルタありの結果
<img src="../storage/post_images/hoge.jpg">これできちんと読み込めました。やった!
参考:https://www.itsolutionstuff.com/post/how-to-replace-string-in-vue-jsexample.html
- 投稿日:2019-12-22T17:20:58+09:00
【Laravel】 Vue.jsのtemplateの中でURLとかの文字列置き換えする方法【フィルタ/非同期】
タイトルからすごく直感的に分かりづらいタイトル!
【前置き】
まず、larabelでは投稿した画像はpublicに保管されてしまうんですが
それを実際に表示させるには画像をシンボリックリンクでstorage側で表示させないといけません。
参考:https://qiita.com/koru1893/items/1d2f522e20744b03e3ad
で、本記事でやりたいことは
vue.jsの中でimgタグの参照urlをpublic→storage に置き換える
という作業。php(view)でそのデータを読み込むだけなら
str_replaceで画像のurlを変数にして置き換えて、imgタグの読み込み先として指定すれば行けます。//$image_urlがdbから持ってきたurl情報。urlの一部を置き換えるということ。 $image_url = str_replace('public/', 'storage/', $image_url);phpのview内でやる方法で完了しているじゃん!て思うんですが、
vue.jsで非同期でも取ってくるのをやるのも試そうとして、img参照用のURLを差し替える方法を探すのに時間がかかったのです。
本題
長くなりましたが本題。
vue.jsで文字列置き換え、前述のreplace的なことをやろうとして「フィルタが良さそう!」
となったんですが、いい感じのreplace処理をやるのに簡単そうな方法がありました。
参考:https://www.itsolutionstuff.com/post/how-to-replace-string-in-vue-jsexample.htmlもう少し細かく全体の流れをかくと
- コントローラーでDBから取得したデータを
- view に持ってきて、そこからvue.jsに受け渡す。
- vue.js内で受け取ったデータのimage出力するときに、url情報を一部書き換えたい(書き換えたい理由は[前提]参照)
1.2は割愛。この辺りが参考になるかもです!
で、3でやった方法。
カスタムフィルタで特定のコードをreplaceしました!
(※vue.jsのフィルタ機能は今は自作しないとダメぽい。vue.1系はフィルタのメソッドあったぽいです。なんで削除されたんだろう?)filtersの中に、
「public」という文字列を「..storage」に置き換える
「replace」という処理を作りました。
(置き換え前、置き換え先のコードはもちろん任意です。)vue.js<script> export default { props:['hoge'], data:function(){ return{ (略) } }, mounted(){ (略) }, filters:{ //カスタムフィルタ。こんな感じ! replace:function(val){ return val.replace("public", "../storage"); } }, } } </script>replaceのフィルタは準備できました。
あとはtemplateの中で、フィルタします!
(※vue.jsの中では {{ フィルタしたいデータ|フィルタの処理名 }} という書き方でフィルタリングできます。マスタッシュ)vue.js<template> (略) <img :src="image_url | replace('public','../storage')" alt=""> (略) </template>これで、urlのなかの一部を置き換えられます。
公開サイト側でソースをみると、下記のようになります。フィルタなしの結果
<img src="public/post_images/hoge.jpg">フィルタありの結果
<img src="../storage/post_images/hoge.jpg">これできちんと画像が公開サイトで読み込めました。やった!
参考:https://www.itsolutionstuff.com/post/how-to-replace-string-in-vue-jsexample.html
- 投稿日:2019-12-22T17:07:13+09:00
v-forによる繰り返しの描画
v-for
による繰り返し配列やオブジェクトをループ処理して、
要素を繰り返しを描画するには、v-for
ディレクティブを使用する。index.html// v-for 構文 <li v-for="各要素を代入する変数名 in 繰り返したい配列やオブジェクト">index.html<div id="app"> <ul> <li v-for="item in items" v-bind:key="item.id"> </ul> </div>app.jsnew Vue ({ el: '#app', data: { items: [ { id: 1, title: '1番目のリスト', }, { id: 2, title: '2番目のリスト', }, { id: 3, title: '3番目のリスト', }, ] } })
data
オプションに登録されているitems
の配列から、v-for
ディレクティブを使って1つずつ要素を取り出し描画します。Key の役割
v-bind:key="item.id"
v-forディレクティブ
でループしている要素に対しては、v-bind:key
ディレクティブにその要素として識別情報となる値(一意の値)を指定することが推奨されています。Vueが各要素を効率よく追跡できるようにするため、ということのようです。
:key
はv-bind:key
の省略構文。不変でユニークなキーを設定しよう
要素の削除や並び替えも考慮して「不変でユニークなキー」を設定する必要があります。
ユニークな乱数を生成するuuid
や、vue-uuid
を使用して:keyの値を乱数で指定することができます。(例)「
vue-uuid
」を使用して:key
を指定する際は乱数を値に指定できるようにする場合index.jsimport Vue from 'vue'; import uuid from 'vue-uuid'; // 追加 Vue.use(uuid); // 追加 new Vue({ el: '#app' });
uuidモジュール
をimportして、Vue.use()
の引数に指定することによって
アプリケーションでuuid
を使用できる様にします。app.vue.jsdata() { return { //省略 items: [ { id: this.$uuid.v4(), // バージョン4のUUIDは、乱数により生成される。 title: '1番目のリスト', }, { id: this.$uuid.v4(), title: '2番目のリスト' }, { id: this.$uuid.v4(), title: '3番目のリスト' } ], } }これで
id
には乱数が指定されるようになりました。
- 投稿日:2019-12-22T14:46:41+09:00
【入門】Laravel×Vue.js②〜実装編〜
はじめに
PHPのフレームワークであるLaravelで作成したアプリケーションに
JavaScriptのフレームワークであるVue.jsを連携させる方法について説明します。
簡単な機能を実装します。自分のコンポーネントを登録する方法について説明します
実装する機能
メッセージを表示して、ボタンを押すと、メッセージを反転するコンポーネントの作成
まず、
resources/js/components/
内にHelloComponent.vue
を作成してください
そして、内容を以下のようにしてくださいresources/js/components/HelloComponent.vue<template> <div id="app"> <p>{{ message }}</p> <button v-on:click="reverseMessage">Reverse Message</button> </div> </template> <script> export default { data:function(){ return { message: 'Hello Vue!', }; }, methods: { reverseMessage: function () { this.message = this.message.split('').reverse().join('') } } } </script>コンポーネントの登録
上で作成したコンポーネントを登録しましょう
resource/js/app.jsrequire('./bootstrap'); window.Vue = require('vue'); Vue.component('example-component', require('./components/ExampleComponent.vue').default); Vue.component('hello-component', require('./components/HelloComponent.vue').default);ビューファイルへの組み込み
ビューファイルの追加したい時に下記を記述してください
hello/index.blade.php<div id="app"> <hello-component></hello-component> </div>以上で実装完了です。
疑問、気になるところがございましたら、質問、コメントよろしくお願いします!!!
- 投稿日:2019-12-22T12:13:53+09:00
メソッドに引数を与える ❏Vue.js❏
メソッドの引数に与えた数の倍数分カウントアップしていきます!
開発環境はJSFiddle
https://qiita.com/ITmanbow/items/9ae48d37aa5b847f1b3bhtml<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <div id="app"> <p>{{ number }}</p> <button @click="countUp(3)">カウントアップ</button> </div>javascriptnew Vue({ el: "#app", data: { number: 0 }, methods: { countUp: function(times) { this.number += times; } } })①html側には引数3を与えます。
@click="countUp(3)"
②js側にはtimesとして引数を受け取ります。
countUp: function(times)
③引数分足します
this.number += times;
できあがり!
ではまた!
- 投稿日:2019-12-22T08:22:25+09:00
初心者によるプログラミング学習ログ 191日目
100日チャレンジの191日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
191日目は
おはようございます
— ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) December 21, 2019
191日目
udemyでVue.js
vue.jsでカンタンなtodoリスト作成#100DaysOfCode #早起きチャレンジ#駆け出しエンジニアと繋がりたい
- 投稿日:2019-12-22T05:12:40+09:00
【CGI】Vue.js + axiosでサーバのPythonプログラムを動かし出力データをもらう
はじめに
フロントエンドで全部できるっちゃできるけど、やっぱり計算部分にPythonの楽さは欲しいなあ、という思いからサーバでプログラムを動的に動かすCGIを触ってみたのでそのまとめ。バックエンドは未だ疎い。
フリーレンタルサーバーのXREAのアカウントを持っているので実際にそこで試してみる。
無料から使える高機能・高品質レンタルサーバー | XREA(エクスリア)やりたいことは、
- ボタンをクリック
- Vue.jsとaxiosを使ってデータをサーバに渡す
- Pythonで書かれたCGIスクリプトを実行して演算、結果をJSONで返す
- 同じ画面に返されたデータを表示
というかんじ。
今回は例として入力された2数の最大公約数と最小公倍数を計算して返すプログラムを作る。
作ってみる
ファイルの配置
├─ cgi-bin │ └─ index.cgi ├─ index.html └─ main.jsPythonで書かれたCGIスクリプトは
cgi-bin
というディレクトリを作ってその中に投入。Pythonで書かれてるけど拡張子は.cgi
。サーバにアップロードした後、CGIまわりのパーミッションを指定する必要があるけどそれは後述。
HTML (index.html)
<html> <head> <meta charset="UTF-8"> <title>最大公約数と最小公倍数を返す</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script> <script type="module" src="main.js"></script> </head> <body> <div id="app"> <!-- 入力部分 --> <p> <input v-model="a" type="number" value="12"> <input v-model="b" type="number" value="15"> <button v-on:click="getResult">計算</button> </p> <!-- 表示部分 --> <p> 最大公約数: {{ result['gcd'] }}<br> 最小公倍数: {{ result['lcm'] }} </p> </div> </body> </html>CDNでVue.jsとaxiosを読み込んでおく。
Vueで書いたJavaScriptのファイルはtype="module"
で読み込むと、DOMが読み込まれた後に実行されるので安心。JavaScript (main.js)
var vm = new Vue({ el: '#app', data: { a: 12, b: 15, result: {}, // 返ってきたオブジェクトを格納する変数 }, methods: { getResult: function() { const url = './cgi-bin/'; // axiosでデータの受け渡し axios.get(url, { params: { // paramsでパラメータを指定 a: this.a, b: this.b } }) .then(res => this.result = res.data) // データをresultに格納 } } });Vueインスタンスを作ってaxiosでデータの受け渡しをする。
URLは./cgi-bin/
。index.cgi
という名前ならHTML同様ファイル名を指定しなくてもOKなもよう。また、返ってくるデータ
res.data
はオブジェクトとして取り出せるのでJSON.parse()
とかで直す必要がなかった。(JSONにして返したんだからJSON文字列で返ってくるだろうという思い込みにやられた。)
ちなみにやるとこんなエラーが出る。SyntaxError: Unexpected token o in JSON at position 1
o
ってなんぞやと思ったらobject
のo
らしい...Python CGI (index.cgi)
#!/usr/local/bin/python3 # -*- coding: UTF-8 -*- import cgi import cgitb import math import json cgitb.enable() # CGIのデバッグをオン form = cgi.FieldStorage() # GETで得たデータを格納 a = int(form['a'].value) # データは文字列でやってくるので数値に変換 b = int(form['b'].value) data = { 'gcd': math.gcd(a, b), # math.gcd() は Python 3.5 で追加されたらしい 'lcm': a * b // math.gcd(a, b) } print('Content-Type: application/json') print() print(json.dumps(data)) # json形式にして返す行頭でPythonのインタプリタの場所を指定。レンタルサーバの仕様ページに各言語のCGIの実行パスが書いてあると思うので確認する。XREAだとここ。
Context-Type
指定の行の後のprint()
は改行のためで、これを入れないとダメな仕様みたい。 普通にContext-Type
文字列の最後に\n
してもOK。アップロード後はCGIスクリプトを入れたディレクトリとそのファイルのパーミッションを指定する必要があり、XREAにも推奨パーミッションが書いてある。
特に、CGIの実行ファイルは700以上(実行可能)にする必要があるのは注意(よく忘れた)。以上のXREAの仕様が書いてあるリンクも貼っておく。
仕様 | 無料から使える高機能・高品質レンタルサーバー | XREA(エクスリア)実行
ファイルを上げて実際に試してみた画面がこちら
いいかんじ。空欄や小数で送信したら普通にエラーになるけど、まあお試しなので。以上。
- 投稿日:2019-12-22T05:12:40+09:00
【CGI】Vue.jsとaxiosを使ってサーバに置いたPythonプログラムを動かしデータを得る
はじめに
フロントエンドで全部できるっちゃできるけど、やっぱりPythonの計算の楽さは欲しいなあと思ってCGIについていろいろ調べたのでそのまとめ。
フリーレンタルサーバーのXREAのアカウントを持っているので実際にそこで試してみます。
無料から使える高機能・高品質レンタルサーバー | XREA(エクスリア)やりたいことは、
- ボタンをクリック
- Vue.jsとaxiosを使ってデータをサーバに渡す
- Pythonで書かれたCGIスクリプトを実行して演算、結果をJSONで返す
- 同じ画面に返されたデータを表示
というかんじ。
今回は例として入力された2数の最大公約数と最小公倍数を計算して返すプログラムを作ります。作ってみる
ファイルの配置
├─ cgi-bin │ └─ index.cgi ├─ index.html └─ main.jsPythonで書かれたCGIスクリプトは
cgi-bin
というディレクトリを作ってその中に投入。Pythonで書かれてるけど拡張子は.cgi
。
サーバにアップロードした後、CGIまわりのパーミッションを指定する必要があるけどそれは後述。HTML
<html> <head> <meta charset="UTF-8"> <title>最大公約数と最小公倍数を返す</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script> <script type="module" src="main.js"></script> </head> <body> <div id="app"> <!-- 入力部分 --> <p> <input v-model="a" type="number" value="12"> <input v-model="b" type="number" value="15"> <button v-on:click="getResult">計算</button> </p> <!-- 表示部分 --> <p> 最大公約数: {{ result['gcd'] }}<br> 最小公倍数: {{ result['lcm'] }} </p> </div> </body> </html>CDNでVue.jsとaxiosを読み込んでおく。
Vueで書いたJavaScriptのファイルはtype="module"
で読み込むと、DOMが読み込まれた後に実行されるので安心。JavaScript
var vm = new Vue({ el: '#app', data: { a: 12, b: 15, result: {}, // 返ってきたオブジェクトを格納する変数 }, methods: { getResult: function() { const url = './cgi-bin/'; // axiosでデータの受け渡し axios.get(url, { params: { // paramsでパラメータを指定 a: this.a, b: this.b } }) .then(res => this.result = res.data) // データをresultに格納 } } });Vueインスタンスを作ってaxiosでデータの受け渡しをする。
URLは./cgi-bin/
。index.cgi
という名前ならHTML同様ファイル名を指定しなくてもOKなよう。
また、返ってくるデータres.data
はオブジェクトとして取り出せるのでJSON.parse()
とかで直す必要がなかった。(JSONにして返したんだからJSON文字列で返ってくるだろうという思い込みにやられた。)
ちなみにやるとこんなエラーが出る。SyntaxError: Unexpected token o in JSON at position 1
o
ってなんぞやと思ったらobject
のo
らしい...Python CGI
#!/usr/local/bin/python3 # -*- coding: UTF-8 -*- import cgi import cgitb import math import json cgitb.enable() # CGIのデバッグをオン form = cgi.FieldStorage() # GETで得たデータを格納 a = int(form['a'].value) # 辞書型で参照が可能 b = int(form['b'].value) # データは文字列でやってくるので数値に変換 data = { 'gcd': math.gcd(a, b), # math.gcd() は Python 3.5 で追加されたらしい 'lcm': a * b // math.gcd(a, b) } print('Content-Type: application/json') print() print(json.dumps(data)) # json形式にして返す行頭でPythonのインタプリタの場所を指定。レンタルサーバの仕様ページに各言語のCGIの実行パスが書いてあると思うので確認する。XREAだとここ。
Context-Type
指定の行の後のprint()
は改行のためで、これを入れないとダメな仕様みたい。 普通にContext-Type
文字列の最後に\n
してもOK。アップロード後はCGIスクリプトを入れたディレクトリとそのファイルのパーミッションを指定する必要があり、XREAにも推奨パーミッションが書いてある。
特に、CGIの実行ファイルは700以上(実行可能)にする必要があるのは注意(よく忘れた)
以上のXREAの仕様が書いてあるリンクも貼っておきます。
仕様 | 無料から使える高機能・高品質レンタルサーバー | XREA(エクスリア)実行
いいかんじ。空欄や小数で送信したら普通にエラーになるけど、まあ試しなので。
以上。
- 投稿日:2019-12-22T05:12:40+09:00
【CGI】Vue.jsとaxiosを使ってサーバのPythonプログラムを動かしデータを得る
はじめに
フロントエンドで全部できるっちゃできるけど、やっぱり計算部分にPythonの楽さは欲しいなあ、という思いからサーバでプログラムを動的に動かすCGIを触ってみたのでそのまとめ。バックエンドは未だ疎い。
フリーレンタルサーバーのXREAのアカウントを持っているので実際にそこで試してみる。
無料から使える高機能・高品質レンタルサーバー | XREA(エクスリア)やりたいことは、
- ボタンをクリック
- Vue.jsとaxiosを使ってデータをサーバに渡す
- Pythonで書かれたCGIスクリプトを実行して演算、結果をJSONで返す
- 同じ画面に返されたデータを表示
というかんじ。
今回は例として入力された2数の最大公約数と最小公倍数を計算して返すプログラムを作る。作ってみる
ファイルの配置
├─ cgi-bin │ └─ index.cgi ├─ index.html └─ main.jsPythonで書かれたCGIスクリプトは
cgi-bin
というディレクトリを作ってその中に投入。Pythonで書かれてるけど拡張子は.cgi
。
サーバにアップロードした後、CGIまわりのパーミッションを指定する必要があるけどそれは後述。HTML (index.html)
<html> <head> <meta charset="UTF-8"> <title>最大公約数と最小公倍数を返す</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script> <script type="module" src="main.js"></script> </head> <body> <div id="app"> <!-- 入力部分 --> <p> <input v-model="a" type="number" value="12"> <input v-model="b" type="number" value="15"> <button v-on:click="getResult">計算</button> </p> <!-- 表示部分 --> <p> 最大公約数: {{ result['gcd'] }}<br> 最小公倍数: {{ result['lcm'] }} </p> </div> </body> </html>CDNでVue.jsとaxiosを読み込んでおく。
Vueで書いたJavaScriptのファイルはtype="module"
で読み込むと、DOMが読み込まれた後に実行されるので安心。JavaScript (main.js)
var vm = new Vue({ el: '#app', data: { a: 12, b: 15, result: {}, // 返ってきたオブジェクトを格納する変数 }, methods: { getResult: function() { const url = './cgi-bin/'; // axiosでデータの受け渡し axios.get(url, { params: { // paramsでパラメータを指定 a: this.a, b: this.b } }) .then(res => this.result = res.data) // データをresultに格納 } } });Vueインスタンスを作ってaxiosでデータの受け渡しをする。
URLは./cgi-bin/
。index.cgi
という名前ならHTML同様ファイル名を指定しなくてもOKなよう。
また、返ってくるデータres.data
はオブジェクトとして取り出せるのでJSON.parse()
とかで直す必要がなかった。(JSONにして返したんだからJSON文字列で返ってくるだろうという思い込みにやられた。)
ちなみにやるとこんなエラーが出る。SyntaxError: Unexpected token o in JSON at position 1
o
ってなんぞやと思ったらobject
のo
らしい...Python CGI (index.cgi)
#!/usr/local/bin/python3 # -*- coding: UTF-8 -*- import cgi import cgitb import math import json cgitb.enable() # CGIのデバッグをオン form = cgi.FieldStorage() # GETで得たデータを格納 a = int(form['a'].value) # データは文字列でやってくるので数値に変換 b = int(form['b'].value) data = { 'gcd': math.gcd(a, b), # math.gcd() は Python 3.5 で追加されたらしい 'lcm': a * b // math.gcd(a, b) } print('Content-Type: application/json') print() print(json.dumps(data)) # json形式にして返す行頭でPythonのインタプリタの場所を指定。レンタルサーバの仕様ページに各言語のCGIの実行パスが書いてあると思うので確認する。XREAだとここ。
Context-Type
指定の行の後のprint()
は改行のためで、これを入れないとダメな仕様みたい。 普通にContext-Type
文字列の最後に\n
してもOK。アップロード後はCGIスクリプトを入れたディレクトリとそのファイルのパーミッションを指定する必要があり、XREAにも推奨パーミッションが書いてある。
特に、CGIの実行ファイルは700以上(実行可能)にする必要があるのは注意(よく忘れた)
以上のXREAの仕様が書いてあるリンクも貼っておく。
仕様 | 無料から使える高機能・高品質レンタルサーバー | XREA(エクスリア)実行
いいかんじ。空欄や小数で送信したら普通にエラーになるけど、まあ試しなので。
以上。
- 投稿日:2019-12-22T04:23:59+09:00
vue-apolloでのsubscriptionの設定方法(リアルタイム同期のChatアプリのサンプル付き)
この記事はVue.js Advent Calendar 23日目の記事です。
リアルタイム更新というとFirebase Firestoreが思い浮かびますが、
実はGraphQLのsubscriptionを使っても手軽に出来ます!
vue-apolloでのsubscriptionの設定についての日本語記事があまりなかったので今回紹介します。サンプルアプリ
「説明いらんから、はよコード」という方は、こちらから。
https://github.com/kawamataryo/hasura-vue-chat-appsubscriptionsの練習用に作ったリアルタイム同期のチャットアプリです。
HasuraでGraphQLサーバーを立てて、vue-apolloでsubscriptionを行っています。
READMEの通り起動すれば数分でhasura, vue-apolloのsubscriptionを体験できます。
(練習用に作ったので優しい目でお願いします。。)Subscriptionとは?
GraphQLでのWebSocketを使ったリアルタイムデータ通信の手段です。
subscriptionsを使うと、更新された内容をページリロードなしにリアルタイムでサーバーから、Webページに直接通知することが出来ます。vue-apolloの設定
では本題のvue-apolloのsubscriptionの設定です。
ポイントは、クエリの種別でhttp通信にするか、websocket通信にするか設定しているところです。
new HttpLink
でhttp、new WebSocketLink
でwebsocketのエンドポイントを設定し、
split
関数で呼ばれるクエリによって向き先を変更しています。import Vue from "vue"; import { ApolloClient } from "apollo-client"; import { HttpLink } from "apollo-link-http"; import { InMemoryCache } from "apollo-cache-inmemory"; import { split } from "apollo-link"; import { WebSocketLink } from "apollo-link-ws"; import { getMainDefinition } from "apollo-utilities"; import VueApollo from "vue-apollo"; // 通常のquery, mutationsで使われるhttp通信のエンドポイントを指定 const httpLink = new HttpLink({ uri: "http://localhost:8000/v1/graphql" // トークンによる認証を追加する場合は以下のように設定 // headers: { // authorization: `Bearer xxxxx` // } }); // subscriptionで使われるwebsocket通信のエンドポイントを指定 const wsLink = new WebSocketLink({ uri: "ws://localhost:8000/v1/graphql", options: { reconnect: true // トークンによる認証を追加する場合は以下のように設定 // headers: { // authorization: `Bearer xxxxx` // } } }); // GraphQLのエンドポイントの向き先をクエリの種別で分離するための設定 // 参考 https://www.apollographql.com/docs/link/composition/#directional-composition const link = split( ({ query }) => { // クエリから種別を取得してsubscriptionの場合は、wsLink(websocket)を利用する。 const definition = getMainDefinition(query); return ( definition.kind === "OperationDefinition" && definition.operation === "subscription" ); }, wsLink, httpLink ); // Apollo Clientの作成 const apolloClient = new ApolloClient({ link, cache: new InMemoryCache(), connectToDevTools: true }); Vue.use(VueApollo); // vue-apolloへの接続 export const apolloProvider = new VueApollo({ defaultClient: apolloClient });subscribeの実行
サンプルアプリのコードをもとに説明します。
通常のvue-apolloのquery内にsubscriptionsToMore
を追加することでそのqueryに紐づくデータをsubscriptionsの結果でリアルタイム更新することが出来ます。
document
にsubscriptionのクエリを設定し、対象のデータに変更がある場合、updateQuery
で設定した関数が呼ばれ、queryに紐づくデータ(この場合はmessages
)が更新されます。export default { data() { return { messages: [] } }, apollo: { messages: { query: gql` query { messages { content userId: user_id iconColor: icon_color id } } `, subscribeToMore: { document: gql` subscription { messages { id userId: user_id iconColor: icon_color content } } `, updateQuery: (previousResult, { subscriptionData }) => { return subscriptionData.data; } } } . . . }終わりに
以上、vue-apolloでのsubscriptionsの設定方法でした。
リアルタイム更新をしようと思うとぱっと思いつくのはFirestoreですが、GraphQLのSubscriptionも手軽でおすすめです。(Hasuraを使えばなおさら)vue-apolloは、上手くApolloをVue.js仕様にラップしていて僅かなコードでGraphQL触れるのでとても良いですね。
参考
https://vue-apollo.netlify.com/guide/apollo/subscriptions.html#setup
https://www.howtographql.com/vue-apollo/8-subscriptions/
- 投稿日:2019-12-22T04:05:41+09:00
初めてのtailwindcss (Vue.js + PurgeCSS)
この記事は
CSS Advent Calendar 2019 21日目の記事です。
気になってたtailwindcssを、Vue.jsでやってみましたという記事です。
リポジトリはこちら→ https://github.com/hisako135/tailwindcss_vue_demo
やったことは以下のような感じです。
- Vue.js でのtailwindcssのセットアップ
- PurgeCSS でのファイル容量の削減
tailwindcssってなんぞ
"Bootstrapをゴリゴリいじってカスタマイズしても良いのだが、そこに時間かけるんならCSSフレームワーク使う利点なくない...?
" などと思ったことがある人はいませんか...?
グリッドシステムとForm周りさえあればよくて、他の必要なコンポーネントは自分で作った方が楽だよな、とかゴニョゴニョ...(小声)そこでtailwindcssです!
Most CSS frameworks do too much.
(ほとんどのCSSフレームワークは多くのことをやり過ぎている)
https://tailwindcss.com/#what-is-tailwind"あらゆる種類のコンポーネントが用意されているCSSフレームワークって初期段階に素早く作るのには確かにとっても便利。でもカスタマイズしようとするとしんどいよね。事前に設計されたコンポーネントの代わりに、低レベルなUtilityクラスを提供することによって、HTMLを離れることなくデザインをカスタマイズできるよ。"
というのがtailwindcssです。ちなみにCSSでのUtilityクラスとは、
.font-small {font-size: 10px;}
や.text-left {text-align: left;}
のように、単一のプロパティを定義した汎用的なクラスを指します。Helperクラスとも呼ばれたり。
FLOCSSではUtilityレイヤーに、FLOCSSのベースとなっているMCSSではCosmeticsレイヤーあたりに記載されるやつです。tailwindcssのUtility-firstの考え方についてはこちらの翻訳記事に詳細書いてありますので是非!
CSS Utility Classes and "Separation of Concerns" 翻訳
セットアップ手順
何はともあれVue.jsでのtailwindcssのセットアップをやっていきましょう。
まずはvue-cliでVue.jsプロジェクトを作成します。以降、tailwindcss/setup-examples を参考に進めます。
- tailwindcssをインストール
npm install tailwindcss
- postcss.config.js ファイルを作成しプラグインとして設定
postcss.config.jsconst tailwindcss = require('tailwindcss'); const autoprefixer = require('autoprefixer'); module.exports = { plugins: [ tailwindcss, autoprefixer, ] }
src/assets/tailwind.css
というtailwindのスタイル用のCSSファイルを作成しますsrc/assets/tailwind.css@tailwind base; @tailwind components; @tailwind utilities;
main.js
でtailwind.css
をimportしますsrc/main.jsimport Vue from 'vue' import App from './App.vue' import '@/assets/tailwind.css' //これ Vue.config.productionTip = false new Vue({ render: h => h(App), }).$mount('#app')セットアップは以上です!
![]()
今回はNavigationやCardの例を利用してサクッと画面を作っています。
あんまりtailwindcssで作り込まれてると<transition>
コンポーネント使いづらいな...と、うっすら思いましたとさ(結果、使ってない)。src/components/Header.vue<template> <nav class="flex items-center justify-between flex-wrap bg-teal-500 p-6"> <div class="flex items-center flex-shrink-0 text-white mr-6"> <svg class="fill-current h-8 w-8 mr-2" width="54" height="54" viewBox="0 0 54 54" xmlns="http://www.w3.org/2000/svg"><path d="M13.5 22.1c1.8-7.2 6.3-10.8 13.5-10.8 10.8 0 12.15 8.1 17.55 9.45 3.6.9 6.75-.45 9.45-4.05-1.8 7.2-6.3 10.8-13.5 10.8-10.8 0-12.15-8.1-17.55-9.45-3.6-.9-6.75.45-9.45 4.05zM0 38.3c1.8-7.2 6.3-10.8 13.5-10.8 10.8 0 12.15 8.1 17.55 9.45 3.6.9 6.75-.45 9.45-4.05-1.8 7.2-6.3 10.8-13.5 10.8-10.8 0-12.15-8.1-17.55-9.45-3.6-.9-6.75.45-9.45 4.05z"/></svg> <span class="font-semibold text-xl tracking-tight">Tailwind CSS</span> </div> <div @click='hideMenu=!hideMenu' class="block lg:hidden"> <button class="flex items-center px-3 py-2 border rounded text-teal-200 border-teal-400 hover:text-white hover:border-white"> <svg class="fill-current h-3 w-3" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><title>Menu</title><path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"/></svg> </button> </div> <div :class='{"hidden md:hidden sm:hidden":hideMenu}' class="w-full block flex-grow lg:flex lg:items-center lg:w-auto"> <div class="text-sm lg:flex-grow"> <a href="#responsive-header" class="block mt-4 lg:inline-block lg:mt-0 text-teal-200 hover:text-white mr-4"> Docs </a> <a href="#responsive-header" class="block mt-4 lg:inline-block lg:mt-0 text-teal-200 hover:text-white mr-4"> Examples </a> <a href="#responsive-header" class="block mt-4 lg:inline-block lg:mt-0 text-teal-200 hover:text-white"> Blog </a> </div> <div> <a href="#" class="inline-block text-sm px-4 py-2 leading-none border rounded text-white border-white hover:border-transparent hover:text-teal-500 hover:bg-white mt-4 lg:mt-0">Download</a> </div> </div> </nav> </template> <script> export default { data() { return { hideMenu: true } } } </script>ざっくり紹介tailwindcss
さて、tailwindcssの特徴を極一部ですがご紹介します!
めちゃくちゃ詳しく書いて下さっている記事はこちらですので是非!
TailwindCSS入門 ~ Utility First + デザインシステムの構築 ~i
:(コロン)
でブレークポイントや擬似クラスの指定ができる
lg:inline-block
hover:text-white
でブレークポイントや擬似クラスへの指定をしています。1つのスタイルを使い回せるの便利だな〜。src/components/Header.vue<a href="#responsive-header" class="block mt-4 lg:inline-block lg:mt-0 text-teal-200 hover:text-white">Blog</a>
@apply
組み合わせて自由に見た目を作れるのが利点とはいえ、何度も同じクラスを並べるのは苦痛ですよね。
@apply
で、utilityの組み合わせをカスタムコンポーネントのクラスとしてまとめることができます。src/assets/tailwind.css@tailwind base; @tailwind components; /* Extracting Components */ .btn-teal { @apply bg-teal-500 text-white py-2 px-4 rounded w-full; } .btn-teal:hover { @apply bg-teal-700 transition-colors transition-250 transition-linear; } @tailwind utilities;カスタムコンポーネントのクラスは、utilitiesの前に読み込まないとダメだそうです。
カスタマイズが簡単
tailwindcssで定義されているスタイルは、
tailwind.config.js
でカスタマイズできます。npx tailwind init //tailwind.config.jsファイルを作成するコマンドtailwind.config.jsmodule.exports = { theme: { extend: {} }, variants: {}, plugins: [] }作成された
tailwind.config.js
にカスタマイズしたいプロパティや追加したいプロパティを記載していきます。
tailwindcssでは現状transition
のようなアニメーションに関するプロパティが定義されていません。
そういうものの追加にも便利そうですね。拡張が簡単なのは嬉しい![]()
(今回はtransitionのutilityクラスを定義するのにtailwindcss-transitionsを使用しました。)PurgeCSSで使ってないCSSを削除
さて、なんだかスマートに感じるtailwindcssですが、ファイル容量は実は結構重いです。
PurgeCSSで、使ってないCSSを削除していきましょう。
- PurgeCSSをインストール
npm install @fullhuman/postcss-purgecss --save-dev
postcss.config.js
にプラグイン設定
- tailwindcssとVue.jsのそれぞれの特徴を踏まえ適切にパージするように
defaultExtractor
とwhitelistPatterns
を設定します。詳細はこちら → https://medium.com/@kyis/vue-tailwind-purgecss-the-right-way-c70d04461475postcss.config.jsconst autoprefixer = require('autoprefixer'); const tailwindcss = require('tailwindcss'); const purgecss = require('@fullhuman/postcss-purgecss')({ // テンプレートファイルへのパス。今回は'./src/**/*.vue' content: [ './src/**/*.vue' ], // https://medium.com/@kyis/vue-tailwind-purgecss-the-right-way-c70d04461475 defaultExtractor: (content) => { const contentWithoutStyleBlocks = content.replace(/<style[^]+?<\/style>/gi, '') return contentWithoutStyleBlocks.match(/[A-Za-z0-9-_/:]*[A-Za-z0-9-_/]+/g) || [] }, whitelistPatterns: [ /-(leave|enter|appear)(|-(to|from|active))$/, /^(?!cursor-move).+-move$/, /^router-link(|-exact)-active$/ ], }) module.exports = { plugins: [ autoprefixer, tailwindcss, // 開発中はビルド時間がかかってしまうので、productionの時のみ実行 ...process.env.NODE_ENV === 'production' ? [purgecss] : [] ] }Before/After
npm build
して、dist/css/
配下のCSS容量を見て見ます。Before
After
644KB減!!
すごいぞ!PurgeCSS!!![]()
今回はサンプルのためスタイリング自体が少ないので、実際のプロジェクトではもっと大きくなるんでしょうけれども、いやぁしかし気持ち良いですね
![]()
まとめ
以上、初めてのtailwindcss (Vue.js + PurgeCSS)でした!
個人的にはめちゃくちゃ好きな思想のフレームワークです。
シンプルで良い。自由 is フリーダム。必要なものは自分で作る緻密かつ堅牢なCSSフレームワークに疲弊している方、ぜひトライしてみては如何でしょうか?
参考にさせて頂いたものまとめ
- tailwindcss
- CSS Utility Classes and "Separation of Concerns" 翻訳
- TailwindCSS入門 ~ Utility First + デザインシステムの構築 ~i
- tailwindcss/setup-examples
- Setting up Tailwind CSS with Vue.js
- Vue + Tailwind + PurgeCSS — The right way
- React上でtailwindcssを使いたい!
tailwindcssなのかTailwindcssなのか、はたまたTailwindCSSなのか、正しい表記が未だに分かりません
![]()
- 投稿日:2019-12-22T00:03:46+09:00
Vue-CLI 4を使用したJavaScript開発環境構築(プロトタイプ版とプロジェクト版)
はじめに
この記事は JavaScript Advent Calendar 2019の22日目の記事になります。
こんばんは、きゅ〜ぶです。
少し前にVue CLI4がリリースされましたね。
Vue CLI4の特徴や3からの変更点などは以下が比較的分かりやすいと思います。
Vue.js CLI 4 Releasedローカル環境でJavaScriptを触りたかったのでせっかくなので新しくなったVue-CLI4で環境構築をしようと思います。
基本的には公式リファレンスに沿ってやっていきます。↓Vue-CLI4のソースコード
https://github.com/vuejs/vue-cli/releases2019年12月現在最新バージョンは、v.4.1.1です。
インストール
公式ドキュメントにも書かれているのですが、
Vue CLIインストールには、前提としてNode.jsのバージョン8.9以上(8.11.0以降を推奨)
が必要となります。
Node.jsが入ってない人はNode.jsからインストールしましょう。以下記事が分かりやすいので参考にしてみてください。
MacにNode.jsをインストールVue-CLIインストール
プロトタイプ版
公式リファレンスのコマンドに沿って入力していきます。
vue serve
とvue build
で簡単なプロトタイプが作れます。
ちょっと処理を確認したいとかそういったときに便利です。$ npm install -g @vue/cli $ vue --version @vue/cli 4.1.1 $ npm install -g @vue/cli-service-global $ touch App.vueApp.vue<template> <h1>Hello!</h1> </template>$ vue serve INFO Starting development server... 98% after emitting DONE Compiled successfully in 1653ms 11:18:54 App running at: - Local: http://localhost:8080/ - Network: http://**.**.***.**:8080/ Note that the development build is not optimized. To create a production build, run npm run build.$ vue build ⠧ Building for production... DONE Compiled successfully in 2432ms 11:42:08 File Size Gzipped dist/js/chunk-vendors.548bada6.js 65.55 KiB 23.58 KiB dist/js/app.e2adb5ac.js 1.78 KiB 0.89 KiB Images and other types of assets omitted. DONE Build complete. The dist directory is ready to be deployed. INFO Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html簡単なJavaScriptを軽く動かしたいならここまでやってあれば問題ないです!
Vue.jsで本格的に開発したいなら以下のようなプロジェクトを作成することもできます。プロジェクト版
Vue-CLI4でプロジェクト作成
$ vue create hello-world ? Your connection to the default npm registry seems to be slow. Use https://registry.npm.taobao.org for faster installation? No Vue CLI v4.1.1 ? Please pick a preset: (Use arrow keys) ❯ default (babel, eslint) Manually select features ? Please pick a preset: Manually select features ? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection) ❯◉ Babel ◯ TypeScript ◯ Progressive Web App (PWA) Support ◯ Router ◯ Vuex ◯ CSS Pre-processors ◉ Linter / Formatter ◯ Unit Testing ◯ E2E Testing ? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)Babel, Linter ? Pick a linter / formatter config: ❯ ESLint with error prevention only ESLint + Airbnb config ESLint + Standard config ESLint + Prettier Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection) ❯◉ Lint on save ◯ Lint and fix on commit ? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys) ❯ In dedicated config files In package.json ? Save this as a preset for future projects?ざっくりこんな感じで作っていきます。
①使用する機能の選択
Babel
とESLint
が入ってるデフォルトを選択するかマニュアルで必要な機能を選択した物を使うかの選択になります。○デフォルト
? Please pick a preset: (Use arrow keys) ❯ default (babel, eslint) Manually select features
○マニュアル
? Please pick a preset: Manually select features ? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection) ❯◉ Babel ◯ TypeScript ◯ Progressive Web App (PWA) Support ◯ Router ◯ Vuex ◯ CSS Pre-processors ◉ Linter / Formatter ◯ Unit Testing ◯ E2E Testing②ESLintプリセットの選択
・ESLint with error prevention only(エラー防止のみ)
・ESLint + Airbnb config(Airbnb設定)
・ESLint + Standard config(標準設定)
・ESLint + Prettier(ESLintとPrettierの併用)? Pick a linter / formatter config: (Use arrow keys) ❯ ESLint with error prevention only ESLint + Airbnb config ESLint + Standard config ESLint + Prettier
③追加のLint機能の選択
・Lint on save(保存時にLint実行)
・Lint and fix on commit(コミット時にLint実行)? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i > to invert selection) ❯◉ Lint on save ◯ Lint and fix on commit④BabelやESLintなどの設定の配置箇所の選択
・In dedicated config files(専用の設定ファイル内)
・In package.json(package.json内)? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys) ❯ In dedicated config files In package.json
⑤今までの設定をプリセットとして保存するかの選択
? Save this as a preset for future projects? (y/N)
```terminal ? Save preset as:ここで設定しておくと次以降、
vue create
でプロジェクトを作る際、また新しく設定する必要がなくなり、設定したプリセットをそのまま使用することができます。以下の画面がターミナルで表示されていれば、無事インストール完了となります?
? Successfully created project test. ? Get started with the following commands: $ cd hello-world $ npm run serveサーバ起動
$ cd hello-world $ npm run serve DONE Compiled successfully in 1222ms 23:48:57 App running at: - Local: http://localhost:8080/ - Network: http://xxx.xxx.x.xxx:8080/ Note that the development build is not optimized. To create a production build, run npm run build.以下画面が表示されれば成功です?
では、楽しいJavaScript生活を。。。