Ich verwende das React Server Framework Next.js Blog, wenn Sie es mögen, geben Sie Sternsupport. https://github.com/weibozzzzzzzz.Next-blog Online-Adresse: http://www.liuweibo.cn Dieses Projekt verwendet Next.js Experience Sharing: https://github.com/weibozz/weibozz.github.io
Softwarearchitektur Beschreibung react.js next.js antd mysql node koa2 fetch
Geben Sie die Ishow von Env.js unter den Konfigurationsordner ein und setzen Sie sie auf true . Hier rufe ich einfach meine eigene Online -Oberfläche an. Natürlich können Sie es nur ansehen und die Schnittstelle nicht ändern. Wenn es falsch ist, kann die Schnittstelle nicht angepasst werden und Sie müssen die Schnittstelle selbst schreiben.
cnpm i
npm run devcnpm i
npm run build
npm startWir werden die persönliche Website, die vollständig mit Hilfe von Next.js entwickelt wurde, und die Online -Adresse http://www.liuweibo.cn verwenden, um die Erfahrung und die Erfahrung der Entwicklung nach Abschluss zusammenzufassen. GTIHUB-Quellcode https://github.com/weibozzz/next-blog. Wenn Sie es mögen, geben Sie Sternunterstützung.
Sprechen wir hier einfach über die wichtigsten Punkte
server.js Verwenden Sie hier den offiziellen express und aktivieren Sie gleichzeitig gzip -Komprimierung
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 )
} ) Der Speicher wird zum Übergeben von Redux -Daten verwendet, und der Speicher ist der gleiche React -Nutzung, und Header und Fußzeile können hier platziert werden, und _err.js wird verwendet, um 404 Seiten zu verarbeiten
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 ) ) link wird verwendet, um auf Seiten zu springen und zu verwenden, um das ursprüngliche http: //***.com in eine schöne/id/1 zu ändernhead kann Meta -Tags für SEO nisten 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 ) Erstellen Sie im Stammverzeichnis einen static Ordner. Dies ist eine obligatorische Anforderung, sonst wird die statische Ressource nicht geladen.
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" ; Schließlich ist die Konfiguration auf dem öffentlichen head einheitlich
< 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 -Datei
{
"presets" : [ " next/babel " ],
"plugins" : [
" transform-decorators-legacy " ,
[
" import " ,
{
"libraryName" : " antd " ,
"style" : " less "
}
]
]
}
next.config.js Dateikonfiguration
const withLess = require ( '@zeit/next-less' )
module . exports = withLess (
{
lessLoaderOptions : {
javascriptEnabled : true ,
cssModules : true ,
}
}
) Es fühlt sich an wie vue 's scope , style jsx , global als global, sonst wird es hier nur wirksam.
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 ( ) Verwenden Sie nur 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
} ) ; next.config.js Dateikonfiguration
module . exports = {
webpack ( config , ... args ) {
return config ;
}
} config.resolve.alias = {
...config.resolve.alias,
'@': path.resolve(__dirname, './'),
}
config.plugins.push(
new webpack.DefinePlugin({
'process.env.NODE_ENV': process.env.NODE_ENV
})
)
config.module.rules.push(
{
test: /.svg(?v=d+.d+.d+)?$/,
use: [
{
loader: 'babel-loader'
},
{
loader: '@svgr/webpack',
options: {
babel: false,
icon: true
}
}
]
}
)
config = withCSS()
.webpack(config, ...args)
config = withLess()
.webpack(config, ...args)
const loaderUtils = require('loader-utils')
const fs = require('fs')
const path = require('path')
const cssModuleRegex = /.module.less$/
config = withLess(
// 开启 css module 自定义
{
cssModules: true,
cssLoaderOptions: {
importLoaders: 1,
minimize: !args[0].dev,
getLocalIdent: (loaderContext, _, localName, options) => {
const fileName = path.basename(loaderContext.resourcePath)
if (cssModuleRegex.test(fileName)) {
const content = fs.readFileSync(loaderContext.resourcePath)
.toString()
const name = fileName.replace(/.[^/.]+$/, '')
const hash = args[0].dev ? `${name}___[hash:base64:5]` : '[hash:base64:5]'
const fileNameHash = loaderUtils.interpolateName(
loaderContext,
hash,
{ content }
)
return fileNameHash
}
return localName
}
}
}
)
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true'
})
config = withBundleAnalyzer({})
.webpack(config, ...args)
)
Wenn es große Besuche gibt, müssen Sie Daten zwischenspeichern
CDN -Knoten -Bilddatum anzeigen
Konfigurationsbildbeschreibung und Änderungen
Das Hochladen hochwertiger Bilder unterstützt noch nicht das Hochladen, und das Hochladen von Codeverbesserungen
Als genau 1m Fehler hochgeladen
Unterstützen Sie nach dem Anmelden Lieblingsartikel und ändern Sie Kommentare
Wenn der vorherige Artikel gelöscht wird, ist die Selbstverlängerungs-ID nicht selbsterlösen 1 und Sie müssen die Datenbank abfragen
Füllen Sie den Markdown -Code aus, um ihn hervorzuheben, ähnlich wie bei Nuggets
Versionen, die sich an diesem Tag verschmelzen
contentEditableGitHub: https: //github.com/weibozzz
Persönlicher Blog: http://www.liuweibo.cn
Segmentfault: https: //segmentfault.com/u/weibozzz
Öffentliche Plattform: Weibo Frontend
Autor: Liu Weibo
Link: http://www.liuweibo.cn/p/206
Quelle: Liu Weibos Blog
Das ursprüngliche Urheberrecht dieses Artikels gehört Liu Weibo. Bitte geben Sie die Quelle beim Nachdruck an. Vielen Dank für Ihre Zusammenarbeit.