This is a React SPA blog built on top of Contentful Headless CMS.
Running version: https://blog.rpenha.net/
- Frontend:
- ReactJS: https://react.dev/
- React Router: https://reactrouter.com/
- Vite: https://vitejs.dev/
- Bootstrap with SASS customization: https://getbootstrap.com/
- SASS: https://sass-lang.com/
- Terser (for JS minification and splitting): https://terser.org/
- PurgeCSS (for minimal CSS bundle size): https://purgecss.com/
- Package Manager: pnpm: https://pnpm.io/
- Hosting: AWS Cloudfront & AWS S3 Static Web App Hosting: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistS3AndCustomOrigins.html#using-s3-as-origin
- Headless CMS: Contentful: https://www.contentful.com/
The following environment variables are required and should be defined in a .env.production file:
VITE_CONTENTFUL_SPACE_ID: Your Contentful Space IDVITE_CONTENTFUL_ACCESS_TOKEN: Your Contentful Delivery API Access Token (Important: Keep this secret!).
More information about configuring Vite environment variables can be found here: https://vitejs.dev/guide/env-and-mode#env-variables-and-modes
Note: You should never commit the .env.production file to version control.
-
Clone this repository.
-
Install dependencies:
pnpm install
-
Create a
.env.productionfile in the project root directory and add the required environment variables (see above). -
Build the project for production:
pnpm run build
This will create an optimized production build in the
distfolder. -
Deploy the
distfolder to your AWS S3 bucket and configure Cloudfront for distribution.
-
Clone this repository.
-
Install dependencies:
pnpm install
-
Create a
.env.localfile in the project root directory and add the required environment variables (see above). -
Build the project for development:
pnpm run dev
This will start a local copy of the app on http://localhost:5173/ for development.
Note: You should never commit the .env.local file to version control.
This blog utilizes Contentful as a headless CMS for managing blog content. Content types and models are defined within the Contentful platform.
Important: Ensure you configure the correct VITE_CONTENTFUL_SPACE_ID and VITE_CONTENTFUL_ACCESS_TOKEN environment variables to connect to your Contentful space.
{
"name": "Post",
"description": "",
"displayField": "title",
"fields": [
{
"id": "title",
"name": "Title",
"type": "Symbol",
"localized": false,
"required": true,
"validations": [],
"disabled": false,
"omitted": false
},
{
"id": "slug",
"name": "Slug",
"type": "Symbol",
"localized": false,
"required": true,
"validations": [],
"disabled": false,
"omitted": false
},
{
"id": "author",
"name": "Author",
"type": "Link",
"localized": false,
"required": true,
"validations": [
{
"linkContentType": [
"author"
]
}
],
"disabled": false,
"omitted": false,
"linkType": "Entry"
},
{
"id": "category",
"name": "Category",
"type": "Link",
"localized": false,
"required": true,
"validations": [
{
"linkContentType": [
"category"
]
}
],
"disabled": false,
"omitted": false,
"linkType": "Entry"
},
{
"id": "summary",
"name": "Summary",
"type": "Symbol",
"localized": false,
"required": true,
"validations": [],
"disabled": false,
"omitted": false
},
{
"id": "cover",
"name": "Cover",
"type": "Link",
"localized": false,
"required": false,
"validations": [
{
"linkMimetypeGroup": [
"image"
]
},
{
"assetImageDimensions": {
"width": {
"min": 800,
"max": null
},
"height": {
"min": 200,
"max": null
}
}
}
],
"disabled": false,
"omitted": false,
"linkType": "Asset"
},
{
"id": "body",
"name": "Body",
"type": "RichText",
"localized": false,
"required": true,
"validations": [
{
"enabledMarks": [
"bold",
"italic",
"underline",
"code",
"superscript",
"subscript"
],
"message": "Only bold, italic, underline, code, superscript, and subscript marks are allowed"
},
{
"enabledNodeTypes": [
"heading-2",
"heading-3",
"heading-4",
"heading-5",
"heading-6",
"ordered-list",
"unordered-list",
"hr",
"blockquote",
"embedded-entry-block",
"embedded-asset-block",
"table",
"hyperlink",
"entry-hyperlink",
"asset-hyperlink",
"embedded-entry-inline"
],
"message": "Only heading 2, heading 3, heading 4, heading 5, heading 6, ordered list, unordered list, horizontal rule, quote, block entry, asset, table, link to Url, link to entry, link to asset, and inline entry nodes are allowed"
},
{
"nodes": {}
}
],
"disabled": false,
"omitted": false
}
],
"sys": {
"space": {
"sys": {
"type": "Link",
"linkType": "Space",
"id": "xj8ro83rjak0"
}
},
"id": "post",
"type": "ContentType",
"createdAt": "2024-04-10T00:43:34.084Z",
"updatedAt": "2024-04-15T20:26:56.814Z",
"environment": {
"sys": {
"id": "master",
"type": "Link",
"linkType": "Environment"
}
},
"publishedVersion": 63,
"publishedAt": "2024-04-15T20:26:56.814Z",
"firstPublishedAt": "2024-04-10T00:43:34.461Z",
"createdBy": {
"sys": {
"type": "Link",
"linkType": "User",
"id": "3KHPR1faSdIgPMY8cWpX4y"
}
},
"updatedBy": {
"sys": {
"type": "Link",
"linkType": "User",
"id": "3KHPR1faSdIgPMY8cWpX4y"
}
},
"publishedCounter": 32,
"version": 64,
"publishedBy": {
"sys": {
"type": "Link",
"linkType": "User",
"id": "3KHPR1faSdIgPMY8cWpX4y"
}
},
"urn": "crn:contentful:::content:spaces/xj8ro83rjak0/environments/master/content_types/post"
}
}
+---------------+
| User |
+---------------+
|
v
+---------------+ +----------------+
| Browser |------->| Contentful |
+---------------+ +----------------+
|
v
+---------------+ +----------------+
| Blog Domain |------->| Route 53 |
+---------------+ +----------------+
|
v
+-----------------+ +-----------------+
| CloudFront |------>| AWS Certificate |
+-----------------+ | Manager |
| S3 Origin | +-----------------+
+-----------------+
|
v
+-------------------+
| S3 Content Bucket |
+-------------------+
- This project utilizes a customized SASS version of Bootstrap for styling consistency.
- Code splitting and minification are handled by Terser to improve application performance.
- PurgeCSS ensures the final CSS bundle only contains styles used by the application components.