#今回陥った内容の概要
React(typescript)で外部scriptを使用するだけなのだがかなりの時間と調査を要して解決したのでのでナレッジの共有をしたいと思います。
ただベストプラクティスではないと思っており、実装内容も少しレガシーの方法となっております。
今回は外部scriptになるが古いライブラリを使用する場合、React(typescript)ですが、@type
に対応していないものを使用する内容となっております。
#今回の用件
- 実装はReactでのSPA
- 外部scriptはbody内に任意の箇所
- headerにはプロパティを追加する外部scriptなし
- innerHtmlはサニタイズを考慮して使用不可
- 外部script内に
document.write
が使用されている() - 外部script内にさらなる外部scriptが使用されている
#試したアプローチ
##1.scriptタグの生成
useEffect
で以下のコードを実装
const script = document.createElement("script");
script.asyc = true;
script.src = "url";
const currentElem = document.getElementById("current");
currentElem?.appendChild(script);
build結果としては
<div id="current">
<scirpt async src="url"></script>
</div>
っとなってしまいました。
望む結果としては外部scriptの実行結果(document.write
)が行われDOM要素を生成して欲しいのでこちらでは望む結果とはなりませんでした。
#解決したアプローチ
postscribe
を使用しました。
npm i postscribe
ただこちらのライブラリは@type
が作成されていなさそうなので、
import postscribe from "postscribe";
ではエディタ上ではErrorとなってしまいます。
そのため、ベストプラクティスではないと思いつつ以下のような実装で対応しました。
// eslint-disable-next-line @typescript-eslint/no-var-requires
const postscribe = require("postscribe");
postscribe(
"#current",
"<script src='url'></script>"
);
上記実装でbuildを実行しますと
<div id="current">
<!-- ここに上記外部scriptのdocument.writeで追加されたDOMが追加 -->
</div>
となり、任意のコンテンツが表示されました。
#まとめ
今回に関してはこのような対応で実現させました。
実現できた時は安堵の方がかなり多かったですが、個人的には満足いく実装が出来なかったです。
自分以外にも似たような内容で困っている方がいれば一度試してみてはいかがでしょうか?
また、他にもっと良い実装があるよって方は残していただければ試してみようかと思います。