I. Initialiser un projet Gatsby
Pour initialiser un projet Gatsby, il suffit d'installer node.js puis exécuter cette commande :
npm install --save gatsby react react-dom
Une fois installé, vous pouvez démarrer Gatsby avec la commande suivante :
./node_modules/.bin/gatsby develop
Puis ajoutez ces lignes dans votre fichier package.json
afin d'avoir accès aux commandes de gatsby plus facilement :
"scripts": {"build": "gatsby build","start": "gatsby develop","serve": "gatsby serve","clean": "gatsby clean"}
Vous pouvez à présent exécuter la commande npm start
pour démarrer Gatsby.
PS : Exécutez la commande npm init -f
si votre fichier package.json
n'existe pas.
II. Importer ses notes markdown
Après avoir Initialiser un projet Gatsby, créez un dossier content
qui va contenir toutes vos notes au format markdown (ex: content/hello-world.md
).
NOTE : Vous pouvez ouvrir se dossier avec Obsidian ou n'importe quel éditeur de fichier markdown pour éditer vos notes.
Installez et configurez le package gatsby-source-filesystem
& gatsby-transformer-remark
pour pouvoir detecter les fichiers markdown de votre dossier content
dans Gatsby :
yarn add -D gatsby-source-filesystem gatsby-transformer-remark
// gatsby-config.jsmodule.exports = {plugins: [{resolve: 'gatsby-source-filesystem',options: {path: './content',},},{resolve: 'gatsby-transformer-remark',},],};
Créez le fichier gatsby-node.js
avec la configuration si dessous pour pouvoir créer des pages pour chacune de vos notes markdown :
// gatsby-node.jsexports.createPages = async ({ actions, graphql, reporter }) => {const { createPage } = actions;const result = await graphql(`{allMarkdownRemark {edges {node {idhtmlparent {... on File {name}}}}}}`);if (result.errors) {reporter.panicOnBuild('Error while running GraphQL query.');return;}const markdowns = result.data.allMarkdownRemark.edges;const noteTemplate = require.resolve('./src/templates/noteTemplate.js');markdowns.forEach(({ node }) => {const { id, html } = node;createPage({path: `/${node.parent.name}`,component: noteTemplate,context: { id, html },});});};
// src/templates/noteTemplate.jsimport React from 'react';export default function Template({ pageContext }) {const { html } = pageContext;return <div dangerouslySetInnerHTML={{ __html: html }} />;}
Si vous avez une note hello-world.md
dans votre dossier content
et que vous vous rendez à l'adresse http://localhost:8000/hello-world, cela devrait afficher le contenu de votre fichier markdown.
III. Ajouter le support de la syntaxe markdown d'Obsidian
Les fichiers markdown dans Obsidian peuvent avoir une syntaxe spéciale propre à Obsidian :
[[Internal link]]
[[Internal link|With custom text]]
[[Internal link#heading]]
[[Internal link#heading|With custom text]]
[[Embed note]]
[[Embed note#heading]]
Cette syntaxe permet de relier des notes entre elles via des liens bidirectionnels ([[Internal link]]
).
Pour ajouter le support de ces liens, j'ai créé un plugin gatsby-remark-obsidian.
Vous pouvez intégrer ce plugin avec Remark ou MDX :
// gatsby-config.jsplugins: [{resolve: "gatsby-transformer-remark",options: {plugins: [{resolve: 'gatsby-remark-obsidian',},]}},],
Si vous utilisez MDX :
// gatsby-config.jsplugins: [{resolve: 'gatsby-plugin-mdx',options: {extensions: ['.md'],gatsbyRemarkPlugins: [{resolve: 'gatsby-remark-obsidian',},],},},],
PS : Si vous utilisez Next.js, j'ai créé un autre plugin.
IV. Créer un Graph Viewer comme Obsidian
![[Créer un Graph Viewer comme Obsidian avec Gatsby]]
V. Créer automatiquement une table des matières des fichiers markdown
Après avoir Initialiser un projet Gatsby et importer vos fichiers markdown, vous pouvez créer automatiquement la table des matière d'un fichier markdown dans Gatsby.
// gatsby-node.jsexports.createPages = async ({ actions, graphql, reporter }) => {const { createPage } = actions;const result = await graphql(`{allMarkdownRemark {edges {node {idhtmlheadings {valuedepth}parent {... on File {name}}}}}}`);if (result.errors) {reporter.panicOnBuild('Error while running GraphQL query.');return;}const markdowns = result.data.allMarkdownRemark.edges;const noteTemplate = require.resolve('./src/templates/noteTemplate.js');markdowns.forEach(({ node }) => {const { id, html, headings } = node;createPage({path: `/${node.parent.name}`,component: noteTemplate,context: { id, html, headings },});});};
// src/components/toc.jsimport React from 'react';import { Link } from 'gatsby';import slugify from 'slugify';export default ({ headings = [], depthMin = 1, className = '' }) => {if (!headings.length) return false;return (<ul className={className}>{headings.filter(({ depth }) => depth >= depthMin).map(({ value }) => {const id = slugify(value, { lower: true, strict: true });return (<li key={value}><Link to={`#${id}`} title={value}>{value}</Link></li>);})}</ul>);};
// src/templates/noteTemplate.jsimport React from 'react';import Toc from '../components/toc';export default function Template({ pageContext }) {const { html, headings } = pageContext;return (<><Toc headings={headings} depthMin={2} /><div dangerouslySetInnerHTML={{ __html: html }} /></>);}
Pour créer automatiquement les id sur chaque header, il existe le plugin gatsby-remark-autolink-headers :
yarn add -D gatsby-remark-autolink-headers
// gatsby-config.jsmodule.exports = {plugins: [{resolve: 'gatsby-source-filesystem',options: {path: './content',},},{resolve: 'gatsby-transformer-remark',options: {plugins: [{resolve: 'gatsby-remark-autolink-headers',options: {icon: false,},},],},},],};
VI. Améliorer le SEO de votre digital garden
Pour améliorer le SEO d'un site Gatsby, il existe le plugin helmet
qui permet d'overrider les balises meta de votre site :
yarn add -D react-helmet
Ensuite, créez le fichier src/component/seo.js
qui génerera toutes les balises meta nécessaires pour un bon référencement :
// src/components/seo.jsimport React from 'react';import Helmet from 'react-helmet';import { useLocation } from '@reach/router';import { useStaticQuery, graphql } from 'gatsby';export default ({ title, image, description, article, datePublished, dateModified, tags = [], meta = [] }) => {const location = useLocation();const { site } = useStaticQuery(graphql`query {site {siteMetadata {titlelanglogodescriptionauthorsiteUrlsiteName}}}`);const defaultTitle = site.siteMetadata?.title;const defaultDescription = site.siteMetadata?.description;return (<HelmethtmlAttributes={{ lang: site.siteMetadata.lang }}title={title || defaultTitle}meta={[{name: 'description',content: description || defaultDescription,},{property: 'og:url',content: location.href,},{property: 'og:site_name',content: site.siteMetadata.siteName,},{property: 'og:title',content: title || defaultTitle,},{property: 'og:description',content: description || defaultDescription,},{property: 'og:type',content: article ? 'article' : 'website',},...(image ? [{property: 'og:image',content: image,}] : []),...(tags ? tags.map((tag) => ({property: 'article:tag',content: tag,})) : []),{name: 'twitter:title',content: title || defaultTitle,},{name: 'twitter:creator',content: site.siteMetadata.twitter,},{name: 'twitter:site',content: site.siteMetadata.twitter,},{name: 'twitter:description',content: description || defaultDescription,},...(image ? [{name: 'twitter:image',content: image,}, {name: 'twitter:card',content: 'summary_large_image',}] : [{name: 'twitter:card',content: 'summary',}]),].concat(meta)}><script type="application/ld+json">{JSON.stringify({'@context': 'https://schema.org','@type': article ? 'Article' : 'WebSite',mainEntityOfPage: {'@type': 'WebPage','@id': site.siteMetadata?.siteUrl,},url: location.href,headline: title || defaultTitle,author: {'@type': 'Person',name: site.siteMetadata.author,},publisher: {'@type': 'Organization',name: site.siteMetadata.author,url: site.siteMetadata?.siteUrl,logo: {'@type': 'ImageObject',url: site.siteMetadata.logo,},},description: description || defaultDescription,...(image && { image }),...(dateModified && { dateModified }),...(datePublished && { datePublished }),})}</script></Helmet>);};
Vous pouvez gérer les données par défault de votre site dans le fichier gatsby-config.js
:
// gatsby-config.jsmodule.exports = {siteMetadata: {title: 'Website Title',siteName: 'Website Name',description: 'Description',author: 'author',twitter: '@author',logo: 'http://example.com/logo.png',lang: 'fr',siteUrl: 'https://example.com',}};
Vous pouvez Intégrer le composant SEO
dans la page de votre choix (ex: index.js
) :
// src/pages/index.jsimport React from 'react';import SEO from '../components/seo';const IndexPage = () => (<><SEO /><p className="text-red-800">Hello world!</p></>);export default IndexPage;
Pour remplacer les balises meta par défaut, vous pouvez ajouter des propriétés au composant <SEO />
:
<SEOtitle="title"description="description"image="https://example.com/image.png"dateModified="2020-01-01T08:00"datePublished="2020-01-01T08:00"tags={["tag1", "tag2"]}article={true}/>
Références :