Было время, когда фронтенд-разработчики считали хорошей практикой использовать jQuery для всего. В то время мы начали создавать веб-приложение Trayn. С тех пор многое изменилось, в том числе и то, что считается хорошей практикой. Что ж, лучшие практики в области JavaScript меняются каждый второй месяц или около того, но хорошо в этом случае мне достаточно.

В продолжающейся борьбе за модернизацию нашей кодовой базы я недавно начал поэтапно отказываться от jQuery. Что я имею в виду под поэтапным отказом? Приложение слишком большое, чтобы за один раз переписать весь код, основанный на jQuery. Но так как базовый функционал приложения (управление сессиями, маршрутизация, локализация и т.д.) уже был модернизирован в последние месяцы, то только детальные представления (их много) используют jQuery и различные его плагины. Итак, план состоит в том, чтобы портировать/модернизировать одно из этих представлений за другим.

Но почему?

Зачем вообще удалять jQuery? Он все еще работает…

Что ж, мы хотим удалить не только jQuery, но и дополнительные плагины и фреймворки, а точнее — то, как мы их используем. Огромные части этих представлений используют устаревшие версии can.js, Bootstrap и FullCalendar, и одновременное обновление всего этого кода кажется более сложным, чем миграция представления за представлением на более современную компонентную архитектуру.

Укрощение наших плагинов jQuery

Использование плагинов jQuery вместе с Webpack может быть затруднительным, поскольку они обычно регистрируют их в любом экземпляре jQuery, к которому они относятся. Поскольку Webpack помещает все в свою собственную область видимости, каждый плагин окажется в другом экземпляре jQuery. Чтобы справиться с этим, Webpack предоставляет параметр конфигурации externals, который можно использовать для исключения некоторых пакетов из сборки, если они загружены откуда-то еще. Это позволяет нам использовать один глобальный экземпляр jQuery и не ломать плагины.

Кроме того, мы копируем уменьшенный файл jQuery в наш выходной каталог для последующего использования:

// webpack.config.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = {
  externals: {
    jquery: 'jQuery'
  },
  plugins: [
    new CopyWebpackPlugin([{ from: 'node_modules/jquery/dist/jquery.min.js'}])
  ]
}

Использовать jQuery или не использовать jQuery?

Это оставляет проблему фактической загрузки jQuery, когда это необходимо. Попробовав некоторые вещи, я решил сделать это на нашем уровне маршрутизации, который использует Vue Router. Я добавил логический флаг jquery в поле meta маршрутов, которые все еще используют устаревший код. Проверяем его в хуке beforeEach: если флаг присутствует, навигация блокируется до загрузки jQuery. Мы не можем использовать здесь import() или require(), потому что мы проинструктировали Webpack рассматривать jQuery как внешнюю зависимость, поэтому мы используем scriptjs:

import $script from 'scriptjs'
const ensurejQuery (route) => new Promise((resolve) => {
  if(route.matched.some(record => record.meta.jquery)) {
    $script('/jquery.min.js', resolve)
  } else {
    resolve()
  }
})
router.beforeEach((to, from, next) => {
  ensurejQuery(to).then(next)
})

Вывод

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

А слово «jQuery» я употребил в этой статье всего 15 раз (не считая заголовков и примеров кода), не придумав для него никаких псевдонимов.