Webpack 이미지 경로 처리

W

참고 : https://stackoverflow.com/questions/48475500/webpack-scss-how-to-work-with-image-paths

현재상황

파일 구조

style.scss

#page {
  overflow: hidden;
  .bg{
    background:url('./assets/bg.png') no-repeat;
    overflow:hidden;
  }
....

webpack.config.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const join = require('path').join;
module.exports = {
  entry: join(__dirname, '/src/main.ts'),
  devtool: 'source-map',
  output: {
    filename: "main.js",
    path: join(__dirname, '/dist'),
  },
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        exclude: /node_modules/,
        use: 'ts-loader'
      },
      {
        test: /\.(scss|css)$/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"]
      },
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "style.css",
    }),
    new HtmlWebpackPlugin({
      template: join(__dirname, '/src/index.html')
    }),
    new CleanWebpackPlugin({
      cleanAfterEveryBuildPatterns: ['dist']
    }),
  ],
  resolve: {
    extensions: ['.js', '.ts', '.json', 'scss']
  }
};

내가 원하는 상황

webpack을 빌드하면 dist폴더의 구조는 아래와 같이 되고

style.css파일안에서 background-image를 지정하는 부분은

.bg { 
   background:url(./assets/bg.png)
}

이렇게 되는것이다.

일단 Build해보자

에러가 따-악

ERROR in ./src/style.scss
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleParseError: Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

You may need an appropriate loader to handle this file type

OK, 내 추측으로는 style.scss파일의 url('./assets/bg.png')가 문제인것같다. 이 코드를 처리할 수 있는 loader가 없다는 의미인듯.

file-loader를 설치해보자고

이렇게 파일을 처리해야 하는경우 file-loader가 필요하다.

npm install --save-dev file-loader

그리고 webpack.config.js도 아래와 같이 변경해준다.

rules: [
  {
    test: /\.(png|jpe?g|gif)$/i,
    loader: 'file-loader',
  },

다시 빌드 해보자!

...

에러가 또 나왔다.

ERROR in ./src/style.scss
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
Error: Automatic publicPath is not supported in this browser

publicPath를 내가 직접 지정해 줘야한다는데,,publicPath가 뭐지?

publicPath

경로 앞에 붙일 string을 의미한다. 예를들어서,

#page {
  overflow: hidden;
  .bg{
    background: url('./assets/bg.png') no-repeat;
    overflow:hidden;
  }

이렇게 하고, webpack.config.js를 아래와 같이 수정하고

{
    test: /\.(scss|css)$/,
    use: [
      {
        loader: MiniCssExtractPlugin.loader,
        options: {
          publicPath: 'abc'
        }
      },
      "css-loader", "sass-loader"
    ]
},

build하면 이런식으로 된다.

.bg{
  background:url(abc/f6d0d64669fe0481d16f73a173c63a4e.png)
}

파일명 앞에 abc가 추가되었다.

근데 나는 url('./assets/bg.png') 이렇게 적었는데, .png빼고 한글자도 같은게 없네? bg 는 뭐 파일이름이 webpack맘대로 바뀌었다고 치다손, ./assets 는 어디로 간걸까?

내 생각에는! file-loader가 ./assets/bg.png을 읽어서 복사해가지고 dist폴더에 f6d0d64669fe0481d16f73a173c63a4e.png 라는 이름으로 붙여넣기 한거다. 그리고 MiniCssExtractPlugin.loader 에서 지정한 publicPath대로 앞에 abc를 붙인거다.

publicPathassets으로 지정해서 다시 build해보자.

.bg { 
  background: url(./assets/f6d0d64669fe0481d16f73a173c63a4e.png)
}

예상대로 css파일에 주소는 publicPath가 적용되서 잘 바뀌었는데,

파일구조에,,,assets폴더가 생성되지 않았다. 어떻게 하지?

name

rules: [
  {
    test: /\.(png|jpe?g|gif)$/i,
    loader: 'file-loader',
    options: {
      name: 'assets/[contenthash].[ext]'
    }
  },

위처럼 하면 된다!. 알아서 assets폴더를 만들어준다!

결과물

webpack.config.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const path = require('path');
const join = path.join;
const resolve = path.resolve;
module.exports = {
  entry: join(__dirname, '/src/main.ts'),
  devtool: 'source-map',
  output: {
    filename: "main.js",
    path: join(__dirname, '/dist'),
  },
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif)$/i,
        loader: 'file-loader',
        options: {
          name: 'assets/[contenthash].[ext]'
        }
      },
      {
        test: /\.(ts|tsx)$/,
        exclude: /node_modules/,
        use: 'ts-loader'
      },
      {
        test: /\.(scss|css)$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: ''
            }
          },
          "css-loader", "sass-loader"]
      },
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "style.css",
    }),
    new HtmlWebpackPlugin({
      template: join(__dirname, '/src/index.html')
    }),
    new CleanWebpackPlugin({
      cleanAfterEveryBuildPatterns: ['dist']
    }),
  ],
  resolve: {
    extensions: ['.js', '.ts', '.json', 'scss']
  }
};

파일구조

assets폴더가 생성되었고, 그 안에 파일이 잘 들어가있다.

style.scss

.bg{
  background: url('./assets/bg.png') no-repeat;
  overflow:hidden;
}

style.css(빌드후 생성된 파일)

.bg { 
  background: url(assets/f6d0d64669fe0481d16f73a173c63a4e.png)
}

브라우저에서 이미지를 잘 읽었는가?

잘 읽었다!

Add Comment