国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

使用 PHP 來做 Vue.js 的 SSR 服務端渲染

李增田 / 1826人閱讀

摘要:對于客戶端應用來說,服務端渲染是一個熱門話題。在服務器預渲染初始應用狀態(tài)。重構(gòu)這段腳本,使其可以在服務端運行。如果這些原因和你的情況吻合,那么使用進行服務端渲染將會是個不錯方案。我已經(jīng)發(fā)布兩個庫來支持的服務端渲染和專為應用打造的。


對于客戶端應用來說,服務端渲染是一個熱門話題。然而不幸的是,這并不是一件容易的事,尤其是對于不用 Node.js 環(huán)境開發(fā)的人來說。

我發(fā)布了兩個庫讓 PHP 從服務端渲染成為可能.spatie/server-side-rendering?和?spatie/laravel-server-side-rendering適配 laravel 應用。

讓我們一起來仔細研究一些服務端渲染的概念,權(quán)衡優(yōu)缺點,然后遵循第一法則用 PHP 建立一個服務端渲染。

什么是服務端渲染

一個單頁應用(通常也叫做 SPA )是一個客戶端渲染的 App 。這是一個僅在瀏覽器端運行的應用。如果你正在使用框架,比如 React, Vue.js 或者 AngularJS ,客戶端將從頭開始渲染你的 App 。

瀏覽器的工作

在 SPA 被啟動并準備使用之前,瀏覽器需要經(jīng)過幾個步驟。

下載 JavaScript 腳本

解析 JavaScript 腳本

運行 JavaScript 腳本

取回數(shù)據(jù)(可選,但普遍)

在原本的空容器渲染應用? (首次有意義的渲染)

準備完成!?(可以交互啦)

用戶不會看到任何有意義的內(nèi)容,直到瀏覽器完全渲染 App(需要花費一點時間)。這會造成一個明顯的延遲,直到 首次有意義的渲染 完成,從而影響了用戶體驗。

這就是為什么服務端渲染(一般被稱作 SSR )登場的原因。SSR 在服務器預渲染初始應用狀態(tài)。這里是瀏覽器在使用服務端渲染后需要經(jīng)過的步驟:

渲染來自服務端的 HTML (首次有意義的渲染)

下載 JavaScript 腳本

解析 JavaScript 腳本

運行 JavaScript 腳本

取回數(shù)據(jù)

使已存在的 HTML 頁面可交互

準備完成!?(可以交互啦)

由于服務器提供了 HTML 的預渲染塊,因此用戶無需等到一切完成后才能看到有意義的內(nèi)容。注意,雖然 交互時間 仍然處于最后,但可感知的表現(xiàn)得到了巨大的提升。

服務端渲染的優(yōu)點

服務端渲染的主要優(yōu)點是可以提升用戶體驗。并且,如果你的網(wǎng)站需要應對不能執(zhí)行 JavaScript 的老舊爬蟲,SSR 將是必須的,這樣,爬蟲才能索引服務端渲染過后的頁面,而不是一個空蕩蕩的文檔。

服務端如何渲染?

記住服務端渲染并非微不足道,這一點很重要。當你的 Web 應用同時運行在瀏覽器和服務器,而你的 Web 應用依賴 DOM 訪問,那么你需要確保這些調(diào)用不會在服務端觸發(fā),因為沒有 DOM API 可用。

基礎(chǔ)設(shè)施復雜性

假設(shè)你決定了服務端渲染你的應用端程序,你如果正在閱讀這篇文章,很大可能正在使用 PHP 構(gòu)建應用的大部分(功能)。但是,服務端渲染的 SPA 需要運行在 Node.js 環(huán)境,所以將需要維護第二個程序。

你需要構(gòu)建兩個應用程序之間的橋梁,以便它們進行通信和共享數(shù)據(jù):需要一個 API。構(gòu)建無狀態(tài) API 相比于構(gòu)建有狀態(tài)是比較 困難 的。你需要熟悉一些新概念,例如基于 JWT 或 OAUTH 的驗證,CORS,REST ,添加這些到現(xiàn)有應用中是很重要的。

有得必有所失,我們已經(jīng)建立了 SSR 以增加 Web 應用的用戶體驗,但 SSR 是有成本的。

服務器端渲染權(quán)衡取舍

服務器上多了一個額外的操作。一個是服務器增加了負載壓力,第二個是頁面響應時間也會稍微加長。 不過因為現(xiàn)在服務器返回了有效內(nèi)容,在用戶看來,第二個問題的影響不大。

大部分時候你會使用 Node.js 來渲染你的 SPA 代碼。如果你的后端代碼不是使用 Javascript 編寫的話,新加入 Node.js 堆棧將使你的程序架構(gòu)變得復雜。

為了簡化基礎(chǔ)架構(gòu)的復雜度, 我們需要找到一個方法,使已有的 PHP 環(huán)境作為服務端來渲染客戶端應用。

在 PHP 中渲染 JavaScript

在服務器端渲染 SPA 需要集齊以下三樣東西:

一個可以執(zhí)行 JavaScript 的引擎

一個可以在服務器上渲染應用的腳本

一個可以在客戶端渲染和運行應用的腳本

SSR scripts 101

下面的例子使用了 Vue.js。你如果習慣使用其它的框架(例如 React),不必擔心,它們的核心思想都是類似的,一切看起來都是那么相似。

簡單起見,我們使用經(jīng)典的 “ Hello World ” 例子。

下面是程序的代碼(沒有 SSR):

// app.js
import Vue from "vue"

new Vue({
  template: `
    
Hello, world!
`, el: "#app" })

這短代碼實例化了一個 Vue 組件,并且在一個容器(id 值為 app 的 空 div)渲染。

如果在服務端運行這點腳本,會拋出錯誤,因為沒有 DOM 可訪問,而 Vue 卻嘗試在一個不存在的元素里渲染應用。

重構(gòu)這段腳本,使其 可以 在服務端運行。

// app.js
import Vue from "vue"

export default () => new Vue({
  template: `
    
Hello, world!
` }) // entry-client.js import createApp from "./app" const app = createApp() app.$mount("#app")

我們將之前的代碼分成兩部分。app.js 作為創(chuàng)建應用實例的工廠,而第二部分,即 entry-client.js,會運行在瀏覽器,它使用工廠創(chuàng)建了應用實例,并且掛載在 DOM。

現(xiàn)在我們可以創(chuàng)建一個沒有 DOM 依賴性的應用程序,可以為服務端編寫第二個腳本。

// entry-server.js
import createApp from "./app"
import renderToString from "vue-server-renderer/basic"

const app = createApp()

renderToString(app, (err, html) => {
  if (err) {
    throw new Error(err)
  }
  // Dispatch the HTML string to the client...
})

我們引入了相同的應用工廠,但我們使用服務端渲染的方式來渲染純 HTML 字符串,它將包含應用初始狀態(tài)的展示。

我們已經(jīng)具備三個關(guān)鍵因素中的兩個:服務端腳本和客戶端腳本。現(xiàn)在,讓我們在 PHP 上運行它吧!

執(zhí)行 JavaScript

在 PHP 運行 JavaScript,想到的第一個選擇是 V8Js。V8Js 是嵌入在 PHP 擴展的 V8 引擎,它允許我們執(zhí)行 JavaScript。

使用 V8Js 執(zhí)行腳本非常直接。我們可以用 PHP 中的輸出緩沖和 JavaScript 中的 print 來捕獲結(jié)果。

$v8 = new V8Js();

ob_start();

// $script 包含了我們想執(zhí)行的腳本內(nèi)容

$v8->executeString($script);

echo ob_get_contents();
print("
Hello, world!
")

這種方法的缺點是需要第三方 PHP 擴展,而擴展可能很難或者不能在你的系統(tǒng)上安裝,所以如果有其他(不需要安裝擴展的)方法,它會更好的選擇。

這個不一樣的方法就是使用 Node.js 運行 JavaScript。我們可以開啟一個 Node 進程,它負責運行腳本并且捕獲輸出。
Symfony 的?Process 組件就是我們想要的。

use SymfonyComponentProcessProcess;

// $nodePath 是可執(zhí)行的 Node.js 的路徑
// $scriptPath 是想要執(zhí)行的 JavaScript 腳本的路徑

new Process([$nodePath, $scriptPath]);

echo $process->mustRun()->getOutput();
console.log("
Hello, world!
")

注意,(打?。┰?Node 中是調(diào)用 console.log 而不是 print 。

讓我們一起來實現(xiàn)它吧!

spatie/server-side-rendering 包的其中一個關(guān)鍵理念是?引擎?接口。引擎就是上述 JavaScript 執(zhí)行的一個抽象概念。

namespace SpatieSsr;

/**
 * 創(chuàng)建引擎接口。
 */
interface Engine
{
    public function run(string $script): string;
    public function getDispatchHandler(): string;
}

run?方法預期一個腳本的輸入 (腳本 內(nèi)容,不是一條路徑),并且返回執(zhí)行結(jié)果。?getDispatchHandler?允許引擎聲明它預期腳本如何展示發(fā)布。例如 V8 中的print?方法,或是 Node 中的 console.log?。

V8Js 引擎實現(xiàn)起來并不是很花俏。它更類似于我們上述理念的驗證,帶有一些附加的錯誤處理機制。

namespace SpatieSsrEngines;

use V8Js;
use V8JsException;
use SpatieSsrEngine;
use SpatieSsrExceptionsEngineError;

/**
 * 創(chuàng)建一個 V8 類來實現(xiàn)引擎接口類 Engine 。
 */
class V8 implements Engine。
{
    /** @var V8Js */
    protected $v8;

    public function __construct(V8Js $v8)
    {
        $this->v8 = $v8;
    }

    /**
     * 打開緩沖區(qū)。
     * 返回緩沖區(qū)存儲v8的腳本處理結(jié)果。
     */
    public function run(string $script): string
    {
        try {
            ob_start();

            $this->v8->executeString($script);

            return ob_get_contents();
        } catch (V8JsException $exception) {
            throw EngineError::withException($exception);
        } finally {
            ob_end_clean();
        }
    }

    public function getDispatchHandler(): string
    {
        return "print";
    }
}

注意這里我們將?V8JsException?重新拋出作為我們的?EngineError。 這樣我們就可以在任何的引擎視線中捕捉相同的異常。

Node 引擎會更加復雜一點。不像 V8Js,Node 需要?文件?去執(zhí)行,而不是腳本內(nèi)容。在執(zhí)行一個服務端腳本前,它需要被保存到一個臨時的路徑。

namespace SpatieSsrEngines;

use SpatieSsrEngine;
use SpatieSsrExceptionsEngineError;
use SymfonyComponentProcessProcess;
use SymfonyComponentProcessExceptionProcessFailedException;

/**
 * 創(chuàng)建一個 Node 類來實現(xiàn)引擎接口類 Engine 。
 */
class Node implements Engine
{
    /** @var string */
    protected $nodePath;

    /** @var string */
    protected $tempPath;

    public function __construct(string $nodePath, string $tempPath)
    {
        $this->nodePath = $nodePath;
        $this->tempPath = $tempPath;
    }

    public function run(string $script): string
    {
        // 生成一個隨機的、獨一無二的臨時文件路徑。
        $tempFilePath = $this->createTempFilePath();

        // 在臨時文件中寫進腳本內(nèi)容。
        file_put_contents($tempFilePath, $script);

        // 創(chuàng)建進程執(zhí)行臨時文件。
        $process = new Process([$this->nodePath, $tempFilePath]);

        try {
            return substr($process->mustRun()->getOutput(), 0, -1);
        } catch (ProcessFailedException $exception) {
            throw EngineError::withException($exception);
        } finally {
            unlink($tempFilePath);
        }
    }

    public function getDispatchHandler(): string
    {
        return "console.log";
    }

    protected function createTempFilePath(): string
    {
        return $this->tempPath."/".md5(time()).".js";
    }
}

除了臨時路徑步驟之外,實現(xiàn)方法看起來也是相當直截了當。

我們已經(jīng)創(chuàng)建好了 Engine 接口,接下來需要編寫渲染的類。以下的渲染類來自于 spatie/server-side-rendering 擴展包,是一個最基本的渲染類的結(jié)構(gòu)。

渲染類唯一的依賴是 Engine 接口的實現(xiàn):

class Renderer
{
    public function __construct(Engine $engine)
    {
        $this->engine = $engine;
    }
}

渲染方法 render 里將會處理渲染部分的邏輯,想要執(zhí)行一個 JavaScript 腳本文件,需要以下兩個元素:

我們的應用腳本文件;

一個用來獲取解析產(chǎn)生的 HTML 的分發(fā)方法;

一個簡單的 render?如下:

class Renderer
{
    public function render(string $entry): string
    {
        $serverScript = implode(";", [
            "var dispatch = {$this->engine->getDispatchHandler()}",
            file_get_contents($entry),
        ]);

        return $this->engine->run($serverScript);
    }
}

此方法接受 ?entry-server.js?文件路徑作為參數(shù)。

我們需要將解析前的 HTML 從腳本中分發(fā)到 PHP 環(huán)境中。dispatch 方法返回 Engine 類里的 getDispatchHandler 方法,dispatch 需要在服務器腳本加載前運行。

還記得我們的服務器端入口腳本嗎?接下來我們在此腳本中調(diào)用我們的 ?dispatch 方法:

// entry-server.js
import app from "./app"
import renderToString from "vue-server-renderer/basic"

renderToString(app, (err, html) => {
  if (err) {
    throw new Error(err)
  }
  dispatch(html)
})

Vue 的應用腳本無需特殊處理,只需要使用 ?file_get_contents 方法讀取文件即可。

我們已經(jīng)成功創(chuàng)建了一個 PHP 的 SSR 。spatie/server-side-rendering 中的完整渲染器 Renderer?跟我們實現(xiàn)有點不一樣,他們擁有更高的容錯能力,和更加豐富的功能如有一套 PHP 和 JavaScript 共享數(shù)據(jù)的機制。如果你感興趣的話,建議你閱讀下源碼 server-side-rendering 代碼庫?。

三思而后行

我們弄清楚了服務器端渲染的利和弊,知道 SSR 會增加應用程序架構(gòu)和基礎(chǔ)結(jié)構(gòu)的復雜度。如果服務器端渲染不能為你的業(yè)務提供任何價值,那么你可能不應該首先考慮他。

如果你 確實 想開始使用服務器端渲染,請先閱讀應用程序的架構(gòu)。大多數(shù) JavaScript 框架都有關(guān)于 SSR 的深入指南。Vue.js 甚至有一個專門的 SSR 文檔網(wǎng)站,解釋了諸如數(shù)據(jù)獲取和管理用于服務器端渲染的應用程序方面的坑。

如果可能,請使用經(jīng)過實戰(zhàn)檢驗的解決方案

有許多經(jīng)過實戰(zhàn)檢驗的解決方案,能提供很好的 SSR 開發(fā)體驗。比如,如果你在構(gòu)建 React 應用,可以使用 Next.js,或者你更青睞于 Vue?則可用 Nuxt.js,這些都是很引人注目的項目。

還不夠?嘗試 PHP 服務端渲染

你僅能以有限的資源來管理基礎(chǔ)架構(gòu)上的復雜性。你想將服務端渲染作為大型 PHP 應用中的一部分。你不想構(gòu)建和維護無狀態(tài)的 API。 如果這些原因和你的情況吻合,那么使用 PHP 進行服務端渲染將會是個不錯方案。

我已經(jīng)發(fā)布兩個庫來支持 PHP 的服務端 JavaScript 渲染: ?spatie/server-side-rendering? 和專為 Laravel 應用打造的 spatie/laravel-server-side-rendering??。Laravel 定制版在 Laravel 應用中近乎 0 配置即可投入使用,通用版需要根據(jù)運行環(huán)境做一些設(shè)置調(diào)整。當然,詳細內(nèi)容可以參考軟件包自述文件。

如果你僅是想體驗,從 spatie/laravel-server-side-rendering-examples? 檢出項目并參考指南進行安裝。

如果你考慮服務端渲染,我希望這類軟件包可以幫到你,并期待通過 Github 做進一步問題交流和反饋!

更多現(xiàn)代化 PHP 知識,請前往 Laravel / PHP 知識社區(qū)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/28506.html

相關(guān)文章

  • 服務渲染之Nuxt(介紹篇)

    摘要:為了解決問題,推出了服務端預渲染,以便提高對優(yōu)化。應用,到了,單頁面應用優(yōu)秀的用戶體驗,逐漸成為了主流,頁面整體式渲染出來的,稱之為客戶端渲染。客戶端接收數(shù)據(jù),然后完成最終渲染。通過對客戶端服務端基礎(chǔ)框架的抽象組織,主要關(guān)注的是應用的渲染。 現(xiàn)在前端開發(fā)一般都是前后端分離,mvvm和mvc的開發(fā)框架,如Angular、React和Vue等,雖然寫框架能夠使我們快速的完成開發(fā),但是由于前...

    Shonim 評論0 收藏0
  • vue服務渲染demo將vue-cli生成項目轉(zhuǎn)為ssr

    摘要:無需使用服務器實時動態(tài)編譯,而是使用預渲染方式,在構(gòu)建時簡單地生成針對特定路由的靜態(tài)文件。與可以部署在任何靜態(tài)文件服務器上的完全靜態(tài)單頁面應用程序不同,服務器渲染應用程序,需要處于運行環(huán)境。更多的服務器端負載。 目錄結(jié)構(gòu) -no-ssr-demo 未做ssr之前的項目代碼用于對比 -vuecli2ssr 將vuecli生成的項目轉(zhuǎn)為ssr -prerender-demo 使用prer...

    whinc 評論0 收藏0
  • Vue.js SSR 內(nèi)容總結(jié)

    摘要:本文只是對官方文檔和對官方的個人學習總結(jié),說得不夠完整的請見諒本文主要對以下幾方面內(nèi)容對的內(nèi)容進行分析總結(jié)出現(xiàn)的原因的總體原理當中的數(shù)據(jù)預取在編寫代碼時候的限制的構(gòu)建原理出現(xiàn)的原因單頁應用有一個很大的缺點就是問題,搜索引擎目前只能對同步的進 本文只是對Vue.js官方SSR文檔和對官方hackernews demo的個人學習總結(jié),說得不夠完整的請見諒 本文主要對以下幾方面內(nèi)容對Vue....

    曹金海 評論0 收藏0
  • Vue 服務渲染實踐 ——Web應用首屏耗時最優(yōu)化方案

    摘要:好在后是支持服務端渲染的,零零散散花費了兩三周事件,通過改造現(xiàn)有項目,基本完成了在現(xiàn)有項目中實踐了服務端渲染。在服務端生成對應的字符串,客戶端接收到對應的字符串,能立即渲染,最高效的首屏耗時。服務端渲染的原理是虛擬。實現(xiàn)前后端同構(gòu)應用。 隨著各大前端框架的誕生和演變,SPA開始流行,單頁面應用的優(yōu)勢在于可以不重新加載整個頁面的情況下,通過ajax和服務器通信,實現(xiàn)整個Web應用拒不更新...

    terasum 評論0 收藏0
  • Vue.js 服務渲染業(yè)務入門實踐

    摘要:說起,其實早在出現(xiàn)之前,網(wǎng)頁就是在服務端渲染的。沒有涉及流式渲染組件緩存對的服務端渲染有更深一步的認識,實際在生產(chǎn)環(huán)境中的應用可能還需要考慮很多因素。選擇的服務端渲染方案,是情理之中的選擇,不是對新技術(shù)的盲目追捧,而是一切為了需要。 作者:威威(滬江前端開發(fā)工程師)本文原創(chuàng),轉(zhuǎn)載請注明作者及出處。 背景 最近, 產(chǎn)品同學一如往常笑嘻嘻的遞來需求文檔, 縱使內(nèi)心萬般拒絕, 身體倒是很誠實...

    miya 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<