0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

webcomponentsやesmのjsのscope

Posted at

jsの読み込み方と、定義が見えるかどうか。変数のスコープ

MACのChrome バージョン: 76.0.3809.132

head内 body直下 body内の子要素 template内 templateからコピーされたbody直下要素 shadow-dom内
class定義 読めた 読めた 読めた 読めなかった 読めた
global変数定義 読めた 読めた 読めた 読めなかった 読めた 読めた
global変数定義(esm) 読めなかった 読めなかった 読めなかった
window変数定義(esm) 読めた 読めなかった 読めた
export(esm) 読めなかった 読めなかった 読めなかった

このことから

  • shadow-domは特にjsの実行環境を隔離したりはしない
  • esmを使ってもesmの中でwindow変数を弄られたら無理
  • template(DocumentFragment)は、実際にFragmentじゃないDomに追加するまで、読めないしそもそも定義が走ってないっぽい

という事がわかる。

つまり、webcomponentを作るときに、副作用なく&自己管理なものを作るとなると、

  • html/cssについては、shadow-domを使えば思考停止でOK
  • jsは、exportが定義されている行儀のよいesmのみを利用する
  • jsは、windowに書き込まない行儀のよいもののみ利用する
  • jsは、idはclassを扱わず、直接elementを扱う行儀のよいもののみ利用する

を守る必要がある。現実にそんなお行儀の良いjsなわけはないので、現実的ではない。

「副作用なく&自己管理」を諦めて、

  • 「webcomponentの依存ライブラリを、予めmainHTML側の責任で読み込む」という使い方を強いる
  • jsは、idはclassを扱わず、直接elementを扱う行儀のよいもののみ利用する
  • 「webcomponent側で、引数にshadowRootを取りjs関係をactivateする関数を提供し、mainHTML側の責任でそれをcallさせる」という使い方を強いる

が限界か。


定義箇所詳細

head内

head内
<head>
  <script></script><!-- ← ここで定義 -->
</head>
<body>
  <button onclick="console.dir(xxx)">check</button> <!-- ← ここでチェック -->
</body>

body直下

body直下
<body>
  <script></script> <!-- ← ここで定義 -->
  <button onclick="console.dir(xxx)">check</button> <!-- ← ここでチェック -->
</body>

body内の子要素

body内の子要素
<body>
  <main>
      <script></script> <!-- ← ここで定義 -->
  </main>
  <button onclick="console.dir(xxx)">check</button> <!-- ← ここでチェック -->
</body>

template内

template内
<head>
  <template>
    <script></script> <!-- ← ここで定義 -->
  </template>
</head>
<body>
  <button onclick="console.dir(xxx)">check</button> <!-- ← ここでチェック -->
</body>

templateからコピーされたbody直下要素

templateからコピーされたbody直下要素
<head>
  <template>
    <script></script> <!-- ← ここで定義 -->
  </template>
</head>
<body>
  <script>
      const body = document.querySelector('body');
      const template = document.querySelector('template');
      body.appendChild(
        document.importNode(template.content, true)
      );
  </script>
  <button onclick="console.dir(xxx)">check</button> <!-- ← ここでチェック -->
</body>

shadow-dom内

<head>
  <template>
    <script></script> <!-- ← ここで定義 -->
  </template>
</head>
<body>
  <main></main>
  <script>
    const main = document.querySelector('main');
    const template = document.querySelector('template');
    main.attachShadow({mode: 'open'}).appendChild(document.importNode(template.content, true));
  </script>
  <button onclick="console.dir(xxx)">check</button> <!-- ← ここでチェック -->
</body>

定義方法詳細

class定義したinlinejs

<script src="./XxxClass.js"></script>
./XxxClass.js
class XxxClass {
}

global変数定義

<script src="./XxxGlobalVar.js"></script>
./XxxGlobalVar.js
xxx = "{{{xxx}}}";

global変数定義(esm)

<script type="module" src="./XxxGlobalVarEsm.js"></script>
./XxxGlobalVarEsm.js
xxx = "{{{xxx}}}";

window変数定義(esm)

<script type="module" src="./XxxWindowVarEsm.js"></script>
./XxxGlobalVarEsm.js
window.xxx = "{{{xxx}}}";

export(esm)

<script type="module">
  import { xxx } from "./XxxExport.js";
</script>
XxxExport.js
export const xxx = '{{{xxx}}}';
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?