초보 개발자

Webpack loader 본문

RECAP - WETUBE

Webpack loader

taehyeki 2021. 10. 2. 15:07

니코쌤이 webpack의 기능들은 기본적으로 툴에 탑재 되어있기에 직접 쓸 일은 많이 없지만

꼭 알아두면 좋다고 했다.

 

Webpack이란 뭐냐면 우리가 그동안 back end에서 babel-bode를 통하여 우리가 원하는 대로(최신 문법) 코들르 작성 해도 서버에서 node.js가 이해해주었다. 그럼 front end에서도 이런걸 해줘야 하는데 이게 webpack이다!!

 

예를들어 .scss파일은 브라우저에서 받아들여지지 않는다 이걸 브라우저가 이해할 수 있는 css로 바꿀필요가 있다.

또한 js가 크롬에선 잘 돌아가는데 파이어폭스나 사파리에선 이해를 못할 수도 있다. 지금 원하는건 프론트엔드에서 최신 js코드를 작성하면 모든 브라우저에서 인식 가능한 js로바꿔주는 무언가가 필요하다!! 그게 webpack이다

 

npm i webpack webpack-cli -D

webpack cli를 이용하면 콘솔에서 webpack을 불러낼 수 있다

 

먼저 webpack.config.js 라는 파일을만든다
여기서 필수적인것이 두가지 있는데 entry, output이다

첫번째는 entry이다 이건 우리가 처리하고자하는 파일들이다.
아무 폴더를 src안에 만들어보자. frontend라던지 client로 만들어 보겠다.

이 폴더 안에 있는 코드들은 다 서버가 아니라 브라우저에서 실행이 될 것이다.
js폴더를만들고 main.js를 만들어보자 거기에서 브라우저에서 실행시킬 코드를 작성한다

그리고 
webpack은 오래된 js코드만 이해할 수 있다. import말고 module.export를 사용해야한다!!


entry에 './src/client/js/main.js'를 적어준다 !!!
그리고 output을 적어서  파일명을 적어줘야한다 변환된 파일명!!
output: {
filename: "main.js" 그대로 해줘보자 그리고 어디에 저장할 지 
path를 통해서 적어줘야한다
path: "./assets/js"라고해준다 즉 entry에 있는 파일을 변경/전환시켜서 작업이 끝난 후에 그 파일을
./asset/js 디렉토리에 저장하라고 하는거다.
webpack.config.js에선 webpack이 읽을 configuration 파일을 내보낸다.

package.json에서 새로운 명령어를 하나 더 추가해준다.
assets: "webpack --config webpack.config.json 까지 입력해주었다.

npm run assets

 

우리가 지금 하는 것들은 프론트엔드 코드를 진행하기 위해서이다. 더이상 백엔드가 아니다.
node.js도 아니고 프론트엔드 코드들이다.

이렇게 하는 순간 에러가 뜰 것이다. path에는 상대경로가 아닌 절대경로를 써야하기 때문이다.
우리는 ./을이용하여 상대경로를 이용했다 여기서 필요한게
const path = required('path') 를 활용하여 절대경로를 준다.
path.resolve(__dirname, '폴더명')

const path = required('path')
path : path.resolve(__dirname, '폴더명')


__dirname은 js가 제공하는 상수이다. 
directory name은 말 그대로 파일까지의 경로 전체를 말하는 것이다.
path.resolve()는 무슨 역할을 하냐면 인수가 몇개가 되든 그 인자를 묶어 경로를 완성시켜주는 역할을 한다.

저렇게 바꿔주면 되는가 싶었지만.....

더보기

전에 언젠가 부터 갑자기 bable-node를 사용하면 err가 떴었고 console창에 package.json에 "type":"module"을 적어 주라고 하길래 적어줬더니 err가 사라져서 뭐 괜찮겠지?? 하고 넘어갔던 적이 있다.

 

근데 여기서 이게 내 발목을 잡을 줄이야... 

webpack을 실행하면 에러가 막 뜨는데 package.json에 있던 "type":"module"을 지워주면 작동이 잘된다.

아마 내가 생각해볼때 저걸쓰면 require을 쓰면안되고 import만 써야되는 것 같다.

그래 그럼 지워주자 했더니 이번에는 서버가 안켜지네..?

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module:
require() of ES modules is not supported.

나는 심지어 require를 한번도 사용한 적이 없었다. import만 사용해왔다고 !!!

우리는 지금까지 bable을 통해서 구버전으로 돌린 뒤에 babel-node가 실행시켜왔는데

"type":"module"가 있다면 import를 js에서 이해할 수 있는가보다 싶어 bable-node를 지워보니 서버가 켜지긴한다... 이럼 바벨 왜씀??ㄷㄷ

이 오류를 고치려고 진짜 이틀동안 아무것도 못하고 미친듯이 이거에만 매달렸는데 결국 해결이 안되었다..

(혼자공부하면 진짜 이런 부분이 너무 힘들어....)

그러다가 그냥 포기하려고 했는데 오류를 찬찬히 읽어보니까 node-fetch에서 뭔가 오류가 발생되는거 같다는 생각이 들었다. 그래서 node-fetch를 계속 구글링하던 도중 나랑 똑같은 사람이 있었다 3.0.0버전을 사용하면 저런 오류가 뜨고

2.6.1버전을 사용하면 안뜬다고 하길래 속는셈치고 해보니까 엥...? 오류가 안난다!!!!! 너무 행복해ㅠㅠ

 

아마 오류가 뜬 이유는 내가 "type":"module"을 package.json에다 적으면 require등과 같이 예전 방식으로 module을 불러오는 것이 안되는 것같은데 webpack에 require이랑 module.exports가 있으니까 오류가 난 것 같다. 이걸 고치기 위해서는 "type":"module"을 지워주니까 webpack은 돌아갔지만 이젠 서버구동이 안된다. 이 서버구동의 오류는 잘 모르지만github login기능을 구현할 때 사용 했던 node-fetch와 버전충돌같은 느낌이 있는 것 같다 그래서 3.0.0버전을 2.6.1버전으로 다운시키니까 webpack 그리고 babel-node도 잘 실행이 되었다. 다신 만나지말자 ^^

 아직 어떤 코드들은 브라우저가 이해할 수 없는 것도 있다. 우리는 이 코드에 호환성을 추가해야 된다.

 

 

package.json에서 새로운 명령어를 하나 더 추가해준다.
assets: "webpack --config webpack.config.json 까지 입력

우리가 지금 하는 것들은 프론트엔드 코드를 진행하기 위해서이다. 더이상 백엔드가 아니다.
오류가 뜨는 것을 확인할 수 있는데 이유를 살펴보면
우리는 ./을이용하여 상대경로를 이용했지만 저 path는 절대경로이어야한다.

const path = required('path')
path.resolve(__dirname, '폴더명', '폴더명'....)


__dirname은 js가 제공하는 상수이다. 
directory name은 말 그대로 파일까지의 경로 전체를 말하는 것이다.
path.resolve()는 무슨 역할을 하냐면 인수가 몇개가 되든 그 인자를 묶어 경로를 완성시켜주는 역할을 한다.

webpack은 loader가 필요하다 필터 같은 느낌이라고 생각하자.

우리는 babel-loader를 통해서 파일을 변환할것이다
이제부턴 프론트엔드랑 백엔드 양쪽에서
babel/core babel/preset-env를 사용할 것이다.!!!
npm i -D babel-loader

npm i -D babel-loader


지금 당장은 가져다 압축시킨것 그 이상 그 이하도 아니다. 우리가 원하는건 이 코드를 babel-loader를 통하여 오래된 브라우저도 이해할 수 있게 전환시키는 거다.

그리고 webpack에게 이 코드가 지금 개발중인지 아니면 완성품인지를 알려줘야한다.
webpack에게 아직 개발중이라고 말하고 나중에 우리가 백엔드를 서버에 직접 올릴 때가 되면 바꾸는 방법을 배울것이다 mode: 'development',도 추가해준다.



브라우저는 assets에 있는 파일을 읽어간다. no client파일!! client파일은 webpack이 처리하기 전이다.
기본적으로 폴더들은 보안상으로 공개되지 않지만 static을 통해 이 폴더안에 있는 파일들을 볼 수 있게 해달라고 요청하는 것이다. 이건 upload를 할때도 한번 다룬 적이 있었다. localhost:8080/assets/js/main.js를 입력하고 들어가면 아무것도 안뜬다
서버는 아직 assets라는 폴더나 라우터가 있는줄도 모른다 express한테 assets안에 js안에 main.js가 있다고 알려줘야한다.



scss폴더를만들고 style.scss와 _variable.scss를 만들어주자. scss에서는 변수개념처럼 $를 활용하여 사용할 수 있다.

@import문을 통해서 변수가 들어있는 scss를 style.scss에서 불러오고 그 style.scss를 main.js에서 불러와지게하자.

이러고 webpack을 돌려보자

 

style.scss

_variable.scss

main.js

err가 발생한다. 

 

이유는 우리가 로더를 설정안해줘서 그런것이다
rules에서 또 다른 객체를 만들고 모든 scss파일에 적용해줄 3가지 로더를 설정해준다
첫번째 loader는 scss를 가져다가 일반 css로 변형하는 것이고, (sass-loader)이건 scss파이릉ㄹ 가져가 css로 전환시켜준다.
두번쨰 loader는 폰트같은걸 불러올 때 css에 굉장히 유용하게 쓰일 loader이다. css-loader
쉽게말해 @import랑 url()을 풀어서 해석해준다.
마지막 loader는 변환한 css를 웹사이트에 적용시킬 loader style-loader이다 css를 DOM에 주입

npm i sass-loader sass css-loader style-loader -D

 


중요한건 제일 마지막 loader부터 시작해야 한다는 거다(역순) 
 
정리해보자면 제일먼저

webpack은 우리 entry파일을 가져온다 (main.js)

webpack은 이걸 js라고 인식해서 bable을 이용하여 변환시킬거고 그리고 

webpack은 이게 scss파일이란걸 인식해서(imort 에적은 scss파일) scss파일을 일반 css로 바꾼다.그리고 그

webpack이 직접 어떤 js코드를 짜준다.( webpack이 웹사이트의 html의 style부분에 컴파일된 css를 자동으로 입력해주는) 

즉 먼저 main.js파일에있는 js코드를 가공했고 그리고나서 import한 scss파일을 일반 css파일로 컴파일했다.
그리고!! 어떤 방법을 썼는지는 모르지만 webpack이 그 js를 우리 웹사이트 head안에 입력해줬다. style
head캡쳐한다 style-loader의가 브라우저에 코드를 주입한다

우린 이제부터 style-loader를 안쓰고 scss -> css 파일을 뽑아내서 따로 쓰려고 한다.  
두 파일을 얻기 위해 webpack plugin을 써야한다.
asstet의 main.js에는 방대한 양의 js코드가 있고 css코드또한 들어있다.
head에 css코드를 넣어주는건데 나는 js파일에서 css를 넣고싶지않아!!!! 분리된 css파일을 만들고싶어
왜냐면 js가 로딩되는걸 기다리기 싫고 바로 화면에 띄우고 싶기 때문이야
이럴 땐 miniCssExtractPlugin을 사용해야한다. 이건 해당 코드를 다른 파일로 분리시키는 녀속이다

 npm i -D mini-css-extract-plugin


공식문서에 적힌대로 그대로 따라주고
이제 style-loader부분에 MiniCssExtractPlugin.loader를 적어준다.


다시말해 만들어진 main.js파일은 css에서 다루는게 아니라 js에서 다루는것이다.
그리고 css파일은 다른 곳 어딘가에 만들어질거다. 이제 main.css가 나타난 것을 확인할 수 있다.

일단 main.js에 적힌 js코드는 main.js로 path에 만들어진다.
그리고 main.js에 있는 css는 minicss~~를 통해서 분리되어 나와진다. 아마 path에 나와지는 듯?
그래서 js폴더를 지우고 main.js이름 자체를 js/main.js라고 해서 첨부터 폴더안에 들어가지게 만든다.
css가 path에 나와진다고 생각이 든것이 이 부분인데 main.js는 js폴더안에 생성되지만 css파일은 그냥 assets에 남아있다. 그럼 css의 filename또한 수정하여 폴더안에 들어와지게 하면된다
이것은 {filename:"css/stlyes.css"} 옵션을 넣어주면 된다.

 


----------------------------------------------------------------------------------------------------
모든 것은 main.js에서 시작된다. 이 파일은 모든 것의 importer이다.
두 코드(import) (console.log)를 분리하는데 js를 babel로 처리하고 css를 추출한것이다..
둘다 assets에 만들어졌고 main.js, style.css로 이제 해야하는 것은 pug에서 css파일 연결하는 것이다.

여기서 의문.. main.js는 단지 scss를 css로 만들기 위한 도구에 불과한것인가.
main.js가 없으면 단독으로 scss에서 css를 못만드는 것인가..?

watch옵션을 true로 설정하면 설정이 바뀔 때마다 자동으로 바뀐다.
이제 2개의 터미널을 실행시켜 실시간으로 작업을 할 수 있게되었다.
여기서 js를 수정하면 서버도 재시작이된다
근데 front-end 자바스크립코드가 변경된다고해서 back-end가 다시 재시작하기를 원치 않는다.

clean :true라는 속성을 output에 주면 말그대로 output folder를 build하기전에 clean해주는거다


위와 같이 nodemon.json이라는 파일을 만들고
{ "ignore": [ "webpack.config.js","src/client/*","assets/*"] ,
webpack.config.js와src/client밑에 있는 모든 파일들이 수정될때는 nodemon이 무시한다/
 exec: "babel-node ./src/init.js" } 또한 처리해주자
이렇게하면 "dev":"nodemon"만 적어줘도 자동으로 --exec가 실행되어 전과 똑같이 실행된다.


--ignore 옵션을 사용하여 package.json에서도 사용할 수 있었지만 이렇게 따로 nodemon.json 파일을 만들어
여기서 정리해주었다.



webpack.config.js가 기본적으로 webpack이 실행될때 찾는 기본 파일이기때문에 webpack만 적어둬도된다.
nodemon도 자동적으로 nodemon.json파일에서 설정을 찾는것처럼말이다.
만약 다른 설정파일을 생성하고싶다면 명령어에 --config를 붙여주면된다.

'RECAP - WETUBE' 카테고리의 다른 글

view +1 API  (0) 2021.10.12
Video player  (0) 2021.10.05
Model populate, bug fix ( ★★★ )  (0) 2021.09.30
avatar , video upload (multer, static)  (0) 2021.09.29
middleware / edit, change-pw handler (★★★)  (0) 2021.09.28