발생한 에러
생활 코딩 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을 추가하는 것보다 더 흥미로운 것을 발견했다.
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 이라는 옵션이 있는데, 클라이언트 측에서 파일을 요청할 때 해당 파일이 존재하지 않으면 전달된 확장자 정보를 붙여 다시 검사를 해보는 것이다.
따라서, 다음과 같은 방법으로도 현재 문제를 해결할 수 있다.
app.use(express.static(resolve('public'),{extensions:['js', 'html', 'htm', 'css']}));
모듈에 타입을 명시하는 대신, express 서버에게 모듈 체크를 맡기는 셈이 된다. 결과는 다음과 같다.
성공적으로 웹 상에서 모듈이 동작했다.
결론
현재 문제는 웹 상에서 script 태그에 type = 'module' 으로 명시하는 상황에 발생할 수 있다. import을 통해 요구한 파일의 주소가 잘못되어 실제로 존재하지 않는 파일을 서버에게 요청하는 경우, 이유는 모르겠지만 서버 혹은 클라이언트 측에서 해당 사이트를 렌더링할 때 사용한 html 파일을 존재하지 않는 파일의 내용으로 가지게 된다. 이때 해당 파일에 접근하면 html의 내용이 있으므로, "모듈" 을 요구했지만, "text/html" 을 가져왔다는 에러가 발생한 것이다.
해당 에러는 html 파일 상에서 요구하는 파일의 위치를 static 폴더 조건에 맞도록 제대로 정의하거나, 서버 상에서 extensions 으로 주어진 확장자들을 검사하여 진짜 파일을 전달하게 하면 해결된다.
'javascript > nodejs' 카테고리의 다른 글
[nodejs] __filename & __dirname / join & resolve (0) | 2022.04.05 |
---|---|
서버가 static 파일을 보내는 방법 (0) | 2022.04.03 |
[nodejs] esmodule 사용 -> "type" : "module" (0) | 2022.02.21 |
[npm] errno -4092 | EACCES 에러 (0) | 2022.01.30 |
Sequelize : 런타임 코드 생성을 활용하는 ORM~ (0) | 2022.01.24 |