Skip to content

Vue + Laravel && SSR + Code-splitting == is real? #238

Open
@yurshery

Description

@yurshery

I have an app with Vue+Vuex+Vue-router and Laravel+spatie/laravel-server-side-rendering.

It works well with SSR and it renders well to:

  1. app.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Test SSR</title>
    <link href="https://github.com/%7B%7B%20mix('/atd/css/main.css') }}" type="text/css" rel="stylesheet">
    <script>window.ssrData = @json($data);</script>
    <script defer src="https://github.com/%7B%7B%20mix('atd/js/app-client.js') }}"></script>
</head>
<body>
    {!!
        ssr('atd/js/app-server.js')
            ->context(['data' => $data])
            ->fallback('<div id="app"></div>')
            ->render()
    !!}
</body>
</html>
  1. routes
import HomePage from '../../pages/HomePage';
import Page404 from '../../pages/Page404';
import AppMainHeader from '../../components/layout/AppMainHeader';
import AppMainFooter from '../../components/layout/AppMainFooter';

export default [
    {
        path: '/',
        name: 'HomePage',
        components: {
            default: HomePage,
            'main-header': AppMainHeader,
            'main-footer': AppMainFooter,
        },
    },
    {
        path: '/404',
        name: 'Page404',
        component: Page404,
    },
    {
        path: '*',
        redirect: { name: 'Page404' },
    },
];
  1. app-server.js
/* eslint-disable */
import app from './app';
import router from './router';
import store from './store';
import renderVueComponentToString from 'vue-server-renderer/basic';

new Promise((resolve, reject) => {
    router.push(context.url);

    store.commit('ssrData', context.data);

    router.onReady(() => {
        const matchedComponents = router.getMatchedComponents();

        if (!matchedComponents.length) {

            return reject({ code: 404 });
        }
        resolve(app);

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

            dispatch(html);
        });
    });
  1. webpack.mix.js
const mix = require('laravel-mix');
const path = require('path');

const SVGSpritemapPlugin = require('svg-spritemap-webpack-plugin');
const ImageminPlugin = require('imagemin-webpack-plugin').default;
const CopyWebpackPlugin = require('copy-webpack-plugin');
const imageminMozjpeg = require('imagemin-mozjpeg');

mix.js('resources/atd/app-client.js', 'public/atd/js')
    .js('resources/atd/app-server.js', 'public/atd/js')
    // .sourceMaps()
    .options({
        extractVueStyles: 'public/atd/css/main.css',
    })
    .browserSync({
        proxy: 'ssr-test.loc',
        open: false,
        files: 'public/atd',
    })
    .webpackConfig({
        resolve: {
            alias: {
                vue$: 'vue/dist/vue.common.js',
            },
        },
        module: {
            rules: [
                {
                    test: /\.pug$/,
                    loader: 'pug-plain-loader',
                },
            ],
        },
        plugins: [
            new SVGSpritemapPlugin('resources/atd/assets/svg/**/*.svg', {
                output: {
                    filename: 'atd/svg/icon-sprite.svg',
                    // svg4everybody: false,
                    svgo: {
                        plugins: [
                            {
                                removeTitle: true,
                            },
                            {
                                removeAttrs: {
                                    attrs: '(stroke|fill)',
                                },
                            },
                        ],
                    },
                },
                sprite: {
                    generate: {
                        symbol: '-',
                        use: true,
                        view: true,
                    },
                },
                styles: path.join(__dirname, 'resources/atd/assets/sass/sprites.scss'),
            }),
            new CopyWebpackPlugin([
                {
                    from: 'resources/atd/assets/images',
                    to: 'atd/images',
                },
            ]),
            new ImageminPlugin({
                test: /\.(jpe?g|png|gif)$/i,
                disable: process.env.NODE_ENV !== 'production', // Disable during development
                plugins: [
                    imageminMozjpeg({
                        quality: 65,
                    }),
                ],
            }),
        ],
    });

// Production mode
if (mix.inProduction()) {
    mix.version(['public/atd/images', 'public/atd/svg']);
}

But if I try to do it with lazy-load with the same code only routes changed for code-splitting:

import HomePage from '../../pages/HomePage';
import AppMainHeader from '../../components/layout/AppMainHeader';
import AppMainFooter from '../../components/layout/AppMainFooter';

export default [
    {
        path: '/',
        name: 'HomePage',
        components: {
            default: HomePage,
            'main-header': AppMainHeader,
            'main-footer': AppMainFooter,
        },
    },
    {
        path: '/404',
        name: 'Page404',
        // LAZY LOAD MODEL
        component: () => import('../../pages/Page404'),
    },
    {
        path: '*',
        redirect: { name: 'Page404' },
    },
];

It always use fallback ssr('atd/js/app-server.js')->context(['data' => $data])->fallback('<div id="app"></div>')->render() with app-client.js and I don’t have SSR…
Is it real to do code-splitting with SSR?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions