M1 Mac의 Strapi로 개츠비 설정하기
오류와 해결 방안을 제외하고 내가 이 블로그에서 언급한 모든 단계는 strapi 공식 사이트tutorial에서 나온 것이다.
1단계: 노드 설치 v14
내가 이 블로그를 쓸 때 v15는 최신 노드 버전이었지만strapi는 지원하지 않았다.
명령줄에 다음 명령을 입력합니다.
nvm install 14.16.0
2. 사선 설치
npm install --global yarn
3단계:strapi 블로그 폴더 만들기
블로그의 백엔드 (strapi) 와 백엔드 (gatsby) 를 저장할 폴더를 만듭니다.다음 명령은 폴더를 만들고 이동합니다.
take strapi-blog
# above command is short for
mkdir strapi-blog
cd strapi-blog
4단계: 템플릿을 사용하여strapi를 설정합니다
yarn create strapi-app backend --quickstart --template https://github.com/strapi/strapi-template-blog
자, 첫 번째 실수를 했습니다.잘못
어!sharp에서 미리 만들어진libvips 8.10.5 바이너리 파일은darwin-arm64v8에 사용되지 않습니다
솔루션
참고 문헌: Fix 샤프 도서관에서 온github repo
brew를 사용하여 VIP 설치
brew install vips
나는 그것을 내 기계에 설치하는 데 약 14분이 걸렸다.샤프를 설치하다
npm i sharp
백엔드 폴더 삭제
템플릿이 있는strapi를 설정하기 위해 명령을 실행할 때, 백엔드 폴더를 만들고,strapi와 관련된 모든 파일과 폴더를 추가합니다.이 명령을 다시 실행할 때,strapi는 백엔드 폴더가 비어 있어야 한다고 불평하기 때문에,strapi가 불평하기 전에 비웁니다.
rm -rf backend
strapi 프로젝트를 설정하기 위해 명령을 다시 실행합니다
yarn create strapi-app backend --quickstart --template https://github.com/strapi/strapi-template-blog
명령은 이제 정상적으로 작동할 수 있을 것이다.단계 5:strapi 대시보드를 설정하는 관리자 사용자
strapi 설정이 완료되면,dashboard는 브라우저에서 열리고, 관리자 사용자를 설정하기 위한 등록 페이지를 볼 수 있습니다.
필요한 세부 사항을 추가하면strapi를 처리할 필요가 없습니다. 지금은 서버를 실행하기만 하면 됩니다.
6단계: 게이츠비 설정
게이츠비cli 설치
yarn global add gatsby-cli
백엔드 폴더 이동
개츠비 항목을 단독 폴더에 설정해야 하기 때문에, 백엔드 폴더에서 먼저 꺼내야 합니다
cd ..
개츠비 프로젝트 만들기
현재,strapi 블로그에서 다음 명령을 실행하여 새로운 게이츠비 프로젝트를 설정해야 합니다
gatsby new frontend
잘못
wasm 코드 제출 분배 실패 - 프로세스 메모리 부족
솔루션
노드 v15로 전환
이 문제는 특히 노드 v14에 나타나기 때문에 v15로 전환합니다.만약 네가 아직 기계에 그것을 설치하지 않았다면, 너는 아래의 명령을 사용할 수 있다
# install node v15
nvm install 15.0.0
# use v15 locally
nvm use 15.0.0
내 기계에 설치하는 데 약 10분이 걸렸는데, 맥의 선풍기 소리가 크게 들렸다.게이츠비 프로젝트를 설정하기 위해 명령을 다시 실행합니다
gatsby new frontend
이제 프로젝트는 아무런 문제가 없을 것이다.단계 7: 생성.게이츠비 프로젝트 루트 디렉터리의 env 파일
# move to gatsby project
cd frontend
# create .env file inside the project root
nano .env
파일에 다음을 추가합니다.GATSBY_ROOT_URL=http://localhost:8000
API_URL=http://localhost:1337
8단계: 게이츠비에 strapi 설정
gatsby source strapi 설치
yarn add gatsby-source-strapi
개츠비 설정 내용을 바꿉니다.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-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/gatsby-icon.png`
},
},
"gatsby-plugin-offline",
],
};
9단계: 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",
},
{
rel: "stylesheet",
href:
"https://cdn.jsdelivr.net/npm/[email protected]/dist/css/uikit.min.css",
},
]}
script={[
{
src:
"https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.0/js/uikit.min.js",
},
{
src:
"https://cdn.jsdelivr.net/npm/[email protected]/dist/js/uikit-icons.min.js",
},
{
src: "https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.0/js/uikit.js",
},
]}
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
}
}
}
}
`;
10단계: 블로그 스타일 디자인
src/assets/css/main을 만듭니다.css 파일 및 다음을 추가합니다.
a {
text-decoration: none !important;
}
h1 {
font-family: Staatliches !important;
font-size: 120px !important;
}
#category {
font-family: Staatliches !important;
font-weight: 500 !important;
}
#title {
letter-spacing: 0.4px !important;
font-size: 22px !important;
font-size: 1.375rem !important;
line-height: 1.13636 !important;
}
#banner {
margin: 20px !important;
height: 800px !important;
}
#editor {
font-size: 16px !important;
font-size: 1rem !important;
line-height: 1.75 !important;
}
.uk-navbar-container {
background: #fff !important;
font-family: Staatliches !important;
}
img:hover {
opacity: 1 !important;
transition: opacity 0.25s cubic-bezier(0.39, 0.575, 0.565, 1) !important;
}
11단계: 불필요한 구성 요소/페이지 삭제
명령줄에 다음 명령을 입력합니다.
rm src/components/header.js src/components/layout.css src/pages/page-2.js src/pages/using-typescript.tsx
12단계: 페이지/인덱스의 내용을 바꿉니다.다음 코드 사용하기
import React from "react";
import { graphql, useStaticQuery } from "gatsby";
import Layout from "../components/layout";
import "../assets/css/main.css";
const IndexPage = () => {
const data = useStaticQuery(query);
return (
<Layout seo={data.strapiHomepage.seo}>
<div className="uk-section">
<div className="uk-container uk-container-large">
<h1>{data.strapiHomepage.hero.title}</h1>
</div>
</div>
</Layout>
);
};
const query = graphql`
query {
strapiHomepage {
hero {
title
}
seo {
metaTitle
metaDescription
shareImage {
publicURL
}
}
}
}
`;
export default IndexPage;
단계 13: 어셈블리/레이아웃의 내용을 대체합니다.다음 코드 사용하기
import React from "react";
import PropTypes from "prop-types";
import { StaticQuery, graphql } from "gatsby";
import Seo from "./seo";
const Layout = ({ children, seo }) => (
<StaticQuery
query={graphql`
query {
strapiHomepage {
seo {
metaTitle
metaDescription
shareImage {
publicURL
}
}
}
}
`}
render={(data) => (
<>
<Seo seo={seo} />
<main>{children}</main>
</>
)}
/>
);
Layout.propTypes = {
children: PropTypes.node.isRequired,
};
export default Layout;
14단계: 생성/src/모듈/내비게이션.다음 코드 사용하기
코드 편집기에서 새 파일을 만들고 다음을 추가합니다.
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) => (
<div>
<div>
<nav className="uk-navbar-container" data-uk-navbar>
<div className="uk-navbar-left">
<ul className="uk-navbar-nav">
<li>
<Link to="/">{data.strapiGlobal.siteName}</Link>
</li>
</ul>
</div>
<div className="uk-navbar-right">
<button
className="uk-button uk-button-default uk-margin-right"
type="button"
>
Categories
</button>
<div uk-dropdown="animation: uk-animation-slide-top-small; duration: 1000">
<ul className="uk-nav uk-dropdown-nav">
{data.allStrapiCategory.edges.map((category, i) => (
<li key={`category__${category.node.slug}`}>
<Link to={`/category/${category.node.slug}`}>
{category.node.name}
</Link>
</li>
))}
</ul>
</div>
</div>
</nav>
</div>
</div>
)}
/>
);
export default Nav;
15단계: 어셈블리/레이아웃에서 탐색 어셈블리를 가져오고 사용합니다.js
구성 요소/레이아웃의 코드를 바꿉니다.js에서 제공하는 내용은 다음과 같습니다.
import React from "react";
import PropTypes from "prop-types";
import { StaticQuery, graphql } from "gatsby";
import Nav from "./nav";
import Seo from "./seo";
const Layout = ({ children, seo }) => (
<StaticQuery
query={graphql`
query {
strapiHomepage {
seo {
metaTitle
metaDescription
shareImage {
publicURL
}
}
}
}
`}
render={(data) => (
<>
<Seo seo={seo} />
<Nav />
<main>{children}</main>
</>
)}
/>
);
Layout.propTypes = {
children: PropTypes.node.isRequired,
};
export default Layout;
16단계: 블로그 목록 인터페이스
게이츠비 이미지 설치
npm install gatsby-image
메모스텔라피 공식 홈페이지의 강좌는 게이츠비 사진을 사용하는데, 이 사진은 이미 버려졌지만, 우리는 본 블로그에서 업데이트하지 않을 것이다.
Deprecation Note
새 파일 구성 요소/카드를 만듭니다.js 다음 코드 추가
import React from "react";
import { Link } from "gatsby";
import Img from "gatsby-image";
const Card = ({ article }) => {
return (
<Link to={`/article/${article.node.slug}`} className="uk-link-reset">
<div className="uk-card uk-card-muted">
<div className="uk-card-media-top">
<Img
fixed={article.node.image.childImageSharp.fixed}
imgStyle={{ position: "static" }}
/>
</div>
<div className="uk-card-body">
<p id="category" className="uk-text-uppercase">
{article.node.category.name}
</p>
<p id="title" className="uk-text-large">
{article.node.title}
</p>
<div>
<hr className="uk-divider-small" />
<div className="uk-grid-small uk-flex-left" data-uk-grid="true">
<div>
{article.node.author.picture && (
<Img
fixed={article.node.author.picture.childImageSharp.fixed}
imgStyle={{ position: "static", borderRadius: "50%" }}
/>
)}
</div>
<div className="uk-width-expand">
<p className="uk-margin-remove-bottom">
{article.node.author.name}
</p>
</div>
</div>
</div>
</div>
</div>
</Link>
);
};
export default Card;
새 파일 구성 요소/글을 만듭니다.js 다음 코드 추가
import React from "react";
import Card from "./card";
const Articles = ({ articles }) => {
const leftArticlesCount = Math.ceil(articles.length / 5);
const leftArticles = articles.slice(0, leftArticlesCount);
const rightArticles = articles.slice(leftArticlesCount, articles.length);
return (
<div>
<div className="uk-child-width-1-2@s" data-uk-grid="true">
<div>
{leftArticles.map((article, i) => {
return (
<Card
article={article}
key={`article__left__${article.node.slug}`}
/>
);
})}
</div>
<div>
<div className="uk-child-width-1-2@m uk-grid-match" data-uk-grid>
{rightArticles.map((article, i) => {
return (
<Card
article={article}
key={`article__right__${article.node.slug}`}
/>
);
})}
</div>
</div>
</div>
</div>
);
};
export default Articles;
페이지/인덱스에서 코드를 바꿉니다.js는 다음과 같은 내용을 제공했다
import React from "react";
import { graphql, useStaticQuery } from "gatsby";
import Layout from "../components/layout";
import ArticlesComponent from "../components/articles";
import "../assets/css/main.css";
const IndexPage = () => {
const data = useStaticQuery(query);
return (
<Layout seo={data.strapiHomepage.seo}>
<div className="uk-section">
<div className="uk-container uk-container-large">
<h1>{data.strapiHomepage.hero.title}</h1>
<ArticlesComponent articles={data.allStrapiArticle.edges} />
</div>
</div>
</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 {
fixed(width: 800, height: 500) {
src
}
}
}
author {
name
picture {
childImageSharp {
fixed(width: 30, height: 30) {
src
}
}
}
}
}
}
}
}
`;
export default IndexPage;
개츠비 응용 프로그램 시작
지금까지 구축해 온 내용을 보려면 개츠비 애플리케이션을 시작하고 블로그를 확인하십시오.
gatsby develop
17단계: 기사 페이지
반작용력 표시와 반작용력 모멘트를 설치하다
yarn add react-markdown react-moment moment
개츠비의 내용을 바꾸다.노드js, 코드는 다음과 같습니다
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions;
const result = await graphql(
`
{
articles: allStrapiArticle {
edges {
node {
strapiId
slug
}
}
}
}
`
);
if (result.errors) {
throw result.errors;
}
// Create blog articles pages.
const articles = result.data.articles.edges;
const ArticleTemplate = require.resolve("./src/templates/article.js");
articles.forEach((article, index) => {
createPage({
path: `/article/${article.node.slug}`,
component: ArticleTemplate,
context: {
slug: article.node.slug,
},
});
});
};
module.exports.onCreateNode = async ({ node, actions, createNodeId }) => {
const crypto = require(`crypto`);
if (node.internal.type === "StrapiArticle") {
const newNode = {
id: createNodeId(`StrapiArticleContent-${node.id}`),
parent: node.id,
children: [],
internal: {
content: node.content || " ",
type: "StrapiArticleContent",
mediaType: "text/markdown",
contentDigest: crypto
.createHash("md5")
.update(node.content || " ")
.digest("hex"),
},
};
actions.createNode(newNode);
actions.createParentChildLink({
parent: node,
child: newNode,
});
}
};
src/templates/article 파일을 만듭니다.다음 코드 사용하기
import React from "react";
import { graphql } from "gatsby";
import Img from "gatsby-image";
import Moment from "react-moment";
import Layout from "../components/layout";
import Markdown from "react-markdown";
export const query = graphql`
query ArticleQuery($slug: String!) {
strapiArticle(slug: { eq: $slug }, status: { eq: "published" }) {
strapiId
title
description
content
publishedAt
image {
publicURL
childImageSharp {
fixed {
src
}
}
}
author {
name
picture {
childImageSharp {
fixed(width: 30, height: 30) {
src
}
}
}
}
}
}
`;
const Article = ({ data }) => {
const article = data.strapiArticle;
const seo = {
metaTitle: article.title,
metaDescription: article.description,
shareImage: article.image,
article: true,
};
return (
<Layout seo={seo}>
<div>
<div
id="banner"
className="uk-height-medium uk-flex uk-flex-center uk-flex-middle uk-background-cover uk-light uk-padding uk-margin"
data-src={article.image.publicURL}
data-srcset={article.image.publicURL}
data-uk-img
>
<h1>{article.title}</h1>
</div>
<div className="uk-section">
<div className="uk-container uk-container-small">
<Markdown source={article.content} escapeHtml={false} />
<hr className="uk-divider-small" />
<div className="uk-grid-small uk-flex-left" data-uk-grid="true">
<div>
{article.author.picture && (
<Img
fixed={article.author.picture.childImageSharp.fixed}
imgStyle={{ position: "static", borderRadius: "50%" }}
/>
)}
</div>
<div className="uk-width-expand">
<p className="uk-margin-remove-bottom">
By {article.author.name}
</p>
<p className="uk-text-meta uk-margin-remove-top">
<Moment format="MMM Do YYYY">{article.published_at}</Moment>
</p>
</div>
</div>
</div>
</div>
</div>
</Layout>
);
};
export default Article;
우리가 게이츠비 노드를 편집했기 때문이다.js, 새로운 변화를 보기 위해 게이츠비 서버를 다시 시작해야 합니다.너는 이제 블로그의 상세한 정보 페이지를 볼 수 있을 것이다.gatsby 서버를 실행하는 명령줄에서 다음을 수행합니다.
# stop the server
control + c
# run the gatsby server again
gatsby develop
18단계: 블로그 분류 페이지
파일 src/templates/category를 만듭니다.다음 코드 사용하기
import React from "react";
import { graphql } from "gatsby";
import ArticlesComponent from "../components/articles";
import Layout from "../components/layout";
export const query = graphql`
query Category($slug: String!) {
articles: allStrapiArticle(
filter: { status: { eq: "published" }, category: { slug: { eq: $slug } } }
) {
edges {
node {
slug
title
category {
name
}
image {
childImageSharp {
fixed(width: 660) {
src
}
}
}
author {
name
picture {
childImageSharp {
fixed(width: 30, height: 30) {
...GatsbyImageSharpFixed
}
}
}
}
}
}
}
category: strapiCategory(slug: { eq: $slug }) {
name
}
}
`;
const Category = ({ data }) => {
const articles = data.articles.edges;
const category = data.category.name;
const seo = {
metaTitle: category,
metaDescription: `All ${category} articles`,
};
return (
<Layout seo={seo}>
<div className="uk-section">
<div className="uk-container uk-container-large">
<h1>{category}</h1>
<ArticlesComponent articles={articles} />
</div>
</div>
</Layout>
);
};
export default Category;
개츠비의 내용을 바꾸다.노드다음 코드 사용하기
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions;
const result = await graphql(
`
{
articles: allStrapiArticle {
edges {
node {
strapiId
slug
}
}
}
categories: allStrapiCategory {
edges {
node {
strapiId
slug
}
}
}
}
`
);
if (result.errors) {
throw result.errors;
}
// Create blog articles pages.
const articles = result.data.articles.edges;
const categories = result.data.categories.edges;
const ArticleTemplate = require.resolve("./src/templates/article.js");
articles.forEach((article, index) => {
createPage({
path: `/article/${article.node.slug}`,
component: ArticleTemplate,
context: {
slug: article.node.slug,
},
});
});
const CategoryTemplate = require.resolve("./src/templates/category.js");
categories.forEach((category, index) => {
createPage({
path: `/category/${category.node.slug}`,
component: CategoryTemplate,
context: {
slug: category.node.slug,
},
});
});
};
module.exports.onCreateNode = async ({ node, actions, createNodeId }) => {
const crypto = require(`crypto`);
if (node.internal.type === "StrapiArticle") {
const newNode = {
id: createNodeId(`StrapiArticleContent-${node.id}`),
parent: node.id,
children: [],
internal: {
content: node.content || " ",
type: "StrapiArticleContent",
mediaType: "text/markdown",
contentDigest: crypto
.createHash("md5")
.update(node.content || " ")
.digest("hex"),
},
};
actions.createNode(newNode);
actions.createParentChildLink({
parent: node,
child: newNode,
});
}
};
새로운 변경 사항을 보기 위해 개츠비 서버를 다시 시작합니다
gatsby 서버를 실행하는 명령줄에서 다음을 수행합니다.
# stop the server
control + c
# run the gatsby server again
gatsby develop
너는 이제 특정 유형에 따라 열거된 블로그를 볼 수 있을 것이다.결론
축하합니다. 스트라피와 게츠비 블로그를 성공적으로 만들었습니다.나는 블로그를 설립한 후 작은 문제에 부딪혔다.블로그 목록 페이지에서 블로그의 특색 있는 그림은 정확하게 불러오지 않고, 분류에 따라 블로그를 열거한 페이지에 정확하게 불러옵니다.너의 상황을 알려줘!
읽어 주셔서 감사합니다. 만약 곤혹스럽거나 건의가 있다면 아래에 평론해 주십시오.다음 블로그에서 만나요!
도구책
Reference
이 문제에 관하여(M1 Mac의 Strapi로 개츠비 설정하기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/truemark/setup-gatsby-with-strapi-in-m1-mac-3j5i텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)