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?

innerHTML内のscriptが実行されなくて沼った話

Posted at

はじめに

引き続き42Tokyoの課題に取り組んでいる間に初めてのことで沼ったのでまとめておきます。

問題

結論から言うと、今回沼った原因はinnerHTMLでDOMに追加されたscriptは実行されないという、ブラウザのセキュリティ上の仕様を理解していなかったことです。

実現したかったこと

実現したかったことは、htmlのdiv内に別のhtmlを埋め込み、そのhtmlの要素をスクリプトで変更することでした。

言葉で説明するとややこしいので、今回はサンプルとして以下のindex.htmlのdiv=appapp.htmlを埋め込んで、そのhtml内の要素をスクリプトで変更することを実現目標とします。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<h1>Hello World</h1>
    <div id="app">
    </div>
</body>
</html>

サンプルコード

まずは問題を再現するためのサンプルコードを用意していきます。
サーバーはfastifyで立てます。

import fastify from "fastify";
import fastifyStatic from "@fastify/static";
import path from 'path';
import process from 'process';

const server = fastify({logger: true});

server.listen({port: 8080});

server.register(fastifyStatic, {
	root: path.join(process.cwd(), ''),
	prefix: '/'
});

server.setNotFoundHandler((__request, reply) => {
	reply.sendFile('index.html');
});

間違ったアプローチ

まずは実際に私が間違えてとったアプローチを再現します。

index.html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<h1>Hello World</h1>
	<div id="app">
    </div>
    <script src="index.js" defer></script>
</body>
</html>

index.js

document.addEventListener('DOMContentLoaded', async () => {
	const h1 = document.getElementsByTagName('h1')[0];
	if (h1)
		h1.textContent = 'Hello Index';
	const response  = await fetch('app.html');
	const htmlContent = await response.text();
	const app = document.getElementById('app');
	if (app) {
		app.innerHTML = htmlContent;
	}
})

app.html

<h2>Hoge</h2>
<script src="app.js" defer></script>

app.js

document.addEventListener('DOMContentLoaded', ()=> {
	const h2 = document.getElementsByTagName('h2')[0];
	if (h2) {
		h2.textContent = 'Hello App';
	}
});

出力はこうなりました
Screenshot 2025-07-04 at 20.28.08.png

app.jsで変更したはずの"Hello App"が表示されず"Hoge"のままになっています。

この問題はどうやらinnerHTMLで埋め込んだhtml内に含まれているscriptはセキュリティ上実行されないというもののようです。エラーコードとして表示されないのでこのことに気づくまで1時間ほど溶かしました。

解決したコード

index.html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<h1>Hello World</h1>
	<div id="app">
    </div>
	<script type="module" src="index.js" defer></script>
</body>
</html>

index.js

import {renderApp} from './app.js';

document.addEventListener('DOMContentLoaded', async () => {
	const h1 = document.getElementsByTagName('h1')[0];
	if (h1)
		h1.textContent = 'Hello Index';
	renderApp();
})

app.js

export async function renderApp() {
	const response  = await fetch('app.html');
	const htmlContent = await response.text();
	const app = document.getElementById('app');
	if (app) {
		app.innerHTML = htmlContent;
	}
	const h2 = document.getElementsByTagName('h2')[0];
	if (h2) {
		h2.textContent = 'Hello App';
	}
}

app.index

<h2>Hoge</h2>

これで無事に表示されました。

Screenshot 2025-07-04 at 20.43.23.png

終わりに

少しでも同じ問題にぶつかった方の参考になれば幸いです。

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?