Автор: Лю Хуа
предисловие
Благодаря постоянному развитию интерфейсных инструментов архитектуры он предоставляет множество возможностей для улучшения нашего опыта разработки и повышения эффективности разработки, в то время как построение стало распространенной технологией в стеке интерфейсных технологий.
Webpack также является многообещающим членом многих инструментов сборки. Ранняя конфигурация веб-пакета сложна и сложна для понимания. По мере его разработки связанные конфигурации также постоянно упрощаются, а производительность постоянно повышается. Однако для разработчиков, которые используют его в глубина, его конфигурация по умолчанию обычно неприменима.Для развития бизнеса вам необходимо приспособиться и адаптироваться к вашему собственному бизнесу.
Как много вы знаете о веб-пакете? Как лучше настроить бизнес-интеграцию? Как оптимизировать процесс разработки? Как получить полную мощность и добиться молниеносной производительности сборки веб-пакета 🚀? Какие еще ямы будут 💣? Эта статья поможет вам ответить на эти вопросы 🔭.
Полный код всех фрагментов кода, задействованных в этой статье, см.склад а8к
1. Ключевые элементы конфигурации веб-пакета
Если вы что-то знаете о строительстве, вы можете сразу пропустить этот раздел.
Соответствующая конфигурация не будет здесь подробно описываться.Для получения более подробного описания и настройки обратитесь к официальной документации и кратко ознакомьтесь с ключевыми элементами конфигурации, чтобы проложить путь к следующему контенту.
entry
webpack ищет зависимые конфигурации файлов записей. Файлов записей может быть несколько.
Конфигурация записи одностраничного приложенияСтандартная конфигурация: сторонняя библиотека зависимостей vendor.js, библиотека заполнения функций polyfill.js, одностраничный файл ввода приложения index.js.
// 导出配置
module.exports = {
entry: {
vendor: './src/vendor.js',
polyfill: './src/polyfill.js',
index: './src/index.js',
},
};
Конфигурация входа в многостраничное приложениеПодобно одностраничному приложению, но разные страницы имеют разные входные файлы, в этом случае эффективным способом является не запись его напрямую в запись, а сканирование указанной директории для определения входного файла каждой страницы при создании веб-пакета. .config и все страницы.
Вот пример
Предположим, что ваши страницы размещены в каталоге src/pages, и каждая из ваших страниц имеет отдельный каталог с index.html и index.jsx в нем.
const path = require('path');
const fs = require('fs');
// 处理公共entry
const commonEntry = ['./src/vendor.js', './src/polyfill.js'];
// 页面目录
const PAGES_DIR = './src/pages/';
const entry = {};
// 遍历页面目录
const getPages = () => {
return fs.readdirSync(PAGES_DIR).filter(item => {
let filepath = path.join(PAGES_DIR, item, 'index.js');
if (!fs.existsSync(filepath)) {
filepath = `${filepath}x`; // jsx
}
if (!fs.existsSync(filepath)) {
return false;
}
return true;
});
};
getPages(options).forEach(file => {
const name = path.basename(file);
// 加入页面需要的公共入口
entry[name] = [...commonEntry, `${PAGES_DIR}/${file}/index`];
});
// 导出配置
module.exports = {
entry,
};
Как вставить границу записи в соответствующий html?
Обычно нам нужен этот плагинHtmlWebpackPlugin
Автоматическая обработка, конкретный код выглядит следующим образом:
const plugins = [];
if (mode === 'single') {
// 单页面只需要一次HtmlWebpackPlugin
plugins.push(
new HtmlWebpackPlugin({
minify: false,
filename: 'index.html',
template: './src/index.html',
})
);
}
if (mode === 'multi') {
// 多页面遍历目录,使用目录下面的html文件
// 不同页面的配置不同,每个页面都单独配置一个html
// 所有页面的公共部分可以抽离后,通过模版引擎编译处理
// 具体的方式后面部分loader中提到
const files = getPages(options);
files.forEach(file => {
const name = path.basename(file);
file = `${PAGES_DIR}/${file}/index.html`;
// 添加runtime脚本,和页面入口脚本
const chunks = [`runtime~${name}`, name];
plugins.push(
new HtmlWebpackPlugin({
minify: false,
filename: `${name}.html`,
template: file,
chunks,
})
);
});
}
// 导出配置
module.exports = {
plugins,
};
output
Соответствующая информация о пакете, выводимом этой конфигурацией, наиболее часто используемые конфигурации следующие:
{
output:{
// name是你配置的entry中key名称,或者优化后chunk的名称
// hash是表示bundle文件名添加文件内容hash值,以便于实现浏览器持久化缓存支持
filename: '[name].[hash].js',
// 在script标签上添加crossOrigin,以便于支持跨域脚本的错误堆栈捕获
crossOriginLoading:'anonymous',
//静态资源路径,指的是输出到html中的资源路径前缀
publicPath:'https://7.ur.cn/fudao/pc/',
path: './dist/',//文件输出路径
}
}
resolve
Эта конфигурация в основном используется для разрешения пользовательских элементов, от которых зависит модуль.Более традиционные элементы конфигурации следующие: модули используются для повышения эффективности поиска по абсолютному пути, и пользователи могут использовать псевдоним для определения поиска модуля. дорожка.
resolve: {
modules: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname,'node_modules'),
],
alias: {
components: path.resolve(__dirname, '/src/components'),
},
}
расширятьЕсли вы используете абсолютный путь, вы можете обнаружить, что интеллектуальная навигация по коду vscode недействительна, не паникуйте! Пожалуйста, настройте в нужном каталогеjsconfig.json
Файл решает эту проблему, и конфигурация соответствует приведенной выше:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"src/*": ["./src/*"],
"components/*": ["./src/components/*"],
"assets/*": ["./src/assets/*"],
"pages/*": ["./src/pages/*"]
}
},
"include": ["./src/**/*"]
}
Таким образом, вы можете с удовольствием использовать интеллектуальные подсказки по коду и навигацию vscode!
module
Основная конфигурация этого элемента — правила.Процессоры, настроенные для разных ресурсов в правилах, являются одним из его ядер.Вот простой пример кода.
module: {
// 这些库都是不依赖其它库的库 不需要解析他们可以加快编译速度
// 通常可以将那些大型的库且已经编译好的库排除,减少webpack对其解析耗时
noParse: /node_modules\/(moment|chart\.js)/,
rules: [
{
test: /\.jsx?$/,
use: resolve('babel-loader'),
// 需要被这个loader处理的资源
include: [
path.resolve(projectDir, 'src'),
path.resolve(projectDir, 'node_modules/@tencent'),
].filter(Boolean),
// 忽略哪些压缩的文件
exclude: [/(.|_)min\.js$/],
}
]
optimization
Самыми важными и наиболее часто используемыми аксессуарами являются:splitChunks
,minimizer
minimizer
Вы можете настроить плагин сжатия выходного файла самостоятельно.Для сжатия js мы можем использовать uglifyjs, интегрированный в webpack, или Terser.Terser поддерживает сжатие кода es6 и поддерживает многопроцессное сжатие;сжатие css мы можем использоватьoptimize-css-assets-webpack-plugin
Сжатие, использующее cssnano в качестве механизма обработки, помогает нам удалять повторяющиеся стили.
splitChunks
Это основная функция, запущенная webpack4.x, оптимизированная стратегия извлечения общедоступных блоков и более эффективное извлечение общедоступных модулей.Его использование будет подробно объяснено в разделе оптимизации производительности позже.
plugin
Плагин может вмешаться на любом этапе всего процесса сборки. Например: отчет о времени сборки, изменение выходного кода для поддержки повторной попытки основного домена, добавление отчета о ходе сборки, сжатие кода, замена ресурсов и многие другие возможности реализованы здесь.
Плагины не обсуждаются, потому что плагинов слишком много. Для проектов, которым необходимо реализовать собственные плагины, следует учесть, что при использовании плагина для обработки результата вывода он должен быть обработан до вывода файла на диск.В нашей предыдущей конструкции основной На это наступил плагин domain retry, в результате получился окончательный билд.В коде есть ошибка. Причина в том, что плагин напрямую модифицирует файлы на диске, и две билда запускаются одновременно. В конце концов, плагины двух сборок изменяют один и тот же файл на диске, что в итоге приводит к ошибкам и требует от нас принудительной очистки среды выпуска.Код возвращается к нормальной публикации.
2. Оптимизация опыта разработки
Удобный опыт разработки помогает повысить эффективность нашей разработки, и оптимизация процесса разработки также имеет решающее значение.
Горячее обновление компонентов, горячее обновление CSS
С тех пор, как webpack запустил горячее обновление, опыт фронтенд-разработчиков в открытой среде значительно улучшился. Нет возможности горячего обновления после изменения компонента
После добавления горячей сборки:
Давайте в основном посмотрим, как наш бизнес основан на стеке технологий React и как получить доступ к горячему обновлению во время разработки.
-
Независимо от того, какой стек технологий, вам нужно добавить его в режиме разработки
webpack.HotModuleReplacementPlugin
плагин -
вставить во все записи
require.resolve('../utils/webpackHotDevClient')
,webpackHotDevClient
Этот код предоставлен официальным приложением create-react-app. -
существует
webpack-dev-server
Добавить в параметры запуска модуляhot:true
-
Добавьте следующий код в файл js, необходимый для горячей загрузки (этот код будет автоматически удален при сборке производственного пакета):
if (process.env.NODE_ENV==='development' && module.hot) { module.hot.accept() }
Примечание. Вы также можете использоватьreact-hot-loaderЧтобы достичь этого, обратитесь к официальной документации для получения подробной информации.
Термическая отладка SSR
Во всех управляемых проектах H5/PC есть некоторые страницы, которые поддерживают прямую отладку.В прошлом метод прямой отладки был следующим:
Этот процесс отладки слишком долгий.Каждая модификация требует пересборки статических ресурсов и перезапуска службы узла, что занимает очень много времени.Во-вторых, в режиме прямого вывода страницы, которые не являются прямым выходом, не смогут быть доступны в обычном режиме. , и весь процесс не будет работать.
Поэтому предлагается новое решение, использующееwebpack watch+nodemon
Комбинированный режим реализует поддержку горячей отладки SSR. HTML/js, требуемый службой узла, динамически выводится через подключаемый модуль веб-пакета. Когда nodemon обнаружит изменение, он автоматически перезапустится, заменит все статические ресурсы в html-файле ресурсами в режиме разработки и сохранит сокет подключение для автоматического обновления страницы.
После реализации горячей отладки процесс отладки значительно сокращается, что согласуется с опытом отладки в обычном непрямом режиме. существуетa8k
прошедшийk dev -s
Команда для включения режима отладки ssr. Ниже представлена блок-схема горячей отладки SSR:
опыт отладки стилей
проблема:
даватьstyle-loader
После того, как sourceMap включен, sourceMap встроен в файл стиля и должен быть импортирован через ссылку.Этот метод заключается в создании BLOB-объекта с помощью JavaScript, а затем выдаче тега ссылки для синтаксического анализа. После этого мы можем напрямую увидеть расположение исходного файла каждого стиля в инструменте разработки, что удобно и быстро для отладки стилей. Но это также вызывает проблему FOUC (мерцание после загрузки страницы), см.ssue
Решение:
Добавить кsingleton: true
Параметры могут решить эту проблему, но sourceMap не может найти исходный файл, но местоположение в объединенном файле, который не может иметь и то, и другое. так вa8k
Параметры предоставляются в инструменте, который включен по умолчанию.singleton:true
,пройти черезk dev -c
Можно открыть сопоставление cssSourceMap
3. Оптимизация производительности
кеш node_modules
Количество зависимостей node_modules большинства проектов в учебнике очень удивительно.После того, как учебный проект ПК устранит зависимости, связанные со сборкой, будет 1883 зависимых пакета, и время установки зависимых пакетов значительно увеличится.Поэтому сокращение установки время зависимых пакетов значительно улучшит общую конструкцию.Важно, метод кеширования.
Компиляция системы JBКаждая компиляция будет запускать новый каталог, из-за чего многие node_modules, от которых зависит проект, не могут быть кэшированы, а каждая компиляция и переустановка занимают много времени.Для компиляции JB я разработал модуль @tencent/im-build для автоматического кэширования зависимости проекта.node_modules, что значительно повышает производительность компиляции.
Система сборки ОКИНет необходимости в дополнительной поддержке подключаемых модулей в OCI. Сама система может обеспечить частичное кэширование каталогов и возможности вторичного использования посредством конфигурации. Методы использования следующие:
-
Добавьте в корневой каталог проекта
.orange-cache.cache
файл и добавьте каталог, который вам нужно кэшировать/node_modules /fudao_qq_com_pc_imt
-
Исправлять
.orange-ci.yml
Конфигурация, добавить путь к файлу конфигурации кешаpush: - cacheFrom: .orange-ci.cache #其它配置省略
Эффект оптимизации
До оптимизации
Оптимизировано
Создайте кеш промежуточных результатов
Оптимизация кэша промежуточных результатов также может значительно повысить производительность сборки, а компиляция модулей сама по себе является задачей, интенсивно использующей ЦП. Вообще говоря, не все модули нужно перерабатывать каждый раз при сборке, можно рассматривать только те модули, содержимое файла которых изменилось, тогда модули, содержимое файла которых не изменилось, можно получить из кеша, обычно хэш-значение содержимое файла используется в качестве файла кеша. , это "Горячая сборка".
В webpack содержимое, которое может кэшироваться: результаты обработки загрузчика, результаты обработки плагина и результаты выходного файла. Далее подробно описывается, как различные ресурсы кэшируются на разных этапах.
1. кеш babel-loader, открыть кеш через cacheDirectory
test: /\.jsx?$/,
use: [
{
loader: resolve('babel-loader'),
options: {
babelrc: false,
// cacheDirectory 缓存babel编译结果加快重新编译速度
cacheDirectory: path.resolve(options.cache, 'babel-loader'),
presets: [[require('babel-preset-imt'), { isSSR }]],
},
},
],
2. кеш eslint-loader, указать путь к кешу через опцию cache
test: /\.(js|mjs|jsx)$/,
enforce: 'pre',
use: [
{
options: {
cache: path.resolve(options.cache, 'eslint-loader'),
},
loader: require.resolve('eslint-loader'),
},
],
eslint-loader обычно нужно открывать только в режиме разработки, что удобно и своевременно, чтобы напоминать разработчикам о наличии ошибок eslint и вовремя исправлять их
3. кеширование css/scss
css-loader/sass-loader/postcss-loader сам по себе не предоставляет механизм кэширования, здесь нам нужно использовать cache-loader, чтобы помочь нам кэшировать результаты построения css/scss Конкретное использование выглядит следующим образом:
{
loader: resolve('cache-loader'),
options: { cacheDirectory: path.join(cache, 'cache-loader-css') },
},
{
loader: resolve('css-loader'),
options: {
importLoaders: 2,
sourceMap,
},
},
...由于篇幅原因,这里不展示其它更多loader
Просто добавьте загрузчик в начало загрузчика, загрузчик может не только кешировать для css
4. Кэш сжатия выходного кода, многопроцессорная обработка механизма сжатия JS
Сжатие кода JS, которое мы используемTerserPlugin
Плагин, конкретная конфигурация выглядит следующим образом:
{
// 设置缓存目录
cache: path.resolve(cache, 'terser-webpack-plugin'),
parallel: true,// 开启多进程压缩
sourceMap,
terserOptions: {
compress: {
// 删除所有的 `console` 语句
drop_console: true,
},
},
}
5. Фиксированный каталог кэша системы CI
Каталог кеша настраивается для разных плагинов и загрузчиков выше.Для системы CI необходимо исправить путь к каталогу кеша, чтобы кешированный контент можно было повторно использовать.Метод использования: настроен JB/tmp/xxx
каталог, систему OCI можно настроить в каталоге проекта.
⚠️Примечание: из-за использования кеша, когда вы изменяете конфигурацию компиляции, вам необходимо немедленно очистить кешированные результаты.Лучший способ - автоматически определить, изменилась ли соответствующая конфигурация в инструменте сборки, и автоматически очистить кеш.
Другие методы оптимизации
1. Укажите абсолютный путь пути поиска модуля, чтобы ускорить поиск модуля.
resolve: {
//加快搜索速度
modules: [
'node_modules',
path.resolve(projectDir, 'src'),
path.resolve(projectDir, 'node_modules')
],
},
2. Отфильтруйте библиотеки, которые не нуждаются в какой-либо обработке
module: {
// 这些库都是不依赖其它库的库 不需要解析他们可以加快编译速度
noParse: /node_modules\/(moment|chart\.js)/,
}
3. Уменьшите объем обработки Babel и избегайте обработки уже сжатого кода.
// 指处理指定目录的文件
include: [
path.resolve(projectDir, 'src'),
path.resolve(projectDir, 'node_modules/@tencent'),
].filter(Boolean),
// 忽略哪些压缩的文件
exclude: [/(.|_)min\.js$/],
4. Библиотека lodash оптимизирована по запросу, чтобы уменьшить количество бесполезного кода.
Когда мы используем библиотеку lodash, мы обычно используем очень мало функций, но код, подобный следующему, приведет к тому, что весь lodash будет введен в окончательный пакет.
import _ from 'lodash'
_.difference(1, 2)
В этом случае, к счастью, есть плагины, которые могут помочь нам оптимизировать, и ссылки lodash по запросу могут автоматически обрабатываться через lodashPlugin.
Способ применения следующий:
const LodashPlugin = require('lodash-webpack-plugin');
plugins:[
// 支持lodash包 按需引用
new LodashPlugin(),
]
После добавления этого плагина приведенный выше код автоматически преобразуется в следующий код:
import difference from 'lodash/difference';
difference([1, 2], [1, 3]);
Примечание. Метод кода импорта должен использовать импорт, а не требовать
5. Для кода рендеринга на стороне сервера мы можем исключить node_modules, тем самым значительно сократив трудоемкую генерацию кода на стороне сервера.
пройти черезwebpack-node-externals
Плагин достигает этого, и конкретное использование выглядит следующим образом:
const nodeExternals = require('webpack-node-externals');
module.export={
// 省略其它配置
externals: [
nodeExternals({
// 注意如果存在src下面其他目录的绝对引用,都需要添加到这里
whitelist: [
/^components/, /^assets/, /^pages/, /^@tencent/, /\.(scss|css)$/
],
}),
],
// 省略其它配置
}
6. SplitChunks, шедевр webpack4.x
До webpack4 способ, которым мы обрабатывали общие модули, заключался в использованииCommonsChunkPlugin
, а то конфигурация плагина громоздка в разработке, а извлечение публичного кода недостаточно тщательно и подробно, поэтому новыйsplitChunks
Эти способности были улучшены. Правильная поза для использования следующая:
splitChunks: {
chunks: 'all',
minSize: 10000, // 提高缓存利用率,这需要在http2/spdy
maxSize: 0,//没有限制
minChunks: 3,// 共享最少的chunk数,使用次数超过这个值才会被提取
maxAsyncRequests: 5,//最多的异步chunk数
maxInitialRequests: 5,// 最多的同步chunks数
automaticNameDelimiter: '~',// 多页面共用chunk命名分隔符
name: true,
cacheGroups: {// 声明的公共chunk
vendor: {
// 过滤需要打入的模块
test: module => {
if (module.resource) {
const include = [/[\\/]node_modules[\\/]/].every(reg => {
return reg.test(module.resource);
});
const exclude = [/[\\/]node_modules[\\/](react|redux|antd)/].some(reg => {
return reg.test(module.resource);
});
return include && !exclude;
}
return false;
},
name: 'vendor',
priority: 50,// 确定模块打入的优先级
reuseExistingChunk: true,// 使用复用已经存在的模块
},
react: {
test({ resource }) {
return /[\\/]node_modules[\\/](react|redux)/.test(resource);
},
name: 'react',
priority: 20,
reuseExistingChunk: true,
},
antd: {
test: /[\\/]node_modules[\\/]antd/,
name: 'antd',
priority: 15,
reuseExistingChunk: true,
},
},
},
Кратко объясните приведенную выше конфигурацию
- Поместите общую часть node_modules в пакет vendor.js;
- Поместите ведро семейства React в пакет react.js;
- Если проект зависит от antd, то вынесите antd в отдельный бандл;
- Последние оставшиеся бизнес-модули ссылаются на общедоступные модули более 3 раз, и общедоступные блоки будут автоматически извлечены.
Эффект оптимизации
После стольких оптимизаций ниже приведен учебный проект h5, основанный на более чем 2,5 тыс. модулей.Сравните время строительства и почувствуйте эффект.
До оптимизации: горячая сборка занимает 40 секунд
После оптимизации: всего 20 секунд
4. Передовой опыт интеграции конвергентной конфигурации
Конфигурация и оптимизация сборки — задача не из легких.Конвергенция и интеграция лучших практик в независимые модули, которые можно повторно использовать в разных проектах, может значительно сократить объем работ по конструированию и обслуживанию, а также сложность последующей работы по обновлению и оптимизации.
Проект команды IMWeb также самостоятельно поддерживает набор инструментов передовой практики построения на основе стека технологий React.a8k
, Во всех проектах вы не увидите сложных и разнообразных конфигураций webpack, а также различных пре- и постскриптов. Каждому проекту требуется только простая конфигурация ключа, чтобы быстро получить доступ к инструменту сборки и насладиться улучшенным опытом разработки и производительностью сборки, которые он обеспечивает.
5. Другой опыт
О узле-sass
Детская обувь, которая использовала node-sass, должна была столкнуться с различными ошибками компиляции, ошибками загрузки бинарных файлов и даже ошибками разрешения на запись файла при установке node-sass 😟. Существуют также различные хитрости для решения этой проблемы, но ведь нельзя сделать это раз и навсегда.
Поэтому я хочу использовать плагин postcss для совместимости с синтаксисом sass.Хотя плагин может быть совместим с некоторым синтаксисом, риск замены node-sass в определенном количестве бизнес-кода очень высок.Я лично тестирую различные ямы 💣
Конечно, есть и другие способы решения этой проблемы, которые не только позволяют использовать полный синтаксис sass, но и позволяют избежать всевозможных проблем с установкой node-sass.Официальный sass-loader на самом деле уже обеспечивает поддержку dart- модуль парсинга sass.Подробнее см.Документация, Некоторые люди могут беспокоиться о том, что производительность js-модуля dart-sass невысока.Я лично протестировал более 2000 модулей в нашем проекте, и производительность компиляции dart-sass не почувствовала значительного снижения.В то же время мы использовали способность кеширования, как правило, мутируют только те ресурсы, которые нужно изменить.
Конкретная конфигурация выглядит следующим образом:
{
loader: resolve('sass-loader'),
options: {
// 安装dart-sass模块:npm i -D sass
implementation: require('sass'),
includePaths: [
// 支持绝对路径查找
path.resolve(projectDir, 'src'),
],
sourceMap,
},
},
проблема с использованием переменной node-sass Я нашел много кода с таким синтаксисом в H5, но он реально не работает, после построения не заменяется на значение переменной.
После компиляции:
Обходной путь выглядит следующим образом:
О postcss
Лично я думаю, что postcss — это будущее препроцессоров css Сейчас postcss для css — то же, что babel для JavaScript. postcss поддерживает будущие функции css через плагины, и в то же время вы можете настроить плагины для достижения желаемых функций. Однако другие препроцессоры, такие как less и sass, трудно вмешиваются в процесс его обработки и могут обрабатываться только в соответствии с его установленными правилами. Поэтому рекомендуется использовать непосредственно для новых проектовpostcss+postcss-preset-env
Используйте новейшие функции синтаксиса CSS и в то же время упростите быстрый доступ к поддержке после полной поддержки соответствующих функций браузерами в будущем.
💣 Если вы используетеcss-loader
возможность импорта, используяpost-css-import
Возможность импорта плагина, два плагина будут конфликтовать, и не рекомендуется использовать их одновременно!
если используетсяpostcss-custom-properties
, следует отметить, что в версии 8.x есть ошибка, которая не может разобрать следующий синтаксис:
:root{
--green: var(--customGreen, #08cb6a);
// 8.x无法正确处理该语法
--primary: var(--customPrimary, var(--green));
}
.test {
background: color(var(--primary) shade(5%));
// 上面面这句将会被转换为如下代码,最终导致浏览器无法解析该语法
background: var(--green);
background: var(--primary);
// 我们期望转换为
background: #08cb6a;
}
Решение: Отключите пользовательские свойства в postcss-preset-env, установите пользовательские свойства версии 6.x и добавьте плагин отдельно.
О кэшировании
Если включено в режиме разработкиeslint-loader
правильноjsx?
Файл проверен и возможность его кеширования включена.При изменении правил проверки eslint необходимо очистить файлы кеша и перезапустить сборку, иначе изменение правила не вступит в силу! При использованииa8k
сборка инструмента, вы можете использоватьk clean
Команды обрабатываются автоматически.
повторная попытка основного домена
Длина слишком велика, чтобы представить подробно. Если вам интересно, вы можете увидеть соответствующий исходный код здесь.webpack-retry-load-plugin, В последующих статьях, связанных с вводом, рассказывается, как реализовать синхронный и асинхронный повтор кода CSS/JS.