• 54
    いいね
  • 0
    コメント

はじめに

この記事は、Vue.js Advent Calendar 2016 12日目の代打記事です。

Nuxt.jsとは?

https://nuxtjs.org/

Few hours after the announcement of Next.js, the idea of creating server-rendered Vue.js applications the same way as Next.js became inevitable: Nuxt.js was born.

Next.jsのVue.js版。

特徴としては以下の点が挙げられている。

  • No need to write Webpack/Babel configuration
  • No need to create a node.js server
  • Writing *.vue files, because it rocks
  • Creating new routes by adding a file in the pages/ directory
  • Accessing the server data inside the routes components easily
  • Webpack/Babelの設定書く必要なし
  • node.jsサーバを準備する必要なし
  • *.vueファイルを書くだけでOK
  • pagesディレクトリにファイル追加すると自動ルーティング
  • ルートコンポーネント内のサーバデータに簡単アクセス

アプリケーション作成

公式ドキュメント: Installation

まずvue-cliをインストールしていない場合は、グローバルオプションでインストールしてください。

$ npm install -g vue-cli

プロジェクト名は[nuxt-example]としましょう。

$ vue init nuxt/starter nuxt-example
$ cd nuxt-example
$ npm install # or $ yarn
$ npm run dev

http://localhost:3000 にこのような画面が表示されていればOKです。

スクリーンショット 2016-12-18 3.27.43.png

vue-cliを使わない場合は、Installation「Starting from scratch」を参照

ディレクトリ構成

公式ドキュメント: Directory Structure

ミニマム構成

|-- pages
    |-- index.vue
|-- package.json
  • /pagesフォルダにindex.vueがありさえすればOK
  • index.vueがアプリケーションのルート(/)にルーティング
  • Hello-Worldサンプルが参考に

推奨構成

|--- assets
    |--- global.css
|--- components
    |--- nav.vue
|--- pages
    |--- index.vue
|--- plugins
    |--- filters.js
|--- static
    |--- favicon.ico
|--- store
    |--- index.js
|--- nuxt.config.js
|--- package.json
  • /storeフォルダを作成することで、Vuexが利用可能

エイリアス

ALIAS DIRECTORY
~ /
~assets /assets
~components /components
~pages /pages
~plugins /plugins
~static /static
~store /store

このエイリアスを利用することで、以下のように記述できる。

<img src="~static/img/logo.png" alt="Logo"/>

ルーティング

公式ドキュメント: Routing

  • Nuxt.jsvue-routerを利用
  • pagesフォルダに従って、ルーティングを作成

基本

このディレクトリ構成からは、次のようなvue-routerの設定が作られる。

|-- pages
    |-- posts
        |-- index.vue
        |-- welcome.vue
    |-- about.vue
    |-- index.vue
routes: [
  {
    path: '/posts',
    component: '~pages/posts/index.vue'
  },
  {
    path: '/posts/welcome',
    component: '~pages/posts/welcome.vue'
  },  
  {
    path: '/about',
    component: '~pages/about.vue'
  },
  {
    path: '/',
    component: '~pages/index.vue'
  }
]

応用

_プレフィックスを与えることで、Nuxt.jsのルーティングシステムに検知されないファイルを作成可能。

|-- pages
    |-- _about.vue
    |-- index.vue
routes: [
  {
    path: '/',
    component: '~pages/index.vue'
  }
]

サンプル集

2016/12/18時点では、ドキュメントには以上の項目しか用意されてない。
用意されているEXAMPLESから、Nuxt.jsでなにができるかを見ていきましょう。

SEO HTML Head

https://github.com/nuxt/nuxt.js/tree/master/examples/head-elements

  • vue-metaを利用して、headerattributeを更新ができる
nuxt.config.js
module.exports = {
  head: {
    titleTemplate: '%s - Nuxt.js',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: 'Meta description' }
    ]
  }
}

Cached Components

https://github.com/nuxt/nuxt.js/tree/master/examples/cached-components

  • lru-cacheを利用して、オブジェクトのキャッシュができる
nuxt.config.js
module.exports = {
  cache: true
}

Custom Loading

https://github.com/nuxt/nuxt.js/tree/master/examples/custom-loading

  • デフォルトのprogress barをカスタマイズできる
  • 自分で作成したloading componentをデフォルトの代わりに設定できる
nuxt.config.js
module.exports = {
  loading: 'components/loading.vue'
}

Custom Routes

https://github.com/nuxt/nuxt.js/tree/master/examples/custom-routes

  • Routingで見てきた以外に、ルーティングを独自に設定できる
nuxt.config.js
module.exports = {
  router: {
    routes: [
      { name: 'user', path: '/users/:id(\\d+)', component: 'pages/_user' }
    ]
  },
  build: {
    vendor: ['axios']
  }
}

Global CSS

https://github.com/nuxt/nuxt.js/tree/master/examples/global-css

  • 以下の形式でグローバルCSSを設定できる
    • 外部モジュール
    • cssへのコンパイルが必要な外部モジュール
    • 内部ファイル
nuxt.config.js
const { resolve } = require('path')

module.exports = {
  css: [
    // Load a node.js module
    'hover.css/css/hover-min.css',
    // node.js module but we specify the lang
    { src: 'bulma', lang: 'sass' },
    // Css file in the project
    // It is important to give an absolute path
    resolve(__dirname, 'css/main.css')
  ]
}

Layouts

https://github.com/nuxt/nuxt.js/tree/master/examples/extend-app

  • /layouts/app.vueでグローバルなレイアウトを設定できる
/layouts/app.vue
<template>
  <nuxt-container>
    <img src="logo.png"/>
    <nuxt/>
  </nuxt-container>
</template>

<style scoped>
img {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 1000;
}
</style>

Plugins

https://github.com/nuxt/nuxt.js/tree/master/examples/plugins-vendor

  • build.vendorに利用する外部モジュールを指定
  • アプリケーションが起動する前に定義する必要があるものはpluginsとして設定
nuxt.config.js
module.exports = {
  build: {
    vendor: ['axios', 'mini-toastr', 'vue-notifications']
  },
  plugins: [
    '~plugins/vue-notifications.js'
  ]
}

Routes transitions

https://github.com/nuxt/nuxt.js/tree/master/examples/routes-transitions

Async Datas

https://github.com/nuxt/nuxt.js/tree/master/examples/async-data

  • Promise
  • callback

を利用した非同期通信の書き方の紹介

Vuex Store

https://github.com/nuxt/nuxt.js/tree/master/examples/vuex-store

  • Vuexを使ってStateパターンを実装
  • /storeフォルダ配下にファイルを設置していく
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    counter: 0
  },
  mutations: {
    increment (state) {
      state.counter++
    }
  }
})

export default store

Testing

https://github.com/nuxt/nuxt.js/tree/master/examples/with-ava

  • ava: テストフレームワーク
  • jsdom: DOMシミュレートライブラリ

を利用してテストが書ける。

index.test.js
/*
** Test with Ava can be written in ES6 \o/
*/
import test from 'ava'
import jsdom from 'jsdom'
import { createServer } from 'http'
import { resolve } from 'path'

let nuxt = null
let server = null

// Init nuxt.js and create server listening on localhost:4000
test.before('Init Nuxt.js', (t) => {
  const Nuxt = require('../../../')
  const options = {
    rootDir: resolve(__dirname, '..'),
    dev: false
  }
  nuxt = new Nuxt(options)
  return nuxt.build()
  .then(function () {
    server = createServer((req, res) => nuxt.render(req, res))
    server.listen(4000, 'localhost')
  })
})

/*
** Example of testing only the html
*/
test('Route / exits and render HTML', async t => {
  let context = {}
  const { html } = await nuxt.renderRoute('/', context)
  t.true(html.includes('<p class="red-color">Hello world!</p>'))
  t.is(context.nuxt.error, null)
  t.is(context.nuxt.data[0].name, 'world')
})

/*
** Example of testing via dom checking
*/
test('Route / exits and render HTML', async t => {
  const window = await nuxt.renderAndGetWindow(jsdom, 'http://localhost:4000/')
  const element = window.document.querySelector('.red-color')
  t.not(element, null)
  t.is(element.textContent, 'Hello world!')
  t.is(element.className, 'red-color')
  t.is(window.getComputedStyle(element).color, 'red')
})

// Close server and ask nuxt to stop listening to file changes
test.after('Closing server and nuxt.js', t => {
  server.close()
  nuxt.close()
})

Production deployment

  • next.js同様にnowの利用を推奨

あわせて読みたい

おわりに

Nuxt.jsはまだまだ発展途上のプロダクトですが、Vue.jsで開発する上でのデファクトスタンダードを学べるいい機会になると思いました。

Nuxt.jsをフォローして、ぜひこれから注目していきましょう!