В нашем проекте, IDE для работы с API TestMace, в качестве основного языка используется TypeScript, поэтому мы активно интересуемся проектами, связанными с данным языком. Сегодня вашему вниманию представляется перевод статьи об инструменте Deno — runtime для TypeScript (но это не единственная его особенность). Приятного чтения.



Около трёх месяцев назад Райан Дал (создатель Node.js) выступил на конференции с докладом «10 вещей в Node.js, о которых я сожалею», где рассказал о некоторых своих неудачных проектных решениях для Node.js. Почти половину выступления он посвятил экспериментальному прототипу Deno, задачей которого было устранить недостатки Node.js.


Deno уже добрался до версии v0.1 (прим. переводчика — уже v0.3.8) и идёт правильной дорогой к своей цели заменить Node.js в будущем.


Что не так с Node.js?


Любая программа может производить запись данных в файловую систему или сеть


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


Быстро устаревающие асинхронные API


Промисы появились в Node.js в 2009 году, а в феврале 2010 их не стало. Однако в большинстве библиотек для работы с асинхронным кодом до сих пор используются колбеки.


Система сборки (GYP)


Собрать модуль для подключения библиотек на C через GYP — сплошное мучение. Чтобы получить адекватный developer experience, придётся использовать node-gyp (слой поверх GYP) и, возможно, другие слои (вроде nan). Я собственноручно пробовал все вышеописанное в своем небольшом проекте, и, готов согласиться, это заставило меня попотеть.


Система модулей и npm


Главная проблема в том, что система модулей не совместима с браузерами, а значит код не до конца изоморфен. Главным образом, на то есть две причины: хранение зависимостей в node_modules и наличие package.json.


Что такое Deno?


«Deno — это защищенная среда выполнения TypeScript на основе движка V8»,
? Райан Дал


Учитывая, что Typescript — это расширенная версия Javascript, Deno также является средой выполнения и для Javascript.


Deno — новый проект Райана Дала (создателя Node.js), призванный исправить проектные ошибки Node.js, речь о которых шла выше.


Основные особенности Deno


Безопасность


По умолчанию Deno запрещает такие деликатные действия, как чтение переменных окружения или запись в файловую систему.


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


Разрешение на запись в файловую систему, а также разрешения, связанные с окружением и сетью, отключены. Чтобы разрешить эти действия, необходимо вызвать Deno c аргументами --allow-write и --allow-net.


Всё взаимодействие привилегированного процесса Deno и v8 сводится к обмену сообщениями (ранее написанному на Go, теперь перенесённому на Rust). Это позволяет создать единую точку для проверки всех сообщений.


Система модулей


Забудьте о package.json и node_modules. При импорте исходных файлов можно указать как относительный или абсолютный путь, так и их полный URL:


import { test } from "https://unpkg.com/deno_testing@0.0.5/testing.ts"
import { log } from "./util.ts"

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


Поддержка TypeScript из коробки


TypeScript поддерживается в Deno по умолчанию. Вот так вот. Без всяких "но". Без конфигураций.


Deno v0.1.4 в действии


Для начала загрузим бинарный файл Deno:


$ mkdir deno-test && cd deno-test
$ wget https://github.com/denoland/deno/releases/download/v0.1.4/deno_linux_x64.gz
$ gunzip -c deno_linux_x64.gz > deno
$ chmod u+x deno
$ ./deno --version
deno: 0.1.4
v8: 7.0.247-deno

Теперь создадим typescript-файл и выполним его:



function hello(place: string): string {
  return `Hello ${place}`
}

console.log(hello('world'))

$ ./deno myscript.ts
Hello world

Можно также попробовать импорт через URL. Единственное требование — файл в конце URL должен иметь расширение .ts.


import { factorial } from "https://gist.githubusercontent.com/DanielRamosAcosta/ad514503b1c7cf8290dadb96a5fddee9/raw/4733e267f05d20110ba962c4418bab5e98abfe93/factorial.ts"

console.log(factorial(10))

$ ./deno myimport.ts
Downloading https://gist.githubusercontent.com/DanielRamosAcosta/ad514503b1c7cf8290dadb96a5fddee9/raw/4733e267f05d20110ba962c4418bab5e98abfe93/factorial.ts
3628800

Во время выполнения скрипта модуль загрузится и добавится в кэш. Чтобы обновить кэш, можно вызвать Deno, используя аргумент --reload, что эквивалентно действию клавиш F5 или Ctrl+R.


Ниже приведён более сложный пример с использованием библиотеки axios:


import axios from "https://gist.githubusercontent.com/DanielRamosAcosta/2f773d815f5434f185c59aec1bab418c/raw/a442cdd8699e39ab9855cbaa571a79049a7b67d4/axios.ts"

// Make a request for a user with a given ID
axios.get('http://jsonplaceholder.typicode.com/users/1')
  .then(response => {
    // handle success
    console.log("User name:", response.data.name);
  })
  .catch(error => {
    // handle error
    console.error("error:", error);
  })

Единственная загвоздка в том, что VSCode не может загружать typings удалённо, поэтому в редакторе появится следующая ошибка:


An import path cannot end with a '.ts' extension.


Но код всё равно работает и выдаёт корректный результат:


./deno --allow-net axios-test.ts
User name: Leanne Graham

Заключение


Deno понадобится ещё немало времени, чтобы вырасти в полноценный рабочий инструмент, но, я считаю, он развивается в верном направлении, и у него есть все шансы стать более продуманной средой выполнения Javascript, чем Node.js.


Благодарю за внимание!

Комментарии (22)


  1. Drag13
    23.04.2019 10:05

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

    Из минусов (с моей субьективной колокольни), то что ребятам нужно будет поддерживать TS который обновляется чаще чем JS. Т.е. им придется или тратить больше усилий на апдейт, либо жить с отставанием. Плюс, пока что, deno отстает по производительности от Node.JS. Но над этим как раз работают.

    Райян недавно выступал в Киеве на JsFest, как раз рассказывал и показывал deno. Релиз обещали на август (если я не ошибся)


    1. biziwalker
      23.04.2019 10:41

      Насчет минусов, тут все подругому: в Deno «под копотом» исполняется тот же JavaScript как и в Node.js, просто он компилируется из TypeScript посредствам tsc перед запуском в V8. Скомпилированная версия кэшируется, чтобы сократить издержки загрузки и компиляции скриптов из Интернета. Посмотрите папку ~/.deno после запуска скрипта, если не верите


      1. Drag13
        23.04.2019 12:02

        Спасибо за исправление.
        А не в курсе, можно ли подкинуть ему свой (более старый/новый) tsc?


  1. Tarik02
    23.04.2019 10:51
    +1

    По-моему, наступают на те же грабли. Если просто разрешать доступ к файловой системе, то мы разрешаем доступ к всей файловой системе сразу. Будь то './config.json' или '~/.ssh/id_rsa', без особой разницы. Не лучше ли сделать более ограниченные разрешения, давая доступ только к конкретным папкам?


    1. Taraflex
      23.04.2019 20:44

      Подобные ограничения логичнее вводить на уровне os и «виртуализаторов» в стиле докера.


      1. justboris
        23.04.2019 21:06
        +1

        Хорошее наблюдение. Правда, в таких условиях с точки зрения безопасности deno ничем не отличается от обычной node


  1. MarcusAurelius
    23.04.2019 12:00

    Из важного нужно добавить, что вместо libuv в Deno используется Tokio, что позволит оптимизировать систему ввода-вввода, сделать ее более производительной из-за лучшей реализации многопоточности. Многие из этих идей можно было бы реализовать и в Ноде, но Райан потерял контроль над разработкой Ноды и влияние в сообществе. Тут его последний доклад в Киеве:


    1. ReklatsMasters
      23.04.2019 15:27

      Райан потерял контроль над разработкой Ноды и влияние в сообществе

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


  1. zim32
    23.04.2019 12:17

    Безопасность какая-то неполная. Лучше бы гранулярность была на уровне модулей. А то ну запустил я привилегированный процесс, потос добавил туда библиотеку, потом её взломали и всё. В чем разница?


  1. ReklatsMasters
    23.04.2019 15:33

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


  1. xPomaHx
    23.04.2019 15:37

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


    1. zim32
      24.04.2019 10:53

      Ну тут сложный вопрос. В той реализации что в статье можно вообще запустить процесс в lxc или как-то еще виртуализировать сеть и диск и все.


  1. justkost
    23.04.2019 16:57

    так Райан Дал вроде бы еще сто лет назад на golang уходил, хейтил уже тогда Node.js, он что всю жизнь этим собирается заниматься, обсирать ноду и хвалить что нибудь другое


  1. KeyJoo
    23.04.2019 21:42

    Всегда было интересно смотреть, кто как умеет крутить к`Oмпас или комп`Ас в руках… Тоже погладываю в сторону Dart.


  1. adictive_max
    24.04.2019 04:53
    +1

    import { test } from "https://unpkg.com/deno_testing@0.0.5/testing.ts"
    Это ж как надо было укуриться, чтобы выдать такое… В системе, ориентированной на безопасность, отрывать зависимости из внешнего URL напрямую, что же может пойти не так?..
    Кроме того, сходу можно прикинуть ещё пару «достоинств»:
    1 — забудьте про декларации, статический анализ и code-assist
    2 — tree-shaking для слабаков, либо тащите всю либу целиком, либо «знайте свой инструмент», в том числе в каком из 10k файлов лежит нужная вам функция, чтобы импортировать её отдельно.
    3 — добро пожаловать в DLL-hell невиданного масштаба, все зависимости будите админить ручками, по месту вызова, каждый раз перелопачивая пофайлово весь проект. Или делать import-export файл, который тот-же package.json, только без автоматизации…


    1. justboris
      24.04.2019 09:18

      В системе, ориентированной на безопасность, отрывать зависимости из внешнего URL

      Сейчас зависимости скачиваются с regsitry.npmjs.org, а будут с тех хостов, которые вы укажете. Децентрализация это хорошо же.


      Принципиально ничего не меняется, качаем зависимости из интернета, локально кешируем и загружаем.


      забудьте про декларации, статический анализ и code-assist

      Уже сейчас Web/PHP Storm подхватывает файлы подключенные через <script src="http://path-to-script/.....js">. В принципе, редактору без разницы, откуда берутся файлы в локальном кеше.


      tree-shaking для слабаков, либо тащите всю либу целиком

      tree-shaking делается бандлером, от способа получения файлов это никак не зависит, здесь ничего не меняется


      добро пожаловать в DLL-hell невиданного масштаба, все зависимости будите админить ручками

      Здесь пока все плохо, да. Ждем import-maps стандарта.


      1. adictive_max
        24.04.2019 09:52

        Принципиально ничего не меняется, качаем зависимости из интернета, локально кешируем и загружаем.

        Но дело-то в том, что regsitry.npmjs.org — он один, а «тех хостов, которые вы укажете» — тысячи. Это значит, что:
        1 — это будет зоопарк
        2 — десятки, если не сотни, потенциальных точек отказа в процессе сборки
        3 — каждый разработчик должен самостоятельно содержать свой репозиторий
        4 — нельзя будет просто посмотреть, какие в проекте зависимости, для этого надо будет выкачивать и просматривать все исходники целиком.

        Собственно, вы не задавались вопросом, почему централизованный репозиторий библиотек — это must-have фича для всех новых платформ, и пользователи крайне огорчаются, если её нет?
        В принципе, редактору без разницы, откуда берутся файлы в локальном кеше.
        Я не зря упомянул декларации, они не обязательно импортируются в проект в явном виде. То есть, пока не выкачаешь ВСЮ библиотеку, в локальном кеше их и не будет. Ну и опять же, это ещё одна неявная подгрузка.


    1. untilx
      24.04.2019 09:34

      Это ж как надо было укуриться, чтобы выдать такое… В системе, ориентированной на безопасность, отрывать зависимости из внешнего URL напрямую, что же может пойти не так?..

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


      1. adictive_max
        24.04.2019 09:58

        Не писал на Go, но подозреваю, что он делает это не в рантайме…


        1. untilx
          24.04.2019 10:15

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


          1. adictive_max
            24.04.2019 12:40

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


  1. jashcka
    24.04.2019 07:57

    Импорты по URL на внешние либы это ужас.
    Я так понял он обратно не совместим с приложениями на nodejs