본문 바로가기

Programming/FE Tooling

AngularJS Bundle 만들기, 그리고 Minification.

2019년에 AngularJS 디렉터리 모범사례에 대하여 조악한 번역글을 올렸는데, 조회 수가 꾸준히 유지되고 있다. 

생각보다 AngularJS를 유지하고 있는 프로젝트들이 여기저기 남아있나 보다.

리액트, 뷰에 비해 조악한 생태계에서 조금이라도 도움이 되기 위해, 레거시 프로젝트를 유지 보수하며 정리한 내용을 포스팅으로 남기기로 결심했다. 

 

 


 

목표   

Task Runner를 실행해서 AngualrJS 프로젝트에 

- 자바스크립트, CSS 압축 (Minification)

- 자바스크립트, CSS 번들 만들기 

- 파일명에 Hash Prefix 붙이기 

를 적용한다. 

 

Prerequisite

 

npm install ... --save-dev 명령어를 사용해서 아래 패키지를 설치한다. 

설명은 간략하게 작성했다. 자세한 정보는 링크를 클릭해서 살펴보시길!

  1. grunt 
  2. grunt-contrib-clean : 설정한 경로 하위의 모든 파일을 삭제한다.
  3. grunt-contrib-concat : 지정한 소스 파일들을 1개의 파일로 연결(취합)한다.
  4. grunt-contrib-copy : 원본 파일의 사본을 만든다. 
  5. grunt-usemin : HTML 파일 내의 스크립트, 스타일 시트 등을 최적화된 버전(cssmin, uglify 된 버전)으로 대체
  6. grunt-contrib-cssmin : CSS 파일을 압축(Minification)한다.
  7. grunt-contrib-uglify : CSS 파일을 압축(Minification)한다.
  8. grunt-rev : 파일명에 해시코드를 붙인다. 
  9. grunt-minjson : JSON 파일을 압축(Minification)한다.
npm install grunt grunt-contrib-clean grunt-contrib-concat grunt-contrib-copy 
grunt-contrib-cssmin grunt-contrib-uglify grunt-rev grunt-usemin grunt-minjson --save-dev

 

디렉터리 설명 

- app : AngularJS로 개발한 소스코드가 들어있다. 

- bower_components : 3rd Party Package가 들어있다. bower.io/ 참고

- dist : Task Runner 실행 결과, 빌드된 소스코드이다. 상용 배포 시, dist 하위 소스를 배포한다. 

 

 

적용 순서

1. 루트에 Gruntfile.js 파일을 생성하고, Task를 작성한다. 

module.exports = function (grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    // dist 디렉토리의 하위 폴더, 파일을 모두 삭제한다. 
    clean: ['dist'],
    // app 경로의 파일을 dist로 복사한다. 
    copy: {
      main: {
        expand: true,
        cwd: 'app/components',
        src: ['**', '!**/*.js'],
        dest: 'dist/app/components',
      },
      assets: {
        expand: true,
        cwd: 'app/assets',
        src: ['**', '!lib/**', '!**/*.css'],
        dest: 'dist/assets',
      },
      bower: {
        expand: true,
        cwd: 'bower_components/',
        src: ['**'],
        dest: 'dist/libs',
      },
    },
    // dist 하위 파일에 Hash Prefix를 붙인다. 
    rev: {
      files: {
        src: ['dist/*.{js,css}', 'dist/app/**.{js,css}'],
      },
    },
    // minification 결과 생성된 파일의 경로가 삽입될 파일을 설정한다. (준비)
    useminPrepare: {
      html: 'app/index.html',
    },
    // 파일을 번들링한다. 
    concat: {
      generated: {
        files: [
          { dest: 'dist/bundle.js', src: ['app/**/*.js'] },
          { dest: 'dist/style.css', src: ['app/assets/css/style.css'] },
        ],
      },
    },
    // 번들링된 파일을 삽입한다. 
    usemin: {
      html: ['dist/index.html'],
    },
    // 자바스크립트 파일을 Minification한다. 
    uglify: {
      options: {
        report: 'min',
        mangle: false,
      },
      build: {
        src: 'dist/bundle.js', //uglify할 대상 설정
        dest: 'dist/bundle.min.js', //uglify 결과 파일 설정
      },
    },
    // CSS 파일을 Minification한다.  
    cssmin: {
      target: {
        files: [
          {
            expand: true,
            cwd: 'dist/',
            src: ['*.css', '!*.min.css'],
            dest: 'dist',
            ext: '.min.css',
          },
        ],
      },
    },
    minjson: {
      compile: {
        files: {
          'dist/assets/translation/ENG/locale_code.json': //destination
          'assets/translation/ENG/locale_code.json', //source
        },
      },
    },
  });

  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-rev');
  grunt.loadNpmTasks('grunt-usemin');
  grunt.loadNpmTasks('grunt-minjson');

  // Tell Grunt what to do when we type "grunt" into the terminal
  grunt.registerTask('default', [
    'clean',
    'copy',
    'useminPrepare',
    'concat',
    'uglify',
    'cssmin',
    'rev',
    'usemin',
    'minjson',
  ]);
};

 

2. 터미널에서 명령어를 실행하면 각각의 Task가 연쇄적으로 실행되어 해싱 > 번들링 > 압축된다. 

grunt

 

 

유의사항 

copy, concat, mincss, uglify, rev 등 Task를 순차적으로 실행하다면 파일 경로나 파일명이 바뀐다. 

예를 들어 

  • /app/shared/scroll.js   👉  /dist/shared/9bb7e1e9.scroll.js
  • /bower_components/jquery/jquery.js    👉   /libraries/jquery/jquery.js
  • /assets/css/style.css    👉   /dist/assets/css/9623c144.style.min.css

파일 경로, 파일 명이 변경된 상태에서 웹서버를 기동하면, Index.html에서 참조하는 파일들을 읽지 못한다. 

경로, 이름이 다르기 때문이다. 

 

다행히 grun-usemin은 html 파일이 참조하는 js, css 경로를 동적으로 변경시켜줄 수 있다. 

아래처럼 index.html에서 아래와 같이 명시적으로 지정해준다. 

    <head>
      <!-- build:css style.min.css --> // 변경 후 파일명(해시코드는 작성할 필요없다)
      <link rel="stylesheet" href="./assets/css/style.css"> // 변경 전 파일명
      <!-- endbuild -->
    </head>
    <body>
      <!-- build:js libs/angular-ui-router/release/angular-ui-router.min.js -->
      <script src="../bower_components/angular-ui-router/release/angular-ui-router.min.js"></script>
      <!-- endbuild -->
      <!-- build:js bundle.min.js -->
      <script src="components/dashboard/dashboard.js"></script>
      <!-- endbuild -->
    </body>