@Azazel1928
Учусь верстать

Webpack 5 как настроить правильную сборку изображений?

Доброго времени суток.
Проблема такая, только осваиваю webpack, сначала собрал сам, но потом нашел готовую сборку и попытался довести до ума.
Не получается при команде npm run build правильно передать изображения в dist.
Проблема в том что файлы изображений добавляются в корень с уникальным хэшем вместо того чтоб идти в папку assets/images со своим названием.
В стилях так же адреса картинок меняются на те, что лежат в корне, а не в нужно папке хотя изначально указаны в папку publick/images.
P.S надеюсь объяснил доступно

Файловая система следующая
  • dist
    • assets
      • images

    • js
    • styles


  • public
    • images
    • fonts

  • src
    • js
    • styles




Конфиг разбит на 4 файла
paths.js
const path = require('path')

module.exports = {
  // Source files
  src: path.resolve(__dirname, '../src'),

  // Production build files
  build: path.resolve(__dirname, '../dist'),

  // Static files that get copied to build folder
  public: path.resolve(__dirname, '../public'),


webpack.commons.js
const paths = require('./paths')

const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  // Where webpack looks to start building the bundle
  entry: [paths.src + '/index.js'],

  // Where webpack outputs the assets and bundles
  output: {
    path: paths.build,
    filename: '[name].bundle.js',
    publicPath: '/',
  },

  // Customize the webpack build process
  plugins: [


    // Copies files from target to destination folder
    new CopyWebpackPlugin({
      patterns: [
        {
          from: paths.public,
          to: 'assets',
          globOptions: {
            ignore: ['*.DS_Store'],
          },
        },
      ],
    }),

    // Generates an HTML file from a template
    // Generates deprecation warning: https://github.com/jantimon/html-webpack-plugin/issues/1501
    new HtmlWebpackPlugin({
      title: 'webpack Boilerplate',
      template: paths.src + '/login.html', // template file
      filename: 'index.html', // output file
    }),
  ],

  // Determine how modules within the project are treated
  module: {
    rules: [
      // JavaScript: Use Babel to transpile JavaScript files
      {test: /\.js$/, exclude: /node_modules/, use: ['babel-loader']},

      // Styles: Inject CSS into the head with source maps
      {
        test: /\.(scss|css)$/,
        use: [
          'style-loader',
          {loader: 'css-loader', options: {sourceMap: true, importLoaders: 1}},
          {loader: 'postcss-loader', options: {sourceMap: true}},
          {loader: 'sass-loader', options: {sourceMap: true}},
        ],
      },

      // Images: Copy image files to build folder
      {test: /\.(?:ico|gif|png|jpg|jpeg)$/i, type: 'asset/resource'},

      // Fonts and SVGs: Inline files
      {test: /\.(woff(2)?|eot|ttf|otf|svg|)$/, type: 'asset/inline'},
    ],
  },
}

webpack.dev.js
const paths = require('./paths')

const webpack = require('webpack')
const { merge } = require('webpack-merge')
const common = require('./webpack.common.js')

module.exports = merge(common, {
  // Set the mode to development or production
  mode: 'development',

  // Control how source maps are generated
  devtool: 'inline-source-map',

  // Spin up a server for quick development
  devServer: {
    historyApiFallback: true,
    contentBase: paths.build,
    open: true,
    compress: true,
    hot: true,
    port: 3000,
  },

  plugins: [
    // Only update what has changed on hot reload
    new webpack.HotModuleReplacementPlugin(),
  ],
})

webpack.prod.js
const paths = require('./paths')
const { merge } = require('webpack-merge')
const common = require('./webpack.common.js')

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = merge(common, {
  mode: 'production',
  devtool: false,
  output: {
    path: paths.build,
    publicPath: '/',
    filename: 'js/[name].[contenthash].bundle.js',
  },
  plugins: [


        // Removes/cleans build folders and unused assets when rebuilding
        new CleanWebpackPlugin(),

    // Extracts CSS into separate files
    // Note: style-loader is for development, MiniCssExtractPlugin is for production
    new MiniCssExtractPlugin({
      filename: 'styles/[name].[contenthash].css',
      chunkFilename: '[id].css',
    }),
  ],
  module: {
    rules: [
      {
        test: /\.(scss|css)$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              importLoaders: 2,
              sourceMap: false,
            },
          },
          'postcss-loader',
          'sass-loader',
        ],
      },
    ],
  },
  optimization: {
    minimize: true,
    minimizer: [new OptimizeCssAssetsPlugin(), "..."],
    // Once your build outputs multiple chunks, this option will ensure they share the webpack runtime
    // instead of having their own. This also helps with long-term caching, since the chunks will only
    // change when actual code changes, not the webpack runtime.
    runtimeChunk: {
      name: 'runtime',
    },
  },
  performance: {
    hints: false,
    maxEntrypointSize: 512000,
    maxAssetSize: 512000,
  },
})


package.json
{
  "name": "webpack-boilerplate",
  "version": "2.0.0",
  "description": "Sensible webpack 5 boilerplate using Babel and PostCSS with a hot dev server and an optimized production build.",
  "main": "index.js",
  "author": "Tania Rascia",
  "license": "MIT",
  "scripts": {
    "start": "cross-env NODE_ENV=development webpack serve --config config/webpack.dev.js",
    "build": "cross-env NODE_ENV=production webpack --config config/webpack.prod.js"
  },
  "keywords": [
    "webpack",
    "webpack 5",
    "webpack boilerplate"
  ],
  "devDependencies": {
    "@babel/core": "^7.12.1",
    "@babel/plugin-proposal-class-properties": "^7.12.1",
    "@babel/preset-env": "^7.12.1",
    "babel-loader": "^8.1.0",
    "clean-webpack-plugin": "^3.0.0",
    "copy-webpack-plugin": "^6.2.1",
    "cross-env": "^7.0.2",
    "css-loader": "^5.0.0",
    "css-minimizer-webpack-plugin": "^1.1.5",
    "html-webpack-plugin": "^5.0.0-alpha.7",
    "mini-css-extract-plugin": "^1.0.0",
    "node-sass": "^4.14.1",
    "optimize-css-assets-webpack-plugin": "^5.0.4",
    "postcss-loader": "^4.0.4",
    "postcss-preset-env": "^6.7.0",
    "sass-loader": "^10.0.3",
    "style-loader": "^2.0.0",
    "webpack": "^5.1.3",
    "webpack-cli": "^4.0.0",
    "webpack-dev-server": "^3.11.0",
    "webpack-merge": "^5.2.0"
  },
  "repository": {
    "type": "git",
    "url": "git@github.com:taniarascia/webpack-boilerplate"
  },
  "dependencies": {}
}
  • Вопрос задан
  • 11104 просмотра
Решения вопроса 1
@1thater
Если правильно понял вашу проблему, нужно правильно указать имя файла в file loader (вы используете новую фичу (asset/resource), если в ней можно указать имя файла, то в ней, если нет то заменить на file loader).

Имя файла - путь до файла.

{
  loader: 'file-loader',
  options: {
    publicPath: '../',
    name: `assets/image/[name].[ext]`,
  }
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
@YahorDanchanka
Frontend developer
Правильное решение для Webpack 5
module.exports = {
   ...
   output: {
     ...
     assetModuleFilename: 'assets/images/[name][ext]'
   },
   module: {
     rules: [
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
     ],
   },
 };
Ответ написан
@Bluorenge
Junior front-end developer
Чтобы настроить путь для разного вида ассетов (например, ещё для шрифтов), нужно добавить в rules тип 'asset/resource':
{
    test: /\.(gif|png|jpe?g|svg)$/i,
    type: 'asset/resource',
},
{
    test: /\.(ttf|eot|woff2?)$/i,
    type: 'asset/resource',
},

А в output добавить поле assetModuleFilename с функцией. В таком случае, все асcеты будут сохранятся по тому же пути, что и в папке src:
output: {
    ...
    assetModuleFilename: pathData => {
        const filepath = path.dirname(pathData.filename).split('/').slice(1).join('/');
        return `${filepath}/[name][ext]`;
    },
},
Ответ написан
@Azazel1928 Автор вопроса
Учусь верстать
Обратился к разработчику сборки. Получил следующий ответ:
Изображения, которые используются в скрипте, должны храниться в src/images. В public хранятся файлы, которые используются в template.html напрямую. В разметке вместо "../public" следует указывать "./assets", например:
<div id="root">
  <!-- на самом деле изображение хранится в ../public/images -->
  <img src="./assets/images/example.jpg" />
</div>

Еще один момент: в webpack.common.js и webpack.prod.js значение publicPath в output надо изменить на "./" (поставить точку в начале).
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы