Отказ от ответственности: я написал это довольно поспешно в немного свободного времени между праздниками. Надеюсь, вы уловили суть. Если нет, я попытаюсь проиллюстрировать свою идею более практическим примером в будущем. Спасибо! 👋

Одна вещь, которую можно сказать наверняка о JavaScript, это то, что у него быстро развивающаяся экосистема и разнообразное сообщество. Большая часть вселенной JavaScript посвящена инструментам. В прошлом году эта тема получила некоторую негативную огласку из-за того, что была слишком чрезмерной. Напомните себе, что вам не нужно отслеживать каждое изменение и каждую новую идею. Учитесь, когда у вас есть время учиться и использовать то, что полезно для вас, а не для других. ✌️ Мне лично очень нравится эта экосистема, потому что люди, стоящие за ней, такие креативные — даже если не каждая идея стоит на практике. В этой статье я хотел бы поместить свое видение будущего инструментов JavaScript в океан идей о инструментах внешнего интерфейса.

Немного истории

Сначала немного предыстории обо мне: я начал следить за инструментами JavaScript и Frontend с момента появления Grunt. Grunt очень помог мне изучить Node и терминал, а также вывести мой фронтенд-проект на новый уровень. Не обошлось и без сбоев, поэтому я отслеживал каждое популярное решение, появившееся после этого: Gulp, npm-скрипты, Broccoli и так далее. Мы довольно рано использовали препроцессор CSS, а также внедрили Babel, когда он был совсем новым. В настоящее время мы являемся счастливыми пользователями TypeScript и Webpack. В нашей компании мы используем оболочку для всех этих инструментов, поэтому мы можем изменять фреймворки в фоновом режиме, не меняя много нашего интерфейса для их использования. Большинство изменений не замечаются нашими пользователями. На мгновение игнорируя создание наших проектов, другие части нашей истории инструментов были сосредоточены на линтерах, тестах и ​​управлении документацией и проектом в целом (журналы изменений, развертывание и т. д.).

Наибольшее влияние на мир инструментов JavaScript за последние годы, вероятно, оказало появление Babel. (По очень веским причинам!) Будучи немного спорным (из-за его сложности на первый взгляд), мне очень нравится Webpack и концепция его загрузчиков, потому что он позволяет мне решать проблемы, которые я не мог решить раньше. Но есть одна менее известная вещь, которая, я думаю, окажет наибольшее влияние на инструменты в целом в долгосрочной перспективе: протокол языкового сервера. Этот протокол был разработан Microsoft для TypeScript. Он поддерживает несколько функций, которые вы знаете и любите из продвинутых IDE, таких как рефакторинг, завершение кода и т. д., но в абстрактном виде, чтобы его можно было легко адаптировать к другим языкам и чтобы его можно было легко интегрировать во множество различных редакторов.

Возможное будущее

Линтеры

MicroSoft разработала несколько языковых сервисов, реализующих протокол языкового сервера для VS Code (например, для HTML и CSS), и другие делают то же самое (например, для Rust и Java). Интересно, что даже поддержка линтеров в VS Code реализована как языковой сервис. ИМХО идея интересная! Подумайте об этом: вы автор библиотеки, который хочет перейти на новую основную версию и объявить функцию устаревшей. В настоящее время автор библиотеки обычно ставит console.warn в эту функцию, и если кто-то использует эту функцию, разработчик увидит это предупреждение в консоли. Но вы знаете, что это можно легко упустить из виду, когда это происходит во время выполнения. Вот почему мы хотим анализировать наш код статически и в первую очередь использовать линтеры или что-то вроде потока или TypeScript. Однако в настоящее время нам нужно установить для этого другую зависимость и настроить ее вручную (например, tslint-react, который не поддерживается самими разработчиками React).

Представьте себе: TypeScript может легко подобрать типизацию, опубликованную либо авторами оригинальной библиотеки, когда они ссылаются на объявления внутри package.json в поле typings, либо в пакетах, поддерживаемых сообществом, либо несколькими другими (более ручными) способами. Было бы неплохо, если бы авторы библиотек могли добавлять пользовательские правила линтера и ссылаться на них в package.json, чтобы они автоматически подхватывались нашей языковой службой линтера? Точно так же компилятор TypeScript подбирает объявления типов?
Или подумайте об этом: в настоящее время большинство линтеров имеют функции автоматического исправления. Было бы неплохо, если бы мы могли автоматически исправлять наше предупреждение об устаревании? Например. потому что наша функция переименована с foo на bar или потому что наша import { foo } from ‘some-lib/foo’ теперь опубликована как отдельный пакет, такой как import { foo } from ‘some-lib-foo’? Это было бы невозможно только с console.warn. Это похоже на codemod, но ИМХО удобнее в использовании. Помимо предупреждений об устаревании, мы могли бы использовать языковую службу для конкретной платформы, чтобы помочь пользователю следовать рекомендациям (предупреждать, если они используют API неправильным способом) или специальные знания, которые не могут быть охвачены общей языковой службой.

Посмотрите, например, в исходный код vscode-html-languageservice. Он содержит жестко закодированные знания о директивах Angular. Было бы лучше, если бы это была отдельная языковая служба. Существует даже существует автономный языковой сервис для Angular, разработанный командой Angular. Но вам нужно установить его отдельно. Опять же… было бы лучше, если бы это могло быть просто подхвачено более общей языковой службой только потому, что у вас есть Angular в качестве зависимости и импортирован в ваш проект.

Плагины компилятора и макросы

Пользовательские правила линтера и функции IDE, такие как рефакторинг для конкретных библиотек, помимо того, что есть еще одна вещь, которая в настоящее время поддерживается отдельно от самих библиотек. Эти вещи, которые я имею в виду, — это плагины компилятора, такие как плагины Babel. Наиболее популярным, пожалуй, является синтаксис JSX для React. Но у многих библиотек есть плагины Babel для самосовершенствования. Два примера: есть гламурный подключаемый модуль Babel для подъема стилей для повышения производительности, и есть подключаемый модуль Babel для styled-components, добавляющий рендеринг на стороне сервера и улучшающий возможности отладки. Было бы неплохо, если бы их можно было просто опубликовать с оригинальными библиотеками? Было бы неплохо, если бы это также можно было просто указать в вашем package.json, чтобы его можно было легко подобрать, если вы импортируете гламур или стилизованные компоненты. Вероятно, нам нужно решить еще несколько задач, чтобы зайти так далеко. Например. нам не нужны конфликты между плагинами. Решением могут быть макросы sweet.js, которые можно импортировать локально, а также позволять расширять наш синтаксис JavaScript. Например, можно написать JSX как макрос.

Мне приходят на ум еще две проблемы. Первое: я хочу красивее везде. Если я напишу свое собственное расширение синтаксиса, такое как JSX, я также хочу быть ответственным за красивую печать моего синтаксиса. Prettier в настоящее время поддерживает JSX и поток, а вскоре и TypeScript, что здорово, но было бы еще лучше, если бы его можно было расширить. Во-вторых: я хочу статическую типизацию везде. В зависимости от вашего расширения синтаксиса это может быть довольно сложно. TypeScript поддерживает JSX, но опять же, это поддерживается поддержкой TypeScript и возможно только потому, что JSX очень популярен. Было бы не так просто добавить поддержку TypeScript в ваше расширение синтаксиса.

Погрузчики

При написании этого мне приходит в голову еще одна часть моего конвейера сборки, которую я хотел бы поддерживать с помощью статической типизации: загрузчики WebPack. Если я использую url-loader для загрузки изображений, мне сейчас нужно где-то добавить это объявление, чтобы TypeScript знал о возвращаемом типе.

declare module ‘*.jpg’ {
  const content: string;
  export default content;
}

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

hello.world=Say hello to "{label}"!

В настоящее время мы прекомпилируем эти файлы в JavaScript и объявления TypeScript, которые выглядят следующим образом:

/**
 * `en_US`: Say hello to "{label}"!
 * `de_DE`: Sag hallo zu "{label}"!
 */
export function helloWorld(data: { label: string }): string;

Это круто. Теперь мы можем просто импортировать helloWorld из нашего предварительно скомпилированного файла и получить завершение кода, правильную проверку типов и даже увидеть переводы, если навести курсор на helloWorld в VS Code. Но… нам нужно создать промежуточные файлы, чтобы решить эту проблему. Мы не можем просто написать загрузчик для WebPack и напрямую загрузить наши переводы.

Было бы неплохо, если бы наши загрузчики могли напрямую общаться с компилятором TypeScript.

Вывод

Я думаю, языковой сервер поможет нам предоставить редакторам больше возможностей IDE. Я мог бы представить себе встраивание языковых серверов в инструменты разработки нашего браузера или в веб-редакторы, такие как JSFiddle. Вы даже можете добавить немного IntelliSense в GitHub уже сегодня с помощью расширения Chrome!

В начале я сказал, что WebPack немного неудобен для новичков из-за его сложности на этапе настройки. Поэтому такие фреймворки, как next.js, так популярны. Они избегают многих настроек, используя файловую систему в качестве API. Когда мы сможем сделать то же самое для линтеров, подключаемых модулей компиляторов, макросов и языковых серверов, мы поможем авторам библиотек и потребителям получить максимальную отдачу от наших веб-технологий.

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