Nuxt3でplotly.jsを自前でコンポーネント化したい!
はじめに
そこのお前!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より前の場合はそちらもアプデ必須
次にコンポーネント実装
<template>
<div :ref="id"></div>
</template>
<script setup lang="ts">
import Plotly from 'plotly.js-dist-min'
import type { Data, Layout, Config } 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 {
data: PlotlyData
layout?: PlotlyLayout
config?: PlotlyConfig
}
const props = defineProps<Props>()
const id = uuidv4()
const graphObj = useTemplateRef<HTMLDivElement>(id)
const setGraph = async () => {
if (!graphObj.value) return
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()
},
{ deep: true },
)
</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.ts
にssr: false
を設定する
ここtrueで扱いたい場合は調べてません(SPAでしか作ることない人なので…)
global is not defined
plotly.js-dist-min
でなくplotly.js
を使っている可能性アリ
そもそもplotly公式も手順でdist-min
の方を使ってる(ぎとはぶ)
この2つのパッケージの違いは正直サイズ以外調べてもよく分からなかったのでChatGPTくんの回答を載せておきます
plotly.js と plotly.js-dist の違いは主にパッケージサイズと用途に関係しています。
- plotly.js
- このパッケージは plotly.js のソースコード全体が含まれたもので、通常の開発環境やモジュールシステムで使用されます。
- 多くの場合、他の JavaScript パッケージと共にバンドルされる形で使われるため、構成ファイルや依存関係の細かな管理が可能です。
- 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のバージョン一度も更新されてないって感じだったので、今回の記事を書くことに至ったのであった……