본문 바로가기

javascript/nodejs

[error] Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html"

발생한 에러

생활 코딩 webpack 편을 듣는 도중, html 상에서 모듈을 이용할 때 다음과 같은 에러가 발생했다.

 

해당 에러가 발생한 환경은 이렇다.

html 파일 : 

<html>
    <head>

    </head>
    <body>
        <h1>Hello, Webpack!</h1>
        <div id="root"></div>
        <!-- <script src="source/hello.js"></script>
        <script src="source/world.js"></script> -->
        <script type="module">
            import word1 from "/source/hello";
            import word2 from "/source/world";
            let root = document.querySelector("div#root");
            if(root)
            {
                console.log("Root!")
                const elem1 = document.createElement('div');
                elem1.append([word1, word2]);
                root.appendChild(elem1);
            }
            else {
                console.log("cannot find root...");
            }
            // root.innerHTML = word1;
        </script>
    </body>
</html>

express 서버 파일 :

import express from 'express';
import {dirname, resolve} from 'path';
import { fileURLToPath } from 'url';

const url = new URL(import.meta.url).href;
const __dirname = dirname(fileURLToPath(url));

const app = express();

app.use(express.urlencoded({extended:true}));
app.use(express.static(resolve('public')));

console.log(resolve('public'))

app.use('/', (req,res,next) => {
    return res.status(200).sendFile(resolve('public', 'index.html'));
});

app.listen(3000);

  많은 코드 수정을 거쳤지만, 결론적으로는 hello.js 및 world.js 에 대한 주소를 잘못 작성한 것이 문제였다. 

 에러에 대한 설명

 기본적으로 웹 상에서 모듈은 확장자가 없는 파일을 인식하지 못한다는 특징이 있다. 이때 나는 html 의 script 상에서 hello 및 world 파일을 import 할 때 확장자를 지정하지 않은 상태였으므로, 해당 파일 자체를 인식하지 못해 이러한 에러가 발생한 것이다.  html 상의 코드를 보면 "/source/hello"를 import 하고 있는 것을 볼 수 있다.

 네트워크 상에서는 해당 파일들을 다운받은 것으로 간주되지만, 실제 파일로 접근하면 index.html과 동일한 내용을 담고 있는 파일을 발견할 수 있다.

 추측이지만, 파일을 발견하지 못하는 경우 위와 같이 html 파일이 복사 혹은 대신 전송되어 "자바스크립트 모듈" 이 아니라 "text/html" 타입의 데이터가 전달되었다고 표현하는 것은 아닐까 생각해본다. 이유는 몰라도 실제로 내부 내용이 index.html 으로 채워져 있으므로, 웹 브라우저는 있는 그대로의 에러를 내뱉는 것이다.

해결책

 해결법은 아주 간단하다. 해당 파일이 제대로 웹 상에 전달될 수 있도록, 주소를 제대로 지정하는 것이다. static 폴더의 경로를 확인하고, 모듈의 경우 확장자 정보까지 필요하므로 확장자 정보 js을 추가하면 된다.

 그런데 구글링을 하다 보니, 단순히 js을 추가하는 것보다 더 흥미로운 것을 발견했다. 

https://stackoverflow.com/questions/69677744/express-error-strict-mime-type-checking-is-enforced-for-module-scripts-per-html/69686367#69686367

 

Express error: Strict MIME type checking is enforced for module scripts per HTML spec

I'm trying to build a simple single page application via express. Everything works fine until I start creating the classes, then the browser throws the following error: Failed to load module script:

stackoverflow.com

 express.static은 두번째 인자로 static 파일에 대한 다양한 옵션들을 객체 형태로 받는다. 다양한 옵션 중 extentions 이라는 옵션이 있는데, 클라이언트 측에서 파일을 요청할 때 해당 파일이 존재하지 않으면 전달된 확장자 정보를 붙여 다시 검사를 해보는 것이다.

extensions 에 대한 정보

 따라서, 다음과 같은 방법으로도 현재 문제를 해결할 수 있다.

app.use(express.static(resolve('public'),{extensions:['js', 'html', 'htm', 'css']}));

 모듈에 타입을 명시하는 대신, express 서버에게 모듈 체크를 맡기는 셈이 된다. 결과는 다음과 같다.

성공적으로 웹 상에서 모듈이 동작했다.

결론

 현재 문제는 웹 상에서 script 태그에 type = 'module' 으로 명시하는 상황에 발생할 수 있다. import을 통해 요구한 파일의 주소가 잘못되어 실제로 존재하지 않는 파일을 서버에게 요청하는 경우, 이유는 모르겠지만 서버 혹은 클라이언트 측에서 해당 사이트를 렌더링할 때 사용한 html 파일을 존재하지 않는 파일의 내용으로 가지게 된다. 이때 해당 파일에 접근하면 html의 내용이 있으므로, "모듈" 을 요구했지만, "text/html" 을 가져왔다는 에러가 발생한 것이다.

 해당 에러는 html 파일 상에서 요구하는 파일의 위치를 static 폴더 조건에 맞도록 제대로 정의하거나, 서버 상에서 extensions 으로 주어진 확장자들을 검사하여 진짜 파일을 전달하게 하면 해결된다.