Cómo crear un CMS simple con Cloudflare, GitHub Actions y Metalsmith
Construyamos nosotros mismos un CMS. Pero en lugar de crear una interfaz de usuario, ¡obtendremos esa interfaz de usuario de forma gratuita en forma del propio GitHub! Aprovecharemos GitHub como forma de administrar el contenido de nuestro generador de sitios estáticos (podría ser cualquier generador de sitios estáticos). Aquí está la esencia: GitHub será el lugar para administrar, controlar versiones y almacenar archivos, y también será el lugar donde editaremos nuestro contenido. Cuando se produzcan modificaciones, una serie de automatizaciones probarán, verificarán y, en última instancia, implementarán nuestro contenido en Cloudflare.
Puede encontrar el código completo del proyecto disponible en GitHub. Impulso mi propio sitio web, jonpauluritis.com, exactamente de esta manera.
¿Cómo se ve la pila completa?
Aquí está la pila tecnológica con la que trabajaremos en este artículo:
- Cualquier editor de Markdown (opcional, por ejemplo, Typora.io)
- Un generador de sitios estáticos (por ejemplo, Metalsmith)
- Github con acciones de Github (CICD e implementación)
- Trabajadores de Cloudflare
¿Por qué debería importarle esta configuración? Esta configuración es potencialmente la forma más sencilla, rápida, barata (~$5/mes) y más sencilla de administrar un sitio web (o sitio Jamstack). Es increíble tanto desde el punto de vista técnico como desde la perspectiva de la experiencia del usuario. Esta configuración es tan asombrosa que literalmente salí y compré acciones de Microsoft y Cloudflare.
Pero antes de empezar…
No voy a guiarte en la configuración de cuentas en estos servicios, estoy seguro de que puedes hacerlo tú mismo. Estas son las cuentas que necesitas configurar:
- GitHub (Registrarse en GitHub Actions).
- Sitios de trabajadores de Cloudflare (este es el que cuesta $5 al mes).
También recomendaría Typora para disfrutar de una increíble experiencia de escritura en Markdown, pero los editores de Markdown son algo muy personal, así que utilice el editor que le parezca adecuado.
Estructura del proyecto
Para darle una idea de hacia dónde nos dirigimos, aquí está la estructura del proyecto completada:
├── build.js├── .github/workflows│ ├── deploy.yml│ └── nodejs.js├── layouts│ ├── about.hbs│ ├── article.hbs│ ├── index.hbs│ └── partials│ └── navigation.hbs├── package-lock.json├── package.json├── public├── src│ ├── about.md│ ├── articles│ │ ├── post1.md│ │ └── post2.md│ └── index.md├── workers-site└── wrangler.toml
Paso 1: cosas de la línea de comando
En una terminal, cambie el directorio al lugar donde guarde este tipo de proyectos y escriba esto:
$ mkdir cms cd cms npm init -y
Eso creará un nuevo directorio, entrará en él e inicializará el uso de npm.
Lo siguiente que queremos hacer es subirnos a hombros de gigantes. Usaremos varios paquetes npm que nos ayudan a hacer cosas, cuyo núcleo es usar el generador de sitios estáticos Metalsmith :
$ npm install --save-dev metalsmith metalsmith-markdown metalsmith-layouts metalsmith-collections metalsmith-permalinks handlebars jstransformer-handlebars
Junto con Metalsmith, hay un par de detalles más útiles. ¿Por qué Metalsmith? Hablemos de eso.
Paso 2: orfebre
He estado probando generadores de sitios estáticos durante 2 o 3 años y todavía no he encontrado “el indicado”. Todos los grandes nombres, como Eleventy, Gatsby, Hugo, Jekyll, Hexo y Vuepress, son totalmente geniales, pero no puedo superar la simplicidad y extensibilidad de Metalsmith.
Como ejemplo, este código le construirá un sitio:
// EXAMPLE... NOT WHAT WE ARE USING FOR THIS TUTORIALMetalsmith(__dirname) .source('src') .destination('dest') .use(markdown()) .use(layouts()) .build((err) = if (err) throw err);
Bastante genial, ¿verdad?
En aras de la brevedad, escriba esto en la terminal y crearemos una estructura y archivos para empezar.
Primero, crea los directorios:
$ mkdir -p src/articles mkdir -p layouts/partials
Luego, cree el archivo de compilación:
$ touch build.js
A continuación, crearemos algunos archivos de diseño:
$ touch layouts/index.hbs touch layouts/about.hbs touch layouts/article.hbs touch layouts/partials/navigation.hbt
Y, finalmente, configuraremos nuestros recursos de contenido:
$ touch src/index.md touch src/about.md touch src/articles/post1.md touch src/articles/post1.md touch src/articles/post2.md
La carpeta del proyecto debería verse así:
├── build.js├── layouts│ ├── about.hbs│ ├── article.hbs│ ├── index.hbs│ └── partials│ └── navigation.hbs├── package-lock.json├── package.json└── src ├── about.md ├── articles │ ├── post1.md │ └── post2.md └── index.md
Paso 3: agregamos algo de código
Para ahorrar espacio (y tiempo), puede utilizar los siguientes comandos para crear el contenido de nuestro sitio web ficticio. Siéntete libre de acceder a los “artículos” y crear tus propias publicaciones de blog. La clave es que las publicaciones necesitan algunos metadatos (también llamados “Front Matter”) para poder generarse correctamente. Los archivos que querrás editar son index.md
, post1.md
y post2.md
.
Los metadatos deben verse así:
---title: 'Post1'layout: article.hbs ---## Post content here....
O, si eres vago como yo, usa estos comandos de terminal para agregar contenido simulado de GitHub Gists a tu sitio:
$ curl https://gist.githubusercontent.com/jppope/35dd682f962e311241d2f502e3d8fa25/raw/ec9991fb2d5d2c2095ea9d9161f33290e7d9bb9e/index.md src/index.md$ curl https://gist.githubusercontent.com/jppope/2f6b3a602a3654b334c4d8df047db846/raw/88d90cec62be6ad0b3ee113ad0e1179dfbbb132b/about.md src/about.md$ curl https://gist.githubusercontent.com/jppope/98a31761a9e086604897e115548829c4/raw/6fc1a538e62c237f5de01a926865568926f545e1/post1.md src/articles/post1.md$ curl https://gist.githubusercontent.com/jppope/b686802621853a94a8a7695eb2bc4c84/raw/9dc07085d56953a718aeca40a3f71319d14410e7/post2.md src/articles/post2.md
A continuación, crearemos nuestros diseños y diseños parciales (“parciales”). Usaremos Manillars.js para nuestro lenguaje de plantillas en este tutorial, pero puedes usar cualquier lenguaje de plantillas que te convenga. Metalsmith puede trabajar con casi todos ellos y no tengo ninguna opinión firme sobre los lenguajes de plantillas.
Construya el diseño del índice
!DOCTYPE htmlhtml head style /* Keeping it simple for the tutorial */ body { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } .navigation { display: flex; justify-content: center; margin: 2rem 1rem; } .button { margin: 1rem; border: solid 1px #ccc; border-radius: 4px; padding: 0.5rem 1rem; text-decoration: none; } /style /head body {{navigation }} div {{#each articles }} a href="{{path}}"h3{{ title }}/h3/a p{{ description }}/p {{/each }} /div /body/html
Un par de notas:
- Nuestra “navegación” aún no ha sido definida, pero eventualmente reemplazará el área donde
{{navigation }}
residemos. {{#each }}
iterará a través de la “colección” de artículos que metalsmith generará durante su proceso de construcción.- Metalsmith tiene muchos complementos que puedes usar para cosas como hojas de estilo, etiquetas, etc., pero este tutorial no trata de eso, así que lo dejaremos para que lo explore.
Crear la página Acerca de
Agregue lo siguiente a su about.hbs
página:
!DOCTYPE htmlhtml head style /* Keeping it simple for the tutorial */ body { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } .navigation { display: flex; justify-content: center; margin: 2rem 1rem; } .button { margin: 1rem; border: solid 1px #ccc; border-radius: 4px; padding: 0.5rem 1rem; text-decoration: none; } /style /head body {{navigation }} div {{{contents}}} /div /body/html
Construya el diseño de los artículos.
!DOCTYPE htmlhtml head style /* Keeping it simple for the tutorial */ body { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } .navigation { display: flex; justify-content: center; margin: 2rem 1rem; } .button { margin: 1rem; border: solid 1px #ccc; border-radius: 4px; padding: 0.5rem 1rem; text-decoration: none; } /style /head body {{navigation }} div {{{contents}}} /div /body/html
Es posible que hayas notado que este es exactamente el mismo diseño que la página Acerca de. Es. Solo quería cómo cubrir páginas adicionales para que sepas cómo hacerlo. Si quieres que este sea diferente, hazlo.
Agregar navegación
Agregue lo siguiente al layouts/partials/navigation.hbs
archivo
div div a href="/"Home/a a href="/about"About/a /div/div
Seguro que no hay mucho que decir… pero realmente no se supone que sea un tutorial de Metalsmith/SSG. ¯_(ツ)_/¯
Paso 4: el archivo de compilación
El corazón y el alma de Metalsmith es el archivo de construcción. Para ser más exhaustivo, lo repasaré línea por línea.
Empezamos importando las dependencias.
Nota rápida: Metalsmith se creó en 2014 y el sistema de módulos predominante en ese momento era common.js
, por lo que me quedaré con las declaraciones requeridas en lugar de los módulos ES. También vale la pena señalar que la mayoría de los otros tutoriales también utilizan declaraciones requeridas, por lo que omitir un paso de compilación con Babel hará que la vida sea un poco menos compleja aquí.
// What we use to glue everything togetherconst Metalsmith = require('metalsmith');
// compile from markdown (you can use targets as well)const markdown = require('metalsmith-markdown');
// compiles layoutsconst layouts = require('metalsmith-layouts');
// used to build collections of articlesconst collections = require('metalsmith-collections');
// permalinks to clean up routesconst permalinks = require('metalsmith-permalinks');
// templatingconst handlebars = require('handlebars');
// register the navigationconst fs = require('fs');handlebars.registerPartial('navigation', fs.readFileSync(__dirname + '/layouts/partials/navigation.hbt').toString());
// NOTE: Uncomment if you want a server for development// const serve = require('metalsmith-serve');// const watch = require('metalsmith-watch');
A continuación, incluiremos a Metalsmith y le indicaremos dónde encontrar sus objetivos de compilación:
// MetalsmithMetalsmith(__dirname) // where your markdown files are .source('src') // where you want the compliled files to be rendered .destination('public')
Hasta ahora, todo bien. Una vez que tengamos el origen y el destino configurados, configuraremos la representación de rebajas, la representación de diseños y le informaremos a Metalsmith que utiliza “Colecciones”. Éstas son una forma de agrupar archivos. Un ejemplo sencillo sería algo así como “publicaciones de blog”, pero en realidad podría ser cualquier cosa, por ejemplo recetas, reseñas de whisky o lo que sea. En el ejemplo anterior, llamamos a la colección “artículos”.
// previous code would go here
// collections create groups of similar content .use(collections({ articles: { pattern: 'articles/*.md', }, })) // compile from markdown .use(markdown()) // nicer looking links .use(permalinks({ pattern: ':collection/:title' })) // build layouts using handlebars templates // also tell metalsmith where to find the raw input .use(layouts({ engine: 'handlebars', directory: './layouts', default: 'article.html', pattern: ["*/*/*html", "*/*html", "*html"], partials: { navigation: 'partials/navigation', } }))
// NOTE: Uncomment if you want a server for development// .use(serve({// port: 8081,// verbose: true// }))// .use(watch({// paths: {// "${source}/**/*": true,// "layouts/**/*": "**/*",// }// }))
A continuación, agregaremos el complemento Markdown, para que podamos usar Markdown para compilar el contenido en HTML.
A partir de ahí, usamos el complemento de diseños para envolver nuestro contenido sin procesar en el diseño que definimos en la carpeta de diseños. Puede leer más sobre los aspectos prácticos de esto en el sitio oficial del complemento, pero el resultado es que podemos usarlo {{{contents}}}
en una plantilla y simplemente funcionará.
La última adición a nuestro pequeño script de compilación será el método de compilación:
// Everything else would be above this.build(function(err) { if (err) { console.error(err) } else { console.log('build completed!'); }});
Al juntar todo, deberíamos obtener un script de compilación similar a este:
const Metalsmith = require('metalsmith');const markdown = require('metalsmith-markdown');const layouts = require('metalsmith-layouts');const collections = require('metalsmith-collections');const permalinks = require('metalsmith-permalinks');const handlebars = require('handlebars');const fs = require('fs');
// Navigationhandlebars.registerPartial('navigation', fs.readFileSync(__dirname + '/layouts/partials/navigation.hbt').toString());
Metalsmith(__dirname) .source('src') .destination('public') .use(collections({ articles: { pattern: 'articles/*.md', }, })) .use(markdown()) .use(permalinks({ pattern: ':collection/:title' })) .use(layouts({ engine: 'handlebars', directory: './layouts', default: 'article.html', pattern: ["*/*/*html", "*/*html", "*html"], partials: { navigation: 'partials/navigation', } })) .build(function (err) { if (err) { console.error(err) } else { console.log('build completed!'); } });
Soy un fanático de lo simple y limpio y, en mi humilde opinión, no hay nada más simple o limpio que una construcción de Metalsmith. Sólo necesitamos hacer una actualización rápida del package.json
archivo y podremos ejecutarlo:
"name": "buffaloTraceRoute", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "node build.js", "test": "echo "No Tests Yet!"" "" }No related posts.
Deja un comentario