VueのCDN版を使いつつ、TypeScriptの型定義も反映させたい

  • 既存のTypeScriptプロジェクトにnpmのvueいれて import {createApp} from 'vue' でimport
  • createApp({}).mount("#app") でマウント

#appの中身が空っぽになってしまう。

CDN版だとDOMの中身を保ったままVueアプリ化されるんだけど…挙動が違った。

もともとCDN版を使おうとするも型定義どうしたらよいのかわからず諦めて、npmのvueいれた…という経緯があったが…。 なにか足りない手順とか、読み込むもの間違っているとかあるんだろうか。

結局CDN版をつかいつつ、どうにか型定義読み込む形でいくことに。

解決手順

あまりTS+Vue CDN版で一部だけVue化したい…というニーズはないのか、情報少なくかなり悩んだ。

  • 型定義のためにnpmパッケージのvueをインストールして変数にimport
  • interface WindowにVueを追加し、importしたvueの変数からtypeofを用いて型を指定
import * as vueProps from 'vue'
declare global {
  interface Window {
    Vue: typeof vueProps
  }
}
export const fetchVueCDN = (): Promise<typeof window.Vue> =>
  new Promise((resolve, reject) => {
    if (window.Vue) resolve(window.Vue)
     const prod = typeof env !== 'undefined' && env === 'prod' ? '.prod' : ''
    const s = Object.assign(document.createElement('script'), {
      src: `https://cdn.jsdelivr.net/npm/vue@3.2.20/dist/vue.global${prod}.js`,
    })
    s.addEventListener('load', () => {
      resolve(window.Vue)
    })
    document.body.append(s)

    setTimeout(() => {
      reject('Vueの読み込みがタイムアウトしました。')
    }, 30000)
  })

あとはこれで、CDN版使いつつ補完もきくようになった

;(async () => {
  const Vue = await fetchVueCDN()
  Vue.createApp({template:'msg:{{msg}}',setup(){return {msg:"テキストが入ります。"}}}).mount('#app')
})()

参考:

TypeScript - TypescriptでimportせずにVue.jsを使う方法|teratail

余談

気軽にCDN版つかお~と思っても、TypeScriptプロジェクトではそうはいかないということに気付かされた…。

Vueの用途はこれまでjQueryでちょこちょこやってた処理の置き換え、程度にとどまっていて vue-cliでのプロジェクト生成などはまだ試したことない。知識も浅い。​.vue 使うの気が進まないんだよななんとなく…。
フルでjsフレームワークのSPAつくるというのなら、どっちかというとReactが気になるしね。

途中解決法がわからずReactいれたら、そちらはシンプルにReact,ReactDOM+その型定義をいれるだけで思った通りに動いたので、このままReact使用に移行しようと思ってた。
気持ち悪くて結局解消するまで調査していたけど…。 Reactやろうと思えるきっかけができたのはよかった。

いちいちつまづいて大変だ。フロントエンド学習身に余るなあ…。