12.2.1 设置Node.js和Express
您可以在百度里搜索“深入浅出React和Redux 艾草文学(www.321553.xyz)”查找最新章节!
12.2.1 设置Node.js和Express
在第11章中,我们已经对create-react-app产生的应用进行了“弹出”操作,这样我们终于获得了任意定制webpack的自由,不过应用启动脚本npm start依然是create-react-app生成的,启动之后虽然也有一个基于Node.js的服务器端在运行,但是只是简单地对所有请求返回public目录下的index.html文件,无法定制服务器端内容,所以只能自己动手创造新的启动脚本。
这一节相关代码可以在本书的Github库https://github.com/mocheng/react-and-redux的目录chapter-12/express_server下找到。
Node.js提供的API都非常的底层,快速开发一个网络应用必须要借助Node.js之上框架的支持,在这里我们使用Express框架,还有在Express中我们要使用ejs模板工具,首先要安装相关npm包:
npm install –-save express ejs
然后,我们在项目根目录下创造一个server目录,这个目录用于存放所有只在服务器端运行的代码,我们先要定义服务器端入口文件server/index.js,代码如下:
const isProductionMode = (process.env.NODE_ENV === 'production');
const app = isProductionMode ? require('./app.prod.js'): require('./app.dev.js');
if (!isProductionMode) {
process.env.NODE_ENV = 'development';
}
const PORT = process.env.PORT || 9000;
app.listen(PORT, function() {
console.log('running in ' + (isProductionMode ? 'producition' : 'development') + ' mode');
console.log('listening on port: ' + PORT);
});
这个文件根据当前环境变量选的“开发模式”或者“产品模式”运行,因为两种模式下代码大不一样,所以主要代码分别放在app.dev.js和app.prod.js文件中。
为了避免和原有的npm start启动脚本冲突,程序监听的端口不是3000而是9000。
相对而言,“产品模式”下的代码简单一些,我们先来看server/app.prod.js如何实现,代码如下:
const express = require('express');
const path = require('path');
const app = express();
const assetManifest = require(path.resolve(__dirname, '../build/asset-manifest.json'));
app.use(express.static(path.resolve(__dirname, '../build')));
app.get('*', (req, res) => {
return res.render('index', {
title: 'Sample React App',
PUBLIC_URL: '/',
assetManifest: assetManifest
});
});
app.set('view engine', 'ejs'); // 使用ejs作为渲染模板。
app.set('views', path.resolve(__dirname, 'views')); //模板文件目录。
module.exports = app;
要运行“产品模式”,必须先通过npm run build命令编译产生所有的浏览器端Java-Script打包文件,这些打包文件都已经做过优化处理,而且文件名中包含8个字符的哈希值,所以要想确定这些打包文件实际的文件名,需要去读取转译过程中产生的描述文件,描述文件存放在项目目录下的build/asset-manifest.json中,这个文件内容是JSON形式,大概如下:
{
"404.js": "static/js/404.d5ac31a0.chunk.js",
"404.js.map": "static/js/404.d5ac31a0.chunk.js.map",
"about.js": "static/js/about.8642419c.chunk.js",
"about.js.map": "static/js/about.8642419c.chunk.js.map",
...
"main.js.map": "static/js/main.f3a22285.js.map"
}
上面只是一个例子,每个文件名中的8位哈希值随文件内容改变而改变,任何一点代码逻辑修改都会导致文件名的不同。
要获得页面应该引用的JavaScript文件,只需读取build/asset-manifest.json文件中main.js和common.js对应的路径就行,其他的分片文件比如home.js和404.js,打包文件main.js会按需去动态加载,也就是require.ensure函数被调用的时候去加载,无需我们操心。
在app.prod.js中,对于所有HTTP请求,先去static目录下匹配静态资源。如果找不到,就会用app.get指定的一个默认路径处理,和React-Router一样,“*”代表任何路径,默认路径的处理方式就是用ejs模板返回一个定制的HTML网页。
在server/views/index.ejs文件中是模板文件,代码如下:
= title
目前,这个模板文件只渲染了一个div作为浏览器端React的舞台,另外引入了common.js和main.js对应的实际JavaScript路径,产生的内容和npm start没有差别,这只是一个阶段性小目标,后面我们会让这个模板包含真正的服务器端渲染内容。
最后我们在package.json中的scripts部分增加一个指令:
"start_prod": "NODE_ENV=production node server/index.js",
就可以在命令行通过npm run start_prod来启动“产品模式”的应用了,这次的应用链接是在http://localhost:9000上,但是每次这样修改代码之后,都要先运行npm run build编译产生打包文件,实在很麻烦,所以大部分时间开发者还是要在“开发模式”下运行程序,为了达到便于开发的目的,相对应的代码server/app.dev.js就要麻烦很多。 深入浅出React和Redux