Webpack 4 генерирует неверный путь sr c для тегов img на разных уровнях структуры папок - PullRequest
0 голосов
/ 08 апреля 2020

У меня есть проект Webpack 4 для создания многоязычной панели администратора с этой папкой и структурой файлов:

admin-dashboard
|
|--build
|  |--assets
|  |  |--img
|  |  |--font
|  |--fa
|  |  |--index.html ----> rtl html output (gets wrong img src like "assets/img/img.png")
|  |--index.html    ----> ltr html output (gets right img src like "assets/img/img.png")
|  |--style.css
|  |--style-rtl.css
|  |--script.js
|  |--script-rtl.js
|
|--config   ---> containing my Webpack config files for production and development
|  |--webpack.dev.js
|  |--webpack.prod.js
|
|--node_modules
|--src
|  |--assets
|  |  |--img
|  |  |--font
|  |
|  |--i18n
|  |  |--fa
|  |  |  |--index.html ----> rtl html template ---> <img src="../../assets/img/img.png" />
|  |  |--index.html    ----> ltr html template ---> <img src="../assets/img/img.png" />
|  |
|  |--js
|  |--locales
|  |--scss
|  |--templates
|
|--.babelrc
|--package.json
|--postcss.config.js

Пути к изображениям в папке i18n в моей папке src правильные при разработке проекта, но когда я собираю проект, он создает папку build в root проекта со своей собственной папкой ресурсов. Как вы можете видеть в структуре файла выше, файл ltr html в папке сборки имеет правильный путь к папке ресурсов, помещенной в папку сборки, но версия rtl в папке fa ссылается на тот же путь, который является неправильным. Эти 2 файла создаются на основе 2 html файлов в src/i18n. Кроме того, все ссылки на изображения favicon в заголовке обоих файлов html остаются неизменными во встроенной версии файлов, что является еще одной проблемой, но другие вставленные ссылки, выполняемые плагином Webpack html, корректно вводятся с правильными путями в обоих html файлах.

Это моя конфигурация веб-пакета для производственного режима: webpack.prod.js:

const webpack = require('webpack');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = {
  entry: {
    main: './src/js/main.js',
    'main-rtl': './src/js/main-rtl.js',
  },
  output: {
    path: path.join(__dirname, '../build'),
    filename: '[name].[chunkhash:8].bundle.js',
    chunkFilename: '[name].[chunkhash:8].chunk.js',
  },
  mode: 'production',
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader', 
        },
      },
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader', 
          'postcss-loader', 
          'sass-loader',
        ],
      },
      {
        test: /\.(png|svg|jpe?g|gif)$/i,
        use: [
          {
            loader: 'file-loader', 
            options: {
              name: '[name].[ext]',
              outputPath: 'assets/img',
              esModule: false,
            },
          },
        ],
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
          {
            loader: 'file-loader', 
            options: {
              name: '[name].[ext]',
              outputPath: 'assets/font',
            },
          },
        ],
      },
      {
        test: /\.html$/i,
        use: {
          loader: 'html-loader',
          options: {
            attributes: {
              list: [
                {
                  tag: 'img',
                  attribute: 'src',
                  type: 'src',
                },
                {
                  tag: 'img',
                  attribute: 'srcset',
                  type: 'srcset',
                },
                {
                  tag: 'img',
                  attribute: 'data-src',
                  type: 'src',
                },
                {
                  tag: 'img',
                  attribute: 'data-srcset',
                  type: 'srcset',
                },
              ],

            },
          },
        },
      },
    ],
  },
  optimization: {
    minimizer: [new TerserJSPlugin(), new OptimizeCSSAssetsPlugin()],
    splitChunks: {
      cacheGroups: {
        commons: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
      chunks: 'all',
    },
    runtimeChunk: {
      name: 'runtime',
    },
  },
  plugins: [
    // load jQuery
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
    }),

    new CleanWebpackPlugin(),

    new MiniCssExtractPlugin({
      filename: '[name].[chunkhash:8].bundle.css',
      chunkFilename: '[name].[chunkhash:8].chunk.css',
    }),

    new HtmlWebpackPlugin({
      chunks: ['main'],
      template: 'src/i18n/index.html',
      filename: 'index.html',
    }),
    new HtmlWebpackPlugin({
      chunks: ['main-rtl'],
      template: 'src/i18n/fa/index.html',
      filename: 'fa/index.html',
    }),

  ],
};

Итак, проблема в том, что когда я собираю проект с моим webpack.prod. js config, он дает мне 2 html файлов в папке сборки для ltr и rtl направлений, которые в индексе версии rtl. html генерирует неверный путь sr c для тегов img, и в обоих файлах не изменяет пути ссылок favicon и упомянутые ссылки остаются такими же, как исходные файлы html, но все другие ссылки, которые вставляются с помощью плагина Webpack html, корректно вводятся с правильными путями в каждом файле html.

Мне нужно 2 html файлы генерируются с правильными путями тега img sr c на основе любого уровня, в котором находится файл в структуре папок.

любая помощь будет так высоко ценится.

1 Ответ

0 голосов
/ 09 апреля 2020

Я провел много исследований, не нашел ничего полезного для этой проблемы. Итак, у меня возникла идея создать два отдельных файла конфигурации webpack для моих выводов ltr и rtl моего проекта. Поэтому я изменил свой webpack.prod.js файл следующим образом:

const webpack = require('webpack');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = {
  entry: {
    main: './src/js/main.js' // ---> the only entry we have is main
  },
  output: {
    path: path.join(__dirname, '../build'), 
    filename: '[name].[chunkhash:8].bundle.js',
    chunkFilename: '[name].[chunkhash:8].chunk.js',
  },
  mode: 'production',
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader', 
        },
      },
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader', 
          'postcss-loader', 
          'sass-loader',
        ],
      },
      {
        test: /\.(png|svg|jpe?g|gif)$/i,
        use: [
          {
            loader: 'file-loader', 
            options: {
              name: '[name].[ext]',
              outputPath: 'assets/img',
              esModule: false,
            },
          },
        ],
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
          {
            loader: 'file-loader', 
            options: {
              name: '[name].[ext]',
              outputPath: 'assets/font',
            },
          },
        ],
      },
      {
        test: /\.html$/i,
        use: {
          loader: 'html-loader',
          options: {
            attributes: {
              list: [
                {
                  tag: 'img',
                  attribute: 'src',
                  type: 'src',
                },
                {
                  tag: 'img',
                  attribute: 'srcset',
                  type: 'srcset',
                },
                {
                  tag: 'img',
                  attribute: 'data-src',
                  type: 'src',
                },
                {
                  tag: 'img',
                  attribute: 'data-srcset',
                  type: 'srcset',
                },
              ],

            },
          },
        },
      },
    ],
  },
  optimization: {
    minimizer: [new TerserJSPlugin(), new OptimizeCSSAssetsPlugin()],
    splitChunks: {
      cacheGroups: {
        commons: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
      chunks: 'all',
    },
    runtimeChunk: {
      name: 'runtime',
    },
  },
  plugins: [
    // load jQuery
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
    }),

    new CleanWebpackPlugin(),

    new MiniCssExtractPlugin({
      filename: '[name].[chunkhash:8].bundle.css',
      chunkFilename: '[name].[chunkhash:8].chunk.css',
    }),

    new HtmlWebpackPlugin({
      chunks: ['main'],
      template: 'src/i18n/index.html',
      filename: 'index.html',
    }),
    // new HtmlWebpackPlugin({
      // chunks: ['main-rtl'],
      // template: 'src/i18n/fa/index.html',    ----> this part removed too
      // filename: 'fa/index.html',
    // }),

  ],
};

Затем я создал другой файл конфигурации webpack с именем webpack.prod.rtl.js для вывода rtl моего проекта и изменил outputPath моего проекта file-loader а также я изменил filename в своем HtmlWebpackPlugin, как вы можете видеть ниже:

const webpack = require('webpack');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = {
  entry: {
    'main-rtl': './src/js/main-rtl.js', // main-rtl instead of main
  },
  output: {
    path: path.join(__dirname, '../build/fa'),
    filename: '[name].[chunkhash:8].bundle.js',
    chunkFilename: '[name].[chunkhash:8].chunk.js',
  },
  mode: 'production',
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader', 
        },
      },
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader', 
          'postcss-loader', 
          'sass-loader',
        ],
      },
      {
        test: /\.(png|svg|jpe?g|gif)$/i,
        use: [
          {
            loader: 'file-loader', 
            options: {
              name: '[name].[ext]',
              outputPath: '../assets/img',
              esModule: false,
            },
          },
        ],
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
          {
            loader: 'file-loader', 
            options: {
              name: '[name].[ext]',
              outputPath: '../assets/font',
            },
          },
        ],
      },
      {
        test: /\.html$/i,
        use: {
          loader: 'html-loader',
          options: {
            attributes: {
              list: [
                {
                  tag: 'img',
                  attribute: 'src',
                  type: 'src',
                },
                {
                  tag: 'img',
                  attribute: 'srcset',
                  type: 'srcset',
                },
                {
                  tag: 'img',
                  attribute: 'data-src',
                  type: 'src',
                },
                {
                  tag: 'img',
                  attribute: 'data-srcset',
                  type: 'srcset',
                },
              ],

            },
          },
        },
      },
    ],
  },
  optimization: {
    minimizer: [new TerserJSPlugin(), new OptimizeCSSAssetsPlugin()],
    splitChunks: {
      cacheGroups: {
        commons: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
      chunks: 'all',
    },
    runtimeChunk: {
      name: 'runtime',
    },
  },
  plugins: [
    // load jQuery
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
    }),

    new CleanWebpackPlugin(),

    new MiniCssExtractPlugin({
      filename: '[name].[chunkhash:8].bundle.css',
      chunkFilename: '[name].[chunkhash:8].chunk.css',
    }),

    new HtmlWebpackPlugin({
      chunks: ['main-rtl'],
      template: 'src/i18n/fa/index.html',
      filename: 'index.html',  // ---> changed from fa/index.html to index.html
    }),

  ],
};

Плюс, у меня установлен пакет npm с именем npm-run-all для запуска некоторых команд npm cli в параллельно. Таким образом, когда мне нужны версии ltr и rtl моего проекта одновременно, я могу собрать их обе с помощью этих команд в script section моего package.json файла:

"scripts": {
    // other scripts,
    "build-ltr": "webpack --config=config/webpack.prod.js",
    "build-rtl": "webpack --config=config/webpack.prod.rtl.js",
    "build": "npm-run-all --parallel build-ltr build-rtl"
  },

Например, после запуска npm run build он дает мне и ltr, и rtl версии моего проекта в предыдущей структуре папок, о которой я упоминал в этом вопросе, но с правильными путями sr c изображения.

Итак, я решил поделиться решением. Определенно, есть и другие решения, но это то, что я придумал, чтобы решить свою проблему на данный момент.

Надеюсь, это будет полезно для других.

...