Как мы позволили сторонним разработчикам встраивать приложения в документы Quip через платформу Quip Live Apps.

В 2016 году мы в Quip сформулировали концепцию: сделать возможным встраивание чего угодно в документ Quip и позволить разработчикам по всему миру расширять холст документа. Мы знали, что это будет невероятно сложно. С технической стороны мы ожидали проблем с управлением iframe, настройкой модели безопасности, изолированием стороннего кода и обработкой производительности. Что касается удобства использования, нам нужно упростить для разработчика создание приложения. Затем все должно было собраться вместе и казаться естественным для конечного пользователя.

Перенесемся в Dreamforce в ноябре 2017 года. Именно тогда мы запустили Live Apps, платформу для разработчиков, позволяющую создавать приложения, которые встраиваются в документы Quip. С помощью API совместной работы разработчики могут использовать автоматическую поддержку синхронизации, редактирования и комментирования в реальном времени, которая по умолчанию доступна в автономном и кросс-платформенном режиме. Мы также запустили собственные приложения, такие как календари, опросы и канбан-доски, и открыли исходный код для справки.

Как все это выглядит в конце дня? Как инженер, начинающий проект, для меня нормально написать документ Quip, содержащий технический проект во фрагментах кода, список задач в контрольных списках и показатели запуска во встраиваемых электронных таблицах. Я добавлю календарь для временной шкалы проекта, опрос для группового обеда и график использования в реальном времени, чтобы повысить срочность. В более широком смысле, Live Apps позволяют командам извлекать данные для видимости из интеграции с Salesforce, Jira или настраиваемыми внутренними инструментами.

Видение расширяемого документа восходит к OpenDoc, ActiveX. », OLE и даже Xerox's Alto . Создав Live Apps for Quip, мы воспользовались возможностью, чтобы пойти дальше и создать что-то, предназначенное для мобильных, сетевых и социальных сетей сегодня.

Проблемы при создании платформы

По сути, Live Apps - это сторонний код внутри iframe в документах Quip. Приложения хранят свои данные в Quip, и они могут дополнительно получить доступ к более широкому Интернету (строго контролируемым образом). Код приложения взаимодействует с кодом Quip через API, которые образуют мост между iframe и главным окном. По умолчанию приложения не могут получить доступ к содержимому документа, и администраторы определяют, какие приложения доступны участникам сайта.

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

  • «Сделайте это проще для разработчиков». Как мы можем упростить для разработчика начало создания приложения?
  • «Создайте платформу! (iframe - это страшно) ». Как мы поддерживаем сторонний код внутри Quip? Ответ, вероятно, связан с iframe ... но как мы можем встраивать сторонние приложения в документы Quip таким образом, чтобы это было безопасно?
  • «Сделайте это совместным». Как предоставить API для модели данных, которая поддерживает несколько редакторов, работающих онлайн или офлайн и комментирующих?
  • «Это неестественно». Как сделать так, чтобы сторонние приложения чувствовали себя первоклассными участниками страницы? Как сделать так, чтобы они меняли размер динамически, как и другие материалы Quip? Как избежать отсечения содержимого, когда компоненты пользовательского интерфейса (например, меню) выходят за границы окна iframe?
  • "Это слишком медленно". Как нам загрузить код для пяти, десяти или двадцати экземпляров приложения, каждый из которых находится в собственном iframe?
  • Теперь сделайте все это во встроенных WebView на iOS и Android. Как сделать так, чтобы все это работало кроссплатформенно в Интернете, Windows, Mac, iOS и Android, где приложения не только живут в окнах iframe, но и в окнах iframe внутри WebView внутри нативного кода? Клиенты ожидают, что Quip будет работать изначально на всех их устройствах - как сделать так, чтобы Live Apps делали то же самое?

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

Сделайте это проще для разработчиков

Мы хотели упростить разработчикам запуск приложения Hello World внутри Quip. Во-первых, мы позволяем любому создавать Live-приложение. Все, что вам нужно, это сайт Quip, доступный через процесс регистрации Quip. Оттуда можно одним нажатием кнопки на Консоли разработчика Quip создать новое приложение с новым идентификатором.

Далее нам нужен был способ, позволяющий людям создавать и загружать пакеты приложений. Оглядываясь на другие инструменты, create-react-app выделяется как образец простой настройки. Это уменьшило сложность до одной команды и не требовало настройки.

Мы создали аналогичный create-quip-app модуль NPM, чтобы разработчики могли сразу начать работу с платформой Quip, не беспокоясь о настройке. create-quip-app зависит от quip-apps-webpack-config, нашего модуля для централизации стандартной конфигурации веб-пакетов. Доставка нашей собственной стандартной конфигурации webpack означала, что мы могли по умолчанию включать babel-polyfill, что означает, что приложения будут поддерживать современный JavaScript, оставаясь при этом совместимыми со старыми платформами, такими как наше приложение Mac для Yosemite.

После установки модуля выполните единственную команду create-quip-app hello-world создает такую ​​папку:

hello-world
├── package.json
├── node_modules
├── webpack.config.js
├── app
│   └── manifest.json
└── src
    └── App.less
    └── App.jsx
    └── root.jsx

На этом этапе требуется лишь скопировать идентификатор, указанный в консоли разработчика, запустить еще одну команду (npm run build) для упаковки приложения и загрузить полученный файл .ele через консоль разработчика (подробные сведения см. В Руководстве по началу работы. ).

Вот и все. На данный момент приложение фактически запущено и работает, и оно доступно для учетной записи разработчика Quip. Его можно добавить в документ Quip по имени через меню @ insert, как и все другие приложения.

Постройте платформу! (фреймы страшные)

Теперь давайте углубимся в то, что определяет опыт разработчиков: платформу.

Почти все платформы требуют трех вещей для поддержки сторонних приложений: данных конфигурации, кода библиотеки и кода приложения. Кроме того, некоторые также поддерживают хранение данных экземпляра приложения. Вот как выглядела эта разбивка для нас:

  1. Данные конфигурации: название приложения, требуемая версия API, цвет панели инструментов и т. Д.
  2. Код приложения: JavaScript, CSS и другие ресурсы для рендеринга приложения в iframe.
  3. Код библиотеки: код Quip для взаимодействия с окружающим документом.
  4. Данные экземпляра приложения: способ для экземпляра приложения хранить в Quip долгосрочные данные, такие как определенные параметры опроса и голоса.

Прохождение каждого из них по очереди проливает свет на жизнь Live App и некоторые соображения безопасности на этом пути.

Данные конфигурации

Мы решили централизовать данные конфигурации в манифесте приложения, простом файле JSON, который описывает приложение. Файл создается, когда разработчик впервые запускает create-quip-app. Вот базовый файл манифеста, который мы используем для приложения Poll.

{
    "id": "JYKAjAYyzLM",
    "name": "Poll",
    "toolbar_color": "blue",
    "js_files": ["dist/app.js"],
    "css_files": ["dist/app.css"]
    ...
}

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

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

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

Если приложению необходимо определить определенные URL-адреса из белого списка, это происходит в манифесте. :

"csp_sources": {
    "script_srcs": [
        "https://foo.com",
        "https://bar.com"
    ]
},

Мы читаем манифест, чтобы определить Политику безопасности контента (CSP) для приложения. В этом примере мы генерируем значение заголовка CSP "script-src https://foo.com https://bar.com;" для заголовка Content-Security-Policy, X-Webkit-CSP или X-Content-Security-Policy в зависимости от браузера. Теперь приложение может загружать скрипты только из foo.com и bar.com. Аналогичным образом приложения могут заносить в белый список URL-адреса для font_srcs, img_srcs, connect_srcs и т. Д., Чтобы загружать другие ресурсы или разрешать вызовы AJAX во внешние домены.

Код приложения

Когда конечный пользователь выбирает приложение для вставки, мы создаем iframe, указывающий на специальный URL-адрес для загрузки кода приложения:

https://element--k-o-r-aj-a-y-h-e50.quipelements.com/-/element/
view-frame?hv=6&element_config_id=KORAjAYHE50&retina=True&
seq=172&api_bundle=6ALan3xqd8N9k-3XkBNmMg

С точки зрения безопасности, в этот URL-адрес было принято несколько важных решений.

Во-первых, URL-адрес обслуживается с отдельного домена (quipelements.com), а не с самого Quip (quip.com). Разделение доменов помогает изолировать сторонний код от документа Quip (например, файлы cookie) и защищает от попыток олицетворять собственный код (например, посредством вызовов сервера).

Далее, у каждого приложения есть свой субдомен. Политика одинакового происхождения означает, что фреймы iframe, загруженные из разных поддоменов, не могут напрямую обращаться друг к другу. Для Quip это означает, что приложение от одного разработчика не может получить доступ к контексту JavaScript или DOM приложения от другого разработчика, даже если оба они отображаются в одном документе Quip.

В iframe используется субдомен приложения для получения ресурсов приложения, включая код JavaScript, который создает экземпляр приложения. Обратите внимание, что этот процесс более сложен в наших собственных приложениях для Mac, Windows, iOS и Android, где мы перехватываем URL-запрос и отправляем обратно кэшированные ресурсы, чтобы по-прежнему поддерживать приложения в автономном режиме.

Продолжение следует…

Мы собираемся закончить на этом захватывающем моменте и возобновить повествование на следующей неделе. До сих пор мы обсуждали Упростить для разработчиков и прошли половину пути Создание платформы (фреймы - это страшно). Во части второй мы перейдем к тому, как код библиотеки обрабатывает обмен данными между приложением и хостом, и обсудим, как платформа поддерживает долговременные, настраиваемые данные с синхронизацией в реальном времени. Затем мы закончим фразой "Сделайте это совместным".

Это первая часть из двух частей. Вот Часть 2.