Notion на максималках: как я открыл для себя бесплатную CMS

Не так давно я познакомился с Notion — приложением для заметок с поддержкой встроенных баз данных и удобным интерфейсом. С тех пор Notion — инструмент №1 в моей повседневной рутине. Я научился привязывать страницы Notion к собственному домену, с тех пор использую его как примитивную CMS для некоторых своих проектов.

Делюсь опытом и подробной инструкцией в данной статье.

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

  • Использовать Notion с любым собственным доменом.
  • Отключать логотип Notion на домене.
  • Потенциально — дорабатывать скрипт, добавлять Google Analytics, метрику и другие сервисы (например, Disqus для поддержки комментирования).

Данный метод придуман не мной. Он найден на просторах GitHub и адаптирован для собственных нужд. Если моя инструкция покажется вам сложной, можете обратиться к оригиналу.

Я использую Notion как базу знаний для своей образовательной платформы, а также веду крутую коллекцию ресурсов для веб-дизайнеров.

Notion — один из лучших инструментов для фанатов структурированной информации

Что нам потребуется?

Сам по себе Notion не позволяет подключить сторонний домен. Поэтому для достижения желаемого эффекта нам придётся немного поплясать с бубном. Что нам потребуется:

  1. Домен + доступ в панель регистратора;.
  2. Аккаунт на Cloudflare — бесплатно.
  3. Базовые знания о работе с доменами.
  4. Прямые руки.

Шаг 1. Регистрируемся на Cloudflare

Cloudflare — одна из ведущих компаний, предоставляющих ряд автоматизированных сервисов для владельцев сайтов (CDN, защита от DDoS и прочее). Если подключиться к Cloudflare (это бесплатно), работать с зоной домена (об этом ниже) станет намного проще и приятнее.

Первым делом создаём аккаунт на Cloudflare по этой ссылке. Сразу после регистрации добавляем свой сайт и выбираем бесплатный тарифный план. Если всё сделано правильно, вы увидите что-то вроде «Scanning for existing DNS records» — это значит, что система проверяет, куда «привязан» ваш домен на данный момент.

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

Именно поэтому система проверяет ваши текущие параметры, чтобы после переноса ничего не отвалилось. Смело прокручиваемся в самый низ и нажимаем «Continue».

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

У каждого регистратора своя панель управления и свои особенности. Можете набрать в поиске «как изменить ns-сервера на X», подставив вместо Х название своего регистратора. Ловите готовые мануалы для самых популярных регистраторов: Reg.ru, RuCenter (NIC), GoDaddy, NameCheap. Также подробная инструкция от самого Cloudflare.

После внесения изменений необходимо в интерфейсе Cloudflare завершить процедуру, нажав кнопку «Done, check nameservers» и снова «Done» в самом низу. Далее остаётся только ждать: скорость делегирования домена зависит от регистратора и может занимать до 24 часов.

Шаг 2. Пишем Worker

Сервис Cloudflare Workers представляет собой среду для выполнения кода без использования стороннего сервера. То есть благодаря данной технологии вам не обязательно приобретать отдельный VDS, устанавливать на него Node и связывать с доменом. Уважаемые разработчики и DevOps-специалисты, прошу, не кидайтесь камнями за такое примитивное объяснение.

Таким образом, всё, что нам необходимо сделать, — это написать скрипт, подгружающий нужную страницу из Notion и связать получившийся Worker с нашим доменом. Вот сам скрипт, описание — в виде комментариев в коде, а также чуть ниже в данной статье.

// Здесь указываем свой домен const MY_DOMAIN = "va-promotion.ru" // Здесь указываем адрес начальной страницы в Notion const START_PAGE = "https://www.notion.so/129ba7e23f214b0eafbe7bfb908e45b7" addEventListener('fetch', event => { event.respondWith(fetchAndApply(event.request)) }) const corsHeaders = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, HEAD, POST,PUT, OPTIONS", "Access-Control-Allow-Headers": "Content-Type", } function handleOptions(request) { if (request.headers.get("Origin") !== null && request.headers.get("Access-Control-Request-Method") !== null && request.headers.get("Access-Control-Request-Headers") !== null) { // Handle CORS pre-flight request. return new Response(null, { headers: corsHeaders }) } else { // Handle standard OPTIONS request. return new Response(null, { headers: { "Allow": "GET, HEAD, POST, PUT, OPTIONS", } }) } } async function fetchAndApply(request) { if (request.method === "OPTIONS") { return handleOptions(request) } let url = new URL(request.url) let response if (url.pathname.startsWith("/app") && url.pathname.endsWith("js")) { // skip validation in app.js response = await fetch(`https://www.notion.so${url.pathname}`) let body = await response.text() try { response = new Response(body.replace(/www.notion.so/g, MY_DOMAIN).replace(/notion.so/g, MY_DOMAIN), response) response.headers.set('Content-Type', "application/x-javascript") console.log("get rewrite app.js") } catch (err) { console.log(err) } } else if ((url.pathname.startsWith("/api"))) { // Forward API response = await fetch(`https://www.notion.so${url.pathname}`, { body: request.body, // must match 'Content-Type' header headers: { 'content-type': 'application/json;charset=UTF-8', 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36' }, method: "POST", // *GET, POST, PUT, DELETE, etc. }) response = new Response(response.body, response) response.headers.set('Access-Control-Allow-Origin', "*") } else if (url.pathname === `/`) { // 301 redrict let pageUrlList = START_PAGE.split("/") let redrictUrl = `https://${MY_DOMAIN}/${pageUrlList[pageUrlList.length - 1]}` return Response.redirect(redrictUrl, 301) } else { response = await fetch(`https://www.notion.so${url.pathname}`, { body: request.body, // must match 'Content-Type' header headers: request.headers, method: request.method, // *GET, POST, PUT, DELETE, etc. }) response = new Response(response.body, response) // Delete CSP to load disqus content response.headers.delete("Content-Security-Policy") // add disqus comment component for every notion page return new HTMLRewriter().on('body', new ElementHandler()).transform(response) } return response } class ElementHandler { element(element) { // An incoming element, such as `div` element.append(` <script> // if you want to hide some element, add the selector to hideEle Array const hideEle = [ "#notion-app > div > div.notion-cursor-listener > div > div:nth-child(1) > div.notion-topbar > div > div:nth-child(6)", "#notion-app > div > div.notion-cursor-listener > div > div:nth-child(1) > div.notion-topbar > div > div:nth-child(5)", "#notion-app > div > div.notion-cursor-listener > div > div:nth-child(1) > div.notion-topbar > div > div:nth-child(4)", ".notion-topbar > div:nth-child(1) > div:nth-child(5)", ] // if you want to replace some element, add the selector and innerHTML to replaceEle Object const replaceEle = { "#notion-app > div > div.notion-cursor-listener > div > div:nth-child(1) > div.notion-topbar > div > div:nth-child(6)": "<span>agodrich<span>" } function hideElement(qs) { let eles = document.querySelectorAll(qs) eles && eles.forEach(ele => ele.style.display = "none") } function replaceElement(qs, _html) { let ele = document.querySelector(qs) if (ele) { ele.innerHTML = _html } } let MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; let body = document.querySelector('body'); let observer = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { let pageContent = document.querySelector("#notion-app div.notion-page-content") if (pageContent) { // Do nothing club } hideEle.forEach( hideE => hideElement(hideE) ) Object.entries(replaceEle).forEach( item => { let [qs,_html] = item; replaceElement(qs,_html) }) }); }); observer.observe(body, { subtree: true, childList: true }); </script> `, { html: Boolean }) console.log(`Incoming element: ${element.tagName}`) } comments(comment) { // An incoming comment } text(text) { // An incoming piece of text } }

По сути, всё, что нужно изменить — две переменных: нужно подставить свой домен и адрес стартовой страницы в Notion. С этим кодом можно играться сколько угодно долго: добавлять аналитику и прочие фишки. Если хоть немного разбираетесь в JavaScript, вам не составит труда «вклинить» нужный код в нужное место. Например, в оригинальной версии на Github на страницы Notion добавляется система комментирования Disqus.

Шаг 3. Собираем всё вместе

Остаётся только собрать воедино данный пазл: добавить Worker в Cloudflare и связать его с доменом. Первым делом переходим на вкладку Workers в самом Cloudflare.

Нажимаем кнопку «Manage workers» в самом начале страницы. Далее устанавливаем любой поддомен (он может быть не связан с вашим основным сайтом, это внутренняя настройка Cloudflare), выбираем бесплатный тарифный план и подтверждаем почтовый адрес, если ещё этого не сделали.

Если всё прошло успешно, вы увидите кнопку «Create worker». Нажимаем её и в появившийся слева редактор вставляем наш код, заменив предварительно необходимые переменные в самом верху.

Нажимаем кнопку «Save & Deploy» и подтверждаем. Через несколько секунд анимация загрузки сменится на стрелочку — значит ваш Worker запущен и работает без ошибок.

Cloudflare по умолчанию запускает Worker на собственном домене. На него можно кликнуть, если всё настроено правильно, откроется ваша страница в Notion

Финальный этап — связь воркера и домена. Нам необходимо вернуться в раздел Workers. Для этого переходим на стартовый экран Cloudflare, далее — Workers. На уже знакомом нам экране жмём «Add route».

Во всплывающем окне указываем параметры:

  • Route — по какому адресу будет запускаться наш Worker. Рекомендую указывать здесь запись в формате domain.com/* — то есть, исключить звёздочку в самом начале, дабы воркер не запускался на поддоменах.
  • Worker — выбираем созданный нами ранее Worker.

Сохраняем, и на этом всё. Чаще всего изменения отображаются мгновенно (при условии, что регистратор уже сменил DNS-записи). Иногда необходимо немного подождать.

Если у вас возникнут трудности с применением данного метода на практике, пишите в Telegram: @valery_alexeev — постараюсь помочь советом.

Всем хорошего дня!

0
63 комментария
Написать комментарий...
Denis Step

Что-то многовато на vc статей про Notion в последнее время <kiselev_face></kiselev_face>

Ответить
Развернуть ветку
Сергей Некрасов

Тоже заметил и недавно сам установил его. Сторителлинг делает свое дело))

Ответить
Развернуть ветку
4 комментария
Rodeus

Беплатный тариф без ограничения по количеству записей появился в мае

Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Валерий Алексеев
Автор

Структура хранения данных в базах есть (задаются типы для колонок), но вы верно подметили — это всё намного примитивнее, чем у полноценных CMS и того же Airtable.

Ответить
Развернуть ветку
Dmitrii

Notion API access coming soon.

Ответить
Развернуть ветку
Денис Любомудров

Я этом направлении использую nTile. Там не такой удобный интерфейс для начала работы, как в notion или airtable, но есть возможность создания сайта через их собственный конструктор, работы с базами данных, знаний, вики, можно подключать различные интеграции с Telegram и тд. Вообщем он закрывает все потребности и имеет больше функционала, чем другие

Ответить
Развернуть ветку
Artem Kurganskiy

Notion, прекрати. Мы все поняли что ты на Россию вышел и активно продвигаешься

Ответить
Развернуть ветку
Арсен Бозиев

вышел бы он на Россию правильно, добавили бы русский язык, а пока - это ооочень нишевый продукт, не для всех)

Ответить
Развернуть ветку
Bogdan DNA

Недавно сам подобное делал, а вы упирались в лимиты клаудфлейра? Там на worker одного 100.000 вызовов бесплатно, один человек при активном изучении просмотре 3-5 страниц в этом ноушене тратит под 1000. 100 человек в день всего использовать могут это получается. Читал что есть другие версии этой реализации с кеширующим скриптом на любом хостинге, но не нашел. Не знаете?

Ответить
Развернуть ветку
Валерий Алексеев
Автор

Да, такой лимит есть — 100 000 запросов в день. Если не ошибаюсь, платная версия  с безлимитным воркером стоит около 5-8 долларов. Примерно в цену слабенького VDS.

Сейчас сам работаю над адаптацией данного скрипта для быстрого развёртывания на любом VDS с кэшем, но это в формате хобби. За те же 5-8 баксов проще оформить подписку на https://super.so и не париться.

Ответить
Развернуть ветку
20 комментариев
Сергей Мазур

интерфейс у Notion перегружен имхо

Ответить
Развернуть ветку
Vladimir Mirolubow

Вы еще Jira не пользовались

Ответить
Развернуть ветку
Сергей Мазур

У меня оказывается был тариф навороченный, переключился на персонал и стало намного лучше тем более он бесплатный анлим стал.

Соглашусь, пока лучший и быстрый из бесплатных программ подобного рода. пожалуй на него перееду.

Ответить
Развернуть ветку
Илья Бузункин

Вот ещё очень крутой сервис, альтернатива Notion

Ответить
Развернуть ветку
Василий Степанов

Крутой потому что вы его пилите?
 Вы бесплатный ноуш видели вообще?

Ответить
Развернуть ветку
1 комментарий
Линьков Олег

Стоимость подписки не соизмерима с функционалом.

Ответить
Развернуть ветку
1 комментарий
Vladimir Mirolubow

прям очень очень крутой? переходить с Ношена?

Ответить
Развернуть ветку
2 комментария
Дмитрий Шмаков

Русского интерфейса не хватает в Notion. Понятно, что и с английским можно работать, но все же видеть русский было бы приятнее, особенно, если программа вышла на российский рынок.

Ответить
Развернуть ветку
Не Вс

Слышал звон не знает где он. (с)

Ответить
Развернуть ветку
Anatoly

Мы не берём денег за доступ к нашей коллекции. Однако, мы будем рады, если вы поделитесь ей в одной из ваших социальных сетей. Спасибо!    - Чем вот это реализовать?

Ответить
Развернуть ветку
Roman BL

https://usocial.pro/socialkey давно еще задавался этим вопросом - из всех что есть этот самый удобный имхо

Ответить
Развернуть ветку
1 комментарий
Валерий Алексеев
Автор
Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Валерий Алексеев
Автор

Спасибо, сейчас починим. Сможете кинуть свой аккаунт Twitter мне в телеграм: @valery_alexeev — в ответ скину ссылку на коллекцию.

Ответить
Развернуть ветку
Валерий Алексеев
Автор

Починили

Ответить
Развернуть ветку
1 комментарий
Сергей Мазур

Кстати, спасибо за статью. читать не стал, но перешел на Ношен)) вроде не тормозит. искал альтернативы эверноуту достаточно давно.

Ответить
Развернуть ветку
Tony Sedniov

Есть еще конкурент
https://coda.io

Ответить
Развернуть ветку
1 комментарий
Никита Лукощенко

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

Ответить
Развернуть ветку
Vladimir Zambakhidze

Всем привет! Кто нибудь кроме автора пробовал эту схему? А то у меня что-то криво косо работает. На мобильном отображается, а на ноуте (на разных) никак не хочет открываться сайт. И вопрос про DNS записи A / CNAME - какие и как нужно прописывать?

Ответить
Развернуть ветку
Alexander Demchenko

Страница виснет и не грузится. Напрямую через notion.so все ок.

Ответить
Развернуть ветку
Ivan Tischenko

Сегодня это актуально? Или уже есть способы проще?

Ответить
Развернуть ветку
60 комментариев
Раскрывать всегда