Vue CLIでVue.jsのプロジェクトを作成したので、手を加えてみる

f:id:ts0818:20211017153849j:plain

scienceportal.jst.go.jp

 宇宙の初期に「ちり」に隠れ、かつ星の形成が穏やかなタイプの銀河を発見した、と国立天文台などの国際研究グループが発表した。南米チリにあるアルマ望遠鏡の電波観測による成果。発見したのは2つで、1つは、ちりに隠れた銀河としては最古の131億年前のものと分かった。このタイプの銀河が多く存在したことがうかがえ、銀河の歴史を理解する上で重要な発見となった。

131億年前、観測史上最古の「ちりに隠れた銀河」発見 | Science Portal - 科学技術の最新情報サイト「サイエンスポータル」

⇧ 131億年前...

全ての世代の人間が100歳生きると仮定して、1億3100万世代の時を刻んでるわけですか...想像を絶しますな。

というわけで、今回は「Vue.js」についてです。

レッツトライ~。

 

「Vue CLI」の「vue create」で作成されたプロジェクトを確認してみる

驚き桃の木山椒の木、なんだけど、意外に、見つかりにくいのが「Vue.js」のプロジェクトを作成した後に、どう手を加えていけば良いのかって情報ですね。

手前味噌になりますが、

ts0818.hatenablog.com

⇧ 前回の記事で、「Vue CLI」を導入しております。

で、今回、確認する「Vue.js」のプロジェクトは、前回記事の中で「Vue CLI」を使って作成したものなのですが、

f:id:ts0818:20211014145303p:plain

⇧「Vue.js」と「Vue CLI」のバージョンは上図のキャプチャ画像の通りです。 

で、「Visual Studio Code」で「Vue.js」のプロジェクトを確認してみると、

f:id:ts0818:20211014145043p:plain

⇧「C:\Users\Toshinobu\Desktop\soft_work\javascript_work\hello-world\src\main.js」ってなファイルで、「Vueインスタンス」を作成していますと。

「Vueインスタンス」ってのは、

vuejs.org

Every Vue application starts by creating a new Vue instance with the Vue function:

var vm = new Vue({
  // options
})

https://vuejs.org/v2/guide/instance.html

⇧「Vue.js」の「アプリケーション」を開始するのに必要というらしいですが、「Vue instance」がいくつでも作れるのかどうかがハッキリしない...

「vue create」コマンドで作成した「Vue.js」のプロジェクトだと、「Vue instance」は1つだけっぽいけど...

「stackoverflow」の情報によると、

stackoverflow.com

⇧ 複数の「Vue instance」を作ることは可能らしい。

そして「Vue instance」の中で唐突に「render」とか出てくるのですが、「Vue.js」で用意されてる標準APIの1つらしく

vuejs.org

render

  • Type: (createElement: () => VNode) => VNode

  • Details:

    An alternative to string templates allowing you to leverage the full programmatic power of JavaScript. The render function receives a createElement method as it’s first argument used to create VNodes.

    If the component is a functional component, the render function also receives an extra argument context, which provides access to contextual data since functional components are instance-less.

    The render function has priority over the render function compiled from template option or in-DOM HTML template of the mounting element which is specified by the el option.

  • See also: Render Functions

https://vuejs.org/v2/guide/instance.html

⇧ 詳しくは、「Render Functions」を確認してくれということらしい。

まぁ、何て言うか、意味の分からん用語が出てき過ぎて、本当に「Vue.js」って「学習コスト」が低いと言えるのか謎過ぎる...。

createElement」とか「VNode」とかもよく分からんのだけど、「Render Functions」の説明を見てみると、

vuejs.org

The Virtual DOM

Vue accomplishes this by building a virtual DOM to keep track of the changes it needs to make to the real DOM. Taking a closer look at this line:

return createElement('h1', this.blogTitle)

What is createElement actually returning? It’s not exactly a real DOM element. It could perhaps more accurately be named createNodeDescription, as it contains information describing to Vue what kind of node it should render on the page, including descriptions of any child nodes. We call this node description a “virtual node”, usually abbreviated to VNode. “Virtual DOM” is what we call the entire tree of VNodes, built by a tree of Vue components.

https://vuejs.org/v2/guide/render-function.html

⇧「Virtual DOM」なる説明の中で、「Virtual DOM」の木構造の中で、全ての子の「node」を我々は「virtual node」と呼んでるんだけど、「VNode」と略してます、ということらしい。

「Virtual DOM」はと言うと、

virtual DOM is a lightweight JavaScript representation of the DOM used in declarative web frameworks such as ReactVue.js, and Elm.

Updating the virtual DOM is comparatively faster than updating the actual DOM (via js). Thus, the framework is free to make unnecessary changes to the virtual DOM relatively cheaply. The framework then finds the differences between the previous virtual DOM and the current one, and only makes the necessary changes to the actual DOM.

https://en.wikipedia.org/wiki/Virtual_DOM

⇧超ザックリ要約すると、「軽量化されたDOM」ということらしい。

「DOM」はと言うと、

Document Object ModelDOM、日: ドキュメントオブジェクトモデル)は、マークアップがなされたリソース(Document)をリソース要素(Object)の木構造Model)で表現し操作可能にする仕組み、またそのモデルである。

Document Object Model - Wikipedia

DOMは、HTML文書やXML文書(あるいはより単純なマークアップされた文章など)をオブジェクトの木構造モデルで表現することで、ドキュメントをプログラムから操作・利用することを可能にする仕組みである。

Document Object Model - Wikipedia

Documentの種類、操作に用いるプログラミング言語の種類に依存しない仕様である。

Document Object Model - Wikipedia

⇧ ということで、「HTML(HyperText Markup Language)」や「XML(Extensible Markup Language)」をプログラミングで操作できるようにする仕組みを「DOM(Document Object Model)」というらしい。

他にも「Shadow DOM」とか「Incremental DOM」とかなるものもあるらしい。このあたりも時間があれば整理したいところですね...

 

そもそもプロジェクトのディレクトリ構造って、どうするのが良いの?

まぁ、何て言うか、

vuejs.org

⇧ 公式のドキュメントで用意されてるビデオの情報によると、上記のような構造を紹介してるんですが、これを見てもどうするのが良いかがサッパリ分からんのよね...

Javaとかだと、「src/main/javaディレクトリに「パッケージ」を作成して分割していくイメージだけども、

itnext.io

vueschool.io

ディレクトリを分割するのが一般的みたい。

ただ、サイトを2つ見ただけでも、微妙に考え方は変わってたりするんで、ある程度、基本形みたいなの知りたいんですけどね...

 

vue createで含まれるVue関連のライブラリが分かり辛い...

まぁ、どの「フレームワーク」でもそうなのかもしれないですが、どこまでライブラリが入ってるのかが分からんというね...

GitHubの「Vue.js」のページを見てみると、

github.com

Introduction

Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. It is designed from the ground up to be incrementally adoptable, and can easily scale between a library and a framework depending on different use cases. It consists of an approachable core library that focuses on the view layer only, and an ecosystem of supporting libraries that helps you tackle complexity in large Single-Page Applications.

https://github.com/vuejs/vue

⇧ ってなっていて、「Ecosystem」が「Vue.js」というフレームワークで用意されている「ライブラリ」群ってことになるらしいですと。

で、「Vue CLI」で「vue create」した時に「Vue.js」のプロジェクトを作成してくれるのですが、「Ecosystem」のどの「ライブラリ」が使えるようになってるのかが分からないというね...

ちなみに、自分の環境では、「vue create」に利用した「Vue CLI」のバージョンは「4.5.13」で、「Vue.js」のプロジェクトの「Vue.js」のバージョンは「2.6.14」となっております。

f:id:ts0818:20211017122518p:plain

で、プロジェクトの「node_modules」を確認してみると、何か「Ecosystem」に載ってない「ライブラリ」が多いんだが...

f:id:ts0818:20211017122020p:plain

なので、このあたりも「Vue CLI」の公式のドキュメントとかに「vue create」した際に含まれる「Vue.js」の「ライブラリ」の情報を載せてくれるとありがたいところですね。

 

VS CodeVisual Studio Code)に拡張機能を追加

とりあえず、「Vue.js」の公式のドキュメントによりますと、「Tooling」の「TypeScript」の説明の中で、

vuejs.org

Editor Support

For developing Vue applications with TypeScript, we strongly recommend using Visual Studio Code, which provides great out-of-the-box support for TypeScript. If you are using single-file components (SFCs), get the awesome Vetur extension, which provides TypeScript inference inside SFCs and many other great features.

WebStorm also provides out-of-the-box support for both TypeScript and Vue.

https://vuejs.org/v2/guide/typescript.html#Editor-Support

⇧ ってなっていて、「Vue.js」で「TypeScript」を使っていく予定があるなら、「VS CodeVisual Studio Code)」を使うのを強く推奨してるっぽいので、特に制約が無ければ、「VS CodeVisual Studio Code)」を使っとけば無難なんですかね。

VS CodeVisual Studio Code)」を使っていく場合、

learnvue.co

⇧ 「Vue.js」用の「VS CodeVisual Studio Code)」の「拡張機能」を入れておいた方が良いらしい。

で、まず、「Vuter」なる「拡張機能」を追加したんだけど、「VS CodeVisual Studio Code)」を起動する度に、

f:id:ts0818:20211017130359p:plain

⇧ 警告が出てしまう。

「Vuter」の「FAQ」に上がってるからして、よくある質問らしい。

vuejs.github.io

Vetur can't find package.json in /xxxx/xxxxxx.

If you don't have any package.json in your project, Vetur can't know the Vue version and component data from other libs. Vetur assumes that the version of Vue is less than 2.5. If the version is wrong, you will get wrong diagnostics from typescript and eslint template validation.

https://vuejs.github.io/vetur/guide/FAQ.html#vetur-can-t-find-package-json-in-xxxx-xxxxxx

You can add this config at the correct position in your project or use vetur.config.js to set file path.

If you want debug info, you can use Vetur: show doctor info command.
You can use vetur.ignoreProjectWarning: true in vscode setting to close this warning.

https://vuejs.github.io/vetur/guide/FAQ.html#vetur-can-t-find-package-json-in-xxxx-xxxxxx

⇧ 説明を読むと、プロジェクトに「package.json」が1つも無い場合、って言っていて、自分の環境では「package.json」あるからして、矛盾してて謎過ぎる...

とりあえず、「vetur.config.js」を加えてみたけども、

f:id:ts0818:20211017132055p:plain

変更するのは、パスを設定してる個所だけで大丈夫かと。

// vetur.config.js
/** @type {import('vls').VeturConfig} */
module.exports = {
  // **optional** default: `{}`
  // override vscode settings
  // Notice: It only affects the settings used by Vetur.
  settings: {
    "vetur.useWorkspaceDependencies": true,
    "vetur.experimental.templateInterpolationService": true
  },
  // **optional** default: `[{ root: './' }]`
  // support monorepos
  projects: [
    './', // Shorthand for specifying only the project root location
    {
      // **required**
      // Where is your project?
      // It is relative to `vetur.config.js`.
      root: './',
      // **optional** default: `'package.json'`
      // Where is `package.json` in the project?
      // We use it to determine the version of vue.
      // It is relative to root property.
      package: './package.json',
      // **optional**
      // Where is TypeScript config file in the project?
      // It is relative to root property.
      tsconfig: './tsconfig.json',
      // **optional** default: `'./.vscode/vetur/snippets'`
      // Where is vetur custom snippets folders?
      snippetFolder: './.vscode/vetur/snippets',
      // **optional** default: `[]`
      // Register globally Vue component glob.
      // If you set it, you can get completion by that components.
      // It is relative to root property.
      // Notice: It won't actually do it. You need to use `require.context` or `Vue.component`
      globalComponents: [
        './src/components/**/*.vue'
      ]
    }
  ]
}    

依然として、警告は消えず...

「Vuter」の「Setup」のページを見ると、

vuejs.github.io

Extentions

https://vuejs.github.io/vetur/guide/setup.html#extensions

⇧ なんか、「拡張機能」をインストールしろってことなのかな?

とりあえず、「ESLint」って「拡張機能」はインストールしておきました。

f:id:ts0818:20211017144935p:plain

ちなみに、

stackoverflow.com

Installing the EsLint extension should solve your problem

if you are on VS Code, search for the EsLint extension by publisher:"Dirk Baeumer", install it and approve the installation to start the EsLint server

Alternatively run this in the terminal npm install eslint in your workspace

The package.json file gets modified and your server will be up again

for further information on the EsLint extension you can check https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint

Good luck!

https://stackoverflow.com/questions/66985894/vetur-cant-find-package-json

⇧プロジェクトのディレクトリで、「npm install eslint」を実行してもOKらしい。

自分は「Visual Studio Code」の「拡張機能」からのインストールと、コマンドでのインストールの両方やってしまったわけだけど、どっちか片方を実施すればOKかと。

f:id:ts0818:20211017133731p:plain

f:id:ts0818:20211017133754p:plain

 

そして「Vuter」の「Setup」で言っている「VS Code Config」が何のことを言ってるのか分かり辛いな...

一応、「VS Code Config」でGoogle検索したら、以下が一番初めにヒットしたので、

code.visualstudio.com

User and Workspace Settings

You can configure Visual Studio Code to your liking through its various settings. Nearly every part of VS Code's editor, user interface, and functional behavior has options you can modify.

https://code.visualstudio.com/docs/getstarted/settings

VS Code provides two different scopes for settings:

  • User Settings - Settings that apply globally to any instance of VS Code you open.
  • Workspace Settings - Settings stored inside your workspace and only apply when the workspace is opened.

Workspace settings override user settings. Workspace settings are specific to a project and can be shared across developers on a project.

Note: A VS Code "workspace" is usually just your project root folder. Workspace settings as well as debugging and task configurations are stored at the root in a .vscode folder. You can also have more than one root folder in a VS Code workspace through a feature called Multi-root workspaces. You can learn more in the What is a VS Code "workspace"? article.

https://code.visualstudio.com/docs/getstarted/settings 

⇧「User Settings」または「Workspace Settings」のどっちかを用意しろってことなのではないかと仮定して話を進めることにします。

というか、「VS CodeVisual Studio Code)」を推奨するのは良いけど、必要な設定情報とかを端折るのは本当に勘弁して欲しい...

あと、「Visual Studio Code」の「Workspace Settings」は、「Visual Studio Code」で開いているフォルダのトップに対して作られてしまうので、今回のプロジェクト(「hello-world」)を例にさせてもらうと、「javascript_work」フォルダに対して作られてしまうっぽい。

f:id:ts0818:20211017142302p:plain

⇧「Vue.js」のプロジェクトは、「hello-world」フォルダなので、こちらのほうに「Workspace Settings」を作ろうかと。(そもそも「Workspace Settings」をどこに作るべきなのかよく分かっていないです...)

というわけで、フォルダを開き直します。

f:id:ts0818:20211017142729p:plain

f:id:ts0818:20211017142916p:plain

で、開き直したら、「Vuter」の警告が出なくなりました...

どうやら、「Visual Studio Code」で開いているフォルダの階層構造とかが「Vuter」に影響してるっぽいですかね、「vetur.config.js」内のパスの設定をしっかりすれば良いのかもしれませんが...

今後のことも考えて、一応、「Workspace Settings」を加えておきます。

f:id:ts0818:20211017140728p:plain

f:id:ts0818:20211017140852p:plain

で、「Vuter」の内容を「setting.json」に追記しておきます。

f:id:ts0818:20211017143230p:plain

⇧ とりあえず、開発環境は整ったのかな...

 

手を加えてみる

というわけで、まずは、ファイルを追加してみます。

f:id:ts0818:20211014164230p:plain

適当に「ファイル名.拡張子」を入力。「拡張子」は「.vue」にしてます。

f:id:ts0818:20211014164444p:plain

コーディングは以下のような感じに。

■hello-world\src\components\EveningWorld.vue

<template>
  <div class="evening">
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
export default {
  name: 'EveningWorld',
  props: {
    msg: String
  }
}
</script>    

■hello-world\src\App.vue

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
    <!-- 追加 -->
    <EveningWorld msg="Thank you for coming! to Your Vue.js App"/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'
// 追加
import EveningWorld from './components/EveningWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld,
    EveningWorld // 追加
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

で、実行なんですが、何故か、自分の環境ではPowerShellで実行しようとするとエラーになってしまうので、コマンドプロンプトで実行します。

f:id:ts0818:20211014193452p:plain

以下のコマンドを実行して、表示されるURLにブラウザでアクセスします。

npm run serve

f:id:ts0818:20211014193822p:plain

f:id:ts0818:20211014193854p:plain

画面が表示されればOK。

f:id:ts0818:20211014193950p:plain

ページが表示されたのを確認できたら、コマンドプロンプト上で「Ctrl」+「C」を押下して、「Y」を入力して、サービスを停止しときます。

f:id:ts0818:20211014194052p:plain

なんか、Vue.jsでタブを実現してるサイトを見つけたので真似してみる。

coliss.com

私は、2つのデモを用意しました。
1つはこの記事で解説するスタイルなしのデモと、もう1つはCodesandboxにアップロードしたTailwind CSSを使用してより美しくしたデモです。

Vue.jsで再利用可能なタブのUIコンポーネントを実装する方法を解説 | コリス

⇧ なんか、見た目を整えたい場合は「Tailwind CSS」ってのインストールする必要があるらしいんですが、

tailwindcss.com

⇧ とあるので、今回は却下で。

自分の環境では「Node.js 10.15.0」を使ってるので...

というわけで、ファイルを追加します。せっかくなんで、フォルダを作って、そこにファイルを追加する方向で。

f:id:ts0818:20211014194822p:plain

適当に名前を入力。

f:id:ts0818:20211014194925p:plain

そしたらば、作成したフォルダを選択した状態で右クリックして、「新しいファイル」を選択。

f:id:ts0818:20211014195009p:plain

適当に「ファイル名.拡張子」を入力。「拡張子」は「.vue」にしてます。

f:id:ts0818:20211014195043p:plain

いまのファイル構成はこんな感じ。

f:id:ts0818:20211017145708p:plain

コーディングは以下のような感じに。

■hello-world\src\components\common\EveningWorld.vue

<template>
    <div
      :class="{
          flex: variant === 'horizontal',
      }"
    >
      <ul
        :class="{
          flex: variant === 'vertical',
        }"
      >
        <li v-for="(tab, index) in tabList" :key="index">
          <label :for="`${_uid}${index}`" v-text="tab"/>
          <input
            :id="`${_uid}${index}`"
            type="radio"
            :name="`${_uid}-tab`"
            :value="index +1"
            v-model="activeTab"
          />
        </li>
      </ul>    

      <template v-for="(tab, index) in tabList">
        <div :key="index" v-if="index +1 === activeTab">
            <slot :name="`tabPanel-${index +1}`"/>
        </div>
      </template>    
    </div>
</template>

<script>
export default {
    props: {
        tabList: {
            type: Array,
            required: true,
        },
        variant: {
            type: String,
            required: false,
            default: () => "vertical",
            validator: (value) => ["horizontal", "vertical"].includes(value),
        },
    },
    data() {
        return {
            activeTab: 1,
        };
    },
};
</script>

<style>
 .flex {
     display: flex;
 }
</style>

■hello-world\src\App.vue

<template>
  <!-- 追加 ↓ここから -->
  <div id="app">
    <app-tabs :tabList="tabList">
      <template v-slot:tabPanel-1> Content 1 </template>
      <template v-slot:tabPanel-2> Content 2 </template>
      <template v-slot:tabPanel-3> Content 3 </template>
      <template v-slot:tabPanel-4> Content 4 </template>
    </app-tabs>
    <!-- 追加 ↑ここまで-->
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
    <EveningWorld msg="Thank you for coming! to Your Vue.js App"/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'
import EveningWorld from './components/EveningWorld.vue'
// 追加
import AppTabs from './components/common/tab.vue';

export default {
  name: 'App',
  components: {
    HelloWorld,
    EveningWorld, // 追加
    AppTabs // 追加
  },
  // 追加
  data() {
    return {
      tabList: ["Tab 1", "Tab 2", "Tab 3", "Tab 4"],
    }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

f:id:ts0818:20211014214348p:plain

タブについては、CSSが「display:flex」しか指定がないから、デザイン性の欠片もないけど、タブは実装できてる模様。

f:id:ts0818:20211014214445p:plain

f:id:ts0818:20211014214627p:plain

なんか、「Vue.js」に限った話ではないとは思うけど、フレームワークって、htmlにいろいろ記述していかないといけないので、管理が大変そう...

まぁ、何て言うか、「Vue.js」以外でも情報がいろいろ端折られてて辛い...

暗黙の前提が多過ぎるんだよな~...

今回はこのへんで。