A super simple way to publish personal pages / blogs using Notion as CMS and Cloudflare Workers as publisher
Check out Demo website
-
Copy the
worker.js
to Cloudflare and edit the configurationThe
.js
file is almost completely influenced by fruitionExcept that I faced an Issue and sent in a Pull Request
-
Notion is great tool that lets you manage your workspace - and that's what we are going to use as our CMS i.e. content management
-
Workers is going to be our execution environment where we are goint to run
worker.js
code and serve out our Notion content on a subdomain provided by Cloudflare (subdomain.domain.workers.dev
) or a personalized domain of our choosing
Prerequisites: Set up your Notion page (make it public) and register at Cloudflare
-
Let's look at our goal first : We want to serve the Notion page we created when people to come to our website or the .workers.dev subdomain
-
So, let's look into the documentation for serving another site:
addEventListener("fetch", event => { return event.respondWith( fetch("https://youtube.com") ) })
Anyone who comes to our site, should be served the YouTube home page!
Let's see if that works?
-
Ok, that works! But, that means we are done, right?
We can just replace
youtube.com
with our Notion public page, and voila! -
Nah, Unfortunately that doesn't work!
(or fortunately rather, otherwise there is not much point in creating this whole post!)
So, if we do a
view-source
of Notion home page, we see:<script type="text/javascript" src="/app-1ae08b9f66e81e1cf0c9.js"></script></body></html>
Yeah, that's a relative reference - and when we serve out our blog, it's not gonna find it!
-
But, I know! Let's just replace these with absolute references!
We are already using
javascript
, a little bit ofregular expression
magic and we are done, right?const regex = /(?<=(href|src)=\")/gm; const subst = `https://www.notion.so`; const new_result = results.replace(regex, subst);
-
Well, not exactly!
You see, we have something called a
content-security-policy
violationIt's basically just that our domain , quite justifiably, doesn't want to run a random javascript it gets from Notion!
And security wise, that's a great thing! You wouldn't want your browser to run arbitrary javascript anyway!
-
Yeah, but, we know what we are doing!, right? Let's edit the csp:
let csp = response.headers.get('content-security-policy') let new_csp = csp.replaceAll("'self'", "'self' https://www.notion.so") new_response.headers.set('content-security-policy',new_csp)
-
Ok, so, we have gone through quite a many hoops. At least, now tell me that we are done?
Well, not exactly! But, we are close!
But, first, the hurdle we face : we are now greeted with a
Mismatch between origin and baseUrl (dev).
pop-up!And it's actually a little but dense function in the
app-1ae08b9f66e81e1cf0c9.js
we saw before:didMount(){const{device:e}=this.environment;"external"===Object(m.l) ({url:window.location.href,isMobile:e.isMobile,baseUrl:g.default.baseURL,protocol:g.default.protocol,currentUrl:window.location.href}).name&&Ve.showDialog({message:"Mismatch between origin and baseUrl (dev).",showCancel:!1,keepFocus:!1,items:[{label:n.createElement(o.FormattedMessage,{defaultMessage:"Okay",id:"notionAppContainer.dialog.mismatchedOriginURL.okayButton.label"}),onAccept:()=>{const e=xi.j({relativeUrl:xi.f(window.location.href),baseUrl:g.default.baseURL}),t=xi.e(e);t.protocol=xi.e(window.location.href).protocol,window.location.href=xi.b(t)}}]})}
-
Sidebar:
Frankly, intensely trying to solve this puzzle for the last 2 days has been pretty rewarding.
I had learnt a little bit of
javascript
when I was starting out - but, by now I had forgotten most of it.So, my knowledge of
js
increased exponentially in these 2 days!But, I was ultimately trying to solve a problem, not trying to learn the language
Yet, unfortunately it seemed like I would need to delve much deeper into this!
-
Fortunately, that's when I came across fruition
Yes, finally we are at the TL;DR part!
Aren't you happy that there was a TL;DR so you could just glean that and get on with your life!
Turns out all we need to do is to download the
.js
files so that it can be served from our blog, and thenredirect
the request to the link that we want!Adapting the code was pretty easy (except for a minor glitch)
All you need to do is to get the code above and edit the configuration here:
/* Step 1: enter your domain name like fruitionsite.com */ // either custom domain or cloudflare one const MY_DOMAIN = '*.workers.dev'; /* * Step 2: enter your URL slug to page ID mapping * The key on the left is the slug (without the slash) * The value on the right is the Notion page ID */ const SLUG_TO_PAGE = { // home page - // add 'page name': 'notion id' for more 'demo': '0d44ee0e01944fabbb047c7bb9f885fd', '': '1d44ee0e01944fabbb047c7bb9f885fd' };
There are a few more things you can change like the
PAGE_TITLE
orFONT
or anyCUSTOM_SCRIPT
you may have.But, even without making those changes, you will be able to have a blog / portfolio / show-case deployed in no time!