[riot.js v7]コンパイルしたtagの読み込みをmodule形式以外で行う方法
Riot.js Advent Calendar 2022 の7日目の記事なります。(埋まれ~)
未だにv3推しですが需要もなさそうなので、今回はRiot v7についての記事を書きたいと思います!
公式ページではriot.jsのタグをプリコンパイルして使用する際は<script type=”module”>を使用して読み込む例が記載されています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<body> <!-- body 内の任意の位置にカスタムコンポーネントを配置 --> <my-component></my-component> <!-- riot.js を導入 --> <script src="riot.min.js"></script> <!-- コンポーネントをマウント --> <script type="module"> // @riotjs/compiler で生成されたコンポーネントの JavaScript の出力をインポートする import MyComponent from './my-component.js' // the riot コンポーネントを登録 riot.register('my-component', MyComponent) riot.mount('my-component') </script> </body> |
できるだけ互いの機能に干渉しないように独立したモジュールとして開発を行うのが良い作法だと思いますが、僕はグローバルな通常の<script>で使用したい場合が多いです。
そこで”通常”の<script>で使用する方法を解説します。
ちなみにブラウザコンパイルを行うriot+compiler.min.jsライブラリを使う場合は”通常”の<script>で使用する事が可能です。
プリコンパイルされたtagを使うriot.min.jsライブラリを使用する場合は<script type=”module”>でしか使用できないように思います。
📓 この”通常”の<script>で処理する方法をなんと呼ぶのが正しいのでしょうか…検索の時なども悩みます…
実践
次のようなタグ(my-tag.html)を作り
1 2 3 4 5 6 |
<my-tag> <p>Hello {test}.</p> <script> this.test = 'yamada'; </script> </my-tag> |
それをコンパイルしたmy-tag.jsがあったとします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
export default { css: null, exports: function exports() { this.test = 'yamada'; return this; }, template: ( template, expressionTypes, bindingTypes, getComponent ) => template( '<p expr4="expr4"> </p>', [ { redundantAttribute: 'expr4', selector: '[expr4]', expressions: [ { type: expressionTypes.TEXT, childNodeIndex: 0, evaluate: _scope => [ 'Hello ', _scope.test, '.' ].join( '' ) } ] } ] ), name: 'my-tag' }; |
始まりが export default なのでモジュールとしてしか読み込めません。
riot+compiler.min.jsの場合には、string状態のtagを export default
→ return
で置換して、objectとして読み込むメソッド(riot.inject)が用意されています。そのため”通常”の<script>で読み込むことができます。
ソースコードを参考に同じような役割の関数を作ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function tagStrToObj(code, url = null){ let temp = 'BjNw93'; //適当なグローバル変数の名前 while (window[temp]!==undefined) temp += 'x'; //同名が存在した場合xを追加 const js = `window.${temp} = (function (global){${code}})(this)`.replace('export default', 'return'); //適当なグローバル変数にtagを読み込むjsテキストを作成 const node = document.createElement('script'); const root = document.documentElement; node.text = url ? `${js}\n//# sourceURL=${url}.js` : js; //必要ならchromeのdevツールで表示するでソース名(URL)を設定 root.appendChild(node); root.removeChild(node); //作成したjsテキストをscriptで読み込み後、すぐ削除 const tag = window[temp]; //グローバル変数からobject化したtagを取得 delete window[temp]; //一時的に作ったグローバル変数を削除 return tag; } |
使い方
公式の例と同じ事が次のように書けます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<body> <my-tag></my-tag> <script src="riot.min.js"></script> <script> fetch('my-tag.js') .then(response => response.text()) .then(text => { const tag = tagStrToObj(text); //ここで使う riot.register(tag.name, tag); riot.mount(tag.name); }) </script> </body> |
またriot.component()を使用して、コンポーネント(タグ)をグローバルに登録せずコンポーネントを生成・マウントすることもできるはずです。
1 2 3 4 5 |
const createApp = riot.component(tag); const app = createApp(document.getElementById('root'), { name: 'This is a custom property', class: 'custom-class' }); |
結び
riot+compiler.min.js(313KB, gzip:88KB)が重いためriot.min.js(15.7KB, gzip:5.78KB)を使いたいと言うときの参考になれば
また文字列のtagをobjectに変換できるとなにか別の利用法もありそうだと思い実現できる方法考えてみました。
さらにriotの記事が増えることを期待してます!!!!