Обновление Webpack с помощью npm и Angular

Вопросы и ответы

Я обновляю устаревшее приложение на node/angular (10 лет назад!) и смог скомпилировать всё без сообщений об ошибках и т.д. Я использую папку index.html в корне сервера, чтобы начать приложение, с помощью следующего кода:

<body>
  <tc-app>Загрузка...</tc-app>
</body>

это часть кода Angular. Это вызывает модуль app.component с селектором ‘tc-app’. Это, в свою очередь, загружает шаблон из файла “app.html”, который также вызывает другие модули компонентов, каждый с собственными шаблонами, и так далее.

В устаревшем приложении, использующем Webpack 1.15.0, webpack генерирует три файла для папки /dist: app.bundle.js, app.css, vendor.bundle.js. Новое приложение, использующее Webpack 5.94.0, с удовольствием генерирует app.bundle.js. Однако оно НЕ генерирует app.css. Это ожидаемо: устаревшее приложение использует ExtractTextPlugin, который теперь устарел. Однако мои попытки выяснить, как использовать MiniCssExtractPlugin для генерации файла app.css в /dist, пока что не увенчались успехом. Включение строки

new MiniCssExtractPlugin("app.css"),

в секцию правил webpack.config.js вызывает ошибку. Пропуск параметра, т.е. new MiniCssExtractPlugin(), позволяет webpack завершить работу, но ничего не генерирует в /dist.

Вторая проблема заключается в создании правильного бандла для всех компонентов angular, который создаётся в vendor.bundle.js устаревшим приложением. Я могу сгенерировать vendor.bundle.js в новом файле с помощью этого кода:

  entry: {
    app: path.join(clientRoot, 'app/boot.js'),
    vendor: path.join(clientRoot, 'app/app.component.js'),
  },
  output: {
    path: path.join(clientRoot, 'dist'),
    filename: '[name].bundle.js',
    devtoolModuleFilenameTemplate(info) {
     return 'file:///${info.absoluteResourcePath.replace(/\\/g, "https://stackoverflow.com/")}';
   },
  },

Тем не менее, загрузка файла vendor.bundle.js, похоже, завершается неудачей. В устаревшем приложении тег <script> запускает код в vendor.bundle.js и заставляет браузер загрузить файл шаблона app.html, и всё продолжается оттуда. В новом приложении тег <script> не вызывает app.component.js, как должно, и app.html не загружается. Это несмотря на то, что app.component.js действительно собран в новом файле vendor.bundle.js.

В устаревшем файле vendor.bundle.js был сгенерирован этот код в массиве плагинов:

   new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor', filename: 'vendor.bundle.js',
      chunks: ['app'],
      minChunks: function(module, count) {
        return module.resource && module.resource.indexOf(clientRoot) === -1;
      }

Тем не менее, в новом приложении этот код возвращает ошибки:

 at Module._compile (node:internal/modules/cjs/loader:1469:14)
 at Module._extensions..js (node:internal/modules/cjs/loader:1548:10)
 at Module.load (node:internal/modules/cjs/loader:1288:32)
 at Module._load (node:internal/modules/cjs/loader:1104:12)
 TypeError: webpack.optimize.CommonsChunkPlugin is not a constructor
    at Object.<anonymous (/Users/pmr906_1/venv/TCangular/tc/public/webpack.js:125:5)

Вот мой текущий webpack.config.js:

var _ = require('lodash')
  , webpack = require('webpack')
  , ResolverPlugin = webpack.ResolverPlugin
  , ProvidePlugin = webpack.ProvidePlugin
  , IgnorePlugin = webpack.IgnorePlugin
//  , ExtractTextPlugin = require("extract-text-webpack-plugin")
  , path = require('path')
  , clientRoot = path.resolve(__dirname)
  , bowerRoot = path.resolve(clientRoot, '..', 'bower_components')
  , nodeRoot = path.resolve(clientRoot, '..', 'node_modules')
  , devtool="eval-source-map"
  , debug = true
  , MiniCssExtractPlugin = require("mini-css-extract-plugin")
;

switch (process.env.NODE_ENV) {
  case 'production':
    devtool="#source-map";
    debug = false;
    break;
  case 'development':
    devtool="eval-source-map";
    debug = true;
    break;
}

var config = {
  context: clientRoot,
  mode: "development",
  entry: {
    app: path.join(clientRoot, 'app/boot.js'),
    vendor: path.join(clientRoot, 'app/app.component.js'),
  },
  output: {
    path: path.join(clientRoot, 'dist'),
    filename: '[name].bundle.js',
    devtoolModuleFilenameTemplate(info) {
     return 'file:///${info.absoluteResourcePath.replace(/\\/g, "https://stackoverflow.com/")}';
   },
  },
  externals: {
    jquery: 'jQuery',
    rxjs: 'Rx',
    lodash: '_',
    bson: 'bson',
    'codemirror/lib/codemirror': 'CodeMirror',
    'codemirror/mode/xml/xml': false,
  },
  module: {
    rules: [
      {
        test: /\.png(\?v=\d+\.\d+\.\d+)?$/,
        use: "url?limit=1000&minetype=image/jpg&prefix=dist/"
      }, {
        test: /\.jpg(\?v=\d+\.\d+\.\d+)?$/,
        use: "url?limit=1000&minetype=image/jpg&prefix=dist/"
      }, {
        test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
        use: "url?limit=1000&minetype=application/font-woff&prefix=dist/"
      }, {
        test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
        use: "url?limit=1000&minetype=application/font-woff&prefix=dist/"
      }, {
        test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
        use: "url?limit=1000&minetype=application/octet-stream&prefix=dist/"
      }, {
        test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
        use: "url?limit=1000&minetype=application/vnd.ms-fontobject&prefix=dist/"
      }, {
        test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
        use: "url?limit=1000&minetype=image/svg+xml&prefix=dist/"
      },
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
      {
        test: /\.less$/,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "less-loader",
            options: {
              lessOptions: {
    //          javascriptEnabled: true,
              },
            }, 
          },
        ],
      },
    ], /*,
    noParse: [
    ] */
  },
  resolve: {
 /*   root: [clientRoot], */
    modules: [clientRoot, 'web_modules', 'node_modules', 'bower_components', ],
    fallback: {
        "fs": false,
        "tls": false,
        "net": false,
        "path": false,
        "zlib": false,
        "http": false,
        "https": false,
        "stream": false,
        "crypto": false,
        "crypto-browserify": false, //если вы хотите использовать этот модуль, не забудьте также установить npm i crypto-browserify 
      },
    alias: {
      bower: bowerRoot,
      node: nodeRoot,
    },
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor', filename: 'vendor.bundle.js',
      chunks: ['app'],
      minChunks: function(module, count) {
        return module.resource && module.resource.indexOf(clientRoot) === -1;
      }
      }), 
     new MiniCssExtractPlugin(), 
  ],
  devtool: devtool,
};

var compiler = webpack(config);

if (process.env.NODE_ENV === 'development') {
  compiler.watch({
    aggregateTimeout: 300,
    poll: 1000,
  }, handleError);
} else {
 compiler.watch({
    aggregateTimeout: 300,
    poll: 1000,
  }, handleError);
  //compiler.run(handleError);
}

Помогите..

Ответ

Для успешного обновления вашего приложения Angular с Webpack 1.15.0 до Webpack 5.94.0, разберем два основных вопроса, с которыми вы столкнулись:

  1. Генерация файла app.css с помощью MiniCssExtractPlugin:
  2. Правильная сборка и загрузка vendor.bundle.js:

1. Генерация файла app.css с помощью MiniCssExtractPlugin

Чтобы использовать MiniCssExtractPlugin правильно и генерировать файл app.css, вам нужно внести некоторые изменения в ваш файл webpack.config.js.

Вот как это можно сделать:

  1. Убедитесь, что вы правильно импортировали MiniCssExtractPlugin в вашем коде:

    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
  2. Измените конфигурацию плагина в массиве plugins. Убедитесь, что вы правильно передаете файл, который будет генерироваться:
    plugins: [
     new MiniCssExtractPlugin({
       filename: 'app.css', // Укажите имя выходного CSS файла
     }),
    ],

Теперь, когда ваш webpack будет собирать проект, он должен создать файл app.css в каталоге /dist.

  1. Проверьте, добавлен ли MiniCssExtractPlugin.loader в правила для .css файлов:
    {
     test: /\.css$/i,
     use: [MiniCssExtractPlugin.loader, "css-loader"],
    },

2. Правильная сборка и загрузка vendor.bundle.js

Проблема с vendor.bundle.js может быть связана с устаревшим представлением о том, как обрабатывать зависимости в Webpack 5.

  1. Устаревший CommonsChunkPlugin:
    Вместо CommonsChunkPlugin в Webpack 5 вы должны использовать оптимизацию с помощью SplitChunksPlugin, который включен по умолчанию. Вот как вы можете адаптировать это:

    optimization: {
     splitChunks: {
       cacheGroups: {
         vendor: {
           test: /[\\/]node_modules[\\/]/, // или укажите путь к вашему компоненту
           name: 'vendor',
           chunks: 'all',
         },
       },
     },
    },
  2. Обновление входных точек:
    Ваши входные точки должны оставаться чем-то вроде этого:

    entry: {
     app: path.join(clientRoot, 'app/boot.js'),
     // Уберите vendor entry, так как он будет теперь автоматически подбираться
    },
  3. Проверка на загрузку:
    Убедитесь, что вы загружаете vendor.bundle.js в вашем index.html. Это можно сделать следующим образом:

    <script src="vendor.bundle.js"></script>
    <script src="app.bundle.js"></script>

Полный обновленный webpack.config.js

Вот полный пример вашего файла webpack.config.js, с учетом предложенных изменений:

const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

const clientRoot = path.resolve(__dirname);

module.exports = {
  context: clientRoot,
  mode: "development",
  entry: {
    app: path.join(clientRoot, 'app/boot.js'),
  },
  output: {
    path: path.join(clientRoot, 'dist'),
    filename: '[name].bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
      // другие правила здесь...
    ],
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendor',
          chunks: 'all',
        },
      },
    },
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'app.css',
    }),
  ],
};

Заключение

С учетом этих изменений, теперь ваш проект должен корректно генерировать app.css и правильно обрабатывать зависимости, чтобы vendor.bundle.js загружался с необходимыми компонентами.

Если возникнут новые ошибки при сборке или загрузке, пожалуйста, проверьте консоль браузера на наличие ошибок и ошибки компиляции в терминале. Это поможет вам диагностировать, в чем может быть еще проблема. Удачи с вашим обновлением!

Оцените материал
Добавить комментарий

Капча загружается...