はじめに
フルスタックWebフレームワークであるRedwoodJSのTutorialをやってみた記事です。 TutorialはChapter 0からありますが、実際に手を動かし始めるChapter 1から始めます。
Prerequisites | RedwoodJS Docs
Redwood is composed of several popular libraries to make full-stack web development easier. Unfortunately, we can't teach all of those technologies from scratch during this tutorial, so we're going to assume you are already familiar with a few core concepts:
プロジェクト作成
初めはプロジェクト作成です。
yarn create redwood-app --ts ./my-first-redwood-app
success Installed "create-redwood-app@7.7.4" with binaries:
- create-redwood-app
[##] 2/2------------------------------------------------------------------
🌲⚡️ Welcome to RedwoodJS! ⚡️🌲
------------------------------------------------------------------
✔ Compatibility checks passed
✔ Creating your Redwood app in ./my-first-redwood-app based on command line argument
✔ Using TypeScript based on command line flag
✔ Do you want to initialize a git repo? · no / Yes
✔ Enter a commit message · Initial commit
✔ Project files created
✔ Initialized a git repo with commit message "Initial commit"
Thanks for trying out Redwood!
⚡️ Get up and running fast with this Quick Start guide: https://redwoodjs.com/quick-start
Fire it up! 🚀
> cd my-first-redwood-app
> yarn install
> yarn rw dev
プロジェクトが作成されたら、パッケージインストール、開発サーバーを起動します。
cd my-first-redwood-app
yarn install
yarn redwood dev
ブラウザが開き、上の画像のような画面になれば OKです。
ファイル構造
├── api
│ ├── db
│ │ └── schema.prisma
│ └── src
│ ├── directives
│ │ ├── requireAuth
│ │ └── skipAuth
│ ├── functions
│ │ └── graphql.ts
│ ├── graphql
│ ├── lib
│ │ ├── auth.ts
│ │ ├── db.ts
│ │ └── logger.ts
│ └── services
│
├── scripts
│ └── seed.ts
│
└── web
├── public
│ ├── favicon.png
│ ├── README.md
│ └── robots.txt
└── src
├── components
├── layouts
├── pages
│ ├── FatalErrorPage
│ │ └── FatalErrorPage.tsx
│ └── NotFoundPage
│ └── NotFoundPage.tsx
├── App.tsx
├── entry.client.tsx
├── index.css
├── index.html
└── Routes.tsx
RedwoodJSではYarnのワークスペース機能を使用しており、api
、scripts
、web
で分かれています。
各ディレクトリの説明は公式ドキュメントを参照ください。
Redwood File Structure | RedwoodJS Docs
Let's take a look at the files and directories that were created for us (config files have been excluded for now):
ページの作成
ページの作成は以下コマンドを実行します。
yarn redwood generate page home /
✔ Generating page files...
✔ Successfully wrote file `./web/src/pages/HomePage/HomePage.stories.tsx`
✔ Successfully wrote file `./web/src/pages/HomePage/HomePage.test.tsx`
✔ Successfully wrote file `./web/src/pages/HomePage/HomePage.tsx`
✔ Updating routes file...
✔ Generating types...
✔ One more thing...
Page created! A note about <Metadata>:
At the top of your newly created page is a <Metadata> component,
which contains the title and description for your page, essential
to good SEO. Check out this page for best practices:
https://developers.google.com/search/docs/advanced/appearance/good-titles-snippets
このコマンドで以下ファイルが作成されます。
- web/src/pages/HomePage/HomePage.tsx: ページコンポーネントファイル
- web/src/pages/HomePage/HomePage.test.tsx: テストファイル
- web/src/pages/HomePage/HomePage.stories.tsx: Storybookファイル
さらにルーティング設定としてweb/src/Routes.tsxにパス/
が追加されています。
// web/src/Routes.tsx
import { Router, Route } from '@redwoodjs/router'
const Routes = () => {
return (
<Router>
<Route path="/" page={HomePage} name="home" />
<Route notfound page={NotFoundPage} />
</Router>
)
}
export default Routes
リンク
次は別ページを作成して、そこへ遷移してみます。
yarn redwood generate page about
Homeの時は最後にパス/
をつけてましたが、今回の場合はパスの指定不要で、指定しない場合はページ名が使われ/about
になります。
Aboutページが用意できたので、Homeページからリンクさせます。
// web/src/pages/HomePage/HomePage.tsx
import { Link, routes } from '@redwoodjs/router'
import { Metadata } from '@redwoodjs/web'
const HomePage = () => {
return (
<>
<Metadata title="Home" description="Home page" />
<header>
<h1>Redwood Blog</h1>
<nav>
<ul>
<li>
<Link to={routes.about()}>About</Link>
</li>
</ul>
</nav>
</header>
<main>Home</main>
</>
)
}
export default HomePage
AboutページからHomeページへ戻る場合は以下のようになります。
// web/src/pages/AboutPage/AboutPage.tsx
import { Link, routes } from '@redwoodjs/router'
import { Metadata } from '@redwoodjs/web'
const AboutPage = () => {
return (
<>
<Metadata title="About" description="About page" />
<header>
<h1>Redwood Blog</h1>
<nav>
<ul>
<li>
<Link to={routes.about()}>About</Link>
</li>
</ul>
</nav>
</header>
<main>
<p>
This site was created to demonstrate my mastery of Redwood: Look on my
works, ye mighty, and despair!
</p>
<Link to={routes.home()}>Return home</Link>
</main>
</>
)
}
export default AboutPage
レイアウト
次はレイアウトを利用して、見た目の共通化を行います。
yarn redwood g layout blog
以下3ファイルが生成されました。
- web/src/layouts/BlogLayout/BlogLayout.test.tsx
- web/src/layouts/BlogLayout/BlogLayout.stories.tsx
- web/src/layouts/BlogLayout/BlogLayout.tsx
BlogLayoutコンポーネントを編集してheaderタグ部分を共通化します。
import { Link, routes } from '@redwoodjs/router'
type BlogLayoutProps = {
children?: React.ReactNode
}
const BlogLayout = ({ children }: BlogLayoutProps) => {
return (
<>
<header>
<h1>Redwood Blog</h1>
<nav>
<ul>
<li>
<Link to={routes.about()}>About</Link>
</li>
</ul>
</nav>
</header>
<main>{children}</main>
</>
)
}
export default BlogLayout
用意したレイアウトをそれぞれHomeとAboutページに適用します。
[About]
// web/src/pages/AboutPage/AboutPage.tsx
import { Link, routes } from '@redwoodjs/router'
import { Metadata } from '@redwoodjs/web'
const AboutPage = () => {
return (
<>
<Metadata title="About" description="About page" />
<p>
This site was created to demonstrate my mastery of Redwood: Look on my
works, ye mighty, and despair!
</p>
<Link to={routes.home()}>Return home</Link>
</>
)
}
export default AboutPage
[Home]
// web/src/pages/HomePage/HomePage.tsx
import { Metadata } from '@redwoodjs/web'
const HomePage = () => {
return (
<>
<Metadata title="Home" description="Home page" />
Home
</>
)
}
export default HomePage
[Routes]
// web/src/Routes.tsx
import { Router, Route, Set } from '@redwoodjs/router'
import BlogLayout from 'src/layouts/BlogLayout'
const Routes = () => {
return (
<Router>
<Set wrap={BlogLayout}>
<Route path="/about" page={AboutPage} name="about" />
<Route path="/" page={HomePage} name="home" />
</Set>
<Route notfound page={NotFoundPage} />
</Router>
)
}
export default Routes
最後はBlogLayoutコンポーネントにHomeへのリンクを追加します。
import { Link, routes } from '@redwoodjs/router'
type BlogLayoutProps = {
children?: React.ReactNode
}
const BlogLayout = ({ children }: BlogLayoutProps) => {
return (
<>
<header>
<h1>
<Link to={routes.home()}>Redwood Blog</Link>
</h1>
<nav>
<ul>
<li>
<Link to={routes.home()}>Home</Link>
</li>
<li>
<Link to={routes.about()}>About</Link>
</li>
</ul>
</nav>
</header>
<main>{children}</main>
</>
)
}
export default BlogLayout
そして不要になったHomeへのリンクをAboutページから削除します。
import { Metadata } from '@redwoodjs/web'
const AboutPage = () => {
return (
<>
<Metadata title="About" description="About page" />
<p>
This site was created to demonstrate my mastery of Redwood: Look on my
works, ye mighty, and despair!
</p>
</>
)
}
export default AboutPage
ここまででChapter 1は終了です。