ハダノ元教頭が GIGAスクール と DX人材育成 について考えるブログ

持続可能なブログ作り
プログラミングWeb標準Vue.js

持続可能なブログ作り

🕓 3/25/2024 ↻ 5/24/2024

 この記事では、

のその後について述べます。

2年前に作ったブログを Vue3+Nuxt3+NuxtContentV2 に移行してみた

高度情報技術

技術の急速な進歩で、ブログの引っ越しがたいへんなことに!

 🔗「生成AI用にデスクトップPCを追加購入した件」 で述べたように、ノートPCでやっていたことをデスクトップPCでもできるように頑張りました。

 データは 🔗パーソナルクラウド にバックアップしていました。

 プログラムは、重要なものから順にインストールしていきました。ブログも早く引っ越したかったのですが、子ども食堂タブレット教室への影響を考え、春休みを「ブログメンテナンス期間」としました。


 ブログシステムは、記事データをデスクトップPCに移しただけでは動きません。Vue.jsNuxt.js などのプログラムをインストールする必要があります。

 2年前と同じ要領でやってみましたが、エラーの嵐に打ちのめされました。

エラーの嵐

 どうやら、この2年間で開発環境が様変わりしていたようです。

  • Vue2 → Vue3
  • Nuxt2 → Nuxt3
  • Nuxt Content → Nuxt Content V2

 おまけに、インストールコマンドまで変わっていました。たった2年間で浦島太郎です。


Vue はオワコンなのか?

 そのままインストールすると最新バージョンになって動かないのなら、古いバージョンを指定してインストールすれば動くかもしれません。ただ、これは持続可能ではありません。Vue2 の公式サポートが2023年で終了したからです。

を読むと、お先真っ暗な感じです。

 それでも、Vue + Nuxt を捨てて、React + Next へ鞍替えしようとは思いません。乗り換えは最後の手段です。

 冷静になると、

  1. Vue3,Nuxt3 を新しいフレームワークだと思って学ぶ。
  2. Vue2,Nuxt2 と似ている部分は、慣れている分だけラッキーと考える。
  3. 現行システムのロジックをベースに Vue3,Nuxt3 で書き直す。
  4. モジュール対応が遅れていれば、代替手段を模索する。
  5. それでもだめなら、旧バージョンでしのぎつつ、React等への移行を検討。

、、、と方針が固まってきました。

Vue3,Nuxt3

Vue3,Nuxt3 を学び、現行システムを書き直してみる

 新・旧の書き方が混在した解説資料が多い中、

ならば、Nuxtバージョンv3.5.2、全編Composition API + script setupを使用……とあるので大丈夫そうです。

// pages/articles/_slug.vue 【 旧バージョン 】
<script>
  export default {
    async asyncData ({ $content, params, redirect, store }) {
      const content = await $content('articles').where({ path: '/articles/' + params.slug }).fetch()
      if (content.length > 0) {
        return {
          content: content[0],
          contenturl: store.state.baseurl + content[0].path,
          imgurl: store.state.baseurl + '/img/' + content[0].thumbnail
        }
      } else {
        redirect('/articles')
      }
    },
    head () {
  ・・・・・・
      ↓

// pages/articles/[slug].vue 【 新バージョン 】
<script setup>
  const route = useRoute()
  const path = route.path
  const { data: content } = await useAsyncData(path,() => queryContent(path).findOne())
  const h1title = content.title
  const formatDate = (date) => new Date(date).toLocaleDateString()
  const contenturl = useBaseurl() + content._path
  const imgurl = useBaseurl() + '/img/' + content.thumbnail

  useHead({
  ・・・・・・

、、、比べてみると、ずいぶん書き方が違います。ファイル名も _slug.vue[slug].vue と変わりました。

 use で始まる Composables関数 は、Nuxt3 側が用意してくれたものが大幅に増えたうえに、簡単に自作してどこでも使えるようになりました。 → 🔗Nuxt3の本気を見た~Composablesの可能性~


ページの構成をすっきりさせてみる

 これまでは、次のようになっていました。

pages
 ├ articles
 |  ├ page
 |  |  └ _id.vue
 |  ├ index.vue
 |  └ _slug.vue  ⇒ 各記事表示用ページ
 ├ category
 |  └ _slug
 |      ├ page
 |      |  └ _id.vue
 |      └ index.vue
 ├ tag
 |  └ _slug
 |      ├ page
 |      |  └ _id.vue
 |      └ index.vue
 └ index.vue

 _slug.vue 以外の7つのvueファイルは、記事一覧表示用なので基本的なつくりは同じです。

 それでも、categorytag など 🔗リテラル を打って各動作を指定する必要があったため、別々に作っていました。前回、「layout は、うまく使えず、原因不明のままです。……」となっていましたが、今回は何とかしたいものです。

 処理を分ける際のネックとなっていたのが、オブジェクトのキーの指定です。

 を読んでやってみたら、リテラル を打たなくてよくなりました。

// pages/category/_slug/page/_id.vue
  async asyncData ({ store, $content, params, redirect }) {
    const ipp = store.state.indexPerPage
    const h1title = store.getters.getCategoryTextBySlug(params.slug)
                                  // Categoryテキスト取得専用メソッド
    ............
    const content = await $content({ deep: true })
      .where({ category: { $contains: params.slug } })
                    // リテラル【 category 】をObjectのKeyに指定
      .sortBy('createdAt', 'desc')
      .skip(pfrom).limit(ipp)
      .fetch()
  ・・・・・・
        ↓

// pages/category/[slug]/page/[id].vue
 ......
  const ipp = useIndexPerPage()
  ......
  // コンテンツの種類による場合分け
  if (route.params.slug) {
    if (mapCat.get(route.params.slug)) {
      parent = 'category'
      child = route.params.slug
      h1title = mapCat.get(child)   // 連想配列からCategoryテキスト取得
    } else {
      if (mapTag.get(route.params.slug)) {
        parent = 'tag'
        child = route.params.slug
        h1title = mapTag.get(child) // 連想配列からTagテキスト取得
      }
  ............
  const { data: contents } = await useAsyncData(rpath,() => queryContent('articles')
      .where({[parent]:{$contains:child}})
                   // 【 [変数] 】でObjectのKeyに変数展開
      .sort({createdAt:-1, $numeric:true})    // 日付を数値順でソート
      .skip(pfrom).limit(ipp) 
      .find()
  ・・・・・・

 これで、7つのVueファイルのコードを共通化できます。layouts フォルダに listing.vue として保存し、index.vue[id].vue は次のように書いておけばよいのです。

<template>
  <NuxtLayout name="listing"> 
    
    ※ listing.vue の <slot /> に差し込む中身があれば書く

  </NuxtLayout>
</template>

 結果的に、7つのVueファイルは同じものになりました。コードを修正するときは、listing.vue だけをいじればよく、保守性がアップしました。


デプロイに四苦八苦

 ブログシステムがだいたい動くようになったので、デプロイ(ネットにアップ)してみることにしました。

 「 GitHubのリモートリポジトリにプッシュ → Cloudflare Pages に自動デプロイ 」という設定にしていたので、更新は楽でした。

 ところが、「Cloudflare PagesとGitHubのリポジトリを連携させ、接続するGitリポジトリを選んで……」という手順で、今回の新しいリポジトリを選択しようとしましたがうまくいきません。どうやら、いったんプロジェクトを削除してやり直すしかないようです。削除を試みましたが、エラーでそれもできません。『最初が肝心』と思い知らされました。

アップロード失敗

 次の手として、「前のGitHubリモートリポジトリをクローンしてローカルリポジトリを作り、そこに新しいブログシステムを移す」ことにしました。

  • 「ローカルリポジトリに前のデータがあるけど、新しいプログラムをインストールするときに邪魔になるかな?」
  • 「マークダウンファイルや画像ファイルは邪魔にならないはずだから、残しておいていいのでは?」
  • 「あれれ?! インストールしようとしたら、'空っぽのフォルダじゃないとダメ'って怒られた!」
  • 「でも、空っぽにしたら、リモートリポジトリにプッシュできなくなるのでは?」
  • 「あーー 詰んだ、、、、」
詰んだ

 あきらめの悪いハダノは、

という記事を見つけ前を向こうとしますが、--overwrite-dirフラグが廃止されたと知ってガックリ。そもそも create-nuxt-app は、Nuxt2 時代のものでした。

 「もしや、Nuxt3 のインストールコマンド npx nuxi init に何かないか?」と思って 🔗Nuxt公式ページ を見ると、

--force 〔Force clone to any existing directory.〕 というオプションがあるではありませんか。

 最終的に、

1. GitHubのリモートリポジトリをクローンし、.gitフォルダ 以外を削除。
2. 親フォルダへ移動し、Nuxtプロジェクトを上書き作成(content も同時に)。
  > npx nuxi init プロジェクト名 --force -t content
  ☑npm
3. gitリポジトリは初期化せず、既存のものを使う。
  > Initialize git repository?
  □Yes / ☑No
4. モジュール(@nuxtjs/google-adsense, @nuxtjs/seo)をインストール。
5. だいたい動くプロジェクトからファイルをコピー(.nuxt, node_modules以外 )。
6. nuxt.config.ts等を修正し、npm run dev で動作確認。
7. GitHubへコミット・プッシュ。
8.Cloudflare Pages デプロイの詳細-ビルドログを確認。

という流れで、やっとデプロイにこぎつけました。

 ビルド コマンド:npx nuxt generateNODE_VERSION20.11.0 などの変更をし、

🔗ビルドエラー回避のため、nuxt.config.ts に 以下を加えました。

  nitro:{
    prerender: {
        failOnError: false,
        },
  },

 開発環境では動いたのに、本番環境では動かず(リロードが必要)、useAsyncData のキャッシュ制御を見直す一幕もありましたが、何とか予定したものができあがりました。


【2024/5/24追記】Pre-transform error

cd c:\nuxth\nuxthblog
npm run dev
cmd /k

 いつものバッチファイル(rundev.bat)でエラーが出たので調べると、

という報告があがっていました。

  • nuxt.config.ts の modules に '@nuxt/devtools', を追加
  • ターミナル(管理者)つまり PowerShell を 起動して実行

で、とりあえずエラーは消えました。


【振り返り】持続可能なブログ作り のため 学び・作り続けよう

 「今動いているシステムをバージョンアップするだけだから、一から作るより楽だろう」という考えは甘すぎました。

 持続可能なシステムとは、「ピラミッドのように堅固なもの」ではなく、「自転車のように動いているもの」だと知りました。

 世界は常に変化しています。完璧に見えるピラミッドも風化していきます。状況に対応しながら走り続ける自転車でありたいものです。そのためには、「学ぶ」「作る」というペダルをこぎ続けるしかありません。

ピラミッドと自転車

 今回、さまざまなエラーに苦しみながら実感したことは、「問題の切り分け」の大切さです。

  • JavaScript(Node.js) の仕様の問題
  • Vue3 の仕様の問題
  • Nuxt3 の仕様の問題
  • NuxtContentV2 の仕様の問題
  • GitHub, Cloudflare Pages の仕様の問題
  • その他の問題

、、、それぞれのレベルごとにバージョン間の互換性はあるので、新しいものが出たからといってすぐに移行しなくてもよさそうです。ただし、年代ごとに想定している環境があるので、ある程度そろえる必要があります。

 例えば、JavaScriptの関数を定義する方法として、「function宣言」のほかに「アロー関数」が出てきました。現在、どちらも使用可能ですが、Vue2:function宣言 ⇒ Vue3:アロー関数 と移り変わっています。参考資料に出てくるコードを理解して利用するためには、古いやり方に固執してはいけません。逆に、新しい書き方を有効にするために、Node.js のバージョンを上げる必要も出てきます。

Nuxt3による開発

ブログシステム移行で参考にした記事

、、、実際にやってみて、記事の時点とは状況が変わっていたものも多かったのですが、基本的な考え方は身につきました。

 Vue2,Nuxt2 に慣れた人からすると「破壊的変更」かもしれませんが、Vue3,Nuxt3 になって「素のJavaScript」に近づいた感じがします。ネストが浅くすっきり書けるので、言われるほど悪くありません。それどころか、もっと新しい書き方を試してみたくなります。


これからも改良を

 自前のブログシステムなので、使っていきながら改良していきます(自転車操業になるかも?)。中身が全部わかっているというのは、安心です。

 これからも応援よろしくお願いします。



※ タイトルと価格だけ見ると、Nuxt2の運用経験のあるハダノには不要な本なのかと思いました。
実際に購入してみると、Nuxt3ブログの具体的な作り方が過不足なく載っていて、非常に参考になりました。
Nuxt3の本は多くないので、貴重な存在です。


※ ハダノがずっと購読している隔月刊のプログラミング雑誌です。
流行をおさえているので、最近はPythonの記事が多めですが、3月号と5月号にはJavaScriptの特集がありました。
アロー関数・Mapオブジェクト・スプレッド構文などの解説には目を開かされました。


←前へ Nuxt+Content+Cloudflareで無料でブログを作ってみた


教育DXブログの著者: ハダノ
ハダノ顔 Q大理学部生物学科数理生物学研究室にて分子進化学権威の宮田隆氏のもとFORTRANでDNA解析に没頭。F社のSEに内定していたが、科学のおもしろさを教えるため中学校理科教員を選択。
 新任のころから、「答えのない問題を追求させたい」「団結力と文化的な力を集団づくりで」「教育研究をもっと科学的に」「教育の情報化が必要」「チョーク&トークの注入式授業からアクティブラーニングへ」「教科横断的なSTEAM教育で生涯学習・SDGsへ」という思いを持ちつつ、4市10校にて勤務。
 9年間の教頭時代、さまざまな不条理・矛盾に悩み、ICTによる働き方改革を推進。2021年3月定年退職。「特定の学校だけでなく、広く人材育成を」「日本陥没をDXで食い止めたい」「元教員の自分にできることを」と、教育DX研究の道へ。
 おおいたAIテクノロジーセンター会員。デジタル人材育成学会・日本STEM教育学会・日本情報教育学会・データサイエンティスト協会・日本RPA協会の会員。JDLA G検定 2022 #1 合格者。
プライバシーポリシー  |  Copyright © 2022 HADANO