[NodeJS] Laravel mix 사용법

Laravel mix란 무엇인가?

Laravel mix는 제목 그대로 PHP 프레임워크인 Laravel에서 webpack의 빌드 기능들을 사용할 수 있게 도와주는 패키지이다. Webpack 보다 더 낫다, 혹은 부족하다 라고 할 수 없을 만큼 사실 webpack과 거의 유사하며 개인적으로는 항상 Webpack config를 설정하며 헤맨걸 생각하면 보다 편하게 사용할 수 있었던 것 같다. 가장 큰 장점으로는 메소드 체이닝 방식으로 원하는 Option을 사용할 수 있으며, 혹여라도 그 외에 추가적으로 커스텀을 하고 싶은 경우에도 위와 같이 config를 추가할 수 있어 확장성 역시 좁다고는 할 수 없다.

기본 사용법

Laravel-mix는 해당 모듈 패키징 Object에 메소드를 추가하는 형태로 사용한다.

//webpack.mix.js

//laravel-mix 모듈을 받아옴
const mix = require('laravel-mix');

//mix.[options]([entry 파일], [output 파일 경로])
mix.js('resources/assets/js/app.js', 'public/js')
   .sass('resources/assets/sass/app.scss', 'public/css');

위의 예제에서는 ‘sass’를 사용했지만 이 외에도, less, stylus 그리고 일반적인 CSS 등에 따라 여러가지 방법으로 CSS로 컴파일할 수 있다. 현재 컴파일 되는 옵션에 공통적으로 총 2개의 인자가 전달되고 있다. 첫번째 인자는 컴파일할 대상이 되는 entry 파일을 입력해주고, 두번째 인자로는 컴파일된 파일이 저장될 목적지를 넣는다. 두번째 인자를 디렉토리로만 넣은 경우에는 entry 파일과 동일한 파일로 컴파일되서 저장이 된다. 위의 경우에는 컴파일 결과 파일이 public/js/app.js 로 저장이 된다.

만약 output 파일명을 지정하고 싶다면 파일 경로 + 파일명을 입력해주면 된다.

//결과 파일명을 bundle로 지정
mix.js('resources/assets/js/app.js', 'public/js/bundle.js')
   .sass('resources/assets/sass/app.scss', 'public/css/bundle.css');

또한 번들되는 파일이 여러개인 경우 여러개를 사용할 수 있다.

//결과 파일명을 bundle로 지정
mix.js('resources/assets/js/app.js', 'public/js')
   .js('resources/assets/js/entry.js', 'public/js/bundle.js');

Laravel-mix의 옵션

위에 기능들은 기본적인 사용법이며, 그 외에도 laravel-mix에는 몇가지 유용한 옵션을 사용할 수 있다.

sourcemaps

sourceMap()를 사용하면 보다 편하게 개발자 도구에서 디버깅을 할 수 있다.

mix.js('resources/assets/js/app.js', 'public/js/bundle.js')
   .sass('resources/assets/sass/app.scss', 'public/css/bundle.css')
   .sourceMaps();

이 부분은 컴파일하는데, 비용이 들기는 하지만 그 비용은 단순히 컴파일 단계에서의 비용일 뿐만 아니라 사실 이 옵션 없이 뭔가 Error가 떴을 때 디버깅이 힘들다는 점에서는 무조건적으로 사용해야 하는 것 같다.

vendor and version

webpack에서는 기본적으로 빌드할 때, 그 빌드된 파일에 대해 캐싱되지 않도록 처리해주는 옵션이 있다. Front의 프레임워크는 javascript로만 이루어진 어플리케이션이다보니 브라우저 자체에서 image, css, javascript 와 같은 파일을 캐시를 이용해서 저장할 때 같이 저장을 한다. 이러한 문제를 해결하기 위해서 캐싱 처리를 한다. 그런데 이때 내가 배포한 앱이 제대로 반영되지 않을 경우가 있다. 바로 이 캐싱 때문인데 이러한 점을 방지하기 위해 많은 개발자들이 내가 배포나간 앱의 번들 파일을 강제로 내려받게 하기 위해서 output 파일에 대해 timestamp나 고유한 토큰을 접미사로 추가해준다. 그렇게 되면 자동으로 캐싱문제가 해결된다. Laravel-mix에서도 이러한 것을 지원해주는 데 그 때 사용하는 것이 바로 version 옵션이다.

mix.js('resources/assets/js/app.js', 'public/js')
   .version();

위와 같이 사용하게 되면 자동으로 번들된 파일에 버전 정보가 붙게 된다. 이렇게 되면 개발자는 그 파일의 정확한 이름을 알 수 없다. 그래서 views에서 그 js을 호출하는 파일에서 다음과 같이 mix helper를 이용해서 파일을 호출한다.

<script type="text/javascript" src=""></script>

사실 이 것은 개발 버전에서는 굳이 의미가 없는 옵션이다. 오히려 개발할 때 그 파일을 내려받는 시간만 늘어날 수 있으므로 이 부분은 상용버전에서만 추가해준다.

mix.js('resources/assets/js/app.js', 'public/js');

//빌드 중 mix 객체에 inProdation 함수가 있으며, Node의 ENV에 따라서 해당 값이 boolean으로 return 됨
if (mix.inProduction()) {
    mix.version();
}

이 때 mix.inProduction() 이 undefined 라고 빌드 중 에러를 뱉어내며 빌드가 안되는 경우가 있다. 그 때는 Laravel-mix 의 버전을 확인해야 해봐야 알겠지만 아마 0.x 버전 을 사용하고 있지 않을까 싶다. 그런 경우는 두가지 방법이 있다. Laravel-mix의 버전을 업데이트 해주던가, 아니면 아래와 같은 옵션을 사용하면 된다.

if (mix.config.inProduction) {
    mix.version();
}

이때 벤더 라이브러리와 함께 내 어플리케이션의 Javascript를 함께 빌드하면 사용자 입장에서는 벤더 라이브러리는 실제 변화가 없음에도 계속해서 그 캐싱된 Javascript 파일을 내려받으며 같이 내려받게 된다. 이 것은 굉장히 비효율적인 방법이며 만약 어플리케이션이 자주 업데이트를 한다면 그 역시도 그 Javascript를 내려받으면서 생기는 비용들 역시 사용자가 감수해야하는 부분이 될 수 있다. 그러한 점을 방지하기 위해 사용하는 옵션이 vendor 옵션이다. 이 vendor 옵션에는 벤더 라이브러리를 별도로 구성해서 vendor 파일은 자동 캐싱하는 데에 영향을 주지 않게 됩니다. 그렇게 되면 사용자 입장에서는 서비스를 계속해서 이용할 때, 어플리케이션의 Javascript 만 계속해서 내려받으면 벤더 라이브러리는 캐싱된 상태에서 이용할 수 있다. 사용법은 아래와 같다.

mix.js('resources/assets/js/app.js', 'public/js')
   .extract(['vue']);

위와 같이 사용하게 되면 아마 번들링 된 파일 결과물이 총 3개로 나오게 될 것이다.

  1. public/js/manifest.js - webpack 초기화 코드
  2. public/js/vendor.js - 벤더 라이브러리를 포함
  3. public/js/app.js - 어플리케이션의 Javascript 파일 위와 같이 3개로 결과물이 나오면 javascript를 호출하는 화면에서 아래와 같이 순서에 맞게 다시 수정해줘야 한다.
    <script src="text/javascript" src="/js/manifest.js"></script>
    <script src="text/javascript" src="/js/vendor.js"></script>
    <script src="text/javascript" src="/js/app.js"></script>
    

browsersync

webpack-mix의 browsersync는 HMR(Hot Module Replacement)과 동일한 역할을 한다. BrowserSync는 파일의 변경사항을 감시하다가 굳이 새로고침을 하지 않아도 자동으로 브라우저에서 바뀐 부분을 새로고침합니다.

mix.js('resources/assets/js/app.js', 'public/js')
   .browserSync({
      proxy: 'my-domain.dev'
    });

출처

Comments