Объяснение современного JavaScript для динозавров

0
8691

Статья помещает вас в хронологию развития JavaScript, от самого просто сайта до современного положения дел в области frontend и современного JavaScript в частности.

Изучение современного JavaScript, является довольно трудной задачей, если вы не следили за его историей развития. Экосистема постоянно растет и изменяется настолько стремительно, что трудно понять те проблемы, которые разработчики пытаются разрешить с помощью различных инструментов. Я начал программировать еще в 1998 году, но серьезно изучать JavaScript стал только в 2014 году. В свое время, помнится мне, заходил я на Browserify и смотрел на их слоган:

«Browserify предоставляет вам возможность запрашивать (‘модули’) в браузере, объединяя все ваши зависимости.»

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

Целью данной статьи является предоставление исторического контекста того, как развивались инструменты современного JavaScript, и что они представляют из себя сейчас, в 2017 году. А начнем мы с самого начала и создадим пример веб-сайта, как это сделали бы динозавры, не имея каких-либо инструментов, используя просто HTML и JavaScript. Затем мы, постепенно, будем добавлять различные инструменты для того, чтобы увидеть, как каждый из них решает поставленные задачи. Благодаря этому историческому контексту, вам будет легче изучать и адаптироваться, под постоянно меняющийся пейзаж современного JavaScript, вы будете просто продвигаться вперёд. Приступим!

Old-school способ использования современного JavaScript

Давайте начнем с построения old-school сайта, используя только HTML и JavaScript. Данное построение будет включать в себя ручную загрузку и связывание файлов. Ниже приведен просто index.html файл, который связан с JavaScript-файлом:

Строка <script src=»index.js»></script> ссылается на отдельный JavaScript-файл, который расположен в той же директории и имеющий название index.js:

Это все что вам нужно для того, чтобы создать сайт! Теперь, давайте представим, что мы хотим добавить библиотеку, которую кто-то другой, любезно, написал. Например, пусть это будет moment.js (библиотека, помогающая преобразовать время в человеческий вид). К примеру, вы можете использовать moment — функцию современного JavaScript, как показано ниже:

Однако вы можете только предполагать, что подключили библиотеку moment.js к своему сайту! На домашней странице moment.js вы можете увидеть следующую инструкцию:

Хмм, в разделе «Установка», который располагается справа, есть много всего. Но давайте пока, просто проигнорируем их. Мы можем добавить библиотеку moment.js к нашему сайту, просто скачав moment.min.js файл из той же директории, и включить его в наш index.html файл.

Обратите внимание, что moment.min.js загружается перед index.js, что означает вы можете использовать функцию moment в index.js, как показано ниже:

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

Использование менеджера пакетов JavaScript (npm)

Начиная примерно с 2010, несколько, конкурирующих между собой, менеджеров пакетов современного JavaScript, объединились для того, чтобы помочь автоматизировать процесс скачивания и обновления библиотек из одного центрального репозитория. Bower был, возможно, самым популярным в 2013 году, но в конечном счете его вытеснил npm, примерно в 2015 году. (Стоит отметить, что начиная с конца 2016 года, yarn приобрел популярность в качестве альтернативы интерфейсу npm, но пока все еще используется менеджер пакетов npm, из-за лучшей внутренней структуры.)

Обратите внимание, что изначально npm был создан в качестве менеджера пакетов специально для node.js – среда для выполнения современного JavaScript-кода на стороне сервера, а не на стороне клиента. Поэтому складывается довольно странный выбор для менеджера пакетов по отношению к библиотекам, которые должны выполняться в браузере.

Примечание: Использование менеджера пакетов, в основном, включается в себя использование командной строки, которая еще недавно не была необходимостью для frontend-разработчика. Если вы никогда не имели дело с командной строкой, то вы можете прочесть данный туториал, чтобы у вас появилось общее представление об этом и вы смогли начать ею пользоваться. Как бы там ни было, знание того, как пользоваться командной строкой является важной частью современного JavaScript. Кроме того, это также открывает для вас двери в другие области разработки.

Давайте посмотрим, как использовать npm для автоматической установки пакета moment.js, вместо того чтобы вручную скачивать его. Если вы уже установили node.js, то у вас уже установлен npm, что означает вы можете с помощью командной строки переместиться в папку с вашим файлом index.html и ввести следующее:

Далее перед вами появится несколько вопросов (пункты по умолчанию нас полностью устраивают, поэтому можем просто нажимать “enter” на каждый вопрос), и будет создан новый файл с названием package.json. Это конфигурационный файл, который npm использует для сохранения всей информации о проекте. По умолчанию файл package.json должен выглядеть, примерно, как показано ниже:

Теперь для установки современного JavaScript-пакета moment.js, мы можем следовать npm указаниям с домашней страницы этого менеджера пакетов, путём ввода следующей команды в командной строке:

Данная команда делает две вещи. Первое, скачивает весь код с пакета moment.js в папку с названием node_modules. Второе, автоматические модифицирует файл package.json для мониторинга за moment.js, получается зависимость для этого проекта.

 

Это будет полезно далее, когда мы будем делиться нашим проектом с другими. Вместо того, чтобы предоставлять доступ к папке node_modules (которая может быть достаточно большой), вам достаточно предоставить доступ к файлу package.json, после чего другие разработчики смогут автоматически скачать все необходимые пакеты, используя команду npm install.

Теперь нам больше не нужно вручную скачивать moment.js с сайта, мы можем автоматически скачать и обновит данный пакет, используя npm. Заглядывая внутрь папки node_modules, мы можем увидеть moment.min.js файл в директории node_modules/moment/min. Это означает, что мы можем привязать, скаченную через npm, версию файла moment.min.js к нашему файлу index.html, как показано далее:

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

Использование сборщика модулей в JavaScript (webpack)

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

По факту, в примерах выше (которые с moment.js) именно так и происходит. Загружается весь файл moment.min.js в наш HTML, в котором определена глобальная переменная moment, которая затем становится доступной для любого файла, загруженного после moment.min.js (в независимости от того, нужен ему доступ к этой переменной или нет).

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

Как было сказано ранее, node.js – это среда для выполнения JavaScript-кода на стороне сервера. Далее приведен пример того, как будет выглядеть код с использованием модулей node.js. Вместо загрузки всего moment.min.js файла с помощью тега <script></script>, вы можете загрузить его напрямую в JavaScript-файл, как показано ниже:

Опять же, это то, как работает загрузка модуля в node.js, и работает она отлично, поскольку node.js – это серверный язык с доступом к файловой системе компьютера. Node.js также знает расположение каждого npm-модуля, поэтому вместо того, чтобы писать require(‘./node_modules/moment/min/moment.min.js), вы можете просто написать require(‘moment’) – довольно симпатично.

Все это хорошо работает в node.js, однако если вы попробуете использовать код из примера выше в браузере, то получите сообщение об ошибке, в котором будет говорится, что запрос не определен. Браузер не имеет доступа к файловой системе, это означает, что загрузка модулей таким способ затруднительна. Загрузка файлов должна выполняться динамически, либо синхронно (что замедляет выполнение), либо асинхронно (могут возникнуть проблемы со временем).

Здесь нам как раз и нужен сборщик модулей. Сборщик модулей в JavaScript – это инструмент, который устраняет проблему с шагом построения (который имеет доступ к файловой системе) для того, чтобы создать окончательный результат совместимый с браузером (которому не нужен доступ к файловой системе). При этом, сборщик модулей нам также необходим, чтобы найти все запрашиваемые выражения (которые являются недопустимым JavaScript-синтаксисом для браузера) и заменяет их на действующее содержание каждого из запрашиваемых файлов. Окончательным результатом является единственный собранный JavaScript-файл (без запрашиваемых выражений)!

Самым популярным сборщиком модулей был  Browserify, релиз которого состоялся в 2011 году и поначалу во фронтенде использовался стиль запрашиваемых выражений из node.js (что по сути является тем, что позволило npm стать frontend менеджером пакетов по выбору). Примерно к 2015 году с течением времени webpack стал более широко используемым сборщиком модулей. Такое явление обусловлено по большему счету за счет популярности frontend-фреймворка React, который в полной мере воспользовался различными функциями webpack-а.

Давайте взглянем на то, как использовать webpack, чтобы получить вышеупомянутый require(‘moment’), который будет работать в браузере. Во-первых, нам необходимо установить webpack в наш проект. Сам по себе webpack – это npm-пакет, поэтому мы можем установить его, используя командную строку:

Обратите внимание на аргумент —save-dev – это сохранение его в качестве зависимости для разработки, что означает пакет, который вам необходим только в среде разработки, а не на вашем рабочем сервере. Все изменения вы можете наблюдать в файле package.json, который автоматически обновляется:

Теперь мы установили webpack, как один из пакетов в папке node_modules. Вы можете использовать webpack из командной строки, как показано ниже:

Эта команда запустит инструмент webpack, который был установлен в папку node_modules. После чего, начиная с файла index.js, webpack найдет все выражения require, и заменит их на соответствующий код для создания единого выходного файла с названием bundle.js. Это означает, что мы больше не будем использовать index.js в браузере, так как он содержит некорректные выражения require. Вместо этого, будем использовать выходной файл bundle.js, который должен быть добавлен в наш файл index.html:

Если вы перезагрузите страницу, то увидите, что все работает, как и прежде!

Заметьте, что нам необходимо запускать webpack каждый раз, как мы меняем index.js. Этот процесс утомителен, и он станет еще более трудозатратным, как только мы начнем использовать более продвинутые возможности webpack (например, генерирование карт кода, предназначенных для помощи в отладке исходного кода из переданного кода). Webpack может считывать параметры из файла конфигурации, расположенного в корневой директории проекта, сам файл называется webpack.config.js, который в нашем случае будет выглядеть так:

Теперь каждый раз, как мы вносим изменения в index.js, необходимо запускать webpack с помощью следующей команды:

Нам больше не нужно указывать index.js и bundle.js параметры, поскольку webpack подгружает эти параметры из конфигурационного файла webpack.config.js. Уже лучше, однако, все еще утомительно вводить каждый раз эту команду при каждом изменении кода. Сделаем этот процесс более легким.

Все это может показаться каким-то сомнительным, но для организации рабочего процесса это имеет несколько огромных преимуществ. Нам больше не нужно загружать внешние скрипты через глобальные переменные. Любая новая JavaScript-библиотека будет добавлена с помощью выражения require, вместо того чтобы каждый раз добавлять теги <script> в наш HTML. Наличие одного современного JavaScript-файла с пакетами – всегда лучше для производительности. И теперь, когда мы добавили шаг построения, можем приступить к некоторым другим мощным возможностям, которые мы можем добавить к нашему рабочему процессу!

JavaScript

Транспайлинг кода для новых возможностей языка (babel)

Транспайлинг кода означает преобразование кода из одного языка программирования в другой схожий язык, с той лишь разницей, что у результата примерно тот же уровень абстракции, что и у исходного текста (например, транслятор из Java в C++). Это является важной составляющей frontend-разработки. В силу того, что добавление нового функционала в браузере происходит медленно, были созданы новые языки с экспериментальными функциями, которые производят компиляцию исходного кода в код на других языках программирования (транспайлинг), которые совместимы для работы в браузере.

Назовем несколько для CSS – это SassLess, и Stylus. Для JavaScript самым популярным транспайлером некоторое время был CoffeeScript (первый релиз был в 2010 году), тогда как в настоящее время разработчики используют babel или TypeScript. CoffeeScript – это язык программирования, целью которого является улучшение современного JavaScript за счет значительного изменения языка (использование дополнительных круглых скобочек, значительно большого количества пробелов и т.д.). Babel – это не новый язык программирования, а транспайлер, который преобразует JavaScript следующего поколения, со всеми новыми функциями, недоступными для всех браузеров (ES2015 и выше), до более старого стандарта JavaScript (ES5). Typescript – это язык программирования, который чрезвычайно идентичен JavaScript-у следующего поколения, также добавляющий статическую типизацию (опционально). Многие делают выбор в пользу использования Babel, так как он наиболее близок к первоначальному JavaScript.

Давайте посмотрим на пример того, как нужно использовать babel в сочетании с нашим webpack-ом на текущем этапе сборки. Во-первых, нужно установить babel (который также является npm-пакетом) в наш проект с помощью командной строки:

Необходимо отметить, что мы устанавливаем 3 отдельных пакета, каждый в качестве зависимости для разработки. Основной частью babel является babel-core, babel-preset-env – это предварительное определение того, что из нового современного JavaScript-функционала подвергать транспайлингу, и babel-loader – это пакет, позволяющий babel работать вместе с webpack. Мы можен сконфигурировать webpack с помощью babel-loader путем изменения файла webpack.config.js, так как показано ниже:

Такой синтаксис может смутить вас (к счастью, нам не придется редактировать подобное очень часто). По факту, мы говорим инструменту webpack, чтобы он нашел любые js-файлы (исключая из поиска файлы из директории node_modules) и применил к ним babel-транспайлинг с помощью babel-loader вместе с babel-preset-env. Вы можете более подробно ознакомиться с синтаксисом конфигурации webpack здесь.

Теперь, когда все настроено, мы можем начать писать ES2015-функции в нашем JavaScript! Далее приведен пример шаблонной строки ES2015 в файле index.js:

Мы также можем использовать ES2015 выражение import вместо require для загрузки модулей, которые вы уже неоднократно видели в примерах кода:

В представленном выше примере, синтаксис выражения import не сильно отличается от require, но import обладает большей гибкостью для более сложных случаев. Из-за того, что мы изменили index.js нам необходимо снова запустить webpack из командной строки:

После этого мы можем обновить index.html в браузере. На момент написания этой статьи, большинство современных браузеров имеет поддержку всех возможностей стандарта ES2015, поэтому трудно сказать выполнил ли babel свою задачу. Вы можете протестировать это, используя более старые версии браузеров, например, с помощью IE9, или же найти следующую строку преобразованного кода в файле bundle.js:

В этом примере вы можете увидеть транспайлинг с помощью babel шаблонной строки стандарта ES2015 в обычную JavaScript-строку, представленную в виде конкатенации строк для совместимости с браузером. Возможно данный пример не такой наглядный, но возможность транспайлинга кода – это очень мощный инструмент. Существует несколько действительно классных языковых фич, которые пришли в JavaScript, например, механизм async/await, и все эти возможности вы можете использовать уже сегодня для того, чтобы писать более грамотный код. И хотя транспайлинг, в некоторых моментах, может показаться громоздким и сложным, данный процесс привел к резкому улучшению языка за последние несколько лет, и конечно же большой вклад вносят разработчики, которые тестируют сегодня, то что появится только завтра.

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

Использование средства запуска задач (npm-скрипты)

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

В 2013 году самым популярным средством для запуска задач являлся Grunt, впоследствии это стал Gulp. Оба этих средства основывались на плагинах, которые оборачивали другие инструменты командной строки. На сегодняшний день самым популярным выбором является использование возможностей скриптов, которые встроены в менеджер пакетов npm. Они не используют обёртку для того чтобы использовать инструменты командной строки, вместо этого просто напрямую используют их.

Что же напишем несколько npm-скриптов, чтобы сделать использования webpack более простым. Для этого немного изменим файл package.json, как показано ниже:

Здесь мы добавили два новых скрипта build и watch. Для запуска, созданных скриптов, вы можете использовать командную строку, введя в нее следующее (для скрипта build):

Это строка запустит webpack, используя конфигурацию из webpack.config.js, которую мы создали ранее. Аргумент —progress показывает состояние прогресса в процентах, а аргумент -p минимизирует код для большей производительности. Для запуска скрипта watch введите следующее:

Здесь используется аргумент —watch, вместо автоматического перезапуска webpack-а, каждый раз, когда происходит изменение в каком-либо JavaScript-файле, что просто отлично для frontend-разработчика.

Обратите внимание, что наши скрипты, расположенные в файле package.json, могут запускать webpack без наличия полного пути ./node_modules/.bin/webpack, потому что node.js знает расположение каждого npm-модуля. Просто замечательно! Однако мы можем сделать все ещё более замечательно путем установки webpack-dev-server – отдельный инструмент, предоставляющий простой веб-сервер с live-перезагрузкой. Для его установки в качестве зависимости для разработки введите следующую команду:

После чего добавим npm-скрипт в package.json:

Теперь вы можете запустить ваш dev-сервер с помощью следующей команды:

Эта команда автоматически откроет наш index.html сайт в браузере, который будет иметь дефолтный адрес localhost:8080. Когда бы вы не меняли ваш index.js файл, webpack-dev-server перестроит свой JavaScript-сборщик и автоматически обновит страницу в браузере. Получается удивительно полезная экономия времени, поскольку она позволяет вам больше концентрироваться на коде, а не на постоянном переключении содержимого браузера и кода, для того чтобы вовремя видеть все внесенные изменения.

Но это только верхушка айсберга и мы далеки от понимания сути вопроса. Возможностей у webpack и webpack-dev-server намного больше, о которых вы можете прочитать здесь. Вы также можете множество npm-скриптов под любые свои нужды, к примеру, для преобразования Sass в CSS, сжатия изображения, запуска различных тестов – для всего, что может использовать командную строку – абсолютно справедливая игра. Кроме того, сами по себе npm-скрипты обладают множеством продвинутых возможностей и фич предназначенных для помощи современного JavaScript, для того чтобы начать в них разбираться рекомендуем следующее видео от Kate Hudson:

Заключение

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

Тем не менее, это не так плохо, как кажется. Со временем любые вещи стабилизируются, не малый вклад в это внесла node-экосистема, которая является эффективным способом работу с фронтендом. Логично и приятно использовать: npm в качестве менеджера пакетов, node-выражения require или import для работы с модулями, и npm-скрипты в качестве средства запуска задач. Это значительно упростило рабочий процесс в сравнении с тем, что было два или даже год назад!

Скорее всего тенденция к частому изменению это даже хорошо как для начинающих, так и для опытных разработчиков. Почему так? Потому что как для одних, так и для других фреймоврки часто обновляются, тем самым появляются новые инструменты/фичи, упрощающие рабочий процесс. Например, Ember имеет ember-cli, который в значительной степени повлиял на angular-cli – интерфейс командной строки  от Angular, React имеет create-react-app, Vue имеет vue-cli и так далее. С помощью всех этих инструментов можно наполнить проект всем что вам нужно, все что от вас требуется – это начать писать код. Тем не менее, эти инструменты не являются какой-то магией, они просто все последовательно устанавливают в ваш проект, но это не означает, что вы не сможете в нужный вам момент вручную что-либо дополнительно настроить с помощью webpack, babel и т.д. Поэтому очень важно понять, что делает каждая из частей, которую мы разобрали в данной статье.

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

Другие материалы по теме

62 лучших видео для тех, кто хочет углубить знания в JavaScript
Как понять, что у тебя глубокие знания в JavaScript
10 вещей, которые стоит знать каждому JavaScript-разработчику
Лучшие JavaScript фреймворки, библиотеки и инструменты в 2017

Ссылка на оригинальную статью
Перевод: Александр Давыдов