Assign the correct output image path to multiple pages in Webpack 4?

Hi guys. I’m having a lot of trouble with webpack, trying to fix my issue for the last 48H without success… I hope some of you can help me with this!

So have started working on a website using Webpack 4. I thought i’d work fine but i have an issue : everything in my index.html file displays correctly, but fonts and images are not loaded in my subpages. I assume my subpage images don’t point to the correct path. But i can’t figure out how to make this happen!

Some help would be very much appreciated!

Here is my folder structure :

|- build/ (my config files)
|- dist/
|- src/
  |- assets/
  |- components/
  |- fonts/
  |- pages/
    |- index.html
    |- index.js
    |- subpage/
      |- index.html
      |- index.js
  |- scss
  app.js

Here is my webpack.config.base.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { getEntries } = require('./utils.js');
const ThreeWebpackPlugin = require('@wildpeaks/three-webpack-plugin');

const entries = getEntries('./src/pages/', 'js');

const config = {
  entry: Object.assign(entries, { app: './src/app.js' }),
  output: {
    pathinfo: false,
    path: path.resolve(__dirname, '../dist'),
    filename: 'js/[name].[hash:8].js',
    chunkFilename: 'js/[name].chunk.[chunkhash:8].js',
  },
  resolve: {
    alias: {
      src: path.resolve(__dirname, '../src'),
    },
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: ['babel-loader'],
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: 'html-loader',
            options: {
              minimize: true,
            },
          },
        ],
      },
      {
        test: /\.(png|jpg|gif)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10000,
              name: 'assets/[name].[md5:hash:hex:8].[ext]',
            },
          },
        ],
      },
      {
        test: /\.(woff|woff2|otf|ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10000,
              name: 'fonts/[name].[md5:hash:hex:8].[ext]',
            },
          },
        ],
      },
      {
        test: /\.(mp4|ogg|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: 'assets/[name].[md5:hash:hex:8].[ext]',
            },
          },
        ],
      },
    ],
  },
  parallelism: 8,
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        commons: {
          name: 'commons',
          chunks: 'initial',
          minChunks: 2,
        },
        vendors: {
          chunks: 'initial',
          name: 'vendors',
          test: /node_modules\//,
          minChunks: 5,
          priority: 10,
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },
  plugins: [new ThreeWebpackPlugin()],
};

const pages = getEntries('./src/pages/', 'html');

for (const pathname in pages) {
  // Configured to generate the html file, define paths, etc.
  const conf = {
    filename: `${pathname}.html`, // html output pathname
    template: path.resolve(__dirname, `.${pages[pathname]}`), // Template path
    inject: true,
    favicon: path.resolve(__dirname, '../src/assets/favicon.ico'),
    chunks: ['commons', 'vendors', 'app', pathname],
    chunksSortMode: 'manual',
  };
  config.plugins.push(new HtmlWebpackPlugin(conf));
}

module.exports = config;

Here is my webpack.config.dev.js

const path = require('path');
const webpackMerge = require('webpack-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const portfinder = require('portfinder');
const webpackConfigBase = require('./webpack.config.base.js');

const webpackConfigDev = webpackMerge(webpackConfigBase, {
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          'style-loader',
          { loader: 'css-loader', options: { importLoaders: 1 } },
          'postcss-loader',
          'sass-loader',
        ],
      },
    ],
  },
  devServer: {
    contentBase: path.resolve(__dirname, '../dist'),
    port: 8080,
    watchOptions: {
      poll: 1000,
    },
    stats: {
      children: false,
    },
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css',
    }),
  ],
});

module.exports = new Promise((resolve, reject) => {
  portfinder.basePort = 8080;
  portfinder.getPort((err, port) => {
    if (err) {
      reject(err);
    } else {
      webpackConfigDev.devServer.port = port;
      resolve(webpackConfigDev);
    }
  });
});

And here is my webpack.config.prod.js

const path = require('path');
const webpackMerge = require('webpack-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const webpackConfigBase = require('./webpack.config.base.js');

module.exports = webpackMerge(webpackConfigBase, {
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          { loader: 'css-loader', options: { importLoaders: 1 } },
          'postcss-loader',
          'sass-loader',
        ],
      },
    ],
  },
  optimization: {
    minimizer: [new OptimizeCSSAssetsPlugin({})],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[hash:8].css',
      chunkFilename: '[id].[hash:8].css',
    }),
    new CleanWebpackPlugin(['dist'], { root: path.resolve(__dirname, '../') }),
  ],
});

Here is the utils.js file used

const glob = require('glob');

exports.getEntries = function (context, extension) {
  if (context[context.length - 1] !== '/') {
    context += '/';
  }

  extension = `.${extension}`;

  const files = glob.sync(`${context}**/*${extension}`);
  const entries = {};

  files.forEach((file) => {
    entries[file.replace(context, '').replace(extension, '')] = file;
  });

  return entries;
};

I thought i solved the issue when adding a publicPath: '/' in my webpack base config file output and running npm run start, but then when i run npm run build , everything’s broken (all links : images, css, etc.).

Thanks!

Up?..

Well what paths do they point to?

PS: That is a lot of config you posted here BTW… could you put together just a minimal setup to reproduce the issue?