Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CJSとESMとnpmパッケージ / CommonJS and ES Modules and npm package

CJSとESMとnpmパッケージ / CommonJS and ES Modules and npm package

Node学園 31時限目の発表資料です
https://nodejs.connpass.com/event/90936/

shimataro

June 29, 2018
Tweet

More Decks by shimataro

Other Decks in Technology

Transcript

  1. CJSとESMとNPMパッケージ
    CJSとESMとNPMパッケージ
    (2018/06/29)
    (2018/06/29)
    小田島 太郎 / @shimataro
    NODE学園 31時限目
    NODE学園 31時限目

    View Slide

  2. 自己紹介
    自己紹介
    ウェブリオ株式会社所属(京都)
    サーバサイドエンジニア
    趣味は手品
    小田島 太郎
    [email protected]
    [email protected]
    [email protected]

    View Slide

  3. この発表について
    この発表について
    対象: 汎用 npmパッケージを開発している人
    技術レベル: 中級
    npmパッケージやBabelの基礎知識を前提
    技術的に濃い話ではありません
    ↓スライドはこちら↓
    https://speakerdeck.com/shimataro
    https://shimataro.github.io/slides/

    View Slide

  4. 目次
    目次
    背景
    今回のゴール
    CJSとESM
    パッケージの構成
    コード生成
    まとめ

    View Slide

  5. 始める前に
    始める前に

    View Slide

  6. 7/5 関西NODE学園 2時限目
    7/5 関西NODE学園 2時限目

    View Slide

  7. それでは始めます
    それでは始めます

    View Slide

  8. 背景
    背景

    View Slide

  9. 背景
    背景
    JavaScript(ECMAScript)のモジュール
    require() / module.exports (CommonJS; CJS)
    import / export (ES Modules; ESM)
    ネイティブESMはあまり使われていない (BabelでCJSに変
    換するのが一般的)
    でもきっとそのうち普及する

    View Slide

  10. 今回のゴール
    今回のゴール

    View Slide

  11. 今回のゴール
    今回のゴール
    CJS / ESM / Babelの どれからでも使える パッケージモジ
    ュールを作りたい

    // パッケージ "foo"
    export default foo;
    export {bar};
    // CJS
    const {default: foo, bar} = require("foo");
    // ESM / Babel
    import foo, {bar} from "foo";

    View Slide

  12. 今回のゴール
    今回のゴール
    パッケージの条件
    ソースコードは単一
    ビルド時に複数ファイルの生成はOK
    default export / named exports 両方対応
    ソースコード内に変なハックは入れない
    おまじない NG
    古い文法 NG
    作る側にも使う側にも、極力負担をかけない

    View Slide

  13. CJSとESM
    CJSとESM

    View Slide

  14. CJSとESM
    CJSとESM
    拡張子 .mjs はESM
    それ以外の拡張子はCJS
    export default foo;
    export {bar};
    module.exports = foo;
    // または
    exports.default = foo;
    exports.bar = bar;

    View Slide

  15. CJSとESM
    CJSとESM
    相互運用について
    Native ES Modules - something almost, but not quite entirely unlike CommonJS by Gil Tayor

    View Slide

  16. CJSとESM
    CJSとESM
    1つのファイルで全部対応するのはややこしい
    .mjs と .js を両方用意する方が確実
    最初にESMで書いて、CJS形式にも変換
    Babelの出番

    View Slide

  17. パッケージの構成
    パッケージの構成

    View Slide

  18. パッケージの構成
    パッケージの構成
    package.json 内の main を 拡張子なし で指定
    2種類のindexを用意
    ./index.js (CJS/Babel用)
    ./index.mjs (ESM用)
    http://yosuke-
    furukawa.hatenablog.com/entry/2016/05/10/111102
    {
    ...
    "main": "./index", // ".js" はつけない
    ...
    }

    View Slide

  19. コード生成
    コード生成

    View Slide

  20. コード生成
    コード生成
    概要
    index.js はこうする
    index.mjs はこのままでOK
    exports.default = foo;
    exports.bar = bar;
    export default foo;
    export {bar};

    View Slide

  21. コード生成 - CJS
    コード生成 - CJS
    index.js は普通にBabelで変換すればOK

    export default foo;
    export {bar};
    exports.default = foo;
    exports.bar = bar;

    View Slide

  22. コード生成 - ESM
    コード生成 - ESM
    index.mjs は何もしなくてOK?
    Nodeがサポートしている文法だけを使うならOK
    デコレータとかstatic propertiesとか使えない
    汎用 パッケージなら、ある程度古いバージョンもサポー
    トしたい
    せめてLTSくらいは…
    そのために 古い文法 を使うのは嫌だ
    というわけで、 やっぱりBabelは使いたい

    View Slide

  23. コード生成 - ESM
    コード生成 - ESM
    Babel使用時の注意 その1
    babel-preset-env のデフォルトはCJS形式
    import / export構文を変換しない場合はこうする
    // .babelrc
    {
    "presets": [
    ["env", {"modules": false}]
    ]
    }

    View Slide

  24. コード生成 - ESM
    コード生成 - ESM
    Babel使用時の注意 その2
    拡張子が自動的に .js になる
    ESMでは .mjs じゃないとダメ
    Babel7に --keep-file-extension が登場
    拡張子を変更しないオプション
    変換元の拡張子も .mjs にする必要あり
    まだbeta段階

    View Slide

  25. コード生成(ESM)
    コード生成(ESM)
    選択肢は2つ
    Babel単体で解決
    Babel7 & --keep-file-extension
    他のツールを導入
    変換後に拡張子をリネーム
    今回は後者(gulp)を採用
    Babel6(安定版)でも使える
    元の拡張子に制限なし

    View Slide

  26. 実際に作ってみた
    実際に作ってみた

    View Slide

  27. 実際に作ってみた
    実際に作ってみた
    ESM(.mjs) / Babel
    CJS
    https://github.com/shimataro/hell-word
    npm install @shimataro/hell-word
    import foo, {bar} from "@shimataro/hell-word";
    foo(); // "hell, word"
    bar(); // "地獄の言葉"
    const {default: foo, bar} = require("@shimataro/hell-word");
    foo(); // "hell, word"
    bar(); // "地獄の言葉"

    View Slide

  28. まとめ
    まとめ
    単一ソースからCJS/ESM/Babel対応のパッケージを作
    る方法
    まずESMの export 構文で作る
    CJS用は exports.default に変換→ .js
    ESM用はそのまま→ .mjs
    package.json の "main" に拡張子をつけない
    サンプル作ってみたからよかったら参考にしてね
    関西Node学園もよろしく!
    手品に興味があったら声をかけてね!

    View Slide

  29. ありがとうございました
    ありがとうございました

    View Slide