🦕

Deno 1.16 localStorage ハンズオン

2021/11/14に公開

Deno 1.16にてlocalStorage APIの更新が入りました。

https://zenn.dev/kawarimidoll/articles/0d384d53953525#localstorageの使用に--locationが不要になった

上記記事でも書いていますが、--locationオプションがなくてもエラーなくlocalStorageを使用できるようになりました。
従来通り--locationをつけることでバケットのキーを直接指定できますが、この指定がない場合はメインモジュール(エントリーポイント)のパスがキーとして使われます。

https://deno.land/manual/runtime/web_storage_api

本記事では1.16のリリースノートに沿って、これを試してみます。

https://deno.com/blog/v1.16#localstorage-does-not-require---location-anymore

基本の読み書き

以下のようなファイルを用意します。

~/one.js
console.log(localStorage.getItem("file"));
localStorage.setItem("file", Deno.mainModule);

Deno 1.15.xまではこれをそのまま実行するとエラーになっていました。

❯ deno --version
deno 1.15.3 (release, aarch64-apple-darwin)
v8 9.5.172.19
typescript 4.4.2

❯ deno run one.js
error: Uncaught ReferenceError: Access to "location", run again with --location <href>.
console.log(localStorage.getItem("file"));
            ^
    at get (deno:ext/web/12_location.js:381:17)
    at createStorage (deno:ext/webstorage/01_webstorage.js:94:28)
    at localStorage (deno:ext/webstorage/01_webstorage.js:179:24)
    at file:///Users/kawarimidoll/one.js:1:13

Deno 1.16.x以降はエラーなく実行できるようになっています。
Deno.mainModuleへのアクセスには--allow-read権限が必要です

❯ deno --version 
deno 1.16.1 (release, aarch64-apple-darwin)
v8 9.7.106.2
typescript 4.4.2

❯ deno run --allow-read one.js
null

❯ deno run --allow-read one.js
file:///Users/kawarimidoll/one.js

初回の実行ではストレージに何も保存されていないため、nullが表示されています。
その後Deno.mainModuleを保存しているので、2回目の実行ではそれが表示されています。

https://doc.deno.land/builtin/stable#Deno.mainModule

同ディレクトリの別ファイル

続いて同ディレクトリに同内容のファイルを用意します。

❯ cp ./one.js ./two.js
~/two.js
console.log(localStorage.getItem("file"));
localStorage.setItem("file", Deno.mainModule);

one.jstwo.jsで内容は同じですが、メインモジュール(エントリーポイントの絶対パス)が異なるため、参照するlocalStorageのバケットキーが異なります。
したがって、two.jsone.jsの保存先は別であり、互いに関係しません。

❯ deno run --allow-read two.js
null

❯ deno run --allow-read two.js
file:///Users/kawarimidoll/two.js

two.jsからはone.jsで保存した内容が見えないことがわかります。

importしたファイル

前述のtwo.jsをインポートしてそのまま実行するthree.jsを作ってみました。 これはどうなるでしょうか。

three.js
import "./two.js";

localStorageのバケットのキーはあくまでメインモジュールに依存し、localStorage
APIを使用しているファイルではありません。 したがって、three.jstwo.jsの保存先も、やはり別になります。

❯ deno run --allow-read three.js
null

❯ deno run --allow-read three.js
file:///Users/kawarimidoll/three.js

もしこれがlocalStorageAPIを使用しているファイル(ここでいうとtwo.js)に依存してしまうとどうなるでしょうか。例えばlocalStorageをラップしたAPIを提供するモジュールがあった場合、そのモジュールを使用しているプログラム同士でバケットが共有されてしまうことになります。
これは望ましい挙動ではないので、エントリーポイントで区別されるというのは理にかなっていますね。

--configオプションの使用

--configオプションで設定ファイルを指定してdeno runすると、その設定ファイルの絶対パスがバケットのキーとして使用されます。
https://deno.land/manual@v1.16.1/getting_started/configuration_file

ファイルは中身がなくても構いません(存在していないとエラーになります)。

~/deno.jsonc
{}

絶対パスがキーとして使われるということは、同じ設定ファイルを使っていれば、別々のプログラムでもバケットが共有されるということです。
以下のように、one.jsで保存した内容をtwo.jsから、逆にtwo.jsで保存した内容をone.jsから読めるようになります。

❯ deno run --allow-read --config=deno.jsonc one.js
null

❯ deno run --allow-read --config=deno.jsonc one.js
file:///Users/kawarimidoll/one.js

❯ deno run --allow-read --config=deno.jsonc two.js
file:///Users/kawarimidoll/one.js

❯ deno run --allow-read --config=deno.jsonc one.js
file:///Users/kawarimidoll/two.js

同一プロジェクト内のプログラムであれば、同じ設定ファイル・localStorageバケットを共有したい可能性は高そうなので、この挙動は適切だと思います。

また、ここで初回のone.jsの実行でnullが出力されていることからわかるように、先程のオプションを付けない実行で保存した内容は見えていません。
先程はone.jsのパスがキーになっていて、今回はdeno.jsoncのパスがキーになっており、別々のバケットを見ているためです。

--locationオプションの使用

前のバージョンからあった方法です。--locationに渡したURLのオリジンがバケットのパスとして使われます。
https://deno.land/manual@v1.16.1/runtime/location_api

--configオプションの場合と同じく、別ファイル同士でバケットを共有していることがわかると思います。

❯ deno run --allow-read --location=http://example.com one.js
null

❯ deno run --allow-read --location=http://example.com one.js
file:///Users/kawarimidoll/one.js

❯ deno run --allow-read --location=http://example.com/page/1 two.js
file:///Users/kawarimidoll/one.js

❯ deno run --allow-read --location='http://example.com?query=ABC' one.js
file:///Users/kawarimidoll/two.js

❯ deno run --allow-read --location=http://example.com:80 two.js   
file:///Users/kawarimidoll/one.js

オリジン部分がキーとして使われるので、上記のようにパスやクエリが入っていても同じバケットを共有します。
また、ポート80はHTTPのデフォルトポートなので、同一オリジンとなります。

以下は異なるオリジンなので、別バケットとなります。

❯ deno run --allow-read --location=https://example.com one.js   
null

❯ deno run --allow-read --location=http://www.example.com one.js
null

❯ deno run --allow-read --location=http://example.com:8080 one.js
null

https://developer.mozilla.org/ja/docs/Glossary/Origin

おわりに

以上、Deno 1.16から--location不要になったlocalStorage APIの簡単な説明でした。
オプションが不要になっただけで、けっこうカジュアルに使えるようになったのではないでしょうか。
基本的にはファイルごとに別々のlocalStorageを使える、という理解で良いと思います。

なお、バケットのキーが暗黙で設定されるようになったというだけで、location.hrefなどの使用には--locationオプションが必要なのでご注意ください。
https://doc.deno.land/builtin/stable#Location

Discussion