初めてOSSを作ってみて、そうだったの？と思ったことまとめ

# はじめに

~~コロナで家にいて暇だったので、~~初めてOSSを作って公開しました。

言語はTypeScript、環境はWebpack、IE11とCDNに対応、リポジトリはGithubです。
ブラウザ、nodejs、コマンドプロンプト、bashで動きます。

作ってみて、「これって実はこうなってたの？」と思ったポイントを共有します。
もし同じようなOSSの公開を検討されている方がおられましたら、ご参考いただきたくと思います。

## OSSについて

OSS（オープンソースソフトウェア）は、ソースコードが公開され、誰でも利用、改良、修正、再配布ができるソフトウェアのことです。

もし作ったOSSに興味があればこちらの記事をご参考ください。

NLP（日本語）で使えるJSのDateライブラリを公開しました
https://qiita.com/ShotaOki/items/5e4b02f795fbf88bf0b1

## CDNに登録する

たとえばjQueryを使いたいとき、htmlのヘッダにこんな風に書いていると思います。

```html:index.html（jQueryをインポートする）
<script src="https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js"></script>
```

今回作成した僕のOSSでは、以下のように書けば取り込むことができます。

```html:index.html
<script src="https://cdn.jsdelivr.net/gh/ShotaOki/NLPDate@v0.0.1/modern/nlpdate-main.min.js"></script>
```

このCDNに登録するには、どこにユーザー登録して、何をすればいいのでしょう。

実のところ、何もしなくても登録されます。
githubにタグが上がっていればCDNとして利用できます。

jsdelivrのURLは`https://cdn.jsdelivr.net/gh/${ユーザー名}/${レポジトリ名}@${タグ名}/${ファイル名}`です。ghが`github`のことです。タグ名には`latest`と書いてもOKです。

```bash:タグを作ってpushする
# githubのメインブランチにタグを作る
git tag -a v0.0.1 -m 'リリースタグを作る'

# githubのメインブランチにタグをpushする
git push origin --tags
```

これでjsdelivrで使えるようになっています。


## コマンドプロンプトでTypeScriptのファイルを動かす。

作ったOSSの都合で、どうしてもbashやコマンドプロンプトから動かしたいと思っていました。

```bat:コマンドプロンプト
REM 普通の使い方
nlp-date "明日の午後三時" -f "和暦の年月日時分秒"
>> 令和3年01月12日 15時00分00秒

REM 「明日」とか「今日」みたいにエポック秒を書けるので、ログを読むのに便利
nlp-date "1610341916の9時間後" -f "年月日時分秒"
>> 2021年01月11日 23時11分56秒
```

これはどうやれば実装できるのでしょう。

拡張子なしのJavaScriptファイルを作って、頭にShebang（#!で始まる行）を付けます。

```javascript:nlp-date
#!/usr/bin/env node

// JavaScriptでソースを書けばよい
var NLPDate = require("../modern/nlpdate-main.min.js");
/** 
中略：引数をパースする
*/
// 標準出力にconsole.logで出力する
console.log(NLPDate(argv["value"]).asString(argv["format"]));
```

頭にShebangがついていると、その環境で実行します。
コマンドプロンプトはShebangが読めないので、cmdを拡張子につけたファイルから呼び出します。

```bat:nlp-date.cmd
@ECHO off
REM nodeでJavaScriptファイル（nlp-date）を実行する
node  "nlp-date" %*
EXIT /b %errorlevel%
```

このファイルの場所に環境変数を通せば、「nlp-date」コマンドが使えるようになります。

## TypeScriptをIE11に対応する

IE11、フルネームで書くと_Internet Explorer 11_です。
TypeScripのts-loaderのままwebpackしても、~~過去の遺物~~ IE11で動きません。

開発元のMicrosoftがEdgeに移ったのだから、こちらとしても切り捨てたいところですが、さすがにWindowsに標準で入っているブラウザを切り捨てるわけにはいきません。

IE11向けのバンドルファイルの生成は、ts-loader -> babel-loaderの順で呼び出します。
こうすることで、IE11で対応していない関数（fetchとか）を作ってくれます。

```json:webpack.config
{
            rules: [
                // JavaScriptをIE11向けにトランスパイルする
                {
                    test: /\.(js|jsx|ts)$/,
                    exclude: /(node_modules|bower_components)/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            presets: [
                                [
                                    '@babel/preset-env',
                                    {
                                        targets: ['> 1%', 'ie 11'],
                                        useBuiltIns: 'usage',
                                        corejs: 3,
                                    },
                                ],
                            ],
                        },
                    },
                },
                // TypeScriptをJavascriptに変換する
                {
                    test: /\.ts$/,
                    exclude: /(node_modules|bower_components)/,
                    loader: 'ts-loader',
                    options: {
                        configFile: 'babel.tsconfig.json', // <- babelの時だけtsconfig.jsonを変更
                    },
                },
            ],
        }
```

「module変数が見つからない」と言われたら、tsconfigのmoduleをes2015に書き換えます。

```babel.tsconfig.json
{
    "includes": ["src/**/*.ts", "test/**/*.ts"],
    "compilerOptions": {
        "target": "es5",
        "module": "es2015", // <- babelの時だけ"commonjs"から"es2015"に書き換える
                            // es2015だとブラウザ以外の実行（例：mochaの自動テスト）で失敗するので、
                            // webpackのoptionでbabelの時だけ変更する
        "lib": ["es6", "es2019", "dom"]
    }
}
```

ソースコード外にアロー関数が書かれる問題を解決するために、対応ブラウザを.browserlistrcに書きます。

```text:.browserlistrc
> 1%
IE 11 // ここにIE 11を書けば、import文（ソースの外側）にアローが使われなくなる
not dead
```

これでトランスパイルすればTypeScriptのファイルがIE11対応されます。
ポリフィルも必要なものだけ取り込まれます。