diff --git a/.dev_to/case-study-template.md b/.dev_to/case-study-template.md new file mode 100644 index 0000000..468b07f --- /dev/null +++ b/.dev_to/case-study-template.md @@ -0,0 +1,55 @@ +# Case-study оптимизации + +## Актуальная проблема +В проекте `dev.to` есть определенная проблема. Анализ показывает, что на всех страницах загружается файл `vendor.js`. + +Этот файл содержит библиотеку moment.js, печально известную своим большим размером. + +У нас уже была программа на `ruby`, которая умела делать нужную обработку. + +## Формирование метрики +В качестве метрики берем объём `js` на главной странице. + +В файле `homeBudget.json` устанавливаем бюджет в 460000 байт. + +## Анализ +С помощью `sitespeed.io` убеждаемся, что бюджет пока не соблюдается: +`docker run --privileged --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io http://host.docker.internal:3000/ -n 1 --budget.configPath homeBudget.json` + +![sitespeed_before.png](/public/reports/sitespeed_before.png) + +С помощью `webpack-bundle-analyzer` убедился, что `moment.js` входит в сборку `vendor`: + +![bundle_analyze_before.png](/public/reports/bundle_analyze_before.png) + +Закомментировал содержимое файла `proCharts.js`. `web-bundle-analyzer` показал что `moment` пропал из `vendor`: + +![bundle_analyze_after.png](/public/reports/bundle_analyze_after.png) + + +## Оптимизация +В первую очередь я раскомментировал содержимое файла `proCharts.js`. + +Проанализировав отчеты и код проекта я выяснил что `proCharts.js` использует `chart.js`, которая, в свою очередь, внутри использует `moment.js`. +Поэтому `moment` попадает в `vendor` вместе с `chart.js`, и они оказываются связанными. + +В качестве оптимизации отредактировал `CommonsChunkPlugin` в `environment.js` путём исключения `chart.js` и `moment.js` из `vendor` сборки. +Этим мы можем гарантировать что теперь они будут подключаться только там, где непосредственно используются. +``` +!module.context.includes('chart.js') && !module.context.includes('moment') +``` +С помощью `web-bundle-analyzer` убедился, что это сработало: + +![bundle_analyze_after_optimization.png](/public/reports/bundle_analyze_after_optimization.png) + +Однако `sitespeed.io` показал что бюджет еще не выполнен: +![sitespeed_after.png](/public/reports/sitespeed_after.png) + +В `webpack-bundle-analyzer` заметил, что в `vendor` остались 2 зависимости `chartjs-color` и `chartjs-color-string`. Поэтому их также исключил из `vendor`. + +Теперь бюджет выполняется: +![sitespeed_finish.png](/public/reports/sitespeed_finish.png) + +## CI +Защитил оптимизацию, настроив CI Github Actions: +https://github.com/alexrails/rails-optimization-task6/actions/runs/13750720227 \ No newline at end of file diff --git a/.dev_to/sitespeed/homeBudget.json b/.dev_to/sitespeed/homeBudget.json new file mode 100644 index 0000000..b9cd551 --- /dev/null +++ b/.dev_to/sitespeed/homeBudget.json @@ -0,0 +1,7 @@ +{ + "budget": { + "transferSize": { + "javascript": 460000 + } + } +} diff --git a/.github/workflows/sitespeedio.yml b/.github/workflows/sitespeedio.yml new file mode 100644 index 0000000..114dcd1 --- /dev/null +++ b/.github/workflows/sitespeedio.yml @@ -0,0 +1,10 @@ +name: sitespeedio +on: [push] +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v4 + - name: run sitespeed.io + run: docker run --privileged --rm -v "$(pwd):/sitespeed.io" sitespeedio/sitespeed.io https://03d1-2a0b-6204-12ef-c100-6424-8e72-d575-70d0.ngrok-free.app -n 1 --budget.configPath .dev_to/sitespeed/homeBudget.json diff --git a/config/webpack/environment.js b/config/webpack/environment.js index da47cd7..c57224c 100644 --- a/config/webpack/environment.js +++ b/config/webpack/environment.js @@ -18,7 +18,9 @@ environment.plugins.append( name: 'vendor', minChunks: (module) => { // this assumes your vendor imports exist in the node_modules directory - return module.context && module.context.indexOf('node_modules') !== -1 + return module.context && module.context.indexOf('node_modules') !== -1 && + !/chart\.js|chartjs|color-name|color-convert/.test(module.context) && + !module.context.includes('moment') } }) ) @@ -31,4 +33,14 @@ environment.plugins.append( }) ) +const BundleAnalyzerPlugin = require('webpack-bundle-analyzer') + .BundleAnalyzerPlugin; +environment.plugins.append( + 'BundleAnalyzer', + new BundleAnalyzerPlugin({ + analyzerMode: 'static', + openAnalyzer: true, + }), +); + module.exports = environment diff --git a/public/reports/bundle_analyze_after.png b/public/reports/bundle_analyze_after.png new file mode 100644 index 0000000..2907eb9 Binary files /dev/null and b/public/reports/bundle_analyze_after.png differ diff --git a/public/reports/bundle_analyze_after_optimization.png b/public/reports/bundle_analyze_after_optimization.png new file mode 100644 index 0000000..45e259c Binary files /dev/null and b/public/reports/bundle_analyze_after_optimization.png differ diff --git a/public/reports/bundle_analyze_before.png b/public/reports/bundle_analyze_before.png new file mode 100644 index 0000000..647639b Binary files /dev/null and b/public/reports/bundle_analyze_before.png differ diff --git a/public/reports/sitespeed_after.png b/public/reports/sitespeed_after.png new file mode 100644 index 0000000..10ed663 Binary files /dev/null and b/public/reports/sitespeed_after.png differ diff --git a/public/reports/sitespeed_before.png b/public/reports/sitespeed_before.png new file mode 100644 index 0000000..6d1aa69 Binary files /dev/null and b/public/reports/sitespeed_before.png differ diff --git a/public/reports/sitespeed_finish.png b/public/reports/sitespeed_finish.png new file mode 100644 index 0000000..630c541 Binary files /dev/null and b/public/reports/sitespeed_finish.png differ