🖼️

Vueで<scripr src=~~>を使うお話

2024/02/08に公開

外部のサービスをサイトに埋め込む時、以下のコードをコピペしてくださいというパターンがよくあります。
そこでそれ用のコンポーネント作って配置を便利にしたいと思い立ったわけです。

しかし、Nuxt3もといVueでは<template>タグの中に<script>タグを入れてしまうとエラーを吐いてしまいます。

そこで<iframe>を使って別に作成した.htmlファイルを読み込む形をとることで、シンプルに実装することができました。そんな記事。

目次

  1. 単純にコンポーネント内で<script>を書いてみる(エラー)
  2. <iframe>を使用して自身が持つ.htmlファイル(仮称)を表示する
  3. <iframe>タグとセキュリティ的なお話(余談)

1. 単純にコンポーネント内で<script>を書いてみる(エラー)

外部サイトの説明書きには<body>タグ内に書けばよいと書いてあるので、単純にそれに対応する<template>タグ内に書いてみよう。

と、何も考えずに実装するとこんな感じ。

エラー文をざっくり英語翻訳すると、"<script><style>といったサイドエフェクトを持つタグは、テンプレートに入れることはできません"とのこと。

これは困った。単純に読み込むだけならnuxt.config.tsで設定すると全部のページに読み込むことができるのだが、今回は外部サービスの要素を表示したいわけなので、<body>内の任意の位置<script>タグを設置する必要がある。

そこでWebページに別のページを埋め込むことができる<iframe>タグを使って、描画された後の外部サービスを埋め込むことで外部コンテンツを設置します。

2. <iframe>を使用して自身が持つ.htmlファイルを表示する

この方法では<iframe>自身が持つ.htmlファイル(仮称)という2つのファクターがあります。
先に自身が持つ.htmlファイルの方から見ていきます。

自身が持つ.htmlファイル(仮称)

このファイル、正確に書くと静的アセットとしてWebサイト自身のルートから公開している.htmlのことを指します。

噛み砕いていうと、"publicフォルダに画像等をファイル入れられるのと同じ要領で.htmlファイルを公開してしまおう"ということ。こんなかんじ。

Nuxt3ではpublicフォルダに入れたものはサイトのトップからのルートで公開されるので、public/test.htmlに配置したものはlocalhost:3000/test.htmlなりhttp://<サイトのドメイン>/test.htmlでアクセスできるわけです。

これはリソースを.htmlファイルとして公開しているので.vueファイルの制約がかからないというわけですね。

これをなんとかしてWebページに埋め込むことで表示が叶いそうだ。

<iframe>タグ

なんとかしてWebページに埋め込むために<iframe>タグを使用します。

Mozillaによると、

<iframe> は HTML の要素で、入れ子になった閲覧コンテキストを表現し、現在の HTML ページに他のページを埋め込むことができます。

とのこと。WebページのなかにWebページ。間違えた使い方するとマトリョシカになって動作が重くなるらしい。

さて、<iframe>で埋め込む際、埋め込むページはsrc属性で指定します。
このとき、/<パス>とすると、自身のサイト内でのパスに対応したページを開くことができます。

こんな感じに、Nuxt標準の404ページが表示され、指定したパスに届いていることがわかる。

さて、自身のページ内の任意のパスを表示できることがわかりました。任意のパスを表示できるということは、当然publicフォルダ内にもアクセスできるわけです。

あとはこの2つを組み合わせて、“publicフォルダ内の.htmlファイルをページとして埋め込んであげる”ことで<template>内で<script>タグを使ったコンテンツを表示することができました。

こんな感じ。

あとは<iframe>にページが埋め込まれていることに留意しながら、CSSを調整してあげればよいわけですね。

3. <iframe>タグとセキュリティ的なお話(余談)

<iframe>を調べているとセキュリティに関する話題がついてまわります。

別のサイトにあるページを表示して、その上に悪意のあるページを表示します。
これで表示上は正常なサイトだが、クリックなどのイベントは悪意のあるページが持っている状況が出来上がります。

こんなかんじ。<iframe>で別のページを表示した上で、ボタンなどを紛れ込ませることができる。

(ここではわかりやすさのために表示しているが、実際には要素を透明にして目立たなくするらしい。タチが悪い)

<iframe>でログインページを表示したと想像して)ログインIDとパスワードを入力させて送信してもらえば、見事にフィッシングが成功するというわけですね。これをクリックジャッキングというそうだ。

そんなわけで、<iframe>を使って外部サイトからの表示を禁止する設定がNginxなどにはあります。
実際に、<iframe>タグでgoogleのページを開こうとすると、何も写せません。

一方、fly.ioのドキュメントは表示できるようです。(ちなみにサインアップ画面はちゃんとブロックされていました)

ドキュメントはログインとかの動作がないので、特に設定する必要はないのだけど、ログインボタンなり情報を入力する必要があるページはブロックするのがセオリーというわけですね。

今回の場合はひとまず、外部ではなく自分のサイト内での.htmlを表示するのでブロック設定などは関係なさそうだと安心したところで、この記事はこれでおしまい

Discussion