安装node
新建一个server文件夹,用命令行在server文件夹中npm init
,出现一个package.json
文件,使文件夹变成一个node
的包,这样的包时比较容易管理的。
然后在这个包中安装npm install express --save
,此时server文件夹中多了一个node_modules文件夹。
在server文件夹中新建一个app.js
在express.js
官网上,入门中选择hello world
,将实例复制到app.js中,了解一下express框架.
const express = require('express')
const app = express()
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(3000, () => console.log('Example app listening on port 3000!'))
服务器段渲染指的是页面上的内容在服务器端已经生成好了,服务器把内容给到浏览器,浏览器负责渲染。
客户端渲染,是由js文件渲染出来的,js文件运行在浏览器中。
优势:前端负责页面的渲染,前端向后端发送ajax请求,后端返回为json数据,前端继续渲染页面。前端只负责渲染,后端向前端提供接口,这样前后端分离,可以给开发效率带来巨大的提升。
劣势:
客户端渲染首屏加载速度慢;服务器端渲染有利于SEO,因为爬虫只认识HTML的内容,而不认识js的内容
在node这种代码体系下遵循的是common.js的规范。所以导入导出用一下形式
const React = require('react');
module.exports = {
default: Home
}
此时的代码也是运行不了的,因为要有webpack配置才可以
在server目录下新建一个webpack.server.js文件,因为是在node端,所以必须加一项target
,为了告诉webpack打包的是服务器端的文件。
const Path = require('path');
const nodeExternals = require('webpack-node-externals');
module.exports = {
target: 'node',
mode: 'development',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: Path.resolve(__dirname, 'build')
},
externals: [nodeExternals()],
module: {
rules: [{
test: /\.js?$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
presets: ['react', 'stage-0', ['env', {
targets: {
browsers: ['last 2 versions']
}
}]]
}
}]
}
}
出现以下警告:
需要安装npm install webpack-node-externals --save
externals: [nodeExternals()]
这个插件的原理是利用了webapck中的externals配置项,来剔除node_modules文件的,因为默认webapck会把所有用到的js文件统统打包,而我们由于是在node端,因此不需要把用到的库也打包了。
import express from 'express';
import Home from './containers/Home';
import { renderToString } from 'react-dom/server';
import React from 'react';
const app = express();
app.get('/', (req, res) => res.send(renderToString( )))
app.listen(3000, () => console.log('Example app listening on port 3000!'))
renderToString(),把页面转换成字符串返回给浏览器
虚拟DOM是真是DOM的一个JavaScript对象映射
客户端渲染react代码在浏览器上执行,消耗的是用户浏览器的性能。
服务端渲染,react代码服务器上执行,消耗的是服务器端的性能,带来的问题是极大的消耗了服务器端的性能。
"build": "webpack --config webpack.server.js --watch"
–watch可以监听入口有文件及入口文件的依赖是否有变化,有变化就自动打包
npm install nodemon -g
全局安装nodemon,帮助node实现文件的监听
"start": "nodemon --watch build --exec node \"./build/bundle.js\""",
监听build文件夹是否有变化,有变化就重新运行bundle.js
总结以上就是build命令来监听文件的变化,start命令来监听build文件夹的变化
npm install npm-run all -g
"scripts": {
"dev": "npm-run-all --parallel dev:**",
"dev:start": "nodemon --watch build --exec node \"./build/bundle.js\"",
"dev:build": "webpack --config webpack.server.js --watch"
},
npm-run-all --parallel dev:**
并行执行以dev开头的所有的命令
一套react代码在服务器端执行一次,在客户端再执行一次。
我们在程序中添加一个button发,并在button上添加一个事件,查看源代码的时候发现事件并没有出现。这时候我们应该用同构来实现。
在根路径下创建一个平public文件,并在其中创建一个index.js文件
import express from 'express';
import Home from './containers/Home';
import { renderToString } from 'react-dom/server';
import React from 'react';
const app = express();
app.use(express.static('public'))
const content = renderToString( );
app.get('/', (req, res) => {
res.send(
`
ssr
${content}
`
)
})
app.listen(3000, () => console.log('Example app listening on port 3000!'))
app.use(express.static('public'));
的意思是服务器发现请求的是静态文件,就到根路径下的public路径中去找。
在src下新建一个client文件夹,并在其中新建一个index.js文件,内容为一下
import React from 'react';
import ReactDom from 'react-dom';
import Home from '../containers/Home';
ReactDom.render( , document.getElementById('root'));
然后再根目录下新建一个public文件夹,在根目录下新建一个webpack.client.js文件,将上面的index.js文件打包到public文件夹中。
但在浏览器上会出现警告:
react-dom.development.js:517 Warning: render(): Target node has markup rendered by React, but there are unrelated nodes as well. This is most commonly caused by white-space inserted around server-rendered markup.
这是由于同构引起的,可以将ReactDom.render
换成ReactDom.hydrate
来解决
如果出现以下错误: 改为 我们发现webpack.client.js和webpack.server.js有很多相同的部分,这样会造成冗余,这时候就引入一个模块 webpack.client.js变成 webpack.server.js变成 还可以对代码结构进行一些优化,服务器端的代码在src/server下,客户端代码在src/client下 在第一步中服务器值渲染出HTML,并不会渲染出事件,所以需要和浏览器段进行重构
react-dom.development.js:523 Warning: Did not expect server HTML to contain the text node " " in
讲的是服务器端渲染不要出现文本节点
将
app.get('/', (req, res) => {
res.send(
`
app.get('/', (req, res) => {
res.send(
`
工程优化整理
npm install webpack-merge --save
这个工具可以帮助我们合并webpack的配置项
在根目录下新建一个webpack.base.js文件,将webpack.client.js和webpack.server.js相同的部分提取到webpack.base.js中module.exports = {
module: {
rules: [{
test: /\.js?$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
presets: ['react', 'stage-0', ['env', {
targets: {
browsers: ['last 2 versions']
}
}]]
}
}]
}
}
const Path = require('path');
const merge = require('webpack-merge');
const config = require('./webpack.base.js');
const clientConfig = {
mode: 'development',
entry: './src/client/index.js',
output: {
filename: 'index.js',
path: Path.resolve(__dirname, 'public')
}
};
module.exports = merge(config, clientConfig);
const Path = require('path');
const nodeExternals = require('webpack-node-externals');
const merge = require('webpack-merge');
const config = require('./webpack.base.js');
const serverConfig = {
target: 'node',
mode: 'development',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: Path.resolve(__dirname, 'build')
},
externals: [nodeExternals()]
};
module.exports = merge(config, serverConfig);
阶段性总结