D
D
Dmitry2020-11-09 23:17:10
webpack
Dmitry, 2020-11-09 23:17:10

Webpack 5 how to setup proper image bundle?

Good day.
The problem is this, I just master webpack, first I assembled it myself, but then I found a ready-made assembly and tried to bring it to mind.
npm run build fails to properly pass images to dist.
The problem is that image files are added to the root with a unique hash instead of going into the assets/images folder with their name.
In the styles, the addresses of the pictures are also changed to those that are in the root, and not in the folder you need, although they were originally specified in the publick/images folder.
PS I hope I explained it in an accessible

way The file system is as follows

  • dist
    • assets
      • images

    • js
    • styles


  • public
    • images
    • fonts

  • src
    • js
    • styles




The config is divided into 4
paths.js files
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": "[email protected]:taniarascia/webpack-boilerplate"
  },
  "dependencies": {}
}

Answer the question

In order to leave comments, you need to log in

4 answer(s)
1
1thater, 2020-11-10
@Azazel1928

If you understand your problem correctly, you need to correctly specify the file name in the file loader (you are using a new feature (asset / resource), if you can specify the file name in it, then in it, if not, replace it with the file loader).
Filename - the path to the file.

{
  loader: 'file-loader',
  options: {
    publicPath: '../',
    name: `assets/image/[name].[ext]`,
  }
}

E
Egor Danchenko, 2021-07-23
@YahorDanchanka

Correct Solution for Webpack 5

module.exports = {
   ...
   output: {
     ...
     assetModuleFilename: 'assets/images/[name][ext]'
   },
   module: {
     rules: [
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
     ],
   },
 };

D
Dmitry, 2020-11-10
@Azazel1928

I contacted the developer of the assembly. Got the following response:

Images that are used in a script should be stored in src/images. Public stores files that are used directly in template.html. In the markup, "../public" should be replaced with "./assets", for example:
<div id="root">
  <!-- на самом деле изображение хранится в ../public/images -->
  <img src="./assets/images/example.jpg" />
</div>

Another point: in webpack.common.js and webpack.prod.js, the value of publicPath in output must be changed to "./" (put a dot at the beginning).

A
Anton M, 2022-04-15
@Bluorenge

To set the path for different types of assets (for example, for fonts), you need to add the 'asset/resource' type to the rules:

{
    test: /\.(gif|png|jpe?g|svg)$/i,
    type: 'asset/resource',
},
{
    test: /\.(ttf|eot|woff2?)$/i,
    type: 'asset/resource',
},

And in the output add the assetModuleFilename field with the function. In this case, all assets will be saved to the same path as in the src folder:
output: {
    ...
    assetModuleFilename: pathData => {
        const filepath = path.dirname(pathData.filename).split('/').slice(1).join('/');
        return `${filepath}/[name][ext]`;
    },
},

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question