feat: refactoring config to site.config.js

This commit is contained in:
Travis Fischer
2021-01-19 20:54:08 -05:00
parent b58d2b69f6
commit 6707fc8d56
17 changed files with 243 additions and 175 deletions

View File

@@ -1,43 +1,65 @@
/**
* Site-wide app configuration.
*
* @see env.ts for config relating to third-party dependencies.
*/
import { getEnv } from './get-env'
import { getSiteConfig, getEnv } from './get-config-value'
// where it all starts -- the site's root Notion page
export const rootNotionPageId = '78fc5a4b88d74b0e824e29407e9f1ec1'
export const rootNotionPageId: string = getSiteConfig('rootNotionPageId')
// general site config
export const siteName = 'Transitive Bullshit'
export const siteAuthor = 'Travis Fischer'
export const siteAuthorTwitter = 'transitive_bs'
export const siteDomain = 'transitivebullsh.it'
export const siteDescription =
'Personal site of Travis Fischer aka Transitive Bullshit'
export const siteFavicon = `https://${siteDomain}/favicon.png`
export const socialImageTitle = 'Transitive Bullshit'
export const socialImageSubtitle = 'Hello World! 👋'
export const name: string = getSiteConfig('name')
export const author: string = getSiteConfig('author')
export const domain: string = getSiteConfig('domain')
export const description: string = getSiteConfig('description', 'Notion Blog')
// social accounts
export const twitter: string | null = getSiteConfig('twitter', null)
export const github: string | null = getSiteConfig('github', null)
export const linkedin: string | null = getSiteConfig('linkedin', null)
export const socialImageTitle: string | null = getSiteConfig(
'socialImageTitle',
null
)
export const socialImageSubtitle: string | null = getSiteConfig(
'socialImageSubtitle',
null
)
// default notion values for site-wide consistency (optional; may be overridden on a per-page basis)
export const defaultPageIcon =
'https://ssfy.io/https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F797768e4-f24a-4e65-bd4a-b622ae9671dc%252Fprofile-2020-280w-circle.png%3Ftable%3Dblock%26id%3D78fc5a4b-88d7-4b0e-824e-29407e9f1ec1%26cache%3Dv2'
export const defaultPageCover =
'https://ssfy.io/https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F9fc5ecae-2b4b-4e73-b0d4-918c829ba69f%252FIMG_0259-opt.jpg%3Ftable%3Dblock%26id%3D78fc5a4b-88d7-4b0e-824e-29407e9f1ec1%26cache%3Dv2'
export const defaultPageCoverPosition = 0.1862
export const defaultPageIcon: string | null = getSiteConfig(
'defaultPageIcon',
null
)
export const defaultPageCover: string | null = getSiteConfig(
'defaultPageCover',
null
)
export const defaultPageCoverPosition: number = getSiteConfig(
'defaultPageCoverPosition',
0.5
)
// image CDN host to proxy all image requests through
export const imageCDNHost: string | null = getSiteConfig('imageCDNHost', null)
// whether or not to enable support for LQIP preview images
// (requires a Google Firebase collection)
export const isPreviewImageSupportEnabled = true
export const isPreviewImageSupportEnabled: boolean = getSiteConfig(
'isPreviewImageSupportEnabled',
false
)
// ----------------------------------------------------------------------------
export const isDev =
process.env.NODE_ENV === 'development' || !process.env.NODE_ENV
export const isServer = typeof window === 'undefined'
export const port = getEnv('PORT', '3000')
export const host = isDev ? `http://localhost:${port}` : `https://${siteDomain}`
export const host = isDev ? `http://localhost:${port}` : `https://${domain}`
export const apiBaseUrl = `${host}/api`
@@ -47,6 +69,8 @@ export const api = {
renderSocialImage: (pageId) => `${apiBaseUrl}/render-social-image/${pageId}`
}
// ----------------------------------------------------------------------------
export const fathomId = isDev ? null : getEnv('FATHOM_ID', null)
export const fathomConfig = fathomId
@@ -54,3 +78,43 @@ export const fathomConfig = fathomId
excludedDomains: ['localhost', 'localhost:3000']
}
: undefined
const defaultEnvValueForPreviewImageSupport =
isPreviewImageSupportEnabled && isServer ? undefined : null
export const googleProjectId = getEnv(
'GCLOUD_PROJECT',
defaultEnvValueForPreviewImageSupport
)
export const googleApplicationCredentials = getGoogleApplicationCredentials()
export const firebaseCollectionImages = getEnv(
'FIREBASE_COLLECTION_IMAGES',
defaultEnvValueForPreviewImageSupport
)
// this hack is necessary because vercel doesn't support secret files so we need to encode our google
// credentials a base64-encoded string of the JSON-ified content
function getGoogleApplicationCredentials() {
if (!isPreviewImageSupportEnabled || !isServer) {
return null
}
try {
const googleApplicationCredentialsBase64 = getEnv(
'GOOGLE_APPLICATION_CREDENTIALS',
defaultEnvValueForPreviewImageSupport
)
return JSON.parse(
Buffer.from(googleApplicationCredentialsBase64, 'base64').toString()
)
} catch (err) {
console.error(
'Firebase config error: invalid "GOOGLE_APPLICATION_CREDENTIALS" should be base64-encoded JSON\n'
)
throw err
}
}

View File

@@ -1,18 +1,17 @@
import * as firestore from '@google-cloud/firestore'
import * as types from './types'
import * as env from './env'
import { isPreviewImageSupportEnabled } from './config'
import * as config from './config'
export let db = null
export let images = null
export let db: firestore.Firestore = null
export let images: firestore.CollectionReference = null
if (isPreviewImageSupportEnabled) {
if (config.isPreviewImageSupportEnabled) {
db = new firestore.Firestore({
projectId: env.googleProjectId,
credentials: env.googleApplicationCredentials
projectId: config.googleProjectId,
credentials: config.googleApplicationCredentials
})
images = db.collection(env.firebaseCollectionImages)
images = db.collection(config.firebaseCollectionImages)
}
async function get<T extends types.Model>(

View File

@@ -1,54 +0,0 @@
/**
* Config for third-party dependencies.
*
* - Google Cloud (Firebase) - for simple database functionality.
* - Fathom - simple analytics.
*
* @see config.ts for primary configuration.
*/
import { getEnv } from './get-env'
import { isPreviewImageSupportEnabled } from './config'
export { isPreviewImageSupportEnabled }
const defaultEnvValueForPreviewImageSupport = isPreviewImageSupportEnabled
? undefined
: null
export const googleProjectId = getEnv(
'GCLOUD_PROJECT',
defaultEnvValueForPreviewImageSupport
)
export const googleApplicationCredentials = getGoogleApplicationCredentials()
export const firebaseCollectionImages = getEnv(
'FIREBASE_COLLECTION_IMAGES',
defaultEnvValueForPreviewImageSupport
)
// this hack is necessary because vercel doesn't support secret files so we need to encode our google
// credentials a base64-encoded string of the JSON-ified content
function getGoogleApplicationCredentials() {
if (!isPreviewImageSupportEnabled) {
return null
}
try {
const googleApplicationCredentialsBase64 = getEnv(
'GOOGLE_APPLICATION_CREDENTIALS',
defaultEnvValueForPreviewImageSupport
)
return JSON.parse(
Buffer.from(googleApplicationCredentialsBase64, 'base64').toString()
)
} catch (err) {
console.error(
'Firebase config error: invalid "GOOGLE_APPLICATION_CREDENTIALS" should be base64-encoded JSON\n'
)
throw err
}
}

37
lib/get-config-value.ts Normal file
View File

@@ -0,0 +1,37 @@
import siteConfig from '../site.config'
if (!siteConfig) {
throw new Error(`Config error: invalid site.config.js`)
}
export function getSiteConfig<T>(key: string, defaultValue?: T): T {
const value = siteConfig[key]
if (value !== undefined) {
return value
}
if (defaultValue !== undefined) {
return defaultValue
}
throw new Error(`Config error: missing required site config value "${key}"`)
}
export function getEnv(
key: string,
defaultValue?: string,
env = process.env
): string {
const value = env[key]
if (value !== undefined) {
return value
}
if (defaultValue !== undefined) {
return defaultValue
}
throw new Error(`Config error: missing required env variable "${key}"`)
}

View File

@@ -1,17 +0,0 @@
export function getEnv(
key: string,
defaultValue?: string,
env = process.env
): string {
const value = env[key]
if (value !== undefined) {
return value
}
if (defaultValue !== undefined) {
return defaultValue
}
throw new Error(`Config error: missing required env var "${key}"`)
}

View File

@@ -6,8 +6,8 @@ export const getSiteForDomain = async (
): Promise<types.Site | null> => {
return {
domain,
name: config.siteName,
name: config.name,
rootNotionPageId: config.rootNotionPageId,
description: config.siteDescription
description: config.description
} as types.Site
}

View File

@@ -3,5 +3,5 @@ import * as config from './config'
import * as types from './types'
export async function getSites(): Promise<types.Site[]> {
return [await getSiteForDomain(config.siteDomain)]
return [await getSiteForDomain(config.domain)]
}

View File

@@ -1,6 +1,5 @@
import { Block } from 'notion-types'
const imageCDNHost = 'https://ssfy.io'
import { imageCDNHost } from './config'
export const mapNotionImageUrl = (url: string, block: Block) => {
if (!url) {
@@ -11,7 +10,7 @@ export const mapNotionImageUrl = (url: string, block: Block) => {
return url
}
if (url.startsWith(imageCDNHost)) {
if (imageCDNHost && url.startsWith(imageCDNHost)) {
return url
}
@@ -48,6 +47,10 @@ export const mapImageUrl = (imageUrl: string) => {
return imageUrl
}
// Our proxy uses Cloudflare's global CDN to cache these image assets
return `${imageCDNHost}/${encodeURIComponent(imageUrl)}`
if (imageCDNHost) {
// Our proxy uses Cloudflare's global CDN to cache these image assets
return `${imageCDNHost}/${encodeURIComponent(imageUrl)}`
} else {
return imageUrl
}
}

View File

@@ -16,8 +16,8 @@ export const oembed = async ({
// TODO: handle pages with no pageId via domain
const pageId = parsePageId(url)
let title = config.siteName
let authorName = config.siteAuthor
let title = config.name
let authorName = config.author
try {
const page = await getPage(pageId)
@@ -50,7 +50,7 @@ export const oembed = async ({
return {
version: '1.0',
type: 'rich',
provider_name: config.siteName,
provider_name: config.author,
provider_url: config.host,
title,
author_name: authorName,