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 комментария
Написать комментарий...
Сергей Мазур

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

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

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

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