Я обновляю устаревшее приложение на 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, разберем два основных вопроса, с которыми вы столкнулись:
- Генерация файла
app.css
с помощьюMiniCssExtractPlugin
: - Правильная сборка и загрузка
vendor.bundle.js
:
1. Генерация файла app.css
с помощью MiniCssExtractPlugin
Чтобы использовать MiniCssExtractPlugin
правильно и генерировать файл app.css
, вам нужно внести некоторые изменения в ваш файл webpack.config.js
.
Вот как это можно сделать:
-
Убедитесь, что вы правильно импортировали
MiniCssExtractPlugin
в вашем коде:const MiniCssExtractPlugin = require("mini-css-extract-plugin");
- Измените конфигурацию плагина в массиве
plugins
. Убедитесь, что вы правильно передаете файл, который будет генерироваться:plugins: [ new MiniCssExtractPlugin({ filename: 'app.css', // Укажите имя выходного CSS файла }), ],
Теперь, когда ваш webpack
будет собирать проект, он должен создать файл app.css
в каталоге /dist
.
- Проверьте, добавлен ли
MiniCssExtractPlugin.loader
в правила для.css
файлов:{ test: /\.css$/i, use: [MiniCssExtractPlugin.loader, "css-loader"], },
2. Правильная сборка и загрузка vendor.bundle.js
Проблема с vendor.bundle.js
может быть связана с устаревшим представлением о том, как обрабатывать зависимости в Webpack 5.
-
Устаревший
CommonsChunkPlugin
:
ВместоCommonsChunkPlugin
в Webpack 5 вы должны использовать оптимизацию с помощьюSplitChunksPlugin
, который включен по умолчанию. Вот как вы можете адаптировать это:optimization: { splitChunks: { cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, // или укажите путь к вашему компоненту name: 'vendor', chunks: 'all', }, }, }, },
-
Обновление входных точек:
Ваши входные точки должны оставаться чем-то вроде этого:entry: { app: path.join(clientRoot, 'app/boot.js'), // Уберите vendor entry, так как он будет теперь автоматически подбираться },
- Проверка на загрузку:
Убедитесь, что вы загружаете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
загружался с необходимыми компонентами.
Если возникнут новые ошибки при сборке или загрузке, пожалуйста, проверьте консоль браузера на наличие ошибок и ошибки компиляции в терминале. Это поможет вам диагностировать, в чем может быть еще проблема. Удачи с вашим обновлением!