Renderización lado servidor de Vue.js on Php

by Luigi Nori Date: 20-04-2020 javascript php vue

¿Intentas que el renderizado del lado del servidor funcione con PHP para renderizar tu aplicación Vue.js pero se atasca?

Hay un montón de grandes recursos por ahí, pero hasta ahra no has encontrado nada que funcione de inmediato sin tener que investigar. Con suerte, después de esta entrada tendrás una mejor idea de cómo realizar el renderizado del lado del servidor para tu aplicación Vue.js!

Requisitos

PHP 7.2 Node.js (Mi servidor tiene la v8.9.4, no estoy seguro de que funcione en versiones anteriores, pero si tienes al menos esta versión deberías ser bueno!)

Crear nuestra Vue App

Para este ejemplo, vamos a utilizar la aplicación de inicio Vue que se ha creado para nosotros utilizando las herramientas de línea de comandos de Vue. Pero, cualquier aplicación Vue funcionará. Así que, para empezar, navega a un directorio donde quieras almacenar tu proyecto y escribe:

vue create test-app

Utiliza la configuración predeterminada.

Una vez que termines de crear el proyecto, necesitamos hacer algunas cosas. Primero necesitamos instalar la biblioteca vue-server-renderer. Para ello, navega en la carpeta test-app y escribe lo siguiente:

npm install --save vue-server-renderer

A continuación tenemos que crear un nuevo archivo de punto de entrada para que el servidor pueda renderizar nuestra aplicación. En la carpeta src, crear un nuevo archivo llamado entry.js . Dentro, pon el siguiente trozo de código:

import createApp from './main';
import renderToString from 'vue-server-renderer/basic'
const app = createApp();
if(typeof dispatch !== 'undefined')
{
renderToString(app, (err, html) => {
if(err)
{
throw new Error(err);
}
dispatch(html);
});
}

Aquí estamos importando nuestra verdadera aplicación Vue.js con la línea import createApp from ‘./main’; . A continuación, estamos importando la función renderToString de la biblioteca vue-server-renderer que creará la carga inicial de nuestra aplicación en el servidor.

A continuación estamos creando una instancia de nuestra aplicación con la línea const app = createApp(); . Luego vamos a comprobar si hay una variable definida llamada dispatch .

dispatch es una función que nos devuelve el html renderizado y se crea a través de la biblioteca de renderizado del lado del servidor que vamos a usar. Así que sólo estará disponible cuando el servidor intente renderizar la aplicación. No estará disponible una vez que el cliente intente renderizar la aplicación. Por lo tanto, al comprobar la variable dispatch estamos comprobando efectivamente si la aplicación se está cargando desde el servidor o el cliente.

Con ese archivo creado y guardado, ahora tenemos que modificar ligeramente el archivo main.js que fue autogenerado para nosotros. Ábrelo y debería verse algo como esto:

import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')

En lugar de crear el nuevo objeto Vue, necesitamos que este archivo exporte una función que devuelva nuestro objeto Vue. Para hacer eso, necesitas cambiar el código para que se vea así:

import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
export default () => new Vue({
render: h => h(App),
}).$mount('#app')

El único cambio fue la adición de export default () => al comienzo de la creación del nuevo objeto Vue. Lo que hace esto es permitirnos importar este archivo main.js y llamarlo como una función. Como puedes ver si regresas al archivo entry.js que creamos anteriormente. Estamos importando nuestro archivo main.js y llamándolo createApp . Luego llamamos a createApp comouna función mas tarde en el código.

El último cambio que necesitamos hacer en nuestro proyecto es añadir un archivo vue.config.js . Esto debería estar justo fuera de la carpeta src, donde está el archivo package.json . Dentro necesitarás poner lo siguiente:

module.exports = {
productionSourceMap: false,
filenameHashing: false,
chainWebpack: config => {
config.optimization.splitChunks(false);
},
configureWebpack: {
entry: './src/entry.js'
}
}

Esto logra dos cosas importantes que necesitamos para trabajar con la biblioteca PHP que vamos a usar más tarde. Configura nuestra aplicación para generar un único archivo javascript en lugar de múltiples trozos. Esto se hace con la propiedad chainWebpack y pasando splitChunks falso, así como el ajuste productionSourceMap a falso.

Lo siguiente importante que hace esto es establecer el punto de entrada para usar nuestro nuevo archivo entry.js en lugar del archivo main.js predeterminado.

La propiedad filenameHashing es más por conveniencia, así que cada vez que construyas tu aplicación, el nombre de archivo no cambiará.

Y con eso hemos terminado con la parte de Vue de nuestra aplicación. A continuación trabajaremos en el lado de PHP.

PHP Script

Navega a la carpeta pública de tu aplicación Vue (si la sigues estará dentro de la carpeta test-app) y usando el composer vamos a instalar una biblioteca PHP llamada spatie/server-side-rendering. Así vamos a escribir lo siguiente:

composer require spatie/server-side-rendering

Una vez que termine de instalarse, crea un nuevo archivo PHP en la carpeta pública llamado app.php . En la parte superior del archivo necesitaremos requerir el archivo autocargable que genera el compositor y luego incluir 2 clases que vamos a usar para renderizar nuestra aplicación Vue en el servidor. Luego instanciaremos las clases y las usaremos para renderizar nuestra aplicación. Aquí está el código php para eso:

require_once("vendor/autoload.php");
use SpatieSsrRenderer;
use SpatieSsrEnginesNode;
$engine = new Node("node", "/var/www/html/vue-ssr/temp");
$renderer = new Renderer($engine);
echo $renderer
->entry(__DIR__."/js/main.js")
->render()
;

La clase Renderer se utiliza para renderizar nuestra aplicación y la clase Node es uno de los motores de renderización que viene con la biblioteca. Esencialmente lo que esta librería hace es crear un archivo javascript temporal con nuestra aplicación Vue, lo llama con nodo, coge el html que se genera y nos lo pasa de nuevo.

Cuando instanciemos la clase Nodo, verás que le pasamos 2 parámetros al constructor. El primero es "node" y el segundo "/var/www/html/vue-ssr/temp" . El primer parámetro "node" debe ser la ruta de acceso a su archivo ejecutable node.js. No necesita ser la ruta completa si puedes acceder al nodo desde la línea de comandos con sólo teclear nodo.

El segundo parámetro "/var/www/html/vue-ssr/temp" , es una ruta a un directorio donde se pueden crear archivos temporales. Puede ser cualquier carpeta que desee, pero es importante que esta carpeta sea escribible por el servidor web. Si no, no podrás hacer que esta biblioteca funcione. Sustituye este parámetro por tu propia ruta de carpeta temporal.

Despues de haber creado la variable $engine ,vamos a crear el objecto $renderer y lo pasamos a $engine . Entonces estamos encadenando 2 llamadas de método desde el objecto $renderer , entry y luego render . En el método entry pasamos el camino a nuestra aplicación compilada. Aún no hemos construido nuestra aplicación, así que este archivo no existe todavía, pero si lo sigues, pronto lo hará.

Por último, llamando a render genera el html inicial para nuestra aplicación.

Construir la Vue app

¡Ahora construyamos nuestra aplicación Vue para la producción! Dentro de la carpeta de la aplicación de prueba, ejecute el siguiente comando:

npm run build

Esto creará una carpeta dist con nuestro archivo app.php y la carpeta del proveedor que creamos en el último paso. Usted querrá configurar su servidor para que la carpeta dist pueda ser accedida desde la web o subir/mover la carpeta dist a algún lugar que pueda ser accedido desde la web. Si todo ha ido bien, si accedes a app.php desde tu navegador deberías ver algo como esto:

Si lo tienes, ¡genial! Si tienes un error, puedes encadenar un método adicional, debug , del objeto $renderer como este:

echo $renderer
->debug(true)
->entry(__DIR__."/js/main.js")
->render()
;

Esto dará como resultado cualquier error que haya ocurrido.

A continuación podemos actualizar nuestro archivo app.php para cargar la aplicación Vue real también para que se vuelva a renderizar una vez que el cliente la cargue:

require_once("vendor/autoload.php");
use SpatieSsrRenderer;
use SpatieSsrEnginesNode;
$engine = new Node("node", "/var/www/html/vue-ssr/temp");
$renderer = new Renderer($engine);
$rendered = $renderer
->entry(__DIR__."/js/main.js")
->render()
;
?>
<html>
<head>
<link rel="stylesheet" type="text/css" href="/css/main.css">
</head>
<body>
<?php echo $rendered; ?>
<script type="text/javascript" src="/js/main.js"></script>
</body>
</html>

Y cuando lo recargas se parecerá más a la aplicación original de Vue:

Hidratando tu aplicación

Ahora, tenemos nuestra aplicación renderizada en el servidor, pero una de las características clave que aún no hemos tocado es la hidratación o el prellenado de nuestro estado. Hay otro método que podemos encadenar al objeto $renderer llamado context . Toma 2 parámetros, una clave y un valor o toma un solo conjunto de elementos clave/valor.

Aquí hay un ejemplo:

$context = [
'message' => 'Test Prerendered Content!'
];
$rendered = $renderer
->context($context)
->entry(__DIR__."/js/main.js")
->render()
;

Esto creará una nueva variable javascript llamada context , que será accesible durante el proceso de renderización del servidor. Así que en nuestra aplicación Vue, podemos comprobar si esta variable context se crea y luego se utiliza para rellenar previamente nuestro almacén de Vuex o las propiedades de los datos.

En este tutorial te mostraré cómo rellenar las propiedades de datos, pero se puede utilizar un método similar para rellenar un almacén.

Por lo tanto, si aún no lo ha hecho, agregue los nuevos cambios de contexto a su script PHP que se muestran arriba. También vamos a sacar el output del array $context como un objeto javascript en nuestra plantilla HTML y crear nuestra propia variable javascript context así que el cliente pueda aceder tambien a una variable context .

Aquí es como va a pintar el php:

require_once("vendor/autoload.php");
use SpatieSsrRenderer;
use SpatieSsrEnginesNode;
$engine = new Node("node", "/var/www/html/vue-ssr/temp");
$renderer = new Renderer($engine);
$context = [
'message' => 'Test Prerendered Content!'
];
$rendered = $renderer
->context($context)
->entry(__DIR__."/js/main.js")
->render()
;
?>
<html>
<head>
<link rel="stylesheet" type="text/css" href="/css/main.css">
</head>
<body>
<?php echo $rendered; ?>
<script type="text/javascript">
var context = <?php echo json_encode($context) ?>;
</script>
<script type="text/javascript" src="/js/main.js"></script>
</body>
</html>

Como pueden ver, simplemente estoy creando una variable llamada contexto en javascript y poniéndola igual a la versión codificada en json de nuestra matriz $context PHP. De esa manera, cuando la página se cargue, habrá una variable de contexto que será accesible para nuestra aplicación en el lado del cliente.

A continuación vamos a nuestro archivo App.vue y usamos la variable de contexto para rellenar nuestro estado.

Primero necesitamos crear algún estado. Así que crea un método de datos en tu aplicación Vue y devuelve un objeto con una propiedad de mensaje como esta:

data() {
return {
message: "Welcome to Your Vue.js App"
}
}

Luego, en la plantilla, cambia el atributo msg del componente de HelloWorld para usar nuestra propiedad de estado del message :

<HelloWorld :msg="message"/>

Ahora estamos listos para hidratar/pre-rellenar el estado inicial de nuestra aplicación.

Necesitaremos hacer el prellenado en un lifecycle hook. Los únicos dos lifecycle hooks que están disponibles para nosotros con la representación del lado del servidor son created y beforeCreate . Voy a usar el hook created . Dentro, vamos a chequear si la variable context existe y tiene la propriedad message . Luego vamos a poner la propriedad de estado de message igual a la propriedad context.message como esto:

created() {
if(typeof context !== 'undefined' && typeof context.message !== 'undefined')
{
this.message = context.message;
}
}

Tu archivo completo de App.vue debería verse ahora así:

<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld :msg="message"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'app',
components: {
HelloWorld
},
data() {
return {
message: "Welcome to Your Vue.js App"
}
},
created() {
if(typeof context !== 'undefined' && typeof context.message !== 'undefined')
{
this.message = context.message;
}
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

Con eso, guarda tu archivo App.vue y luego ejecuta el siguiente comando para reconstruir tu aplicación:

npm run build

Si es necesario, asegúrate de volver a cargar los nuevos archivos que se generaron y luego vuelve a acceder a tu archivo app.php desde la web.

Debería verse algo como esto:

¡Y eso es todo!

Espero que este tutorial haya sido útil para que superes el obstáculo de que el servidor renderice tu aplicación Vue. Si tienes alguna pregunta o comentario, házmelo saber en los comentarios de abajo!

También, como escribí al principio de este post, hay un montón de grandes recursos para ayudar con el renderizado del lado del servidor usando PHP y usé muchos de ellos para escribir este tutorial.

 
by Luigi Nori Date: 20-04-2020 javascript php vue visitas : 7745  
 
Luigi Nori

Luigi Nori

He has been working on the Internet since 1994 (practically a mummy), specializing in Web technologies makes his customers happy by juggling large scale and high availability applications, php and js frameworks, web design, data exchange, security, e-commerce, database and server administration, ethical hacking. He happily lives with @salvietta150x40, in his (little) free time he tries to tame a little wild dwarf with a passion for stars.

 
 
 

Artículos relacionados

Seguimiento en tiempo real de los vuelos: la API de Flight Tracker

La API de Flight Tracker brinda a los desarrolladores la capacidad de acceder al estado de los vuelos en tiempo real, lo cual resulta extremadamente útil para integrar un seguimiento…

Crear PDF con Javascript y jsPDF

El formato PDF es muy útil para descargar datos de forma masiva en una aplicación web. Ayuda a los usuarios a descargar contenido dinámico en forma de archivo para que…

Como hacer tu propio cursor personalizado para tu web

Cuando empecé a ojear webs distintas y originales para aprender de ellas, de las primeras cosas que me llamaron la atención fue que algunas de ellas tenían sus propios cursores,…

Ejecución de funciones PHP en AWS Lambda y API Gateway

¿Qué es AWS Lambda? AWS Lambda es un servicio de procesamiento sin servidor que puede ejecutar código en respuesta a eventos o condiciones predeterminados y administrar automáticamente todos los recursos de…

Explorando la API de CSS Paint: Redondeo de formas parte 1

Añadir bordes a las formas complejas es un auténtico rollo (a veces), pero redondear las esquinas de las formas complejas es un suplicio jejeje. Por suerte, la API de pintura…

Cómo enviar un correo electrónico desde un formulario de contacto HTML

En el artículo de hoy vamos a escribir sobre cómo hacer un formulario que funcione y que al pulsar ese botón de envío sea funcional y envíe el correo electrónico…

Cómo hacer un sitio web multilingüe sin redireccionamiento

Hoy, vamos a hablar de cómo implementar un simple selector de idioma en el sitio web estático o básico, sin necesidad de ningún backend o llamadas a la base de…

6 Formas de leer archivos en PHP, con strings, array y más

Bienvenido a un tutorial sobre cómo leer archivos en PHP. Sí, así es, ¿qué tan difícil puede ser leer archivos en PHP? Se sorprenderá... No es tan sencillo como algunos…

Comenzando con Bootstrap-Vue paso a paso

Hoy te mostraremos cómo usar BootstrapVue, describiremos el proceso de instalación y mostraremos la funcionalidad básica. El proyecto está basado en el framework CSS más popular del mundo - Bootstrap, para…

Por qué los desarrolladores de JavaScript deberían preferir Axios a Fetch

Por qué los desarrolladores de JavaScript deberían preferir Axios a Fetch En mi artículo anterior, "Usando la Api Fetch Para Hacer Llamadas Ajax", hablé de los fundamentos de la API Fetch.…

Instalar Laravel Homestead en Windows 10

Instalar Homestead Mediante Vagrant Laravel Homestead es una máquina virtual que viene ya preparada para el desarrollo de proyectos con Laravel y otras tecnologías de PHP . Al ser una máquina…

Creación de un sencillo spinner-loader CSS

En el artículo de hoy mostraremos cómo animar un loader básico que gira cuando se define alguna acción predefinida, como cargar una imagen. Eso se puede utilizar en un sitio…

Clicky