LoginSignup
3
3

More than 5 years have passed since last update.

npmパッケージを公開していざ使おうと思ってもimportできなかったので調べたこと

Last updated at Posted at 2019-03-07

こちらの記事でも書きましたが、アメーバのような形状をp5.jsで作り、generatorも公開しました。この記事はこれを機にこのアメーバーの生成をnpmパッケージにして公開してみようと思い、公開方法を調べた記録です。HowToではないです。つまづいた点などの記録ですので、作り方などは私も参考にしていた以下の方の記事が良いと思います。

参考

初めてのnpm パッケージ公開
3分でできるnpmモジュール

公開用のフォルダ

パッケージの作り方を参考にして、npmにアカウント登録とpackage.jsonにライブラリ情報を記入し、npm publishで公開するところまでいけました。公開するフォルダの中身はwebpackでアプトプットしたデータです。package.jsonに以下を記入すると、プロジェクトディレクトリの中のデータが、例えば他のプロジェクトでnpm install p5-amebaとインストールした時にnode_modulesに入ってきます。

package.json

...
  "files": [
    "README.md",
    "lib"
  ]
...

上の例だと、README.mdとlibフォルダにあるデータですね。なので、使い手がimport ameba from 'p5-ameba'とした時に必要なデータを書き込めば良いと思います。このp5-amebaはパッケージのname fieldで決められるので、libフォルダの中にp5-ameba.jsのようなファイルを用意する必要はないです。それで、npm install p5-amebaとした時に読み込むjsファイルは、package.jsonのmain fieldで指定します。

package.json
...
 "name": "", <- npm install するときの名前
  "main": "", <- importした時に読み込むファイル
  "files": [] <- node_modulesに入るファイルを指定
...

公開してもimportで読み込めない

なんとかパッケージを公開してみて、いざ使ってみようと思い、別プロジェクトで実際にnpm install p5-amebaとし、jsファイルからimport ameba from p5-amebaとやってみました。すると、以下のエラーが出て読み込みができません。

Uncaught SyntaxError: Unexpected identifier

開いた口が塞がりません。。。まだまだフロントエンドの勉強中なので、おそらく何かの知識が抜け落ちてるか、何となくの知識で使っている何かが原因だと思います。ただ、用語が多すぎたりでまだ自分の技術にできていません。仕方がないので、少しづつ原因を追っていきました。

確認作業

  • 開発環境で配布したライブラリが本当に使えているのかを確かめる  -> 使えた
  • 配布したライブラリを、新しいプロジェクトで直接読み込んでみる -> 使えた(要は開発環境と同じ)
  • 配布したライブラリを、node_modulesから読み込む -> エラー

つまり、node_modulesにある状態だとなぜか読み込まれないことが分かりました。ほかのnpmパッケージのライブラリはimportしても使えているので、node_modulesにデータを置く過程か、データそのものに原因がありそうです。作成したライブラリはES2015で書いているため、もしかしたらbabelとかwebpackも含めてこの辺りの知識の曖昧さが原因なのでは?と思い調べてみました。怪しいのはwebpackでアウトプットしたデータです。

他のパッケージの作りを研究

作成したアメーバーのアニメーションライブラリは、animejsというライブラリの構成をかなり参考にしています。初期化時にパラメータを指定するなど。なので、このanimejsのパッケージはどのような作りになっているのか調べました。

Usage

  • ES6 modules
  • CommonJS
  • File include

パッケージの使い方で、ライブラリの使用方法が上記の3方法あります。このうち、CommonJS...???と恥ずかしながら私はこの用語を知りませんでした。。。少し調べてみると、

CommonJS

  • モジュール管理の規格のひとつ。
  • require(<モジュール名>)でライブラリを読み込む仕様。
  • この記事が参考になりました。
  • node.jsでも使用する場合は必須のよう

これを踏まえてanimejsのpackage.jsonを見てみると作りは以下になっています。

animejsのpackage.jsonの一部
  "umd:main": "lib/anime.min.js", 
  "module": "lib/anime.es.js", 
  "main": "lib/anime.js", 
  "files": [ 
    "lib" 
  ], 

mainumd:とついてますが、UMDとはUniversal Module Definitionの略で、以下のように定義されています。(GitHubより抜粋)

The UMD pattern typically attempts to offer compatibility with the most popular script loaders of the day (e.g RequireJS amongst others). In many cases it uses AMD as a base, with special-casing added to handle CommonJS compatibility.

また不明な用語、、、AMDとはAsynchronous Module Definitionの略で、モジュールを非同期で読み込むため規格のようです。CommonJSの規格を非同期で読み込むための仕様。。。かな。それともう一つ、module fieldがあり、これの読み込み先のファイルがES2015基準のファイルを指していました。npmの仕様には

The main field is a module ID that is the primary entry point to your program. That is, if your package is named foo, and a user installs it, and then does require("foo"), then your main module’s exports object will be returned.
This should be a module ID relative to the root of your package folder.
For most modules, it makes the most sense to have a main script and often not much else.

このように書かれてあり、どうやらmain fieldにはCommonJS規格のファイルを指定する必要があるようです。ではこのmodulefieldは何だろうとしらべてみると、こちらに詳しく書いてありますが、

"module"フィールドに書くファイルパスは名前のとおりECMAScript モジュール形式のコードで、このコードはimport/exportのままのコードを配置します。webpackなどのbundlerは"module"フィールドが存在する場合はそちらを優先して読み込みます。

ES2015形式で書かれたコードのファイルを指定するfieldのようです。

CommonJS用にライブラリを書き出す

ライブラリを作成したのはES2015形式なので、これをCommonJSのファイルとして扱えるように書き出す必要があります。webpackでoutputしただけのファイルは、ライブラリのモジュールとしては使えないようです。やはりこれが読み込みができない原因と言えそうです。

ライブラリ用にビルドする

私が使っていたwebpackの設定はjsなどのアセットをまとめて、ブラウザで読み込める形に書き出すことはやりますが、ライブラリ用のモジュールとして書き出すことはしません。webpackでもライブラリ用にビルドする設定はあると思いますが、他にも調べてみるとRollupというモジュールバンドラがライブラリ開発に適しており、CommonJS形式に変換できるようです。基本的にこちらの記事を参考にすると変換までできます。記事元ではアウトプットのフォーマットがcjsとCommonJSのみの変換になっていたので、これでも良いと思いますが、今回私が参考にしたanimejsのパッケージはumd規格のファイルになっていたので、私もこれに習ってumd規格のファイルを作りました。

rollup.config.js
export default {
    input: './lib/ameba.es.js',
    output: [{
      file: './lib/ameba.js',
      format: 'umd',
      name: "p5-ameba"
    }],
    external: [
        'p5'
      ]
  };

formatのfieldのプロパティをumdに変えただけです。これでビルドして、CommonJSファイルを作り、ようやくnpmパッケージが使えるようになりました。

Conclusion

まだまだフロントエンドは分からないことが多く知らない用語がたくさんあります。それでも調べながらコツコツやっていくとレベルアップできるのではないかと感じました。このamebaライブラリはあまり役に立つものではないですが、パッケージ配布までの全体像が掴めたことは自分にとっては収穫です。その中で知らない単語を少しずつ吸収していけました。

ちなみに、ライブラリを開発していく中で、作ったライブラリを試すのにイチイチnpm publishとやって公開してから別プロジェクト作ってnpm install p5-amebaとやって確認作業していましたが、開発中のライブラリを擬似的にnode_modulesに入れて確認できるようです。

配布予定のライブラリを入れる/外す
npm link p5-ameba   <- node_modulesにいれる
npm unlink p5-ameba <- node_modulesから外す

今回作成したnpmパッケージはこちらです。
GitHubにもあります。

sample.gif

3
3
1

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
3
3