強まっていこう

あっちゃこっちゃへ強まっていくためのブログです。

UMD を出来るだけシンプルに説明してみる

何?

Node.js とブラウザの両方で強引にコードを読ませるための暴力的な書き方

実例

public/js/umd.js にモジュールが存在し、そこが Web でも公開されているとして呼び方は以下のようになる

Node.js で呼ぶ場合

#!/usr/bin/env node

const UMD = require('./public/js/umd')

const umd = new UMD()
umd.say()

ブラウザで呼ぶ場合

script(src='/js/umd.js')
script.
  const umd = new UMD()
  umd.say()

こんな感じで Webpack とかしなくても普通に読めるようになる

モジュールの書き方

;(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(factory)
  }
  else if (typeof exports === 'object') {
    module.exports = factory()
  }
  else {
    root.UMD = factory()
  }
}(this, function () {
  return class {
    say() { console.log('UMD') }
  }
}))

これが一般的な書き方なんだが、一番上の if の部分は Require.js 用の記述なので今や要らん

;(function (root, factory) {
  if (typeof exports === 'object') {
    module.exports = factory()
  }
  else {
    root.UMD = factory()
  }
}(this, function () {
  return class {
    say() { console.log('UMD') }
  }
}))

これで良い

まぁコード見れば分かる通りやってる事はバカバカしいほどシンプル
即時実行関数を使って export するものを環境別に出しわけてる

モジュールの説明

この部分が export させたいコード

return class {
  say() { console.log('UMD') }
}
if (typeof exports === 'object') {
  module.exports = factory()
}

この部分が Node.js 用の定義
exports が存在したらそいつを使って export している

root.UMD = factory()

これがブラウザの場合に読まれる部分

root には window オブジェクトが来るので、そいつに直接ぶら下げてるだけ

お行儀は相当悪いわな
名前固定しているからこんなモジュールを多用すると名前衝突祭りで死ねる
まぁ元々ここらへんの JavaScript のお行儀なんて暴走族みたいなもんだから馴染み深いといえば馴染み深い

どうせ行儀が悪いんだから以下で良いよ、もう

;(function (factory) {
  if (typeof exports === 'object') { module.exports = factory() }
  else {
    window.UMD = factory()
  }
}(function () {
  return class {
    say() { console.log('UMD') }
  }
}))

モジュールの中で別のモジュールを呼ぶとさらにキモくなる

依存モジュールを読み込む例

;(function (factory) {
  if (typeof exports === 'object') {
    module.exports = factory(require('./umd')) }
  else {
    window.UMD2 = factory(window.UMD)
  }
}(function (UMD) {
  return class {
    say2() {
      const umd = new UMD()
      umd.say()
      console.log('UMD2')
    }
  }
}))

UMD モジュールを内部で使っている UMD2 モジュールの定義がコレ
どうだ?絶望的にキモいだろ?
読み込むモジュールが増えれば増えるほど地獄みたいになって行く様が容易に想像付くだろう

Node.js 側からは普通に読めるがブラウザから読む場合依存ライブラリを全て自力で呼んでやる必要がある
依存モジュールのロード順の解決を自力でやる事になるので
モジュールが多いと100%大パニックで発狂してノートPCをフリスビーよろしく投げ捨てる事請け合いだ

script(src='/js/umd.js')
script(src='/js/umd2.js')
script.
  const umd2 = new UMD2()
  umd2.say2()

普通に Webpack だの Turbopack だののバンドルツールを使った方が絶対に良い
だが、世の中にはこいつを使ってるモジュールも結構あるから知っておいて損は無いと言う知識

じゃぁの