黃胤翔 (Ben)
可能被推坑、打算下次開發時用
你並不孤單,有機會還能參考一下我的經驗
更清楚自己的需求,並找到最適合你的工具
Modern web development bundles advances in performance (bundle splitting, asset prefetching, offline support, image optimization, or server side rendering), developer experience (componentization via React, transpilation via Babel, webpack, hot reloading), accessibility, and security together.
https://www.gatsbyjs.org/docs/gatsby-core-philosophy/
https://www.datocms.com/blog/static-ecommerce-website-snipcart-gatsbyjs-datocms/
每個 HTTP Request 都會回傳一個唯一的頁面,適合內容有高度動態需求的網站
預先把內容渲染出來並輸出到 html 檔,可以放到任何 Static Hosting 而不需要 Application Server
兩種 Pre-rendering
# Create new project
gatsby new [SITE_DIRECTORY] [URL_OF_STARTER_GIT_REPO]
# Run locally
gatsby develop
功能 | 適用情境 | |
gatsby-starter-default (Default) | 安裝基本的設定和樣板 | 適用大部分的情境 |
gatsby-starter-blog | 安裝 Blog 所需的文章列表與文章內頁 | 架 Blog |
gatsby-starter-hello-world | 僅安裝 Gatsby 核心部分 | 研究或開發用途 |
https://www.gatsbyjs.org/starters
/
|-- /.cache
|-- /plugins
|-- /public # Build 完後的檔案都會放在這(自動產生)
|-- /src
|-- /pages # 根據檔名建立路由規則
|-- /templates # 建立動態頁面
|-- html.js
|-- /static
|-- gatsby-config.js
|-- gatsby-node.js
|-- gatsby-ssr.js
|-- gatsby-browser.js
import { graphql } from 'gatsby'
export default ({ data }) => (
<>
{
data.allPost.edges.map(({ node }) => (
<div key={node.id}>
<Link to={node.slug}>
<h3>{node.title}</h3>
</Link>
</div>
))
}
</>
)
export const query = graphql`
query {
allPost(
sort: { fields: [createdAt] order: [DESC] }
) {
edges {
node {
id
slug
title
}
}
}
}
`
src/pages/post.js
export default props => {
return (
<StaticQuery
query={graphql`
query {
allProduct(
limit: 10,
filter: { qty: { gt: 0 } },
sort: { fields: [order, createdAt] order: [DESC, DESC] }
) {
edges {
node {
id
slug
name
product_tags {
id
name
group_number
}
}
}
}
}
`}
render={({ allProduct }) => (
<>{/* render UI by renderProps */}</>
)}
/>
)
}
src/components/ProductBanner.js
(gatsby-plugin-sharp, gatsby-image...)
module.exports = {
siteMetadata: {
title: 'ModernWeb 形象官網',
description: 'ModernWeb 2019',
author: 'Ben',
},
plugins: [
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
`gatsby-plugin-sass`
],
}
gatsby-config.js
https://www.gatsbyjs.org/packages/gatsby-remark-prismjs
Gatsby + Prism.js
https://www.gatsbyjs.org/packages/gatsby-transformer-remark
tomorrow theme
// import at top level
import 'prismjs/themes/prism-tomorrow.css'
// Use line numbers
import 'prismjs/plugins/line-numbers/prism-line-numbers.css'
// require at gatsby-browser.js
require('prismjs/themes/prism-tomorrow.css')
.container {
display: flex;
margin: 3rem auto;
}
src/components/container.module.css
src/components/container.js
import React from 'react'
import containerStyles from './container.module.css'
export default ({ children }) => (
<section className={containerStyles.container}>{children}</section>
)
module.exports = {
plugins: ['gatsby-plugin-emotion'],
}
gatsby-config.js
src/pages/index.js
import styled from '@emotion/styled'
import { css } from '@emotion/core'
const Container = styled.div`
display: flex;
margin: 3rem auto;
`
const underline = css`
text-decoration: underline;
`
export default () => (
<Container>
<h1 css={underline}>Emotion 棒棒</h1>
</Container>
)
module.exports = {
plugins: ['gatsby-plugin-styled-components'],
}
gatsby-config.js
src/pages/index.js
import React from 'react'
import styled from 'styled-components'
import User from '../components/User'
const Container = styled.div`
display: flex;
margin: 3rem auto;
`
export default () => (
<Container>
<User name="Ben" />
<User name="Elvis" />
</Container>
)
slug === '暫停出貨通知'
import React from "react"
import NewsCover from "../components/banners/newsCover"
import NewsDetail from "../components/banners/newsDetail"
import SEO from "../components/seo"
export default ({ data }) => (
<>
<SEO title={data.contentfulPost.title} keywords={['最新消息', 'ModernWeb', 'Gatsby', 'Contentful']} />
<NewsCover />
<NewsDetail data={data.contentfulPost} />
</>
)
export const query = graphql`
query($id: String!) {
contentfulPost(id: { eq: $id }) {
id
title
body {
json
}
createdAt
covers {
sizes(maxWidth: 1000) {
...GatsbyContentfulSizes_withWebp
}
}
}
}
`
src/templates/news.js
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
const promises = [
new Promise((resolve, reject) => {
const template = path.resolve('src/templates/news.js')
resolve(
graphql(
`
{
allContentfulPost {
edges {
node {
id
slug
}
}
}
}
`
).then(result => {
if (result.errors) reject(result.errors)
result.data.allContentfulPost.edges.forEach(({ node }) => {
createPage({
path: `/news/${node.slug}`,
component: template,
context: {
id: node.id,
},
})
})
})
)
})
]
return Promise.all(promises)
}
gatsby-node.js
const module = typeof window !== `undefined` ? require("module") : null
rm -rf .cache
plugins: [
{
resolve: 'gatsby-source-contentful',
options: {
spaceId: 'your_space_id_grab_it_from_contentful',
accessToken: 'your_token_id_grab_it_from_contentful',
},
},
]
gatsby-config.js
export const query = graphql`
query($id: String!) {
allContentfulProductTag(sort: { fields: [group_number, order] order: [ASC, DESC] }) {
edges {
node {
id
name
group_number
}
}
}
}
`
?keyword=外套&tags=CHAMPION
const getFromSearch = data => {
let search = queryString.parse(window.location.search, { arrayFormat: 'comma' })
if (!Array.isArray(search.tags)) {
search = { ...search, tags: [search.tags] }
}
return {
keyword: search.keyword,
tags: data.allContentfulProductTag.edges.reduce((tags, cur) => {
if (search.tags.find(nameOfTag => nameOfTag === cur.node.name)) return tags.concat(cur)
return tags
}, [])
}
}
useEffect(() => {
const { tags: initTags, keyword: initKeyword } = getFromSearch(data)
setSelectedTags(initTags)
setKeyword(initKeyword)
window.onpopstate = function(event) {
const { tags: newTags, keyword: newKeyword } = getFromSearch(data)
setSelectedTags(newTags)
setKeyword(newKeyword)
}
setDidMount(true)
return () => {
setSelectedTags(false)
setKeyword(false)
window.onpopstate = null
}
}, [(typeof window === 'undefined') ? null : window.location.href])
如果兩者相比,Gatsby 更適合拿來快速開發靜態頁面,Next 則適合拿來開發大型架構