Utilizo el Blog React Server Framework Next.js, si te gusta, le doy soporte a Star. https://github.com/weibozzz/next-log Dirección en línea: http://www.liuweibo.cn Este proyecto utiliza el intercambio de experiencia Next.js: http://www.liuweibo.cn/p/206 Hay también un Warehouse para establecer su propio sistema de conocimiento delantero: https://github.com/weibozz/weibozz.github.io
Software Architecture Descripción react.js next.js antd mysql node koa2 fetch
Ingrese el ISSHOW de Env.JS en la carpeta de configuración y configúrelo en True . Aquí solo llamo a mi propia interfaz en línea. Por supuesto, solo puede verlo y no modificar la interfaz. Si es falso, la interfaz no se puede ajustar y debe escribir la interfaz usted mismo.
cnpm i
npm run devcnpm i
npm run build
npm startUtilizaremos el sitio web personal desarrollado completamente con la ayuda de Next.js, y la dirección en línea http://www.liuweibo.cn para resumir la experiencia y la experiencia de usar el desarrollo después de la finalización. Código fuente de GTIHUB https://github.com/weibozzz/next-log. Si te gusta, brinda apoyo estelar.
Hablemos de los puntos clave aquí
server.js Use el express oficial aquí y habilite la compresión gzip al mismo tiempo
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 )
} ) Se usa para pasar los datos de Redux, el almacén es lo mismo que el uso de React Ordinary, y el encabezado y el pie de página se pueden colocar aquí, y _err.js se utiliza para procesar 404 páginas
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 se usa para saltar a las páginas y usar para cambiar el http: //***.com? Id = 1 en una hermosa/id/1head puede anidar metaetiquetas para 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 ) Cree una carpeta static en el directorio raíz. Este es un requisito obligatorio, de lo contrario el recurso estático no se cargará.
antd-custom.less
@primary-color : # 722ED0;
@layout-header-height : 40px;
@border-radius-base : 0px;estilos.
@import "~antd/dist/antd.less" ;
@import "./antd-custom.less" ; Finalmente, la configuración se unifica en el head público
< 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 > archivo .babelrc
{
"presets" : [ " next/babel " ],
"plugins" : [
" transform-decorators-legacy " ,
[
" import " ,
{
"libraryName" : " antd " ,
"style" : " less "
}
]
]
}
next.config.js Configuración del archivo
const withLess = require ( '@zeit/next-less' )
module . exports = withLess (
{
lessLoaderOptions : {
javascriptEnabled : true ,
cssModules : true ,
}
}
) Se siente como si scope de vue , style jsx , agregue global como global, de lo contrario solo entrará en vigencia aquí.
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 ( ) Use solo la necesidad de 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 Configuración del archivo
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)
)
Cuando hay grandes visitas, debe almacenar datos en caché
Fecha de imagen de vista de nodo CDN
Descripción y cambios de la imagen de configuración
La carga de imágenes de alta calidad aún no admite la carga, cargando mejoras en el código
Subido como exactamente 1M Bug
Después de iniciar sesión, apoye los artículos favoritos y modifique los comentarios
Si se elimina el artículo anterior, la identificación de autoincripción no es auto-aumento 1, y debe consultar la base de datos
Complete el código de Markdown para resaltarlo, similar a Nuggets
Versiones para fusionar ese día
contentEditablegithub: https: //github.com/weibozzz
Blog personal: http://www.liuweibo.cn
Segmentfault: https: //segmentfault.com/u/weibozzz
Plataforma pública: Weibo Frontend
Autor: Liu Weibo
Enlace: http://www.liuweibo.cn/p/206
Fuente: Blog de Liu Weibo
Los derechos de autor originales de este artículo pertenecen a Liu Weibo. Indique la fuente al reimprimir. Gracias por su cooperación.