28
22

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 3 years have passed since last update.

オープンストリームAdvent Calendar 2018

Day 19

NuxtとFirebaseでTwitterまとめサイトを作る! (ツイートを表示する前編)

Last updated at Posted at 2018-12-19

はじめに - "Vue.js / Nuxt.js / Firebase のアプリ開発体験コース"

🎄🎄 🎅 オープンストリーム Advent Calendar 2018 の 19 日目です 🎁🎄🎄

最近、 Vue.jsとFirebaseを使ってサービス作ったー …と流行っていますね!

この記事では、そんなVue.jsを使ってWebアプリを作る Nuxt.js と、 Firebase を用いて ツイートをまとめるアプリ を作ってみたいと思います!
Vue.js / Nuxt.js / Firebaseの入門としてこの記事を位置づけています🔰

環境はこんな感じです!

$ node -v
v11.4.0

$ npm -v
6.4.1

$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.14.2
BuildVersion:	18C54

2019/12/18現在の create-nuxt-app (でプロジェクトが作成できるNode.jsの環境)には対応しません

まずは当時のNode.js 11.4.0でプロジェクトを作成しようとするとESLintが設定できなくなっています。

warning nuxt > @nuxt/webpack > @nuxt/babel-preset-app > core-js@2.6.11: core-js@<3 is no longer maintained and not recommended for usage due to the number of issues. Please, upgrade your dependencies to the actual version of core
-js@3.
error eslint@6.7.2: The engine "node" is incompatible with this module. Expected version "^8.10.0 || ^10.13.0 || >=11.10.1". Got "11.4.0"
error Found incompatible module.

次に、 create-nuxt-app のESLintが動作できるバージョン(11.10.1)で試したところ、ツイートの埋め込みコンポーネント(tonickkozlov/vue-tweet-embed)が動作しなくなります。

import Tweet from 'vue-tweet-embed/tweet' と呼び出す方法ではビルドができず yarn dev ができません。

pages/index.vue
<template>
  <div>
    <h1>🐥まとめページ</h1>
    <hr>
    <div
      v-for="tw in tweets" :key="tw">
      <Tweet :id="tw"/>
    </div>
  </div>
</template>

<script>
import Tweet from 'vue-tweet-embed/tweet'

export default {
  components: {
    Tweet
  },

$ yarn dev
...

This dependency was not found:

  • vue-tweet-embed/tweet in ./node_modules/babel-loader/lib??ref--2-0!./node_modules/vue-loader/lib??vue-loader-options!./pages/index.vue?vue&type=script&lang=js&

importするモジュールを変えた方法 では、ページを開いたときに "Unknown custom element: - did you register the component correctly?"と表示されます。

pages/index.vue
...

<script>
import Tweet from 'vue-tweet-embed'

export default {
  components: {
    Tweet
  },

詳しい検証を進めたいところですがまだできていません🙇‍♂️
「NuxtとFirebaseを組み合わせてなにか作りたい」という趣旨の場合はこちらの記事をご確認ください。

Nuxt.js + Vuex + Firebase(Authentication, Cloud Firestore)でTwitterユーザー向けの伝言板を作る - Qiita
https://qiita.com/ysd_marrrr/items/cf7871e7803d7b4919f1

作ったモノ

Twitterで モーメント の機能があったのはご存じでしょうか? 使ったことないって?
モーメントはツイートを一つのページにまとめられる機能ですが、この前 スマートフォンアプリからのモーメントの作成ができなくなりました。 不便ですね。

この記事で作るのは、そんなモーメントのようにツイートをまとめるアプリを作ります 🗒
前編ではここまで作ります。このようにまとめたツイートをTwitterの埋め込み機能で表示するアプリになります。
HTMLに埋め込みタグ貼り付ければおしまいだろ

image.png

最終的には Vue.js/Nuxt.js/Firebase を習得しながら次を目指していきます😃

  • Twitterのアカウントで認証して自分だけのまとめを作れるようにする
  • スマートフォンでもツイートをまとめられるようにする

Nuxtプロジェクトの作成

create-nuxt-app を使います。 Node.jsの環境は整えましたよね?
プロジェクトの名前からCSSのフレームワーク、SPAにするかどうかまでこのコマンドで設定でき、素早くプロジェクトが始められます。

$ npm install -g npx
$ npx create-nuxt-app moments-sub
> Generating Nuxt.js project in ~/Projects/moments-sub
? Project name moments-sub
? Project description My tweet collection project
? Use a custom server framework express
? Use a custom UI framework bulma
? Choose rendering mode Single Page App
? Use axios module yes
? Use eslint yes
? Use prettier yes
? Author name Masataka Yoshida
? Choose a package manager yarn

プロジェクトの動作確認

作ったプロジェクトが動くか yarn dev で試してみましょう。

$ cd moments-sub

$ yarn dev
~/Projects/moments-sub/pages/index.vue
  36:1  error  Delete ``  prettier/prettier

✖ 1 problem (1 error, 0 warnings)
  1 error and 0 warnings potentially fixable with the `--fix` option.

おっと、ファイルに触れていないのにエラーが出ました🤔

ソースコードが整形された形になっていないと このエラーが出るようですが、プロジェクト開始直後から出るのはテンションが下がります。

./node_modules/.bin/eslint --fix pages/index.vue とeslintに --fix オプションを付けて実行するとこのエラーを解決してくれるそうですが、 動作を確認するときに毎回このエラーが出て --fix オプションを付けて直す…なんてやってられません。

整形に関するエラーを自動で修正する

yarn dev を実行したときに --fix オプションでeslintを走らせられるといいのですが、この方法が見つかりません。
そこで、 エディターでプロジェクト内のファイルを変更したときにこのエラーを直してもらうよう 設定しましょう。Atomの場合は次を参考にするとAtomとeslintを連携させることができます。

Atom & Vue.js & ESLint で自動整形環境構築 - Qiita
https://qiita.com/taiju59/items/326bb25814f60ecf9c3c

最後に linter-eslint パッケージの "Fix errors on save" にチェックを入れると、 上記の整形に関するエラーが自動で治ります 😃

image.png

http://localhost:3000 を開いてNuxt.jsの画面が出たら次に進みましょう😃
すこし話がそれましたが、これでNuxtの準備が整いました!

まとめたツイートを表示する画面を作る

では、ツイートを表示してみましょう。

create-nuxt-app で作ったNuxtのプロジェクトを見ると次のような構成になっています。

image.png

このNuxt.jsのプロジェクトに画面を作るには pages ディレクトリにファイルを追加しますが、 pages/index.vue を変更します。
この pages/index.vue がVue.jsの 単一ファイルコンポーネント というものです。 <style> に何も書いていませんが、HTML/JS/CSSを書いたことがあれば <template>, <script>, <style> は何を書いているかイメージしやすいですよね☺️

<template> の下にある <div> は必要です。

pages/index.vue
<template>
  <div>
    <h1>🐥まとめページ</h1>
    <hr>
    <ul>
      <li> {{ tweets }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data: function() {
    return { tweets: 'ここにツイートが出たらいいなぁ' }
  }
}
</script>

<style>
</style>

まとめたツイートをクライアントに送る

まとめたツイートをクライアントに送る部分を作りましょう。 まず、server ディレクトリに apiapi/tweets.js を作ります。これはまとめたツイートのデータを返す部分(API)になります。
次に同じディレクトリに datadata/tweets.json を作ります。これはまとめたツイートのデータになります。
こんな感じになります。

image.png

Twitterのツイートをみると、URLは次の形式になっています。この数値の部分がツイートのIDになるので、これを手作業で抜き出してツイートをまとめましょう。

https://twitter.com/Adobe/status/1074067849872900097
                    ~~~~~        ~~~~~~~~~~~~~~~~~~~
  @以降の名前(screen_name)         ツイートのID(id, id_str)

まとめたツイートを次の形で先ほどの server/data/tweets.json に保存します。

server/data/tweets.json
{
  "tweets": [
    "1073763832869179392",
    "1073909919839997952",
    "1074076529838120960"
  ]
}

次に、このまとめたデータを返すAPIを作ります。 server/api/tweets.js を次の内容にします。
ここでまとめたツイートのJSONを読み込んでクライアントに送ります。

server/api/tweets.js
const express = require('express')
const router = express.Router()
var path = require('path')
var fs = require('fs')

router.get('/tweets', (req, res, next) => {
  const tweetsPath = path.join(__dirname, '../data/tweets.json')
  var tweetsFile = JSON.parse(fs.readFileSync(tweetsPath, 'UTF-8'))

  res.header('Content-Type', 'application/json; charset=utf-8')
  res.send(tweetsFile)
})

module.exports = router

APIを作ってもNuxt側は把握できないため、 server/index.js を編集して先ほどのAPIを登録します。

ファイルの中に2行を入れますが、既にコードが書かれているのと、それぞれ挿入する場所が決まっているので注意して入れます。

  1. const apiRouter = require('./api/tweets') : APIのJSを読み込みます。 require 内には index.js から見たAPIのJSまでの場所を 拡張子無しで 指定します。
  2. app.use('/api', apiRouter) : APIを登録します。 /api はクライアントから見た場所になります。
server/index.js
const express = require('express')
const consola = require('consola')
const { Nuxt, Builder } = require('nuxt')
const app = express()
const host = process.env.HOST || '127.0.0.1'
const port = process.env.PORT || 3000

const apiRouter = require('./api/tweets')  // <- ここに挿入

app.set('port', port)

// Import and Set Nuxt.js options
let config = require('../nuxt.config.js')
config.dev = !(process.env.NODE_ENV === 'production')

async function start() {
  app.use('/api', apiRouter)  // <- ここに挿入

  // Init Nuxt.js
  const nuxt = new Nuxt(config)

...

APIができたら画面に出してみましょう!再び pages/index.vue を編集します。
先ほどのIDのリストが tweets になって <template> 内に入るため、リストの中身でループしています。 :key は必要です。

pages/index.vue
<template>
  <div>
    <h1>🐥まとめページ</h1>
    <hr>
    <ul
      v-for="tw in tweets" :key="tw">
      <li> {{ tw }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data: function() {
    return { tweets: ['ここにツイートが出たらいいなぁ'] }
  },
  mounted: function() {
    this.$axios
      .$get('/api/tweets')
      .then(response => {
        this.tweets = response.tweets
      })
      .catch(error => {
        console.log(error)
      })
  }
}
</script>

編集後は http://localhost:3000 に接続するとツイートのIDが並ぶはずです😀

image.png

画面に送られたツイートを表示する

まだIDしか表示されていませんが……これで

  • Nuxt.jsでAPIを作って
  • そのAPIに通信して
  • まとめたツイートの情報を取得できました

このIDをツイートとして表示するのですが、便利なプラグインを使ってみましょう。

ここでは、Vueのプラグインである vue-tweet-embed を使います。
yarnを使ってプラグインを導入するので、 yarn devhttp://localhost:3000 に接続できる状態であれば Ctrl+c / Cmd+c で終了しましょう。

次に、このコマンドで vue-tweet-embed をインストールします。

$ yarn add vue-tweet-embed

インストールが終わったら pages/index.vue を編集します。
コンポーネントを追加するので、 <script> 内の importcomponents を忘れないようにしましょう。

使用方法は <Tweet :id="'692527862369357824'"></Tweet> と文字列を入れるようになっていますが、変数をセットするときは <Tweet :id="tw"/> と書くことができます。

pages/index.vue
<template>
  <div>
    <h1>🐥まとめページ</h1>
    <hr>
    <div
      v-for="tw in tweets" :key="tw">
      <Tweet :id="tw"/>
    </div>
  </div>
</template>

<script>
import Tweet from 'vue-tweet-embed/tweet'

export default {
  components: {
    Tweet: Tweet
  },
  data: function() {
    return { tweets: ['ここにツイートが出たらいいなぁ'] }
  },
  mounted: function() {
    this.$axios
      .$get('/api/tweets')
      .then(response => {
        this.tweets = response.tweets
      })
      .catch(error => {
        console.log(error)
      })
  }
}
</script>

yarn dev を実行してブラウザで確認すると、ツイートのIDが埋め込みツイートに変化しました😆
これでまとめたツイートが表示できましたね!

image.png

このままでは自分でツイートを追加したり、新しいまとめページを作るときにファイルを作って、そのファイルを指定して……とファイルが必要になってきます。

  • スマートフォンからまとめページをいじりたいですよね?
  • データベースを用意してツイートやページを追加できるようにしたいですよね?
  • Twitterのアカウントで認証したいですよね?

🔥ここでFirebaseを使います🔥

前編おわり

…………とFirebaseの導入を書きたいところですが、Firebaseの部分を書くと その部分だけで10,000文字を超えてものすごく長くなってしまうので 後編に分けます 🙇‍♂️
だっていろいろハマったんだもん

(あれ……とりあえず19日の分は書けたよね……?明日でいいよね……?🛌💤)

明日は @maemori さんです!

この記事を書いているときに、ツイートをまとめる Togetter があったのをすっかり忘れてました。

参考

Nuxt.js でバックもフロントもこれ一本 - Qiita
https://qiita.com/kawaMk4/items/298f95f751540b96d39b

28
22
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
28
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?