blogこの広告は、90日以上更新していないブログに表示しています。3.4対応されました。一通り普通に動いてる感じ。これまで自分で使っていて問題になったのがパフォーマンス。ESLint単体やTSLintに比べて、プロジェクトによるだろうけど2倍以上遅い。typescript-eslint/typescript-eslintこれはTypeScriptのパーサーを通す部分の構造上の問題が原因なので、簡単には直せなそうな気配。projectを削除することにしました。追記終わりJavaScript用のlinterはESLintが絶対的な地位を確立している一方で、TypeScript用はTSLintがメジャーではあるものの、ドキュメントがひどい、recommendedがopinionatedすぎる、OSSとしてのガバナンスがアレなど微妙な状況だった(ESLintチームのレベルが高すぎるので比べるのは酷だけど)。したので、時代は今後ESLintに傾いていくのが確実視されている状況。いうことで現時点ではどんなもんか試してみたら普通に思ったより使えたという話を書きます。v12でESM周りの仕様が大幅に変更されました。この記事の内容は既に古くなっているため、最新の情報は以下の公式ブログを参考にしてください。Medium追記終了この話を今日のNode学園で話すので、ご興味あればどうぞ。Modules(ESM)の仕様が策定されたものの実装がなかなか進まない、という話を1年前に発表した。Modulesネイティブサポートにも7月に入って動きがあり、draftというステータスながらも仕様がマージされ、初期実装のプルリクが投げられた。Modules仕様と実装を眺めてみたので紹介する。実はのんびり書いている間に下記のブログが公開されました。blog.jxck.io重複部分は省略してるので、上の記事と前回のスライドを合わせてご参照ください。Modulesのシンタックスは決めたが、それが実際どう動くかはホスト側が決めることになっていた。Modulesの周辺仕様を策定していく必要があるため、実装方針だけ決めれば良い他の機能に比べて時間がかかっていた。論点になったのは以下3点。いうモジュール機構を持っているNode.jsでは相互互換性という面倒な要素を考える必要があった。制限付きで互換ブラウザについては前述のスライドや記事を参照してもらうとして、以下ではNode.jsについて見ていく。今どうすればいいの?長くなるので、つべこべ言わずに今どんなコードを書けば良いのか教えて!という人のために、先に今押さえておくべきことだけピックアップ。Modulesを多くの人にとって、まだ仕様が不安定なESMでコードを今書くメリットは「かっこいい」「キマル」ということ以外にほとんどない。世間に踊らされずrequire()を書いていれば、あとでNode.jsにESMが来たときでも互換性が確保される予定なので、これまで書いたパッケージをESMからimportできる。Modulesを書きたい人は以下2点に気をつける。importを使わない。importだけを使う。__filenameは利用できなくなるので、できるだけ使わない、または後で変更する覚悟をしておく。して議論が分かれている.mjs関連に比べて、この辺りはコンセンサスが取れているようなのでそのまま通りそう。今から気をつけておくと修正リスクが減らせる。世界では普通に利用されているので要注意。ModulesがサポートされたNode.jsではエラーになる。importで書き直す必要がある。fs;readFile(...);拡張子.mjsについては議論も実装もまだ揺れているし、機械的にリネームするのも難しくないので、今はとりあえずスルーしておくのが良さそう。Modulesとして認識させるには、ファイル拡張子を.mjsにする必要がある。.jsファイルは従来のCJS扱いになるため、.jsの中でimportやexportを使うとシンタックスエラーになる。.mjsは新しい拡張子のため、ローカル開発環境のエディタ、IDE、ビルドツールやlintツールなどの設定変更が必要になる。ブラウザは拡張子は全くチェックしない。nosniffと同等にcontent-typeをチェックすることになったため、application/octet-stream等ではJavaScriptとして実行してくれない)。よって、.mjsファイルをブラウザでもJSとして実行させたい場合、配信時にcontent-typeヘッダをapplication/javascriptなどJavaScriptとして適切なものにする必要がある。そのために、例えばnginx/apacheなどのサーバー設定で.mjsファイルに対する設定を変更しなければいけない。Modulesの識別子(下記でいう'./foo'の部分)をどう扱うかについて。Node.jsのESMでもこれを追随して、URLとして扱うことになった。%などの扱いが従来のCJSの識別子とは異なる。通常の用途ではまあ問題ないと思う。systemを参照)探索方法は基本的には旧来のNode.jsの方式を継承している。従来と異なるのは、自動で付与される拡張子に.mjsが追加されていること。優先順位は.jsより高い。'./foo';と書かれた場合、以下の優先順位になる。package.jsonの探索」では、例えばmainが./barだった場合、./foo/bar./foo/bar.mjs./foo/bar.js./foo/bar.json./foo/bar.node./foo/bar/index(拡張子を変えて探索)のように探索される。これを利用して、npmパッケージをESM/CJS両対応でリリースすることができる(後述)。これを踏まえて、Node.jsでESMからESMを呼び出すのは以下のようになる。'foo!'上述の通り、識別子の拡張子は自動で補われるため省略して./fooと書ける。このままブラウザに配信しても動作しない。拡張子自動付与はNode.js独自の仕様であるため。変更/変換なしでそのままブラウザでも動かしたい場合、以下のように自分で拡張子を書いてあげる必要がある。'./foo.mjs';ただ、この書き方をすると後述するESM/CJS両対応パッケージを作りにくくなるのが悩ましいところ。Modulesでは従来のscriptに比べて以下のような違いがある。Modulesでは、従来のCJSでは使えた以下のようなグローバル変数が削除されている。requiremoduleexports__filename__dirnamearguments最初の3つが意味することは、ESMの中でrequire()を使ってCJSを読み込んだり、ESMとCJSの両方の方式でexportしたりすることはできないということ(CJSを呼び出す方法は後述)。__dirnameについては、URLベースになったため単純な置き換えが不可能として削除された。よってファイルのURLが取得可能にすることが検討されている。詳細は未定だが、こんな感じになりそう。file:///foo/bar.mjsimport.metaは、言語仕様に入らないホスト依存のメタ情報をモジュール内部に渡す役割をする特殊なプロパティ。他にはブラウザではモジュール内部からscript要素の各種属性へのアクセスなんかもこれを使うことが検討されている。Modulesを読み込むESMからは、CJSを直接importで読み込むことができる。module.exports}のようなESMとして扱われる。exportは利用できない。繰り返しになるが、以下のように書くとエラーになる。'readFile'つまり、インポート先のパッケージがESMなのかCJSなのか把握しておく必要がある。従来のrequireように、宣言的ではなく命令的に、かつ同期的にCJSを読み込みたい場合はどうするの?という要望に対しては、import.meta.requireとして提供するということも検討されているようだ。(ついさっき実装完了した模様)でだけ使えるもの。8等で実行したCJSファイルからESMを読み込めるというわけではない(もちろんpolyfill等は出てくるだろうけど)。Importimport()はPromiseを返すので、そのまま.then()でつなぐか、awaitで受ける。Import自体は、CJSとESMのどちらの中でも使える。ESMでは条件別ロードや遅延ロードで利用される想定。importしか扱えない。handは用意されていないため、上述のように.defaultにプロパティアクセスするか、以下のようにDestructuringを使うしかない。index.jsという挙動になるので、Babel等でimport/export文をCJSにトランスパイルすると同時に拡張子を.mjsから.jsに変換し、両方をnpmパッケージにバンドルすると、ESM/CJS両対応パッケージとなる。サンプルリポジトリを用意したので詳細はこちらを参照。#60どれもpros/cons、トレードオフがあって、完璧な解決策はない。module関連のissueはbikeshedなため数百のレスがついてしまいもはやオープンな議論はほぼ不可能なんじゃないかという印象なので、個人的にはとにかく最初の仕様と実装を進めることが大事だと思う。その最初の実装として.mjsは仕様も実装もシンプルなので進めやすい。Modulesの議論をリードしているbmeckも、.mjs以外の案について排他ではなくadditionalな仕様として検討したいと発言している。Modulesがどんどん広がって本当に収拾がつかなくなってしまうので。module";については、先月のTC39でECMAScript仕様に入れるか議論されたが、ネガティブな意見が多く進まなかった。ES仕様に入れるためにはNodeだけでなくブラウザでも有益であることを示すことが求められた。module";を採用することもできる(ECMAScript仕様に準拠した拡張として可能)が、Node陣営としてはそれは行わない方針らしいので、このまま行くとこの提案はお蔵入りになりそう。.mjsの不安なところは、マネージドサービスのcontent-typeが対応してくれるかどうか。Pagesから.mjsファイルをscript要素で読み込んでも実行できずエラーになる。.mjsというNode.js特有仕様なので(Web/ブラウザの仕様ではない)、それを各種サービスのWebサーバー設定にどれだけ反映してくれるのだろうか。apacheでのデフォルト設定の改善などに向けて動いているとのこと。h2oにもプルリクが来ている。Codeの対応はマージ済み。NodeのCLIで標準入力や-eから実行するときはどうするの?拡張子を指定するためのフラグが検討中。Modulesでは以下の様なモジュールラッパーによって特殊な変数を提供していた。here});https://nodejs.org/api/modules.html#modules_the_module_wrapperESMの提供というタイミングで、識別子がURLベースになったこと、非標準なグローバル変数を外したい、といった要因で削除された。今後、こういったホストから提供される情報はimport.metaを経由するのが標準になっていくはず。その方がbrowserify的な変換もしやすいし。いつ使えるようになるの?現時点でプルリクはまだレビュー中。Modulesを学んでいるという印象。プルリクでは--harmony-modulesフラグ付きで実行することになっている(フラグの名称は議論中なので変わるかも)。さっき--experimental-modulesに変更された。freezeしてbetaリリース、10月にRCをリリース予定としている。Modulesのフラグ付き実装がリリースされそう。v10でフラグを外すのは難しいと予想する。v12でLTSデビューという流れか。いうポリフィルパッケージがリリースされたので試せる。importのポリフィルを当てるライブラリ。パフォーマンスへの配慮か、tar.gzで固めるなどパッケージングの仕方もおもしろい。JavaScriptは実現しますか?識別子の仕様の違いから、素の静的なHTTPサーバーだけで実現することは難しい。識別子の拡張子を省略するとブラウザは解釈できない。node_modules以下のnpmパッケージを参照する方法がない。'./foo'では動かないので./foo.mjsにする必要があるが、そうするとNode.js側でのフォールバックが素直にはできなくなって辛い。'foo'のような、絶対URLでもなく、.または/から始まらない文字列は認めていないのでエラーになる。Workerで変換を挟むなどして頑張る必要がある。Babelは分かったが、TypeScriptはどうなの?まだちゃんと議論は始まってないけど、おそらくちゃんとコードを書いてればTypeScript側のトランスパイルで吸収してくれそう。TypeScriptには二つのモジュール構文がある。使うというルールがある(と思う)。それが徹底されている限りはTypeScriptのトランスパイル側で吸収してくれるはず。この辺りは、型の整合性を保つ必要があるので、Babelに比べると厳格に検討されていたことが結果的に良かった。Modulesサポートの現状確認と備え広告を非表示にするコメントを書くもっと読む2017-08-21thank-you-starsで利用しているnpmパッケージに気軽にスターを送る先週、こういうツイートを見て、OSSを使っているなら、GitHubのリポジトリにそっとスターをつけると開発者のキャリアにわりと直接的に貢献できるのでお薦めです。共感したのでサクッと作った。github.compackage.jsonと同じディレクトリで実行するだけで、depsとdevDepsのパッケージのGitHubリポジトリにスターできる。事前にパーソナルトークンをホームディレクトリに保存しておく必要があるけど、その辺はREADMEを読んでくれ。依存に入れて使っているということは、それなりに恩恵を受けているということなので、問答無用でスターを送ってしまって良いと思う。孫依存のパッケージにも送るか迷ったけど、npm的にそこ含めると一気に数が膨れてしまうのでやめた。これでみんなももりもりスターを送ろう!package.jsonに関する知見これだけの単純なパッケージながら多少の知見が得られたので共有。"git@github.com:facebook/react.git"}のようなオブジェクト型だけど、文字列型でfacebook/reactなどの特殊形も認められていて扱いがめんど臭い。npmの中で使っているパッケージを調べたらこれだったので同じものを使った。https://www.npmjs.com/package/normalize-package-dataこれによって、typeとurlのあるオブジェクト型に統一される。他のプロパティも一通り正規化できるし、オプションによってバリデートも可能なので、package.jsonを扱うときに必要なら使うと良い。GitLabなどの特殊な省略形式があって、これまた扱いが面倒。npmの内部ではこれを使っている。IssuesのURLを生成できたりして、非常に便利。package.json以外の用途でもGitHubいじるときに使えそう。無事リリースされたので、betaが取れるのを待ってた方は是非どうぞ。今の所は爆速だったbeta時代と遜色ない速度で動いてる。2.0のメリットは前回記事に書いたのでご参照ください。GAがリリースされたので、curlではなく標準機能Workflowsを使ったバージョンを紹介する記事を書いたので、こちらをご参照ください。2.0が高速でカスタマイズできて最高だという話と、Node.jsのマルチバージョンテストのやり方、キャッシュ戦略などを紹介する。前提として、以下はnpmパッケージのようなユニットテストでほぼ完結するシンプルなライブラリのCIを想定している。サービスやアプリ開発のCIは要求が違ってくるのでまた別。先に結論としてサンプルプロジェクトを貼っておく。2.0はまだβテスト中なので、もろもろ変更される可能性はある。ここから申し込めばすぐ使えるようになるのでGO。oss先日アナウンスされた脆弱性とその周辺について、とりとめなく。よれば、今回問題になっているのはnpmの以下の性質を利用するとnpmパッケージでワーム(自己増殖力のあるマルウェア)を作れるというもの。いうリポジトリを公開している*1。以下のように動作する。publishが失敗するだろうが、npmの外部パッケージ依存度の高さから一部のオーナーに感染すれば雪だるま式に拡散するだろう、と主張している。所有パッケージを根こそぎダウンロードしてワーム仕込んだ方が効率的な気がする。/*するPoCパッケージが公開された騒動でも話題になった。inc.は問題あるパッケージを都度削除する対応を取った。今回のポイントは、ワームが仕込まれてても同じことできるの?ということ。有名パッケージも含めて大量のパッケージがガシガシ感染していったらどうする?都度削除とかムリだし取り返しつかない状態になるのでは?と。たしかに、substackやsindresorhusが感染したらと想像するとやばそう。npmブログの見解としては、publishの頻度をモニタリングしてるから、ワームが広がり始めたら全体のpublishを止めるよ、と言っている。したらいいの?さて各ユーザーはどう対応したら良いのか。--ignore-scriptsnpmはブログでは以下の方法が紹介している。trueで上記動作をデフォルトに設定するしかし、npm自身もブログで書いていることであるけど、installスクリプトを防いだところで、そのパッケージ自身に悪意のコードがあればrequireした時点で攻撃されてしまう。感染力を弱める効果は多少あるかもしれないけど、攻撃コードの実行を防ぐという意味では正直気休め程度かなと思う*2。installスクリプトが動かないことでインストールできないパッケージもあったりして面倒(行儀悪いけど)。shrinkwrapshrinkwrapを使って子孫すべての依存関係をロックして、感染したパッケージがアップデートしたバージョンの混入を防ぐ方法。依存関係のアップデートするときどうするの?というのはあるけど、感染力はだいぶ弱まりそう。ライブラリ系だと現実的には運用が厳しいし、全パッケージがshrinkwrapし始めたらnpmの思想を根本的には壊しかねない気がする。publishなど必要なときだけログインする方法。ログアウトしておけば、自分自身の環境での悪意のコード実行は防げないけど、自分が所有するパッケージへの感染による拡散は防げる。認証が必要な操作って普通はpublishぐらいなので、普通の人は頻繁に使わないから問題なさそう。npmさん、ぜひログイン状態を永続化せず都度パスワードを聞くようにするオプションを付けて欲しい。authを準備中らしい。オープンソースと信頼ということで、今回のワームの拡散は認証周りをちゃんとやれば防げそうそうだけど、根本的な問題である悪意のあるコードの実行を防ぐのは難しい。当たり前ではあるのだけど、当のnpmに改めて言われるとなかなか重い。Contoliniのブログにはこう書いてある。Contolini普段は目をそらしがちではあるのだけど、オープンソースだからといってセキュアなわけではないし、誰かが見てくれている保証もない。いう問題ってモダン≒オープンソースをベースにしたソフトウェア開発では共通する問題だと思うけど、多くの細かい外部パッケージに依存しがちなNode.js世界では特に大きな影響がある。先日のkik/left-pad問題にもつながる話だ。マイクロパッケージ文化には光の側面と闇の側面がある。自分が依存するパッケージ、その子孫までの中にどこにも悪意のコードが無いことを自信を持って言えるだろうか?ねずみ算式に増えるので自分ですべてチェックするのは現実的にはムリだろう。ただの考えすぎで善意が解決してくれる問題なのか、プロジェクトの性質によって対応を考えればよいのか。他の言語では何か仕組みがあるのかな?できればnpmの自由な雰囲気と両立できる何かがほしい。いうちょうど良いものがあるじゃないですか!なんだ、すべては杞憂だったのか(違う)。*1:npmには公開されてない。追加される機能が以下の2つに決定した。Operator今後は3月1日にスペックのスナップショットが切られ、6月の公開に向けた作業が始まる。新しい策定プロセスを確認されたし。仕様策定プロセスは機能ベースで毎年リリースするスタイルになった。4になる)ためには2つ以上の実装が必要ということ。Meetingをもって実装の締め切り宣言がなされた。実装済み、という状況。これで実装が2つとカウントされたことから、少なくとも4大ブラウザに実装されればフラグ付きだったりStable版でなかったりしてもカウントされると考えて良さそう。V8には実装されたけどChromeには載ってない、とかだとどうなんだろう。確定したので、改めて。いう言葉が使われがちという問題があった。ES7の機能セットが確定して明らかな誤用と言えるレベルになってきたので、さすがにもう使うべきでない。proposalsと言及するか、あるいは単にESと言う方がまだ誤解が少ない。おいてはもはやバージョン番号は重要ではないのだから。先生も同じようなエントリを書いてた。入るか入らないかはあまり重要ではない。年度の切り替えがいつかという手続き上の問題に過ぎないので。Phelpsがほぼ同じ記事をポストしている。呼ぶことを推奨している。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。