ssr服务端渲染

305 阅读3分钟

由于最近项目对于首屏渲染速度的要求比较高,之前项目中使用的是nuxt框架,但由于其本身加载的时候,需要额外加载该框架的一些底层js,导致页面会等待其加载成功后,才会开始加载其他东西。一开始使用纯静态页面作为首页进行测试,发现首屏效果提升明显。美中不足的是静态页面无法动态配置页面属性,因此需要使用最直接的服务端渲染,减少加载其他资源。因此最终确认了使用Express-Handlebars的方案

1、安装express 和 Handlebars

yarn init
yarn add express -d
npx express-generator --view=express-handlebars
yarn install

安装成功,如图所示。view里面没有默认的视图,此时视图模板引擎还没有,因为该模板引擎不是官方默认的,需要另外安装

image.png 执行如下指令,就可以安装对应handlebars的引擎

yarn add express-handlebars -d

2、引入express-handlebars

在app.js下进行设置,如下代码

var exphbs = require('express-handlebars');
console.log(exphbs)
app.engine('hbs', exphbs.engine({
    helpers: {
    },//工具函数
    layoutsDir: 'views',//视图
    defaultLayout: 'layouts/main',//默认布局文件
    extname: '.hbs'//视图后缀名
}));
app.set('view engine', 'hbs');//设置对应的视图引擎
app.set('views', './views');// 视图文件的位置

3、初步测试使用

  • 1、创建views/layouts/main.hbs
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Example App</title>
</head>
<body>
    1111111
    {{{body}}}
</body>
</html>
  • 2、创建views/layouts/main.hbs
{{title}}
  • 3、在routes/index.js下,代码如下
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

module.exports = router;

运行后,效果如图所示:

image.png

4、handlebarsjs常用语法

  • 1、一般使用{{}}输出变量,{{{}}}输出没有转义的变量
模板:
{{title}}
{{obj.category}}
数据:
{ 
    title: 'Express', 
    obj:{
        category: 'handlebars', 
    }
}
页面:
Express
handlebars
  • 2、常用的默认助手函数if 、each、with、lookup if:注意,使用if判断的时候,后面不能跟表达式,只能跟变量和助手函数。如果其参数返回 falseundefinednull""、 0 或者 [],Handlebars 将不会渲染该块
模板:
{{#if }}
    {{showtext}}
{{/if}}
数据:
{ 
    show: true, 
    showtext:"展示"
}
页面:
展示

each:注意,当遍历 each 中的项目时,你可以选择通过 {{@index}} 引用当前循环的索引。要访问父级的索引,可以使用 {{@../index}}

模板:
<ul class="people_list">
 {{#each people}}
   <li>{{this}}</li>
 {{/each}}
</ul>
数据:
{
  people: [
    "Yehuda Katz",
    "Alan Johnson",
    "Charles Jolley",
  ],
}
页面:
<ul class="people_list">
    <li>Yehuda Katz</li>
    <li>Alan Johnson</li>
    <li>Charles Jolley</li>
</ul>

with:允许你更改 template-part 的上下文表达式

模板:
{{#with person}}
   {{firstname}} {{lastname}}
{{/with}}
数据:
{
  person: {
    firstname: "Yehuda",
    lastname: "Katz",
  },
}
页面:
Yehuda Katz

lookup:允许使用 Handlebars 变量进行动态的参数解析。这对于解析数组索引的值非常有用。

模板:
{{#each people}}
  {{.}} lives in {{lookup ../cities @index}}
{{/each}}

数据:
{
  people: ["Nils", "Yehuda"],
  cities: [
    "Darmstadt",
    "San Francisco",
  ],
}
页面:
  Nils lives in Darmstadt
   Yehuda lives in San Francisco
  • 3、自定义助手函数 可以在设置引擎的时候设置,就会变成全局调用。也可以在对应路由设置
app.engine('hbs', exphbs.engine({
    helpers: {
        getOneFromList(list) {
            if (list && list.length > 0) {
                return list[0]
            } else {
                return null
            }
        },
        compareEqual(obj1, obj2) {
            return obj1 === obj2
        },
        compareLessThanOrEqual(obj1, obj2) {
            return obj1 <= obj2
        }
    },
    layoutsDir: 'views',
    defaultLayout: 'layouts/main',
    extname: '.hbs'
}));

调用方式跟变量的一样,但是参数后面不需要加括号,空格分开

{{getOneFromList list}}
  • 5、设置部分视图,可以在if,each,等块级助手函数中直接调用,需要在文件夹partials/card/grid下设置,代码如下
{{> card/grid category=category }}

直接在文件夹partials/grid下设置的话,引用代码如下

{{> grid category=category }}

其中category 是该部分视图组件里的变量

image.png

  • 6、也可以自定义块级助手函数,直接引用
模板:
{{#list people}}{{firstname}} {{lastname}}{{/list}}

数据及助手函数:
router.get('/', function (req, res, next) {
  res.render('index', {
    people: [
      {
        firstname: "Yehuda",
        lastname: "Katz",
      },
      {
        firstname: "Carl",
        lastname: "Lerche",
      },
      {
        firstname: "Alan",
        lastname: "Johnson",
      },
    ],
    helpers: {
      list(items, options) {
        const itemsAsHtml = items.map(item => "<li>" + options.fn(item) + "</li>");
        return "<ul>\n" + itemsAsHtml.join("\n") + "\n</ul>";
      }
    }
  });
});
页面:
<ul>
<li>Yehuda Katz</li>
<li>Carl Lerche</li>
<li>Alan Johnson</li>
</ul>

5、dotenv

yarn add dotenv -d

在项目根目录中,创建.env文件,在app.js入口文件设置后,就可以直接引用环境变量

require('dotenv').config();// 设置环境变量
直接通过process.env.GOOGLE_ADSENSE_ID就可以引用

6、最终效果图

默认处于首屏的导航栏图片,按照顺序排列,前两个索引的卡片是不做懒加载的。 image.png