イマドキのnpmでは何を配布すべきか


## はじめに

みなさん、npmでパッケージ公開してますか？

[自分はこれまでいくつか公開した](https://www.npmjs.com/~zprodev)んですが、ここ最近「**モダンに使ってもらうために何をパッケージングして配布すべきか**」を見つめ直したので、自分なりの結論を語らせていただきたいと思います。

## CommonJSのモジュール
Node.js環境でモジュールとして使用されるために、CommonJS形式で実装したモジュールは現状必須かなと思います。

CommonJSモジュールをpackage.jsonの`main`フィールドに設定すると、`require("パッケージ名")`で利用可能になります。

### 配布例

CommonJS形式で定数`hoge`をexport

```js
// hoge.js
exports.hoge = "HOGE";
```

package.jsonのmainフィールドに設定

```json
{
  "name": "パッケージ名",
  "main": "hoge.js"
}
```

これで、Node.js環境なら以下のように使えます

```js
const { hoge } = require("パッケージ名");
```

## ECMAScriptのモジュール

webpackなどでバンドルして使われる想定の場合、ES Modulesとして実装したコードも配布した方が良いと思います。
webpackやRollup等のモダンなモジュールバンドラーでは、package.jsonの`module`フィールドに設定されているコードをES Modulesとして優先的に読み込むようになっていて、その場合はTreeShakingによるコード量の削減が期待できます。

### 配布例

ES2015形式で定数`hoge`をexport

```js
// hoge.js
export const hoge = "HOGE";
```

package.jsonのmoduleフィールドに設定

```json
{
  "name": "パッケージ名",
  "module": "hoge.js"
}
```

バンドル前のJavaScriptで以下のように使えます

```js
import { hoge } from "パッケージ名";
```

## TypeScriptの型定義ファイル

[こちらのアンケート](https://ashleynolan.co.uk/blog/frontend-tooling-survey-2018-results#js-extensions)によるとTypeScriptは約半数のエンジニアが使ったことがあり、AltJSでは現状一番人気と言えるのかなと思います。

そんなTypeScriptでは型定義ファイルが提供されていないモジュールは使いづらく、型定義の無いモジュールがTypeScriptのプロジェクトに採用されることは滅多にないんじゃないでしょうか。

有名どころのパッケージは[@types](https://www.npmjs.com/~types)でサポートされていたりしますが、いざ使ってみると最新版の定義が反映されていなかったりして辛い時があります。

そういう訳で、イマドキのnpmなら型定義も一緒に配布してあげた方が親切だしメンテもしやすいんじゃないかなと思います。

TypeScriptの型定義ファイルは、package.jsonの`types`フィールドに設定しておけばOKです。

詳しくは公式ドキュメントで
https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html

## ブラウザ用にバンドルしたコード

バンドルしてブラウザで使われる想定のモジュールの場合、あらかじめバンドルしたコードも一緒に配布することをオススメします。
そうすると、`npm install xxx`せずとも[unpkg.com](https://unpkg.com)経由でダウンロードできるので、CodePenなどのサービスでサクッと試してもらうことができます。

例えば[png.es](https://www.npmjs.com/package/png.es)では以下のURLで、npmに配布中のバンドル済みコードを取得できます。
https://unpkg.com/png.es@0.4.0/dist/browser/png.min.js

なのでHTMLのscriptタグで読み込んで使用できます。
<p data-height="265" data-theme-id="0" data-slug-hash="GPpbgK" data-default-tab="html,result" data-user="zprodev" data-pen-title="GPpbgK" class="codepen">See the Pen <a href="https://codepen.io/zprodev/pen/GPpbgK/">GPpbgK</a> by zprodev (<a href="https://codepen.io/zprodev">@zprodev</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## バンドルしたECMAScriptのモジュール

[モダンなブラウザは概ねESModulesに対応済み](https://caniuse.com/#feat=es6-module)です。
上のブラウザ用バンドルコードと同様の理由で、ECMAScriptモジュールもバンドルして提供すると簡単に試してもらうことができます。

[png.es](https://www.npmjs.com/package/png.es)では以下のURLでバンドル済みECMAScriptモジュールを配布しています。
https://unpkg.com/png.es@0.4.0/dist/esm/png.min.js

CodePenのJavaScriptは`type="module"`設定されているため、すぐにESModulesを使用できます。

<p data-height="265" data-theme-id="0" data-slug-hash="Ydyobw" data-default-tab="js,result" data-user="zprodev" data-pen-title="Ydyobw" class="codepen">See the Pen <a href="https://codepen.io/zprodev/pen/Ydyobw/">Ydyobw</a> by zprodev (<a href="https://codepen.io/zprodev">@zprodev</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## さいごに

触ったことないけどモダンと噂のVue.jsを覗いてみました。

<img width="408" alt="スクリーンショット 2018-12-13 20.39.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/142643/45c62ee6-b5d0-6eb9-c880-f7896ab2dc7f.png">

devとかprodとか分けて色々配布されてますね。親切。

package.jsonの配布物っぽいフィールドはこんな感じです。

```json
  "main": "dist/vue.runtime.common.js",
  "module": "dist/vue.runtime.esm.js",
  "typings": "types/index.d.ts",
  "unpkg": "dist/vue.js",
```

`typings`と`types`は同じ役割なので、CommonJS、ESModules、TypeScriptの型定義を配布するのは一緒ですね。

`unpkg`は[unpkg.com](https://unpkg.com)用なんだろうか・・・？