LHJ

I'm a FE developer.

자주 사용하는 플러그인 - DefinePlugin

01 Oct 2020 » node_webpack2

DefinePlugin

어플리케이션은 개발환경과 운영환경으로 나눠서 운영한다.
가령 환경에 따라 API 서버 주소가 다를 수 있다.
같은 소스 코드를 두 환경에 배포하기 위해서는 이러한 환경 의존적인 정보를 소스가 아닌 곳에서 관리하는 것이 좋다.
배포할 때마다 코드를 수정하는 것은 곤란하기 때문이다.

웹팩은 이러한 환경 정보를 제공하기 위해 DefinePlugin을 제공한다.
DefinPluginBannerPlugin처럼 웹팩의 기본 플러그인이다.

new webpack.DefinePlugin({}) 이렇게 선언해주면 DefinePlugin이 기본적으로 어플리케이션에 주입해주는 환경변수가 있는데, 그것이 노드의 환경변수이다.

// webpack.config.js
const path = require('path');
const webpack = require('webpack');
const childProcess = require('child_process');

module.exports = {
    mode: "development",
    entry: {
        main: "./src/app.js"
    },
    output: {
        path: path.resolve('./dist'),
        filename: "[name].js"
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ],
            },
            {
                test: /\.(png|jpg|gif|svg)$/,
                loader: 'url-loader',
                options: {
                    publicPath: './dist',
                    name: '[name].[ext]?[hash]',
                    limit: 20000, // 20kb
                }
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin({
            banner: `
                Build Date: ${new Date().toLocaleString()}
                Commit Version: ${childProcess.execSync('git rev-parse --short HEAD')}
                Author: ${childProcess.execSync('git config user.name')}
            `
        }),
        new webpack.DefinePlugin({})
    ]
}

이렇게 빈 객체를 전달해도 기본적으로 넣어주는 값이 있다.
노드 환경정보인 process.env.NODE_ENV인데 웹팩 설정의 mode에 설정한 값이 여기에 들어간다.
development를 설정했기 때문에 어플리케이션 코드에서 process.env.NODE_ENV 변수로 접근하면 development 값을 얻을 수 있다.

console.log(process.env.NODE_ENV); // development

process.env.NODE_ENV 노드쪽에서 제공하는 변수인데, 웹팩이 노드환경이다보니 빌드할 때 process.env.NODE_ENV 이 변수를 기본으로 넣어주는 것이다.
app.js에서 콘솔로그를 찍어보자.

// app.js
import './app.css';
import nyancat from './nyancat.jpg';

document.addEventListener('DOMContentLoaded', () => {
    document.body.innerHTML = `<img src="${nyancat}">`;
})

console.log(process.env.NODE_ENV);

좀 더 정확히 말하자면 NODE_ENV 환경변수라기 보다는 mode에 전달하는 웹팩 모드를 얘기하는 것이다.
지금은 development를 설정해놨기 때문에 위 콘솔에 development가 찍힐 것이다.

직접 환경변수를 넣고 싶다면 아래와 같이 넣을 수 있다.

// webpack.config.js
const path = require('path');
const webpack = require('webpack');
const childProcess = require('child_process');

module.exports = {
    mode: "development",
    entry: {
        main: "./src/app.js"
    },
    output: {
        path: path.resolve('./dist'),
        filename: "[name].js"
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ],
            },
            {
                test: /\.(png|jpg|gif|svg)$/,
                loader: 'url-loader',
                options: {
                    publicPath: './dist',
                    name: '[name].[ext]?[hash]',
                    limit: 20000, // 20kb
                }
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin({
            banner: `
                Build Date: ${new Date().toLocaleString()}
                Commit Version: ${childProcess.execSync('git rev-parse --short HEAD')}
                Author: ${childProcess.execSync('git config user.name')}
            `
        }),
        new webpack.DefinePlugin({
            TWO: '1+1'
        })
    ]
}

이렇게 넣으면 어플리케이션에선 TWO라는 전역변수로 접근이 가능하고, 1+1이란 코드가 TWO에 들어간다.
코드이기 때문에 2라는 값이 출력이 될 것이다.

// app.js
import './app.css';
import nyancat from './nyancat.jpg';

document.addEventListener('DOMContentLoaded', () => {
    document.body.innerHTML = `<img src="${nyancat}">`;
})

console.log(process.env.NODE_ENV);
console.log(TWO);

코드가 아니라 값을 넣고 싶을 땐, 어떻게할까?
JSON.stringify 메서드를 통해서 한번 더 문자열화 하면 된다.

// webpack.config.js
const path = require('path');
const webpack = require('webpack');
const childProcess = require('child_process');

module.exports = {
    mode: "development",
    entry: {
        main: "./src/app.js"
    },
    output: {
        path: path.resolve('./dist'),
        filename: "[name].js"
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ],
            },
            {
                test: /\.(png|jpg|gif|svg)$/,
                loader: 'url-loader',
                options: {
                    publicPath: './dist',
                    name: '[name].[ext]?[hash]',
                    limit: 20000, // 20kb
                }
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin({
            banner: `
                Build Date: ${new Date().toLocaleString()}
                Commit Version: ${childProcess.execSync('git rev-parse --short HEAD')}
                Author: ${childProcess.execSync('git config user.name')}
            `
        }),
        new webpack.DefinePlugin({
            TWO: JSON.stringify('1+1')
        })
    ]
}

DefinePlugin은 객체 타입도 지원을 한다.

// webpack.config.js
const path = require('path');
const webpack = require('webpack');
const childProcess = require('child_process');

module.exports = {
    mode: "development",
    entry: {
        main: "./src/app.js"
    },
    output: {
        path: path.resolve('./dist'),
        filename: "[name].js"
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ],
            },
            {
                test: /\.(png|jpg|gif|svg)$/,
                loader: 'url-loader',
                options: {
                    publicPath: './dist',
                    name: '[name].[ext]?[hash]',
                    limit: 20000, // 20kb
                }
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin({
            banner: `
                Build Date: ${new Date().toLocaleString()}
                Commit Version: ${childProcess.execSync('git rev-parse --short HEAD')}
                Author: ${childProcess.execSync('git config user.name')}
            `
        }),
        new webpack.DefinePlugin({
            TWO: JSON.stringify('1+1'),
            'api.domain': JSON.stringify('http://dev.api.domain.com')
        })
    ]
}

개발 환경에 따라 dev.api 또는 library.api를 쓸 수 있다.
그리고 app.js에선 다음과 같이 접근할 수 있다.

// app.js
import './app.css';
import nyancat from './nyancat.jpg';

document.addEventListener('DOMContentLoaded', () => {
    document.body.innerHTML = `<img src="${nyancat}">`;
})

console.log(process.env.NODE_ENV);
console.log(TWO);
console.log(api.domain);

우리가 위에서 api.domain 이렇게 객체 형식으로 적었기 때문에 위에서도 객체 형식으로 접근한다.