じまろぐ

めめ

GridsomeでGraphCMSのデータを使う

gridsome.server.js

const axios = require('axios')

module.exports = function (api) {
  api.loadSource(async ({ addContentType }) => {
    const res = await axios.get(process.env.GRIDSOME_GRAPHCMS_ENDPOINT, {
      params: {
        query: `query {
          posts {
            id
            title
            slug
            date
            cover {
              thumbnail: url(transformation: {
                image: {
                  resize: {
                    width: 200
                    height: 200
                    fit: crop
                  }
                }
              })
              url
            }
            tags {
              name
            }
            category {
              name
            }
            body {
              html
            }
          }
        }`
      },
      headers:
        {
          Authorization: process.env.GRIDSOME_GRAPHCMS_TOKEN
        }
    })
    const {posts} = res.data.data
    if (posts) {
      const contentType = addContentType({
        typeName: 'Posts',
        route: '/posts/:slug'
      })
      posts.forEach(post => {
        contentType.addNode(post)
      })
    }
  })
}

addNode に追加したやつから自動でschemaを作ってくれて page-query とかから取得できるようになる。

axiosでGraphCMSのデータ取得

API Explorerでこんなクエリで取得するやつ

{
  posts {
    title
  }
}

jsから

const endPoint = "https://api-apeast.graphcms.com/v1/xxxxxxxxxxxxxx/master"
const authToken = "xxxxxxxxxxxx"
const res = await axios.get(endPoint, {
  params: {
    query: `query {
      posts {
        title
      }
    }`
  },
  headers:
    {
      Authorization: authToken
    }
})
console.log(res.data)

※ フロントから叩く場合はfunctionsとかかませてtokenは環境変数で。

Nuxtプロジェクト内で使われてないコンポーネントを探す

  • プロジェクトが進むと役目を終えた使わないコンポーネントが出てくる
  • 放置していくとどれが使っててどれが使ってないかわからなくなってくる
  • 使わなくなったコンポーネントの代わりに作られたコンポーネントの名前が似てると最悪みがある
    • 「このコンポーネントだろう」と思って変更してみたら「残念!そっちじゃありません!」みたいなやつ
  • 使わなくなったタイミングで削除するのがベストだけどそうもいかないのが現実

という感じで、使われなくなったコンポーネントを削除したい。

使われなくなったコンポーネントを見つける

webpackのプラグインでビルド時に使われていないコンポーネントが探せる。

unused-files-webpack-pluginを使って一覧を出す

github.com

nuxt.config.jsbuild.plugins に追記する。

const { UnusedFilesWebpackPlugin } = require('unused-files-webpack-plugin')

export default {
  // 省略
  build: {
    plugins: [
      new UnusedFilesWebpackPlugin({
        patterns: ['src/**/*.vue', 'src/**/*.js']
      })
    ],
  }
}

patterns はビルド時に使われてないファイルをフィルターするオプション。

['src/**/*.vue', 'src/**/*.js'] を指定すると、 src/ ディレクトリ内でビルド時に使われてない .vue.js ファイルが一覧で出力されるようになる。

build の実行

nuxt build を実行すると、次のような出力が得られる。

...

Entrypoint app [big] = aaa5230fc2fc8d2d7264.js a4af7f6bc00ce5633bbf.js b2deabd0e786c068c1e3.js 9d7368b9e3e8d6ddd2a4.js

WARNING in 
UnusedFilesWebpackPlugin found some unused files:
src/components/lp/AppFooter.vue
src/components/lp/ShareButtons.vue
src/components/lp/SocialLinks.vue
src/components/organisms/AppFooter.vue
src/components/organisms/AppPage.vue
src/modules/generate_route.js

...

ここに出てきたファイルを ビルド時に使われてない = 不要 とみなして削除。

実際は使ってないけど import されてるファイルは出てこない

使わなくなったけど、使われているコンポーネントから import されてる場合、使われてないファイルとしてはでてこない。

たとえば次のような場合

<script>
import AppFooter from '~/components/lp/AppFooter'
export default {
  layout: 'lp'
}
</script>

AppFooter は使われてないけど import しているコンポーネントが使われているのでunusedではなくなる。ESLintなりでチェックして潰していきましょう

Nuxtプロジェクトじゃなくても

unused-files-webpack-pluginは名前の通りただのwebpackのプラグインなので、webpackでビルドしてるプロジェクトなら使えます

開業届を出しました

会社はやめてません。

副業はじめてました

半年前くらいから継続してやってく副業をやりはじめて、本業と並行して続けていけそうだったので開業届を出しました。

屋号は技術書典のときに使ったサークル名から「PONYHEAD」にしました。

現状2案件を受けてるので直近では受けられないですが、タイミングとご縁があったらお仕事のご相談まっております。

やってる(やってた)こと

本業と同じくフロントエンドをやってます。JavaScriptが書きたいのです。

ウェルプレイドではWELLPLAYED JOURNALというesportsに関するメディアのお手伝いをしてます。esportsに関わる仕事やりたいな〜と思ってたので楽しくやっております。

※ 2019年半ばくらいで契約終了しました。

wellplayed.media

ROXXではback checkというリファレンスチェックを行う新規サービス開発のお手伝いをしてます。HRテックに興味もあり、VueでごりごりSPAが書けて楽しいです。

backcheck.jp

エンジニア募集してるらしいです。

社会性を取り戻す戦い

フルリモートな会社に勉めて6年目になるんですが、どんどん外に出る回数も少なくなりこりゃいかんなと思い始めてたので、人との接点が増えて今のところよい感じです。

本業+副業2つという感じなのでわりとパツパツで時間の管理が大変ですが、その分だけ収入が増えたので頑張りたい所存です。

収めるぞ税を。

宇田川町あたりで作業してる日があるので渋谷近辺の人はランチのお誘いお待ちしております。

Vue.jsのrender関数(JSX)に思いを馳せた結果

この記事はVue.js #2 Advent Calendar 2018の18日目の記事です。

Vue.jsを使った開発では、特別な理由がない限り.vueファイルで記述するのが主流かと思います。.vueの場合、テンプレートの定義は<template>で行うことになるでしょう。

自分も何の疑問が湧くことなく<template>を使っていましたが、ある日ふとrender関数に思いを馳せ、いくつかの個人プロジェクトで試してみました。

本記事では、その試行錯誤から得たrender関数についてのあれこれを記しています。

<template>コンパイルされるとどうなるか

render関数の前に、まずは<template>コンパイルされるとどうなるかについて目を向けてみます。

.vue<template>コンパイルした結果どのように変換されるのか、あまり知らずにVue.jsを使っている方もいるかと思います。意識せずとも使えますし、別に知らなくても特に問題となるようなものでもありません。

<template>createElementを使った関数になる

たとえばApp.vue<template>を次のように定義します。

<template>
  <div id="app">
    <HelloWorld/>
  </div>
</template>

これがコンパイルされると、次のような関数に変換されます(見やすいように整形してます)。

var Appvue_type_template_id_54d52fb2_render = function() {
  var _vm = this;
  var _h = _vm.$createElement;
  var _c = _vm._self._c || _h;
  return _c("div",
    {
      attrs: {
        id: "app"
      }
    }, [_c("HelloWorld")], 1);
};

このように<template>createElementでVDOMを作成する関数へと変換されます。

変数名のAppvue_type_template_id_54d52fb2_renderから、これがApp.vue<template>renderにしたもの、と読み取れます。

renderといえば、render関数ですね。

render関数の基本

render関数は<template>と同じく、Vueコンポーネントにテンプレートを定義するためのものです。

簡単なコードは次のような感じになります。

export default {
  data() {
    return { msg: "hello render function"}
  },
  render(h) {
    return h("div", {}, this.msg)
  }
}

render関数は引数にcreateElementを受けるので、それをhという名前にして使うのが一般的な作法です。

render関数がコンパイルされるとどうなるか

render関数で定義したものをコンパイルするとどうなるでしょう。

次のrenderは前述した<template>の例をcreateElementを使ったものに置き換えたやつです。

export default {
  render(h) {
    return h("div", {
      attrs: {
        id: "app"
      }
    }, [h(HelloWorld)]);
  }
}

これをコンパイルすると次のようになります。

var Appvue_type_script_lang_js_ = ({
  render: function render(h) {
    return h("div", {
      attrs: {
        id: "app"
      }
    }, [h(HelloWorld)]);
  }
});

コンパイルされる前と一緒になりました。render関数でcreateElementを使って定義されたテンプレートは、変換の必要がない(そのまま実行できる)ということになります。

【ネタ】ビルド速度を突き詰めるとcreateElement!?【真似しないで】

これは計測もしてない完全な推測ですが、いろいろなものを犠牲にしてもいいなら、ビルドの速度を速くするだけのため<template>を捨ててcreateElementにする、みたいなのも考えられるかもしれません。

考えられないし絶対やらないですけど。

宣言的vs命令的

.vue<template>は宣言的にテンプレートを記述できるのが特徴であり、一つの利点です。render関数はこれと逆を行くもので、関数によってDOMを組み立てるように命令を記述します。

では命令的な記述が必ずしも宣言的なテンプレートに劣っているか?と言われると全くそうではないと思います。それぞれにメリデメがありますし、何を選択するかは使う人に委ねられているでしょう。

ただしcreateElementをそのまま使ってテンプレートを定義するのは実用に耐えるものではない(めんどくさいし読みづらい)と思います。

createElementは現実的じゃないけどJSXは結構いける

render関数ではJSXが使えます。JSXでの記述は、createElement以上<template>未満レベルで宣言的であると思います。

ちなみに、Vue CLI V3で作成したプロジェクトはBabelのプリセットに@vue/appが指定されていて、この中にJSXを使うのに必要なものが入っているので、パッケージの追加インストールなしにJSXが使えます。

export default {
  render(h) {
    return <div id="app">
      <HelloWorld/>
    </div>
  }
}

JSXを使ったrendercreateElementに変換される

render関数でcreateElementを使った場合は、コンパイルされても変化はありませんでしたが、JSXを使っている場合はcreateElementを使った関数に変換されます。

次のコードは上記JSXの変換結果です。

var Appvue_type_script_lang_js_ = ({
  render: function render(h) {
    return h("div", {
      attrs: {
        id: "app"
      }
    }, [h(HelloWorld)]);
  }
});

前述したcreateElementを使ったrender関数と同じものに変換されました。

render with JSXの可能性を探る

「VueでJSX使うくらいならReact使えばよくない?」みたいなことを何度も見たり聞いたりしますが、そんな単純な話ではないと思います。

Vueの書き味やエコシステムといった部分に乗っかりつつ、要所要所でテンプレートをJSX(render関数)で書くのは何もおかしいところはないと思います。

JSX(render関数)の可能性を探るために、<template>を使わずにJSXだけを使ってアプリケーションを作成してみました。そこから得た知見?と感想をまとめておきます。

JSXとcreateElementは共存できる

属性やイベントを細かく指定したい場合、JSXで書くよりcreateElementのほうが記述しやすい場合があります。JSXとcreateElementは共存できるので、次のような書き方もできます。

render(h) {
    return <div id="app">
      <HelloWorld/>
      {h("div", {}, "hoge")}
    </div>
  }

JSXで書いているとピンポイントでcreateElementを使いたい場面もでてくるかと思いますので、覚えておいて損はないです。

renderでしかできないこと

renderではできて、<template>ではできないことがいくつかありました。

componentsに登録せずコンポーネントを使える

importしたコンポーネント<template>で使う場合、componentsまたはVue.componentで登録しないと使えません。

render関数はJavaScriptのスコープにいるので、importしたコンポーネントは登録せずに使うことができます。前述しているrender関数の例ではHelloWorldコンポーネントを使ってますが、componentsに登録せずに使っています。

import HelloWorld from './components/HelloWorld.vue'
export default {
  render(h) {
    return <div id="app">
      <HelloWorld/>
    </div>
  }
}

使うコンポーネントが増える度に、わざわざcomponentsに登録する手間がrenderではありません。

別ファイルの定数をそのまま使える

前述したコンポーネントと同じ話ですが、別の.jsファイルに定義した定数をコンポーネント内で使う場合、computeddataに割り当ててからでないと<template>からは参照できません。

render関数ではimportした値はそのまま使えます。

import constants from './constants'
export default {
  render(h) {
    return <div id="app">
      {constants.message}
    </div>
  }
}

イベントなどをすべて定数にする

<template>@customEventな記法をするときに、このcustomEventの値を変数を参照する形で定数にしたい、と思っていろいろ試したができませんでした。

render関数では次のように記述できます。

import Channel from "../components/Channel.vue"
import types from "../store/types"
import events from "../variables/events"
export default {
  name: "Channels",
  render(h) {
    return h(Channel, {
      class: "Channel",
      on: {
        [types.REACTION_TO_MESSAGE]: this.reactionToMessage,
        [events.CLICK_REACTION]: this.reactionToMessage,
      },
    })
  },
  // ...省略
}

$emitdispatchなどに使うイベント名を定数にして、テンプレートで同じ値を参照して使うようにできます。

<template>ではcomputedでオブジェクトを返してv-onに指定することでできなくもないが、これ以外の方法があれば教えて欲しい。)

render propで<div>を挟まない

HOCに代わるパターンとしてrender propが市民権を得つつあります(もう得た?)。

Vueでrender propをする場合、スコープ付きスロット(scoped slot)を使うことになりますが、<template>はルート要素として<slot>を許容しないので、<div>で挟む必要があります。

render関数であれば、次のように記述することで綺麗にrender propできます。

render(h) {
  return this.$scopedSlots.default({
    message: this.message,
  })
}

すべてはJavaScript

<template>を使わずに書いていると、<style>も削れないかな?と思ってしまうのが人間。

そんな願いを叶えてくれるのがvue-styled-components

github.com

JSX+vue-styled-componentsを使うと、もはや.vueにする必要もなく.jsですべてを記述できます。

import styled from 'vue-styled-components'
import HelloWorld from './components/HelloWorld.vue'

const Wrapper = styled.div`
  padding: 1em;
  font-size: 1.5em;
  text-align: center;
`

export default {
  render(h) {
    return <Wrapper>
      <HelloWorld/>
    </Wrapper>
  }
}

ただし、ここまで来るとさすがに「これVueでやる必要あるか〜???」という声が自分の中から聞こえてきます。

(この組み合わせ、別に推奨してるわけじゃないです。)

Vue 3.0が来たらワンチャン?

Vue 3.0ではTypeScript対応が強化されるとのことなので、.tsxで書くのがわりと普通な状況も来そうだなと予想しています。そうなるとJSX+vue-styled-componentsも候補にあがってもおかしくないのかなと思います。

おわりに

いろいろと書きましたが、Vueのrender関数(JSX)に対する印象が少しでも変わったなら幸いでございます。

Nuxt.jsが気になるならNuxt.jsビギナーズガイドを読めばいいと思う

f:id:nakajmg:20181110032919j:plain

Nuxt.jsビギナーズガイドを著者の@potato4dさんよりいただきましたので、読んでみての客観的な感想を記しておきたいと思います。

Nuxt.jsビギナーズガイド―Vue.js ベースのフレームワークによるシングルページアプリケーション開発

Nuxt.jsビギナーズガイド―Vue.js ベースのフレームワークによるシングルページアプリケーション開発

ちなみますと、自分のNuxt.js経験は0.10系からで、個人/業務を問わず採用した経験があります。

超実践的ビギナーズガイド

まずこの本を一言で表すとしたら超実践的ビギナーズガイドです。

本書ではフレームワークの解説にありがちな「それドキュメント読めばよくない?」的な、機能を羅列して紹介するようなことをしていません。一貫してアプリケーションを作りながら機能を覚えていくというスタイルを取っており、手を動かせば動かしたぶんだけ強くなれるような内容になっています。

作っておしまいではなく、アプリケーションをデプロイする方法についても数パターン紹介されています。

また、Nuxt.jsだけではなく、FirebaseやJestといった、実際に使う機会が多そうなライブラリも一緒に学べます。

Nuxt.jsのポテンシャルを知れる

Nuxt.js公式のAPIのドキュメントを見るとわかるように、Nuxt.js独自の機能はそこそこ数があります。しかしながら、これら機能の中にはドキュメントを読んだだけでは便利さに気づけないような機能もあります。

自身の経験として、Nuxt.js使い始めのころは「middlewareってこれいつどこで必要になるの?誰向け?」な状態で、Nuxt.jsの持つポテンシャルを十分に理解していませんでした。middlewareの強さは、実案件で必要になった機能を実装するのにあれやこれやと調べたうえで使ってみてやっとのことで理解しました。

本書ではパブリックなAPIからデータをfetchして表示したり、認証の機構を追加したり、プラグインを使ってみたりと、実際に作りがちなアプリケーションを例にNuxt.jsの機能を解説しています。その過程で「こんな機能を実装したい場合にはNuxt.jsのこれを使えばよくて実装方法はこうですよ」というのを簡潔に、段階的に理解できます。

本書を読みきればNuxt.jsの全容をほぼ知っている状態になれると思います。

テストも書けるようになる

本書ではVueコンポーネントやVuexストアについてのテストについても書かれています。これらテストについては、本質的にいうとNuxt.jsではなくVue.jsのテストですが、どういった指針で何をどうテストするかについて、コンパクトにまとまった内容で学べます。

Nuxt.jsを使ったプロジェクトをはじめるとき、もしVueコンポーネントのテストを書いたことがない人がいても、本書を読んでもらえばきっと大丈夫です。

個人的お気に入りチャプター

テストについて書いてあるのもビギナーズガイドらしからぬ(?)ポイントでとてもよいのですが、自分の個人的なお気に入りは最終チャプターの「最新情報キャッチアップのススメ」です。このチャプターは次のような内容になっています。

  • 関連情報のキャッチアップ方法
  • ドキュメント翻訳への貢献方法
  • 関連するSlackやDiscordチャンネルの紹介

ライブラリやフレームワークは1回覚えておしまい、とはいかないのが現実です。更新に合わせて新しい機能を調べたり、困ったときに検索したりと、都度都度アクションが必要になります。しかし情報にアクセスする方法と、その必要性に気づけないままだと、そういったアクションも起こせません。

最終チャプターでこの道標を提示することで自走できるように後押しをする、そんな著者の気づかいが表れているかのようなチャプターです。本書の底本でもある「Nuxt tech book」でも同様の内容について触れられていますが、これを商業本の単独チャプターとして乗せる心意気にあっぱれでございます。

ちょっとでもNuxt.jsに興味があるならオススメ

はじめに触れたとおり、本書はNuxt.jsの超実践的なビギナーズガイドです。もしNuxt.jsを使ってみようかなと思ったら、まずは本書を読みながら一通りの機能を試してみてください。

本書を読んだあとにNuxt.jsを実戦投入すれば、まるで強くてニューゲームのような状態で開発に臨めるでしょう。そんな本でした。

Nuxt.jsビギナーズガイド―Vue.js ベースのフレームワークによるシングルページアプリケーション開発

Nuxt.jsビギナーズガイド―Vue.js ベースのフレームワークによるシングルページアプリケーション開発

入門者じゃない人にこそ読んで欲しい「Vue.js入門」

f:id:nakajmg:20181013191832j:plain

Vue.js入門を@kazu_ponさんより頂きました。ありがとうございます。

遅くなりましたが、読んだ感想を残しておきたいと思います。

Vue.js入門 基礎から実践アプリケーション開発まで

Vue.js入門 基礎から実践アプリケーション開発まで

感想の前に

自分は専業のフロントエンドエンジニアです。Vue.jsの使用歴は4年ほど。個人・案件を問わず多くのプロジェクトでVue.jsを採用した経験があるので、正直に言うと本書の対象からは少し外れてるかなと思います。

それでも本書からは得られるものがありました。

入門だけじゃない内容

タイトルこそ「入門」とついていますが、ページ数(460P)から想像できるように、カバーしている範囲がすさまじいです。

入門して終わりではなく、入門から修了までの道筋が記されています。よくある入門本にあるような「簡単な使い方はわかったけどこっからどうしたらいいの?」といった状態にはならないと思います。

整えられた情報たち

今までVue.jsで「これどうやるのかな?」と思ったときは、ドキュメントを見るか検索してそれっぽいものを探すかでした。

そうやって調べて知見を溜めていくのもいいですが、本書はそういったネット上に散らばっていたような情報が詰め込まれています。

情報を詰め込んでいるだけでなく、整理され、必要なタイミングで得られるようにしっかりと道筋が整えられています。

本書から始めると効率めっちゃいいと思います。

つまみ食いするように読める

入門する人は最初から、そうでない人は途中の章から読めるように章立てされています。

Vue.jsでSPAを作ったことがある人なら、8章からの「中規模・大規模向けのアプリケーション開発」から読んでもいいと思います。

入門する人も本書を最後まで一気に読み切る必要はなく、まずは1章から3章くらいまでを読めば、Vue.jsの基本的な使い方が把握できると思います。

個人的なオススメポイント

本書の個人的なオススメポイントはコラムです。

技術書には本線となるテーマが章ごとにありますが、コラムは本線に入れるとちょっとノイズになるような「知らなくても支障が出るものじゃないけど、知ってると周辺知識の理解が深まるもの」だと思います。コラムと合わせて前後の文章を読むことでさらに理解が深まります。

本書をすでに持っているけど読んでいないという人も、まずはコラムだけでも目を通してみると新しい発見があるかもしれません。

Vue.jsに興味があるすべての人にオススメできる圧倒的入門書

はじめにいったように、本書は入門から修了までをとてつもないボリュームでカバーし、解説しています。これから始める人も、すでに始めている人も、本書を読めば得られるものが確実にあると思います。

Vue.js入門 基礎から実践アプリケーション開発まで

Vue.js入門 基礎から実践アプリケーション開発まで

もしVue.jsに明るくないメンバーがプロジェクトに参加するようなときには本書を読んでもらえばいい、そんな本が出てきてくれて感謝の極みです。