LoginSignup
4
4

More than 5 years have passed since last update.

vue+hugo+milligramでブログを作ってみた

Last updated at Posted at 2018-09-03

最近、フロントエンドにvue.jsを使うことが多くなりました。

vueは何がいいのかと言うと、私の感想では、「簡単に作れる」という点がいいなと思っています。それほど複雑でもないし。

ですが、大規模なものをvueで作っていくと、スケールしにくいんじゃないかなって感じはします。一方、reactとかだと最初は複雑だったり、難しかったりするかもですが、スケールしやすいのではないかな。

とは言え、かなり大雑把な感想ですが、私は、vueのほうが好きですね。しかし、内容によって使い分けたほうが良いと思います。

サンプルコード

そんなvueですが、実際にどう使ったのかと言うと、jsonを読み込んでページに反映するみたいな感じのものを書きました。

package.json

{
  "name": "vue-sample",
  "version": "0.0.1",
  "author": "syui <syui@syui.cf>",
  "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

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
    })
  ]);
}

ここでビルドやプレビューに必要なものをインストールします。

$ 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

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>title</title>
        <style>
            table {
              border: 2px solid #42b983;
              border-radius: 3px;
              background-color: #fff;
            }

            th {
              background-color: #42b983;
              color: rgba(255,255,255,0.66);
              cursor: pointer;
              -webkit-user-select: none;
              -moz-user-select: none;
              -ms-user-select: none;
              user-select: none;
            }

            td {
              background-color: #f9f9f9;
            }

            th, td {
              min-width: 120px;
              padding: 10px 20px;
            }
        </style>
    </head>
    <body>

    <script type="text/x-template" id="grid-template">
      <table>
        <thead>
          <tr>
            <th v-for="key in columns"
              @click="sortBy(key)"
              :class="{ active: sortKey == key }">
              {{ key | capitalize }}
              <span class="arrow" :class="sortOrders[key] > 0 ? 'asc' : 'dsc'">
              </span>
            </th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="entry in filteredData">
            <td v-for="key in columns">
              {{entry[key]}}
            </td>
          </tr>
        </tbody>
      </table>
    </script>

    <div id="status">
      <demo-grid
        :data="gridData"
        :columns="gridColumns">
      </demo-grid>
    </div>

  </body>
</html>

あとは、プレビューで確認してみましょう。

$ yarn dev

hugo+milligram

このvueと静的サイトジェネレーターであるhugo、cssフレームワークであるmilligramを組み合わせて、簡単にブログを作ってみました。

何でかと言うと、vueって、トップページやWebアプリを作るのには向いていると思うんですが、ブログを作るのには向いてないと思うんですよね。まず、各種ページを作ってmarkdownで書く体裁を作るのがめんどくさそう。ということで、ここは慣れたhugoを使うことに。あと、cssも書くの面倒ですからね。milligramというやつを使って設定することに。

組み合わせに関しては、yarn buildして./public-vue/build*hugo./static/に置いて、適時、もしくはheadとかに<script type="text/javascript" src="build.js"></script>みたいな感じで読み込めばいいと思います。

感想

ほとんどサンプルなんですけどね、ざっとコードを見てみた感じで言いますと、vueはわかりやすいし、作りやすい感じしますね。

なので、フロントエンドの初学者には、vue.jsはおすすめかもです。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4