개발/Front-End

Vue CLI 또는 Webpack 설정을 이용한 이미지 파일명 관리

날고싶은병아리 2022. 6. 23. 08:21

webpack 에서 브라우저 캐싱을 회피하기 위한 전략으로 hash 값을 많이 사용한다.

 

일반적으로 [name].[contenthash][ext] 같이 파일명에 hash 값을 많이 사용하는데,

파일명에 hash 값이 들어있을 경우 파일 내용이 변경되거나 빌드 때 chunk id 가 변경되어 파일명이 계속 바뀌는 문제가 있다.

이 경우 이미 업로드 된 파일을 지우고 다시 올려야 하는 번거로움이 생긴다.

 

나의 경우 파일명 난독화가 필요하기도 하여 hash 값을 이용하긴 해야 한다.

따라서 파일명으로 난독화 처리를 하였다.

const path = require("path");
const crypto = require("crypto");

const IS_LIVE = process.env.NODE_ENV === "production";

module.exports = defineConfig({
  chainWebpack: (config) => {
    config.module
      .rule("images")
      .set("type", "asset/resource")
      .set("generator", {
        filename: (pathData) => {
          const fixedFilenameFlag =
            path
              .extname(pathData.module.resourceResolveData.context.issuer)
              .toLowerCase() === ".html";
          const hashFilename = crypto
            .createHash("md4")
            .update(pathData.filename)
            .digest("hex");
          return fixedFilenameFlag
            ? "img/[name][ext]"
            : !IS_LIVE
            ? `img/${hashFilename}?[name][ext].[contenthash]`
            : `img/${hashFilename}[ext]?[contenthash]`;
        },
      });
  },
});

node.js 기본 모듈인 crypto 를 이용하여 md4 hash 를 뽑아 파일명 난독화를 처리하고

쿼리 스트링에 contenthash 값을 넣어 캐싱을 회피한다.

 

다만 html 파일에서 사용하는 이미지의 경우 og image 로 사용하기도 하고

Back-End 개발자가 관리해야 하는 경우도 있어 난독화를 하지 않는다.

pathData 의 issuer 를 이용하면 어느 파일에서 호출한 이미지인지 확인이 가능하다.

const path = require("path");
const crypto = require("crypto");

const IS_LIVE = process.env.NODE_ENV === "production";

module.exports = {
  output: {
    assetModuleFilename: (pathData) => {
      const fixedFilenameFlag =
        path
          .extname(pathData.module.resourceResolveData.context.issuer)
          .toLowerCase() === ".html";
      const hashFilename = crypto
        .createHash("md4")
        .update(pathData.filename)
        .digest("hex");
      return fixedFilenameFlag
        ? "img/[name][ext]"
        : !IS_LIVE
        ? `img/${hashFilename}?[name][ext].[contenthash]`
        : `img/${hashFilename}[ext]?[contenthash]`;
    },
  },
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|webp|avif)(\?.*)?$/,
        type: "asset/resource",
      },
    ],
  },
};

추가로 순수 webpack 에서는 assetModuleFilename 을 이용하면 된다.