TypeScript+webpackでブラウザでもNodeでも動くライブラリを作るメモ

ブラウザで動く事は確認したけど、Node環境でうまくいくかの動作検証はできてない状態

概要

webpackを使ってTypeScriptで書かれたライブラリをブラウザ向け、もしくはNode向けにバンドルしようと思ってあれこれしてみた備忘録

webpack.config.jsでoutputの設定をごにょごにょするだけでもある程度行けるが

型定義ファイルとかちゃんと用意しようとすると一筋縄ではいかなかったので

そのあたりについて記載する。

入れたパッケージは以下 - webpack - webpack-cli - typescript - ts-loader

webpack.config.json

とりあえずwebpack.config.jsの中身

const path = require('path');

//-----------------------------------------------------------------------------
// コマンドライン引数には以下の値を指定する
// --mode: development or production
// --type: browser or node
//-----------------------------------------------------------------------------
module.exports = (env, argv) => {

  // コマンドライン引数による判定
  const mode = (argv.mode === undefined)? "production" : "development";
  const isDev = mode === "development";
  const type="node";

  // ブラウザ用の設定
  const browser = {
    path: path.join(__dirname, '/browser'),
    filename: (isDev)? "mylib.js":"mylib.min.js",
    configFile: "tsconfig.json",
  };

  // Node環境用の設定
  const node = {
    path: path.join(__dirname, "/dist"),
    filename:"index.js",
    configFile: "tsconfig.node.json"
  };

  // argv.typeにはbrowserかnodeのどちらかを指定する。指定しないと多分エラーになる
  const params = {browser, node}[argv.type];

  console.log(params);

  const conf = {
    mode: mode,

    entry: './src/index.ts',
    output: {
        path: params.path,
        publicPath: '/',
        filename: params.filename,
        library: 'MyLib',
        libraryExport: '',
        libraryTarget: 'umd',
        globalObject: 'this',
    },
    module: {
        rules: [{
            test: /\.ts$/,
            exclude: /node_modules/,
            use: [
              {
                loader: 'ts-loader',
                options: {
                  configFile: params.configFile
                }
              }
            ]
        }]
    },
    // import 文で .ts ファイルを解決するため
    // これを定義しないと import 文で拡張子を書く必要が生まれる。
    // フロントエンドの開発では拡張子を省略することが多いので、
    // 記載したほうがトラブルに巻き込まれにくい。
    resolve: {
      // 拡張子を配列で指定
      extensions: [
        '.ts', '.js',
      ],
    }
  }

  // 開発時のみ
  if (isDev) {
    conf.devtool = 'inline-source-map';
  }

  return conf;
}

まずコマンドライン引数でwebpack --mode development --type browserって感じで

modeとtypeを受け取るようにした。

この引数の内容を見て、webpackの設定を切り替えるようにしている。

outputの設定

    output: {
        path: params.path,
        publicPath: '/',
        filename: params.filename,
        library: 'MyLib',
        libraryExport: '',
        libraryTarget: 'umd',
        globalObject: 'this',
    },

pathは出力先のフォルダで

  • typebrowserが指定された場合は./browser
  • typenodeが指定された場合は./dist

コンパイルしたファイルを出力するようにした。

filenameに関しては

ブラウザ向けの場合、開発時はmylib.js、製品版はmylib.min.jsとなるようにし

Node向けの場合はindex.jsというファイルが生成されるようにした。

libraryに関してはライブラリを作るときにそれっぽい名前にし

libraryTarget: 'umd',
globalObject: 'this',

この設定をしておくことでブラウザでも動作するようにコンパイルされる。

Node向けにビルドする際に.d.tsとかを出す

型定義ファイルを出力するにはtsconfig.jsonの設定が必要だった。

{
   "compilerOptions": {
    "declaration": true,
    "declarationMap": true,
  }
}

このdeclarationdeclarationMaptrueに指定すれば型定義ファイルやマップファイルが出力されるが

これはブラウザ向けの場合は不要なのでtsconfig.jsonを2種類用意した。

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "es2015",
    "rootDir": "./src", 
    "strict": true,
    "moduleResolution": "node",
    "esModuleInterop": true,   
    "skipLibCheck": true,                    
    "forceConsistentCasingInFileNames": true  
  }
}

tsconfig.node.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "declaration": true,                   /* Generates corresponding '.d.ts' file. */
    "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */
    "outDir": "./dist",                        /* Redirect output structure to the directory. */
  }
}

ブラウザ向けビルドの時はtsconfig.jsonが適用され、Node向けビルドの時はtsconfig.node.jsonが適用されるようにwebpack.config.jsの以下の部分に細工している

module: {
    rules: [{
        test: /\.ts$/,
        exclude: /node_modules/,
        use: [
            {
                loader: 'ts-loader',
                options: {
                    configFile: params.configFile
                }
            }
        ]
    }]
},

ts-loaderのオプションで適用するコンフィグファイルを指定できるので、ここでコマンドライン引数のtypeで判定して、適用するコンフィグファイルを変更している。

tsconfig.node.jsonoutDirの指定について

型定義ファイルはoutDirで指定した場所に出力されるので指定している。

これでビルドした結果は予想通りの動きになっていていい感じだ。

ビルドされたjsはブラウザではうまいこと動いている。

あとはこれで作成したものが、他のNodeプロジェクトにインストールしてうまく動くかどうか。