Rumah  >  Artikel  >  hujung hadapan web  >  Apakah SSR? Bagaimana untuk melaksanakan pemaparan sisi pelayan SSR dalam vue?

Apakah SSR? Bagaimana untuk melaksanakan pemaparan sisi pelayan SSR dalam vue?

青灯夜游
青灯夜游ke hadapan
2022-02-25 11:23:535029semak imbas

Apakah itu SSR? Artikel berikut akan memperkenalkan kepada anda kaedah melaksanakan pemaparan sisi pelayan SSR dalam vue saya harap ia akan membantu anda!

Apakah SSR? Bagaimana untuk melaksanakan pemaparan sisi pelayan SSR dalam vue?

1 Apakah itu SSR

Server-Side Rendering Kami memanggilnya SSR, yang bermaksud pemaparan sebelah pelayan

merujuk kepada teknologi pemprosesan halaman yang melengkapkan HTML penyambungan struktur halaman pada bahagian pelayan, menghantarnya ke penyemak imbas, dan kemudian mengikat status dan acara kepadanya untuk menjadi halaman interaktif sepenuhnya. [Cadangan berkaitan: tutorial video vuejs]

Mari kita lihat dahulu sejarah pembangunan 3 peringkat Web:

  • Pelayan tradisional- SSR pemaparan sisi
  • SPA aplikasi halaman tunggal
  • SSR pemaparan sisi pelayan

Pembangunan web tradisional

Halaman web kandungan dipaparkan pada bahagian pelayan ⼀Pindahkan ke penyemak imbas pada satu masa

Apakah SSR? Bagaimana untuk melaksanakan pemaparan sisi pelayan SSR dalam vue?

Buka halaman untuk melihat kod sumber yang diperolehi oleh penyemak imbas ialah keseluruhan dom struktur

SPA Aplikasi satu halaman

Pengalaman pengguna yang sangat baik bagi aplikasi satu halaman secara beransur-ansur menjadikan ia menjadi arus perdana Kandungan halaman dipaparkan oleh JS Ini kaedah dipanggil pemaparan sisi klien

Apakah SSR? Bagaimana untuk melaksanakan pemaparan sisi pelayan SSR dalam vue?

Buka halaman untuk melihat kod sumber Penyemak imbas hanya mendapat elemen hos #app dan tiada kandungan

SSR pemaparan bahagian pelayan

SSR Penyelesaian: Bahagian belakang memaparkan struktur dom lengkap skrin pertama dan mengembalikannya Kandungan yang diperolehi bahagian hadapan termasuk skrin pertama dan struktur spa yang lengkap Selepas aplikasi diaktifkan, ia masih berjalan dalam mod spa

Apakah SSR? Bagaimana untuk melaksanakan pemaparan sisi pelayan SSR dalam vue?

Selepas melihat pembangunan bahagian hadapan, mari kita lihat penjelasan rasmi Vue tentang SSR:

Vue.js digunakan untuk membina bingkai aplikasi klien. Secara lalai, komponen Vue boleh dikeluarkan dalam penyemak imbas untuk menjana DOM dan memanipulasi DOM. Walau bagaimanapun, anda juga boleh membuat komponen yang sama seperti rentetan HTML sebelah pelayan, menghantarnya terus ke penyemak imbas, dan akhirnya "mengaktifkan" teg statik ini sebagai aplikasi interaktif sepenuhnya pada klien

Rendering Pelayan A Aplikasi Vue.js juga boleh dianggap "isomorphic" atau "universal" kerana kebanyakan kod aplikasi boleh dijalankan pada kedua-dua pelayan dan klien

Kami mendapatkannya dari Laman Utama Diterangkan Kesimpulan berikut:

  • Vue SSR ialah pemaparan sisi pelayan yang dipertingkatkan pada SPA halaman yang dipaparkan melalui
  • perlu diaktifkan pada klien untuk mencapai interaksi
  • Vue SSR akan mengandungi dua bahagian: skrin pertama yang diberikan oleh pelayan, termasuk interaktif
  • Vue SSRSPA
  • 2. Perkara yang telah diselesaikan

SSR terutamanya menyelesaikan dua masalah berikut:

seo: Enjin carian mengutamakan merangkak halaman

struktur Apabila menggunakan
    , pelayan telah menjana kandungan yang berkaitan dengan perniagaan .
  • , yang sesuai untuk HTMLssrHTML pemaparan skrin pertama: pengguna boleh melihat paparan halaman tanpa menunggu semua seo halaman dimuatkan (tekanan datang kepada pelayan, jadi adalah perlu untuk menimbang sama ada untuk menggunakan rendering sisi pelayan , yang diserahkan kepada pelanggan)
  • jsTetapi menggunakan
  • juga mempunyai kelemahan berikut:

SSR

Kerumitan: kerumitan keseluruhan projek
  • Sokongan perpustakaan, keserasian kod
  • Isu prestasi
  • Setiap permintaan adalah untuk

    contoh Buat, jika tidak, ia akan tercemar, dan penggunaan akan menjadi sangat besar
    • Cache n,
    • x menentukan sama ada pengguna semasa telah tamat tempoh, jika tidak , cache dan gunakan hasilnya tadi.
    • node serve Turun taraf: Monitor ngin, penggunaan memori terlalu banyak, cuma
    • , kembalikan satu shell
    • cpuspa
    Beban pelayan menjadi lebih besar, berbanding dengan sebelum dan selepas Jika pelanggan hanya perlu menyediakan sumber statik kepada pelayan, beban pelayan akan lebih besar, jadi kita harus menggunakannya dengan berhati-hati
  • Jadi sebelum kita memilih sama ada untuk menggunakan
  • , kita perlu bertanya kepada diri sendiri dengan teliti Soalan-soalan ini:

SSR

Adakah terdapat hanya beberapa halaman yang memerlukan
    Bolehkah ini dicapai menggunakan prapemarahan (Prerender SPA Plugin)
  • SEO

    Adakah logik tindak balas permintaan pada kompleks skrin pertama dan sama ada pengembalian data adalah besar dan perlahan?
  • 3 melaksanakan

Untuk pembangunan isomorfik, kami Masih menggunakan pembungkusan , kami perlu menyelesaikan dua masalah: pemaparan skrin pertama sebelah pelayan dan pengaktifan sebelah pelanggan

Di sini anda perlu menjana fail pelayan bundle untuk pemaparan skrin pertama pelayan dan fail bundle klien untuk pengaktifan klien

Apakah SSR? Bagaimana untuk melaksanakan pemaparan sisi pelayan SSR dalam vue?

Sebagai tambahan kepada struktur kod Kecuali untuk dua pintu masuk yang berbeza, struktur lain adalah sama seperti aplikasi vue sebelumnya

src 
├── router 
├────── index.js # 路由声明 
├── store 
├────── index.js # 全局状态 
├── main.js # ⽤于创建vue实例 
├── entry-client.js # 客户端⼊⼝,⽤于静态内容“激活” 
└── entry-server.js # 服务端⼊⼝,⽤于⾸屏内容渲染

konfigurasi penghalaan

import Vue from "vue"; import Router from "vue-router"; Vue.use(Router);
//导出⼯⼚函数
export function createRouter(){
    return new Router({
    mode: 'history',
    routes: [ 
       // 客户端没有编译器,这⾥要写成渲染函数 
        { path: "/", component: { render: h => h('div', 'index page') } }, 
        { path: "/detail", component: { render: h => h('div', 'detail page') }} 
    ] 
  });
 }

fail utama main.js

adalah sama seperti sebelum Berbeza, fail utama adalah kilang yang bertanggungjawab untuk mencipta contoh vue Setiap permintaan akan mempunyai penciptaan contoh vue bebas

import Vue from "vue";
import App from "./App.vue";
import { createRouter } from "./router"; 
// 导出Vue实例⼯⼚函数,为每次请求创建独⽴实例 
// 上下⽂⽤于给vue实例传递参数
export function createApp(context) {
    const router = createRouter();
    const app = new Vue({ router, context, render: h => h(App) });
    return { app, router };
  }

Tulis entri pelayan src/entry-server.js.

ia Tugasnya adalah untuk mencipta contoh Vue dan menulis portal pelanggan berdasarkan url masuk dengan menyatakan skrin pertama

import { createApp } from "./main";
// 返回⼀个函数,接收请求上下⽂,返回创建的vue实例
export default context => {
// 这⾥返回⼀个Promise,确保路由或组件准备就绪
    return new Promise((resolve, reject) => {
        const { app, router } = createApp(context);
        // 跳转到⾸屏的地址
        router.push(context.url);
        // 路由就绪,返回结果
        router.onReady(() => {
        resolve(app);
        }, reject);
    }); 
};

entry-client.js

Portal pelanggan hanya perlu mencipta contoh vue Dan laksanakan pelekap, langkah ini dipanggil pengaktifan

import { createApp } from "./main"; 
// 创建vue、router实例
const { app, router } = createApp();
// 路由就绪,执⾏挂载
router.onReady(() => { app.$mount("#app"); });

Konfigurasikanwebpack

Pasang kebergantungan

npm install webpack-node-externals lodash.merge -D

Ya vue.config.jsKonfigurasikan

// 两个插件分别负责打包客户端和服务端
const VueSSRServerPlugin = require("vue-server-renderer/server-plugin");
const VueSSRClientPlugin = require("vue-server-renderer/client-plugin");
const nodeExternals = require("webpack-node-externals");
const merge = require("lodash.merge");
// 根据传⼊环境变量决定⼊⼝⽂件和相应配置项
const TARGET_NODE = process.env.WEBPACK_TARGET === "node";
const target = TARGET_NODE ? "server" : "client";
module.exports = {
    css: {
        extract: false
    },
    outputDir: './dist/'+target,
    configureWebpack: () => ({
        // 将 entry 指向应⽤程序的 server / client ⽂件
        entry: `./src/entry-${target}.js`,
        // 对 bundle renderer 提供 source map ⽀持
        devtool: 'source-map',
        // target设置为node使webpack以Node适⽤的⽅式处理动态导⼊,
        // 并且还会在编译Vue组件时告知`vue-loader`输出⾯向服务器代码。
        target: TARGET_NODE ? "node" : "web",
        // 是否模拟node全局变量
        node: TARGET_NODE ? undefined : false,
        output: {
            // 此处使⽤Node⻛格导出模块
            libraryTarget: TARGET_NODE ? "commonjs2" : undefined
        },
        // https://webpack.js.org/configuration/externals/#function
        // https://github.com/liady/webpack-node-externals
        // 外置化应⽤程序依赖模块。可以使服务器构建速度更快,并⽣成较⼩的打包⽂件。
        externals: TARGET_NODE
        ? nodeExternals({
            // 不要外置化webpack需要处理的依赖模块。
            // 可以在这⾥添加更多的⽂件类型。例如,未处理 *.vue 原始⽂件,
            // 还应该将修改`global`(例如polyfill)的依赖模块列⼊⽩名单
            whitelist: [/\.css$/]
        })
        : undefined,
        optimization: {
            splitChunks: undefined
        },
        // 这是将服务器的整个输出构建为单个 JSON ⽂件的插件。
        // 服务端默认⽂件名为 `vue-ssr-server-bundle.json`
        // 客户端默认⽂件名为 `vue-ssr-client-manifest.json`。
        plugins: [TARGET_NODE ? new VueSSRServerPlugin() : new
                  VueSSRClientPlugin()]
    }),
    chainWebpack: config => {
        // cli4项⽬添加
        if (TARGET_NODE) {
            config.optimization.delete('splitChunks')
        }

        config.module
            .rule("vue")
            .use("vue-loader")
            .tap(options => {
            merge(options, {
                optimizeSSR: false
            });
        });
    }
};

Konfigurasikan skrip dan pasang kebergantungan

npm i cross-env -D

"scripts": {
 "build:client": "vue-cli-service build",
 "build:server": "cross-env WEBPACK_TARGET=node vue-cli-service build",
 "build": "npm run build:server && npm run build:client"
}

Laksanakan pembungkusan: npm run build

Fail hos terakhir diubah suai/public/index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width,initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <!--vue-ssr-outlet-->
    </body>
</html>

ialah lokasi kemasukan pemaparan sebelah pelayan Berhati-hati untuk tidak menambah ruang sebelum dan selepasnya untuk demi penampilan.

vuex pelayan dalam fail

Paparan sisi ialah "gambar" aplikasi Jika aplikasi bergantung pada beberapa data tak segerak, maka sebelum memulakan pemaparan, data ini perlu diambil terlebih dahulu. dan dihuraikan

npm install -S vuexLakukan pemerolehan data satu langkah dalam

vuex

Logik praambil data dalam komponen
import Vue from &#39;vue&#39;
import Vuex from &#39;vuex&#39;
Vue.use(Vuex)
export function createStore () {
    return new Vuex.Store({
        state: {
            count:108
        },
        mutations: {
            add(state){
                state.count += 1;
            }
        }
    })
}

main.jsPrafetching data sisi pelayan, store

import { createStore } from &#39;./store&#39;
export function createApp (context) {
    // 创建实例
    const store = createStore()
    const app = new Vue({
        store, // 挂载
        render: h => h(App)
    })
    return { app, router, store }
}

Klien dipasang pada aplikasi Sebelum ini,

sepatutnya mendapat status,

store

export function createStore() {
    return new Vuex.Store({
        mutations: {
            // 加⼀个初始化
            init(state, count) {
                state.count = count;
            },
        },
        actions: {
            // 加⼀个异步请求count的action
            getCount({ commit }) {
                return new Promise(resolve => {
                    setTimeout(() => {
                        commit("init", Math.random() * 100);
                        resolve();
                    }, 1000);
                });
            },
        },
    });
}
pemprosesan prafetch data pelanggan,

export default {
    asyncData({ store, route }) { // 约定预取逻辑编写在预取钩⼦asyncData中
        // 触发 action 后,返回 Promise 以便确定请求结果
        return store.dispatch("getCount");
    }
};

ubah suai fail permulaan pelayanentry-server.js

import { createApp } from "./app";
export default context => {
    return new Promise((resolve, reject) => {
        // 拿出store和router实例
        const { app, router, store } = createApp(context);
        router.push(context.url);
        router.onReady(() => {
            // 获取匹配的路由组件数组
            const matchedComponents = router.getMatchedComponents();

            // 若⽆匹配则抛出异常
            if (!matchedComponents.length) {
                return reject({ code: 404 });
            }

            // 对所有匹配的路由组件调⽤可能存在的`asyncData()`
            Promise.all(
                matchedComponents.map(Component => {
                    if (Component.asyncData) {
                        return Component.asyncData({
                            store,
                            route: router.currentRoute,
                        });
                    }
                }),
            )
                .then(() => {
                // 所有预取钩⼦ resolve 后,
                // store 已经填充⼊渲染应⽤所需状态
                // 将状态附加到上下⽂,且 `template` 选项⽤于 renderer 时,
                // 状态将⾃动序列化为 `window.__INITIAL_STATE__`,并注⼊ HTML
                context.state = store.state;

                resolve(app);
            })
                .catch(reject);
        }, reject);
    });
};

Ringkasanstoreentry-client.js

// 导出store
const { app, router, store } = createApp();
// 当使⽤ template 时,context.state 将作为 window.__INITIAL_STATE__ 状态⾃动嵌⼊到最终的 HTML 
// 在客户端挂载到应⽤程序之前,store 就应该获取到状态:
if (window.__INITIAL_STATE__) {
    store.replaceState(window.__INITIAL_STATE__);
}

Tiada mod tunggal apabila menggunakan main.js, dan contoh

baharu
Vue.mixin({
    beforeMount() {
        const { asyncData } = this.$options;
        if (asyncData) {
            // 将获取数据操作分配给 promise
            // 以便在组件中,我们可以在数据准备就绪后
            // 通过运⾏ `this.dataPromise.then(...)` 来执⾏其他任务
            this.dataPromise = asyncData({
                store: this.$store,
                route: this.$route,
            });
        }
    },
});
akan dibuat untuk setiap permintaan pengguna

// 获取⽂件路径
const resolve = dir => require(&#39;path&#39;).resolve(__dirname, dir)
// 第 1 步:开放dist/client⽬录,关闭默认下载index⻚的选项,不然到不了后⾯路由
app.use(express.static(resolve(&#39;../dist/client&#39;), {index: false}))
// 第 2 步:获得⼀个createBundleRenderer
const { createBundleRenderer } = require("vue-server-renderer");
// 第 3 步:服务端打包⽂件地址
const bundle = resolve("../dist/server/vue-ssr-server-bundle.json");
// 第 4 步:创建渲染器
const renderer = createBundleRenderer(bundle, {
    runInNewContext: false, // https://ssr.vuejs.org/zh/api/#runinnewcontext
    template: require(&#39;fs&#39;).readFileSync(resolve("../public/index.html"), "utf8"), // 宿主⽂件
    clientManifest: require(resolve("../dist/client/vue-ssr-clientmanifest.json")) // 客户端清单
});
app.get(&#39;*&#39;, async (req,res)=>{
    // 设置url和title两个重要参数
    const context = {
        title:&#39;ssr test&#39;,
        url:req.url
    }
    const html = await renderer.renderToString(context);
    res.send(html)
})
Pelaksanaan

memerlukan pemaparan skrin pertama sebelah pelayan dan pengaktifan pihak pelanggan

    Pemerolehan data tak segerak sebelah pelayan
  • boleh dibahagikan kepada pemerolehan tak segerak skrin pertama Perolehi data dengan komponen pensuisan

    ssrvue tak segerak pada skrin pertama, yang sepatutnya diselesaikan semasa pra-pemarahan sebelah pelayan

  • Komponen pensuisan dicampurkan dalam melalui
  • dan dilengkapkan dengan

    cangkuk Pemerolehan datassr

  • (Video pembelajaran perkongsian: asyncDatatutorial vuejs

    ,
      bahagian hadapan web
    • )

Atas ialah kandungan terperinci Apakah SSR? Bagaimana untuk melaksanakan pemaparan sisi pelayan SSR dalam vue?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:juejin.cn. Jika ada pelanggaran, sila hubungi admin@php.cn Padam