46
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Nuxt.js #2Advent Calendar 2018

Day 8

Nuxt.js+Laravelで開発しているCMSの紹介

Last updated at Posted at 2018-12-07

みなさんNuxt.jsとLaravelはお好きですか?
僕は大好きです。

まだNuxt.jsもLaravelも初心者ですが、その2つを使って開発しているCMSについての紹介と技術周りでハマった点、使ったものなどを紹介させていただきます。

自己紹介

遅れましたが自己紹介を少し。

現在中学3年生でプログラミングは小学4年生からはじめました。
今はLaravelやNuxt.js、ゲーム周りだとUnityやScratchなどを使っています。
最近ポートフォーリオを作ってみたので良ければ見てみてください。

http://me.hota1024.com/

では本題に移ります

CMSとは?

CMSとはContent-Management-Systemの略です。
代表的なものだと

  • Wordpress
  • OctoberCMS

などが挙げられます。

今回僕が開発しているCMSは以下の機能を持っています。

  • 記事投稿
  • ファイル管理
  • タグ
  • SPA

なぜ作ろうと思ったか

主な理由は以下のとおりです

  • 自分で開発したCMSなら記事などの投稿のモチベーションが保持できる
  • 管理画面やブログがSPAなCMSがほしかった
  • 腕試し

実際に開発しているもの

io-cms-1024のコピー.png

ロゴは適当です。

下の画像が実際の記事編集画面です。
スクリーンショット 2018-12-04 22.14.04.png

記事はMarkdownで記述します。
そのMarkdownの機能について少し紹介します。

MarkdownのコードはQiitaみたいにファイル名を指定できるようにしています。

変換後

Markdownも少し拡張していてアラートを出せるようにしています。

変換後

技術周りの紹介

今回使ったものは以下のとおりです

  • エディタ
    • PhpStorm
    • WebStorm
  • バックエンド
    • Laravel
    • Laravel Homestead
  • フロントエンド
    • Nuxt.js
    • Vuetify

最近Vuetifyというマテリアルデザインフレームワークを気にっています。
コンポーネントが豊富で機能も優秀すぎる。
おすすめなのでぜひ使ってみてください。

Vuetify

スクリーンショット 2018-12-04 22.26.13.png

Nuxt.jsは普段僕はVue.jsを使っていたのですが、Nuxt.js知ったときはかなり衝撃的でした。
とにかく楽。コマンド打つだけで静的サイトを生成したりSSRもできたりで便利すぎる。
こちらもおすすめです。

Nuxt.js

スクリーンショット 2018-12-04 22.29.24.png そいういえば最近Nuxt.jsのトップページの下の方にすぐにNuxt.jsを試せる[CodeSandbox.io](https://codesandbox.io/)の埋め込みが追加されましたね。 これはこれで嬉しい。

ちなみにNuxt.jsでカウンターアプリやVue.jsで「カップ麺タイマー」などを作ったので良ければ見てみてください。

http://nuxt-counter.xii.jp/
スクリーンショット 2018-12-04 22.43.39.png

http://ntimer.xii.jp/#/
スクリーンショット 2018-12-04 22.44.47.png

Laravel

スクリーンショット 2018-12-04 22.33.26.png 最近Ruby on Railsが熱いですがLaravelも再び熱くなってきています。 PHPをやり始めて2年間、そもそも「Webフレームワーク」というものの存在を知らなくて初めてLaravelを知ったときは今までの苦労はなんだったのかと... それぐらい簡単に色々なことができるPHPフレームワークなのでぜひ使ってみてください。

ちなみに今回io-cmsを開発するにあたってLaravel HomesteadというVagrantのBoxを使用しました。

やっぱり仮想環境はいいですね。

つまりポイント

今回このio-cmsの開発にあたって詰まったポイントをいくつか紹介したいと思います。

許可

一番悩んだのがどうやってログインしているユーザーだけが管理画面で操作をできるようにするかです。

基本的にNuxt.jsからLaravelのAPIを叩くのでこのときに認証情報をどうやって送ればいいのかぐぐってみるとちょうどいいものが見つかりました。

どうやらJWTという方法があるらしいのでそのJWTをLaravelで使うためのライブラリを探してみました。

https://github.com/tymondesigns/jwt-auth

このライブラリが一番使いやすそうでした。
いろいろ設定ファイルをいじってNuxt.js側でcookieにトークンを格納するロジックを書くだけで実現できてしまいました。

axios地獄

ちょっとふざけてるように感じますが、これもかなり悩まされました。

例えば以下のようなコードがあるとします。

const state = {
  methods: {
    async new () {
      this.article = {
        id: -1,
        title: '',
        body: '',
      }
    },
    async get () {
      this.article = await this.$axios.$get('article/' + this.id)
    },
    save () {
      this.$axios.$put('article/' + this.article.id, this.article)
    },
    delete () {
      this.$axios.$delete('article/' + this.id)
    }
  }
}

今回Nuxt.jsからLaravelへAjaxするにあたってaxiosというライブラリを用いました。
上のコードだとそのaxiosの呼び出しであるthis.$axiosがたくさん見られます。
このコードの問題点は以下のとおりです。

  • 一回のリクエストのコードが長い
  • 他のプログラムでも同じコードを書いたときに APIの仕様変更をした際に修正する箇所が多い

とりあえずORMみたいなAPIでリクエストできたら見やすくなるかなーなんて思って以下のようにリクエストできるようにしました。
ただしRESTfulAPI前提です。

const state = {
  methods: {
    new () {
      this.article = new Article({
        title: '',
        body: ''
      })
    },
    async get () {
      this.article = await Article.find(this.id)
    },
    save () {
      this.article.save()
    },
    delete () {
      this.article.delete()
    }
  }
}

ActiveRecordっぽい感じですね。
オブジェクトベースのAPIでLaravelにリクエストできるようにしました。

すこし長いですがこのArticleオブジェクトは以下のようなコードです。

Article.js
import Model from './Model'
import MediaFile from './MediaFile'

class Article extends Model
{
  static table = 'articles'
  columns = ['title', 'body', 'description', 'thumbnail_id', 'is_published', 'published_at']
  tags = []
  thumbnail = null

  buildData () {
    let data = super.buildData()

    data['tags'] = this.tags.map(tag => tag.id)
    data['thumbnail_id'] = this.hasThumbnail() ? this.thumbnail.id : -1

    return data
  }

  constructor (data) {
    super()
    super.set(data)
    this.tags = data.tags
    this.thumbnail = new MediaFile(data.thumbnail)
  }

  url () {
    return `/articles/${this.id}`
  }

  previewUrl () {
    return `${this.url()}/preview`
  }

  hasThumbnail () {
    if (this.thumbnail && this.thumbnail.isNew() === false)
    {
      return true
    }

    return false
  }

  releaseThumbnail () {
    this.thumbnail = null
  }
}

export default Article

予めModelというクラスを作っており、そのModelクラスを継承してRESTfulAPIのパスを指定すればすぐに使えるようになっています。

こうすればリレーションもオブジェクトベースでアクセスできますし、一石二鳥です。

Object.assignが深い部分までコピーしてくれない

JavaScriptのオブジェクトは基本的に参照が代入されるのでオブジェクトをコピーする際にはObject.assign関数を持ち入ります。

sample.js
let a = { value: 10 }
let b = Object.assign({}, a}

a.value = 20

console.log(a) //20
console.log(b) //10

それで何が問題かというとオブジェクトにオブジェクトのプロパティーがあってもObject.assignはそこまでコピーしてくれない、というものです。

sample.js
let a = { obj: { value: 10 } }
let b = Object.assign({}, a)

a.obj.value = 20

console.log(a.obj.value) //20
console.log(b.obj.value) //20 上と参照が同じ

そこで自分で関数を用意するのも良かったのですが、lodashというライブラリにcloneDeepという関数があったのでそれを利用してみました。

sample.js
import { cloneDeep } from 'lodash'

let a = { obj: { value: 10 } }
let b = cloneDeep(a)

a.obj.value = 20

console.log(a.obj.value) //20
console.log(b.obj.value) //10

lodashいいですね。ドキュメント見てても飽きない。

目標

まだ目標が定まっていませんが

  • 追加したい機能
    • Unsplash連携
    • Wordpressで書いた記事の移行システム
    • SEO
    • テーマ管理
  • その他
    • OSS
      • ある程度機能を作ってソースのリファクタリングをしたらGithubで公開する予定です。

最後に

まだNuxt.jsとLaravelの機能を使いこなせていない部分もありますが、このCMSの開発でいろいろなことを学べましたし、これからももっと知識を得ていきたいと思います。

良ければアドバイスなどコメントしていただけると幸いです。

長かったですが最後まで読んでくださってありがとうございました。

46
29
1

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
46
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?