前言
搭建官网,考虑后期的SEO优化,一般会使用前端写静态页面,后端来渲染的模式。但其实前端也可以进行服务端渲染,今天讲的主要内容就是前端方面的服务端渲染。本案例使用node做中间层向后端请求数据,再用koa-swig进行服务端模板渲染。
首先配置webpack文件,这个主要是习惯了写es6,还有用到它的公共代码提取和代码压缩。
官网如图所示,主要内容有首页、案例、行业和案例详情、资讯详情等。选主要的2个点,案例和案例详情页,这样就可以了。
1、配置webpack
1、电脑安装node
2、在目标文件夹输入
npm init
开始新建项目
输入项目名称后也可以一直回车完成。
3、全局安装webpack
4、在文件目录里新建webpack.config.js,这个就是webpack的配置文件
var webpack = require("webpack");
var path = require("path");
var glob = require('glob');
// var HtmlWebpackPlugin = require('html-webpack-plugin');
var ROOT_PATH = path.resolve(__dirname,'./dist/js');
var BUILD_PATH = path.resolve(ROOT_PATH, '../es6js');
/**
* 根据目录获取入口
* @param {[type]} globPath [description]
* @return {[type]} [description]
*/
function getEntry(globPath) {
let entries = {};
glob.sync(globPath).forEach(function(entry) {
let basename = path.basename(entry, path.extname(entry)),
pathname = path.dirname(entry);
if (!entry.match(/js\/lib\//)) {
entries[basename] = pathname + '/' + basename;
}
});
return entries;
}
let entryJs = getEntry('./dist/js/*.js');
module.exports = {
resolve: {
modules: [path.resolve(__dirname, 'node_modules')]
},
entry: entryJs,
output: {
path: BUILD_PATH,
publicPath: BUILD_PATH,
filename: "[name].js"
},
module: {
rules: [
{
test: /\.scss$/,
loader: ["style-loader", "css-loader", "sass-loader", ]
},
{
test: /\.js$/,
loader: ["babel-loader?cacheDirectory"],
},
{
test: /\.css$/,
loader: ["style-loader", "css-loader"],
include: path.resolve(__dirname, './src/es6/route')
}
]
},
plugins: [
/**
* 抽出公共JS
*/
new webpack.optimize.CommonsChunkPlugin({
name: "common",
filename: "common.js",
minChunks: 2,
}),
new webpack.optimize.UglifyJsPlugin()
// new HtmlWebpackPlugin()
]
}
引入依赖项,引入的都是需要使用npm安装的,当然,你也可以使用淘宝镜像。
其中ROOT_PATH是转换前的源文件,BUILD_PATH是转换为es5打包后的文件地址。
插件:
- CommonsChunkPlugin是用来抽取公共引入的部分打包成common.js,这里配置的是引入2次及以上的模块会被打包进common.js。
- UglifyJsPlugin这个是用来进行代码压缩。
5、配置编译es6还需要加个文件,.babelrc
.babelrc代码
{
"presets": [
[
"es2015",
{
"modules": false
}
]
],
"plugins": []
}
这样就可以把es6直接转换为es5运行了。
6、目录解释:我把模板文件放在了views文件夹,其他附带的js\css\img等统一放在静态目录dist文件夹.设置后可以当做根目录直接使用端口调用。
7、node服务端app.js
const Koa = require("koa");
const serv = require("koa-static");
const render = require("koa-swig");
const co = require("co");
const path = require("path");
const app = new Koa();
const initRouter = require("./router");
app.use(serv(__dirname+'/dist'));
app.context.render = co.wrap(render(app, {
root: path.join(__dirname, 'views'),
autoescape: true,
cache: 'memory',
writeBody: false,
ext: 'html'
}));
initRouter(app);
app.listen( (process && process.env && process.env.PORT) || 3000, ()=>{
console.log('服务已启动,port:' + ((process && process.env && process.env.PORT) || 3000));
});
注意其中app.use(serv(__dirname+'/dist'))就是设置静态目录。
8、node端请求封装base.js
const request = require('request');
const querystring = require('querystring');
let baseHttp = "http://172.1.1.1/TB/"; //这里是你的后端的接口默认地址。
class myRequest{
constructor(){
}
get(url,data,callback){
let myUrl = `${url}?`;
let dataArray = [];
for(let k in data){
let paramStr = `${k}=${data[k]}`;
dataArray.push(paramStr);
}
let urlStr = dataArray.join("=");
myUrl = `${myUrl}${urlStr}`;
request(myUrl,(error, response, body)=> {
if (response && response.statusCode && response.statusCode === 200) {
try{
body = JSON.parse(body);
}catch(e){
body = null;
}
callback&&callback(body);
}
});
}
post(url,data){
return new Promise(function (resolve, reject) {
request.post({
url: `${baseHttp}${url}`,
json: true,
form:(data)
}, function(error, response, data) {
if (response) {
if (!error && response.statusCode == 200) {
resolve(data);
// callback && callback(data.Data);
}else{
reject('error===');
}
} else {
console.log(error);
//后台程序错误
var data = {
ResultCode:0,
Message:'与后台通信异常'
}
resolve(data);
}
});
})
}
}
module.exports=myRequest;
9、路由router.js
const Router = require('koa-router')
const koaBody = require('koa-body');
const myrequest = require('./modules/base');
let myRequest = new myrequest();
module.exports = function (app) {
const router = new Router();
app.use(router.routes());
app.use(router.allowedMethods());
//案例页路由
router.get('/cases.html',async (ctx,next)=>{
// ctx.router available
let cbdata = {};
let data = {};
let pagecurrent = ctx.query.page || 1;
data = await myRequest.post('/api/Home/GetProjectCaseList',{PageNo:pagecurrent,PageSize:20});
if(data && data.ResultCode=="6666"){
cbdata = data.Data;
}
cbdata.base = {
title:'案例页',
self:'cases',
};
if(cbdata.PageInfo){
cbdata.PageInfo.PageList = [];
let count = cbdata.PageInfo.PageCount || 0;
let className = "";
for(let i=0;i{
// ctx.router available
let id = ctx.query.id;
let cbdata = {};
let data = {};
data = await myRequest.post('/api/Home/GetProjectCaseById',{'id':id});
if(data && data.ResultCode=="6666"){
cbdata = data.Data;
}
cbdata.base = {
title:'案例详情页',
self:'casesdetail',
};
ctx.body = await ctx.render('casesdetail',cbdata);
});
}
这个js写的比较粗糙,主要作用:
router.get('/cases.html',async(ctx,next)=>{
let id = ctx.query.id;
ctx.body = await ctx.render('cases',cbdata);
}
根据koa-router路由捕获到触发路由cases.html后,ctx.query.id获取参数,例如浏览器显示路由/cases.html?id=12345,那么就可以直接提取到12345作为id.可以用这个来进行分页和判断选择了那个类目
ctx.body = await ctx.render('cases',cbdata);就是从views文件夹里寻找文件名为cases的文件,将值cbdata放进模板渲染然后形成一个html文件代码返回给ctx.body显示。
cbdata.base = {
title:'案例页',
self:'cases',
};
里面的self用来在公共模板按每个不同的页面引入文件名对应的js
10、模板文件:
- 模板文件也是html后缀,页面顶部导航和底部导航公用,所以提取出来作为header和footer
- header.html
{% if ObjDetail %}
{% endif %}
{% if ObjDetail %}
{% endif %}
{% if base %}
{{base.title}}
{% endif %}
{{}}插值运算
判断是否存在:{% if ... %},以{% endif %}结尾
- cases.html
{% include 'header.html' %}
用真实案例说话
“为客户打造传奇品牌,成就电影人生”
{% if List %}
{% for item in List %}
-
{{item.Title}}
{% endfor %}
{% endif %}
{% if (PageInfo && PageInfo.PageList) %}
{% for item in PageInfo.PageList %}
{{loop.index}}
{% endfor %}
{% endif %}
{% include 'footer.html' %}
{% include template%}引入模板
{% for i in k %}、{% endfor %}循环渲染
- casedetail.html
{% include 'headerdetail.html' %}
{% if ObjDetail %}
{{ObjDetail.Title}}
{{ObjDetail.PublishDate}} {{ObjDetail.Author}}
{% autoescape false %}
{{ ObjDetail.Content }}
{% endautoescape %}
{% include 'footer.html' %}
{% autoescape false %}、{% endautoescape %}html渲染,相当于jq的.html()和vue的v-html
这样模板就渲染好了,footer.js中我也引入了common.js和各自对应的文件名js文件
好了,这样就做完了,css我是用sass写的,不知道怎么用的也可以看我之前的文章。使用命令:webpack -w可以打包文件,node app.js可以运行项目,然后在浏览器中打开,当然也可以在package.json中配置start,这样直接运行npm start也可以直接运行项目.
在这里还要特别感谢沃土社区老胡,你的指导让我们越来越强大
写完了,觉得辛苦就支持下吧,另外有小项目兼职的也可以给我一点小单一起做啊