개발/webpack

Webpack. 빌드 시 파라미터 기반 소스 코드 문자열 치환

워로디스 2026. 11. 3. 22:16

1. 개요

Webpack 빌드 실행 시 --env로 전달한 파라미터를 사용하여 기존 소스 코드의 특정 문자열을 치환한다.

문자열 치환은 string-replace-loader를 사용하며, 각 치환 규칙마다 대상 소스 파일을 명시적으로 지정하여 의도하지 않은 치환을 방지한다.

핵심 요구사항

  • 기존 소스 코드를 수정하지 않는다.
  • 빌드 시 전달한 파라미터로 상수 값을 변경한다.
  • 여러 상수를 동시에 치환할 수 있다.
  • 각 치환 규칙은 지정된 소스 파일에만 적용한다.
  • 파라미터가 없으면 해당 Loader 규칙을 적용하지 않는다.
  • 다른 Loader보다 문자열 치환을 먼저 수행한다.
  • 별도의 빌드 스크립트나 커스텀 Loader를 작성하지 않는다.

적용 기술

기능 사용 방법
빌드 파라미터 전달 Webpack --env
문자열 치환 string-replace-loader
대상 파일 지정 include
조건부 Loader 적용 module.rules 동적 구성
Loader 실행 순서 enforce: 'pre'
동일 파일 내 다중 치환 multiple 옵션

2. 패키지 설치

npm install -D string-replace-loader

참고로 string-replace-loader 3.x는 Webpack 5 이상을 대상으로 한다. Webpack 4 이하에서는 호환 버전을 확인해야 한다.

npm

3. 소스 코드 구성

다음과 같은 프로젝트 구조를 가정한다.

project/
├── src/
│   ├── index.js
│   ├── a.js
│   └── b.js
├── webpack.config.js
└── package.json

src/index.js

import './a.js';
import './b.js';

src/a.js

const a = 1;

console.log(a);

src/b.js

const b = 2;

console.log(b);

기존 소스 코드는 변경하지 않으며, 빌드 시점에 각 파일의 지정된 상수 값만 치환한다.

4. Webpack 설정

webpack.config.js

const path = require('path');

module.exports = (env = {}) => ({
  mode: 'production',
  entry: './src/index.js',

  module: {
    rules: [
      // 기존 Babel Loader
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
      },

      // a.js의 상수 치환
      ...(env.a !== undefined ? [{
        include: path.resolve(__dirname, 'src/a.js'),
        enforce: 'pre',
        loader: 'string-replace-loader',
        options: {
          search: 'const a = 1;',
          replace: `const a = ${env.a};`,
        },
      }] : []),

      // b.js의 상수 치환
      ...(env.b !== undefined ? [{
        include: path.resolve(__dirname, 'src/b.js'),
        enforce: 'pre',
        loader: 'string-replace-loader',
        options: {
          search: 'const b = 2;',
          replace: `const b = ${env.b};`,
        },
      }] : []),

      // 기존 CSS Loader
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
});

설정의 핵심

  1. 파일별 치환 범위 제한
include: path.resolve(__dirname, 'src/a.js')

해당 규칙은 src/a.js에만 적용된다.

다른 소스 파일에 동일한 문자열이 존재하더라도 치환하지 않는다. 파일 경로를 직접 지정하므로 이 규칙에서는 별도의 test가 필수는 아니다.

  1. 조건부 Loader 등록
...(env.a !== undefined ? [{
  // Loader 설정
}] : [])

env.a가 전달된 경우에만 해당 Loader 규칙을 등록한다.

파라미터가 없으면 빈 배열이 반환되므로 해당 규칙은 Webpack 설정에서 제외된다.

  1. Loader 실행 순서
enforce: 'pre'

Babel 같은 일반 Loader보다 문자열 치환을 먼저 수행하도록 지정한다.

5. 빌드 실행

5.1. 모든 상수 변경

npx webpack --env a=11 --env b=22

빌드 과정에서 다음과 같이 치환된다.

src/a.js

const a = 11;

console.log(a);

src/b.js

const b = 22;

console.log(b);

5.2. 일부 상수만 변경

npx webpack --env a=11
파일 처리 결과
src/a.js const a = 11;
src/b.js const b = 2; (변경 없음)

env.b가 없으므로 b.js의 문자열 치환 Loader는 등록되지 않는다.

5.3. 파라미터 없이 빌드

npx webpack
  • 두 문자열 치환 Loader 모두 등록되지 않는다.
  • 기존 Loader만 사용하여 빌드한다.
  • 소스 코드의 기존 값이 그대로 사용된다.

5.4. npm run build 사용

package.json

{
  "scripts": {
    "build": "webpack"
  }
}

빌드 실행:

npm run build -- --env a=11 --env b=22

npm run build 뒤의 --는 나머지 인자를 Webpack CLI로 전달하기 위한 구분자다.

Webpack의 --env는 여러 개 지정할 수 있으며, 설정 함수의 env 객체에서 각 값을 사용할 수 있다.

webpack

6. 동일 파일에서 여러 상수를 치환하는 경우

여러 상수가 하나의 파일에 존재한다면 별도 Loader를 여러 번 등록할 필요 없이 multiple 옵션을 사용할 수 있다.

예를 들어 src/config.js에 다음 코드가 있다고 가정한다.

const a = 1;
const b = 2;

Webpack 설정:

const replacements = [
  ...(env.a !== undefined ? [{
    search: 'const a = 1;',
    replace: `const a = ${env.a};`,
  }] : []),

  ...(env.b !== undefined ? [{
    search: 'const b = 2;',
    replace: `const b = ${env.b};`,
  }] : []),
];

그리고 module.rules에 다음 규칙을 추가한다.

...(replacements.length > 0 ? [{
  include: path.resolve(__dirname, 'src/config.js'),
  enforce: 'pre',
  loader: 'string-replace-loader',
  options: {
    multiple: replacements,
  },
}] : [])

이 방식은 동일한 파일에 여러 치환 대상이 존재하는 경우에 사용한다.

각 파라미터가 없으면 해당 치환 항목만 제외되며, 모든 파라미터가 없으면 Loader 규칙 자체가 제외된다.

7. 다른 Loader와의 관계

Webpack에서는 하나의 파일에 여러 Loader가 적용될 수 있다.

module: {
  rules: [
    {
      test: /\.js$/,
      loader: 'babel-loader',
    },

    {
      include: path.resolve(__dirname, 'src/a.js'),
      enforce: 'pre',
      loader: 'string-replace-loader',
      options: {
        search: 'const a = 1;',
        replace: 'const a = 11;',
      },
    },

    {
      test: /\.css$/,
      use: ['style-loader', 'css-loader'],
    },
  ],
}

이 경우 src/a.js에는 string-replace-loader와 babel-loader가 모두 적용된다.

실행 순서는 다음과 같다.

  1. string-replace-loader: 원본 소스의 문자열 치환
  2. babel-loader: JavaScript 코드 변환
  3. Webpack: 모듈 번들링 및 최적화

enforce: 'pre'를 지정하면 일반 Loader보다 먼저 소스를 변환한다.

webpack

또한 각 규칙의 test, include는 해당 규칙의 적용 대상을 결정할 뿐, 다른 Loader 규칙에는 영향을 주지 않는다.

8. 주의사항

8.1. 정확한 문자열 일치

string-replace-loader는 기본적으로 문자열을 그대로 비교한다.

예를 들어 다음 설정은:

search: 'const a = 1;'

아래 코드에는 일치하지 않는다.

const a=1;

따라서 대상 소스 코드의 표현이 변경되면 치환이 적용되지 않을 수 있다.

8.2. 치환되지 않아도 빌드가 성공할 수 있음

기본적으로 치환할 문자열을 찾지 못해도 오류가 발생하지 않는다.

치환 실패 시 빌드를 중단해야 한다면 다음 옵션을 사용할 수 있다.

options: {
  search: 'const a = 1;',
  replace: `const a = ${env.a};`,
  strict: true,
}

단, strict: true는 치환 전후의 내용이 같을 때도 실패할 수 있다. 예를 들어 원래 값이 1인데 --env a=1을 전달하는 경우다.

8.3. 치환값의 자료형

Webpack CLI의 --env a=11에서 env.a는 문자열 "11"로 전달된다.

숫자 상수를 치환할 때는 숫자 형식을 검증하는 것이 좋다.

문자열 상수라면 다음과 같이 JSON.stringify()를 사용한다.

{
  search: "const name = 'old';",
  replace: `const name = ${JSON.stringify(env.name)};`,
}

이렇게 하면 따옴표나 특수 문자가 포함된 값도 JavaScript 문자열 리터럴로 안전하게 생성할 수 있다.

8.4. 중복 문자열

같은 파일에 검색 문자열이 여러 번 존재하면 기본적으로 첫 번째 일치 항목만 치환한다.

모든 일치 항목을 치환하려면 전역 정규식을 사용해야 한다.

8.5. 원본 파일 유지

Loader는 Webpack이 읽어 들인 소스를 변환한다.

따라서 원본 소스 파일은 변경되지 않으며, 변환된 내용이 번들링 과정에 전달된다.

단, 최종 번들에서는 압축 및 최적화에 따라 실제 코드 형태가 달라질 수 있다.

8.6. Webpack이 처리하는 파일만 대상

Loader는 Webpack의 모듈 처리 과정에서 실행된다.

따라서 include로 파일을 지정하더라도 해당 파일이 entry 또는 의존성 그래프에 포함되지 않았다면 치환되지 않는다.

9. 최종 권장 구성

항목 권장 방식
파라미터 전달 --env a=11 --env b=22
문자열 치환 string-replace-loader
대상 범위 파일 경로를 include에 명시
서로 다른 파일 파일별 Loader 규칙 등록
동일 파일의 다중 치환 multiple 옵션
파라미터 누락 조건부로 해당 규칙 제외
다른 Loader와의 순서 enforce: 'pre'
원본 코드 수정 하지 않음

결론

최종적으로 Webpack --env + string-replace-loader + 파일별 include + 조건부 Loader 등록 방식을 사용한다.

이 구성의 장점은 다음과 같다.

  • 기존 소스 코드를 변경하지 않는다.
  • 빌드 파라미터만으로 필요한 값을 변경할 수 있다.
  • 치환 대상을 파일 단위로 명확하게 제한한다.
  • 파라미터가 없는 경우 불필요한 치환 작업을 수행하지 않는다.
  • 기존 Babel, CSS 등 다른 Loader 설정과 독립적으로 관리할 수 있다.
  • 별도의 빌드 스크립트나 커스텀 Loader 없이 Webpack 설정만으로 구현할 수 있다.

치환 대상의 파일과 문자열이 명확하게 정해져 있고, 빌드 시점에 해당 값만 변경하면 되는 프로젝트에 적합한 구성이다.

반응형