Front-end проект компании использует фреймворк Vue, а фреймворк Vue использует Webpack для построения.При непрерывной итерации проекта проект постепенно становится больше, но скорость построения проекта становится медленной, поэтому необходимо срочно оптимизировать построение Webpack. После непрерывных исследований и практики, после оптимизации с помощью следующих методов, скорость строительства проекта увеличилась на 50%. Соответствующие методы оптимизации теперь обобщены и распространены.
Адрес гитхаба:GitHub.com/ревматизм123/…, если вам нравится или у вас есть вдохновение, пожалуйста, помогите поставить звезду ~, что также является поощрением для автора.
1. Сузить область поиска файла
1.1 Оптимизация конфигурации загрузчика
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test')]
},
{
// 1、如果项目源码中只有js文件,就不要写成/\.jsx?$/,以提升正则表达式的性能
test: /\.js$/,
// 2、babel-loader支持缓存转换出的结果,通过cacheDirectory选项开启
loader: 'babel-loader?cacheDirectory',
// 3、只对项目根目录下的src 目录中的文件采用 babel-loader
include: [resolve('src')]
},
1.2. Оптимизация конфигурации resolve.modules
resolve.modules используется для настройки каталогов, в которых Webpack ищет сторонние модули. Значение по умолчанию для resolve.modules равно [node modules], что означает сначала перейти в каталог /node modules текущего каталога, чтобы найти нужный модуль.Если нет, перейдите в ../../node modules. найти его и т. д., что очень похоже на механизм поиска модулей в Node.js. При размещении установленных сторонних модулей в каталоге ./node modules корневого каталога проекта нет необходимости выполнять послойный поиск по методу по умолчанию, можно указать абсолютный путь для хранения сторонних модулей сократить поиск.
resolve: {
// 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
modules: [path.resolve(__dirname,'node_modules')]
},
1.3 Оптимизация конфигурации resolve.alias
Элемент конфигурации resolve.alias сопоставляет исходный путь импорта с новым путем импорта через псевдоним.
alias: {
'@': resolve('src'),
},
// 通过以上的配置,引用src底下的common.js文件,就可以直接这么写
import common from '@/common.js';
1.4 Оптимизация конфигурации resolve.extensions
Если в операторе импорта нет суффикса файла, Webpack автоматически добавит суффикс, чтобы попытаться узнать, существует ли файл. По умолчанию: extensions:['.js','.json'] . Другими словами, при встрече с оператором импорта, таким как require ( './data '), Webpack сначала будет искать файл ./data .js. Если файл не существует, он будет искать файл ./data. json. Если вы все еще не можете найти его, вы получите сообщение об ошибке. Если этот список будет длиннее или правильный суффикс окажется дальше назад, это вызовет больше попыток, поэтому конфигурация разрешения .extensions также повлияет на производительность сборки.
Меры по оптимизации:
• Старайтесь, чтобы список попыток суффиксов был как можно меньше, и не записывайте невозможные условия в проекте в список попыток суффиксов.
• Файловый суффикс с наибольшей частотой должен быть помещен первым, чтобы завершить процесс поиска как можно скорее.
• При написании операторов импорта в исходном коде старайтесь включать как можно больше суффиксов, чтобы избежать процесса поиска. Например, при определенных обстоятельствах напишите require('./data ') как require('./data.json '), что можно использовать в сочетании с EnforceExtension и EnforceModuleExtension, чтобы заставить разработчиков соблюдать эту оптимизацию.
1.5 Оптимизация конфигурации resolve.noParse
Элемент конфигурации noParse позволяет Webpack игнорировать рекурсивный синтаксический анализ и обработку некоторых файлов, которые не являются модульными, что повышает производительность сборки. Причина в том, что некоторые библиотеки, такие как jQuery и ChartJS, огромны и не принимают модульных стандартов, а Webpack отнимает много времени и не имеет смысла анализировать эти файлы.
noParse — необязательный элемент конфигурации, и его тип должен быть одним из RegExp, [RegExp] и function. Например, если вы хотите игнорировать jQuery, ChartJS,Оптимизированная конфигурация выглядит следующим образом:
// 使用正则表达式
noParse: /jquerylchartjs/
// 使用函数,从 Webpack3.0.0开始支持
noParse: (content)=> {
// 返回true或false
return /jquery|chartjs/.test(content);
}
2. Сократите избыточный код
babel-plugin-transform-runtime — это официальный плагин, предоставляемый Babel для сокращения избыточного кода. Когда Babel преобразует код ES6 в код ES5, ему обычно требуются некоторые вспомогательные функции, написанные ES5, для завершения реализации нового синтаксиса. реализовать наследование. babel-plugin-transform-runtime заменит связанные вспомогательные функции операторами импорта, тем самым уменьшив размер файла кода, скомпилированного babel.
3. Разбирать и обрабатывать файлы с помощью многопроцессорного режима HappyPack.
Поскольку необходимо проанализировать и обработать большое количество файлов, сборка представляет собой операцию чтения файлов и ресурсоемких вычислений, особенно когда количество файлов увеличивается, проблема медленной сборки Webpack становится более серьезной. Webpack, работающий на узле, представляет собой однопоточную модель, что означает, что Webpack должен обрабатывать задачи одну за другой и не может обрабатывать несколько задач одновременно. Happy Pack (https://github.com/amireh/happypack) позволяет Webpack делать именно это: он разбивает задачу на несколько подпроцессов для одновременного выполнения, а затем отправляет результат основному процессу после того, как подпроцессы их обработают.
(1)HappyPack插件安装:
$ npm i -D happypack
(2)webpack.base.conf.js 文件对module.rules进行配置
module: {
rules: [
{
test: /\.js$/,
// 将对.js 文件的处理转交给 id 为 babel 的HappyPack实例
use:['happypack/loader?id=babel'],
include: [resolve('src'), resolve('test'),
resolve('node_modules/webpack-dev-server/client')],
// 排除第三方插件
exclude:path.resolve(__dirname,'node_modules'),
},
{
test: /\.vue$/,
use: ['happypack/loader?id=vue'],
},
]
},
(3)webpack.prod.conf.js 文件进行配置 const HappyPack = require('happypack');
// 构造出共享进程池,在进程池中包含5个子进程
const HappyPackThreadPool = HappyPack.ThreadPool({size:5});
plugins: [
new HappyPack({
// 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件
id:'vue',
loaders:[
{
loader:'vue-loader',
options: vueLoaderConfig
}
],
threadPool: HappyPackThreadPool,
}),
new HappyPack({
// 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件
id:'babel',
// 如何处理.js文件,用法和Loader配置中一样
loaders:['babel-loader?cacheDirectory'],
threadPool: HappyPackThreadPool,
}),
]
4. Используйте ParallelUglifyPlugin для сжатия файлов кода в нескольких процессах.
Поскольку при сжатии кода JavaScript необходимо разобрать код в синтаксическое дерево AST, представленное абстракцией объектов, а затем применить различные правила для анализа и обработки AST, поэтому этот процесс требует больших вычислительных ресурсов и времени. Когда в Webpack есть несколько файлов JavaScript, которые необходимо вывести и сжать, UglifyJS будет использоваться для сжатия и последующего вывода по одному, но ParallelUglifyPlugin откроет несколько подпроцессов и назначит работу по сжатию нескольких файлов нескольким подпроцессам. завершен, каждый подпроцесс будет завершен.На самом деле, процесс по-прежнему использует UglifyJS для сжатия кода, но он становится параллельным выполнением. Таким образом, плагин ParallelUglify может быстрее сжимать несколько файлов.
ParallelUglifyPlugin в проекте использует конфигурацию:
(1)ParallelUglifyPlugin插件安装:
$ npm i -D webpack-parallel-uglify-plugin
(2)webpack.prod.conf.js 文件进行配置
const ParallelUglifyPlugin =require('webpack-parallel-uglify-plugin');
plugins: [
new ParallelUglifyPlugin({
cacheDir: '.cache/',
uglifyJs:{
compress: {
warnings: false
},
sourceMap: true
}
}),
]
5. Используйте автоматическое обновление
С помощью автоматизированных средств при отслеживании изменений в локальном файле исходного кода он автоматически перестраивает исполняемый код, а затем управляет обновлением браузера. Webpack имеет встроенные функции и предоставляет нам множество вариантов на выбор.
Конфигурация автоматического обновления в проекте:
devServer: {
watchOptions: {
// 不监听的文件或文件夹,支持正则匹配
ignored: /node_modules/,
// 监听到变化后等300ms再去执行动作
aggregateTimeout: 300,
// 默认每秒询问1000次
poll: 1000
}
},
Связанные меры по оптимизации:
(1) Конфигурация игнорирует некоторые файлы, которые не отслеживаются, например: node_modules.
(2) Чем больше значение watchOptions.aggregateTirneout, тем выше производительность, поскольку это может снизить частоту перестроения.
(3) Чем меньше значение watchOptions.poll, тем лучше, потому что это может снизить частоту проверки.
6. Включите горячую замену модуля
DevServer также поддерживает технологию под названием «горячая замена модуля», которая обеспечивает сверхбыстрый предварительный просмотр в реальном времени без обновления всей веб-страницы. Принцип заключается в том, что при изменении исходного кода необходимо только перекомпилировать измененный модуль, а затем заменить соответствующий старый модуль в браузере новым выходным модулем. Технология горячей замены модулей значительно повысила эффективность и опыт разработки.
Настройка горячей замены модулей в проекте:
devServer: {
hot: true,
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
// 显示被替换模块的名称
new webpack.NamedModulesPlugin(), // HMR shows correct file names
]
7. Извлеките общедоступный код
Если код каждой страницы включает эти общие части, это вызовет следующие проблемы:
• Одни и те же ресурсы загружаются повторно, что приводит к трате пользовательского трафика и затрат на сервер.
• Ресурсы, необходимые для загрузки каждой страницы, слишком велики, что приводит к медленной загрузке первой страницы страницы и влияет на работу пользователей.
Если общий код нескольких страниц извлечь в отдельные файлы, вышеперечисленные проблемы можно оптимизировать. В Webpack есть встроенный плагин CommonsChunkPlugin, предназначенный для извлечения общих частей нескольких чанков.
Конфигурация CommonsChunkPlugin в проекте:
// 所有在 package.json 里面依赖的包,都会被打包进 vendor.js 这个文件中。
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function(module, count) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
);
}
}),
// 抽取出代码模块的映射关系
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vendor']
}),
8. Загружайте код по запросу
Когда одностраничное приложение написано на Vue, может быть введено много маршрутов. После упаковки и сборки пакет javascript может стать очень большим и повлиять на загрузку. Было бы более эффективно, если бы мы могли разделить компоненты, соответствующие разным маршрутам, на разные блоки кода, а затем загружать соответствующие компоненты при доступе к маршруту. Это значительно улучшит скорость отображения выше сгиба, но скорость других страниц может снизиться.
Настройка маршрутизации загрузки по требованию (ленивая загрузка) в проекте:
const Foo = () => import('./Foo.vue')
const router = new VueRouter({
routes: [
{ path: '/foo', component: Foo }
]
})
9. Оптимизируйте исходную карту
После того, как мы упакуем проект, мы упакуем код нескольких разрабатываемых файлов в один файл и сожмем его, чтобы удалить лишние пробелы, и после того, как babel будет скомпилирован, он в конечном итоге будет использоваться в онлайн-среде, а затем обработанный Там будет большая разница между кодом и исходным кодом.Когда есть ошибка, мы можем найти только местоположение сжатого кода, но не можем найти код в среде разработки, что не очень хорошо для разработки, поэтому появляется sourceMap, это решить проблему плохо отлаженного кода.
Необязательные значения SourceMap следующие:
Рекомендуемая среда разработки: дешевый-модуль-eval-исходная-карта
Рекомендуемая производственная среда: дешевый-модуль-источник-карта
Причины следующие:
1. Информация столбца в исходном коде не имеет никакого эффекта, поэтому наш упакованный файл не хочет содержать информацию, относящуюся к столбцу, только информация строки может установить зависимости до и после упаковки. Поэтому, будь то среда разработки или производственная среда, мы хотим добавить базовый тип Cheap, чтобы игнорировать информацию столбца до и после упаковки.
2. Будь то среда разработки или формальная среда, мы все надеемся найти конкретное местоположение исходного кода ошибки.Например, если файл vue сообщает об ошибке, мы надеемся найти конкретный файл vue, поэтому нам также нужна конфигурация модуля.
3. Нам нужно сгенерировать форму файла карты, поэтому нам нужно добавить атрибут source-map.
4. Когда мы представили код упаковки eval, мы знали, что упаковка eval работает очень быстро, потому что не генерирует файл карты, но eval-source-map можно использовать в сочетании с eval, и файл карты будет храниться в форма DataURL после упаковки .js файла. Не используйте eval-source-map в производственной среде, потому что это увеличит размер файла, но в среде разработки вы можете попробовать это, потому что они быстро упаковываются.
10. Анализ результатов строительства
Код, выводимый Webpack, очень нечитаем, а файл очень большой, что доставляет нам много головной боли. Для более простого и интуитивно понятного анализа выходных результатов в сообществе появилось множество инструментов визуального анализа. Эти инструменты графически представляют результаты более интуитивно, позволяя нам быстро понять, в чем проблема. Далее я объясню инструмент анализа, используемый в проекте vue: webpack-bundle-analyzer.
Настройте в webpack.prod.conf.js в проекте:
if (config.build.bundleAnalyzerReport) {
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
webpackConfig.plugins.push(new BundleAnalyzerPlugin());
}
执行 $ npm run build --report 后生成分析报告如下:
Адрес гитхаба:GitHub.com/ревматизм123/…, если вам нравится или у вас есть вдохновение, пожалуйста, помогите поставить звезду ~, что также является поощрением для автора.