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

資訊專欄INFORMATION COLUMN

vue 博客優化,服務端渲染(SSR)指南

Mr_houzi / 2444人閱讀

摘要:現在我們需要在服務端和瀏覽器之間開啟一個中間層用于服務端渲染。問題設置的配置文件這樣我們的層才能獲取到的,并在客戶端將登陸時將保存下來,同時返回給客戶端。這樣用戶在刷新頁面時,會通過并帶上請求服務器獲取數據。

vue 博客優化,服務端渲染(SSR)指南 對已有的單頁應用進行改造,優化,使之成為一個具有良好seo的應用

github地址
WdBly博客地址

安裝
git clone https://github.com/WdBly/my-blog-WdBly.git
服務端配置:
cd server && composer install
配置.env文件 包含了SESSION_DOMAIN APP_KEY DATABASE的相關信息
配置目錄權限
配置nginx 參考下方配置
客戶端配置
cd web && npm install
npm run build-client && npm run build-server
啟動客戶端
node ssr
后臺啟動 需要pm2
npm install pm2 -g
pm2 start ssr

優化進度

[x] webpack開啟vendor分包,壓縮代碼,異步路由組件

[x] nginx gzip

[x] 服務端渲染

[x] cookie轉發

[x] 圖片cdn

[x] 部分https

Vue 項目改造 - 服務端渲染

幾個問題:使用服務端渲染解決了什么問題?,技術上如何實現? 經過服務端渲染改造的項目和改造前的單頁的區別?

場景:已有基于vue-cli的單頁博客項目,前端使用 vue+vue-router+vuex+axios+elementui+webpack,后臺使用laravel + mysql
,服務器阿里云 Ubuntu 16.04,web服務器nginx。

面臨的問題。1:單頁應用首屏加載過慢;2:無法被搜索引擎抓取;3:首屏白屏時間過長(重要);

解決一:首屏加載過慢。
經過分析,頁面首屏慢主要是首次需要加載的js文件過大。

1:對webpack打包過程進行優化,采用多入口將項目的vender依賴分割,對不需要變動的文件做緩存,同時對路由做異步加載。

    //多個入口
    entry: {
        "app": path.join(projectRoot, "entry-client.js"),
        "vendor": ["vue", "vue-router", "vuex", "element-ui"]
    }

    //對多入口的文件 多帶帶打包 并且不開啟hash保證緩存
    new webpack.optimize.CommonsChunkPlugin({
        name: "vendor",
        filename: "client/[name].bundle.js",
    })

    //js壓縮 縮減文件大小
    new UglifyJsPlugin({
        uglifyOptions: {
            compress: {
                warnings: false
            }
        },
        sourceMap: true,
        parallel: true
    })

    //異步的路由 使得首屏加載的代碼盡量小
    const Home = ()=> import("@/components/Home.vue");

2:服務端nginx開啟gzip壓縮

 gzip on;
 gzip_disable "msie6";
 gzip_vary on;
 gzip_proxied any;
 gzip_comp_level 6;
 gzip_buffers 16 8k;
 gzip_http_version 1.1;
 gzip_types text/plain text/css application/json application/javascript 
 text/xml application/xml application/xml+rss text/javascript;
經過驗證 開啟gzip壓縮的js文件大小大概能縮減為源文件的1/5

通過前面兩部的優化,首屏加載快了不少,但還是有點慢。

解決二三:SEO和白屏的處理

開啟服務端的渲染

首先我們來捋一捋實現流程,傳統的單頁應用的流程為前端將文件打包后生成了index.html文件和其他依賴文件,index.html文件中引入了一些js文件和css文件。如下:



    
        
        
        
    
    
        

nginx中配置相應的server_name和root字段,兩個路由分別對應前端頁面和后臺接口。

//前端頁面的路由
server {
    root /www/wwwroot/myblog-WdBly/web/dist
    server_name www.wddsss.com
    ...
}
//后臺接口路由
server {
    root /www/wwwroot/myblog-WdBly/server/public
    server_name api.wddsss.com
    ...
}

用戶訪問前端路由www.wddsss.com時 會返回dist目錄下的index.html文件給瀏覽器。剩下的所有工作都由瀏覽器完成。

現在我們需要在nginx服務端和瀏覽器之間開啟一個node中間層用于服務端渲染。

理想狀態是 當用戶訪問 www.wddsss.com時,nginx通過proxy_pass將訪問流量代理到node中間層監聽的端口,而不是直接返回一個index.html文件,nginx將后面的返回頁面的工作交給了node。nginx代理配置:

//node監聽了 5006端口,注意我們并不對外部暴露5006端口,也就是說通過
//www.wddsss.com:5006的訪問是會失敗的。

upstream z.com {
   server 127.0.0.1:5006;
}

//proxy_pass 將訪問轉移到 127.0.0.1:5006
server {
    server_name www.wddsss.com;
    access_log  /var/log/nginx/blog.api.access.log;
    error_log  /var/log/nginx/blog.api.error.log;
    location / {
        proxy_pass http://z.com;
    }
}

現在的任務清晰了不少,我們需要開啟一個node服務,監聽一個端口,當有用戶訪問的時候完成一大波事情,最后需要返回一個充滿數據的html文件。

那么我們開始實現這個任務吧!,首先分析,用戶訪問www.wddsss.com/app/home這個路由時,我們在node中監聽到訪問,必然需要將此路由對應的組件,以及組件中需要的數據獲取并整合形成html文件。

vue-server-renderer 提供了一個renderToString方法,此方法接受一個Vue組件,返回一段對應的html代碼。這不就解決了我們的問題嘛。

重新整理思路,node在監聽到某個路由被訪問時,會去查找前端路由表,并找到對應的組件。對于某些需要ssr的組件,我們手動為其添加了一個asyncData()方法,在node加載這些組件同時會去執行asyncData()方法,拿到組件內的數據渲染到組件中。最后將這個組件傳入renderToString方法。這樣一個簡陋無比的ssr就做好了!部分代碼如下(刪減版,完整的請前往github查看)

const { createRenderer } = require("vue-server-renderer")
const createApp = require("./dist/bundle.server.js")["default"]
const renderer = createRenderer({
    template: require("fs").readFileSync("ssr/view/index.template.html", "utf-8")
})
const data = {
  script: `
    
    
  `,
  state: ``
}

express.get("*", (req, res) => {

    const context = {url: req.url};
    
    createApp(context).then(app => {
        var state = JSON.stringify(context.state);

        data.state =  ``
    
        renderer.renderToString(app, data, (err, html) => {
        res.end(html)
        })
    })
})

1:我們可以看到createRenderer方法可以接受一個html模板文件,因為renderToString方法最終生成的html片段時不帶head頭等內容的,需要我們自定義一個模板,將renderToString方法生成的html插入到次模板html文件即可。
2:createApp變量來自一個bundle.server.js,這個js文件是通過特定的配置對項目打包后生成的入口文件,它接受一個context用于根據路由尋找對應組件并將最終的state添加至context,后面會說到。
3:createApp本身是一個異步過程,因為在這個函數中可能會存在數據的獲取,當數據獲取且組件加載完畢后,執行then中的renderToString,renderToString的第二個data參數即是傳入模板html文件的參數。

webpack.server.js部分配置

    target: "node",
    entry: [path.join(projectRoot, "entry-server.js")],
    output: {
        libraryTarget: "commonjs2",
        path: path.join(projectRoot, "dist"),
        filename: "bundle.server.js",
        chunkFilename: "[name].bundle.js",
        publicPath: "/"
    }

這個比較簡陋的ssr存在很多問題,主要是客戶端拿到的只是一個多帶帶的html頁面其中,我們綁定的事件,統統是不生效的。

正確的流程是當客戶端拿到首屏渲染好的頁面時,會在瀏覽器后臺執行一次重繪,生成一系列的虛擬Node,并且和從服務端獲取的真實dom節點進行比對,若是不匹配,會執行重繪(使用瀏覽器端生成的頁面),而瀏覽器在后臺生成虛擬Node依賴于頁面中的數據,而我們又不可能在瀏覽器再次發送ajax請求來獲取頁面數據(浪費),所有在上方代碼中我們可以看到window.__INITIAL_STATE__這一句,當服務端獲取到組件的數據時,會將state放在script標簽的一個變量中,在客戶端執行重繪時采用的即是這里的數據。

具體過程參考下圖:

在整個過程中產生的一些問題總結

element-ui樣式丟失問題。

在 app.js 中我們引入了 "element-ui/lib/theme-chalk/index.css"的css文件,我們必須要清楚 app.js本身會在服務端執行,所以我們必須在webpack.server.js中配置處理css文件的loader

    {
        test:/.css$/,
        use:["vue-style-loader", "css-loader"],
    }
區分是當前執行環境時node還是瀏覽器

因為我們的項目是要在服務端執行,同時也會在客戶端執行,到時服務端不支持某些客戶端對象 如window對象,所以在我們的代碼中如果有使用到window,document等瀏覽器API的地方需要對當前的執行環境進行判斷
我們使用的方式是webpack的插件

       new webpack.DefinePlugin({
            "process.env.VUE_ENV": ""client"",
            "process.env.NODE_ENV": ""production"",
       }),
       new webpack.DefinePlugin({
            "process.env.VUE_ENV": ""server"",
            "process.env.NODE_ENV": ""production"",
       }),
某些頁面與用戶是否登陸相關

對于某些頁面,我們可能會在頁面中顯示當前登陸用戶的信息,并將這個信息存入了localStorage中,但結合上個問題我們可以看出來,在服務端渲染中我們并不能獲取到這個localStorage這個對象。那么最終渲染出的頁面在和瀏覽器重繪的頁面進行對比時必然會出現不匹配的錯誤。
處理方法,在node層為登陸用戶設置cookie,當用戶請求時,若是判斷出當前的執行環境為node,則從cookie中讀取信息載入頁面,否則從localStorage讀取數據。

兩次渲染不匹配問題

除了上述情況可能導致兩個渲染不匹配,還有從服務端返給客戶端的__INITIAL_STATE__不存在或者__INITIAL_STATE__的內容有誤時,都會導致客戶端獲取不到初始__INITIAL_STATE__而發生不匹配的錯誤(這里__INITIAL_STATE__不存在的情況有很多種),
1:若是直接將 做為參數傳入index.template.html,那么需要使用{{{ }}}的語法解析。
2:在index.template.html 引入state的標簽需要在引入build.client.js的標簽之前引入,因為build.client.js需要依賴初始state。
3:若是state中存在標簽(比如mackdown語法生成的dom結構)需要使用不轉義插值{{{}}}。
4: 若是state中有某些特殊字符 :: 回車等特殊字符,需要使用{{}}進行轉移,否則在渲染頁面時這部分state會直接跑到頁面上去。

cookie問題

laravel設置的cookie配置 .env 文件 SESSION_DOMAIN=.wddsss.com
這樣我們的node層(www.wddsss.com)才能獲取到laravel的cookie,并在客戶端將登陸時將cookie保存下來,同時返回給客戶端。這樣用戶在刷新頁面時,node會通過axios并帶上cookie請求nginx服務器獲取數據。

圖片走七牛cdn

我們的首頁圖片加載可以明細看到很慢(畢竟1M的小服務器),開啟七牛cdn,具體流程就不說了,使用的是laravel itbdw/laravel-storage-qiniu包。

開啟https

到這個時候我們發現網站被標記為不安全了,https走一波,推薦一個免費證書申請機構。

certbot證書申請

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/40193.html

相關文章

  • vue 博客優化服務渲染(SSR)指南

    摘要:現在我們需要在服務端和瀏覽器之間開啟一個中間層用于服務端渲染。問題設置的配置文件這樣我們的層才能獲取到的,并在客戶端將登陸時將保存下來,同時返回給客戶端。這樣用戶在刷新頁面時,會通過并帶上請求服務器獲取數據。 vue 博客優化,服務端渲染(SSR)指南 對已有的單頁應用進行改造,優化,使之成為一個具有良好seo的應用 github地址WdBly博客地址 安裝 git clone htt...

    KnewOne 評論0 收藏0
  • vue搭建的個人博客介紹----mapblog小站

    摘要:后端主要使用的框架,數據庫采用。后臺管理登錄采用與后端進行登陸狀態的確認。本文首發于小站,這是一個積累和分享知識的個人博客 這篇文章擱置了很長時間,最終決定還是把它寫出來,給剛開始學習vue并且想用vue寫個人博客的同學一個參考。因為當初我也是參考了其他人分享的知識,從一個vue小白變成了一個入門級選手,并最終完成了這個個人博客的搭建工作,代碼已托管在Github-justJokee。...

    Ashin 評論0 收藏0
  • 使用 PHP 來做 Vue.js 的 SSR 服務渲染

    摘要:對于客戶端應用來說,服務端渲染是一個熱門話題。在服務器預渲染初始應用狀態。重構這段腳本,使其可以在服務端運行。如果這些原因和你的情況吻合,那么使用進行服務端渲染將會是個不錯方案。我已經發布兩個庫來支持的服務端渲染和專為應用打造的。 showImg(https://segmentfault.com/img/remote/1460000014155032);對于客戶端應用來說,服務端渲染是...

    李增田 評論0 收藏0
  • 每周清單第 11 期:Angular 4.1支持TypeScript 2.3,Vue 2.3優化

    摘要:斯坦福宣布使用作為計算機課程的首選語言近日,某位有年教學經驗的斯坦福教授決定放棄,而使用作為計算機入門課程的教學語言。斯坦福官方站點將它們新的課程描述為是最流行的構建交互式的開發語言,本課程會用講解中的實例。 前端每周清單第 11 期:Angular 4.1支持TypeScript 2.3,Vue 2.3優化服務端渲染,優秀React界面框架合集 為InfoQ中文站特供稿件,首發地址為...

    warkiz 評論0 收藏0

發表評論

0條評論

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