Custom Element のモジュールで define すべき?
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ define するならクラスはエクポート不要
◆ グローバルに登録されるので get で取得できる
◆ define しないと使う側で登録の手間が増える
◆ 複数箇所で登録するとエラーなので共通のラッパーモジュールが必要になる
◆ define までモジュール内でやったほうが良いと思う
◆ グローバルに登録されるので get で取得できる
◆ define しないと使う側で登録の手間が増える
◆ 複数箇所で登録するとエラーなので共通のラッパーモジュールが必要になる
◆ define までモジュール内でやったほうが良いと思う
普段 Custom Element のモジュールをつくるときはこういう感じで書いています
必要に応じて import したり関数定義を追加しますが メインの Custom Element 部分は customElements.define に直接書くだけです
クラスのエクスポートはしません
React や Vue とは違って Custom Element はグローバルに登録するしかないので define 関数で登録すればエクスポートするものはありません
使う側は import するだけです
継承したり static メソッドの呼び出しをしたいことはありますが customElements.get で取得できるので クラスをエクスポートしなくても困りません
共通処理を持たせただけの createElement しないベースクラスの場合はエクスポートします
これで特に困ってなかったのですが クラスをエクスポートしたり define しない書き方をしているものも見かけたので少し考えてみました
クラスのエクスポートが必要かについては customElements.define をしているならなくてもいいと思います
一度 define したものは上書きや削除などの変更はできないので import に成功していれば確実に customElements.get で取得できるはずです
import 構文で一緒に受け取りたいとか そのほうがインポートする側のコード量が少し減るとかあるかもしれませんが どっちじゃないと困るとかは無いので好みの問題です
モジュール内で define を実行すべきかという点では やっぱりしておいたほうが良いと思います
foo-bar 要素があって 動きを変えたい時に define していなければ
のように同じ名前で継承したものを使ったりできます
しかし Custom Element の定義はグローバルなので継承したものじゃない元のを想定して使ってるライブラリもありえます
また foo-bar 要素を拡張する気がなくて 2 箇所で foo-bar 要素を使う場合
のように 使う側が define をしないといけなくなり手間です
さらに 1 つのページでこの 2 ファイルの両方を import した場合 foo-bar を二重に登録するのでエラーになります
登録内容は同じですが無視されずエラーが起きます
これを防ごうとすると foo-bar を登録するラッパーが必要で
これを 2 箇所から import する必要があります
2 箇所目で import されてもモジュールがインポート済みなので define 処理は実行されず エラーは起きません
使うときにこういうのを作らないといけないのは手間ですし foo-bar 要素を提供する側としても 2 種類のファイルを作るのは手間です
少し楽にするために モジュールでは URL のクエリパラメータを取得できるので 「define=false」 があれば define しないとすることもできます
こういうことをする場合 クエリパラメータのありなしは別の URL 扱いです
ありなしの両方を import した場合は 2 回実行されます
ただ この仕組みが役に立つのは foo-bar という名前を使ってしまっては困るときで 実際には異なるライブラリで同じ名前を使ってるようなケースくらいでしょう
基本的にライブラリ名を含めるなど重複しないようにしてそうですし やっぱり余計なことはせずシンプルにモジュール内で define する作りでいいと思います
customElements.define("foo-bar", class extends HTMLElement {
//
})
必要に応じて import したり関数定義を追加しますが メインの Custom Element 部分は customElements.define に直接書くだけです
クラスのエクスポートはしません
React や Vue とは違って Custom Element はグローバルに登録するしかないので define 関数で登録すればエクスポートするものはありません
使う側は import するだけです
継承したり static メソッドの呼び出しをしたいことはありますが customElements.get で取得できるので クラスをエクスポートしなくても困りません
import "./foo-bar.js"
customElements.define("ex-foo-bar", class extends customElements.get("foo-bar") {
//
})
共通処理を持たせただけの createElement しないベースクラスの場合はエクスポートします
//// base.js
export default class extends HTMLElement {
//
}
//// foo-bar.js
import Base from "./base.js"
customElements.define("foo-bar", class extends Base {
//
})
これで特に困ってなかったのですが クラスをエクスポートしたり define しない書き方をしているものも見かけたので少し考えてみました
クラスのエクスポートが必要かについては customElements.define をしているならなくてもいいと思います
一度 define したものは上書きや削除などの変更はできないので import に成功していれば確実に customElements.get で取得できるはずです
import 構文で一緒に受け取りたいとか そのほうがインポートする側のコード量が少し減るとかあるかもしれませんが どっちじゃないと困るとかは無いので好みの問題です
モジュール内で define を実行すべきかという点では やっぱりしておいたほうが良いと思います
foo-bar 要素があって 動きを変えたい時に define していなければ
//// foo-bar.js
export default class extends HTMLElement { /* */ }
//// ex-foo-bar.js
import FooBar from "./foo-bar.js"
customElements.define("foo-bar", class extends FooBar { /* */ })
のように同じ名前で継承したものを使ったりできます
しかし Custom Element の定義はグローバルなので継承したものじゃない元のを想定して使ってるライブラリもありえます
また foo-bar 要素を拡張する気がなくて 2 箇所で foo-bar 要素を使う場合
//// foo-bar-user1.js
import FooBar from "./foo-bar.js"
customElements.define("foo-bar", FooBar)
// something
//// foo-bar-user2.js
import FooBar from "./foo-bar.js"
customElements.define("foo-bar", FooBar)
// something
のように 使う側が define をしないといけなくなり手間です
さらに 1 つのページでこの 2 ファイルの両方を import した場合 foo-bar を二重に登録するのでエラーになります
登録内容は同じですが無視されずエラーが起きます
これを防ごうとすると foo-bar を登録するラッパーが必要で
//// foo-bar-wrapper.js
import FooBar from "./foo-bar.js"
customElements.define("foo-bar", FooBar)
これを 2 箇所から import する必要があります
2 箇所目で import されてもモジュールがインポート済みなので define 処理は実行されず エラーは起きません
使うときにこういうのを作らないといけないのは手間ですし foo-bar 要素を提供する側としても 2 種類のファイルを作るのは手間です
少し楽にするために モジュールでは URL のクエリパラメータを取得できるので 「define=false」 があれば define しないとすることもできます
const should_define = new URL(import.meta.url).searchParams.get("define") !== "false"
if (should_define) {
customElements.define(...)
}
こういうことをする場合 クエリパラメータのありなしは別の URL 扱いです
ありなしの両方を import した場合は 2 回実行されます
ただ この仕組みが役に立つのは foo-bar という名前を使ってしまっては困るときで 実際には異なるライブラリで同じ名前を使ってるようなケースくらいでしょう
基本的にライブラリ名を含めるなど重複しないようにしてそうですし やっぱり余計なことはせずシンプルにモジュール内で define する作りでいいと思います