@rifat2125

Как мне настроить Webpack?

Здравствуйте!
Я сейчас занимаюсь тем, что переписываю старый конфиг webpack. Раньше была 4 версия, обновили вебпак до 5, обновили все зависимости и всё сломалось, соответственно)

Проблема заключается сейчас в том, что при сборке вебпак ломается и выходит ошибка в которой сказано что не получается загрузить модуль и показывает ссылку на SVG файл. Он ругается на все sass файлы, в которых есть ссылка на SVG
62bc2533bbf56727754754.png

Код webpack.config.js

const fs = require('fs');
const webpack = require('webpack');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const WebpackAssetsManifest = require('webpack-assets-manifest');
const TerserPlugin = require("terser-webpack-plugin");

// Куда собираем, old или modern
const BROWSER = process.env.BROWSERSLIST_ENV;
const IS_OLD = BROWSER === 'old';
const IS_MODERN = BROWSER === 'modern';

// Тип сборки, dev или prod
const MODE = process.env.NODE_ENV;
const IS_DEV = MODE === 'development' || MODE === 'watch';
const IS_PROD = MODE === 'production';
const IS_WATCH = MODE === 'watch';

// const makeSourceMap = true
// const makeSourceMap = true
const MAKE_SOURCE_MAP = process.env.S_MAPS;
const ANALYZE = process.env.IS_ANALYZE;

// файлы ложатся в корень проекта
const OUTPUT_PATH = IS_WATCH ? './dist' : '../';
const FILENAME = `js/${BROWSER}/${IS_DEV ? '[name]__' : ''}[contenthash].js`;

const getFullPath = filepath => path.resolve(__dirname, filepath);

function getEntryPoints() {
  let res = {
    default: [getFullPath('./src/js/app.js')]
  };
  const styles = getFiles('./src/sass/pages/promo', /\.s(c|a)ss$/);
  const scripts_folders = getFolders('./src/js/pages');

  styles.map((style) => {
    const [name, ext] = style.split('.');
    res[name] = [
      getFullPath('./src/js/app.js'),
      getFullPath(`./src/sass/pages/promo/${style}`)
    ];
  });

  scripts_folders.map((folder_name) => {
    res[folder_name] = [
      getFullPath(`./src/js/pages/${folder_name}/${folder_name}.js`)
    ];
  });

  return res;
}

function getFolders(dir) {
  return fs.readdirSync(path.resolve(__dirname, dir))
    .filter(item => !item.startsWith('.'))
}

function getFiles(dir, ext) {
  return fs.readdirSync(
    path.resolve(__dirname, dir)
  ).filter(
    item => ext.test(item)
  );
}

function getPlugins() {
  const cssFilename = `./css/${IS_DEV ? '[name]__' : ''}[contenthash].css`;

  const plugins = [
    new MiniCssExtractPlugin({
      filename: cssFilename,
      chunkFilename: cssFilename,
    }),

    new webpack.ProvidePlugin({
      '$': 'cash-dom',
    }),

    new webpack.DefinePlugin({
      "isDev": JSON.stringify(IS_DEV),
      "isProd": JSON.stringify(IS_PROD),
      "isOld": JSON.stringify(IS_OLD),
      "isModern": JSON.stringify(IS_MODERN),
    })
  ];

  if (ANALYZE) {
    plugins.push(new BundleAnalyzerPlugin());
  }

  if (!IS_WATCH) {
    plugins.push(
      new WebpackAssetsManifest({
        entrypoints: true,
        publicPath: true,
        output: BROWSER + '--manifest.json',
        entrypointsKey: 'root',
        transform(assets, manifest) {
          return assets['root']
        }
      })
    )
  } else {
    const templateFiles = fs.readdirSync(path.resolve(__dirname, './src/html/pages'))

    templateFiles.filter(file => file.split('.')[1] === 'html').map(html => {
      const [name, extension] = html.split('.');

      const item = new HtmlWebpackPlugin({
        filename: IS_WATCH ? `${name}.html` : `html/${name}.html`,
        title: name,
        chunks: [name],
        entry: `./src/js/pages/${name}.js`,
        template: path.resolve(__dirname, `./src/html/pages/${name}.${extension}`)
      });

      plugins.push(item);
    });
  }
  
  return plugins;
}

function getOptimization() {
  const optimization = {
    splitChunks: {
      chunks: 'async',
      minSize: 20000,
      minRemainingSize: 0,
      minChunks: 1,
      maxAsyncRequests: 30,
      maxInitialRequests: 30,
      enforceSizeThreshold: 50000,
      cacheGroups: {
        defaultVendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
          reuseExistingChunk: true,
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  };

  if (IS_PROD) {
    optimization.minimize = true;
    optimization.minimizer = [new TerserPlugin({
      parallel: true,
      extractComments: false,
      terserOptions: {
        output: {
          comments: false
        },
        compress: {
          drop_console: true,
        },
      }
    })];
  }

  return optimization;
}

function getCacheLoader(isJS = false) {
  const loader = {
    loader: 'cache-loader',
    options: {}
  }

  // эти манипуляции с путями до кеша нужны так как без этого он не различает __TARGET__
  let path = 'node_modules/.cache/cache-loader/'

  if (isJS) {
    path += IS_OLD ? 'oldjs' : 'modernjs'
  }

  loader.options.cacheDirectory = getFullPath(path)

  return loader
}

function getBabelSettings() {
  const settings = {};

  if (IS_OLD) {
    settings.useBuiltIns = "usage"
    settings.corejs = 3
  }

  return settings
}

if (!IS_WATCH && IS_MODERN) {
  if (fs.existsSync('../js')) {
    fs.promises.rmdir('../js', { recursive: true })
  }
  if (fs.existsSync('../css')) {
    fs.promises.rmdir('../css', { recursive: true })
  }
}

const config = {
  mode: MODE,
  node: {
    global: false,
  },
  entry: getEntryPoints(),
  plugins: getPlugins(),
  optimization: getOptimization(),
  output: {
    filename: FILENAME,
    chunkFilename: FILENAME,
    path: getFullPath(OUTPUT_PATH),
    publicPath: '/',
  },
  resolve: {
    extensions: ['.js', '.sass', '.scss'],
    alias: {
      '@': getFullPath('src'),
      '@js': getFullPath('src/js'),
      '@css': getFullPath('src/sass'),
      '@css-pages': getFullPath('src/sass/pages'),

      '@libs': getFullPath('src/js/libs'),
      '@parts': getFullPath('src/js/parts/'),
      '@other': getFullPath('src/js/other'),
      '@pages': getFullPath('src/js/pages'),
      '@components': getFullPath('src/js/components'),
    }
  },
  module: {
    rules: [
      {
        test: /\.s(c|a)ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'sass-loader'
        ]
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          // getCacheLoader(true),
          {
            loader: 'babel-loader',
            options: {
              presets: [
                [
                  '@babel/preset-env',
                  getBabelSettings()
                ]
              ],
              plugins: [
                '@babel/plugin-proposal-optional-chaining',
                '@babel/plugin-proposal-class-properties',
              ]
            }
          },
          ...IS_DEV ? ['eslint-loader'] : [],
        ]
      },
      {
        test: /\.(woff|ttf|otf|eot|woff2|svg)$/i,
        type: 'asset/resource',
      }
    ]
  }
};

if (IS_WATCH) {
  config.watchOptions = {
    ignored: /node_modules/
  }

  config.devServer = {
    port: 7777,
    writeToDisk: true,
    watchContentBase: true,
    contentBase: '../'
  }
}

module.exports = config;



P.S. прошу не плеваться ядом. Код изначальный писал не я, но мне сказали его переписать. Опыта с настройке в Вебпак у меня не много, поэтому я решил спросить у Вас.
  • Вопрос задан
  • 75 просмотров
Решения вопроса 1
@rifat2125 Автор вопроса
Задачу удалось решить следующим образом. По дефолту css-loader подхватывает все url() внутри файла стилей. Я указал в параметрах url: false, что говорит css-loader не трогать файлы указанные через url()

rules: [
      {
        test: /\.s(c|a)ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          //'css-loader',       -было так
         {
            loader: 'css-loader',
            options: {
              url: false,
            }
          },
          'sass-loader'
        ]
      },
]
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы