打造基于web3的博客|web3.0 dApp开发(番外一)
作者:李大狗 & msfew
本篇是 web3.0 dApp 开发系列的番外,也就是在主线以外的支线。
在本支线中,会通过几篇文章构造出一个嵌入了 web3.0 各项功能的博客系统,主要技术栈为 React。
历史文章合集:
以太坊核心开发者Austin | 如何在以太坊上构建应用程序?
eth.build 快速上手 | Web3.0 dApp 开发(一)
项目Repo:
https://github.com/leeduckgo/web3-blog-ts
1 Gatsby Starter Blog Typescript
1.1 项目运行
Gatsby 是一个基于 React 的免费、开源框架,用于帮助开发者构建运行速度极快的 网站 和 应用程序。
Gatsby Github Repo:https://github.com/gatsbyjs/gatsby
Gatsby 官方主页:https://www.gatsbyjs.cn/plugins/
我们也可以在 Github 上找到很多基于 Gatsby 的项目:
https://github.com/search?q=gatsby
本次我们选择的是Gatsby Starter Blog Typescript
,一个基于 Gastby 的博客系统:
https://github.com/gperl27/Gatsby-Starter-Blog-Typescript
我们可以先跑一下没有嵌入 web3 的 blog 来玩玩:
注意:node 使用 16 以上版本
git clone https://github.com/gperl27/Gatsby-Starter-Blog-Typescript.git
cd Gatsby-Starter-Blog-Typescript
rm -rf yarn.lock
yarn
yarn start
1.2 项目结构
再看一下项目结构:
// 注:使用 tree -I '*node_module*' -L 4 命令查看文件树
.
├── LICENSE
├── README.md
├── codegen.yml
├── content
│ ├── assets
│ │ ├── gatsby-icon.png
│ │ └── profile-pic.jpg
│ └── blog
│ ├── hello-world
│ │ ├── index.md
│ │ └── salty_egg.jpg
│ ├── hi-folks
│ │ └── index.md
│ └── my-second-post
│ └── index.md
├── gatsby-browser.js
├── gatsby-config.js
├── gatsby-node.js
├── package.json
├── public
│ ├── chunk-map.json
│ ├── favicon-32x32.png
│ ├── favicon.ico
│ ├── icons
│ │ ├── icon-144x144.png
│ │ ├── ……
│ ├── manifest.webmanifest
│ ├── page-data
│ │ ├── 404.html
│ │ │ └── page-data.json
│ │ ├── dev-404-page
│ │ │ └── page-data.json
│ │ ├── hello-world
│ │ │ └── page-data.json
│ │ ├── index
│ │ │ └── page-data.json
│ │ └── sq
│ │ └── d
│ ├── render-page.js
│ ├── render-page.js.map
│ ├── robots.txt
│ ├── static
│ │ ├── 4f27694bd7811d13157e5e488ad64f43
│ │ │ └── 99438
│ │ └── 8058f3f26913fea3b6a89a73344fe94a
│ └── webpack.stats.json
├── src
│ ├── components
│ │ ├── bio.tsx
│ │ ├── layout.tsx
│ │ ├── link.tsx
│ │ └── seo.tsx
│ ├── graphql-types.d.ts
│ ├── index.d.ts
│ ├── lib
│ │ └── createPages.ts
│ ├── pages
│ │ ├── 404.tsx
│ │ └── index.tsx
│ ├── templates
│ │ └── blog-post.tsx
│ ├── types.ts
│ └── utils
│ └── typography.ts
├── static
│ ├── favicon.ico
│ └── robots.txt
├── tsconfig.json
├── tslint.json
└── yarn.lock
•主入口是src/pages/index.tsx
•各个组件在src/components
里•博客源文件在content
目录下
2 Web3 Modal
Web3 Modal 是一个易于使用的库,可帮助开发人员通过简单的可自定义配置在其应用程序中添加对多个 web3 提供者的支持。
Web3Modal is an easy-to-use library to help developers add support for multiple providers in their apps with a simple customizable configuration.
我们可以参考 Web3 Modal 的 example 来完成我们的实践:
https://github.com/Web3Modal/web3modal/tree/master/example
Example 运行效果:
3 编写 SuperWeb3.tsx 组件
我们将 Example 中的相关部分抽象成 React 组件 SuperWeb3.tsx
:
https://github.com/leeduckgo/web3-blog-ts/blob/main/src/components/SuperWeb3.tsx
这里定义了一个关键类 SuperWeb3,我们来看一下类的结构:
// 声明SuperWeb3为React的类组件
class SuperWeb3 extends React.Component<any, any> {
// 此处以及其余地方的public可以省略
public web3Modal: Web3Modal;
// 在初始化过程中可以接收父组件(如index.tsx)传输来的props
constructor(props: any) {
super(props);
this.state = {
...INITIAL_STATE
};
}
// 此处为React类组件的生命周期函数,当SuperWeb3组件挂载后会触发Web3登录
// 把函数放到此处可解决 window is not defined 问题
public componentDidMount() {
this.web3Modal = new Web3Modal({
network: this.getNetwork(),
cacheProvider: true,
providerOptions: this.getProviderOptions()
});
if (this.web3Modal.cachedProvider) {
this.onConnect();
}
}
public onConnect = async () => {
// ……
}
// render函数会把地址等信息更新为SuperWeb3中的state中的值
public render = () => {
const {
address,
connected,
chainId
} = this.state;
return(
<Column maxWidth={1000} spanHeight>
<Header
connected={connected}
address={address}
chainId={chainId}
killSession={this.resetApp}
/>
<SContent>
{ // 如果已经连接,则关闭p标签;如果未连接,则渲染连接标签 }
{ connected ? (
<p/>
) : (
<ConnectButton onClick={this.onConnect} />
)}
</SContent>
</Column>
)
}
}
我们来着重看一下组件中的 onConnect 方法。当页面中的登录按钮被按下后,会触发onConnect方法。
public onConnect = async () => {
const provider = await this.web3Modal.connect();
await this.subscribeProvider(provider);
const web3: any = initWeb3(provider);
const accounts = await web3.eth.getAccounts();
const address = accounts[0];
const networkId = await web3.eth.net.getId();
const chainId = await web3.eth.chainId();
await this.setState({
web3,
provider,
connected: true,
address,
chainId,
networkId
});
await this.getAccountAssets();
……
};
首先这是一个async方程,意味着其中可以使用await关键词来进行异步操作。onConnect方程的主要作用就是创建Web3登录所用的provider、拿到当前使用的地址、拿到网络id以及链id,之后把组件的状态更新为刚刚拿到的地址等数据,最后获取此地址中的assets。
其中更新组件状态这一步虽然不是一个异步操作[1],但是为了保证视图拿到最新更新后的值,我们可以让更新state这一步进行一个等待,等待前面的操作全部完成后再进行更新。
4 index.tsx 引入组件
完成 SuperWeb3.tsx
组件的编写后,我们需要将这个子组件引入到我们的首页 index.tsx
。
https://github.com/leeduckgo/web3-blog-ts/blob/main/src/pages/index.tsx
我们在文件头部引入组件文件夹中的 SuperWeb3.tsx
, 在 BlogIndex
组件的返回值中加入 <SuperWeb3 />
,在首页渲染时就会包含SuperWeb3的组件。
// ……
import SuperWeb3 from "../components/SuperWeb3"
// ……
const siteTitle = data.site.siteMetadata.title
const posts = data.allMarkdownRemark.edges
return (
<Layout location={props.location} title={siteTitle}>
<SEO
title="All posts"
keywords={[`blog`, `gatsby`, `javascript`, `react`]}
/>
<SuperWeb3 />
<BlogTitle />
<Bio />
{posts.map(({ node }: { node: MarkdownRemark }) => {
const frontmatter = node!.frontmatter!
const fields = node!.fields!
const slug = fields.slug!
const excerpt = node!.excerpt!
const title = frontmatter.title || fields.slug
return (
<div key={slug}>
<Title>
<StyledLink to={slug}>{title}</StyledLink>
</Title>
<small>{frontmatter.date}</small>
<p
dangerouslySetInnerHTML={{
__html: frontmatter.description || excerpt,
}}
/>
</div>
)
})}
</Layout>
)
}
export default BlogIndex
我们可以看下改造后的 Blog 的效果:
5 Github-pages 的部署实践
如有疑问,可以参考Gatsby[2]的官方文档。
我们会将项目部署到GitHub中的普通仓库,链接形如:https://github.com/fewwwww/web3-blog-ts。
1.下载 gh-pages
库
进入终端,进入项目文件夹,通过npm下载 gh-pages
库。
npm install gh-pages --save-dev
2. 修改 gatsby-config.js
配置
在 gatsby-config.js
中加入pathPrefix, 设置其值为 /仓库名称
。
module.exports = {
pathPrefix: '/web3-blog-ts',
// pathPrefix: "/reponame",
// ……
3.修改 package.json
脚本
{
"scripts": {
// ……
"deploy": "gatsby build --prefix-paths && gh-pages -d public",
// ……
}
}
4.在GitHub中开启pages功能
进入仓库页面,点击上方的 Settings
按钮,点击左侧的 Pages
,将source选择为"main",之后点击"save"。
注意此步必须在下一步开始前完成,否则会导致部署脚本无法正常运行。
5.开始部署
进入终端,进入项目文件夹,通过npm运行我们刚刚修改好的部署脚本。
npm run deploy
等待完成后可以看到如下信息
Waiting for the debugger to disconnect...
Debugger attached.
Published
Waiting for the debugger to disconnect...
Waiting for the debugger to disconnect...
6.在GitHub中切换source
进入仓库页面,点击上方的 Settings
按钮,点击左侧的 Pages
,将source选择为"gh-pages",之后点击"save"。
等待片刻后就完成了部署。
6 Web3.0 dApp 训练营计划
Web3.0 dApp训练营旨在让「传统计算机从业者、在校学生、区块链技术从业人员」快速习得基于 Ethereum 的 Web3.0 dApp 开发。
课程内容部分会转化为文章放在公众号上~本篇文章即是该系列中的内容!
训练营详情可查看:
Crypto觉醒 | Web3.0 DApp 全面掌握 李大狗Leeduckgo,公众号:李大狗LeeduckgoCrypto觉醒 | Web3.0 DApp 全面掌握
References
[1]
不是一个异步操作: https://stackoverflow.com/questions/51968714/is-it-correct-to-use-await-setstate[2]
Gatsby: https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting/how-gatsby-works-with-github-pages/