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は出力先のフォルダで
typeにbrowserが指定された場合は./browserにtypeにnodeが指定された場合は./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, } }
このdeclarationとdeclarationMapをtrueに指定すれば型定義ファイルやマップファイルが出力されるが
これはブラウザ向けの場合は不要なので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.jsonのoutDirの指定について
型定義ファイルはoutDirで指定した場所に出力されるので指定している。
これでビルドした結果は予想通りの動きになっていていい感じだ。
ビルドされたjsはブラウザではうまいこと動いている。
あとはこれで作成したものが、他のNodeプロジェクトにインストールしてうまく動くかどうか。