VuePre is a package to prerender vue templates. This is useful for SEO and avoiding blank pages on page load. What VuePre does, is translating the Vue template to a PHP template, then replaces the javascript expressions with PHP expressions and caches it. Once cached, you can render thousands of templates per second depending on your hardware.
- Very fast
- No dependencies
- Some javascript expressions are not supported (yet).
composer require ctxkiwi/vue-pre
$vue = new \VuePre\Engine();
$vue->setCacheDirectory(__DIR__ . '/cache');
// Method 1
$data = ["name" => "world"];
$html = $vue->renderHtml('<div>Hello {{ name }}!</div>', $data);
// Method 2 - Using component directory (required if you use sub-components)
$vue->setComponentDirectory(__DIR__ . '/components');
$html = $vue->renderComponent('my-page', $data);
// If you set your directory like this
$vue->setComponentDirectory(__DIR__ . '/components');
// It's going to look for any .php file and register the filename as a component
// So, if you have components/pages/homepage.php
// It will use this file for the <homepage> component
<?php
return [
'beforeRender' => function (&$data) {
$data['counter'] = 0;
},
];
?>
<template>
<div>
<button v-on:click="min"> - </button>
{{ counter }}
<button v-on:click="plus"> + </button>
</div>
</template>
<script>
Vue.component('homepage', {
template: '#vue-template-homepage',
data: function () {
return {
counter: 0,
};
},
methods: {
plus: function(){ this.counter++; },
min: function(){ this.counter--; },
}
});
</script>
class View{
public static function render($view, $data = []){
// Normal PHP template engine
...
return $html;
}
public static function renderComponent($name, $data = []){
$vue = new \VuePre\Engine();
$vue->setCacheDirectory(Path::get('tmp'). '/cache');
$vue->setComponentDirectory(Path::get('views') . '/components');
$html = $vue->renderComponent($name, $data);
$templates = $vue->getTemplateScripts();
$js = $vue->getJsScripts();
$vueInstance = $vue->getVueInstanceScript('#app', $name, $data);
$html = '<div id="app">'.$html.'</div>'.$templates.$js.$vueInstance;
return static::render('layouts/main.html', ['CONTENT' => $html];
}
}
class ViewController{
public function homepage(){
$data = [
// Dont put private data in here, because it's shared with javascript
'layoutData' => [
'authUser' => \AuthUser::getUser()->getPublicData(),
],
'featureProducts' => Product::where('featured', true)->limit(10)->get();
];
// Render <homepage> component
echo View::renderComponent('homepage', $data);
}
}
<!-- views/layouts/main.html -->
<!DOCTYPE>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
{!! $CONTENT !!}
<body>
</html>
<?php
// views/components/layout.php
return [
'beforeRender' => function (&$data) {
$data = $data['layout-data'];
},
];
?>
<template>
<div>
<header>...</header>
<main>
<slot></slot>
</main>
<footer>...</footer>
</div>
</template>
<script>
Vue.component('layout', {
props: ['layoutData'],
template: '#vue-template-layout',
data: function () {
return this.layoutData;
},
});
</script>
<?php
// views/components/homepage.php
?>
<template>
<layout :layout-data="layoutData">
<div class="homepage">
<h1>Welcome</h1>
<p>...</p>
<h2>Featured products</h2>
<div v-for="product in featuredProducts"><h3>{{ product.name }}</h3></div>
</div>
</layout>
</template>
<script>
Vue.component('homepage', {
props: ['layoutData', 'featuredProducts'],
template: '#vue-template-homepage',
data: function () {
return {};
},
});
</script>
You can generate scripts for your component templates and your component.js files.
// Based on your last render
$vue->getScripts();
$vue->getTemplateScripts(); // only template scripts
$vue->getJsScripts(); // only js scripts
// By component name
$vue->getTemplateScript('my-page');
$vue->getJsScript('my-page');
// Usefull
$vue->getRenderedComponentNames();
->setCacheDirectory(String $path)
->setComponentDirectory(String $path)
->setGlobals(Array $globalVariables) // e.g. ['loggedIn' => true, 'user' => ['id'=>123, 'username'=>'TerryDavis']]
->renderHtml(String $html, Array $data)
->renderComponent(String $componentName, Array $data)
// Optional settings
->ignoreAttributes(Array $attributeNames)
->unignoreAttributes(Array $attributeNames)
->getIgnoredAttributes() : Array $attributeNames
// Generating scripts
->getScripts($idPrefix = 'vue-template-');
->getTemplateScripts($idPrefix = 'vue-template-');
->getTemplateScript(String $componentName, $default = null, $idPrefix = 'vue-template-');
->getJsScripts();
->getJsScript(String $componentName, $default = null);
// Others
->getComponentAlias(String $componentName, $default = null)
->getRenderedComponentNames();
# Prototype functions
.indexOf()
.length
# JS Functions
typeof()
# Values: variables, strings, numbers, booleans, null, objects, arrays, functions
# Comparisons
myVar === 'Hello'
something ? 'yes' : false
# Nested expressions
(((5 + 5) > 2) ? true : false) ? (myBool ? 'Yes' : 'Yez') : 'No'
# Objects
product.active ? product.name : product.category.name
# Methods using $vuePre->setMethods(['myFunc'=> function(){ ... }])
product.active ? myFunc(product.name) : null
Note: Feel free to make an issue for these, so i can make them a prority. The only reason these are not implemented yet is because of low priority.
- Custom error handlers
- Options:
ignoreVariableNotFound
ignoreVariableNames
ignoreMethodNames
ignoreSubComponents
ignoreSubComponentNames
The DOM iterator code was partially copied from wmde/php-vuejs-templating