👨‍💻

npmライブラリを公開する(TypeScript、CDN対応)

2021/11/22に公開

jQueryのようにCDNで使用することもできるし、TypeScript等で型付モジュールとして使用することもできる。そんなライブラリを開発&公開する手順です。ミニマム構成なので適宜webpackやtsconfigを調整してください。

事前準備

  • npmアカウントを作成
  • 以下のコマンドでnpmにログインする
  • ライブラリ用の公開GitHubリポジトリを作成
npm login
npm whoami # アカウトが表示されればOK

ライブラリ初期化

# ライブラリディレクトリの作成
mkdir demo-library
cd demo-library

# package.jsonをスコープ付きで初期化
npm init --scope=@scope-name

# 開発用バンドルツールのインストールと設定ファイル作成
npm i -D ts-loader typescript webpack webpack-cli
touch tsconfig.json webpack.config.js

# ライブラリコードを実装するディレクトリ、ファイルを作成
mkdir src
touch src/cdn.ts src/index.ts

上記の中で@scope-name はnpmのアカウント名にする必要があります。(例: --scope=@nino_cast

webpack.config.js
module.exports = {
  mode: 'production',
  entry: './src/cdn.ts',
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader',
      },
    ],
  },
  resolve: {
    extensions: ['.ts', '.js'],
  },
};
tsconfig.json
{
  "compilerOptions": {
    "target": "es2016",
    "module": "ES2015",
    "moduleResolution": "node",
    "declaration": true,
    "outDir": "./dist",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true,
    "lib": ["ES2020", "DOM"]
  },
  "include": ["src"]
}
package.json
{
  "name": "<自動入力されたままでOK>",
  "version": "1.0.0",
  "description": "<ライブラリの説明>",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "scripts": {
    "prepublishOnly": "npm run build", # npm公開前に自動で走る
    "build": "tsc && webpack"
  },
  "files": [
    "dist/main.js",
    "dist/index.js",
    "dist/index.d.ts"
  ],
  "repository": {
    "type": "git",
    "url": "<リポジトリURL>"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    // ...
  },
  "devDependencies": {
    // ...
  }
}

概要としては以下を行います。CDN利用が不要であればwebpackやCDNの対応は不要です。

webpack → cdn.ts の内容をCDN公開用にビルドする
tsc → tsファイルをモジュール用にコンパイルする

不要ファイルの除外

.gitignore
node_modules
dist

ライブラリ開発

今回は指定IDのElementに現在日時を表示するライブラリを作成します。

npm i date-fns
src/index.ts
import { format } from 'date-fns';

export const renderClock = function (id: string): void {
  const element = document.getElementById(id);
  setInterval(() => {
    if (element) {
      element.innerHTML = format(new Date(), 'yyyy年MM月dd日 HH:mm:ss');
    }
  }, 1000);
};

これでモジュールができたので、CDN公開用にグローバル(window)オブジェクトにぶら下げましょう。

src/cdn.ts
import { renderClock } from '.';

(<any>window).renderClock = renderClock;

これでライブラリ実装終了です。

テスト

いきなりnpmに公開するのではなくまずはローカルでテストします。まずはビルドを行った上で、ローカルで使用できるように npm link を実行します。

npm run build
npm link

権限がない場合 sudo npm link としてください。

次にテスト用に適当なプロジェクトディレクトリを作成します。

mkdir lib-test
cd lib-test
npm i typescript webpack webpack-cli ts-loader
touch webpack.config.js tsconfig.json main.ts
npm link <ライブラリ名> #たとえば @nino_cast/demo-library
webpack.config.js
module.exports = {
  mode: 'development',
  entry: './main.ts',
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader',
      },
    ],
  },
  resolve: {
    extensions: ['.ts', '.js'],
  },
};
tsconfig.json
{
  "compilerOptions": {
    "target": "es2016",
    "module": "ES2015",
    "moduleResolution": "node",
    "outDir": "./dist",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true,
  }
}
main.ts
import { renderClock } from '@スコープ/ライブラリ名';

renderClock('clock');
index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script defer src="./dist/main.js"></script>
</head>
<body>
  <div id="clock"></div>

</body>
</html>
package.json
# 以下を追加
"scripts": {
  "build": "webpack"
},

以後ライブラリディレクトリとテストプロジェクトのディレクトリで npm run buil を叩けば自動で最新のライブラリが反映されるようになります。

テスト終了後の後始末

テストが終わったら必ずunlinkを行いましょう。ライブラリとテスト用プロジェクトのディレクトリ両方で以下のコマンドを実行します。

npm unlink <@スコープ/ライブラリ名>

CDN動作のローカルチェック

CDN利用の動作を確認したい場合、ローカルディレクトリ上のdist/main.js を読み込めば良いでしょう。

cdn.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="<PC上のパス>/main.js"></script>
</head>
<body>
  <div id="clock"></div>
  <script>
    renderClock('clock')
  </script>
</body>
</html>

公開

問題なければ公開します。ライブラリのディレクトリで以下のコマンドを実行します。

npm publish --access=public

ちなみに同じバージョンで公開することはできないので修正を加えた場合以下のコマンドでバージョンアップしてから公開してください。アップデートの種類変更(メジャー、マイナー)や付随する自動化テクニックは公式ドキュメントを参照してください。

npm version patch -m "アップデート内容"
npm publish

実際に使ってみる

CDNの利用

jsDelivrは公開したライブラリを自動でCDNにホストしてくれます。特に何をすることもなく以下のようにいきなり使えます。

<script src="https://cdn.jsdelivr.net/npm/@スコープ/ライブラリ名@バージョン/dist/main.min.js"></script>

<script src="https://cdn.jsdelivr.net/npm/@nino_cast/simple-clock@1.0.1/dist/main.min.js"></script>

自動で圧縮ファイル min.js を作ってくれるのでそちらを使うのが良いでしょう。バージョンを省略すると常に最新バージョンが参照されるようになります。さまざまな呼び出し方があるのでドキュメントを参照してください。

モジュール使用

TypeScriptが使える環境で一般的なライブラリ同様にインストールすることができます。

npm i @スコープ名/ライブラリ名

おまけ

TypeScript library starter
を使えばテストなど全部入りの状態でライブラリ開発をスタートすることができます。CDN配布する場合前述の通りwebpackによる配布用バンドルを作成する必要がありそうですが、一般的なTypeScriptライブラリであればCDN配慮は不要だと思うのでこちらのスターターキットから開発するのが良いと思います。


Discussion