1

PUG require image (webpack)

Problem with image processing in pug + webpack. Earlier in PUG, I don't process pictures via loader. I used WebpackCopyPlugin, and wrote absolute paths.

Like that:

- let imgPath = '/assets/img/'
img(src=imgPath + 'icons/logo/boto.agency.b.svg')

When I build the project, WebpackCopyPlugin copied all the pictures, pug compiled with the correct paths and everything worked fine. Now I need to process the pictures via Loader. According to the documentation, I need to write the paths like this: img (src = require ('./ img.png')) But generally it does not work fine. I discovered several scenarios. In the src/assets/img folder there are several pictures.

1.

img(src=require('../../../../assets/img/1-1.png'))

or

img(src=require(`@img/1-1.png`)) 
// '@img': path.resolve(__dirname, '../../src/assets/img/')

Everything works, during assembly we have 1 file 1-1.png. Here I do not use variables in require, therefore these options are not suitable

2.Starting to use variables:

- let fileName = '1-1.png'

img(src=require(`@img/${fileName}`))

or

img(src=require(`../../../../assets/img/${fileName}`))

or

img(src=require(`@img/`+fileName))

or use mixin

In dev mode everything is fine. After project's building, happens following - file-loader copies ALL files from the folder, although I specify only 1. It happens like this:

file-loader test: /\.(png|jpg|gif|svg)$/,
  • assets
    • img
      • 1-1.png
      • 2-2.jpg
      • icons
        • 3.svg
      • pictures
        • 3.png
        • 3.jp2
        • 3.jxr

After project's building, in the folder public(dist)/assets/img will be all files except 3.jp2 3.jxr, (3.png and 3.svg will also be copied even though they are in folders). This option is also not suitable. I want to receive only those files that I specify.

3. Start experimenting

- let fileName = 'img/1-1.png'
img(src=require(`../../../../assets/${fileName}`))

I get an error in dev and build both:

throw new Error('Callback was already called.'); ^ Error: Callback was already called.

- let fileName = 'img/1-1.png'
// '@': path.resolve(__dirname, '../../src/assets/')
img(src=require(`@/${fileName}`))

Also an error

4.

- let fileName = '1-1.png'
- let basePath = '../../../../assets/img/'
- let path = basePath+fileName

img(src=require(path))

or

- let aliasPath = '@/img/'
- let path = aliasPath+fileName
img(src=require(path))

Error: Cannot find module '../../../../assets/img/1-1.png'

- let fileName = 'img/1-1.png'
- let basePath = '../../../../assets/'
- let path = fileName+basePath2
img(src=require(path))

Error: Cannot find module '../../../../assets/img/1-1.png'

With any file-loader configurations, it all depends on whether I use variables in equire or not

What is the problem?

My webpack config:

/* Base config:
   ========================================================================== */
const webpack = require('webpack');
const path = require('path');
const fs = require('fs');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {VueLoaderPlugin} = require('vue-loader');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// Main const. Feel free to change it
const isDev = process.env.NODE_ENV === 'development';
const isProd = !isDev;
const PATHS = {
  src: path.join(__dirname, '../../src'),
  dist: path.join(__dirname, (isProd ? '../../public' : '../../dist')),
  webpack: path.join(__dirname, '../../webpack'),
  assets: 'assets/',
};

const fileName = ext => isDev ? `[name].${ext}` : `[name].[hash].${ext}`
const plugins = (type) => {
  const base = [
    new VueLoaderPlugin(),
    new MiniCssExtractPlugin({
      filename: `${PATHS.assets}css/${fileName('css')}`,
    }),
    new webpack.ProvidePlugin({
      '$': 'jquery',
      'jQuery': 'jquery',
      'window.jQuery': 'jquery',
    }),
    new CopyWebpackPlugin({
      patterns: [
        //{from: `${PATHS.src}/${PATHS.assets}img`, to: `${PATHS.assets}img`},
        {from: `${PATHS.src}/${PATHS.assets}fonts`, to: `${PATHS.assets}fonts`},
        {from: `${PATHS.src}/pages/php`, to: ``},
        {from: `${PATHS.src}/static`, to: ''},
      ]
    }),
    new CleanWebpackPlugin(),
  ];
  switch (type) {
    case 'html': {
      const PAGES_DIR = `${PATHS.src}/pages`;
      const PAGES = fs
        .readdirSync(PAGES_DIR)
        .filter((fileName) => fileName.endsWith('.html'));
      base.push(
        ...PAGES.map(
          (page) =>
            new HtmlWebpackPlugin({
              template: `${PAGES_DIR}/${page}`,
              filename: page,
            }),
        ),);
      break;
    }

    case 'pug': {
      const PAGES_DIR = `${PATHS.src}/pages/pug/includes/pages`;
      const PAGES = fs
        .readdirSync(PAGES_DIR)
        .filter((fileName) => fileName.endsWith('.pug'));
      base.push(
        ...PAGES.map(
          (page) =>
            new HtmlWebpackPlugin({
              template: `${PAGES_DIR}/${page}`,
              filename: (page === 'index.pug' || page === '404.pug' ?
                page.replace(/\.pug/, '.html') :
                `${page.split('.')[0]}/index.html`),
            }),
        ),);
      break;
    }
  }
  const PAGES_PHP = fs
    .readdirSync(PATHS.src)
    .filter((fileName) => fileName.endsWith('.php'));
  base.push(
    ...PAGES_PHP.map(
      (page) =>
        new HtmlWebpackPlugin({
          template: `${PATHS.src}/${page}`,
          filename: `${page}`,
          inject: false,
        }),
    ),)
  return base
}


module.exports = {
  externals: {
    paths: PATHS,
  },
  entry: {
    app: ['@babel/polyfill', PATHS.webpack]
    // module: `${PATHS.src}/your-module.js`,
  },
  output: {
    filename: `${PATHS.assets}js/${fileName('js')}`,
    path: PATHS.dist,
    publicPath: isDev ? '/' : '/',

  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          name: 'vendors',
          test: /node_modules/,
          chunks: 'all',
          enforce: true,
        },
        // css: {
        //   name: 'css',
        //   test: /\.css$/,
        //   chunks: 'all',
        //   enforce: true,
        // },
        // scss: {
        //   name: 'scss',
        //   test: /\.scss$/,
        //   chunks: 'all',
        //   enforce: true,
        // },
      },
    },
  },
  devtool: isDev ? 'source-map' : 'eval',
  module: {
    rules: [
      // TypeScript
      {
        test: /\.ts$/,
        exclude: /node_modules|vue\/src/,
        loader: 'ts-loader',
        options: {
          appendTsSuffixTo: [/\.vue$/],
        },
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          presets: [
            '@babel/preset-env'
          ]
        }
      },
      {
        test: /\.pug$/,
        oneOf: [
          {
            resourceQuery: /^\?vue/,
            use: ['pug-plain-loader'],
          },
          {
            use: ['pug-loader'],
          }
        ],
      },
      {
        // Vue
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loader: {
            scss: 'vue-style-loader!css-loader!sass-loader',
          },
          postcss: {
            config: {
              path: PATHS.webpack,
            },
          },
        },
      },
      {
        // Fonts
        test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
        loader: 'file-loader',
        options: {
          name: `[name].[ext]`,
          outputPath: '/assets/fonts/'
        },
      },
      {
        test: /\.(png|jpg|gif|svg)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              esModule: false,
               name: '[name].[ext]',
              outputPath: `${PATHS.assets}/img`,
             //publicPath: `/${PATHS.assets}img`,
            },
          },
        ],

      },
      {
        // scss
        test: /\.scss$/,
        use: [
          'style-loader',
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {sourceMap: true},
          },
          {
            loader: 'postcss-loader',
            options: {
              sourceMap: true,
              config: {path: `${PATHS.webpack}/postcss.config.js`},
            },
          },
          {
            loader: 'sass-loader',
            options: {
              sourceMap: true,
            },
          },
          {
            loader: 'sass-resources-loader',
            options: {
              resources: [
                './src/assets/scss/core/base.scss',
              ],
            },
          },
        ],
      },
      {
        // css
        test: /\.css$/,
        use: [
          'style-loader',
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {sourceMap: true},
          },
          {
            loader: 'postcss-loader',
            options: {
              sourceMap: true,
              config: {path: `${PATHS.webpack}/postcss.config.js`},
            },
          },
        ],
      },
      // {
      //   test: /\.(html)$/,
      //   use: [
      //     {
      //       loader: 'html-loader',
      //       // options: {
      //       //   minimize: {
      //       //     removeComments: true,
      //       //     collapseWhitespace: false,
      //       //   },
      //       // },
      //     },
      //   ],
      // },
    ],
  },
  resolve: {
    alias: {
      '~': PATHS.src,
      'vue$': 'vue/dist/vue.js',
      '@': path.resolve(__dirname, '../../src'),
      '@img': path.resolve(__dirname, '../../src/assets/img/'),
    },
    extensions: ['.tsx', '.ts', '.js'],
  },

  plugins: plugins('pug'),


};
Graham
  • 7,431
  • 18
  • 59
  • 84
  • Hi [Михаил Журавлёв](https://stackoverflow.com/users/13098907/%d0%9c%d0%b8%d1%85%d0%b0%d0%b8%d0%bb-%d0%96%d1%83%d1%80%d0%b0%d0%b2%d0%bb%d1%91%d0%b2), welcome to _stackOf_. I understand, that you wanted to be as clear to understand as possible. But professionals get idea the moment they look at right code snippet. I would suggest to come straight to point and make question as short/simple as possible. and leave rest of it on some online js editors like JSBIN/JSFiddle – Sumit Ramteke Jun 29 '20 at 13:30

0 Answers0