LoginSignup
11
2

More than 1 year has passed since last update.

Deno1.17で導入されるJSONインポートを試す

Last updated at Posted at 2021-12-15

Deno1.17でついにJSONインポートが導入されます!!

もともとDenoにはバージョン0時代にJSONインポートが実装されていました(#1065)。当時の構文はimport json from "./foo.json"という単純なものでした。
しかし、JSONインポートがECMAScript仕様に入るにあたりassert { type: "json" }という構文(Import Assertions)への対応が必要になったため、バージョン1.0.0リリース時にJSONインポートは削除されていました(#5037)。
先日TypeScript4.5がリリースされたことで、Import Assertionsへの対応が全て完了したため、再びDenoにJSONインポートが導入されました。(swcやv8などは既に対応しており、TSが最後のブロッカーでした。)

JSONインポートを試す

JSONインポートは12月16日リリースのDeno1.17で導入されるのですが、アドベントカレンダーの担当日的な意味でギリギリ間に合わないので、canary版を使って試していきます。

※canary版のリリースもギリギリ間に合わなかったので(日本時間で12/16の朝4時)、投稿が遅れました。ごめんなさい。

canary版へアップデート
> deno upgrade --canary

先ほど述べた通り、JSONインポートはImport Assertionsと組み合わせて使います。

test.json
{ "Hello": "World" }
JSONインポート
import data from "./test.json" assert { type: "json" };
console.log(data); //=> { Hello: "World" }

ちなみに、型推論も効きます。

image.png

複数回importした時の挙動

1つのJSONファイルを複数回importした時、===で比較するとtrueになります。

import data1 from "./test.json" assert { type: "json" };
import data2 from "./test.json" assert { type: "json" };
console.log(data1 === data2); //=> true

プロパティを書き換えた時の挙動

上で実験した通り、複数回importすると参照が同一になります。
importしたモジュールの一部を書き換えた場合、他の場所でimportしたモジュールも書き換わってしまうのか試してみます。

import data1 from "./test.json" assert { type: "json" };
import data2 from "./test.json" assert { type: "json" };

data1.Hello = "Konnichiwa";
console.log(data2.Hello); //=> "Konnichiwa"
// data1の内容を変更したら、data2の内容も変更される!

無事(?)、他の場所でimportしたモジュールの内容も書き換わりました。
JSONモジュールを複数回importする時は、プロパティを書き換えると意図せず他の場所に影響を及ぼすかもしれないので、気を付けましょう。

動的import

動的importでもJSONインポートを利用することができます。

const { default: data } = await import("./test.json", {
  assert: { type: "json" },
});
console.log(data);

JSONインポートはdefault exportとして扱われるため、代入時にdefaultで受ける必要があります。
data URLとの組み合わせも可能です。

function JSONParse(code: string) {
  return import("data:application/json," + encodeURIComponent(code), {
    assert: { type: "json" },
  });
}
console.log(await JSONParse('{"Hello":"World"}'));

まあこれはただのJSON.parseなので、使い道はありませんが…

JSのimport構文の今後

Import Assertionsの導入により、JavaScript以外のリソースをimportできるようになりました。まず手始めにJSONのimportが導入されたわけですが、JSON以外のimportも導入が検討されています。
なお、以下はDenoに限った話ではなく、ブラウザ含むJavaScript・Web標準についての話になります。

CSS / HTMLのimport

CSSについてはCSS Module Scriptという名前で標準化が進んでいます。
Chromeなど、いくつかのブラウザでは既に利用可能です。

import sheet from './styles.css' assert { type: 'css' };

Denoにはまだ導入されていません(そもそも導入すべきか決まっていないような状況)。個人的には、将来フロントエンド開発にDenoが使われるようになり、ブラウザのCSSモジュールとよく連携できるならば、導入するのもアリだと思います。

HTMLインポートについては仕様がまだ議論中のようです。

アセット参照

importに似た構文で、assetという構文の導入が検討されています。

asset Logo from "./logo.gif";

「このファイルはimportするわけではないけど後で使うよ」というのを宣言するための構文です。assetで宣言しておくとバンドラーが画像やHTMLをまとめてバンドルしてくれる、みたいな事も可能になります。あとはDenoでdllファイルなどを呼び出すときに、assetで読み込むことで--allow-read,--allow-netフラグが不要になり--allow-ffiフラグのみでOKになるといった効果が期待できます。
もちろん、TSやリンターのような静的解析にも役立つでしょう。

Import Reflection

こちらはImport Assertionの姉妹のような構文で、importしたモジュールの評価方法を指定する構文です。

import FooModule from "./foo.wasm" as "wasm-module";

例に出した通り、これはWasmモジュールをimportするための構文です。
(今知ったのですが)Wasmを実行するには型付き配列をWebAssembly.Moduleに一旦変換してからWebAssembly.Instanceに変換しないと実行できないそうです。
WebAssembly.ModuleWebAssembly.Instanceのどちらの形式でimportするかを選べるようにするため、この構文が必要なようです。

実はこのproposal、DenoコアチームのLuca Casonatoさんが主導しています。先日発表された「DenoがJavaScriptの仕様策定に参加する」というニュースでもBetter support for non-JS assets in the ES module graphと書かれているとおり、DenoとしてもJSのモジュールシステムを改善していきたいと考えているみたいです。

まとめ

Deno1.17で導入されるJSONインポートを試してみました。

そもそもNode.jsのエコシステムではrequireや拡張子無しimportがある上、ライブラリやバンドラーが勝手に独自でCSSやJSONのimportをサポートしていたりする現状があります。
はやくこの辺の構文が統一されて、普通に動くようになってほしいですね。

11
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
2