使用设备检测(Device detection)的 JS 服务端渲染(SSR)

原文链接:https://mobiforge.com/design-development/javascript-server-side-rendering-with-device-detection

服务器端渲染有何优势?

自从由 JavaScript 框架负责页面渲染后,就出现了在生成页面之前,需要下载和执行一大堆 JavaScript 来获取资源的问题。

在移动设备处于弱网情况下的时候,或者老旧的硬件,性能不好的硬件上运行的时候,这种方式就会出现问题。

介绍一下服务器端渲染(SSR)。SSR 可以解决这些框架在移动端面临的挑战。简单来说,SSR 将在客户端执行的 Javascript 放在服务器端运行。生成 HTML 页面后,将其发送给客户端,使得客户端根本不需要做太多的工作,就可以将页面呈现给用户。需要给大家提个醒,SSR 并不是一个完美的,添加 SSR 到您的应用程序后,将增加代码的复杂性。

服务器端渲染的常见用例是在用户首次发出请求时,初次渲染页面。当服务器接收到请求时,它将页面组件呈现为 HTML 字符串,然后将其作为响应发送给客户端。之后,客户端只管渲染。

设备检测有何帮助?

过去,批评添加设备检测,因为将服务器端代码添加到 Web 项目中,使得事情变得复杂了。但是,如果您正打算通过 SSR 优化页面加载性能,那么再优化下设备,您肯定不会介意的。既然您已经克服了服务器端解决问题的困难,为什么不能继续追求完美呢?

服务器端设备可以通过使用 User-Agent 字符串来唯一标识客户端设备类型。通过将其与设备功能的数据库进行匹配,可以了解有关用户设备的相关详细信息,并可用于为该设备定制响应优化。

那么,为什么不在 JavaScript 框架中尝试使用有设备检测的服务器端渲染?我能想到的最简单的例子,就是做一个移动和 PC 间的模板切换。示例使用Vue.js,这个框架针对 SSR 的文档最全,易上手。

使用 Vue.js 实现简单的服务器端呈现

我们将从 Chris Fritz 的“ 最简单的Vue 2.0 SSR演示 ”开始。

首先,我们先把例子下载下来,运行起来。从git仓库中把文件下载到本地,运行 npm install 安装依赖。除此之外,应该引入 Vue 框架和 Vue 服务器端渲染程序包。

您可以通过运行下面命令,来检查所有设置是否正确:

npm run dev

现在可以看到你本地起了一个5000端口的服务,浏览器 http://localhost:5000,您可以看到下图:

用开发者工具中的 DOM 检查器,检查页面源(查看源),你会看到好玩的事情发生。在原始来源中,您可以看到 id="app" 具有属性的div server-rendered="true"。恭喜!使用 Vue 的服务器端渲染已经成功运行。

在开发者工具检查器中,该 server-rendered 属性不存在。

我们来看看这是怎么回事,我们的主页面看起来像这样。

<!DOCTYPE html>
<html>
<head>
  <title>My Vue App</title>
  <script src="/assets/vue.js"></script>
</head>
<body>
  <div></div>
  <script src="/assets/app.js"></script>
  <script>app.$mount('#app')</script>
</body>
</html>

Vue.js 初次渲染,将<div id="app"></div>替换,客户端接管并更新DOM。这就是为什么当您检查 DOM 的时候已更改,并且不再具有 server-rendered 属性。

如果您想进一步探索Vue SSR,您可以从Vue.js SSR文档开始

使用DeviceAtlas添加服务器端设备检测

接下来就是让DeviceAtlas node.js客户端启动并运行。你可以从这里获取源码 tarball:https://deviceatlas.com/resources/download-enterprise-api#nodejs。安装方法:npm install deviceatlas-deviceapi-2.1.0.tgz

我们现在可以使用以下代码,在我们的应用程序中导入和设置 DeviceAtlas

var DeviceApiWeb = require('deviceatlas-deviceapi').DeviceApiWeb;
var deviceApi = new DeviceApiWeb();

接下来,我们需要加载DeviceAtlas数据文件,其中包含设备数据。DeviceAtlas是用来确定用户代理的功能的。您需要在这里单独下载此文件

  try {
      deviceApi.loadDataFromFile('47722_20170307.json');
  } catch(e) {
      //json could not load! do something!
      console.log('couldnt load data');
  }

接下来,我们传一个请求对象给DeviceAtlas,以便它检查请求中的User-Agent字符串,提供设备的属性。对于这个简单示例,我们只对 mobileDevice 属性感兴趣,根据特性的不同,使用不同的Vue模板。您可以在DeviceAtlas站点上查看全部属性。可用的属性包括屏幕宽度、高度、用于优化图像,isTouchscreen等可以优化的目标。

检查一下是否是移动设备?简单!

var properties = deviceApi.getPropertiesFromRequest(request);
var isMobile = properties.contains('mobileDevice', true);

DeviceAtlas 代码添加到我们的 server.js 文件。路由用Express.js。将刚刚看到设备检测代码添加到Express路由代码中,效果如下,新的代码突出显示:

server.get('*', function (request, response) {
  // Render our Vue app to a string
  var DeviceApiWeb = require('./deviceatlas-deviceapi').DeviceApiWeb;
  /* Create an instance of DeviceApiWeb with default config */
  var deviceApi = new DeviceApiWeb();
  /* Load data. */
  try {
      deviceApi.loadDataFromFile('./26732_20170308.json');
  } catch(e) {
      //json could not load! do something!
      console.log('couldn\'t load DA data');
  }
  var properties = deviceApi.getPropertiesFromRequest(request);
  var isMobile = properties.contains('mobileDevice', true);

  renderer.renderToString(
    // Create an app instance
    require('./assets/app')(isMobile),
    // Handle the rendered result
    function (error, html) {
      // If an error occurred while rendering...
      if (error) {
        // Log the error in the console
        console.error(error)
        // Tell the client something went wrong
        return response
          .status(500)
          .send('Server Error')
      }
      // Send the layout with the rendered app's HTML
      response.send(
        layout.replace('<div></div>', html)
        )
    }
  )
})

接下来,我们需要为Vue选择正确的模板来使用,我们必须确保当渲染被传递给客户端以供将来的请求时,模板是一致的。

这可以通过几种不同的方式实现。

基于设备类型的切换模板

我们的SSR示例是从/assets/app.js返回单个模板开始的,使用代码如下:

(function () { 'use strict'
  var createApp = function () {
    // ---------------------
    // BEGIN NORMAL APP CODE
    // ---------------------

    // Main Vue instance must be returned and have a root
    // node with the id "app", so that the client-side
    // version can take over once it loads.
    return new Vue({
      template: '<div>You have been here for {{ counter }} seconds.</div>',
      data: {
        counter: 0
      },
      created: function () {
        var vm = this
        setInterval(function () {
          vm.counter += 1
        }, 1000)
      }
    })

    // -------------------
    // END NORMAL APP CODE
    // -------------------
  }
  if (typeof module !== 'undefined' && module.exports) {
    module.exports = createApp
  } else {
    this.app = createApp()
  }
}).call(this)

为了支持设备切换,我们修改代码,写了两个可以返回的模板:一个用于桌面,一个用于移动设备:

  var desktopPage = {
        template: '<div>You have been here for {{ counter }} seconds DESKTOP.</div>',
        data: {
          counter: 0
        },
        created: function () {
          var vm = this
          setInterval(function () {
            vm.counter += 1
          }, 1000)
        }
      }

  var mobilePage = {
    template: '<div>You have been here for {{ counter }} seconds MOBILE.</div>',
    data: {
      counter: 0
    },
    created: function () {
      var vm = this
      setInterval(function () {
        vm.counter += 1
      }, 1000)
    }
  }

我们这两个模板只是更改一些文本显示,但在实际的应用中,您可能会根据需要,向移动端和PC端用户代理发送完全不同的组件。

那么我们如何触发选择哪个模板呢?将isMobile当变量传入server.js文件传入,然后使用它来选择正确的模板。

将下面这行代码:

require('./assets/app')(),

修改为

require('./assets/app')(isMobile),

现在我们可以决定要返回哪个模板app.js:

  var createApp = function (isMobile) {
    return new Vue(isMobile ? mobilePage : desktopPage)
  }

  if (typeof module !== 'undefined' && module.exports) {
    module.exports = createApp
  } else {
    this.app = createApp(this.isMobile)
  }
}).call(this)

如果您重新加载这个应用程序,就会看到服务器正确显示了移动用户代理的移动模板。但之后,客户端接管,服务器端检测不到客户端的改变,因此在首次渲染后,它始终默认为桌面模板。

我们可以通过将Vue模板写入DOM的同时,将设备类型传递给客户端应用来解决这个问题。所以我们添加一个isMobile属性到我们的index.html应用程序 shell:

<!DOCTYPE html>
<html>
<head>
  <title>My Vue App</title>
  <script src="/assets/vue.js"></script>
</head>
<body>
  <div></div>
  <script>window.isMobile = false</script>
  <script src="/assets/app.js"></script>
  <script>app.$mount('#app')</script>
</body>
</html>

当在服务器端运行的时候,我们可以更改这个值:

    response.send(
      layout.replace('<div></div>', html).replace('window.isMobile = false', 'window.isMobile = ' + isMobile)
      )

重新加载,一切都应该按预期工作,客户端和服务器端都会为用户呈现正确的模板。(完整的代码可以在文章的最后下载)。

基于设备类型的路由

例子中,迄今为止只区分了移动用户和非移动用户,并且基于在桌面或移动设备app.js上返回合适的模板。这是一个不错的解决方案,都运行在一个相同的URL上。

但这不是唯一的解决方案。在下面的示例中,我们将展示如何根据使用Express路由实现更细致的设备检测。这种细粒度的设备分割是自适应网页设计的基础,是Alexa百强网站80%应用的技术

例如,我们会将iOS用户代理重定向到一个页面/ios。请注意,我们不是说必须要这样做,只是表明有多种方法可以实现基于设备的流量分割。

我们继续修改我们的案例。

首先,在我们的server.js文件中,我们读取了iOS设备的HTML布局:

var layoutiOS = fs.readFileSync('./ios/index.html', 'utf8')

接下来,我们设置了一个用于iOS设备的新路由:

server.get('/ios', function (request, response) {
  renderer.renderToString(
    // Create an app instance
    require('./assets/ios')(),
    // Handle the rendered result
    function (error, html) {
      // If an error occurred while rendering...
      if (error) {
        // Log the error in the console
        console.error(error)
        // Tell the client something went wrong
        return response
          .status(500)
          .send('Server Error')
      }
      // Send the layout with the rendered app's HTML
      response.send(
        layoutiOS.replace('<div></div>', html)
        )
    }
  )
})

更新我们的设备检测代码来处理iOS的情况:

      var isiOs = properties.contains('osiOs', true);
      if (isiOs) {
        response.redirect('/ios');
        return;
      }

这就是针对服务器端进行的所有的更改。

现在,我们创建iOS目录并添加HTML页面。大体上和我们以前的HTML相同,具体的iOS特定差别,高亮显示:

<!doctype html>
<html>
<head>
  <title>My Vue App - iOS</title>
  <script src="/assets/vue.js"></script>
</head>
<body>
  <div></div>
  <script src="/assets/ios.js"></script>
  <script>iOSWebApp.$mount('#app')</script>
</body>
</html>

最后,我们还必须创建一个iOS特定的应用程序文件。和之前的文件写法也很类似:

(function () { 'use strict'
  var iOSPage = {
    template: '<div><h1>iOS Page</h1> You have been here for {{ counter }} seconds.</div>',
    data: {
      counter: 0
    },
    created: function () {
      var vm = this
      setInterval(function () {
        vm.counter += 1
      }, 1000)
    }
  }

  var createApp = function () {
    return new Vue(iOSPage)
  }
  if (typeof module !== 'undefined' && module.exports) {
    module.exports = createApp
  } else {
    this.iOSWebApp = createApp()
  }
}).call(this)

完成了。重新启动服务器,如果您访问了许多不同的用户代理(Firefox用户代理切换器添加对此很有用),您应该会看到:

1.桌面UA - >桌面模板
2.移动(非iOS)UA - >移动模板
3.iOS UA - >新的iOS模板

结束语

在本文中,我们探索了针对移动端优化的方法,使用设备检测(Device detection)的 JS 服务端渲染。服务器端设备检测,有时被批判,是因为服务器端代码比纯客户端特性检测更难实现。但如果您已经克服了服务端渲染的困难,为什么不优化一下设备检测?您已经克服了将应用程序添加到服务器组件的麻烦,为什么不尽全力地优化您的应用程序?

这里的例子不是最佳的,只是为了认证观点。Vue.js被选为示例,因为它似乎是提供服务器端渲染和运行的最简单方法。毫无疑问,可能还有更有效的方法达到目的。

非常感谢Hasnat Ullah@hasnatullah)在我被卡住的时候,告诉我使用 Vue.js 的例子。

下载

vue-ssr-device-detection.zip

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 服务端渲染(Server Side Rendering,简称 SSR)是一种将应用程序的 HTML 和 CSS 部分渲染到服务器端,再将渲染结果发送给客户端的技术。这样做的目的是为了提高首屏加载速度,并且在某些情况下改善 SEO。 传统的客户端渲染(Client Side Rendering,简称 CSR)技术中,客户端接收到的是一段空白的 HTML 文档,再通过 JavaScript 来动态渲染页面。这种方式对于用户体验来说不够优秀,因为首屏加载需要等待 JavaScript 执行完成。 服务端渲染的技术能够解决这个问题,因为客户端接收到的是一个完整的 HTML 文档,能够立即呈现。用户在操作页面时,再通过 JavaScript 来完成剩余的渲染和交互。 服务端渲染并不适用于所有场景,在选择是否使用 SSR 时需要考虑到应用程序的特定要求和需求。但对于需要提高首屏加载速度和改善 SEO 的应用程序来说,服务端渲染是一个不错的选择。 ### 回答2: 服务端渲染(Server-Side Rendering,简称SSR)是指在服务端动态生成页面内容,然后将渲染好的页面传输给浏览器进行展示的一种网页渲染技术。 传统的客户端渲染,即前端渲染,是指将数据请求发送给服务端,然后由浏览器的JavaScript代码异步获取数据,再将数据和模板进行渲染生成页面。这种渲染方式可以实现灵活的交互效果,但也存在一些问题,如首屏加载较慢、对搜索引擎的SEO不友好等。 而SSR则是在服务端生成完整的HTML页面,然后将渲染好的页面返回给浏览器展示。它的主要优点有: 1. 更快的首屏加载速度:由于服务端渲染页面时已经生成完整的HTML,用户在打开网页时能够立即看到内容,提高了页面的加载速度和用户体验。 2. 更好的SEO:由于搜索引擎爬虫主要是获取HTML内容进行分析,使用SSR能够保证搜索引擎能够正确的读取页面的内容,提高网站的搜索引擎排名。 3. 更好的可访问性:由于服务端渲染生成的页面已经包含了完整的内容和结构,相对于客户端渲染,能够更好地支持辅助功能和设备兼容性。 尽管SSR在首屏加载和SEO方面具有很大的优势,但也存在一些限制和挑战。比如对于复杂的交互和动态内容的处理较为复杂,需要更多的服务器负载和带宽资源。此外,SSR还需要考虑页面的缓存策略和更新机制,以保证渲染的页面始终能够与最新的数据保持同步。 总之,服务端渲染(SSR)是一种能够提高网页加载速度、改善SEO和可访问性的网页渲染技术。尽管它也有一些限制和挑战,但在某些场景下,特别是对于需要快速首屏加载和SEO友好的网站来说,SSR是一种值得采用的渲染方式。 ### 回答3: 服务端渲染(Server-Side Rendering,简称SSR)是指在服务器端进行网页内容的渲染,生成完整的HTML页面后再发送给客户端的一种网页渲染方式。相对于传统的客户端渲染(Client-Side Rendering,简称CSR),SSR具有以下特点: 1. SEO友好:由于搜索引擎爬虫只能解析HTML页面,传统的CSR渲染会导致搜索引擎无法获取到完整的页面内容。而使用SSR时,服务器端渲染出的HTML页面包含了完整的内容,有利于SEO优化和搜索引擎收录。 2. 更快的首次加载速度:在CSR中,页面初始化的过程需要先下载基础的HTML结构和JavaScript代码,然后再通过JavaScript请求并渲染数据,这个过程会产生较长的白屏时间。而SSR在服务器端就生成了完整的HTML页面,用户首次访问时可以直接加载这个HTML,减少首次加载时间。 3. 更好的用户体验:因为SSR在服务器端就渲染了完整的HTML页面,用户可以更快地看到网页的基本内容,提升了用户体验。而在CSR中,由于需要等待JavaScript的下载和执行,用户可能会出现闪动的页面或者突然出现的内容,造成用户体验不佳。 4. 兼容性好:由于SSR在服务器端渲染,不依赖于浏览器的特定功能或版本,对于不支持JavaScript或禁用JavaScript的浏览器仍然可以渲染出完整的页面。 5. 服务器压力较大:相对于CSR,SSR需要在服务器端进行页面渲染,因此对服务器的压力较大,特别是当网站的流量较大时。服务器需要消耗更多的计算资源和内存来渲染页面并返回给客户端。 总结来说,服务端渲染SSR)通过在服务器端生成完整的HTML页面,提供了更好的SEO友好性、首次加载速度和用户体验,但增加了服务器的压力。它适用于对SEO要求较高、首次加载速度重要的网站。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值