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. パッケージ化するコンポーネントを作成
<template>
<v-text-field label="自作コンポーネント" />
</template>
パッケージングの流れを確認するためだけであれば何でもOKです。
4. エントリポイントとなるファイルを作成
エントリポイントは、インストール先でライブラリとして利用される際に読み込まれるモジュールという認識です。
コンポーネントを利用する際は、
- コンポーネントを利用するvueファイルごとにimportする(ローカル登録)
- Vue.use()を利用してコンポーネントを登録する。(グローバル登録)
の2種類があります。
ここでは自作コンポーネントをVue.use()でグローバル登録することを前提としてエントリポイントを作成します。(理由は後述)
// パッケージングしたいコンポーネントを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を編集。
"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プロジェクトで利用する場合
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プロジェクトで利用する場合
import Vue from 'vue'
import xxxxx from 'PACKAGE_NAME'
import 'PACKAGE_NAME.css'
Vue.use(xxxxx)
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
勉強させていただきました。ありがとうございます。