Nuxt3でplotly.jsを自前でコンポーネント化したい!

2024-11-02

はじめに

そこのお前!nuxt-plotlyはほとんどメンテされてる感じしないしあまり使いたくないな、直接plotly扱いたいな、と思ってここに辿り着いたな!?

ここではお手軽にplotlyを自前でコンポーネント化してNuxt3プロジェクトで使う方法を紹介するぜ!

経緯

  • nuxt-plotlyはあまりメンテされてなさそう
  • 新しめのNuxt(^3.12.0)でnuxt-plotlyの内部エラーが出て使えなかった
  • nuxt-plotly内のplotlyバージョンも古いまま
  • じゃあもう直接plotly.js使って自分でコンポーネント化しちまおう!

環境

  • nuxt 3.13.2
  • vue 3.5.12 ←このマイナーバージョン重要
  • plotly.js-dist-min 2.35.2 ←単にplotly.jsでなくdistが付いてるの重要
  • @types/plotly.js-dist-min 2.3.4
  • uuid 11.0.2

Vue 3.5を使う理由

Nuxt(Vue)で直接plotlyを使うには

<template>
  <div ref="obj"></div> <!-- ここと -->
</template>
​
<script setup lang="ts">
import Plotly from 'plotly.js-dist-min'
import type { Data, Layout } from 'plotly.js-dist-min'const obj = ref<HTMLDivElement>()  // ←ここconst data: Data = [...]
const layout: Layout = {...}
​
onMounted(() => {
  if (!obj) return
  Plotly.newPlot(obj.value, data, layout)
})
</script>

のように、ref属性と同じ名前でrefを定義する必要があった。

しかしこれはVue 3.5で改善され、useTemplateRef()というヘルパーを使うことで動的に命名することが可能となった。
https://ja.vuejs.org/guide/essentials/template-refs#accessing-the-refs

つまりUUIDつっこんでコンポーネント作りまくっても大丈夫な仕組みができる!

実装

まず必要なライブラリのインストールをば

  • plotly.js-dist-min
  • @types/plotly.js-dist-min
  • uuid

以上の3つをnpmやらyarnやらでインストール
使ってるVueのバージョンが3.5より前の場合はそちらもアプデ必須

次にコンポーネント実装

NuxtPlotly.vue
<template>
  <div :ref="id"></div>
</template>
​
<script setup lang="ts">
import Plotly from 'plotly.js-dist-min'
import type { DataLayoutConfig } from 'plotly.js-dist-min'
import { v4 as uuidv4 } from 'uuid'export type PlotlyData = Array<Data>
export type PlotlyLayout = Partial<Layout>
export type PlotlyConfig = Partial<Config>
​
interface Props {
  dataPlotlyData
  layout?: PlotlyLayout
  config?: PlotlyConfig
}
const props = defineProps<Props>()
​
const id = uuidv4()
const graphObj = useTemplateRef<HTMLDivElement>(id)

const setGraph = async () => {
  if (!graphObj.valuereturn
  await Plotly.newPlot(graphObj.value, props.data, props.layout, props.config)
}

// 描画領域のサイズが変化したときに、動的にグラフのサイズを調整するための設定
const resizeObserver = new ResizeObserver(() => {
  setGraph()
})
const setResizeObserver = () => {
  if (graphObj.value) {
    resizeObserver.observe(graphObj.value)
  }
}
​
onMounted(() => {
  setGraph()
  setResizeObserver()
})

onBeforeUnmount(() => {
  resizeObserver.disconnect()
})
​
watch(
  () => [props.data, props.layout, props.config],
  () => {
    setGraph()
  },
  { deeptrue },
)
</script>

若干nuxt-plotly参考にしてる
https://github.com/superdev-tech/nuxt-plotly/blob/main/src/runtime/components/nuxt-plotly.ts

そして呼び出し側

<template>
  <NuxtPlotly :data="barChartData" :layout="barChartLayout" />
</template>
​
<script setup lang="ts">
import NuxtPlotly from "@/components/NuxtPlotly.vue"const barChartData: PlotlyData = [...]
​
const barChartLayout: PlotlyLayout = {...}
</script>

……以上!

まだ試せてないけどJspreadsheet CEとかでも同様にコンポーネント化できそう

エラーが出たときは

self is not defined

 ERROR  Cannot start nuxt:  self is not defined                                                                           11:03:49
​
  at node_modules/.pnpm/[email protected]/node_modules/plotly.js-dist-min/plotly.min.js:8:229

nuxt.config.tsssr: falseを設定する

ここtrueで扱いたい場合は調べてません(SPAでしか作ることない人なので…)

global is not defined

plotly.js-dist-minでなくplotly.jsを使っている可能性アリ
そもそもplotly公式も手順でdist-minの方を使ってる(ぎとはぶ)

この2つのパッケージの違いは正直サイズ以外調べてもよく分からなかったのでChatGPTくんの回答を載せておきます

plotly.js と plotly.js-dist の違いは主にパッケージサイズと用途に関係しています。

  1. plotly.js
    • このパッケージは plotly.js のソースコード全体が含まれたもので、通常の開発環境やモジュールシステムで使用されます。
    • 多くの場合、他の JavaScript パッケージと共にバンドルされる形で使われるため、構成ファイルや依存関係の細かな管理が可能です。
  1. plotly.js-dist
    • plotly.js の事前バンドル済み版で、最小限の依存関係で動作します。
    • バンドルファイルとして提供されるため、すぐにブラウザで使える形でファイルが含まれています。
    • スクリプトタグで直接読み込んで、プロジェクトに簡単に追加する場合に便利です。

どちらを使うべきか

  • 他の JavaScript パッケージと連携しながら細かく構成・バンドルしたい場合は plotly.js を使うと便利です。
  • 一方、即座に利用したい場合や依存関係が少ない環境で利用する場合には plotly.js-dist を使うとセットアップが楽になります。

つまり「バンドル済み」 「すぐにブラウザで使える形」であるかという感じなんですかね

出てたエラーを見る感じ、何となく言いたいことは分かるかも…?

余談

何故nuxt-plotlyが上手く動かなくなっていたのか

実際にはRequested module does not provide an export named 'default'ってエラーが出る

このエラーが出ている箇所のコードを覗いてみるとimport Plotly from "plotly.js-dist-min"という部分で発生していた。
ちなみにこれはnuxt-plotlyのplugin.tsファイル

何となくだけどこれはimport * as Plotly from "plotly.js-dist-min"みたいな書き方にすれば解決しそうだなぁと思ったり。

でもリポジトリ見ての通り、プルリク投げたところであんま見てもらえなさそうだし、
plotlyのバージョン一度も更新されてないって感じだったので、今回の記事を書くことに至ったのであった……

スポンサーリンク