👏

Vite(Vue.js) + VitePressによるPackage管理

2021/11/25に公開

はじめに

今回は、前回作成したToDoアプリのナビゲーションバーをPackage化し、VitePressでドキュメント化、Package配布、利用までを紹介していきます。

Package作成

前回の記事をベースに、新しくtraning-partsというプロジェクトを新規作成し、環境設定、SB Admin、Font Awesomeのインストールまで行ってください。その後、既存のvueファイルや、public配下のファイルを削除し、以下のファイルを作成してください。

  • src/components/NaviBar.vue
     → <router-view />は、VitePressでも確認できるように<slot />に変更。
  • src/components/NotFound.vue

その後、main.tsのファイル名を、index.tsに変更し、以下のように修正します。

index.ts
import { createApp } from "vue";

import { library } from "@fortawesome/fontawesome-svg-core";
import { fas } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { dom } from "@fortawesome/fontawesome-svg-core";

import "startbootstrap-sb-admin/src/scss/styles.scss";

library.add(fas);
dom.watch();

// App.vueは不要
createApp({}).component("font-awesome-icon", FontAwesomeIcon);

// パッケージ化するコンポーネントを取り込む
export { default as NaviBar } from "./components/NaviBar.vue";
export { default as NotFound } from "./components/NotFound.vue";

作成したパッケージをTypescriptで利用できるように、typesを出力するように修正します。

tsconfig.json
  ...
    "declaration": true,
    "emitDeclarationOnly": true,
    "declarationDir": "./types",
  }

パッケージには、CommonJSやES Module, UMDがありますが、今回はVue.jsからimportするためのモジュールなので、ES Moduleのみを作成します。また、コンポーネントの動作確認はvitepress上で行うようにします。

package.json
{
  "name": "traning-parts",
  "version": "0.0.0",
  "files": [
    "dist",
    "types"
  ],
  "types": "./types/index.d.ts",
  "module": "./dist/traning-parts.es.js",
  "exports": {
    ".": {
      "import": "./dist/traning-parts.es.js"
    }
  },
  "scripts": {
    "dev": "vitepress dev docs",
    "build": "vitepress build docs",
    "serve": "vitepress serve docs",
    "build:library": "vue-tsc && vite build"
  },
  ...

最後に、以下のコマンドを実行し、distフォルダにesファイルができることを確認してみてください。

> npm run build:library

VitePress

パッケージ化したコンポーネントを動作確認するために、VitePress上でサンプル表示およびコンポーネントの説明を作成します。

> npm i -D vitepress

作成先は、一般的にdocsフォルダ配下に、Markdownファイルを作成していきます。

docs/index.md
---
title: Introduction
---

# Traning Parts

## 使い方
...

ソースコードは、記事の関係上、コードブロック記号(```vue→'''vue)は置き換えています。
mdで表を作成する際は、Excel to Markdown tableを利用すると、Excelで表をコピーし、Shift-Alt-Vで張り付けると、改行も含めて、Markdown形式に変換できます。

docs/guide/navibar.md
# NaviBar

[[toc]]

## Usage
'''vue
<script setup>
const menuItems: MenuItem[] = [
  {
    type: "heading",
    title: "Heading",
  },
  {
    type: "menu",
    title: "Main",
    icon: "fa-list",
    url: "/",
  },
];
</script>

<NaviBar title="Title" :menu-items="menuItems">
  <router-view />
</NaviBar>
'''

## Sample

<a href="navibarSample" target="_blank">Sample</a>

## Props

| Name     | Type       | Required | Description            |
| -------- | ---------- | -------- | ---------------------- |
| title    | string     | true     | タイトルを表示します。 |
| menuItem | MenuItem[] | true     | メニューを設定します。 |

## Type

### MenuItem

| Name  | Type              | Required | Description                                             |
| ----- | ----------------- | -------- | ------------------------------------------------------- |
| type  | "heading" ,"menu" | true     | メニュータイプ<br/>heading の場合は、icon, url 指定不可 |
| title | string            | true     | メニュータイトル                                        |
| icon  | string            | false    | アイコン                                                |
| url   | string            | false    | URL                                                     |

ナビゲーションバーのサンプルは、全画面表示になるため、別ウィンドウで表示されるように、mdファイルを別にしましたが、通常は1ファイルで問題ないと思います。lang="ts"は利用できないようです。

docs/guide/navibarSample.md
<script setup>
import { NaviBar } from "../../src/index";

const menuItems = [
  {
    type: "heading",
    title: "Heading",
  },
  {
    type: "menu",
    title: "Menu",
    icon: "fa-list",
    url: "/",
  },
]
</script>

<NaviBar title="Title" :menu-items="menuItems">
  <h1 class="mt-4">Main Page</h1>
</NaviBar>

VitePressのrouter設定を行います。viteのオプションは、build時に以下のエラーが発生するため、追加しています。

  • build.chunkSizeWarningLimit ... Some chunks are larger than 500 KiB after minification.
  • css.preprocessorOptions.css.charset ... warning: "@charset" must be the first rule in the file
docs/.vitepress/config.ts
import { defineConfig } from "vitepress";

export default defineConfig({
  lang: "ja-JP",
  title: "Traning Parts",
  description: "Traning Parts Vue 3 component library",
  themeConfig: {
    docsDir: "docs",
    sidebar: [
      {
        text: "Introduction",
        link: "/",
      },
      {
        text: "Components",
        children: [{ text: "NaviBar", link: "/guide/navibar" }],
      },
    ],
  },
  vite: {
    build: {
      chunkSizeWarningLimit: 1500,
    },
    css: {
      preprocessorOptions: {
        scss: {
          charset: false,
        },
      },
    },
  },
});

動作確認は、以下のコマンドで確認できます。

> npm run dev
→ プレビュー
> npm run build
→ html作成

Package公開

Package公開には、以下のようなサービスがありますが、今回は手順がシンプルなAzure Artifactを利用しています。使い慣れた手順で実施してください。

  1. Azure Artifactにログインし、作成したProjectsからArtifactsを選択する。そこで、Create Feedを選択し、以下の内容でFeedを作成する。
    ・Name ... traning-parts
  2. [Connect to feed]ボタンを押して、npmを選択し、記載されている手順に沿って、Package公開を行う。
.npmrc
registry=https://pkgs.dev.azure.com/....      
always-auth=true
> vsts-npm-auth -config .npmrc
→ Azure Artifactsのアクセストークン作成
> npm publish
→ パッケージ公開
  1. ソースを変更した際は、package.jsonのvesionをカウントアップしてから、publishを行う。

Package利用

今回作成したPackageを利用して、実際にナビゲーションバーを表示してみます。

まずは、新たにプロジェクトを作成し、作成したパッケージをインストールします。その際、Package公開で作成した.npmrcをコピーします。

> npm i traning-parts
→ 必要なパッケージがすべてインストールされる。
> npm i -D sass
→ scssをimportする際に必要。

次に、作成したパッケージを利用して、ナビゲーションバーを表示してみます。その際、不要なvueファイルは削除してください。

views/Main.vue
<template>
  <h1 class="mt-4">Main Page</h1>
</template>
views/Sub.vue
<template>
  <h1 class="mt-4">Sub Page</h1>
</template>
App.vue
<script setup lang="ts">
import { NaviBar, MenuItem } from 'traning-parts'

const menuItems : MenuItem[] = [
  {
    type: "heading",
    title: "Heading",
  },
  {
    type: "menu",
    title: "Main",
    icon: "fa-list",
    url: "/",
  },
  {
    type: "menu",
    title: "Sub",
    icon: "fa-list-alt",
    url: "/sub",
  },
]
</script>

<template>
  <NaviBar title="test" :menu-items="menuItems">
    <router-view />
  </NaviBar>
</template>
router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
import { NotFound } from 'traning-parts'
import Main from "../views/Main.vue";
import Sub from "../views/Sub.vue";

const routers: Array<RouteRecordRaw> = [
  {
    path: "/",
    component: Main,
  },
  {
    path: "/sub",
    component: Sub,
  },
  {
    path: "/:pathMatch(.*)*",
    component: NotFound,
  },
];

const router = createRouter({
  history: createWebHistory(),
  routes: routers,
});

export default router;
main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from "./router";

import "startbootstrap-sb-admin/src/scss/styles.scss";

createApp(App).use(router).mount('#app')

これだけで実装が終わりです。動作確認として、ナビゲーションバーが普通に動作するか、確認してみてください。もし、Packageを更新した場合は、package.jsonのversionを変更し、npm updateを行ってください。

> npm update traning-parts

終わりに

bootstrap + VitePressを利用する際、scssを利用しないとwarning: "@charset" must be the first rule in the fileが出てしまい、気が付くまで、苦労しました。

今後、Viteでパッケージ開発するプロジェクトも増えてくると思いますので、この記事を活用いただければ幸いです。

Discussion