成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

使用 PHP 來(lái)做 Vue.js 的 SSR 服務(wù)端渲染

李增田 / 1861人閱讀

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


對(duì)于客戶端應(yīng)用來(lái)說(shuō),服務(wù)端渲染是一個(gè)熱門話題。然而不幸的是,這并不是一件容易的事,尤其是對(duì)于不用 Node.js 環(huán)境開發(fā)的人來(lái)說(shuō)。

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

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

什么是服務(wù)端渲染

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

瀏覽器的工作

在 SPA 被啟動(dòng)并準(zhǔn)備使用之前,瀏覽器需要經(jīng)過(guò)幾個(gè)步驟。

下載 JavaScript 腳本

解析 JavaScript 腳本

運(yùn)行 JavaScript 腳本

取回?cái)?shù)據(jù)(可選,但普遍)

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

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

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

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

渲染來(lái)自服務(wù)端的 HTML (首次有意義的渲染)

下載 JavaScript 腳本

解析 JavaScript 腳本

運(yùn)行 JavaScript 腳本

取回?cái)?shù)據(jù)

使已存在的 HTML 頁(yè)面可交互

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

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

服務(wù)端渲染的優(yōu)點(diǎn)

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

服務(wù)端如何渲染?

記住服務(wù)端渲染并非微不足道,這一點(diǎn)很重要。當(dāng)你的 Web 應(yīng)用同時(shí)運(yùn)行在瀏覽器和服務(wù)器,而你的 Web 應(yīng)用依賴 DOM 訪問(wèn),那么你需要確保這些調(diào)用不會(huì)在服務(wù)端觸發(fā),因?yàn)闆](méi)有 DOM API 可用。

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

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

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

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

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

服務(wù)器上多了一個(gè)額外的操作。一個(gè)是服務(wù)器增加了負(fù)載壓力,第二個(gè)是頁(yè)面響應(yīng)時(shí)間也會(huì)稍微加長(zhǎng)。 不過(guò)因?yàn)楝F(xiàn)在服務(wù)器返回了有效內(nèi)容,在用戶看來(lái),第二個(gè)問(wèn)題的影響不大。

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

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

在 PHP 中渲染 JavaScript

在服務(wù)器端渲染 SPA 需要集齊以下三樣?xùn)|西:

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

一個(gè)可以在服務(wù)器上渲染應(yīng)用的腳本

一個(gè)可以在客戶端渲染和運(yùn)行應(yīng)用的腳本

SSR scripts 101

下面的例子使用了 Vue.js。你如果習(xí)慣使用其它的框架(例如 React),不必?fù)?dān)心,它們的核心思想都是類似的,一切看起來(lái)都是那么相似。

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

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

// app.js
import Vue from "vue"

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

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

如果在服務(wù)端運(yùn)行這點(diǎn)腳本,會(huì)拋出錯(cuò)誤,因?yàn)闆](méi)有 DOM 可訪問(wèn),而 Vue 卻嘗試在一個(gè)不存在的元素里渲染應(yīng)用。

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

// 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)建應(yīng)用實(shí)例的工廠,而第二部分,即 entry-client.js,會(huì)運(yùn)行在瀏覽器,它使用工廠創(chuàng)建了應(yīng)用實(shí)例,并且掛載在 DOM。

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

// 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...
})

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

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

執(zhí)行 JavaScript

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

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

$v8 = new V8Js();

ob_start();

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

$v8->executeString($script);

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

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

這個(gè)不一樣的方法就是使用 Node.js 運(yùn)行 JavaScript。我們可以開啟一個(gè) Node 進(jìn)程,它負(fù)責(zé)運(yùn)行腳本并且捕獲輸出。
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 。

讓我們一起來(lái)實(shí)現(xiàn)它吧!

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

namespace SpatieSsr;

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

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

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

namespace SpatieSsrEngines;

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

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

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

    /**
     * 打開緩沖區(qū)。
     * 返回緩沖區(qū)存儲(chǔ)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 引擎會(huì)更加復(fù)雜一點(diǎn)。不像 V8Js,Node 需要?文件?去執(zhí)行,而不是腳本內(nèi)容。在執(zhí)行一個(gè)服務(wù)端腳本前,它需要被保存到一個(gè)臨時(shí)的路徑。

namespace SpatieSsrEngines;

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

/**
 * 創(chuàng)建一個(gè) Node 類來(lái)實(shí)現(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
    {
        // 生成一個(gè)隨機(jī)的、獨(dú)一無(wú)二的臨時(shí)文件路徑。
        $tempFilePath = $this->createTempFilePath();

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

        // 創(chuàng)建進(jìn)程執(zhí)行臨時(shí)文件。
        $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";
    }
}

除了臨時(shí)路徑步驟之外,實(shí)現(xiàn)方法看起來(lái)也是相當(dāng)直截了當(dāng)。

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

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

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

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

我們的應(yīng)用腳本文件;

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

一個(gè)簡(jiǎn)單的 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 需要在服務(wù)器腳本加載前運(yùn)行。

還記得我們的服務(wù)器端入口腳本嗎?接下來(lái)我們?cè)诖四_本中調(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 的應(yīng)用腳本無(wú)需特殊處理,只需要使用 ?file_get_contents 方法讀取文件即可。

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

三思而后行

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

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

如果可能,請(qǐng)使用經(jīng)過(guò)實(shí)戰(zhàn)檢驗(yàn)的解決方案

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

還不夠?嘗試 PHP 服務(wù)端渲染

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

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

如果你僅是想體驗(yàn),從 spatie/laravel-server-side-rendering-examples? 檢出項(xiàng)目并參考指南進(jìn)行安裝。

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

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

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/28506.html

相關(guān)文章

  • 服務(wù)預(yù)渲染之Nuxt(介紹篇)

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

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

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

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

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

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

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

    terasum 評(píng)論0 收藏0
  • Vue.js 服務(wù)渲染業(yè)務(wù)入門實(shí)踐

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

    miya 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<