Tutti Progetti

Come ho costruito il mio sito web: Portfolio e Blog.

Oct 31
Sito web di Marco De Carlo

Sito Web: https://marcodecarlo.com/

GitHub: https://github.com/marcodecarlo/marcodecarlo/

Questo sito è stato progettato per presentare il mio profilo professionale e riunire i progetti in un'unica piattaforma. L'obiettivo? Offrire una panoramica chiara e approfondita delle mie competenze e agevolare le connessioni professionali.

Stack Tecnologico

La scelta delle tecnologie è stata guidata da tre criteri:

Lo stack include Next.js, Tailwind CSS, MDX e Typescript.

Next.js

Next.js è un framework basato su React che semplifica la configurazione e ottimizza le prestazioni. Tra i vantaggi che ho trovato:

Grazie a Next.js, posso sviluppare applicazioni più efficaci e scalabili, che sarebbero altrimenti difficili da mantenere come sviluppatore singolo.

Tailwind CSS

Tailwind CSS è un framework CSS che utilizza utility class per semplificare la stilizzazione. Le sue principali qualità:

TypeScript

TypeScript fornisce un sistema di tipi statici per JavaScript, migliorando la qualità del codice. TypeScript mi permette di individuare errori durante la scrittura, velocizzando il flusso di lavoro e rendendo superflua la consultazione continua della documentazione.

MDX

MDX consente di combinare componenti JSX con Markdown. Questa caratteristica è perfetta per creare articoli interattivi e progetti personalizzati in cui i componenti diventano parte integrante del contenuto.

Contentlayer

Contentlayer semplifica la gestione dei contenuti in Next.js, importando file Markdown/MDX come componenti React. La tipizzazione robusta assicura che i dati siano coerenti e ben strutturati.

Definizione dei tipi

La tipizzazione dei post è definita in un file schema dedicato, e il percorso dei file è configurato per accedere direttamente ai file .mdx.

Seleziona file
./content/definitions/Post.ts
import { defineDocumentType } from "contentlayer/source-files";
 
const Post = defineDocumentType(() => ({
name: "Post",
filePathPattern: "posts/\*.mdx",
contentType: "mdx",
fields: {
title: { type: "string", required: true },
publishedAt: { type: "string", required: true },
description: { type: "string" },
status: { type: "enum", options: ["draft", "published"], required: true },
},
}));
 
export default Post;

Nel percorso definito da contentDirPath + filePathPattern = /content/posts possiamo trovare tutti i file in formato .mdx che vanno a descrivere i diversi progetti presenti nel sito web.

Pagine e Routing

app
(main)
progetti
[slug]
page.tsx

Ogni progetto è una pagina dinamica in progetti/[slug], con rotte generate tramite generateStaticParams() di Next.js per SEO ottimizzata e migliori prestazioni.

./app/(main)/progetti/[slug]/page.tsx
import { allPosts } from "@/.contentlayer/generated";
 
export async function generateStaticParams() {
  const posts = allPosts
    .filter((p) => p.status === "published")
    .map((p) => ({ slug: p.slug }));
 
  return posts.map((post) => ({
    slug: post.slug,
  }));
}
 
export default function Page({ params }: { params: { slug: string } }) {
  const post = allPosts.find((post) => post.slug === params?.slug);
 
  if (!post) {
    notFound();
  }
  const formattedPost = formatPost(post);
 
  return <Post post={formattedPost} />;
}

Grazie all'utilizzo di generateStaticParams() vengono generati in modo automatico le rotte del sito web, durante il processo di build. Abbiamo utilizzato allPosts che importa tutti i post generati nella build, grazie a ContentLayer.

Componenti per MDX

Sono stati realizzati diversi componenti personalizzati per migliorare la visualizzazione di elementi HTML, come titoli, liste, immagini, ecc... e per avere un maggior controllo sul loro stile e/o comportamento.

Questi componenti vengono esportati e successivamente vengono usati per sostituire gli elementi HTML presenti nel contenuto dei file MDX. L'hook useMDXComponent permette di trasformare il codice MDX in un componente React, pronto per essere renderizzato con JSX.

./components/post/Post.tsx
import { useMDXComponent } from "next-contentlayer/hooks";
import { components } from "@/lib/mdx";
 
export default function Post({ post }: { post: FormattedPost }) {
  const MDXContent = useMDXComponent(post.body.code);
  return (
    <>
      <h1>{post.title}</h1>
      <MDXContent components={components} />
    </>
  );
}

Design e Layout

Sono un appassionato di design minimalista, dove il contenuto è il fulcro dell’esperienza utente. Tuttavia, un design semplice non deve essere privo di personalità. Il design rappresenta l'identità di una persona o di un’azienda.

Durante i miei colloqui ho imparato che l'aspetto visivo di un sito può essere determinante per le prime impressioni, specialmente per i recruiter che hanno poco tempo per valutare tutte le competenze tecniche. Per questo, ho curato ogni dettaglio, aggiungendo elementi visivi per catturare l’attenzione e trasmettere professionalità.

Layout e Configurazioni Tailwind

app
(main)
progetti
layout.tsx
layout.tsx

Grazie NextJS ho definito un layout root, che viene utilizzato per le pagine presenti nella directory ./app, mentre è stato definito un diverso layout per le pagine interne al sito web in modo da poter utilizzare un header di tipo sticky.

Per creare un layout flessibile e responsivo, ho personalizzato le griglie tramite Tailwind, andando a definire due principali classi di layout grid specifiche (layout-sm e layout-xl).

./tailwind.config.ts
{
  plugins:[
    plugin(function({addBase, theme}){
      addBase({
        ".layout-sm": {
          "grid-template-columns": `1fr min(${theme("screens.sm")},100%) 1fr`,
        },
        ".layout-xl": {
          "grid-template-columns": `1fr minmax(auto,${theme("spacing.60")}) min(${theme("screens.sm")},100%) minmax(auto,${theme("spacing.60")}) 1fr`,
        },
      })
    })
  ],
}

Questo tipo di layout permette di adattarsi a diverse dimensioni di schermo, creando una colonna centrale principale e due colonne ai lati.

La caratteristica principale è quella di aver definito la colonna centrale con una dimensione massima del breakpoint sm, cioè la dimensione massima per i mobile, in modo tale che la colonna centrale sia ottimizzata per i dispositivi mobile e le colonne laterali si espandono correttamente sui schermi più grandi.

Organizzazione dei Componenti

components
catalog
common
layout
svg

Ho organizzato la struttura delle cartelle per i componenti in quattro macro-aree:

Ogni componente ha un proprio file di stile .module.scss per una maggiore leggibilità del codice.

SEO e Sitemap

Per l'ottimizzazione SEO, ho integrato robots.txt e sitemap.xml, generata dinamicamente con Next.js. infatti NextJs permette di generare dinamicamente la sitemap per tutte le pagine del sito, garantendo che ogni nuovo progetto sia automaticamente aggiunto e indicizzato. Ogni pagina dei progetti è stata inserita nella sitemap, così quando si effettua la build viene generata in modo autoomatico. Visitando il sito online sarà possibile vedere la sitemap generata.

Seleziona file
./app/(main)/progetti/sitemap.ts
import { allPosts } from '@/.contentlayer/generated';
import type { MetadataRoute } from 'next';
 
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const posts = await allPosts
.filter((p) => p.status === "published")
 
    return posts.map((p) => ({
      url: `https://marcodecarlo.com/progetti/${p.slug}`,
      lastModified: new Date(p.publishedAt),
    }))
 
}
 

Grazie all'uso di generateMetadata() vengono generati dinamicamente i metadati delle pagine. Viene così personalizzato il titolo per ogni pagina e l'url canonico che è utile a livello SEO perchè aiuta i moti di ricerca a capire quale versione di una pagina è considerata quella principale, evitando così errori di contenuti duplicati.

./app/(main)/progetti/[slug]/page.tsx
export async function generateMetadata({
  params,
}: {
  params: { slug: string };
}): Promise<Metadata> {
  const post = allPosts.find((post) => post.slug === params?.slug);
 
  if (!post) {
    notFound();
  }
 
  const url = `/progetti/${post.slug}`;
 
  return {
    title: `${post.title} ⋅ Marco De Carlo`,
    alternates: { canonical: url },
  };
}

Infine ho eseguito un'analisi delle prestazioni del sito web "marcodecarlo.com" effettuata con Lighthouse e il risultato è altamente ottimizzato in termini di prestazioni, accessibilità, SEO e "Best Practices".

Analisi Lighthouse

Vercel

Vercel è una piattaforma di deployment e collaborazione per sviluppatori frontend integrata con GitHub, che supporta un flusso di lavoro fluido tra sviluppo e rilascio. Nel mio caso, gestisco due branch principali:

Seguo una numerazione del tipo "X.X.X-SNAPSHOT", dove:

Quando le modifiche passano su main, il suffisso -SNAPSHOT viene rimosso per indicare che la versione è stabile e pronta per la distribuzione.

Futuri sviluppi

Includerò una sezione Blog per condividere aggiornamenti, esperienze e approfondimenti sugli strumenti e sulle tecnologie che utilizzo.

La possibilità di aggiungere delle categorie e un input di ricerca per migliorare l'esperienza d'uso.

Infine vorrei portare il multilingua in inglese per rendere il mio lavoro fluibile a più persone possibili.