CDNから引っ張ったjqueryやlodashをtypescriptで使う


はじめに

TypeScriptは近年ますます重要視されている。またCDNを活用して自社サーバーの負荷を減らし、ページの表示速度を向上する手段としても重宝されている。
ただし、ライブラリそれぞれの特性の違い、webpackの環境の違いなどで、設定でつまずくことも多々ある。

設定の仕方

HTML

まずはHTMLにタグを追加し、CDNからjQueryとLodashを引っ張ってくる。CDNは別にどこでも良いが、ここは例として、cdnjsを使う。

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.9/lodash.min.js"></script>

Webpack側の設定

そしてwebpackでCDN指定したいライブラリをむき出す。
要するにwebpackのデフォルトの仕様では、ライブラリ等をbundleの中に混ぜ込み、$_などのグロウバル変数は最終、ランダムの名前になったり、closureにラッピングされたりするので、CDNから導入する際、そういうグロウバル変数を変な形にコンパイルしないような設定が必要である。

externalsの設定

この設定はローカルにインストールされたLodashやjQueryを使わないように指示するための設定である。特にLodashはwebpackの依存関係にあるので、何も設定しないとローカルのLodashを使ってしまう。

webpack.config.js
module.exports = {
  // 他の設定は省略
  externals: {
    jquery: '$',
    lodash: '_',
  }
}

externalsの詳しい使い方はこちらを参照してください。

ProvidePluginの設定

この設定は$_などのグローバル変数をグローバルであるように、すべてのファイルに示すための設定である。
設定しなければ、すべてのファイルにimport $ from 'jquery'のような宣言を書かなければ行けなくなる。

webpack.config.js
module.exports = {
  // 他の設定は省略
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
      'window.$': 'jquery',
      _: 'lodash',
      'window._': 'lodash',
    }),
  ],
}

ProvidePluginの詳しい使い方はこちらを参照してください。

RailsのWebpackerの場合

Webpackerの設定config/webpack/environment.jsは若干構文は違うが、内容は一緒である。

environment.js
// 他の設定は省略
const webpack = require('webpack')

environment.config.externals = {
  lodash: '_',
  jquery: '$',
}

environment.plugins.prepend(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    'window.$': 'jquery',
    _: 'lodash',
    'window._': 'lodash',
  })
)

WebpackerのDOCSを読めば、このあたりの書き方がわかるはず。

TypeScript側の設定

Type定義のインストール

本体別にいらない、型定義だけで十分。

npm i -D @types/jquery @types/lodash
# または
yarn add -D @types/jquery @types/lodash

Global定義を実装

Project直下か、tsconfig.json"typeRoots"に設定されたフォルダにindex.d.tsファイルを作成、下記コードを記入。

index.d.ts
// Global definition
import * as _ from 'lodash'

declare global {
    // 他の設定は省略
  const _: _.LoDashStatic
  // const $: JQueryStatic // jqueryはすでにGlobalに定義済み
  interface Window { // W <= 大文字, Window Classの方を拡張する
    $: JQueryStatic,
    _: _.LoDashStatic,
  }
}

globalの詳しい使い方はこちらを参照してください。

ここでライブラリの設計思想の違いが出てしまう:
- jQueryはできるだけGlobalで使ってほしいだろうが、@types/jqueryで予め$をGlobal名前空間に置いてある。
- Lodashはfunctional programmingを推奨しており、本当はconst isObj = require('lodash/isObject')のようなFunctionベースでの導入がベストでした。今回は無理して_をGlobal名前空間に出したようなものである。

app.tsで使う

うまく設定が完了できれば、app.ts(またはその他一般の.tsファイル)では、IntelliSenseが効いているはず。

また、webpackでコンパイルする際、_$が外部のライブラリを使うようになっているのがわかる。

[28] external "_" 42 bytes {0} [not cacheable]
[29] external "$" 42 bytes {0} [not cacheable]

余談: lodash/fpの導入

lodash/fpは、lodashのfunctionをカリー化したライブラリであり、それを使えばlodashをよりエレガントに使えることができる。ただしカリー化関数はやや理解が難しく、lodash/fpのDocumentもそこまで充実していないため、実験的に導入するのはおすすめである。

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.9/lodash.fp.min.js"></script>
<script>
  window.fp = _.noConflict()
</script>

こうすればfpという定数でlodash/fpを導入した。

TypeScriptの設定

index.d.ts
import * as fp from 'lodash/fp'

declare global {
    // 他の設定は省略
  const fp: fp.LoDashFp
  interface Window {
    fp: fp.LoDashFp,
  }
}

こうすれば、lodash/fpも使えるようになった。

参考

https://www.cnblogs.com/zichi/p/7787669.html
https://qiita.com/jkr_2255/items/283bc12dd07bc237179e
https://qiita.com/NoUkeNoLife/items/b5aa1934dc8c92459957
https://qiita.com/re-fort/items/972d9a6cdc5c00864a6e