LoginSignup
0
0

More than 1 year has passed since last update.

【Vue2.x, Vuetify, Nuxt】自作コンポーネントをnpmパッケージとして公開する手順

Last updated at Posted at 2022-12-21

Vuetifyに依存した自作コンポーネントをnpmパッケージとして公開する手順の備忘録です。

背景

今まで自作コンポーネントはファイルごとプロジェクトにコピーして使っていたのですが、新しいコンポーネントを作ったり、改修したりした場合のバージョン管理がずさんになりがち。
npmパッケージとして公開・管理することでより便利になるとは思い試してみました。
vue-cliが何たるかも分からずwebpackから手を付け始めてしまったので、実際に公開できるようになるまで2日、公開したものをインストールして使えるようになるまで更に1日。
これは手順を残しておかなければ、ということでこの記事を作りました。
※結果、vue-cliがwebpackのラッパーなので、vue-cli単体で何とかなります。

1. npmアカウントの作成

兎にも角にも、自作コンポーネントをnpmに公開するには、自身のアカウントが必要です。
作成手順自体は難しくないので割愛します。こちらを参考にどうぞ。

2. 自作コンポーネント用のプロジェクトを作成

vue create PACKAGE_NAME

プロジェクトを作成したいディレクトリ(フォルダ)で上記を実行します。
PACKAGE_NAME の部分は適宜変更してください。
VueCLI便利。

3. パッケージ化するコンポーネントを作成

src/components/inputs/MyComponent.vue
<template>
  <v-text-field label="自作コンポーネント" />
</template>

パッケージングの流れを確認するためだけであれば何でもOKです。

4. エントリポイントとなるファイルを作成

エントリポイントは、インストール先でライブラリとして利用される際に読み込まれるモジュールという認識です。
コンポーネントを利用する際は、

  1. コンポーネントを利用するvueファイルごとにimportする(ローカル登録)
  2. Vue.use()を利用してコンポーネントを登録する。(グローバル登録)
    の2種類があります。
    ここでは自作コンポーネントをVue.use()でグローバル登録することを前提としてエントリポイントを作成します。(理由は後述)
src/build/build.lib.js
// パッケージングしたいコンポーネントをimport(複数OK)
import MyComponent from "../components/inputs/MyComponent.vue";
import hoge from "../components/inputs/Hoge.vue";
import fuga from "../components/inputs/Fuga.vue";

// importしたコンポーネントをオブジェクトに入れておく
const Components = {
  MyComponent,
  Hoge,
  Fuga,
};

// install()を定義する。
// Vue.use(XXX)は、XXX.install()を実行する。
// ここではimportしたコンポーネントをVueにグローバル登録している。
const install = function (Vue) {
  if (install.installed) return;
  install.installed = true;
  Object.keys(Components).forEach((component) => {
    Vue.component(component, Components[component]);
  });
};

const plugin = { install };

// まだ調べ切れていないが、CDNで使用されるときはここが呼ばれる???
let GlobalVue = null;
if (typeof window !== "undefined") {
  GlobalVue = window.Vue;
} else if (typeof global !== "undefined") {
  GlobalVue = global.Vue;
}
if (GlobalVue) {
  GlobalVue.use(plugin);
}

// ここが公式や他の投稿と異なる。
// pluginをexport defaultしておかないと、Vue.use(XXX)で上記のinstall()が実行されない。
// export default Components <- これだとダメ
export default plugin;

公式を読んで自分がハマったところなのですが、公式のサンプルだとpluginをexportしていないので、Vue.use()してもinstallが実行されません。
pluginはdefault exportしておいて、importしたコンポーネントはnamed exportしておかなければならないのではないだろうか。。。
npmパッケージとして公開してでも再利用したいコンポーネントなのであれば、使用頻度が高いでしょうから、グローバル登録を前提としています。

5. package.jsonを編集。

package.json
  "name": "PACKAGE_NAME",
  "version": "0.1.5",
  "private": false,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "build-bundle": "vue-cli-service build --target lib --name PACKAGE_NAME --formats umd src/build/build.lib.js",
    "lint": "vue-cli-service lint"
  },
  "main": "dist/PACKAGE_NAME.umd.js",
  "files": [
    "dist"
  ],

PACKAGE_NAME の部分は適宜修正。
privateはfalseに。trueの場合、課金しないとnpmに公開できません。
scriptsにbuildするためのコマンドを「build-bundle」として設定しています。VueCLIを使うので「vue-cli-service build」コマンドでOK。
--targetはライブラリとして登録するため「lib」を、--nameはそのままパッケージ名を、最後のパスには前述したエントリポイントのパスを設定します。
--fomatsは、出力されるファイルの形式を指定します。このオプションを付けないと「common.js」と「umd.js」が両方生成されます。
試してみたのですが、Nuxtで利用する場合は「umd.js」でなければダメでした。
mainはbuildした際に生成されるdist内のファイルのうち、インストール先で実行されるファイルを指定します。
※npm installした場合とCDN利用の場合とで分けることもできますが、ここでは割愛します。
filesにはdistを設定しておけばOKです。依存プラグインなどがある場合は追加記述できるそうです。

6. buildします。

npm run build-bundle

7. publishします。

npm publish

npmにログインしていないとpublishできません。
ログインしていない場合はコンソールで「npm login」を実行しましょう。

8. テスト用のプロジェクトを作成し、パッケージをインストールします。

npm install PACKAGE_NAME

9. 動きを確認します。

Vueプロジェクトで利用する場合
main.js
import Vue from "vue";
import App from "./App.vue";
import xxxxx from 'PACKAGE_NAME' // add
import 'PACKAGE_NAME.css' // add

Vue.use(xxxx) // add

new Vue({
  vuetify,
  render: (h) => h(App),
}).$mount("#app");

インストールしたパッケージをimportし、Vue.use()を実行。
PACKAGE_NAME.cssもimportしておかないと、cssが機能しない。

Nuxtプロジェクトで利用する場合
plugins/PackageName.js
import Vue from 'vue'
import xxxxx from 'PACKAGE_NAME'
import 'PACKAGE_NAME.css'

Vue.use(xxxxx)
nuxt.config.js
plugins: [
  '~/plugins/PackageName.js',
],

パッケージを利用するためのjsファイルをpluginsディレクトリに作成し、nuxt.config.jsのpluginsオプションでこれを指定します。

CSSファイルをimportしたくない場合

VueCliによるバンドルでは、デフォルトではcssファイルが別ファイルとして生成されます。
この場合、前述のパッケージをライブラリとしてimportしているところで

import 'PACKAGE_NAME.css'

しないとcssが適用されません。
vue-cliによって生成されるjsファイルにcssを含めたい場合は、vue.config.jsで以下のように設定します。

const { defineConfig } = require("@vue/cli-service");
module.exports = defineConfig({
  transpileDependencies: ["vuetify"],
+  css: {
+    extract: false,
+  },
});

vue.config.jsでcssの出力を上記のように定義すれば、jsとcssが一つのファイルにまとめられます。

参考

https://cli.vuejs.org/guide/cli-service.html#vue-cli-service-build
https://cli.vuejs.org/guide/build-targets.html#library
https://tech-blog.optim.co.jp/entry/2021/04/15/100000
https://passe-de-mode.uedasoft.com/ja/tips/software/frontend/vuetify/vuetify05.html#_2-vue-cli-%E3%81%A6%E3%82%99%E6%9C%80%E5%88%9D%E3%81%8B%E3%82%89%E5%87%BA%E6%9D%A5%E3%81%A6%E3%81%84%E3%82%8B-package-json-%E3%81%AB%E3%80%81%E3%81%84%E3%81%8F%E3%81%A4%E3%81%8B%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B
https://jp.vuejs.org/v2/cookbook/packaging-sfc-for-npm.html
勉強させていただきました。ありがとうございます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0