Дату основания города принято считать с первого заложенного камня. Начало фронтенд проекта в 2020 можно считать с выполнения npm install. И точно так же, как и в бурно растущем городе, обрастающем как крупными проспектами, так и мелкими переулками, в проект попадают новые пакеты, за которыми следуют пакеты поновее. Вот только если местные жители знают каждую улочку рядом с домом, большинство из нас понятия не имеет, что попадает в папку node_modules/.

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

Насколько вкусный сыр в мышеловке?

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

А ещё программисты не любят велосипеды и при первой же возможности переводят их на другой фреймворк или даже язык (но это всё равно байки).

Особенно популярные пакеты кроме уже готового кода предоставляют в подарок пропуск в собственную экосистему, что резко увеличивает шансы найти решение очередной проблемы или нанять разработчика, который уже знаком с немалой частью проекта, описанной в package.json.

Поэтому в теории npm — идеальное место для идеального кода.

Но это не так

Эта фраза вынесена в заголовок и выделена жирным, хотя ни для кого не секрет, что идеального кода там нет, а я просто нагоняю пафос. Однако насколько именно этот код далёк до совершенства и должен ли он к нему стремиться?

Всё же, что не так с нашим списком зависимостей?

Мы теряем контроль

Количество пакетов в node_modules/ уже исчисляется тысячами, порой для этого достаточно установить всего один. Верить в то, что обновление одной библиотеки на n-ном уровне вложенности не уронит проект с каждым выполненным npm install всё труднее. И когда это произойдет, нам останется только смотреть на падающие сборки и комментарии на гитхабе.

Порой необходимая функциональность нашей библиотекой просто не поддерживается. Ещё хуже, если она вообще не входит в планы и/или идеологию ее мейнтейнеров. Остается только заполнять пулреквест, который может так и не попасть в мастер, или делать форк и поддерживать его самостоятельно, теряя плюсы готового кода (кстати, форк почему-то выбирают реже).

Мы грузим слишком много

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

Как сделать лучше?

Подключая новый пакет, стоит понимать, какую именно проблему мы собираемся решить перед тем, как создать несколько новых. Если добавление зависимости обусловлено в основном тем, что про неё много пишут в Твиттере — это плохой подход.

Узнать что именно мы грузим

Код lodash/debounce занимает около 130 строк и поддерживает 3 параметра, про которые в большинстве случаев можно даже и не знать. Этот метод покрывает как можно больше случаев и настолько раздут, что lodash/throttle использует его же. В основной массе проектов потребность в отложенном выполнении кода можно закрыть простой реализацией в 7 строк.

В добавок, кроме действительно полезных функций, lodash предоставляет методы mapfiltersome и многие другим, которые уже давно являются частью JavaScript и неизменно присутствуют в ежегодных топах «10 методов массивов, про которые вы не слышали». Вместо изучения документаций многочисленных библиотек стоит хорошо узнать возможности, предоставляемые браузерами.

Поиск значений через indexOf === -1 легко заменяется на includes/startsWith/endsWith, а вместо lodash/get можно использовать chaining-operator.

Настроить сборщик

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

"size-limit": [
    {
      "limit": "60 s",
      "path": "dist/app.js"
    }
  ]

Если приложение грузится дольше минуты, мы вовремя узнаем об этом!

Чтобы этот момент не наступал как можно дольше, стоит отслеживать крупные модули с помощью webpack-bundle-analyzer:

Классические локали moment.js, которые высасывают бюджет бандла просто потому, что мы забыли их отключить.

Также некоторые из зависимостей в проекте могут использовать одну и ту же библиотеку, но подключать ее по-разному, из-за чего код в бандле дублируется. Например, один пакет подключает lodash, другой использует lodash-es, в итоге в бандле — оба. Правильно настроив сборщик, можно избавиться от лишних килобайт.

Одна и та же зависимость может подключаться в нескольких версиях, в примере ниже выделены core-js 1.2.7, 2.5.3 и 3.3.4.

Большинство популярных библиотек имеют окно для оптимизаций, которые достаточно просто применить, чтобы минимизировать их вклад в размер бандла. Полный список — в репозитории Google Chrome Labs. Больше советов по увеличению производительности — на канале Ивана Акулова.

Как контролировать список зависимостей?

Стоит признаться самим себе, что нам не нужно столько оболочек и посредников между программистом и кодом.

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

И нам точно не нужен лендинг на React.js, просто потому что всё остальное написано на нём же. Конечно, не стоит полностью изолироваться от мира и npm, но стоит чаще задумываться о том, что мы ставим в проект, и действительно ли нужно именно это.

Однако современный JavaScript достаточно выразителен, чтобы заменить им устаревшие библиотеки:

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


«Доктайп» — журнал о фронтенде. Читайте, слушайте и учитесь с нами.

ТелеграмПодкастБесплатные учебники

Читать дальше

Ошибка JavaScript «Uncaught TypeError: Cannot read property of undefined». Что делать?

Описание проблемы
Эта ошибка возникает, когда вы пытаетесь получить доступ к свойству объекта, который в данный момент имеет значение undefined. Например:


let obj = undefined;
console.log(obj.property); // Uncaught TypeError: Cannot read property 'property' of undefined
  

Возможные причины

  • Объект не был инициализирован. Возможно, переменная еще не была объявлена или ей не присвоено значение.
  • Неправильный путь к данным. Вы пытаетесь обратиться к свойству объекта, но объект отсутствует в цепочке.
  • Асинхронность. Данные могли еще не загрузиться или быть доступны в момент обращения.
  • Опечатка в названии свойства. Вы могли неверно написать имя свойства объекта.

Шаги по исправлению

1. Проверка объекта перед доступом к свойствам

Убедитесь, что объект существует, прежде чем пытаться получить его свойства.

if (obj !== undefined && obj !== null) {
    console.log(obj.property);
}

// Или современный способ:
console.log(obj?.property); // Вернет undefined, если obj равен null или undefined
  

2. Инициализация объекта перед использованием

Если переменная должна содержать объект, убедитесь, что он инициализирован.

Неверный код:

let data;
console.log(data.user.name); // Ошибка
  

Исправление:


let data = { user: { name: "Иван" } };
console.log(data.user.name); // "Иван"
  

3. Проверка API или данных с сервера

Если данные загружаются с сервера, добавьте проверку, что ответ корректен.

fetch('https://api.example.com/data')
    .then(response => response.json())
    .then(data => {
        if (data?.user?.name) {
            console.log(data.user.name);
        } else {
            console.error('Данные пользователя отсутствуют');
        }
    });

4. Использование значений по умолчанию

Для предотвращения ошибок можно задавать значения по умолчанию.

let user = undefined;
let userName = user?.name || "Гость";
console.log(userName); // "Гость"

5. Отладка с помощью console.log

Проверяйте промежуточные значения переменных в консоли браузера.

console.log(obj); // Убедитесь, что объект определен 

Пример из жизни
Вы пишете код для отображения имени пользователя из объекта user:

let user = null; // Данные еще не загружены
console.log(user.name); // Uncaught TypeError: Cannot read property 'name' of null

Исправление:

let user = null;
console.log(user?.name || "Имя пользователя не найдено"); // "Имя пользователя не найдено"

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

JS
  • 15 ноября 2024

Как исправить ошибку JavaScript «Uncaught ReferenceError: variable is not defined»

Эта ошибка возникает, когда вы пытаетесь обратиться к переменной, которая не была объявлена в текущей области видимости. Например:

console.log(myVariable); // Uncaught ReferenceError: myVariable is not defined

Возможные причины

  • Вы пытаетесь обратиться к переменной до ее объявления.
  • Переменная объявлена внутри функции и недоступна за ее пределами.
  • Ошибка в написании имени переменной (опечатка).

Шаги по исправлению

1. Проверка объявления переменной

Убедитесь, что переменная объявлена перед ее использованием.

Неверный код:

console.log(myVariable); // Ошибка

Исправление:

let myVariable = 10;
console.log(myVariable); // 10

2. Правильное определение области видимости переменной

Если переменная объявлена внутри функции, она недоступна за ее пределами.

Неверный код:

function myFunction() {
    let localVariable = "Привет";
}
console.log(localVariable); // Ошибка

Исправление:

function myFunction() {
    let localVariable = "Привет";
    console.log(localVariable); // "Привет"
}
myFunction();

3. Использование глобальных переменных

Если переменная должна быть доступна везде, объявляйте ее глобально (но избегайте этого, если возможно).

let globalVariable = "Глобальная переменная";
function showVariable() {
    console.log(globalVariable);
}
showVariable(); // "Глобальная переменная"

4. Проверка имени переменной на ошибки

Проверьте, нет ли опечаток в имени переменной.

Неверный код:

let myVariable = "Данные";
console.log(myVarible); // Ошибка

Исправление:

let myVariable = "Данные";
console.log(myVariable); // "Данные"

5. Использование typeof для проверки существования переменной

Вы можете использовать оператор typeof, чтобы проверить, объявлена ли переменная.

if (typeof myVariable !== "undefined") {
    console.log(myVariable);
} else {
    console.log("Переменная не определена");
}

Пример из жизни
Вы пишете функцию для проверки данных пользователя:

function checkUser() {
    if (userName) {
        console.log(`Добро пожаловать, ${userName}!`);
    }
}
checkUser(); // Ошибка: userName не определен

Исправление:

let userName = "Иван";
function checkUser() {
    if (userName) {
        console.log(`Добро пожаловать, ${userName}!`);
    }
}
checkUser(); // "Добро пожаловать, Иван!"

Итог
Эта ошибка часто возникает из-за опечаток или неверной области видимости. Убедитесь, что переменные объявлены и доступны в нужных местах. Если необходимо, используйте typeof для проверки их существования.

JS
  • 15 ноября 2024

Как исправить ошибку JavaScript «Uncaught TypeError: Cannot set property of undefined»

Эта ошибка возникает, когда вы пытаетесь присвоить значение свойству объекта, который не существует (имеет значение undefined или null). Например:

let obj;
obj.property = "value"; // Uncaught TypeError: Cannot set property 'property' of undefined

Возможные причины

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

Шаги по исправлению

1. Инициализация объекта перед использованием

Убедитесь, что объект объявлен и инициализирован перед тем, как вы присваиваете его свойствам значения. Неверный код:

let obj;
obj.property = "value"; // Ошибка

Исправление:

let obj = {};
obj.property = "value"; // Работает

2. Проверка существования объекта перед доступом

Проверяйте объект на null или undefined, чтобы избежать ошибок. Пример:

let obj;
if (obj) {
    obj.property = "value";
} else {
    console.log("Объект не определен");
}

3. Использование опциональной цепочки

Если ошибка возникает в глубоко вложенных объектах, используйте опциональную цепочку. Пример:

let obj;
obj?.nestedProperty?.subProperty = "value"; // Не вызовет ошибку

4. Проверка асинхронных данных

Если объект формируется после загрузки данных, убедитесь, что данные доступны перед их использованием.

let obj;
setTimeout(() => {
    obj = { property: "value" };
    console.log(obj.property); // Работает
}, 1000);

// Нельзя обращаться к obj до инициализации:
console.log(obj.property); // Ошибка

Пример из жизни
Вы загружаете данные пользователя с сервера и пытаетесь установить свойство объекта:

let user;
user.name = "Иван"; // Ошибка

Исправление:

let user = {};
user.name = "Иван"; // Работает

Итог
Чтобы избежать ошибки «Cannot set property of undefined», убедитесь, что объект существует и инициализирован. Используйте проверки на null, опциональную цепочку или инициализируйте объект перед работой с его свойствами.

JS
  • 15 ноября 2024

Как исправить ошибку JavaScript «Uncaught SyntaxError: Unexpected token»

Эта ошибка возникает, когда интерпретатор JavaScript сталкивается с неожиданным токеном (символом) в коде, который нарушает синтаксические правила. Например:

let obj = { key: "value", }; // Uncaught SyntaxError: Unexpected token }

Возможные причины

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

Шаги по исправлению

1. Проверка корректности синтаксиса

Убедитесь, что все запятые, точки с запятой и кавычки находятся на своих местах. Неверный код:

let obj = { key: "value", }; // Лишняя запятая

Исправление:

let obj = { key: "value" }; // Правильный синтаксис

2. Проверка закрытия скобок

Проверьте, закрыты ли все фигурные, круглые и квадратные скобки. Неверный код:

if (true {
    console.log("Ошибка!");
}

Исправление:

if (true) {
    console.log("Исправлено!");
}

3. Проверка типов кавычек

Не смешивайте одинарные и двойные кавычки. Неверный код:

let str = "Привет'; // Ошибка

Исправление:

let str = "Привет"; // Или let str = 'Привет';

4. Использование отладчика

Откройте консоль браузера или отладчик в вашей IDE, чтобы найти строку с ошибкой. Она будет указана в сообщении об ошибке.

// В консоли может быть указано:
Uncaught SyntaxError: Unexpected token } at script.js:10

Исправьте строку, где произошла ошибка.

5. Проверка работы кода в строгом режиме

Добавьте "use strict"; в начало вашего файла или функции, чтобы браузер проверял ваш код на соответствие строгому синтаксису.

"use strict";
let obj = { key: "value" };
console.log(obj);

Пример из жизни
Вы пытаетесь использовать стрелочную функцию, но забыли закрыть скобки:

const add = (a, b => {
    return a + b;
};

Исправление:

const add = (a, b) => {
    return a + b;
};

Итог
Чтобы избежать ошибок «Unexpected token», всегда проверяйте синтаксис вашего кода на наличие лишних или пропущенных символов, используйте инструменты отладки и следите за правильным использованием конструкций JavaScript.

JS
  • 15 ноября 2024
9 книг по JavaScript для начинающих в 2024

9 книг по JavaScript для начинающих в 2024

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

Мы опросили знакомых разработчиков, узнали, что читают они сами, и предлагаем вам подборку хороших книг по JavaScript.

Читать дальше
JS
  • 6 марта 2024
Объект URL в JavaScript: полный разбор

Объект URL в JavaScript: полный разбор

Объект URL в JavaScript представляет URL-адрес и предоставляет удобные методы для работы с ним. Он позволяет анализировать, конструировать и декодировать URL-адреса.

Создать объект URL можно двумя способами:

Конструктор URL() — самый распространённый способ, в котором вы передаёте любой URL в виде строки в качестве аргумента.

const url = new URL("https://www.example.com/path?query=123#hash");

Использование window.location — это глобальный объект в браузерах, который содержит информацию о текущем URL.

const currentUrl = new URL(window.location.href);
Читать дальше
JS
  • 23 января 2024
Знакомство с JavaScript

Знакомство с JavaScript

Теперь, когда вы знаете, как создать структуру веб-страницы с помощью HTML и оформить ее стилями с помощью CSS, пришло время оживить её с помощью JavaScript (JS). JavaScript — это мощный язык программирования, который используется для создания интерактивных и динамических веб-сайтов.

Вы можете добавить JavaScript в ваш HTML-документ двумя способами:

Встроенный JavaScript: непосредственно в HTML-документ, в тегах <script>:

<script>
  alert("Привет, мир!");
</script>

Внешний JavaScript: подключение внешнего .js файла к HTML-документу:

<script src="script.js"></script>
Читать дальше
JS
  • 1 ноября 2023