+++ date = "2018-07-26" tags = ["vue"] title = "vue+hugo+milligramでブログを作ってみた" slug = "vue" +++ ## 導入 最近、フロントエンドに`vue.js`を使うことが多くなりました。 とは言え、私は、コンピュータ関連のことは何も知らないのに、カッコつけてそれらしいキーワードを並び立ててるに過ぎないんですけどね。フロントエンドとか`vue.js`とか、いかにもって感じじゃないですか。前回書いた記事も本当はそんな感じの内容なんですよね。多分、分かる人には「あ、こいつそれらしいキーワードを並び立ててるだけで、本当はコンピュータ、プログラミングのことをまるで分かっていない初心者だな」と見抜かれてしまうと思うんですけどね...。 さて、前置きはそのくらいにして、この前、`vue.js`という「それっぽいやつ」をなんとなしに使ってみたのですが、所感としては、`vue.js`かなりいいです! で、これは何かと言うと、`react`, `angular`みたいなやつです、Webフレームワーク。 ということで、今回は、どんな感じで`vue`を使ってみたのかの記録になっています。 ### vueは何がいいのか あ、いつの間にか名前を小文字にしてしまってる。本当はVue.jsなのかな。知らん。 しかし、やっぱり基本的には全部小文字で書きたいので、今後は小文字でいきます。 いきなり話がそれましたが、`vue`は何がいいのかと言うと、私の感想では、「簡単に作れる」という点がいいなと思っています。それほど複雑でもないし。 ですが、大規模なものを`vue`で作っていくと、スケールしにくいんじゃないかなって感じはします。一方、`react`とかだと最初は複雑だったり、難しかったりするかもですが、スケールしやすいのではないかな。 とは言え、かなり大雑把な感想ですが、私は、vueのほうが好きですね。しかし、内容によって使い分けたほうが良いと思います。 ## サンプルコード そんな`vue`ですが、実際にどう使ったのかと言うと、jsonを読み込んでページに反映するみたいな感じのものを書きました。 > package.json ```json { "name": "vue-sample", "version": "0.0.1", "author": "syui ", "license": "MIT", "scripts": { "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot --host 0.0.0.0 --port 7000", "build": "cross-env NODE_ENV=production webpack --progress --hide-modules", "build:watch": "cross-env NODE_ENV=production WEBPACK_WATCH=true webpack --progress --hide-modules" }, "dependencies": { "vue": "^2.4.2", "vuex": "^2.4.0" }, "devDependencies": { "axios": "^0.17.1", "babel-core": "^6.0.0", "babel-loader": "^6.0.0", "babel-preset-latest": "^6.0.0", "copy-webpack-plugin": "^4.0.1", "cross-env": "^3.0.0", "css-loader": "^0.28.7", "extract-text-webpack-plugin": "^2.1.0", "file-loader": "^0.11.2", "html-webpack-plugin": "^2.28.0", "postcss": "^6.0.11", "postcss-base64": "^0.7.1", "postcss-cssnext": "^3.0.2", "postcss-loader": "^2.0.6", "postcss-smart-import": "^0.7.5", "postcss-url": "^7.1.2", "style-loader": "^0.18.2", "vue-loader": "^12.0.4", "vue-template-compiler": "^2.4.2", "webpack": "^2.6.1", "webpack-dev-server": "2.7.1" } } ``` > webpack.config.js ```sh var path = require('path'); var webpack = require('webpack'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var HtmlWebpackPlugin = require('html-webpack-plugin'); var CopyWebpackPlugin = require('copy-webpack-plugin'); module.exports = { watch: process.env.WEBPACK_WATCH === 'true', entry: './src/main.js', output: { path: path.resolve(__dirname, './public-vue'), publicPath: '', filename: 'build.js' }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', options: { loaders: { } // other vue-loader options go here } }, { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, { test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/, loader: 'file-loader', options: { name: '[name].[ext]?[hash]' } }, { test: /\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: [ { loader: 'css-loader', options: { importLoaders: 1 } }, { loader: 'postcss-loader', options: { plugins: [ require('postcss-smart-import')(), require('postcss-url')(), require('postcss-base64')({ extensions: ['.svg'], root: 'src' }), require('postcss-cssnext')({ browsers: ['> 1%', 'last 2 versions', 'Firefox ESR', 'Opera 12.1'], features: { autoprefixer: { remove: false } } // 'background-image: radial-gradient' broken in autoprefixer }) ] } } ] }) } ] }, plugins: [ new ExtractTextPlugin('[name].css'), new HtmlWebpackPlugin({ template: 'src/index.html' }) ], resolve: { alias: { 'vue$': 'vue/dist/vue.esm.js' } }, devServer: { historyApiFallback: true, noInfo: true }, performance: { hints: false }, devtool: '#eval-source-map' }; if (process.env.NODE_ENV === 'production') { module.exports.devtool = '#source-map'; // http://vue-loader.vuejs.org/en/workflow/production.html module.exports.plugins = (module.exports.plugins || []).concat([ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"production"' } }), new webpack.optimize.UglifyJsPlugin({ sourceMap: true, compress: { warnings: false } }), new webpack.LoaderOptionsPlugin({ minimize: true }) ]); } ``` ここでビルドやプレビューに必要なものをインストールします。 ```sh $ yarn install ``` インストールできたら先程作った`webpack`の設定ファイルに沿って、vueのコードを書いていきます。 > src/main.js ``` import Vue from 'vue' import axios from 'axios' Vue.component('demo-grid', { template: '#grid-template', props: { data: Array, columns: Array, filterKey: String }, data: function () { var sortOrders = {} this.columns.forEach(function (key) { sortOrders[key] = 1 }) return { sortKey: '', sortOrders: sortOrders } }, computed: { filteredData: function () { var sortKey = this.sortKey var filterKey = this.filterKey && this.filterKey.toLowerCase() var order = this.sortOrders[sortKey] || 1 var data = this.data if (filterKey) { data = data.filter(function (row) { return Object.keys(row).some(function (key) { return String(row[key]).toLowerCase().indexOf(filterKey) > -1 }) }) } if (sortKey) { data = data.slice().sort(function (a, b) { a = a[sortKey] b = b[sortKey] return (a === b ? 0 : a > b ? 1 : -1) * order }) } return data } }, filters: { capitalize: function (str) { return str.charAt(0).toUpperCase() + str.slice(1) } }, methods: { sortBy: function (key) { this.sortKey = key this.sortOrders[key] = this.sortOrders[key] * -1 } } }) var status = new Vue({ el: '#status', data: { gridColumns: ['name','team','xp','get','zukan'], gridData: [] }, beforeCreate: function () { axios.get('https://syui.gitlab.io/pokemon-zukan/json/status.json') .then(function (response) { status.gridData = response.data; }) .catch(function (error) { console.log(error); }); } }); ``` > src/index.html ``` title
``` あとは、プレビューで確認してみましょう。 ```sh $ yarn dev ``` ## hugo+milligram この`vue`と静的サイトジェネレーターである`hugo`、cssフレームワークである`milligram`を組み合わせて、簡単にブログを作ってみました。 何でかと言うと、`vue`って、トップページやWebアプリを作るのには向いていると思うんですが、ブログを作るのには向いてないと思うんですよね。まず、各種ページを作ってmarkdownで書く体裁を作るのがめんどくさそう。ということで、ここは慣れたhugoを使うことに。あと、cssも書くの面倒ですからね。milligramというやつを使って設定することに。 あ、組み合わせに関しては、`yarn build`して`./public-vue/build*`を`hugo`の`./static/`に置いて、適時、もしくは`head`とかに``みたいな感じで読み込めばいいと思います。 ## 感想 ほとんどサンプルなんですけどね、ざっとコードを見てみた感じで言いますと、vueはわかりやすいし、作りやすい感じしますね。 なので、フロントエンドの初学者には、`vue.js`はおすすめかもです。