Astro js web framework
Experiment with Astro → GitHub → Cloudflare web deployment
~/winxp/projects/astro-test
GitHub: ncvp/astro-test
Cloudflare: cornett1610@gmail.com
Web: astro-test.ncvp.me
See also
Contents
Create astro-test.ncvp.me subdomain.
Add CNAME record specified by Cloudflare. Host name - astro-test, Points to - astro-test-8ol.pages.dev
Delete all other DNS records. IONOS may leave a spurious A record.
Create ncvp/astro-test private repo.
Connection between Cloudflare and GitHub is automatically achieved when setting up Cloudflare.
Connection between local PC and GitHub
% git remote add origin git@github.com-ncvp:ncvp/astro-test
There were some subtleties in setting up the project.
The project is ‘Pages’ not ‘Workers’. Dashboard should hav a url like this dash.cloudflare/…/pages/view/… AI said this was required for simple DNS change from IONOS which didn’t affect anything other than astro-test.ncvp.me
Build settings: Build command - npm run build, Build oputput directory - /dist
Basic
% cd ~/winxp/projects/astrojs
% npm create astro@latest
Where install: ./astro-test
Start with basic, helpful starter project
Initialise a new Git repository: yes
Extensions
% npm install @fancyapps/ui
% npx astro add mdx
Git
% cd astro-test
% git remote add origin git@github.com-ncvp:ncvp/astro-test
% git branch -M main
% git commit -m “Initial Astro setup”
% git push -u origin main
Shows state in browser as it is modified
% cd ~/winxp/projects/astro-test
% npm run dev
Prepare site for production
% cd ~/winxp/projects/astro-test
% npm run build
Leave out
Preview build locally before deploying
% cd ~/winxp/projects/astro-test
% npm run preview
% cd ~/winxp/projects/astro-test
% git push -u origin main
astro-local & astro-wpress
Normal Cloudflare deployment doesn’t work with local WP because Cloudflare can’t get at local site. GitHub is not needed.
You can’t use the normal Cloudflare build mechanism, but have to build locally and upload /dist
Install Cloudflare CLI tool (Wrangler)
% npm install -D wrangler
Connect to Cloudflare account
% npx wrangler login
Build Astro site locally
% npm run build
Upload complete site to Cloudflare
% npx wrangler pages deploy dist
Adding this to package.json
”deploy”: “npm run build && wrangler pages deploy dist”,
allows
% npm run deploy # Build and deploy in one command
Deployment failed, 8 Jun 26
Authentication error.
Gemini seemed to think this was not unusual
% npx wrangler login
Follow instructions
Successfully logged in
% npm run deploy # Worked
It is possible to deploy the media library direct to Cloudflare and get CF to do the build, but above method works, and seems simpler
Follow this Astro doc
Nothing happens locally. Possibly because it hasn’t been built yet by Cloudflare.
fancyapps.com/fancybox/api/options
Options difficult to find. Ask AI
Install with npm
% cd ~/winxp/projects/astro-test
% npm install @fancyapps/ui
Add
<script>
import { Fancybox } from “@fancyapps/ui”;
import “@fancyapps/ui/dist/fancybox/fancybox.css”;
Fancybox.bind(“[data-fancybox]”, {});
</script>
to end of <body> in Layout.astro
It can also be installed via its CDN, but why would one?
Export all content from WP site to ~/winxp/projects/wordpress/export/xxxx
% npx wordpress-export-to-markdown # Invokes wizard
GitHub page
Options:
Quite a few images in gallery 3 from several-galleries were not downloaded.
They were in the XML file, but the tool did not download them.
Lots of them had a localhost URL in their <guid> tags. Even when I changed these strings to the correct site url and reran the tool it still missed the images.
Construct gallery HTML with
% wp_gall_ext xml-file-path
% md ~/winxp/projects/astrojs
% mv ~/winxp/projects/astro-test ~/winxp/projects/astrojs/astro-test
% cd ~/winxp/projects/astrojs/astro-test
% npm run dev # Worked normally
% git push -u origin main # Worked normally
Browse https://astro-test.ncvp.me # Worked normally
Create GitHub private repo ncvp/astro-blog
% cd ~/winxp/projects/astrojs
% npm create astro@latest
./astro-blog, blog template, create Git repo
% cd astro-blog
% git remote add origin git@github.com-ncvp:ncvp/astro-test
% git branch -M main
% git commit -m “Initial Astro setup”
% git push -u origin main
% npm install @fancyapps/ui
Cloudflare
Had to configure GitHub to allow connection to ncvp/astro-blog
Build settings: Build command - npm run build, Build oputput directory - /dist
IONOS
Create astro-blog.ncvp.me
Create CNAME record as specified by Cloudflare. All other records deleted automatically.
Remove toolbar at bottom of screen
Add devToolbar: {enabled: false}, to astro.config.mjs
This is Astro’s term for mapping site-url/slug to page file.
Astro routing reference is not very helpful with specifics
Basics
Fairly obvious
site-url/xxxx → project/src/pages/xxxx.astro, or xxxx.md
Slightly subtle
site-url/xxxx/→ project/src/pages/xxxx/index.astro, or xxxx.md
Confusing in the sitemap. Don’t use index.yyyy except where required, ie src/pages/index.astro
Blog
Individual posts are xxxx.md files in src/content/blog accessed via site-url/blog/xxxx.
This scheme can presumably be extended if we get thousands of posts, but it should be good enough for me.
Lists
site-url/blog list all posts
site-url/blog/category/xxxx lists all posts in category xxxx.
This is done
Similarly author.
Tags could be implemented in the same way.
Weird directory/file names
| site-url/slug | Astro file |
| /yyyy/mm | /src/pages/[year]/[month].astro |
| /author/xxxx | /src/pages/author/[slug].astro |
| /category/xxxx | /src/pages/category/[slug].astro |
| /tag/xxxx | /src/pages/tag/[slug].astro |
| xxx/yyy | /src/pages/[slug].astro Renders post xxx/yyy |
| xxx/yyy | /src/pages/[...path].astro Renders page xxx/yyy |
All missing url’s come here. There’s supposed to be a mechanism for routing site-url/blog/category/invalid-slug to […category], for example, but Gemini couldn’t get it too work.
It’s quite easy to get 404.astro to deal with obvious stale links and mis-typings, and this is actually a better solution.
I thought initially that this would not be possible with a static site, but Astro has an ingenious solution. At build time it generates a compact index which the client only downloads if the search box is clicked.
% npm install fuse.js
src/pages/search.json.js
Includes getCollection() like rss.xml.js
The only website of mine that has real data is ncvp.co.uk/ngarden, and the connections with local WP site and Leaflet plans pages make it rather unsuitable.
echoandnarcissus.co.uk is a good candidate. It doesn’t have an ssl certificate, so would benefit with Cloudflare deployment. It’s completely static anyway. SEO could be tried. Possible route:
-
Move coral.ncvp.net/echo-orig to ncvp.me/echo
-
Develop astro-echo.ncvp.me
-
Point echoandnarcissus.co.uk → Cloudflare
Rebuild
% npm run build # Full rebuild for production using cache
% npx astro build —force # Clears cache before production build
% npx astro dev —force # Starts dev server bypassing the cache
% npx astro —version
Follow this Astro article
Create src/pages/wpress.astro and src/pages/posts/[slug].astro in astro-test project. That works for posts, but doing the same for pages will interfere with the existing pages. Create a new project astro-wpress.
Special pages
| / | Home. Must be provided as src/pages/index.astro |
| /sitemap | WP page rendered by shortcode. Astro page urls all point to https://ncvp.me/wp. Not easily replaced ‘cos my src/pages/sitemap is built by traversing tree of real files. |
| /blog | Replacement src/pages/blog.astro seems to hide WP blog, whose urls are wrong anyway. |
| 404 | Replacement src/pages/404.astro |
| /select-posts | Block page |
| /category/category-name | Not a WP page. Will need to be constructed |
| /tag/tag-name | |
| /author/author-name |
Special routing
/src/pages[…path].astro
% cd astro-project-root
% npx astro add mdx
What are the advantages over MD. Are there any of my standard pages which can’t be expressed as MD
Remove endpoint from built site
Sometimes it’s useful to have files like src/pages/all-pages.astro which are used in development but shouldn’t be part of the final site.
Change this line in /package.json
{
…
“scripts”: {
…
“build”: “astro build && rm -rf dist/all-pages”,
…
},
…
}
Presumably this will also affect the build that Cloudflare does.
% tree . -dq —gitignore
.
├── public
├── scripts
└── src
├── assets
├── components
├── data
├── layouts
├── pages
│ ├── author
│ ├── category
│ ├── tag
│ └── [year]
├── styles
└── utils
Possibly need for favicon
scripts
Node.js scripts ‘outside’ Astro. eg get-menu.mjs which gets the menu in location header in astro-wpress
src/assets
Gemini recommends this should be used for ‘almost everything’
import alias @assets is set to point here
src/data
Where I keep all the menu definition files, including the ouptu of get-menu.mjs in astro-wpress
src/styles
Global astro-wpress.css in astro-wpress
src/utils
Helper JS utilities used in various Astro components
% npm install @astrojs/rss
/astro.config.mjs
export default defineConfig({
…
site: ‘https://xxxx.ncvp.me\’, // Cloud URL
…
});
Layout.astro
Add to <head>
<link rel=“alternate” type=“application/rss+xml” title=“astro-wpress.ncvp.me” href={`${Astro.site}rss.xml`} />
/src/pages/rss.xml.js
Two sorts of posts fetch (so far). From local collection, and from WP REST API
% npx astro add react
First needed for Gemini supplied MDX test page
Create new subdomain at IONOS
In Cloudflare add the new custom domain to the Workers & Pages project
In Astro update the domain name in /astro.config.mjs
Change the site title in Header.astro
Change the url in src/pages/rss.xml.js
Gemini says I can keep old domain in Cloudflare and set up a Bulk Redirect, but I don’t need this with a new test site. Delete astro-blog.ncvp.me from CloudFlare and IONOS
This is proving surprisingly difficult.
These are the features that need to be converted
-
Document title in heading.
-
Internal anchors and links.
-
External file and web links.
-
Tables.
-
Sections with 2 columns.
-
Interpret single <CR> as new line (not new paragraph).
-
Interpret <CR><CR> as new paragraph.
pandoc and Mammoth fail with single <CR> in paragraph.
Test files in ~/winxp/projects/doc
test.docx
test1.docx
Utilities in ~/winxp/projects/doc
docx2astro.js and docx2html.js
Node.js projects using Mammoth and Turndown
Mildly interesting. Ultimately unusable because Mammoth can’t handle <CR>
Useful the way it writes the .md directly to an Astro post or page.
docx_to_astro.py
doc2md.py
docx_to_astro_md.py
docx_to_markdown_precise.py
Looked promising for a while, but turned out to be unusable.
AstroEditor looked a bit crude, and only seemed to work on content collections.
/scripts/get-menu.mjs gets the menu via the WP REST API and builds menu_definition_auto.js in /src/data
Check carefully against menu_definition.js and replace when OK
Add to package.json manually
…
“scripts”: {
“get-menu”: “node scripts/get-menu.mjs”,
…
Run with
% cd ~/winxp/projects/astrojs/astro-local
% npm run get-menu
Neat, but in practice it’s so simple to handcraft a menu and it’s changed so rarely it’s hardly worth bothering with the automated version.
Copy /tsconfig.json from astro-wpress
Add
site: “https://al.ncvp.me\”,\
devToolbar: { enabled: false },
to astro.config.mjs. Rest of file slightly different with MDX stuff
Create a 70x70 logo, and put separately named copies in /public and /src/assets
Copy src/layouts/Layout.astro from astro-wpress and tweak
Copy src/components/Footer.astro, Header.astro, Menu.astro from astro-wpress and tweak
Copy src/styles/astro-wpress.css and rename astro-local.css
Copy src/data/menu_definition.js from astro-wpress
Copy src/pages/index.astro from astro-wpress and tweak. At this point Home page burst into life.
Copy src/utils from astro-wpress
Content source possibilities (Gemini)
Other editorial possibilities
**1. Decoupled CMS (Headless)
**If you like the “dashboard” feel but want something more modern or specialized than WordPress, look at:
Payload CMS: This is currently the “darling” of the Astro community. It’s a Node.js-based headless CMS that is incredibly flexible. You can run it locally (just like WP) or host it. It uses TypeScript, so it integrates perfectly with your Astro constants and types.
Sanity.io: A cloud-based CMS where you define your “schema” (fields) in code. It has a great real-time editor and an Astro integration that makes fetching data very simple.
**2. Git-Based CMS (The “MD” Evolution)
**Since you’ve already worked with Markdown files, these tools provide a visual UI on top of your .md or .mdx files. They don’t need a database; they just commit changes to your Git repo.
Decap CMS (formerly Netlify CMS): An open-source classic. It adds an admin dashboard to your site that lets you write posts, and when you hit “Save,” it commits a Markdown file to your repo.
TinaCMS: This is the most impressive “modern” choice. It allows for Visual Editing, where you click on a heading directly on your Astro site and type to change it. It saves the changes back to your Markdown files.
**3. Keystatic (The “Local-First” Winner)
**Since you are currently enjoying a local-first workflow with Xubuntu and symlinks, you should definitely check out Keystatic.
It was built specifically for the “Astro/Next.js” era.
It has no database. It’s a beautiful UI that runs in your browser but saves everything as local files in your project.
It handles image uploads brilliantly---it will save them directly into your public/ folder without needing symlinks or rsync.
Comparison for a WP User:
| Feature | WordPress | Keystatic | TinaCMS |
| Data Source | MySQL Database | Local Markdown/JSON | Git-based Markdown |
| Interface | Familiar / Heavy | Minimal / Clean | Visual / Live |
| Images | Media Library | Local Folder | Local Folder/Cloud |
| Astro Setup | REST API Fetch | Local File Import | GraphQL/Git |
My Recommendation: If you want to stick with a “Local Build” workflow but want to get away from the overhead of a full PHP/MySQL WordPress install, try Keystatic. It gives you a clean editorial UI while keeping everything as simple files on your hard drive.
Vanilla classic galleries work fine.
Block galleries are useless. Don’t waste time on them.
Astro static sites with content supplied by WordPress sites.
| astro-wpress | Uses ncvp.me/wp for content Downloads wp-content/uploads |
| astro-local | Uses localhost/wp/wp for content Symlinks wp-content/uploads |
| astro-echo | Uses ncvp.me/echo for content Media library remains at ncvp.me/echo |
astro-wpress
Content supplied by ncvp.me/wp.
Media library downloaded to ~/winxp/projects/astrojs/astro-wpress/public/wp-content/uploads.
Deployment to Cloudflare via Wrangler.
Requires a media sync step in the build process.
No GitHub repo.
This method allows editorial input from several people in disparate locations.Should the source site be private? How?
astro-local
Content supplied by localhost/wp/wp.
Media library symlinked to ~/winxp/projects/astrojs/astro-local/public/wp-content/uploads
Deployment to Cloudflare via Wrangler.
Very straightforward connection.
No GitHub repo.
astro-echo
Weird issue with Blog page. Nothing happened until the block page was copied from one of the other sites, when it burst into life
Simpler setup. No categories or tags, so no special post lists required.Uses the cloud media library. Can’t be downloaded because at least half the pictures are not used on the site. Can they be deleted?
What’s the point of this sort of setup?
All the pages are classic apart from the following:
Home
Nice arrangement of general notes in the left-hand column and recent news posts in the right-hand. Keep it because it just works in Astro and ncvp-class
Blog
I made this look like the RHS of the home page by copying the Home page and taking out the ‘General’ column. I had to leave the single column in place, however.
There was an oddity with astro-echo. Initially /blog produced nothing. But when I copied the Blog page from one of the other sites it sprang into life.
Select posts
I made this in the block editor for the category date and tag WP selector blocks. I had to make an [ncvp_author] shortcode because the author selector is missing in WP. This caused a lot of trouble (for Gemini) because WP scripts try to get in and hijack the links to /category/test etc. It may be less trouble to do the whole page with a classic shortcode.
The post search section at the bottom is hidden in CSS. It could never work. It’s replaced with src/pages/search-posts.astro
Apart from src/pages/search-posts.astro there are no pages or posts stored in the src tree. All pages and posts are retrieved from the WordPress REST API via these weird directory/file names:
| site-url/slug | Astro file |
| /yyyy/mm | /src/pages/[year]/[month].astro |
| /author/xxxx | /src/pages/author/[slug].astro |
| /category/xxxx | /src/pages/category/[slug].astro |
| /tag/xxxx | /src/pages/tag/[slug].astro |
| xxx/yyy | /src/pages/[slug].astro Renders post xxx/yyy |
| xxx/yyy | /src/pages/[...path].astro Renders page xxx/yyy |
astro-local
Astro needs access to localhost/xxxx/wp-content/uploads to build the static site locally.
Do this with a symlink. This seems to survive Git and Wrangler deployment to Cloudflare.
~/winxp/projects/astrojs/astro-local/public/wp-content$ ls -l uploads
lrwxrwxrwx 1 ncvp ncvp 55 May 23 13:59 uploads -> /home/ncvp/winxp/apache/htdocs/wp/wp/wp-content/uploads
astro-wpress
Astro static site gets everything from ncvp.me/wp. Media files are downloaded (and synced) to /public/wp-content/uploads. This works well, but it isn’t a s neat as astro-local.
astro-echo
Astro static site currently gets media files from ncvp.me/echo. This is not ideal. It would be better to use Cloudflare like astro-local but only when the future of echo is decided.
Fancybox on Astro works well, and is version 5.
ncvp-image-gallery works fine with galleries with ncvp-class. Behaviour is very slightly different on localhost/wp/wp and astro-local. Nothing to be worth trying to fix.
Two textflow test pages on localhost/wp/wp both use hard-coded HTML. Much the best way. Don’t bother with anything else.
/
astro.con.mjs
tsconfig.json --- defines paths to layouts, components, utils etc.
/public
Site logo
All images as .webp for sites with content in /src
/wp-content/uploads for sites sourced from WP sites
/scripts
constants.ts --- site url, WP REST API url etc.
get-menu.mjs --- automatic menu builder. Over the top
/src
content.config.ts --- defines posts collection as Zod schema
content --- defines posts and pages content collections
data --- menu definition
styles --- global stylesheet
utils --- post_helpers.js
Python script in ~/winxp/projects/astrojs/fmatter
Call with % fmatter from anywhere