next-blog
项目介绍
利用react服务端框架next.js写的博客,喜欢就给个Star支持一下。
https://github.com/Weibozzz/next-blog
线上地址: http://www.liuweibo.cn
本项目使用next.js经验分享:http://www.liuweibo.cn/p/206
软件架构
软件架构说明react.js next.js antd mysql node koa2 fetch
网站使用技术
- 前端:React(16.x) Next.js antd-design fetch Less
- 后端:node框架koa和mysql (目前前后端分离,这里只负责写接口,和平常的ajax获取接口一样,这里就不开放源码了)
- 网站目的:业余学习,记录技术文章,学以致用
- 网站功能
- markdown发布文章
- 修改文章(增删改查)
- 用户评论
- 上传图片到七牛云存储
安装教程
- 快速开始
虽然是服务端渲染,但是也要调用接口,所以需要调用后端的接口
进入config文件夹下的env.js的isShow设置为true,这里只是调用了我自己线上的接口,当然你
只能看不能修改接口哦。如果为false则调不到接口,需要自己去写接口。
- 运行
cnpm i npm run dev
- 部署
cnpm i npm run build npm start
使用说明
- 关于演示不能上传图片,不能发表文章或者修改属于正常情况,因为只是为了展示。
- 关于路看不到发布文章路由和后台管理也属于正常情况,可以修改代码展示路由效果。
网站截图
- 详情页
- 列表页
- 编辑页面和发布文章,上传图片到七牛云
网站技术介绍
完全借助于 next.js 开发的个人网站,线上地址 http://www.liuweibo.cn 总结一下开发完成后的心得和使用体会。gtihub源码https://github.com/Weibozzz/next-blog。喜欢就给个Star支持一下。
为什么使用服务器端渲染(SSR)?
- 网站是要推广的,所以需要更好的 SEO,搜索引擎可以抓取完整页面
- 访问速度,更快的加载静态页面
网站使用技术
- 前端:React(16.x) Next.js antd-design fetch Less
- 后端:node框架koa和mysql (目前前后端分离,这里只负责写接口,和平常的ajax获取接口一样,这里就不开放源码了)
- 网站目的:业余学习,记录技术文章,学以致用
- 网站功能
- 发布文章
- 修改文章(增删改查)
- 用户评论
源码剖析
这里就只讲重点了
入口文件server.js
这里用的官方提供的express
,同时开启gzip
压缩
const express = require('express')
const next = require('next')
const compression = require('compression')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
let port= dev?4322:80
app.prepare()
.then(() => {
const server = express()
if (!dev) {
server.use(compression()) //gzip
}
//文章二级页面
server.get('/p/:id', (req, res) => {
const actualPage = '/detail'
const queryParams = { id: req.params.id }
app.render(req, res, actualPage, queryParams)
})
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(port, (err) => {
if (err) throw err
console.log('> Ready on http://localhost ' port)
})
})
.catch((ex) => {
process.exit(1)
})
page根组件_app.js
用于传递redux数据,store就和普通react用法一样了,还有header和footer可以放在这里,同理还有_err.js
用于处理404页面
import App, {Container} from 'next/app'
import React from 'react'
import {withRouter} from 'next/router' // 接入next的router
import withReduxStore from '../lib/with-redux-store' // 接入next的redux
import {Provider} from 'react-redux'
class MyApp extends App {
render() {
const {Component, pageProps, reduxStore, router: {pathname}} = this.props;
return (
<Container>
<Provider store={reduxStore}>
<Component {...myPageProps} />
</Provider>
</Container>
)
}
}
export default withReduxStore(withRouter(MyApp))
网站的服务端渲染页面Blog页面
link
用于跳转页面,利用as把原本的http://***.com?id=1变为漂亮的 /id/1head
可以嵌套meta标签进行seo- 配置不需要seo的组件
import dynamic from 'next/dynamic';
//不需要seo
const DynasicTopTipsNoSsr = dynamic(import('../../components/TopTips'),{
ssr:false
})
import React, {Component} from 'react'
import {connect} from 'react-redux'
import Router from 'next/router'
import 'whatwg-fetch' // 用于fetch请求数据
import Link from 'next/link'; // next的跳转link
import Head from 'next/head' // next的跳转head可用于seo
class Blog extends Component {
render() {
return (
<div className="Blog">
<Head>
<title>{BLOG_TXT}»{COMMON_TITLE}</title>
</Head>
<MyLayout>
<Link as={`/Blog/${current}`} href={`/Blog?id=${current}`}>
<a onClick={this.onClickPageChange.bind(this)}>{current}</a>
</Link>
</MyLayout>
</div>
)
}
}
//这里才是重点,getInitialProps方法来请求数据进行渲染,达到服务端渲染的目的
Blog.getInitialProps = async function (context) {
const {id = 1} = context.query
let queryStringObj = {
type: ALL,
num: id,
pageNum
}
let queryTotalString = {type: ALL};
const pageBlog = await fetch(getBlogUrl(queryStringObj))
const pageBlogData = await pageBlog.json()
return {pageBlogData}
}
// 这里根据需要传入redux
const mapStateToProps = state => {
const {res, searchData, searchTotalData} = state
return {res, searchData, searchTotalData};
}
export default connect(mapStateToProps)(Blog)
静态资源
根目录创建static
文件夹,这里是强制要求,否则加载不到静态资源
配置antd和主题并且按需加载
主题配置
antd-custom.less
@primary-color: #722ED0;
@layout-header-height: 40px;
@border-radius-base: 0px;
styles.less
@import "~antd/dist/antd.less";
@import "./antd-custom.less";
最后统一配置在公共head
<Head>
<meta charSet="utf-8"/>
<meta httpEquiv="X-UA-Compatible" content="IE=edge, chrome=1"/>
<meta name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no"/>
<meta name="renderer" content="webkit"/>
<meta httpEquiv="description" content="刘伟波-天天向上"/>
<meta name="author" content="刘伟波,liuweibo"/>
<link rel='stylesheet' href='/_next/static/style.css'/>
<link rel='stylesheet' type='text/css' href='/static/nprogress.css' />
<link rel='shortcut icon' type='image/x-icon' href='/static/favicon.ico' />
</Head>
按需加载配置
.babelrc
文件
{
"presets": ["next/babel"],
"plugins": [
"transform-decorators-legacy",
[
"import",
{
"libraryName": "antd",
"style": "less"
}
]
]
}
next.config.js
文件配置
const withLess = require('@zeit/next-less')
module.exports = withLess(
{
lessLoaderOptions: {
javascriptEnabled: true,
cssModules: true,
}
}
)
页面css
感觉和vue
的scope
一样,style
的jsx
,加了global
为全局,否则只在这里生效
render() {
return (
<Container>
<Provider store={reduxStore}>
<Component {...myPageProps} />
</Provider>
<style jsx global>{`
.fl{
float: left;
}
.fr{
float: right;
}
`}</style>
</Container>
)
页面顶部加载进度条
import Router from 'next/router'
import NProgress from 'nprogress'
Router.onRouteChangeStart = (url) => {
NProgress.start()
}
Router.onRouteChangeComplete = () => NProgress.done()
Router.onRouteChangeError = () => NProgress.done()
markdown发表文章和代码高亮
使用只需要marked('放入markdown字符串');
import marked from 'marked'
import hljs from 'highlight.js';
hljs.configure({
tabReplace: ' ',
classPrefix: 'hljs-',
languages: ['CSS', 'HTML, XML', 'JavaScript', 'PHP', 'Python', 'Stylus', 'TypeScript', 'Markdown']
})
marked.setOptions({
highlight: (code) => hljs.highlightAuto(code).value,
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: true,
smartLists: true,
smartypants: false
});
学累了,来个图放松下
参与贡献
- Fork 本项目
- 新建 Feat_xxx 分支
- 提交代码
- 新建 Pull Request
遗留问题
- 访问量大的时候要做数据缓存
- cdn node查看图片日期
- 配置图片描述和更改
- 上传图片高质量暂未支持上传,上传代码改进
- 上传为刚好1M bug
- 登陆后支持收藏文章和修改评论
- 顶部加载滚动条首次没loading
- 增加koa子模块
- 评论支持markdown,评论内容过多建议去sf平台
待学习修改
- 开发环境 warning.js:33 Warning: A component is
contentEditable
- eslint
关于作者 / About
- github:https://github.com/Weibozzz
- 个人博客:http://www.liuweibo.cn
- segmentfault:https://segmentfault.com/u/weibozzz
版权声明
- 所有原创文章的著作权属于 Weibozzz。
作者:刘伟波
链接:http://www.liuweibo.cn/p/206
来源:刘伟波博客
本文原创版权属于刘伟波 ,转载请注明出处,谢谢合作
发表评论:
你好,我最近正在部署next应用,但是我不知道该如何部署,请教下。
您好,最近在研究有关ssr的东西,你的分享对我帮助很大。谢谢你。
还有个问题我想咨询依稀你关于next.js项目部署的问题。执行build ,start后,他应该会改期一个服务,我们部署的话,是需要将那些文件上传。是通过查找文件路径的方式映射,还是启动服务。希望能帮忙看看这个问题。非常感谢!本人的服务器和您都是linux的。
你可以试一试只上传
build
之后的文件,不过我这边为了方便文件是全部需要上传的,部署用的pm2
来部署,可以执行npm run prd
。 但是不理解 '查找文件路径的方式映射' .linux服务端部署后,next build && next start,detail详情页(localhost:3000/p/206)刷新 404,如何解决?
好的,多谢波波解答
我这个是部署在阿里
linux
服务器的,你这种问题得靠自己细细看下最新仓库 前端知识体系 喜欢的可以收藏一下!
这明明引用的是express呀,哪有koa2 :)
我可能没表述清楚,
koa2
是后端代码,在这里没有开发出来请问next在跳转路由的时候怎么做loading状态
页面放着不操作,时间稍微一长点击跳转路由一直处于加载状态,但是实际上那个js文件已经在head中引用了
还有引入antd样式后,页面所有样式都被antd的样式覆盖了,我有我自己的默认样式=。=!
我使用antd后 next的路由跳转不起作用。。。 问题是只要在下个路由页面中引入antd组件,页面就跳不了
loading
可以查看根文件_app.js
的NProgress
的使用还有我发现开发模式下的时候,访问首页会加载3个300多kb的js文件和两个800左右kb的js文件。。。build后部署服务器加载不会慢吗 我新手前端=。=
请问一下next.js做得网站如何保存用户的登录信息呢
这个就和普通网站一样,用
cookie
吧请问自己用next开发个人博客,最后是怎么样部署和上线的呢?next build之后有个.next文件夹,然后怎么利用这个文件夹呢,需要放到哪里才能通过个性域名来让别人能够访问到?谢谢!
部署推荐用
pm2
一键部署linux 系统打包报错的是怎么回事
npm ERR! A complete log of this run can be found in:
npm ERR! /root/.npm/_logs/2018-10-19T04_57_22_622Z-debug.log
1.可以尝试删掉build之后的文件任何执行,
npm run build
2.可能内存不够,需要重启服务器
怎么把 less 文件打包到style.css 的呢
能具体说遇到了什么问题吗?less文件是自动编译的
cssModules 应该房子外面那一层,我已经实现了但是遇到一个问题,antd 也被cssModules 转换了
已回复!
你在你的GitHub上提了 issuse
jsx 对lexx 的支持是 2.7.3 依赖 ,最新的是3.8.0 这个和less-loader 可能会有一些冲突
我期望
https://github.com/zeit/next.js/issues/5180
这是我来的例子
https://github.com/VanquisherMe/with-nextjs-antd-app
希望能帮助我解决
用户名咋登陆
你的具体代码实现呢?贴出来看看
<style jsx global>{` //这里css就相当于cssModules `}</style>
发现只有首页才会服务端渲染,点击进入其他页面后还是客户端渲染的,那是不是可以理解成其他页面就没有必要使用getInitialProps了
我写了个demo 首页的请求写在getInitalProp里,发现确实是在服务端请求好之后再返回的,但是,我在其他页面里的getInitialProps里写请求(在首页点击链接后跳转进去的页面),发现并不是服务端渲染,而是在页面点击进入后,进行请求
不是的。用了
next.js
框架。getInitialProps
方法去请求就相当于服务端渲染,如果不在这里面请求的数据,那就不是服务端渲染。我在使用next.js+axios时,遇到一个问题,就是在getInitialProps中且在服务端请求数据的时候报错,但是把,但是在其他地方请求数据一点问题都没有
请问报错提示是什么?你是怎么请求的?贴上代码 看看
不错不错
有大佬知道怎么设置菜单高亮吗?pathname获取不到啊。。
这里您可以引入,在DIdMount的时候可以打印一下Router就会有pathname,如果有其他的问题,可以把我的项目克隆下来,全局查找就可以找到解决办法。
import Router from next/router
在getInitialProps里的操作感觉在生命周期函数里也可以,为什么要在getInitialProps里执行?
在getInitialProps这里执行,请求数据,才会映射到props,才能起到服务端渲染的作用,虽然在生命周期函数里也可以,但是和单页面一样了
关于技术问题或者有啥不懂的都可以留言,我会定期回复!
没看到心得,就是把 https://github.com/zeit/next.js/tree/canary/examples 下的几个功能整合到一起而已...
说的挺好,功能整合,分享一下经验吧,也算是一种分享
向大佬学习
666
好好学习,天天向上 哈哈