DEV/JS

[JS] gulp.spritesmith 레티나 이미지 스프라이트 자동화 (심화편)

zineeworld 2020. 7. 14. 15:16

요구사항

나는 1배수/2배수 스타일이 따로 필요하지 않았다. 2배수 이미지로 만들어진 스프라이트 이미지와 1배수 사이즈 기반으로 작성된 코드만 있으면 되었기에 좀 더 파보기로 했다.

 

1. 원하는 scss 파일 형식으로 자동화 하기 (100% 성공)

2. 이미지 최적화 적용 (50% 성공)

 

원하는 SCSS 파일 형식으로 자동화하기

gulp 패키지 추가 설치

이미지 최적화를 위해 아래 패키지를 추가로 설치한다. 

npm install --save-dev gulp-imagemin vinyl-buffer

gulpfile.js

⚠️ spConfig 안에 있는 경로값는 각자의 환경과 다르므로 주의하길 바란다.

const gulp = require('gulp');
const buffer = require('vinyl-buffer');
const merge = require('merge-stream');
const imagemin = require('gulp-imagemin');
const spritesmith = require('gulp.spritesmith');

const spConfig = {
  targetImgPath: './apps/markup/src/assets/sprite/input/*.png',
  targetRetinaImgPath: './apps/markup/src/assets/sprite/input/*@2x.png',
  destImgName: 'sprite.png',
  destRetinaImgName: 'sprite2x.png',
  destCssName: '_sprite.scss',
  destImgPath: './apps/markup/src/assets/sprite/output/',
  destCssPath: './libs/shared/assets/scss/components/',
  destCssTemplate: './apps/markup/src/assets/handlebarsStr.css.handlebars'
}

gulp.task('sprite', function() {
  const spriteData = gulp.src(spConfig.targetImgPath)
    .pipe(spritesmith({
      retinaSrcFilter: spConfig.targetRetinaImgPath,
      imgName: spConfig.destImgName,
      retinaImgName: spConfig.destRetinaImgName,
      padding: 5,
      cssName: spConfig.destCssName,
      cssTemplate: spConfig.destCssTemplate,
    }));

  const imgStream = spriteData.img
    .pipe(buffer())
    .pipe(imagemin())
    .pipe(gulp.dest(spConfig.destImgPath));

  const cssStream = spriteData.css
    .pipe(buffer())
    .pipe(gulp.dest(spConfig.destCssPath));

  return merge(imgStream, cssStream);
});

handlebarsStr.css.handlebars

이 handlebarsStr.css.handlebars 을 통해 SCSS 코드를 군더더기 없이 내가 필요한 형태로 뽑을 수 있게 커스텀 할 수 있었다.

handlebarsjs란?
참고 : https://handlebarsjs.com/guide

 

{{#spritesheet}}
.sprite {
  display: block;
  flex-shrink: 0;
  background-image: url($sprite-url);
  background-repeat: no-repeat;
  background-size: {{px.width}} {{px.height}};
}
{{/spritesheet}}

{{#sprites}}
.sprite-{{name}} {
  width: {{px.width}};
  height: {{px.height}};
  background-position: {{px.offset_x}} {{px.offset_y}};
}
{{/sprites}}

_sprite.scss

이 파일은 매번 생성시 마다 덮어씌워지기 때문에, $sprite-url은 _variable.scss 파일에서 따로 관리한다. 경로가 바뀌지 않는 다면 고정값으로 변경해두어도 무방하다.

.sprite {
  display: block;
  flex-shrink: 0;
  background-image: url($sprite-url);
  background-repeat: no-repeat;
  background-size: 176px 176px;
}

.sprite-btn-arrow-down {
  width: 32px;
  height: 32px;
  background-position: -96px -64px;
}
.sprite-btn-arrow-right {
  width: 32px;
  height: 32px;
  background-position: 0px -112px;
}
.sprite-btn-common-back-m {
  width: 32px;
  height: 32px;
  background-position: -32px -112px;
}

이미지 최적화 결과

imagemin을 적용해도 tinypng 를 이길 수는 없었다. tinyPNG 만큼 퍼포먼스 나오는 패키지 있으면 알려주세요!

original gulp-imagemin tinypng
24KB 15KB (-38.8%) 7.5KB (-65%)

 

 


이건 순전히 내 요구에 맞춰진 방법이다. cssTemplate 핸들러를 사용하지 않고 sprite.scss 파일을 생성해서 _mixin_sprite.scss 로 재조합해서 쓰는 방법도 있다! 확장성을 생각하면 이 방법이 좋긴 한데, 파악하기가 쉽지 않고 간결하게 쓰고 싶어서 내가 생각했던 방식으로 코드를 만들어 낼 수 있는지 확인해 보고 싶었다. 시간이 꽤 걸리긴 했지만 해내서 만족스러웠다.

이렇게 쓰는 방법도 있습니다

 

반응형