Практика оптимизации для средних проектов в React

внешний интерфейс JavaScript React.js Webpack
Практика оптимизации для средних проектов в React

На фронте написано - почти год двигаю кирпичи в компании.Видя, что проект становится все больше и больше, нужно срочно решать проблему оптимизации. Оптимизация — штука очень противоречивая, но ради поэзии и дистанции нам все же придется пройти тернистый путь оптимизации.

Что эта статья может охватывать--

Введение в проект

Весь проект имеет около 60+ страниц, около 150+ используемых компонентов и около 70+ зависимостей в пакете, Его вряд ли следует рассматривать как проект React среднего размера.

Давайте посмотрим на результаты нашего текущего проекта сборки --

Время упаковки составляет около 150 с, а упакованные ресурсы после gzip-сжатия составляют около 1,2 м. Хотя некоторые общие зависимости были разделены ранее, по-прежнему недопустимо, чтобы объем индексного пакета достигал 600+.

Проблемы, требующие решения && Рассмотренные решения

Прежде чем мы приступим к оптимизации, самое главное — понять, что именно мы хотим оптимизировать. После определения цели оптимизации мы можем начать думать о плане оптимизации, а затем реализовывать план оптимизации. В сочетании с пакетным анализом проекта и нашим собственным пониманием проекта мы можем изначально определить следующие направления оптимизации:

① похудеть

Прежде всего, нам нужно достаточно знать о нашей программе, чтобы начать худеть. Вот очень мощный инструмент, который можно рекомендовать всемwebpack-bundle-analyzer

Украсть карту на github

Как показано, мы можем четко видеть модуль в каждом файле JS, вы также можете увидеть размер каждого модуля и композиции модуля, который может обеспечить нашу резервирование и оптимизацию кода. Большая помощь.

Конкретный способ питания также очень прост.

Таким образом, у нас есть более конкретное понимание проекта, от списка зависимостей проекта до ссылок на компоненты определенной страницы, которые можно найти в отчете об анализе. Тогда мы можем начать наше путешествие по снижению веса.

Сначала найди старшего брата

Когда мы впервые видим отчет об анализе пакета, мы всегда можем найти неожиданных «больших парней», Если это незаменимая зависимость, нет способа, но если это какая-то зависимость, которую можно заменить, есть другие. . Здесь вы можете просто увидеть меня раньшеОбработка зависимостей moment.js в приложении create-реагировать, если обработка идет хорошо, вы можете интуитивно увидеть изменение размера пакета.

В заключение, если есть небольшие и удовлетворяющие зависимости, которые можно заменить, пожалуйста, не стесняйтесь, но если нет удовлетворяющих зависимостей, вы можете попробовать построить колесо самостоятельно, конечно, последнее нужно рассматривать в соответствии с вашими собственная ситуация.

распространяться

Я считаю, что все используют множество зависимостей при разработке веб-сайтов, но эти зависимости после вывода упаковываются бизнес-кодом, что явно не соответствует нашим ожиданиям. Перед лицом этих в основном неизменных зависимостей мы предпочитаем, чтобы они взяли на себя инициативу по формированию группы и держались подальше от нашего бизнес-кода.

На данный момент пришло время использовать CommonsChunkPlugin из webpack (похоже, он был заменен другими плагинами в wp4, мы не будем здесь обсуждать wp4), который может помочь нам упаковать некоторые указанные модули в указанные бандлы. Конкретные варианты использования могут бытьОбратитесь к соответствующему введению на официальном сайте wp., тут есть подвох — если вы хотите, чтобы имя файла, отвечающего за сбор зависимых бандлов, при упаковке оставалось неизменным, вам нужно сгенерировать манифест.

Не кладите все страницы в одну корзину (1) — разделение страниц

Некоторые низкочастотные страницы мы можем полностью вытащить из проекта, возьмем для примера наш проект, там всего 60+ страниц, и большинство пользователей будут посещать только несколько или десяток из них, а зайти невозможно все страницы сразу. В результате неизбежно будут какие-то страницы с очень низкой частотой посещения, как быть с этими страницами? Здесь есть несколько вариантов:

  • Перепишите соответствующие страницы вне рамок и повторно разверните
  • Скопируйте код проекта, снова запустите его в других местах и ​​разверните, исходный проект может удалить ненужные страницы
  • Упрощенная версия предыдущего решения, скопировать окружение проекта, запустить новый чистый проект и развернуть его, а низкочастотную страницу исходного проекта "вырезать" в новый проект

Вышеупомянутые три схемы лично чувствуют, что у каждой есть свои преимущества и недостатки, первая схема很简单, применимым сценарием является статическая страница, аналогичная Q&A.Его можно отделить от проекта и написать как статическую страницу и развернуть в других местах, но недостатком является то, что исходные компоненты проекта нельзя использовать повторно.

Второй вариант时间至上Решение можно быстро мигрировать, но минус в том, что мигрированные страницы фактически все равно запихиваются в одну корзину, но заменяется новая корзина.

Третий вариант质量至上План со временем в качестве стоимости в обмен на новый «проект низкочастотной страницы». Я думаю, что конкретное решение, которое будет использоваться, также зависит от текущей ситуации с проектом, а не от стремления к совершенству, а от стремления к наиболее подходящему.

② Загрузка первого экрана

Первая загрузка экрана, наверное, вечная тема оптимизации, все оптимизации не могут обойти эту тему, потому что только она может заставить «каждого» максимально интуитивно ощутить результаты нашей оптимизации. Для пользователей стандарт думать, что первый экран веб-страницы быстрый, на самом деле очень прост, то есть пустой экран в течение длительного времени после открытия страницы.所以我们需要做的就是弱化用户对白屏的感知, Примерно с этого момента я лично считаю, что оптимизация загрузки над кратером может иметь два направления: одно — скорость, а другое — опыт.

Добавление заполнителей для загрузки

По сути, это очень популярный некоторое время назад «скелетный экран», мы можем показать пользователю «фейковую» страницу до того, как страница будет фактически отрисована, и подождать, пока не наступит определенный временной узел (например, данные готовы ...) заменить реальный контент. Вот пример, который я написал очень небрежно :)

Мое решение на этой странице списка купонов состоит в том, чтобы отображать три скелета элементов списка при инициализации страницы и заменять реальный контент при возврате данных интерфейса.

Наш первый экран на самом деле похож, мы можем сделать соответствующий каркасный компонент в соответствии со структурой отображения первого экрана, а затем отображать его по мере необходимости, что может эффективно сократить время, в течение которого пользователи видят белый экран. Ниже приведен код моего скелета, места для оптимизации много, но поскольку приоритет не очень высокий, итерации нет.

Структура, вероятно, такая, а стиль очень грубый, потому что каждый элемент является независимым компонентом, и вы можете напрямую использовать абсолютное позиционирование, чтобы сложить краткий элемент списка заполнителей. Эффект, аналогичный индикатору прогресса внутри, достигается анимацией css3, мы можем изменить цвет фона каждого блока на градиент, а затем добиться эффекта на картинке, изменив background-position.

Ленивая загрузка изображения

Это должно быть старомодное направление оптимизации Принцип, вероятно, состоит в том, чтобы использовать одно и то же изображение-заполнитель для всех изображений вне представления, сохранить ссылку на реальное изображение в data-* и судить, входит ли изображение в представление, отслеживая прокрутку . , чтобы управлять значением тега img src. Конкретную реализацию можно найти во многих местах, и вы можете выбрать ее в соответствии со своей ситуацией.

Не кладите все страницы в одну корзину (2) -- ленивая загрузка

Фактически, в процессе всей оптимизации, моя гравитация помещается в это место, и другие думают о том, что это на полпути ...

Напомним, мы говорили вышеОтдельные низкочастотные страницы, то неизбежно будет несколько страниц с очень высокой посещаемостью, так что же нам делать с этими страницами?

Из-за высокой частоты посещений мы можем предположить, что эти страницы тесно связаны с нашим основным бизнесом, поэтому разделять их нерентабельно (вероятно, существует дилемма поддержки нескольких наборов кода).

Но такие высокочастотные страницы — ключевые области для оптимизации, что делать? Столкнувшись с такой страницей, мы все еще можем использовать метод ленивой загрузки (ленивая загрузка страницы || ленивая загрузка компонента || зависимая ленивая загрузка).

Чтобы добиться всех видов ленивой загрузки на уровне js, нам всем нужно использовать функции в webpack.Code Splitting, он может разложить js, который мы изначально упаковали вместе, на части, и может добиться эффекта загрузки и использования по запросу.

  • ленивая загрузка страницы

Поскольку мы используем react-router, мы можем использовать getComponent реакции-маршрутизатора, чтобы легко выполнить требование ленивой загрузки страницы. Как показано на рисунке ниже, если главная страница введена в маршрут таким образом, она будет разделена на независимый js при упаковке.

  • Ленивая загрузка компонентов и ленивая загрузка зависимостей

Ленивая загрузка компонентов и зависимостей также очень проста.Эффект ленивой загрузки может быть достигнут, написав, как показано на следующем рисунке, но если мы используем babel, нам нужно изменить конфигурацию babel, чтобы он мог плавно анализировать синтаксис динамического импорта().

③ Ускорение упаковки

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

Используйте DLL для сопровождения упаковки

Из-за нехватки времени я не пытался использовать DLL в проекте компании, но я видел, что многие студенты в Интернете рекомендовали его, поэтому я решил упомянуть его здесь~Имеется документация по библиотекам DLL webpack.

Изменить версию веб-пакета с 2.0 --> 4.x

Поскольку проект был официально запущен почти год назад, он имел версию 1.x, когда он вступил во владение, и он был обновлен до версии 2.x для отложенной загрузки, когда он впервые вступил во владение.

Но теперь я обнаружил, что 2.x кажется недостаточным, ведь две основные версии были удалены, новые функции, новые функции или новые оптимизации после обновления должны быть мотивацией для меня, чтобы перенести проект на новую версию. Конкретные детали конфигурации wp4 были представлены многими студентами на Nuggets.Здесь я хотел бы представить, как я перенес старый проект на wp4:

Прежде чем начать миграцию версии, я представил два решения: одно — напрямую обновить и изменить конфигурацию исходного проекта, второе — создать новый проект webpack4 и перенести бизнес-код после его сборки.

Оценив вероятность успеха и затраты времени, я, наконец, выбрал второй вариант. Итак, до какой степени этот новый проект должен быть улучшен, чтобы его можно было мигрировать? Я лично прошел следующие этапы:

  • Создайте скелет проекта

На этот раз проект отличается от предыдущего: мы не используем строительные леса великих богов для построения скелета проекта, нам нужно изучить использование веб-пакета и различия между старой и новой версиями с нуля.

Для некоторых базовых знаний и настройки настоятельно рекомендуется прочитатьДокументация на официальном сайте webpackи некоторые ранее упомянутые статьиwebpack4-первый опыт,Знакомство с новыми функциями webpack 4.0.0-beta.0.

Я считаю, что после прочтения этого у всех будет базовое понимание конфигурации wp, а следующим шагом будет создание каталога и установка зависимостей. В итоге мы получаем такую ​​структуру каталогов:

  • Напишите Привет Мир!

Как мы должны решить, когда переместить код проекта в новый проект? Очень просто, когда этот новый проект можно нормально отлаживать или упаковывать Hello World соответствующего фреймворка.

Возьмем в качестве примера наш проект. После создания каталога проекта и некоторых базовых конфигураций следующим шагом будет полное моделирование стека технологий исходного проекта и написание нескольких простых демонстрационных страниц в новом проекте. Конечно, эти демо-страницы написаны не случайно, а не случайно, по своему опыту я написал несколько файлов index.js, App.js, Hello.js, Global.scss, router.js.

Strip опирается на non-core, ядром нашей зависимости на самом деле является react & react-router & sass, пока webpack может правильно анализировать es6 и sass, мы можем в значительной степени уменьшить среду старого проекта. (Babel настраивает связанный jsx в пакете)

  • Внимательно прочитайте пакет

После того, как приведенная выше демонстрация завершена, наш новый проект начал обретать форму. Далее нам нужно перенести старый проект package.json в новый проект. Здесь следует отметить следующие моменты:

① Обратите внимание на инструкции в "скриптах", надо посмотреть, что делает каждая инструкция в нем, а потом подумать, как написать инструкцию с той же функцией в новом проекте.

② "dependencies" && "devDependencies" Зависимости старого проекта также должны быть легко перенесены, но мы можем воспользоваться этой возможностью, чтобы удалить неиспользуемые зависимости.

③ Конфигурация вспомогательных инструментов, таких как «babel» || «autoprefixer», также должна соответствовать старому проекту.

  • Миграция проектов и исправление

После работы вышеуказанных шагов вы можете удалить оригинальную демонстрацию, перенести весь бизнес-код старого элемента. Далее посмотрите на ошибку, одно исправление. Я столкнулся с такой ямой здесь, и я давно устроил меня. Страница очень гладкая, и она будет работать плавно после полагаться на завершение.

Но переключение страниц в среде разработки всегда приводит к ошибке 404. Я думаю, все поймут, когда вы увидите это здесь.Я использовал маршрут режима истории.Эта строка конфигурации должна быть добавлена ​​​​на devServer.

devServer {
    historyApiFallback: true
}

Ну а после устранения 404 новая ситуация.Статические ресурсы всегда не ссылаются.Почему так? На самом деле это вызвано тем, что мы не указали publicPath при выводе, в dev’овском webpack.config мой вывод настроен так

output: {
    path: path.resolve('dist'),
    publicPath: '/'
},
// ...
devServer = {
    contentBase: './dist',
    port: 9000,
    historyApiFallback: true
}

После решения этой проблемы наша среда разработки практически восстановлена. Далее пришло время ступить на упаковочную яму.Первая проблема, с которой я столкнулся, это то, что после того, как упаковка была завершена, в папке был только вывод упаковки, а index.html пропал... Это не то же самое. Позже выяснилось, что он пропалcopy-webpack-plugin

const CopyWebpackPlugin = require('copy-webpack-plugin')
const config = {
    // ...
    plugins: [
        new CopyWebpackPlugin([{from: 'public', to: ''}])
    ]
}

После добавления этой зависимости содержимое нашей общей папки послушно появится в дистрибутиве. Но тут появилась новая проблема: когда пакет был запакован во второй раз, почему дистрибутив не опустел? То же, что и выше, в младшем возрасте я использую на один плагин меньшеclean-webpack-plugin

const CleanWebpackPlugin = require('clean-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')

let cleanOptions = {
    root: path.join(__dirname, '..'),
    verbose: true,
    dry: false
}

const config = {
    // ...
    plugins: [
        new CleanWebpackPlugin(['dist'], cleanOptions),
        new CopyWebpackPlugin([{from: 'public', to: ''}])
    ]
}

После выполнения приведенной выше настройки папка dist будет очищаться каждый раз при упаковке веб-пакета, а после завершения упаковки общедоступный контент будет скопирован в папку dist. Ну, вроде бы все должно быть ок, но когда я открыл сервер локально для запуска страницы, я обнаружил, что различные статические ресурсы были 404. Что за чертовщина? Честно говоря, здесь больше всего времени уходит на то, чтобы наступить на яму, но решение удушающе простое... Виню себя, что невнимательно читал документацию

const CleanWebpackPlugin = require('clean-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')

let cleanOptions = {
    root: path.join(__dirname, '..'),
    verbose: true,
    dry: false
}

const config = {
    output: {
        filename: 'static/js/[name].[chunkhash:8].js',
        chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
        publicPath: 'http://localhost:5000/' // !!!这里一定要使用绝对路径,不然就会被坑到
    }
    // ...
    plugins: [
        new CleanWebpackPlugin(['dist'], cleanOptions),
        new CopyWebpackPlugin([{from: 'public', to: ''}])
    ]
}

Суммировать

Ну, я не знаю, сколько студентов это увидят.Спасибо, во-первых, что смотрите, как я тут много придираюсь~ Я видел много различных схем оптимизации в Интернете, но, похоже, все только говорят о схеме, а делают не требует практики.Когда я на самом деле пошел играть, я обнаружил, что оптимизация не так проста, как я себе представлял. Необходимо учитывать оригинал, и стараться использовать более новые и лучшие. Много раз мы будем выбирать между трещины.

Кстати, кажется, я забыл лениво загрузить оптимизированный образ (или упакованный wp2), эффект может быть не таким идеальным, как я себе представлял, но это очень трудный шаг вперед :)

На самом деле существует очень много вещей, которые можно оптимизировать: запросы, бизнес и даже написание кода — все это можно оптимизировать, но как это сделать за одну ночь? Вам все еще нужно сделать шаг, посмотреть на шаг и выбрать план оптимизации, который наиболее подходит для вашего собственного проекта, это лучший план ~