Warum Server-Side Rendering (SSR) verwenden?
Bei der Verwendung von Server-Side-Rendering (SSR) gibt es auch einige Kompromisse:
Verzeichnisstruktur 1. Definieren Sie Verpackungsbefehle und EntwicklungsbefehleEntwicklungsbefehle werden für die Client-Entwicklung verwendet Verpackungsbefehle werden verwendet, um serverseitige Entwicklung bereitzustellen –watch ist praktisch, um Dateien zu ändern und sie dann automatisch zu verpacken "client:build": "webpack --config scripts/webpack.client.js --watch", "Server:Build": "webpack --config scripts/webpack.server.js --watch", "run:all": "gleichzeitig \"npm run client:build\" \"npm run server:build\"" So führen Sie client:build und server:build gleichzeitig aus 1.1 Paket.json { "Name": "11.vue-ssr", "version": "1.0.0", "Beschreibung": "", "main": "index.js", "Skripte": { "client:dev": "webpack serve --config scripts/webpack.client.js", "client:build": "webpack --config scripts/webpack.client.js --watch", "Server:Build": "webpack --config scripts/webpack.server.js --watch", "run:all": "gleichzeitig \"npm run client:build\" \"npm run server:build\"" }, "Schlüsselwörter": [], "Autor": "", "Lizenz": "ISC", "Abhängigkeiten": { "gleichzeitig": "^5.3.0", "koa": "^2.13.1", "koa-router": "^10.0.0", "koa-static": "^5.0.0", "vue": "^2.6.12", "vue-router": "^3.4.9", "vue-server-renderer": "^2.6.12", "vuex": "^3.6.0", "webpack-merge": "^5.7.3" }, "devAbhängigkeiten": { "@babel/core": "^7.12.10", "@babel/preset-env": "^7.12.11", "babel-loader": "^8.2.2", "css-loader": "^5.0.1", "html-webpack-plugin": "^4.5.1", "vue-loader": "^15.9.6", "vue-style-loader": "^4.1.2", "vue-template-compiler": "^2.6.12", "webpack": "^5.13.0", "webpack-cli": "^4.3.1", "webpack-dev-server": "^3.11.2" } } 1.2 Grundkonfiguration von webpack.base.js // Die von webpack gepackte Eintragsdatei muss die Konfiguration exportieren // webpack webpack-cli // @babel/core Babels Kernmodul // Babel-Loader ist eine Brücke zwischen Webpack und Babel // @babel/preset-env konvertiert es6+ in eine Low-Level-Syntax // Vue-Loader Vue-Template-Compiler analysiert .vue-Dateien und kompiliert Vorlagen // Vue-Style-Loader CSS-Loader analysiert CSS-Stile und fügt sie in Stil-Tags ein, Vue-Style-Loader unterstützt serverseitiges Rendering const path = require('path'); const HtmlWebpackPlugin = erfordern('html-webpack-plugin'); const VueLoaderPlugin = erforderlich('vue-loader/lib/plugin') modul.exporte = { Modus: "Entwicklung", Ausgabe: { Dateiname: '[name].bundle.js', // Der Standard ist main, der Standard ist der dist-Verzeichnispfad: path.resolve(__dirname,'../dist') }, Modul: { Regeln: [{ Test: /\.vue$/, verwenden: „vue-loader“ }, { Test: /\.js$/, verwenden: { Loader: 'babel-loader', // @babel/core -> voreingestellte Umgebung Optionen: Voreinstellungen: ['@babel/preset-env'], // Sammlung von Plugins} }, exclude: /node_modules/ // gibt an, dass Dateien unter node_modules nicht durchsucht werden müssen}, { Test: /\.css$/, verwenden: ['vue-style-loader', { Lader: "CSS-Lader", Optionen: esModule: false, // Beachten Sie, dass vue-style-loader in Verbindung mit verwendet wird } }] // Von rechts nach links ausführen }] }, Plugins: [ neues VueLoaderPlugin() // Behoben] } 1.3 Die Konfiguration von webpack.client.js ist die Client-Entwicklungskonfiguration, die die normale Konfiguration des Vue Spa-Entwicklungsmodus ist const {merge} = erfordern('webpack-merge'); const base = erfordern('./webpack.base'); const Pfad = require('Pfad') const HtmlWebpackPlugin = erfordern('html-webpack-plugin') modul.exporte = merge(base,{ Eintrag: { Client:Pfad.Auflösen(__Verzeichnisname, '../src/client-entry.js') }, Plugins:[ neues HtmlWebpackPlugin({ Vorlage: Pfad.auflösen(__dirname, '../public/index.html'), Dateiname: „client.html“ // Der Standardname ist index.html }), ] }) 1.4 Die Konfiguration webpack.server.js wird nach dem Verpacken für die Serverbereitstellung verwendet const base = erfordern('./webpack.base') const {merge} = erfordern('webpack-merge'); const HtmlWebpackPlugin = erfordern('html-webpack-plugin') const Pfad = require('Pfad') modul.exporte = merge(base,{ Ziel: 'Knoten', Eintrag: { server:Pfad.auflösen(__dirname, '../src/server-entry.js') }, Ausgabe:{ libraryTarget:"commonjs2" // module.exports exportieren}, Plugins:[ neues HtmlWebpackPlugin({ Vorlage: Pfad.auflösen(__dirname, '../public/index.ssr.html'), Dateiname:'server.html', excludeChunks:['Server'], minimieren:false, Kunde: '/client.bundle.js' // Der Standardname ist index.html }), ] }) excludeChunks:['server'] importiert das Paket server.bundle.js nicht Client ist eine Variable Dateiname ist der Name der HTML-Datei, die nach dem Verpacken generiert wird. Vorlage: Vorlagendatei 2. Schreiben Sie HTML-DateienZwei Portionen: 2.1 öffentlich/index.html <!DOCTYPE html> <html lang="de"> <Kopf> <meta charset="UTF-8"> <meta name="viewport" content="width=Gerätebreite, Anfangsmaßstab=1.0"> <title>Dokument</title> </Kopf> <Text> <div id="app"></div> </body> </html> 2.2 öffentlich/index.ssr.html <!DOCTYPE html> <html lang="de"> <Kopf> <meta charset="UTF-8"> <meta name="viewport" content="width=Gerätebreite, Anfangsmaßstab=1.0"> <title>Dokument</title> </Kopf> <Text> <!--vue-ssr-outlet--> <!-- ejs-Vorlage --> <script src="<%=htmlWebpackPlugin.options.client%>"></script> </body> </html> <!--vue-ssr-outlet--> ist die feste Slot-Position, die vom Server zum Rendern des DOM verwendet wird. <%=htmlWebpackPlugin.options.client%> füllt die Variablen von htmlwebpackplugin 3. Schreiben Sie gemäß der normalen Vue-Entwicklung die entsprechenden DateienDefinieren Sie eine app.js-Datei src/app.js Der Zweck der Konvertierung des Eintrags in eine Funktion besteht darin, bei jedem Rendern des Servers eine neue Instanz über diese Factory-Funktion zurückzugeben und so sicherzustellen, dass jeder Besucher seine eigene Instanz erhalten kann. importiere Vue von „vue“; App aus „./App.vue“ importieren importiere createRouter aus './router.js' importiere createStore aus „./store.js“ // Der Zweck der Konvertierung des Eintrags in eine Funktion besteht darin, bei jedem Rendern des Servers eine neue Instanz über diese Factory-Funktion zurückzugeben und so sicherzustellen, dass jeder Besucher seine eigene Instanz erhalten kann. export default () => { const router = createRouter(); const store = erstelleStore() const app = new Vue({ Router, speichern, rendern: h => h(App) }); Rückgabe { App, Router, Store } } src/app.vue <Vorlage> <div id="app"> <router-link to="/">foo</router-link> <router-link to="/bar">Bar</router-link> <Router-Ansicht></Router-Ansicht> </div> </Vorlage> <Skript> Standard exportieren {}; </Skript> src/Komponente/Bar.vue <Vorlage> <div> {{ $store.state.name }} </div> </Vorlage> <Stil scoped="true"> div { Hintergrund: rot; } </Stil> <Skript> Standard exportieren { asyncData(store){ //Methode wird auf dem Server ausgeführt, aber diese Methode wird auf der Backend-Konsole ausgeführt.log('Serveraufruf') // axios.get('/Serverpfad') returniere Promise.resolve('Erfolg') }, mounted(){ // Browser führt aus, Backend ignoriert} } </Skript> src/Komponente/Foo.vue <Vorlage> <div @click="anzeigen">foo</div> </Vorlage> <Skript> Standard exportieren { Methoden:{ zeigen(){ Alarm(1) } } } </Skript> src/router.js importiere Vue von „vue“; importiere VueRouter von „vue-router“; importiere Foo aus './components/Foo.vue' Importiere Bar aus './components/Bar.vue' Vue.use(VueRouter); // Zwei globale Komponenten werden intern bereitgestellt Vue.component() //Jeder, der auf den Server zugreift, muss ein Routing-System generieren export default ()=>{ let router = neuer VueRouter({ Modus: „Verlauf“, Routen:[ {Pfad:'/',Komponente:Foo}, {path:'/bar',component:Bar}, // Lazy Loading, lade die entsprechende Komponente dynamisch entsprechend dem Pfad {path:'*',component:{ rendern:(h)=>h('div',{},'404') }} ] }); Rückrouter; } //Zwei Möglichkeiten zur Front-End-Routing-Hash-Historie // Hash # // Routing dient dazu, verschiedene Komponenten entsprechend unterschiedlicher Pfade zu rendern. Das Merkmal des Hash-Werts besteht darin, dass eine Änderung des Hash-Werts nicht dazu führt, dass die Seite erneut gerendert wird. Wir können die Änderung des Hash-Werts überwachen, um die entsprechende Komponente anzuzeigen (Verlauf kann generiert werden). Das Merkmal von hashApi besteht darin, dass es hässlich ist (der Server kann den Hash-Wert nicht abrufen). // historyApi Die API von H5 ist wunderschön. Das Problem besteht darin, dass beim Aktualisieren eine 404-Fehlermeldung auftritt. src/store.js importiere Vue von „vue“; importiere Vuex von „vuex“; Vue.use(Vuex); //Verwenden Sie vuex auf dem Server, um Daten im globalen Variablenfenster zu speichern, und ersetzen Sie die vom Server gerenderten Daten durch die vom Browser gerenderten Daten. Export Standard ()=>{ let store = neuer Vuex.Store({ Zustand:{ Name: „Zhufeng“ }, Mutationen: changeName(Status,Nutzlast){ Zustand.Name = Nutzlast } }, Aktionen: { Änderungsname({commit}){// store.dispatch('Änderungsname') returniere neues Promise((lösen,ablehnen)=>{ setzeTimeout(() => { commit('Name ändern','jiangwen'); lösen(); }, 5000); }) } } }); wenn(Fenstertyp!='undefined' && Fenster.__INITIAL_STATE__){ // Der Browser beginnt mit dem Rendern // Synchronisiere die gerenderten Ergebnisse des Backends mit der Kernmethode im Front-End vuex store.replaceState(window.__INITIAL_STATE__); // Ersetze es durch die vom Server geladenen Daten} Rückgabegeschäft; } 4. Definieren Sie die EingabedateiDie Paketeintragsdatei des Client-Pakets: src/client-entry.js ist die JS-Eintragsdatei für den Client importiere createApp aus „./app.js“; let {app} = erstelleApp(); app.$mount('#app'); // Clientseitiges Rendering kann client-entry.js direkt verwenden src/server-entry.js Server-Eintragsdatei Es handelt sich um eine Funktion, die vom Server ausgeführt wird, wenn er sie anfordert. // Servereintrag importiere createApp von './app.js'; // Serverseitiges Rendering kann eine Funktion zurückgeben export default (context) => { // Der Server übergibt das URL-Attribut beim Aufruf der Methode // Diese Methode wird auf dem Server aufgerufen // Das Routing ist eine asynchrone Komponente, daher muss ich hier warten, bis die Route geladen ist const { url } = context; returniere neues Promise((auflösen, ablehnen) => { // renderToString() let { app, router, store } = createApp(); // vue-router router.push(url); // Zeigt einen permanenten Sprung/Pfad an router.onReady(() => { // Wartet, bis die Route zum Sprung abgeschlossen ist und die Komponente zum Auslösen bereit ist const matchComponents = router.getMatchedComponents(); // /abc if (matchComponents.length == 0) { //Keine Übereinstimmung mit der Front-End-Route return reject({ code: 404 }); } anders { // matchComponents bezieht sich auf alle Komponenten, die mit der Route übereinstimmen (Komponenten auf Seitenebene) Versprechen.alles(matchComponents.map(Komponente => { if (component.asyncData) { // Der Server findet die asyncData beim Rendern standardmäßig in der Komponente auf Seitenebene, erstellt außerdem ein Vuex auf dem Server und übergibt es an asyncData gibt Komponente.asyncData(Store) zurück } })).then(()=>{ // Standardmäßig wird eine Variable unter dem Fenster generiert. Dies geschieht standardmäßig // "window.__INITIAL_STATE__={"name":"jiangwen"}" context.state = store.state; // Nachdem der Server ausgeführt wurde, wird der letzte Status in store.state gespeichert resolve(app); // app ist die Instanz, die die Daten erhalten hat }) } }) }) // App entspricht newVue und wird nicht vom Router verwaltet. Ich hoffe, warten zu können, bis der Router springt, bevor ich serverseitiges Rendering durchführe // Wenn ein Benutzer eine nicht vorhandene Seite besucht, wie kann die Front-End-Route angepasst werden // Jedes Mal kann eine neue Anwendung generiert werden} // Wenn der Benutzer die Leiste besucht: Ich führe das serverseitige Rendering direkt auf dem Server durch und das gerenderte Ergebnis wird an den Browser zurückgegeben. Der Browser lädt das JS-Skript, lädt das JS-Skript entsprechend dem Pfad und rendert die Leiste erneut
5. Definieren Sie die serverseitige Datei server.js, einen mit Knoten bereitgestellten Server, und fordern Sie die entsprechende Vorlagendatei anVerwenden Sie koa und koa-router zur Anforderungsverarbeitung vue-server-renderer ist ein Must-Have-Paket für serverseitiges Rendering Koa-static verarbeitet Anfragen für statische Ressourcen wie JS-Dateien serverBundle ist das gepackte js Vorlage ist das HTML, das nach dem Servereintrag server:build gepackt ist const Koa = erfordern('koa'); const app = new Koa(); const Router = erforderlich('koa-router'); const router = neuer Router(); const VueServerRenderer = erforderlich('vue-server-renderer'). const static = erforderlich('koa-static') const fs = erfordern('fs'); const Pfad = require('Pfad') const serverBundle = fs.readFileSync(Pfad.resolve(__dirname, 'dist/server.bundle.js'), 'utf8') const template = fs.readFileSync(Pfad.resolve(__dirname, 'dist/server.html'), 'utf8'); // Erstellen Sie einen Renderer basierend auf der Instanz und übergeben Sie das gepackte JS und die Vorlagendatei const render = VueServerRenderer.createBundleRenderer(serverBundle, { Vorlage }) // Anfrage an localhost:3000/ Übergeben Sie diese entsprechend dem URL-Parameter der Anfrage -》 {url:ctx.url} an serverBundle. Anschließend wird eine Seite mit der vollständigen DOM-Dekonstruktion der Route entsprechend dem gepackten .js-Routingsystem auf dem Server gerendert. router.get('/', async (ctx) => { console.log('springen') ctx.body = warte auf neues Promise((lösen, ablehnen) => { render.renderToString({url:ctx.url},(err, html) => { // Wenn CSS wirksam werden soll, können Sie die Rückrufmethode nur verwenden, if (err) reject(err); lösen (html) }) }) // const html = await render.renderToString(); // Einen String generieren // console.log(html) }) // Wenn der Benutzer einen Serverpfad besucht, der nicht existiert, kehre ich zu Ihrer Homepage zurück. Wenn Sie über das Front-End-JS rendern, wird die Komponente entsprechend dem Pfad erneut gerendert. // Solange der Benutzer aktualisiert, sendet er eine Anfrage an den Server. router.get('/(.*)', async (ctx)=>{ console.log('springen') ctx.body = warte auf neues Promise((lösen, ablehnen) => { render.renderToString({url:ctx.url},(err, html) => { // Zurück nach dem Rendern über serverseitiges Rendering if (err && err.code == 404) resolve(`nicht gefunden`); konsole.log(html) lösen (html) }) }) }) // Wenn der Client eine Anfrage sendet, sucht er zuerst im „dist“-Verzeichnis app.use(static(path.resolve(__dirname,'dist'))); // Sequenzproblem app.use(router.routes()); // Stellen Sie sicher, dass Sie Ihre definierte Route verwenden, bevor Sie nach statischen Dateien suchen app.listen(3000); 5.1 Anforderung an localhost:3000/ Übergeben Sie diese gemäß dem Anforderungs-URL-Parameter -》 {url:ctx.url} an serverBundle. Es wird eine Seite mit der vollständigen DOM-Dekonstruktion der Route gemäß dem gepackten .js-Routingsystem auf dem Server gerendert. Da die Komponente, die / entspricht, Foo ist, zeigt die Seite Foo an. Der Quellcode der Webseite wird in DOM analysiert und kann für SEO verwendet werden 5.2 Wenn die Anfrage http://localhost:3000/bar ist Dann lautet die Route /(.*) renderToString übergibt URL Werde gehen Die Standardfunktion der Datei server-entry.js ist ebenfalls ein Vue. Sie enthält die gesamte ursprüngliche Logik des Clients, wird jedoch auf dem Server ausgeführt. Die URL ist /bar Entfernen Sie die Bar-Komponente entsprechend der Route /bar Der Router springt zur Leiste und die Seite wird zur Leistenkomponente. Das gleichzeitige Ausführen der Funktion asyncData kann den Speicher oder andere Daten neu schreiben Denken Sie dann daran, context.state = store.state zuzuweisen, um das Statusobjekt des Stores zum Fenster hinzuzufügen. Fenster.INITIAL_STATE = {"Name":"jiangwen"} Denken Sie daran, store.js (window. INITIAL_STATE) erneut zu verarbeiten store.replaceState(window. INITIAL_STATE ) dient zum Übertragen des Serverstatus auf den Client Nachdem dist/server.html gepackt wurde, wird /client.bundle.js eingeführt, sodass koa-static für die statische Anforderungsverarbeitung erforderlich ist <!DOCTYPE html> <html lang="de"> <Kopf> <meta charset="UTF-8"> <meta name="viewport" content="width=Gerätebreite, Anfangsmaßstab=1.0"> <title>Dokument</title> </Kopf> <Text> <!--vue-ssr-outlet--> <!-- ejs-Vorlage --> <script src="/client.bundle.js"></script> </body> </html> 6. Bereitstellung6.1 Führen Sie den Befehl npm run run:all aus "run:all": "gleichzeitig \"npm run client:build\" \"npm run server:build\"" Es dient zum Verpacken der Client- und Server-Ressourcenpakete einschließlich js, html usw. Legen Sie dann die gesamte Datei server.js auf den Server. Führen Sie node server.js aus, um den Node-Server zu starten 6.2 Richten Sie die in server.js angegebenen Dateien server.bundle.js und server.html einfach auf den entsprechenden Serverordner. Befehl Erklärung Bei der serverseitigen Verwendung wird client.bundle.js im Browser und server.bundle.js auf dem Server verwendet. 7. Zusammenfassung1. SSR erfordert zunächst einen Knotenserver und das Vue-Server-Renderer-Paket. 2. Verwenden Sie einfach die normale Vue-Entwicklung und bedenken Sie, dass der Lebenszyklus „beforeMount“ oder „Mounted“ auf der Serverseite nicht verwendet werden kann. 3. Erstellen Sie server.js und setzen Sie koa oder express für die Anforderungsanalyse ein. Übergeben Sie dann serverBundle und Vorlage an VueServerRenderer.createBundleRenderer-Funktion Holen Sie sich ein Rendering 4. render.renderToString übergibt die angeforderte Route, z. B. /bar 5. Zu diesem Zeitpunkt wird die Standardfunktion serverBundle (abgeleitet vom Paket server-entry.js) eingegeben, eine Vue-Instanz-App erstellt, die Routing-Vue-Instanz analysiert und dann die Route übersprungen. Zu diesem Zeitpunkt hat sich nur die Vue-Instanz auf der Serverseite geändert und dies wurde noch nicht auf der Seite widergespiegelt. 6. Führen Sie die Funktion asyncData der entsprechenden Komponente aus, die store.state ändern kann. Weisen Sie den Wert dann context.state zu. 7. resolve(app) Zu diesem Zeitpunkt analysiert das Rendern in server.js das DOM entsprechend dem Routing-Status der Vue-Instanz-App zu diesem Zeitpunkt und gibt es an die Seite ctx.body = ...resolve(html) zurück; 8. Zu diesem Zeitpunkt erhält die Seite nach dem normalen Routing-Matching die DOM-Struktur 9. Es wird ein Fenster in HTML angezeigt. INITIAL_STATE = {"name":"zhufeng"} entspricht der Aufzeichnung des Store-Status des Servers. 10. Wenn der Client den Store ausführt, gibt es auf dem Server tatsächlich keinen geänderten Status. Führen Sie store.replaceState(window. INITIAL_STATE ); aus, um den Status auf dem Server zu ersetzen. 11. Die Gesamtsituation ist, dass sowohl der Server als auch der Client über ein JS-Paket verfügen. Führen Sie das JS-Paket im Voraus auf dem Server aus, analysieren Sie dann das DOM und zeigen Sie es an. Der Server ist fertig und die verbleibende Logik wird vom JS des Clients verarbeitet. Konzeptkarte Offizielle Website:
ZusammenfassenDies ist das Ende dieses Artikels über das serverseitige Rendering von Vue SSR. Weitere verwandte Inhalte zum serverseitigen Rendering von Vue SSR finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird! Das könnte Sie auch interessieren:
|
<<: Detaillierter Installationsprozess von mysql5.7.21 unter Win10
>>: So konfigurieren Sie Nginx's Anti-Hotlinking
Die EXPLAIN-Anweisung liefert Informationen darüb...
Installationsschritte 1. Erstellen Sie eine virtu...
mysql-5.7.20-winx64.zipInstallationspaket ohne In...
Die Lösung für das Problem, dass Ubuntu 18.04 in ...
Bei der Verwendung von MySQL werden häufig Trigge...
Der Weg vor uns ist lang und beschwerlich, aber i...
Alle Websites, ob offiziell, E-Commerce, soziale ...
MySQL-Replikation - ausführliche Erklärung und ei...
Kurzeigenschaften werden verwendet, um mehreren E...
Apache Tika ist eine Bibliothek zur Dateityperken...
Der Standardzeittyp (Datum/Uhrzeit und Zeitstempe...
Heute stellen wir mehrere Möglichkeiten vor, mit ...
Linux-Systemversion: CentOS7.4 MySQL-Version: 5.7...
Inhaltsverzeichnis 1. Automatische Installation m...
Schritt 1: Holen Sie sich die MySQL YUM-Quelle Ge...