Skip to content

Commit

Permalink
injecting assets via manifests with createBundleRenderer
Browse files Browse the repository at this point in the history
VERY IMPORTANT NOTE: at this commit date, in order to work properly with
VueSSRServerPlugin on webpack.ssr.config.js must use WEBPACK VERSION 4,
version 5 has an issue on fetching app entry file and output.libraryTarget,
more details check vuejs/vue#11718
  • Loading branch information
carloscorti committed Jan 26, 2021
1 parent 0a11483 commit 81b8ea4
Show file tree
Hide file tree
Showing 12 changed files with 3,907 additions and 929 deletions.
13 changes: 6 additions & 7 deletions build/webpack.base.config.js
Expand Up @@ -4,7 +4,9 @@ const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plug
const MiniCssExtraxtPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const VueSSRClientPlugin = require('vue-server-renderer/client-plugin');
const webpack = require('webpack');

// let executionMode = 'production';
// let sourceMapStatus = 'source-map';
Expand Down Expand Up @@ -84,12 +86,9 @@ module.exports = (env, argv) => {
filename: 'assets/css/[name].[contenthash].css'
}),

new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../', 'template', 'index.html'),
filename: path.resolve(__dirname, '../', 'public', 'index.html'),
inject: true,
favicon: path.resolve(__dirname, '../', 'template', 'favicon.png')
})
// This plugins generates `vue-ssr-client-manifest.json` in the
// output directory.
new VueSSRClientPlugin()
],

optimization: {
Expand Down
12 changes: 8 additions & 4 deletions build/webpack.ssr.config.js
@@ -1,18 +1,23 @@
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

const webpack = require('webpack');

const VueSSRServerPlugin = require('vue-server-renderer/server-plugin');

const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
target: 'node',
// externals: nodeExternals({ allowlist: /\.css$/ }),
externals: nodeExternals(),
entry: {
App: path.resolve(__dirname, '../', 'src', 'server-entry.js')
},

output: {
path: path.resolve(__dirname, '../', 'ssr'),
filename: '[name].js',
libraryTarget: 'commonjs2'
},

Expand Down Expand Up @@ -44,9 +49,8 @@ module.exports = {
},

plugins: [
new VueSSRServerPlugin(),
new VueLoaderPlugin(),
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1
})
new CleanWebpackPlugin()
]
};
File renamed without changes
4,729 changes: 3,867 additions & 862 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions package.json
Expand Up @@ -18,7 +18,6 @@
"axios": "0.21.1",
"bulma": "0.9.1",
"express": "4.17.1",
"serialize-javascript": "5.0.1",
"vue": "2.6.12",
"vue-router": "3.4.9",
"vue-server-renderer": "2.6.12",
Expand All @@ -41,7 +40,6 @@
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "4.2.1",
"eslint-plugin-standard": "5.0.0",
"html-webpack-plugin": "4.5.1",
"ignore-loader": "0.1.2",
"mini-css-extract-plugin": "1.3.3",
"node-sass": "5.0.0",
Expand All @@ -51,7 +49,7 @@
"terser-webpack-plugin": "5.0.3",
"vue-loader": "15.9.6",
"vue-template-compiler": "2.6.12",
"webpack": "5.11.1",
"webpack": "4.44.2",
"webpack-cli": "4.3.1",
"webpack-dev-middleware": "4.0.2",
"webpack-hot-middleware": "2.25.0",
Expand Down
36 changes: 13 additions & 23 deletions server.js
@@ -1,7 +1,6 @@
const express = require('express');
const path = require('path');
const fs = require('fs');
const serialize = require('serialize-javascript');

const { createBundleRenderer } = require('vue-server-renderer');

Expand All @@ -11,47 +10,38 @@ const config = {

const app = express();

const indexHTML = fs.readFileSync(
path.join(__dirname, 'public', 'index.html'),
const template = fs.readFileSync(
path.join(__dirname, 'template', 'index.html'),
'utf-8'
);

const appBundle = fs.readFileSync(
path.join(__dirname, 'ssr', 'App.js'),
'utf-8'
);
const appBundle = require('./ssr/vue-ssr-server-bundle.json');

const clientManifest = require('./public/vue-ssr-client-manifest.json');

app.use(express.static('public'));
app.use('/icon', express.static(path.join(__dirname, 'images')));

if (process.env.NODE_ENV === 'development') {
// require('./build/dev-server')(app);
console.info(`Running on ${process.env.NODE_ENV} mode`);
}

app.get('/*', (req, res) => {
const renderer = createBundleRenderer(appBundle);
const renderer = createBundleRenderer(appBundle, {
runInNewContext: false,
template,
clientManifest
});

const context = { url: req.url };

renderer.renderToString(context, (err, html) => {
if (err) {
console.log(err);
console.error(err);
return res.status(500).send('server error');
}

let ssrIndexHTML = indexHTML.replace('{{APP}}', html);
ssrIndexHTML = ssrIndexHTML.replace(
'{{STATE}}',
`<script type="text/javascript">window.__INITIAL_STATE__=${serialize(
context.state,
{
isJSON: true
}
)}</script>`
);

res.write(ssrIndexHTML);
res.end();
res.send(html);
});
});

Expand Down
16 changes: 2 additions & 14 deletions src/app.js
@@ -1,26 +1,14 @@
import Vue from 'vue';
import AppLayout from './theme/AppLayout.vue';
// import router from './router';
import { createRouter } from './router';
// import store from './vuex-state';
import { createStore } from './vuex-state';
import './styles/index.scss';

// Vue.config.productionTip = false;

if (typeof window !== 'undefined') {
console.log('on browser');
Vue.config.devtools = true;
}

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

// export { app, router, store };

const createApp = () => {
const router = createRouter();

Expand All @@ -30,7 +18,7 @@ const createApp = () => {
store,
router,
// render: (h) => h(AppLayout),
...AppLayout
...AppLayout,
});
return { app, router, store };
};
Expand Down
7 changes: 1 addition & 6 deletions src/client-entry.js
@@ -1,17 +1,12 @@
// import { app, router, store } from './app';
import { createApp } from './app';

const { app, router, store } = createApp();

if (window.__INITIAL_STATE__) {
// We initialize the store state with the data injected from the server
// console.log(store);
// store.replaceState(window.__INITIAL_STATE__);
// Initialize the store state with the data injected from the server
store.replaceState(window.__INITIAL_STATE__);

delete window.__INITIAL_STATE__;

console.log(store);
}

router.onReady(() => {
Expand Down
6 changes: 2 additions & 4 deletions src/server-entry.js
Expand Up @@ -25,16 +25,14 @@
// }
// resolve(app);
// });

// // the Promise should resolve to the app instance so it can be rendered
// }, reject);
// });
// // return app;
// };

import { createApp } from './app';

export default context => {
export default (context) => {
const { app, router, store } = createApp();
// console.log(context);
return new Promise((resolve, reject) => {
Expand All @@ -43,7 +41,7 @@ export default context => {
router.onReady(() => {
context.rendered = () => {
context.state = store.state;
console.log(context.state);
// console.log(context.state);
};

resolve(app);
Expand Down
2 changes: 1 addition & 1 deletion src/theme/AppLayout.vue
@@ -1,5 +1,5 @@
<template>
<div>
<div id="app">
<app-header></app-header>

<router-view></router-view>
Expand Down
4 changes: 2 additions & 2 deletions src/vuex-state/modules/posts/index.js
Expand Up @@ -6,9 +6,9 @@ import actions from './actions';

Vue.use(Vuex);

const state = {
const state = () => ({
posts: []
};
});

const getters = {
posts: state => state.posts
Expand Down
7 changes: 4 additions & 3 deletions template/index.html
Expand Up @@ -4,12 +4,13 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
{{STATE}}
<title>Vue SSR</title>
<link href="/icon/favicon.png" rel="icon">
<link href="/icon/favicon.png" rel="apple-touch-icon">
</head>

<body>
<div id="app">{{APP}}</div>
<!--vue-ssr-outlet-->
</body>

</html>

0 comments on commit 81b8ea4

Please sign in to comment.