0

我有一个 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项目的根目录中创建一个带有自己资产文件夹的文件夹。正如您在上面的文件结构中看到的,build 文件夹中的 ltr html 文件具有放置在 build 文件夹中的 assets 文件夹的正确路径,但文件夹中的 rtl 版本fa指的是相同的路径,这是错误的。这 2 个文件基于src/i18n. 另外,两个 html 文件的标题中的所有指向图标图像的链接在文件的构建版本中保持不变,这是另一个问题,但是由 Webpack html 插件完成的其他注入链接都正确地注入了两个 html 文件中的正确路径。

这是我的生产模式的 webpack 配置 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 配置构建项目时,它在构建文件夹中为我提供了 2 个用于 ltr 和 rtl 方向的 html 文件,在 rtl 版本 index.html 中它会为 img 标签生成错误的 src 路径并在这两个文件都不会更改 favicon 链接的路径,并且提到的链接与源 html 文件保持相同,但注入 Webpack html 插件的其他链接都正确地注入了每个 html 文件中的正确路径。

我需要根据文件在文件夹结构中的任何级别使用正确的 img 标签 src 路径生成 2 个 html 文件。

任何帮助将不胜感激。

4

1 回答 1

0

我做了很多研究,发现对这个问题没有任何帮助。因此,我想出了一个想法,即为我的项目的 ltr 和 rtl 输出提供两个单独的生产 webpack 配置文件。因此,我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.prod.rtl.js然后我制作了另一个以我的项目的 rtl 输出命名的 webpack 配置文件,并更改了outputPath我的项目的配置文件,并且我在我的项目中进行了file-loader修改,如下所示:filenameHtmlWebpackPlugin

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 版本,但具有正确的图像 src 路径。

所以,我决定分享解决方案。肯定还有其他解决方案,但这是我现在想出的解决我的问题的方法。

希望这对其他人有帮助。

于 2020-04-09T13:50:54.757 回答