#1 Webpack이란?

    여러 프론트엔드를 이루는 파일들을 모아 컴파일해서 js, css 등등으로 변환하여 프로젝트에 적용해주는 프로그램.

    압축, 최소화, 최적화 등의 처리를 해준다.

     

    #2 Webpack 설정

    보통은 React 등 대부분 Frontend 라이브리러에 이미 적용되어 있어 직접 사용할 필요는 없지만, 이번에는 공부겸 강좌를 보며 직접 프로젝트에 적용해보려고 한다.

    npm i webpack --save-dev
    npm i webpack-cli --save-dev

    개발자에게 도움을 주는 라이브러리이므로 devDependencies에 설치

     

    이후 프로젝트 폴더에 webpack.config.js 파일을 만든다. 여기서 설정을 해주는데, 최신 자바스크립트 문법은 사용할 수 없음.

    따라서 module.export = {} 구조를 통해서 프론트엔드 파일을 받아오는데, 이는 인자로 entry와 output이라는 두가지 인자를 가지고 있다.

     

    entry에는 소스코드(소스 코드 저장 경로), 

    output에서는 webpack이 코드를 컴파일하고 나온 결과물을 저장할 경로 + 저장할 파일명을 넣어준다.

    이때 경로는 절대경로가 되어야 하며, 따라서 아래와 같은 코드가 나온다.

    const path = require("path");
    
    module.exports = {
        entry: "./src/client/js/main.js",
        output:{
        	filename: "main.js",
            path: path.resolve( __dirname, "assets", "js" )
        }
    }

     

    경로에 대한 코드들을 짧게 정리하자면,

    JS 에서 __dirname 은 현재 프로젝트까지의 절대 경로가 저장되어 있다.

     

    const path = require("path"); 를 통해 import 받은 path의 경우 경로에 대한 메소드를 가지고 있고,

    이 중 path.resolve( __dirname, ~~ );은 경로명을 연결해서 특정 경로명을 반환해준다.

     

    따라서 path.resolve( __dirname, "assets", "js" ); 의 반환값은 (프로젝트 경로)/assets/js 가 된다.

     

    위와 같은 방식으로 파일을 타켓팅하여 변환하는 방법을 알았으나, 파일마다 어떤 변환이 필요한지도 설정을 해주어야한다. css는 style-loader 나 js는 babel을 적용해주는 등의 기능을 결정하는 역할을 한다.

     

    그게 rules를 미리 설정하는 것인데, 위에서 썼던 object에 module항목을 추가 작성해준다.

     

    module.exports = {
        entry: "./src/client/js/main.js",
        mode: "development",
        output:{
        	filename: "main.js",
            path: path.resolve( __dirname, "assets", "js" )
        },
        module:{
        	rules: [
            	{
                	test: /\.js$/,
                    use:{
                        loader: "babel-loader",
                        options: {
                            presets:[["@babel/preset-env", {targets: "defaults"}]]
                        }
                    }
                }
            ]
        }
    }

     

    백엔드에서 설치했던 babel 라이브러리 외에 babel-loader의 설치도 필요하다.

     

    추가로 mode도 설정해주었는데, 개발중일때의 'development'모드와 운영중일 때의 'prodcution'모드가 있다.

    운영모드로 설정하면 컴파일한 코드가 줄바꿈 없이 압축되어 개발이 힘들게 되므로 잘 설정해두도록하자.

     

    위에 만든 설정들을 기반해서 컴파일하기 위한 콘솔 명령어도 있으니 이를 script에 미리 저장해두자.

    "scripts":{
    	"assets": "webpack --config webpack.config.js"
    }

     

    #3 express와 연동하기

    webpack의 결과물로 생성된 파일들을 express에 정적인 파일로서 추가해주는 과정이 필요하다.

     

    이는 server.js(이름은 자유. 그냥 express가 설정되는 파일)에서 설정하는데, 아래와 같은 문법으로 사용한다.

    //첫번째 인자-브라우저에서 실행할 때 URL, 두번째 인자-읽어올 폴더 경로 
    app.use("/static", express.static("assets"));

     

    이후 아래와 같이 scirpt 파일을 문법대로 추가해주기만 하면 된다.

    이때, 경로명을 위에서 설정해둔 경로명으로 잘 맞춰주도록 하자. 위에서 설정한 경로명이 사용자 지정 경로명 같은 것이다. 따라서 실제 폴더명은 asstes이겠지만, static으로 설정해줄 것.

    //pug
    script(src="/static/js/main.js")
    
    //ejs
    <script src="../static/js/main.js"></script>

     

    이후 CSS를 추가할 때, JS에다가 CSS파일을 import하는 방식을 사용하는데, 이는 js가 css를 적용하는 어떠한 역할을 하도록 webpack이 파일을 변환한다.

    webpack설정은 다음과 같다.

     

    const path = require("path");
    
    module.exports = {
        entry: "./src/client/js/main.js",
        mode: "development",
        output:{
        	filename: "main.js",
            path: path.resolve( __dirname, "assets", "js" )
        },
        module:{
        	rules: [
            	{
                	test: /\.js$/,
                    use:{
                        loader: "babel-loader",
                        options: {
                            presets:[["@babel/preset-env", {targets: "defaults"}]]
                        }
                    }
                },
                {
                	test: /\.css$/,
                    use:['style-loader', 'css-loader'],
                }
            ]
        }
    }

     

    특이한 걸 꼽자면, use에 배열로 넣을 때, 파일을 컴파일 하는 순서의 역순으로 넣어줘야한다.

    따라서 위 코드에 따르면 css-loader 이후에 style-loader가 동작하는 방식이다.

     

     

    #4 JS와 CSS파일 분리하기

    위에서는 JS에서 CSS를 import하게 했지만 코드를 조금 수정해서 CSS파일이 따로 import하게 만들어주려고 한다.

    그렇지 않으면 JS가 로딩되기 전에는 사이트에 HTML 밖에 없기 때문.

    npm install --save-dev mini-css-extract-plugin

    위 플러그인을 사용한다.

     

    webpack.config도 아래와 같이 변경

    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    const path = require("path");
    
    module.exports = {
        entry: "./src/client/js/main.js",
        mode: "development",
        plugins: [new MiniCssExtractPlugin({
            filename:"css/styles.css"
        })]
        ,
        output:{
        	filename: "js/main.js",
            path: path.resolve( __dirname, "assets")
        },
        module:{
        	rules: [
            	{
                	test: /\.js$/,
                    use:{
                        loader: "babel-loader",
                        options: {
                            presets:[["@babel/preset-env", {targets: "defaults"}]]
                        }
                    }
                },
                {
                	test: /\.css$/,
                    use:[MiniCssExtractPlugin.loader, 'css-loader'],
                }
            ]
        }
    }

     

     

    ++ 개발환경 개선하기

    1. module.export에 watch:"true" 입력해주기. 프론트엔드 코드의 변경점이 있으면 파일 refresh와 compile을 다시 진행해준다. 다만 콘솔에서 실행중이기 때문에 다른 콘솔에서 추가로 서버를 열어줘야한다.

     

    2. output파일을 지웠다가 새로 만들어주도록 설정하기는 아래와 같다,

    output:{
        	filename: "js/main.js",
            path: path.resolve( __dirname, "assets"),
            clean:true,
        },

    clean:true를 추가해줌.

     

    3. frontend 코드를 수정했을 때, 백엔드의 nodemon이 이를 인식해서 백엔드를 재실행하지 않도록 설정한다.

    nodemon.json 파일 생성후 아래와 같이 입력해주고

    {
        "ignore" : ["webpack.config.js", "src/client/*"],
        "exec" : "babel-node src/server.js"
    }

     

    기존 package.json에 저장된 npm run dev 명령어는 단순히 nodemon만 실행하도록 바꿔주면, 실행과 무시할 파일들이 잘 설정되어 동작한다.

    "scripts": {
        "dev": "nodemon",
        "assets": "webpack --config webpack.config.js"
      },

     

    • 네이버 블러그 공유하기
    • 네이버 밴드에 공유하기
    • 페이스북 공유하기
    • 카카오스토리 공유하기