Slide 1

Slide 1 text

NODE.JS V12 のES MODULES NODE.JS V12 のES MODULES (2019/10/25) (2019/10/25) ⼩⽥島 太郎 / @shimataro 関⻄NODE 学園 8 時限⽬ 関⻄NODE 学園 8 時限⽬

Slide 2

Slide 2 text

⾃⼰紹介 ⾃⼰紹介 ⼩⽥島 太郎 Web エンジニア(最近はインフラ寄り) 趣味は⼿品 ⼿品業界→Web 業界 実は関⻄Node 学園の⽴ち上げにも関わ ってます https://shimataro.me

Slide 3

Slide 3 text

この発表について(1) この発表について(1) 対象者 ES Modules って何? Node.js v12 で何か変わったの? ⾮対象者 Node.js を触ったことないよ v12 の変更点もちゃんとフォローしてるよ

Slide 4

Slide 4 text

この発表について(2) この発表について(2) ゴール ES Modules について理解し、使えるようになる Node.js v12 で有効なコードを書けるようになる ↓スライドはこちら↓ https://speakerdeck.com/shimataro https://shimataro.me/slides/

Slide 5

Slide 5 text

⽬次 ⽬次 きっかけ CommonJS ES Modules 相互運⽤ v12 での変更点 対応⽅法 まとめ

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

きっかけ きっかけ ⾃作のnpm パッケージを公開中 CommonJS / ES Modules どちらでも使える CI を導⼊ Node.js v12 のES Modules 版でコケていた v12 以外では問題なし CommonJS 版では問題なし どういうこと?

Slide 8

Slide 8 text

COMMONJS COMMONJS

Slide 9

Slide 9 text

COMMONJS おさらい COMMONJS おさらい ECMA 標準ではない(後に⼀部取り込まれた) モジュール管理 ←今回話すやつ ⾮同期処理 ファイル⼊出⼒ etc CommonJS とは、サーバーサイドなどのウェブブラウザ環境 外におけるJavaScript の各種仕様を定めることを⽬標とした プロジェクトである。 (Wikipedia より)

Slide 10

Slide 10 text

NODE.JS とCOMMONJS NODE.JS とCOMMONJS Node.js ではCommonJS 形式のモジュールをサポート 最近は使うことは少なくなった(※個⼈の感想です) // import const fs = require("fs"); // export module.exports = () => { console.log("hell,word"); // 地獄の⾔葉 };

Slide 11

Slide 11 text

ES MODULES ES MODULES

Slide 12

Slide 12 text

ES MODULES おさらい ES MODULES おさらい ECMAScript6(ES2015) で策定されたモジュール仕 様 関数や変数ではなく構⽂として導⼊ Babel やTypeScript を使うとCommonJS 形式に変換 してくれる 今はこの⽅法が主流?(※個⼈の感想です) import fs from "fs"; export default () => { console.log("hell,word"); // 地獄の⾔葉 };

Slide 13

Slide 13 text

NODE.JS とES MODULES NODE.JS とES MODULES v8.5.0 から実験的サポート Windows では絶対パスでimport するとエラーに なるので、v8.6.0 以降を使ってください 拡張⼦は .mjs --experimental-modules フラグが必要 // v8.5.x on Windows // "C" という URI スキームが⾒つからない import foo from "C:/path/to/foo";

Slide 14

Slide 14 text

相互運⽤ 相互運⽤ module.exports したものを import する場合 export したものを require() する場合

Slide 15

Slide 15 text

相互運⽤ 相互運⽤ できんことないけどやめたほうがいい Native ES Modules - something almost, but not quite entirely unlike CommonJS by Gil Tayor

Slide 16

Slide 16 text

ここから本題 ここから本題 ここの記事の内容です。 Announcing a new --experimental-modules https://medium.com/@nodejs/announcing-a-new- experimental-modules-1be8d2d6c2ff

Slide 17

Slide 17 text

V12 での変更点 V12 での変更点 破壊的変更がいろいろ。

Slide 18

Slide 18 text

NODE.JS 開発チーム内での議論 NODE.JS 開発チーム内での議論 1. ブラウザと挙動あわせようず ブラウザ(script タグ)では拡張⼦必須 Node.js では拡張⼦省略可 さらに foo/index.js は foo だけでimport 可 2. いつまでも .mjs はイヤだ 今後ES Modules 形式が⼀般的になっていくはず 10 年後も .js=CommonJS 形式でいいのか? 3. 現状との互換性も確保したい

Slide 19

Slide 19 text

ブラウザと挙動あわせようず ブラウザと挙動あわせようず import ⽂で拡張⼦を必須にした CommonJS 形式には適⽤されない(拡張⼦省略可) By default in the new --experimental-modules, le extensions are mandatory in import statements: import ‘./ le.js’, not import ‘./ le’. // ./path/to/foo.mjs というファイルを import したい import foo from "./path/to/foo"; // NG import foo from "./path/to/foo.mjs"; // OK

Slide 20

Slide 20 text

いつまでも いつまでも .MJS .MJS はイヤだ はイヤだ .mjs と .js をES Modules として扱う CommonJS では、新たな拡張⼦ .cjs を使う The .cjs extension provides a way to save CommonJS les in a project where both .mjs and .js les are treated as ES modules.

Slide 21

Slide 21 text

現状との互換性も確保したい(1) 現状との互換性も確保したい(1) いきなり .js をES Modules として扱われると困る package.json の設定で挙動を変える module: ES Modules 形式とみなす commonjs: CommonJS 形式とみなす (従来挙動& デフォルト) Add “type”: “module” to the package.json for your project, and Node.js will treat all .js les in your project as ES modules.

Slide 22

Slide 22 text

現状との互換性も確保したい(2) 現状との互換性も確保したい(2) いきなり拡張⼦を必須にされると困る コマンドラインオプションで挙動を変える node: 拡張⼦や index.js は省略可(従来挙動) explicit: 拡張⼦が必須(デフォルト) ※全ファイルに適⽤される(パッケージ単位の指定は 不可) However, the CommonJS-style automatic extension resolution behavior (‘./ le’) can be enabled via a new ag, --es-module- speci er-resolution=node.

Slide 23

Slide 23 text

対応⽅法 対応⽅法 Node.js v12 に対応したコードの書き⽅

Slide 24

Slide 24 text

対応⽅法: 基本 対応⽅法: 基本 import 対象のファイルに拡張⼦をつける package.json に以下を追加 { ... "type": "module", ... }

Slide 25

Slide 25 text

対応⽅法: BABEL (1) 対応⽅法: BABEL (1) を使うとよさげ import の拡張⼦を⾃動付与してくれるプラグイン 相対パス( "." で始まるパス)のみ対応 うまくいかない場合もある 例)@babel/preset-env でPoly ll が埋め込まれる場合 babel-plugin-extension-resolver // パッケージ内のファイルを直接参照するコードが⽣成される // "." で始まらないので拡張⼦をつけてくれない import "core-js/modules/es.array.iterator";

Slide 26

Slide 26 text

対応⽅法: BABEL (2) 対応⽅法: BABEL (2) Babel に投げた , 取り込まれるまで --es-module-specifier- resolution=node でやり過ごしましょう Issue #10548 PR #10549

Slide 27

Slide 27 text

対応⽅法: TYPESCRIPT 対応⽅法: TYPESCRIPT TypeScript では対応不可? 「拡張⼦つけてよ」→「TS はJS のコード部分は変更 しないから無理だよ」 解決⽅法を知っている⼈がいたら教えてください。 Issue #33588 TypeScript always emits JavaScript code as written, and import statements are JavaScript code so aren't changed on emit.

Slide 28

Slide 28 text

対応⽅法: パッケージ作成 対応⽅法: パッケージ作成 新しい仕様でCommonJS とES Modules の両⽅に対応 したパッケージはどうやって作るの?

Slide 29

Slide 29 text

対応⽅法: パッケージ作成 対応⽅法: パッケージ作成 無理 パッケージの汎⽤性にこだわりたい場合は、従来仕様 の "type": "commonjs" を設定しましょう Currently, it is not possible to create a package that can be used via both require(‘pkg’) and import ‘pkg’.

Slide 30

Slide 30 text

まとめ(1) まとめ(1) ES Modules の挙動はv12 から変わったよ .js はES Modules 形式だよ import 時に拡張⼦必須だよ CommonJS とES Modules の両⽅に対応したパッケ ージは作れないよ ⼿品が好きな⼈はお話しましょう

Slide 31

Slide 31 text

まとめ(2) まとめ(2) ゴール(再掲) ES Modules について理解し、使えるようになる Node.js v12 で有効なコードを書けるようになる ⼿品に興味を持つ

Slide 32

Slide 32 text

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