内鬼 Hapi.js + React.js 配合写的 SPA 之痛苦!

阅读时长 13 分钟读完

前端开发中,尤其是在单页应用程序(SPA)的开发中,组件化已经变成了一个流行的趋势。React.js 则是这个趋势中的重要一环,它被广泛使用,并且它的组件化设计使得它非常适合构建大型的,复杂的前端应用。而 Hapi.js 又是 node.js 中最流行的 WEB 框架之一,它提供了许多开箱即用的功能,例如路由配置、错误处理和中间件等。

然而,在将 Hapi.js 和 React.js 应用于 SPA 开发中时,有一些需要注意的细节。在这篇文章中,我将告诉你在实际开发中,将 Hapi.js 和 React.js 结合使用时,可能会遇到哪些问题以及如何解决它们。

问题 1:SPA 路由

在单页应用中,页面切换是通过路由来实现的。对于 React.js 应用程序,有很多的服务端渲染解决方案,例如 Next.js 或 Gatsby.js 等,这些方案不仅可以提高应用程序的性能,而且可以使搜索引擎更好的处理你的网站并且可以提高你的网站的 SEO。然而,这些解决方案需要你将应用程序与 React.js 绑定在一起。那么问题来了,如果你已经在已有的 Hapi.js 项目中使用 React.js,那么该如何实现这些路由呢?

解决方案

我们可以使用固定路径的路由,每个路由都做一个标志,然后在客户端和服务端中同时匹配。如果匹配成功,就渲染相应的组件。客户端的路由可以使用 React.js 相关的库(例如 React Router),服务端路由可以使用 Hapi.js 的服务器路由。

举个例子,我们可以定义一个路由文件,例如 routes.js,并将其加入到服务器路由:

-- -------------------- ---- -------
----- ------ - -
  -
    ----- ----
    ---------- ----
  --
  -
    ----- ---------
    ---------- ------
  --
--

-------- ---------------------- -
  -------------------- -- -
    --------------
      ------- ------
      ----- -----------
      -------- --------- -- -- -
        ----- ------- - ---
        ----- - ----- ----- - - ------------
        ----- --- - -
          ------------- ----------- --------- ----- ------- ----- -- ------------------
            --------------------------------------
          ---------------
        --
        ----- ---- - --------------------
        ----- - ------ ----------- - - ----------- -- ---

        ------ -
          -------------------- ----- ------ ----------- ---
          -------------------
      -
    ---
  ---
-

在这个例子中,我们创建了一个 routes 数组,它包含每个路由的名称和相应的组件。我们还创建了一个 registerRoutes 函数,它会将组件和路由注册进 Hapi.js 的路由配置文件中。我们使用 StaticRouter 组件将路由注入到组件中,并使用 renderToString 将其转化为字符串。最后,我们返回了完整的 HTML 标记,以便服务器可以将其发送给客户端。

在客户端代码中,我们可以使用 BrowserRouter 对象来设置路由,这样我们的路由就可以同时在服务端和客户端进行匹配。这里我们可以举一个例子。

-- -------------------- ---- -------
------ - ------------- -- ------- ------ ------ - ---- -------------------
------ - ------ - ---- ------------
------ ---- ---- --------------------
------ ----- ---- ---------------------

-------
  --------
    --------
      ------ ----- -------- ---------------- --
      ------ ----- ------------- ----------------- --
    ---------
  ----------
  ------------------------------
--

在这个例子中,我们使用 BrowserRouter 来设置路由,同时在客户端中设置了与服务端相同的路由。当我们在客户端中调用 render 函数时,就会启动我们的应用并使用 React.js 来渲染我们的组件。这样就可以实现我们前面提到的路由匹配逻辑了。

问题 2:样式

在 React.js 应用程序中,样式通常与组件绑定在一起。例如,在创建一个 Button 组件时,我们通常会定义相应的样式。然而,在使用 Hapi.js 与 React.js 结合开发 SPA 时,我们面临着样式不一致的问题。

解决方案

为了解决这个问题,我们可以使用一个流行的样式库来帮助我们保持样式一致性。例如,我们可以使用 Material-UI 这样的库来定义组件和相应的样式。

首先,在服务器和客户端都需要加入 css 的编译工具,例如 less 或 sass。这里我们采用 less 为例,在 package.json 中添加依赖:

.less 文件编译后,我们需要让其生效。所以在客户端中可以手动引入放置在 /dist 目录下的样式文件:

-- -------------------- ---- -------
----- ---- - ----------------
----- ------------ - --------------------------
----- ----------- - -------------------------
----- ------- - ---------------------------

----- --------- - ----- -- -- -
  ----- --- - ---------
    ------- -------------------- --- ------------
  ---
  ----------------------

  ------------------ ------------------------------------ -------------
  --------
    ----
    ------------
      -
        ------- -
          ---- --------------
        --
        ----- ----------------------- ---------------
      --
      --
    -
  --

  ------ ----
--

----- ----- - ----- -- -- -
  --- -
    ----- --- - ----- ------------
    ----- -----------------

    ---------------- ----------- -- --------- -- ---- -------------------------------
  - ----- ----- -
    -----------------
    ----------------
  -
--
--------

在服务端,比较建议的方式是将样式文件注入到 HTML 模板中。这里我们提供一个 template.js 示例:

-- -------------------- ---- -------
----- -------- - -- ------ ----- ------------ -- -- -
  --------- -----
  ------
    ------
      -----------------------
      ----- ------------------------------ -----------------
    -------
    ------
      ---- ----------------------
      --------
        ------------------------ - --------------------------------
      ---------
      ------- ----------------------------------------
      ------- --------------------------------------
    -------
  -------
--

-------------- - ---------

这个例子中,我们添加了一个链接到主要样式文件的 <link> 标记。这个文件将在用户打开页面时自动加载,并使样式在客户端和服务器之间保持一致。其他样式文件也可以加入以扩展应用 UI 设计的自由空间。

问题 3:多语言支持

对于一些有实际业务场景的应用,多语言支持也是必不可少的。尽管在 React.js 和 Hapi.js 中都有支持不同语言的库,但是结合使用时,仍然需要一些额外的工作来使其正确运作。

解决方案

在服务端中,Hapi.js 的 Accept-Language 插件可以帮助我们解决这个问题。它可以自动检查用户的首选语言并将其储存在请求变量中。我们可以使用这些变量来确定合适的语言。

-- -------------------- ---- -------
----- - -------------------- - - -------------------------------
----- --- - ---------------------

----- ----- - -
  --------- -------------------------------------------- ---------
  ------- ---------------------------------------------
  ------- ----------------------------------------------
--

----- -------- - --------------------------- -
  ------ -----
    ---- -----
    ------- ---- - -- - --
  ---
  ---------------- -----
---

--------------
  ------- ------
  ----- -----------
  -------- --------- ------ -- -
    ----- ---- - -----------------
    -- ---
  -
---

在客户端中,我们可以采用 React.js 的 LocaleProvider 组件,它可以在应用程序的顶层级别上设置当前用户的语言。下面是一个简单的示例:

-- -------------------- ---- -------
------ - -------------- - ---- -------
------ ----- ---- ---------------------------------
------ ----- ---- ---------------------------------
------ --- ---- -------------------

------ ---------------

----- ---- - -------------------

----------------
  --------------- ------------ --- ------- - ----- - -------
    ---- --
  ------------------
  -------------------------------
--

在这个例子中,我们使用了 Ant Design 的组件库,并通过 LocaleProvider 组件来使用不同的语言环境。我们检查了当前用户使用的语言,并根据其内容来初始化 LocaleProvider 组件。

问题 4:鉴权

SPA 的一个基本要求就是需要进行鉴权。然而,在使用 Hapi.js 和 React.js 相结合时,这个要求需要考虑到更多的细节。

解决方案

首先,我们需要在登录后在服务器返回一个 token 以用于鉴权。然后,我们必须在客户端持久化该 token 标识,并将其附加到每个后续发出的请求中。我们可以使用一个小的库,例如 universal-cookie,来简化这个过程:

-- -------------------- ---- -------
------ ------- ---- -------------------

----- ------- - --- ----------

------- -- ---- -- -------------
----- ----- - ---------------------
-- ------- -
-- --- -------------- ------ ---- -----
 ---------------------------------------------- - ------- ----------
-

在这个例子中,我们检查是否有名为 token 的 cookie,如果存在,则将 Authorization 附加到每个请求的头部中。

然后,在客户端进行路由管理时,我们可以使用 react-router-dom 库中的 PrivateRoute 组件来实现鉴权控制。这个组件的核心是通过检查用户是否已经登录,并在未登录时重定向到确认页面:

-- -------------------- ---- -------
------ ----- ---- --------
------ - ------ -------- - ---- -------------------
------ ------- ---- -------------------

----- ------ - --- ----------

----- ------------ - -- ---------- ---------- ------- -- -- -
  ----- --------------- - ------------------- --- ----------
  ------ -
    ------
      ---------
      ------------- --
        --------------- - -
          ---------- ---------- --
        - - -
          ---------
            ----- --------- --------- ------ - ----- -------------- - --
          --
        -
      -
    --
  --
--

------ ------- -------------

这个组件采用了一个标志,用于检查用户是否已登录。如果用户已经登录,就使用正常的路由组件,否则就重定向到指定的错误页面。

总结

结合 Hapi.js 和 React.js 开发 SPA,虽然会有一些问题,但是它仍然可以是一种非常强大,灵活的方法,可以帮助我们构建大型的,高效的前端应用程序。通过我们在上述问题中所提到的解决方案,您应该能够在自己的应用程序中快速开始使用这两种技术。同时,这些方案也只是冰山一角。您可以通过深度学习 Hapi.js 和 React.js 这两个库,来探究更多的可优化点,进一步提升 SPA 开发体验。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6465e954968c7c53b0692b30

纠错
反馈