GithubHelp home page GithubHelp logo

spatie / laravel-server-side-rendering Goto Github PK

View Code? Open in Web Editor NEW
650.0 650.0 63.0 81 KB

Server side rendering JavaScript in your Laravel application

Home Page: https://sebastiandedeyne.com/posts/2018/server-side-rendering-javascript-from-php

License: MIT License

PHP 99.55% JavaScript 0.45%
javascript php server-side-rendering ssr

laravel-server-side-rendering's Introduction

Server side rendering JavaScript in your Laravel application

Latest Version on Packagist GitHub Workflow Status Total Downloads

Making server side rendering a bit less hard in Laravel.

<html>
    <head>
        <title>My server side rendered app</title>
        <script defer src="{{ mix('app-client.js') }}">
    </head>
    <body>
        {!! ssr('js/app-server.js') !!}
    </body>
</html>

This package is a Laravel bridge for the spatie/server-side-rendering library. Before getting started, dig through the readme to learn about the underlying concepts and caveats. This readme also assumes you already have some know-how about building server rendered JavaScript apps.

Vue and React example apps are available at spatie/laravel-server-side-rendering-examples if you want to see it in action.

Support us

We invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.

Installation

You can install the package via composer:

composer require spatie/laravel-server-side-rendering

The service provider and Ssr alias will be automatically registered.

You can optionally publish the config file if you want to tweak things.

php artisan vendor:publish --provider="Spatie\Ssr\SsrServiceProvider" --tag="config"

Usage

Prerequisites

First you'll need to pick an engine to execute your scripts. The server-side-rendering library ships with V8 and Node engines. By default, the package is configured to use node, since you probably already have that installed on your system.

Set up the NODE_PATH environment variable in your .env file to get started:

NODE_PATH=/path/to/my/node

You'll also need to ensure that a storage/app/ssr folder exists, or change the ssr.node.temp_path config value to something else.

If you'd rather use the V8 engine, you can skip the previous two steps. You'll need to have the v8js extension installed though.

Configuration

Besides the above, no configuration's required. If you need to tweak things anyway, the config file is well documented.

Setting up your scripts

You'll need to build two scripts: a server script and a client script. Refer to your frontend-framework-of-choice's documentation on how to build those.

mix.js('resources/js/app-client.js', 'public/js')
   .js('resources/js/app-server.js', 'public/js');

The server script should be passed to the ssr function, the client script should be loaded manually. The package assumes you're using Laravel Mix, and will resolve the path for you. You can opt out of this behaviour by setting mix to false in the config file.

{!! ssr('js/app-server.js') !!}
<script src="{{ mix('js/app-client.js') }}">

Your server script should call a dispatch function to send the rendered html back to the view. Here's a quick example of a set of Vue scripts for a server-rendered app. Read the spatie/server-side-rendering readme for a full explanation of how everything's tied together.

// resources/js/app.js

import Vue from 'vue';
import App from './components/App';

export default new Vue({
    render: h => h(App),
});
// resources/js/app-client.js

import app from './app';

app.$mount('#app');
// resources/js/app-server.js

import app from './app';
import renderVueComponentToString from 'vue-server-renderer/basic';

renderVueComponentToString(app, (err, html) => {
    if (err) {
        throw new Error(err);
    }

    dispatch(html);
});

Rendering an app in your view

The package exposes an ssr helper to render your app.

<html>
    <head>
        <title>My server side rendered app</title>
        <script defer src="{{ mix('js/app-client.js') }}"></script>
    </head>
    <body>
        {!! ssr('js/app-server.js')->render() !!}
    </body>
</html>

A facade is available too.

<html>
    <head>
        <title>My server side rendered app</title>
        <script defer src="{{ mix('js/app-client.js') }}"></script>
    </head>
    <body>
        {!! Ssr::entry('js/app-server.js')->render() !!}
    </body>
</html>

Rendering options can be chained after the function or facade call.

<html>
    <head>
        <title>My server side rendered app</title>
        <script defer src="{{ mix('js/app-client.js') }}"></script>
    </head>
    <body>
        {!! ssr('js/app-server.js')->context('user', $user)->render() !!}
    </body>
</html>

Available options are documented at spatie/server-side-rendering.

Testing

composer test

Changelog

Please see CHANGELOG for more information what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you've found a bug regarding security please mail [email protected] instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.

laravel-server-side-rendering's People

Contributors

adrianmrn avatar andredewaard avatar cbl avatar cwdn avatar erikn69 avatar freekmurze avatar laravel-shift avatar magiczne avatar mammutalex avatar nspehler avatar patinthehat avatar reed-jones avatar richardkeep avatar sebastiandedeyne avatar serdud avatar timrspratt avatar traubisoda avatar tutnichts avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-server-side-rendering's Issues

Vue router lazy components not working

I have explained the issue in detail here:
laravel-mix/laravel-mix#2245

To recap, this works:

import Home from '../view/Home';
export const routes = [{ path: '/', name: "Home", component: Home }]

...however these don't

const Home = resolve => require(['../views/Home.vue'], m => resolve(m.default));
export const routes = [{ path: '/', name: "Home", component: Home }]

<div id="app" data-server-rendered="true"><!----></div>


export const routes = [{ path: '/', name: "Home", component: () => import('../views/Home.vue)' }]

<div id="app" data-server-rendered="true"><!----></div>


For the () => import('../views/Home.vue), client.js works, only server.js doesn't work.

I suspect it's because server.js doesn't wait for the dynamic routes to be loaded, however I couldn't find any solution. Thanks in advance

Can't get file from store/app/ssr

I have an error:

The command "node /home/site/list/test.ru/storage/app/ssr/a22a8133fc128812e26e6321cfeb1079.js" failed.
Exit Code: 1(General error)

Working directory: /home/site/list/shadowsproject.ru/public

Error Output:
================
...

ReferenceError: document is not defined

I've checked store/app/ssr folder. Files aren't created here.
All files configured like as in instruction. SSR folder exist. No any other errors appeared...

Will this work with Laravel Vapor?

Hi, thank you for this wonderful package! I've been a big fan of Spatie's open source packages, you're really making the PHP / Laravel ecosystem a much better place to work in.

We've been using this package successfully on a Forge setup. But do you think this will work with Laravel Vapor / Lambda? If not out of the box, do you have ideas on any workarounds to make it work?

dispatch() function in entry-server.js

Thanks very much for the code.

I'm trying to use it to implement SSR with React. I'm struggling with the dispatch() function in entry-server.js. Where does this function come from? It isn't native JS and doesn't seem to come from App, React or ReactDOMServer.

Any help would be much appreciated.

This package has some problems when the project is deployed trough Envoyer

Hey.

I'm using this package in one of my projects. It worked perfectly, with one caveat. My project is deployed with Envoyer. i'm using this webpack config:

const { mix } = require('laravel-mix');
var nodeExternals = require('webpack-node-externals');

mix.setPublicPath('public/js/ssr')
    .js('resources/assets/js/search-app.js', 'public/js/ssr/')
    .js('resources/assets/js/entry-server.js', 'public/js/ssr/');

mix.webpackConfig(
    {
        resolve: {
            alias: {
                vue$: 'vue/dist/vue.runtime.common.js',
            },
        },
        name: "server",
        externals: [nodeExternals()],
        target: "node"
    }
);

if (!mix.inProduction) {
    mix.webpackConfig.devtool = 'source-map';
    mix.sourceMaps();
}

The server script isn't executed on the server, because it is placed on storage/app/ssr. Since the storage folder is symlinked on Envoyer, I see a lot of "Cannot find module XXXX" with the require() on the bundle when the server script is executed.

What I did to solve this what changing the node temp_path to something inside the public folder on the current release.

Just thought it can be useful to make this thread in case anyone has the same issue, or if there's any other "cleaner" fix for this.

Not sure how to pass context to store

Hi,

Thank you as always for your great packages! I'm trying this out but got stuck trying to pass data to save in my Vuex store. I was wondering if you might have a more detailed example of what the app-server.js and app-client files would look like. How do I access that context in those files?

This part of the directions are what I'm not sure how to implement:

// app-server.js

store.user = context.user // { name: 'Sebastian' }

// Render the app...

Thank you!!

Cannot contribute

Hi!

First, thanks for this awesome package! :)

I'd like to suggest a few little changes to the readme that would make it easier for newcomers to set the package up, but I can't push to the repo, so I couldn't make a PR.

This is the error I got:
remote: Permission to spatie/laravel-server-side-rendering.git denied to traubisoda.
fatal: unable to access 'https://github.com/spatie/laravel-server-side-rendering.git/': The requested URL returned error: 403

In case this repo is not open to pull requests, the changes I'd suggest to the readme:
The link to the examples is broken.
For me, it was not clear, that the NODE_ENV env variable is to be set in the .env file or in the OS.

Webpack config

Hi,I want ask about css,it can be work only with extractVuestyles?
And I tried make lazy load ,but v8 engine crashed on first line,may be u know what need to do?

Patch / Polyfill for DOM globals like document / window

Has anyone resolved issues relating to third party modules using these globals?

I know that I can refactor out the includes for these third party dependencies with a
if(typeof window !== 'undefined') { }

condition but am wondering if there is a more automatic solution.

Thanks!

ReferenceError: window is not defined

ReferenceError: window is not defined
I am getting this error when I run it on a digitalocean server. And there are several references to window on the built code for entry-server.js. I am following the example related to this repo.

error laravel ssr using node

The command "/c/Program Files/nodejs/node C:\xampp\htdocs\Agrirecruit_Laravel\storage\app/ssr\c244232e15965255150ad76e7d13d123.js" failed. Exit Code: 1(General error) Working directory: C:\xampp\htdocs\Agrirecruit_Laravel\public Output

Note: the c244232e15965255150ad76e7d13d123.js never gets written to the storage/app/ssr folder

I've been stuck on the same error as this #13 for the past few days and can't figure it out.
Note: I'm using windows 10

I ran which node to get node path
I've set the NODE_PATH="/c/Program Files/nodejs/node"

APP_ENV=production

Here's my files.

package.json

"dependencies": { "vee-validate": "^2.0.9", "vue": "^2.5.7", "vue-head": "^2.0.12", "vue-router": "^3.0.1", "vue-server-renderer": "^2.5.16", "vue-the-mask": "^0.11.1", "vue-wysiwyg": "^1.7.2", "vue2-editor": "^2.5.0", "vuex": "^3.0.1" }

mix

mix.js('resources/assets/js/app-client.js', 'public/js') .js('resources/assets/js/app-server.js', 'public/js') .sass('resources/assets/sass/app.scss', 'public/css') .sourceMaps().version();

Blade

<script type="text/javascript" defer src="{{ mix('js/app-client.js') }}"></script>

<main class="container-fuild" id="app"> {!! ssr("js/app-server.js")->render() !!} </main>

The I didn't change anything in the ssr.php

return [

'enabled' => env('APP_ENV') === 'production',

'debug' => env('APP_DEBUG', false),

'mix' => true,

'engine' => \Spatie\Ssr\Engines\Node::class,

'node' => [
    'node_path' => env('NODE_PATH', '/usr/local/bin/node'),
    'temp_path' => storage_path('app/ssr'),
],

'context' => [],

'env' => [
    'NODE_ENV' => 'production',
    'VUE_ENV' => 'server',
],

];

Client.js

import app from './app'; app.$mount('#app');

Server.js

import app from './app'; import renderVueComponentToString from 'vue-server-renderer/basic'; renderVueComponentToString(app, (err, res) => { if (err) { throw new Error(err); } dispatch(res); });

Support For Head Tags

Hello

Been playing around with this for a few days and its super awesome!! Thanks for the time put in to get this working :)

Is there any support for using a Vue package to update tags in the html head? Or rather, what is the best way to do this?

I have take a look at the vue-meta package but seem to be running into issues. Their docs also explain things from a node backend which leaves me here.

Any help would be appreciated :)

throw error window is not defined

blade code

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>vtest</title>
    {{-- <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,600,700' rel='stylesheet' type='text/css'> --}}
    @stack('styles')
    <script defer src="{{ assetic('js/manifest.js','modules/dashboard/frontend') }}"></script>
    <script defer src="{{ assetic('js/vendor.js','modules/dashboard/frontend') }}"></script>
    <script defer src="{{ assetic('js/client.js','modules/dashboard/frontend') }}"></script>
    @stack('scripts')
  </head>
  <body>
    {!! ssr(assetic('js/server.js','modules/dashboard/frontend'))
            ->fallback('<div id="app"></div>')
            ->render() !!}
  </body>
</html>

server.js

import app from './src/main'
import renderServer from 'vue-server-renderer/basic'
app.$router.push(context.url)
renderServer(app, (err, html) => {
    if (err) throw new Error(err)
    dispatch(html)
})

client.js

import app from './src/main'

// app.$router.onReady(() => {
//     app.$mount('#app')
// })
app.$mount('#app')

vue-cli3 && vue.config.js

const path = require('path')
const fs = require('fs')
const fse = require('fs-extra')
const argv = require('yargs').argv
const webpack = require('webpack')
const ManifestPlugin = require('webpack-manifest-plugin')
const _ = require('lodash')

function resolve (dir) {
    return path.join(__dirname, dir)
}

const renderName = _(argv).has('render') ? argv.render : ''
const renderDir = renderName.length > 0 ? `/${renderName}` : ''
const moduleConfig = JSON.parse(fs.readFileSync('module.json', 'utf8'))
const moduleLowerName = _(moduleConfig.name).toLower()
const assetsDir = `modules/${moduleLowerName}${renderDir}`
const assetsUrl = `${assetsDir}/`
const outputPath = path.join('../../public', assetsDir)
const compiler = require(`./render${renderDir}/compiler`)

const params = {
    renderName,
    renderDir,
    moduleConfig,
    moduleLowerName,
    assetsDir,
    assetsUrl,
    outputPath
}

// const getBaseUrl = (host, port) => process.env.NODE_ENV === 'development'
//     ? `http://${host}:${port}/${assetsUrl}` : `/${assetsUrl}`

if (process.env.NODE_ENV === 'development') {
    if (fse.pathExistsSync(outputPath)) fse.removeSync(outputPath)
    let hot = path.join(outputPath, 'hot')
    fse.ensureFileSync(hot)
    fs.chmodSync(hot, '0755')
}
module.exports = {
    baseUrl: `/${assetsUrl}`,
    outputDir: outputPath,
    devServer: {
        publicPath: `http://localhost:8080/${assetsUrl}`,
        headers: {
            'Access-Control-Allow-Origin': '*'
        }
    },
    chainWebpack: config => {
        if (process.env.NODE_ENV === 'development') {
            config.output.publicPath(`http://localhost:8080/${assetsUrl}`)
        }
        config.entryPoints.delete('app')

        config.resolve.alias.set('@', resolve(`render${renderDir}/src`))
        config.module
            .rule('gql')
            .test(/\.(gql|graphql)$/)
            .include
            .add(resolve('render'))
            .add(resolve('test'))
        config.devtool('cheap-module-eval-source-map')

        config.plugins.delete('html')
            .delete('preload')
            .delete('prefetch')
            .end()
            // .plugin('provide')
            // .use(webpack.ProvidePlugin, [{
            //     $: 'jquery',
            //     jQuery: 'jquery',
            //     _: 'lodash'
            // }])
            // .end()
            .plugin('manifest')
            .use(ManifestPlugin, [{
                writeToFileEmit: true,
                filter: ({ isInitial, isModuleAsset }) => {
                    return isInitial && !isModuleAsset
                },
                generate: (seed, files) => files.reduce(
                    (manifest, { name, path }) => {
                        let ext = path.split('.').pop()
                        let key = ext ? `/${ext}/${name}` : `/${name}`
                        return {
                            ...manifest,
                            [key]: process.env.NODE_ENV === 'development'
                                ? path : path.replace(assetsUrl, '')
                        }
                    },
                    seed
                )
            }])
        if (process.env.NODE_ENV === 'production') {
            config.optimization.splitChunks({
                cacheGroups: {
                    vendors: {
                        name: `vendor`,
                        test: /[\\/]node_modules[\\/]/,
                        priority: -10,
                        chunks: 'initial'
                    },
                    common: {
                        name: `common`,
                        minChunks: 2,
                        priority: -20,
                        chunks: 'initial',
                        reuseExistingChunk: true
                    }
                }
            }).runtimeChunk({
                name: 'manifest'
            })
        }
        compiler(config, params)
    }
}

compiler file

module.exports = function (config, { renderDir }) {
    config.entry('client').add(`./render${renderDir}/client.js`)
    config.entry('server').add(`./render${renderDir}/server.js`)
}

assetic function


if (!function_exists('assetic')) {

    function assetic($path, $manifestDirectory = '', $hotLoad = true)
    {
        static $moduleFests = [];
        if (!Str::startsWith($path, '/')) {
            $path = "/{$path}";
        }

        $manifestPath = public_path($manifestDirectory . '/manifest.json');

        if (!isset($moduleFests[$manifestPath])) {
            if (!file_exists($manifestPath))
                throw new Exception('The Mix manifest does not exist.');

            $moduleFests[$manifestPath] = json_decode(file_get_contents($manifestPath), true);
        }

        $manifest = $moduleFests[$manifestPath];

        if (file_exists(public_path($manifestDirectory . '/hot')))
            return !$hotLoad ? null : new HtmlString($manifest[$path]);

        if (!isset($manifest[$path]))
            report(new Exception("Unable to locate Mix file: {$path}."));

        return new HtmlString($manifestDirectory . $manifest[$path]);
    }
}

errors

7.2.3-1+ubuntu16.04.1+deb.sury.org+1589.49ms6.74MBGET {path?}
The command "/usr/bin/node /home/vagrant/code/gkr/storage/app/ssr/ffeb939d8da979a357015fbda03e1188.js" failed. Exit Code: 1(General error) Working directory: /home/vagrant/code/gkr/public Output: ================ Error Output: ================ /home/vagrant/code/gkr/storage/app/ssr/ffeb939d8da979a357015fbda03e1188.js:1 (function (exports, require, module, filename, dirname) { var dispatch = console.log;var process = process || { env: {} };process.env.NODE_ENV = "production";process.env.VUE_ENV = "server";var context = {"url":"/"};(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[4],{1:function(e,n,c){e.exports=c("CvHz")},CvHz:function(module,webpack_exports,webpack_require){"use strict";eval('webpack_require.r(webpack_exports);\n/* harmony import */ var src_main__WEBPACK_IMPORTED_MODULE_0 = webpack_require("a0+3");\n/* harmony import */ var vue_server_renderer_basic__WEBPACK_IMPORTED_MODULE_1 = webpack_require("kPwN");\n/* harmony import / var vue_server_renderer_basic__WEBPACK_IMPORTED_MODULE_1___default = /#PURE*/webpack_require.n(vue_server_renderer_basic__WEBPACK_IMPORTED_MODULE_1_);\n\n\n_src_main__WEBPACK_IMPORTED_MODULE_0__[/* default */ "a"].$router.push(context.url);\nvue_server_rende ReferenceError: window is not defined at Object. (/home/vagrant/code/gkr/storage/app/ssr/ffeb939d8da979a357015fbda03e1188.js:1:221) at Module._compile (module.js:652:30) at Object.Module._extensions..js (module.js:663:10) at Module.load (module.js:565:32) at tryModuleLoad (module.js:505:12) at Function.Module._load (module.js:497:3) at Function.Module.runMain (module.js:693:10) at startup (bootstrap_node.js:188:16) at bootstrap_node.js:609:3 (View: /home/vagrant/code/gkr/modules/Dashboard/template/views/index.blade.php)
/home/vagrant/code/gkr/vendor/symfony/process/Process.php#223

Active

Is this repo still active?

Not working after php artisan config:cache

Package not run when using chached config (php artisan config:cache).

before run php artisan config:cache, content is rendered in server side
image

after run php artisan config:cache, only shell template rendered, content not rendered
image

dump config ssr dd(config('ssr')); (before or after, return is same)
image

Disabling Javascript should still populate the items on DOM

Hi Spatie,

Thanks again for your great package.
I tried it using react example provided in https://github.com/spatie/laravel-server-side-rendering-examples/
I disabled javascript in the Chrome browser and the list doesn't get populated. Is that normal behavior?
As the SEO crawlers, don't wait for JS and there are no dom elements for the list data from server added. There is however data in the window.PRELOADED_STATE. My impression with SSR is that the DOM has the data that is rendered by React components before hand.

Support mix.extract() ?

Thank you make this awesome package !

One question; is this package support mix.extract?
how can I make manifest.js & vendor.js work in SSR?

Please help ! thanks~

How to use SSR with Blade engine?

Thank you for providing this awesome package!

I wonder, how do you server-side render when one is using both, Vue components and Blade engine?

For example, this is how my master file looks:

<html>
    <head>
        <title>My server side rendered app</title>
        <script defer src="{{ mix('app-client.js') }}">
    </head>
    <body>
        <div id="app">
            <navigation>
                <nav-item>@lang('Home')<nav-item>
                <nav-item>@if(Auth::check())@lang('Dashboard')@else @lang('Login') @endif </nav-item>
            <navigation>
            @yield('content')
            <flash message="{{ $message }}"></flash>
       </div>
    </body>
</html> 

Since I can't put any Blade syntax into my App.vue nor the $message value from the controller, I can't just use

<html>
    <head>
        <title>My server side rendered app</title>
        <script defer src="{{ mix('app-client.js') }}">
    </head>
    <body>
        {!! ssr('js/app.vue') !!}
    </body>
</html> 

Is using Blade syntax and using values from controller still possible when using SSR?

How to do ajax calls?

Hi, first of all I want to thank you as it takes a lot of effort to make such an amazing package. Secondly, I'm sorry if this is not the proper place for my question. Currently, our system is filtering data from our API through axios calls and I was tasked to implement server-side rendering to improve SEO and still fetch the data when javascript is disabled in the browser. However, I am not sure how I can implement that (if possible) through V8 and your package as this is my first time diving into something like this.

Any help would be greatly appreciated.

Node path for Linux

What should I put on the node path? Should I like, put the nodejs directory (/usr/bin/node)?

Multiple entry files

Hello

What do you think about new feature - multiple entry files?

So,

{!! ssr('js/app-server.js')
    ->entry('js/app-server2.js')
    ->entry('js/app-server3.js')
    // If ssr fails, we need a container to render the app client-side
    ->fallback('<div id="app"></div>')
->render() !!}

Is it possible to implement some functionality like this?
Does it make sense (for existing projects)?

how to use axios in ssr

export default {
    data () {
        return {
            items: []
        }
    },
    created () {
        this.login()
    },
    methods: {
        login () {
            let self = this
            this.http.get('test')
            .then(function (response) {
                self.items = response.data
            })
            .catch(function (error) {
                console.log(error);
            });

        }
    }
};

image

Node path on windows

Hello,

I have followed all the steps in the documentation, but are still returning to the fallback.

My .env: NODE_PATH="C:\Program Files\nodejs"

Blade:

<!doctype html>
<html lang="{{ app()->getLocale() }}">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Laravel</title>
    <link rel="stylesheet" href="{{ mix('css/app.css') }}">
    <script defer src="{{ mix('js/app-client.js') }}"></script>
  </head>
  <body>
    {!! ssr('js/app-server.js')->fallback('<div id="app"></div>')->render() !!}
  </body>
</html>

v-if mutating router-link to

Version

3.0.2

Steps to reproduce

Just add an li using v-if, and then try change the value of variable, in the example bellow update start with value 0, I can add a button to increment or decrement it, and get error about mutating :for from router-link.

<li v-if="update" id="dashboard-menu-top-updates">
	<router-link :to="{ name: 'Update' }" :exact="$route.name === 'Update'">Atualizações</router-link>
</li>

What is expected?

The expected is render or remove the element without errors about mutating ":to" from router-link

What is actually happening?

The li is correctly rendered as wished, but make a lot of erros on console about mutating ":to" from router-link.

Error:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "to"

Object of class Spatie\Ssr\Renderer could not be converted to string

Thanks for making a package to enable SSR for Laravel!
I tried to follow the instructions, but when I try to view my app in the browser I get the following exception:

Object of class Spatie\Ssr\Renderer could not be converted to string

As in your installation guide, I´ve put this code in the body tag of my blade file, which causes the error:

{!! ssr('js/app-server.js') !!}

I try to use Node as the engine. Do you have any advice how to fix this? Thank you!

SSR not working - just shows Empty screen

Hello! I try make ssr by Your package, but content not render on page. Errors and warning no!
Title of page is!

My code app.blade.php:
`
{{-- Entrypoints app --}}
<script src="/_nuxt/53245307c716d2b6d1a7.js"></script>
<script src="/_nuxt/2072e2dd77a468210c2a.js"></script>
<script src="/_nuxt/69075bae224098322cdb.js"></script>
<script src="/_nuxt/b4fdb60abb9b8bcc3665.js"></script>

{{-- Entrypoint server --}}
{!! ssr('_nuxt/server/server.js')->render() !!}

`

.env
...
NODE_PATH=C:/Program%Files/nodejs/node.exe
...

Снимок2

Page Source Not Showing Full HTML

Hello
I followed the steps and got to render the default example component.
However the page source is not showing the full html.

`

<head>
    <title>My server side rendered app</title>
    <script defer src="/js/app-client.js?id=7b9c9df636c18d74773f"></script>
</head>
<body>   
<div id="app">     
</div>
'

Kindly assist.
Screenshot_2019-06-19 My server side rendered app

Server - generated code not appearing in source code

Hey,
I'm new to the concept of SSR, so correct me if i'm wrong, but as far as I know, the point of it is to have the app's code rendered on the initial page load, without having to wait for javascript to compile.
I'm trying to make my laravel + vue spa app rendered on the server, I'm trying to use this package, integrated everything (I think), all seems to work, but when i'm looking at the source code for the page, I only get an empty element.
Same thing happens when compiling Spatie's laravel-server-side-rendering-examples.

vue

Also, the page is empty when javascript is disabled.
As I said, I am quite new to the concept so please forgive me if it's a dumb question, i'm only concerned about SEO, and thought rendering my app on server would ease my mind a bit, but now I don't really understand what's different if I get no content on initial page load with no js.

Thanks!

Unexpected Error

I am facing this issue. Since it is not showing any file to look I don't know where the error is occurring.
This issue came unexpectedly. I was working the other night, it was working fine and when I run npm run watch the next morning, it is showing this error.

> @ watch /home/ubuntu/workspace
> cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js

undefined:4
}
^

SyntaxError: Unexpected token } in JSON at position 50
    at Object.parse (native)
    at babelrc (/home/ubuntu/workspace/node_modules/laravel-mix/src/config.js:212:36)
    at global.tap (/home/ubuntu/workspace/node_modules/laravel-mix/src/helpers.js:10:5)
    at Object.babel (/home/ubuntu/workspace/node_modules/laravel-mix/src/config.js:210:13)
    at module.exports (/home/ubuntu/workspace/node_modules/laravel-mix/src/builder/webpack-rules.js:15:33)
    at WebpackConfig.buildRules (/home/ubuntu/workspace/node_modules/laravel-mix/src/builder/WebpackConfig.js:81:41)
    at WebpackConfig.build (/home/ubuntu/workspace/node_modules/laravel-mix/src/builder/WebpackConfig.js:25:14)
    at Object.<anonymous> (/home/ubuntu/workspace/node_modules/laravel-mix/setup/webpack.config.js:26:38)
    at Module._compile (module.js:577:32)
    at Object.Module._extensions..js (module.js:586:10)
    at Module.load (module.js:494:32)
    at tryModuleLoad (module.js:453:12)
    at Function.Module._load (module.js:445:3)
    at Module.require (module.js:504:17)
    at require (internal/module.js:20:19)
    at requireConfig (/home/ubuntu/workspace/node_modules/webpack/bin/convert-argv.js:97:18)

Error: TypeError: Cannot read property 'render' of undefined

Npm run build successfully.I have a problem while rendering.I have no idea about the reason cause it.Could someone help me to check.Thank you~

// debug info
Facade\Ignition\Exceptions\ViewException: The command "/usr/local/bin/node /Users/jialinzhang/code/lavuetify-blog/storage/app/ssr/4957fb2b412b1220dbeb1d7e11e781d9.js" failed.

Exit Code: 1(General error)

Working directory: /Users/jialinzhang/code/lavuetify-blog/public

Output:
================


Error Output:
================
/Users/jialinzhang/code/lavuetify-blog/storage/app/ssr/4957fb2b412b1220dbeb1d7e11e781d9.js:4
!function(e){var t={};function r(n){if(t[n])return t[n].exports;var a=t[n]={i:n,l:!1,exports:{}};return e[n].call(a.exports,a,a.exports,r),a.l=!0,a.exports}r.m=e,r.c=t,r.d=function(e,t,n)
.
.
.
n=r("bUC5"),a=r("kPwN");r.n(a)()(n.default,(function(e,t){if(e)throw new Error(e);dispatch(t)}))},yLpj:function(e,t){var r;r=function(){return this}();try{r=r||new Function("return this")()}catch(e){"object"==typeof window&&(r=window)}e.exports=r}});
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            

Error: TypeError: Cannot read property 'render' of undefined
    at /Users/jialinzhang/code/lavuetify-blog/storage/app/ssr/4957fb2b412b1220dbeb1d7e11e781d9.js:4:252658
    at /Users/jialinzhang/code/lavuetify-blog/storage/app/ssr/4957fb2b412b1220dbeb1d7e11e781d9.js:4:252402
    at Module.qLbf (/Users/jialinzhang/code/lavuetify-blog/storage/app/ssr/4957fb2b412b1220dbeb1d7e11e781d9.js:4:252621)
    at r (/Users/jialinzhang/code/lavuetify-blog/storage/app/ssr/4957fb2b412b1220dbeb1d7e11e781d9.js:4:110)
    at Object.2 (/Users/jialinzhang/code/lavuetify-blog/storage/app/ssr/4957fb2b412b1220dbeb1d7e11e781d9.js:4:949)
    at r (/Users/jialinzhang/code/lavuetify-blog/storage/app/ssr/4957fb2b412b1220dbeb1d7e11e781d9.js:4:110)
    at /Users/jialinzhang/code/lavuetify-blog/storage/app/ssr/4957fb2b412b1220dbeb1d7e11e781d9.js:4:910
    at Object.<anonymous> (/Users/jialinzhang/code/lavuetify-blog/storage/app/ssr/4957fb2b412b1220dbeb1d7e11e781d9.js:4:919)
    at Module._compile (internal/modules/cjs/loader.js:1185:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1205:10)
 (View: /Users/jialinzhang/code/lavuetify-blog/resources/views/ssr.blade.php) in file /Users/jialinzhang/code/lavuetify-blog/vendor/symfony/process/Process.php on line 252

composer & package
"laravel/framework": "^7.0",
"spatie/laravel-server-side-rendering": "^1.4"
"vue-server-renderer": "^2.6.11",
"vuer": "^2.6.11",

// ssr.blade.php
<!doctype html>
<html lang="{{ app()->getLocale() }}">
  <head>
    <title>My server side rendered app</title>
      <!-- Styles -->
      <link href="{{ mix('css/app.css', 'assets') }}" rel="stylesheet">
      <script defer src="{{ mix('js/app-client.js', 'assets') }}"></script>
  </head>
  <body>
  {!! ssr('assets/js/app-server.js')->render() !!}
  </body>
</html>
// app.js
import Vue from "vue";

export default () =>
  new Vue({
    template: `
    <div>Hello, world!</div>
  `
  });
// app-server.js
import app from './app';
import renderVueComponentToString from 'vue-server-renderer/basic';

renderVueComponentToString(app, (err, html) => {
    if (err) {
        throw new Error(err);
    }
    dispatch(html);
});
// app-client.js
import createApp from "./app";
const app = createApp();
app.$mount("#app");

Unresolvable dependency error when using V8 engine

Hi there! When using the V8 engine, I run in the following exception;

Unresolvable dependency resolving [Parameter #0 [ <optional> $object_name ]] in class V8Js

It looks like I can solve the issue by adding;

$this->app->singleton(V8::class, function () {
    return new V8(new \V8Js());
});

But I do not know if that's the "Laravel" way.

How can I use axios? A get the error TypeError: adapter is not a function at dispatchRequest.

When sending a get request, the promise is redirected with an error:

TypeError: adapter is not a function at dispatchRequest (/Users/vladimir/Programming/GR/lawsystem.test/storage/app/ssr/28d918e4632a3b48ddcaf89db6812bd7.js:1058:10) TypeError: adapter is not a function at dispatchRequest (/Users/vladimir/Programming/GR/lawsystem.test/storage/app/ssr/28d918e4632a3b48ddcaf89db6812bd7.js:1058:10) at async Promise.all (index 0) "

webpack:

const mix = require('laravel-mix');

mix.js('resources/js/CustomerPortal/app-server.js', 'public/js/customer-portal');
mix.webpackConfig({
    target: 'node',
});

Here I make get request.

getServices() {
      return axios.get('https://lawsystem.grani-riska.ru/api/services/get',
      ).then(response => {
          return response;
      }).catch(error => {
          console.log(error); //here I catch the error
      })
  },

app.js

import Vue from 'vue';
import store from '../Core/store';
import VueRouter from 'vue-router';

const router = new VueRouter({
    mode: 'history',
    routes: routes.concat(serviceRoutes.routes)
});

const app = new Vue({
    render: h => h(AppComponent),
    router,
    store
});

export default {app, router, store}

app-server.js

import app from './app'
import renderVueComponentToString from 'vue-server-renderer/basic';

new Promise((resolve, reject) => {
    app.router.push(context.url);
    app.router.onReady(() => {
        const matchedComponents = app.router.getMatchedComponents();
        if (!matchedComponents.length) {
            return reject(app.app);
        }

        context.rendered = () => {
            context.state = app.store.state
        };

        resolve(app.app);
    }, reject);
}).then(app => {
    renderVueComponentToString(app, (err, html) => {
        if (err) {
            throw new Error(err);
        }

        dispatch(html);
    });
}).catch((err) => {
    throw new Error(err);
});

Version
axios - 0.19.2
vue - 2.6.11
laravel-server-side-rendering = 1.3

How can I solve this?

ErrorException (E_ERROR)
The command "/usr/local/bin/node /Users/lucassimines/Laravel/Dashboard New/storage/app/ssr/f2d73b9786b42d203679a6a382d15b85.js" failed. Exit Code: 1(General error) Working directory: /Users/lucassimines/Laravel/Dashboard New/public Output: ================ Error Output: ================ module.js:538 throw err; ^ Error: Cannot find module '/Users/lucassimines/Laravel/Dashboard' at Function.Module._resolveFilename (module.js:536:15) at Function.Module._load (module.js:466:25) at Function.Module.runMain (module.js:676:10) at startup (bootstrap_node.js:187:16) at bootstrap_node.js:608:3 (View: /Users/lucassimines/Laravel/Dashboard New/resources/views/frontend/index.blade.php)

ReactJS render issue? Facade\Ignition\Exceptions\ViewException

Hi, This is my first time to write an issue, actually I'm not sure if this is an issue or my configuration is wrong.

I'm actually using Laravel + ReactJS

Here's my composer.json

"php": "^7.2.5",
"laravel/framework": "^7.0",
 "laravel/tinker": "^2.0",
"laravel/ui": "^2.0",
"spatie/laravel-server-side-rendering": "^1.4",

Followed everything on the example and when I tried to run npm run prod and run it on my localhost the error shows me

Facade\Ignition\Exceptions\ViewException
The command "node C:\xampp7.4.2\htdocs\polln\storage\app/ssr\29ef9693d18a4efde5e940aeab495f93.js" failed. Exit Code: 1(General error) Working directory: C:\xampp7.4.2\htdocs\polln\public Output: ================ Error Output: ================ C:\xampp7.4.2\htdocs\polln\storage\app\ssr\29ef9693d18a4efde5e940aeab495f93.js:4
 !function(e){function t(t){for(var r,i,o=t[0],a=t[1],u=0,c=[];u<o.length;u++)i=o[u],Object.prototype.hasOwnProperty.call(n,i)&&n[i]&&c.push(n[i][0]),n[i]=0;for(r in a)Object.prototype.hasOwnProperty.call(a,r)&&(e[r]=a[r]);for(s&&s(t);c.length;)c.shift()()}var r={},n={8:0};function i(t){if(r[t])return r[t].exports;var n=r[t]={i:t,l:!1,exports:{}};return e[t].call(n.exports,n,n.exports,i),n.l=!0,n.exports}i.e=function(e){var t=[],r=n[e];if(0!==r)if(r)t.push(r[2]);else{var o=new Promise((function(t,i){r=n[e]=[t,i]}));t.push(r[2]=o);var a,u=document.createElement("script");u.charset="utf-8",u.timeout=120,i.nc&&u.setAttribute("nonce",i.nc),u.src=function(e){return i.p+""+({}[e]||e)+".js"}(e);var s=new Error;a=function(t){u.onerror=u.onload=null,clearTimeout(c);var r=n[e];if(0!==r){if(r){var i=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src;s.message="Loading chunk "+e+" failed.\n("+i+": "+o+")",s.name="ChunkLoadErr
 
 ReferenceError: window is not defined
 at C:\xampp7.4.2\htdocs\polln\storage\app\ssr\29ef9693d18a4efde5e940aeab495f93.js:4:1923
 at Object.<anonymous> (C:\xampp7.4.2\htdocs\polln\storage\app\ssr\29ef9693d18a4efde5e940aeab495f93.js:4:2058)
 at Module._compile (internal/modules/cjs/loader.js:778:30)
 at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
 at Module.load (internal/modules/cjs/loader.js:653:32)
 at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
 at Function.Module._load (internal/modules/cjs/loader.js:585:3)
 at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)
 at startup (internal/bootstrap/node.js:283:19)
 at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)
 (View: C:\xampp7.4.2\htdocs\polln\resources\views\index.blade.php)

Here's my client.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import AppProvider from './ApolloProvider';

if (document.getElementById('app')) {
	ReactDOM.render(
		<AppProvider>
			<App />
		</AppProvider>,
		document.getElementById('app'),
	);
}

Here's my server.js

import React from 'react';
import ReactDOMServer from 'react-dom/server';
import App from './App';
import AppProvider from './ApolloProvider';

const html = ReactDOMServer.renderToString(
	<div id="app">
		<AppProvider>
			<App />
		</AppProvider>
	</div>,
);

dispatch(html);

My node version: 10.16.3

I'm kinda desperate because I need SSR for the SEO part. Much appreciate if anyone could help me out

Edit:
My node js path is defined in Environment Variables

My .env

NODE_PATH=node

How to make this work with Twig?

I want to use this package with my existing Laravel app (Octobercms), but with Twig templating I can't seem to make it work. Is there anything I should be doing to make it work?

Thanks for the help

error laravel ssr

I ran into the same problem as #23.
Php version: 7.2
Node Version: 10.15.3
System: Windows 7
My env configuration: NODE_PATH = node

Error: failed. Exit Code: 1(General error) Working directory

Ssr config:

return [
     'enabled' => true
     'debug' => true
     'mix' => true
     'engine' => \ Spatie \ Ssr \ Engines \ Node :: class,
   
     'node' => [
         'node_path' => env ('NODE_PATH', '/ usr / local / bin / node'),
         'temp_path' => storage_path ('app / ssr'),
     ],
  
     'context' => [],
     'env' => [
         'NODE_ENV' => 'production',
         'VUE_ENV' => 'server',
     ],
];

Node+React How To Catch Tree Errors?

Hi, nice package but I'm struggling with debugging;

React componentDidCatch doesn't fire on server, so some workaround is necessary for ssr; how can we catch tree render errors using this library and node?
People recommend wrapping renderToString in try-catch, but it doesn't catch all errors and renderToString just returns empty string if something failed, most of the times

What is possible to do?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.