블로그에서 Tailwind CSS 사용
백엔드에서 다음strapi 항목을 사용합니다.
Gatsby의 개발 환경 구축
단계는 아래 설명Gridsome 때였어요.과 같습니다.
여기에서 strappi-starter-gridsome-blog/gatsby-blog 디렉터리를 만들고 VScode에서 다음 파일을 만듭니다.
.devcontainer/devcontainer.json
{
"name": "gatsby-blog",
"dockerComposeFile": "docker-compose.yml",
"service": "gatsby-blog",
"workspaceFolder": "/src",
"settings": {
},
"extensions": [
],
}
name과 서비스가gatsby 블로그인 것을 제외하고는 Gridsome 때와 같다..devcontainer/docker-compose.yml
version: "3"
services:
gatsby-blog:
image: node:14.16
ports:
- "8000:8000"
volumes:
- ../:/src
working_dir: /src
command: /bin/sh -c "while sleep 1000; do :; done"
networks:
- shared-network
networks:
shared-network:
external: true
연결strapi 프로젝트와 같은 네트워크을 위해shared-network를 네트워크로 설정합니다.파일이 작성되면 VScode에서 Remote-Contaainer:Reopen in Contaainer가 실행됩니다.
$ yarn create strapi-starter . gatsby-blog
Gatsby 설치가 끝난 후 다음과 같이strapi를 계속 설치하지만 여기에는 설치하지 않고 control+c로 강제로 종료합니다.Gatsby 구성
Gatsby는 fronted 디렉토리에 설치됩니다.
frontend/.env.example fronte를/를 입력합니다.다음과 같이 env로 복사합니다.
frontend/.env
GATSBY_ROOT_URL=http://localhost:8000
API_URL=http://strapi-blog:1337
strapi-blog는 strapi의devcontainer/docker-compose.yml에 설정된 용기 이름입니다.Gatsby 시작
다음 명령을 실행하여 Gatsby를 시작합니다.
$ cd frontend
$ yarn develop
Gatsby가 시작될 때http://localhost:8000/가 방문할 때 블로그가 표시됩니다.Tailwind CSS 설치
$ yarn add --dev gatsby-plugin-postcss tailwindcss@latest postcss@latest autoprefixer@latest
tailwind.config.js 만들기
다음 명령을 실행하여tailwind를 진행합니다.config.postcssconfig.제작
$ npx tailwindcss init -p
tailwind.config.js 편집
제작된 fronte/tailwind입니다.config.다음은 js를 편집하고 Purge 설정을 추가합니다.
frontend/tailwind.config.js
module.exports = {
purge: ['./src/**/*.{js,jsx,ts,tsx}'],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}
gatsby-plugen-postcss의 유효성
frontend/gatsby-config.js의plugens에gatsby-plugen-postcss를 추가합니다.
frontend/gatsby-config.js
require("dotenv").config({
path: `.env`,
});
module.exports = {
plugins: [
"gatsby-plugin-react-helmet",
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
{
resolve: "gatsby-source-strapi",
options: {
apiURL: process.env.API_URL || "http://localhost:1337",
contentTypes: ["article", "category", "writer"],
singleTypes: [`homepage`, `global`],
queryLimit: 1000,
},
},
"gatsby-plugin-image",
"gatsby-transformer-sharp",
"gatsby-plugin-sharp",
{
resolve: `gatsby-plugin-manifest`,
options: {
name: "gatsby-starter-default",
short_name: "starter",
start_url: "/",
background_color: `#663399`,
theme_color: `#663399`,
display: `minimal-ui`,
icon: `src/images/favicon.png`,
},
},
"gatsby-plugin-offline",
// 追加
"gatsby-plugin-postcss"
],
};
CSS 읽기 추가
frontend/src/styles/global.제작 css는 다음과 같다.
frontend/src/styles/global.css
@tailwind base;
@tailwind components;
@tailwind utilities;
전체 사이트에 CSS를 반영하기 위해fronte/gatsby-browser.js,fronte/src/styles/global을 만듭니다.import css.frontend/gatsby-browser.js
import './src/styles/global.css';
TailBlocks 기반 구성 요소 편집 첫 페이지
Gridsome의 상황입니다.와 마찬가지로 편집합니다.
frontend/src/pages/index.js의main.css의 import을 삭제하고 JSX를 변경합니다.
또한 allStrapiArtical의 검색에 description을 추가합니다.
frontend/src/pages/index.js
import React from "react";
import { graphql, useStaticQuery } from "gatsby";
import Layout from "../components/layout";
import ArticlesComponent from "../components/articles";
const IndexPage = () => {
const data = useStaticQuery(query);
return (
<Layout seo={data.strapiHomepage.seo}>
<ArticlesComponent articles={data.allStrapiArticle.edges} />
</Layout>
);
};
const query = graphql`
query {
strapiHomepage {
hero {
title
}
seo {
metaTitle
metaDescription
shareImage {
publicURL
}
}
}
allStrapiArticle(filter: { status: { eq: "published" } }) {
edges {
node {
strapiId
slug
title
category {
name
}
image {
childImageSharp {
gatsbyImageData(width: 800, height: 500)
}
}
author {
name
picture {
childImageSharp {
gatsbyImageData(width: 30, height: 30)
}
}
}
}
}
}
}
`;
export default IndexPage;
frontend/src/components/seo.js의 UIkit CSS와 JS의 읽기 부분을 삭제합니다.frontend/src/components/seo.js
import React from "react";
import PropTypes from "prop-types";
import { Helmet } from "react-helmet";
import { useStaticQuery, graphql } from "gatsby";
const SEO = ({ seo = {} }) => {
const { strapiGlobal } = useStaticQuery(query);
const { defaultSeo, siteName, favicon } = strapiGlobal;
// Merge default and page-specific SEO values
const fullSeo = { ...defaultSeo, ...seo };
const getMetaTags = () => {
const tags = [];
if (fullSeo.metaTitle) {
tags.push(
{
property: "og:title",
content: fullSeo.metaTitle,
},
{
name: "twitter:title",
content: fullSeo.metaTitle,
}
);
}
if (fullSeo.metaDescription) {
tags.push(
{
name: "description",
content: fullSeo.metaDescription,
},
{
property: "og:description",
content: fullSeo.metaDescription,
},
{
name: "twitter:description",
content: fullSeo.metaDescription,
}
);
}
if (fullSeo.shareImage) {
const imageUrl =
(process.env.GATSBY_ROOT_URL || "http://localhost:8000") +
fullSeo.shareImage.publicURL;
tags.push(
{
name: "image",
content: imageUrl,
},
{
property: "og:image",
content: imageUrl,
},
{
name: "twitter:image",
content: imageUrl,
}
);
}
if (fullSeo.article) {
tags.push({
property: "og:type",
content: "article",
});
}
tags.push({ name: "twitter:card", content: "summary_large_image" });
return tags;
};
const metaTags = getMetaTags();
return (
<Helmet
title={fullSeo.metaTitle}
titleTemplate={`%s | ${siteName}`}
link={[
{
rel: "icon",
href: favicon.publicURL,
},
{
rel: "stylesheet",
href: "https://fonts.googleapis.com/css?family=Staatliches",
},
]}
script={[
]}
meta={metaTags}
/>
);
};
export default SEO;
SEO.propTypes = {
title: PropTypes.string,
description: PropTypes.string,
image: PropTypes.string,
article: PropTypes.bool,
};
SEO.defaultProps = {
title: null,
description: null,
image: null,
article: false,
};
const query = graphql`
query {
strapiGlobal {
siteName
favicon {
publicURL
}
defaultSeo {
metaTitle
metaDescription
shareImage {
publicURL
}
}
}
}
`;
frontend/src/components/nav.js의 JSX를 변경합니다.frontend/src/components/nav.js
import React from "react";
import { Link, StaticQuery, graphql } from "gatsby";
const Nav = () => (
<StaticQuery
query={graphql`
query {
strapiGlobal {
siteName
}
allStrapiCategory {
edges {
node {
slug
name
}
}
}
}
`}
render={(data) => (
<header className="text-gray-600 body-font">
<div className="container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center">
<Link to="/" className="flex title-font font-medium items-center text-gray-900 mb-4 md:mb-0">{data.strapiGlobal.siteName}</Link>
<nav className="md:ml-auto flex flex-wrap items-center text-base justify-center">
{data.allStrapiCategory.edges.map((category, i) => (
<Link to={`/category/${category.node.slug}`} key={`category__${category.node.slug}`} className="mr-5 text-gray-600 hover:text-gray-900">
{category.node.name}
</Link>
))}
</nav>
</div>
</header>
)}
/>
);
export default Nav;
frontend/src/components/articles.js의 JSX를 변경합니다.frontend/src/components/articles.js
import React from "react";
import Card from "./card";
const Articles = ({ articles }) => {
return (
<section className="text-gray-600 body-font">
<div className="container px-5 py-4 mx-auto">
<div className="flex flex-wrap -m-4">
{articles.map((article, i) => {
return (
<Card
article={article}
key={`article__left__${article.node.slug}`}
/>
);
})}
</div>
</div>
</section>
);
};
export default Articles;
frontend/src/components/card.js의 JSX를 변경합니다.frontend/src/components/card.js
import React from "react";
import { Link } from "gatsby";
import { GatsbyImage } from "gatsby-plugin-image";
const Card = ({ article }) => {
return (
<div className="p-4 md:w-1/3">
<Link to={`/article/${article.node.slug}`}>
<div className="h-full border-2 border-gray-200 border-opacity-60 rounded-lg overflow-hidden">
<GatsbyImage
image={article.node.image.childImageSharp.gatsbyImageData}
alt={`Hero image`}
className="lg:h-48 md:h-36 w-full object-cover object-center"
/>
<div className="p-6">
<h2 className="tracking-widest text-xs title-font font-medium text-gray-400 mb-1">{article.node.category.name}</h2>
<h1 className="title-font text-lg font-medium text-gray-900 mb-3">{article.node.title}</h1>
<p className="leading-relaxed mb-3 text-gray-600">{article.node.description }</p>
<div className="flex items-center flex-wrap ">
<span className="text-gray-400 inline-flex items-center lg:ml-auto md:ml-0 ml-auto leading-none text-sm py-1">
{article.node.author.name}
{article.node.author.picture && (
<GatsbyImage
image={article.node.author.picture.childImageSharp.gatsbyImageData}
alt={`Picture of ${article.node.author.name}`}
className="rounded-full h-12 w-12 flex items-center justify-center ml-3"
/>
)}
</span>
</div>
</div>
</div>
</Link>
</div>
);
};
export default Card;
수정 전수정 후
아바타 이미지의 왼쪽 상단만 왜 원형이 되지 않았을까.
총결산
개인적으로 Vue제 Gridsome은 쓰기가 더 쉽다.
다만, Gatsby의 개발은 활발하지만, Gridsome의 개발은 매우 느린 것 같아 아직 버전 1이 되지 않았다.
백엔드에서 사용하는 strapi의 관리 화면에도 리액트가 있어 향후 일을 고려하면 가츠비도 나쁘지 않다.
Reference
이 문제에 관하여(블로그에서 Tailwind CSS 사용), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/mseto/articles/strapi-starter-gatsby-blog텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)