15
6

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.

明日使えるかもしれない Nuxt 上で唱えるプチ闇魔法3連発

Last updated at Posted at 2019-12-11

この記事は Sansan Advent Calendar 2019 の12日目の記事です。

今年に入ってから Nuxt.js を使い始めましたがとっても便利で、今まで React 派でしたがこれがあるから Vue っていいなと思いました。
みなさんも Nuxt 使っているでしょうか。そして、モダンにかっこよく使えているでしょうか。

僕はあんまりモダンじゃ無い、泥臭くやることを強いられた部分があったので、もしも同じことで悩む人のためにいくつか紹介したいと思います。

コンテンツは

の3点です。

前提

以下で動作確認

また、今回のコード全部入りはGitHubで公開しています

1. Component 内で外部 jQuery を利用する

これは比較的普通に使えるネタかもしれません。
Component 内で jQuery を import して、$で使用します。

型定義を準備

  1. package をインストール
npm i -D @types/jquery
  1. tsconfig.jsontypesを以下のように追記します。
tsconfig.json
{
  // "@types/jquery" を追加!
  "types": ["@types/jquery", "@types/node", "@nuxt/types"]
}

Component を書く

こんな感じ

jquery-example.vue
<template>
  <div>
    <button @click="buttonClick" class="continue">
      Click me
    </button>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

// Ref: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/jquery#authoring-type-definitions-for-jquery-plugins
declare const $: JQueryStatic

// このページだけで外部jQueryを利用する書き方
// Ref: https://ja.nuxtjs.org/faq/#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%AA%E8%A8%AD%E5%AE%9A
@Component({
  head() {
    return {
      script: [{src: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js'}]
    }
  }
})
export default class extends Vue {
  buttonClick() {
    $('button.continue').html('Next Step...')
  }
}
</script>

これで使えます。

2. SPA モードでもエラーが起きた時にエラーページへ飛ばす

これは今回書く中でも特にやってみたら動いた系のネタなので Production レベルでは使わないか、使うにしても Nuxt のバージョンをしっかり固定しましょう

Nuxt では、layout/error.vue を置くことで、404 にアクセスされた時や予期せぬエラーが起きた時に、そのエラーページを表示してくれる機能があります。 (参考)

ですが、SPA モードかつ production build の場合、Component でエラーが throw されるとこのエラーページへ行かなかったので、無理やり制御しました。

エラーページを準備

これは layout/error.vue を追加するだけです。

layout/error.vue
<template>
  <div>
    <h1>エラーが発生しました</h1>
    <nuxt-link to="/">
      ホーム
    </nuxt-link>
  </div>
</template>

error を制御する plugin を追加する。

Vue.config.errorHandler を使ってエラーをキャッチして、nuxt インスタンスのerror()を呼び出します。
この部分が、ソースを追っかけていて「これで行けるんじゃね?」ってやったら動いた系なので取り扱い注意です。

plugins/error-handler.js
import Vue from 'vue'
import { NuxtApp } from '@nuxt/types/app'

Vue.config.errorHandler = (err, vm) => {
  const $nuxt = vm.$root as NuxtApp
  $nuxt.error(err)
}

nuxt.config.ts にも忘れず追加します。

nuxt.config.ts
plugins: ['~/plugins/error-handler.ts'],

これで、Component 内でエラーが起きた時に error.vue へ飛ぶようになります。
ちなみに SPA Production モードの挙動は build した後にnuxt-ts start で確認できます。

エラーを起こすためのお試しComponentはこちら

3. CORS を無視して API にリクエストするための Proxy サーバーを立てる

backend がまだ準備できてない等の理由で、開発中、どうしてもクロスオリジンな API にリクエストしたい場合がないでしょうか。まあ、普通は無いと思います。

Nuxt には ServerMiddleware という機能があり、例えば /api という serverMiddleware を定義すると
http://localhost:3000/api というエンドポイントを作ることができます。

これを活用して、あたかも同じサーバーのエンドポイントなのに、裏では外部 API をリクエストする、みたいなことを実現できます。

(追記) proxy moduleを使う

これですが、公式ドキュメントにある通り@nuxtjs/proxyを使うことで簡単に実現できます。

nuxt.config.ts
  proxy: {
    '/api': {
      target: 'http://example.com/', // Nuxtを起動しているサーバーから見たエンドポイントを記載する
      pathRewrite: {
        '^/api': '/'
      }
    }
  }

上記の記載をすると、 /apiへのアクセスでexample.comへリクエストが飛びます。

以下は、追記前の冗長なやり方です。

外部 API へリクエストするサーバーを書く

  1. リクエストを受けて
  2. パスやパラメータを解析して
  3. そのパスとパラメータそのまま外部 API にリクエストする

みたいなサーバーを node.js で書きます。これは正直どんな実装でも良いのですがサンプルを載せておきます。

server/index.js
const express = require('express')
const request = require('request')

const app = express()

// この場合 localhost:8080/api/~~ とリクエストするとこのserverが受ける
const rootPath = '/api'
// 実際のエンドポイントを入力
const actualEndpoint = process.env.ENDPOINT || 'https://example.com/v1'

const requestWrapper = async (options) => {
  const result = await new Promise((resolve, reject) => {
    request(options, (err, response) => {
      if (err) {
        reject(err)
      }
      if (!response) {
        reject(err, 'Nothing response')
      }
      resolve(response)
    })
  })
  return result
}

// 全部のリクエストを受けて外部APIへ飛ばす
app.all('/*', async (req, res) => {
  console.log(`original url: ${req.originalUrl}`)
  const options = {
    url: actualEndpoint + req.originalUrl.replace(rootPath, ''),
    method: req.method,
    qs: req.query,
    json: req.body
  }

  console.log('request with following options.')
  console.log(options)

  const response = await requestWrapper(options)

  res.status(response.statusCode).send(response.body)
})

// for Nuxt.js server middleware
module.exports = {
  path: rootPath,
  handler: app
}

express とか依存関係がある場合は、npm install も忘れずに!

nuxt.config に serverMiddleware を追加する

serverMiddleware に先ほど追加したパスを指定します。

nuxt.config.ts
  mode: 'spa',
  serverMiddleware: ['~/server/'],

これで、以下のように書くと、上のサーバーへリクエストし、レスポンスを受け取ることができます。

this.response = await this.$axios.$get('/api/hoge')

こんなの2度と使うのか・・・わからないけど以上です!
取り扱いにはくれぐれも注意しましょう。

15
6
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
15
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?