Skip to content

Commit 81b8ea4

Browse files
committed
injecting assets via manifests with createBundleRenderer
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
1 parent 0a11483 commit 81b8ea4

File tree

12 files changed

+3907
-929
lines changed

12 files changed

+3907
-929
lines changed

build/webpack.base.config.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plug
44
const MiniCssExtraxtPlugin = require('mini-css-extract-plugin');
55
const TerserPlugin = require('terser-webpack-plugin');
66
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
7-
const HtmlWebpackPlugin = require('html-webpack-plugin');
7+
8+
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin');
9+
const webpack = require('webpack');
810

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

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

9594
optimization: {

build/webpack.ssr.config.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
const path = require('path');
22
const nodeExternals = require('webpack-node-externals');
33
const VueLoaderPlugin = require('vue-loader/lib/plugin');
4+
45
const webpack = require('webpack');
56

7+
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin');
8+
9+
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
10+
611
module.exports = {
712
target: 'node',
13+
// externals: nodeExternals({ allowlist: /\.css$/ }),
814
externals: nodeExternals(),
915
entry: {
1016
App: path.resolve(__dirname, '../', 'src', 'server-entry.js')
1117
},
1218

1319
output: {
1420
path: path.resolve(__dirname, '../', 'ssr'),
15-
filename: '[name].js',
1621
libraryTarget: 'commonjs2'
1722
},
1823

@@ -44,9 +49,8 @@ module.exports = {
4449
},
4550

4651
plugins: [
52+
new VueSSRServerPlugin(),
4753
new VueLoaderPlugin(),
48-
new webpack.optimize.LimitChunkCountPlugin({
49-
maxChunks: 1
50-
})
54+
new CleanWebpackPlugin()
5155
]
5256
};
File renamed without changes.

package-lock.json

Lines changed: 3867 additions & 862 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
"axios": "0.21.1",
1919
"bulma": "0.9.1",
2020
"express": "4.17.1",
21-
"serialize-javascript": "5.0.1",
2221
"vue": "2.6.12",
2322
"vue-router": "3.4.9",
2423
"vue-server-renderer": "2.6.12",
@@ -41,7 +40,6 @@
4140
"eslint-plugin-node": "11.1.0",
4241
"eslint-plugin-promise": "4.2.1",
4342
"eslint-plugin-standard": "5.0.0",
44-
"html-webpack-plugin": "4.5.1",
4543
"ignore-loader": "0.1.2",
4644
"mini-css-extract-plugin": "1.3.3",
4745
"node-sass": "5.0.0",
@@ -51,7 +49,7 @@
5149
"terser-webpack-plugin": "5.0.3",
5250
"vue-loader": "15.9.6",
5351
"vue-template-compiler": "2.6.12",
54-
"webpack": "5.11.1",
52+
"webpack": "4.44.2",
5553
"webpack-cli": "4.3.1",
5654
"webpack-dev-middleware": "4.0.2",
5755
"webpack-hot-middleware": "2.25.0",

server.js

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
const express = require('express');
22
const path = require('path');
33
const fs = require('fs');
4-
const serialize = require('serialize-javascript');
54

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

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

1211
const app = express();
1312

14-
const indexHTML = fs.readFileSync(
15-
path.join(__dirname, 'public', 'index.html'),
13+
const template = fs.readFileSync(
14+
path.join(__dirname, 'template', 'index.html'),
1615
'utf-8'
1716
);
1817

19-
const appBundle = fs.readFileSync(
20-
path.join(__dirname, 'ssr', 'App.js'),
21-
'utf-8'
22-
);
18+
const appBundle = require('./ssr/vue-ssr-server-bundle.json');
19+
20+
const clientManifest = require('./public/vue-ssr-client-manifest.json');
2321

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

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

3130
app.get('/*', (req, res) => {
32-
const renderer = createBundleRenderer(appBundle);
31+
const renderer = createBundleRenderer(appBundle, {
32+
runInNewContext: false,
33+
template,
34+
clientManifest
35+
});
3336

3437
const context = { url: req.url };
3538

3639
renderer.renderToString(context, (err, html) => {
3740
if (err) {
38-
console.log(err);
41+
console.error(err);
3942
return res.status(500).send('server error');
4043
}
41-
42-
let ssrIndexHTML = indexHTML.replace('{{APP}}', html);
43-
ssrIndexHTML = ssrIndexHTML.replace(
44-
'{{STATE}}',
45-
`<script type="text/javascript">window.__INITIAL_STATE__=${serialize(
46-
context.state,
47-
{
48-
isJSON: true
49-
}
50-
)}</script>`
51-
);
52-
53-
res.write(ssrIndexHTML);
54-
res.end();
44+
res.send(html);
5545
});
5646
});
5747

src/app.js

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,14 @@
11
import Vue from 'vue';
22
import AppLayout from './theme/AppLayout.vue';
3-
// import router from './router';
43
import { createRouter } from './router';
5-
// import store from './vuex-state';
64
import { createStore } from './vuex-state';
75
import './styles/index.scss';
86

9-
// Vue.config.productionTip = false;
10-
117
if (typeof window !== 'undefined') {
8+
console.log('on browser');
129
Vue.config.devtools = true;
1310
}
1411

15-
// const app = new Vue({
16-
// store,
17-
// router,
18-
// // render: (h) => h(AppLayout),
19-
// ...AppLayout
20-
// });
21-
22-
// export { app, router, store };
23-
2412
const createApp = () => {
2513
const router = createRouter();
2614

@@ -30,7 +18,7 @@ const createApp = () => {
3018
store,
3119
router,
3220
// render: (h) => h(AppLayout),
33-
...AppLayout
21+
...AppLayout,
3422
});
3523
return { app, router, store };
3624
};

src/client-entry.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
1-
// import { app, router, store } from './app';
21
import { createApp } from './app';
32

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

65
if (window.__INITIAL_STATE__) {
7-
// We initialize the store state with the data injected from the server
8-
// console.log(store);
9-
// store.replaceState(window.__INITIAL_STATE__);
6+
// Initialize the store state with the data injected from the server
107
store.replaceState(window.__INITIAL_STATE__);
118

129
delete window.__INITIAL_STATE__;
13-
14-
console.log(store);
1510
}
1611

1712
router.onReady(() => {

src/server-entry.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,14 @@
2525
// }
2626
// resolve(app);
2727
// });
28-
29-
// // the Promise should resolve to the app instance so it can be rendered
3028
// }, reject);
3129
// });
3230
// // return app;
3331
// };
3432

3533
import { createApp } from './app';
3634

37-
export default context => {
35+
export default (context) => {
3836
const { app, router, store } = createApp();
3937
// console.log(context);
4038
return new Promise((resolve, reject) => {
@@ -43,7 +41,7 @@ export default context => {
4341
router.onReady(() => {
4442
context.rendered = () => {
4543
context.state = store.state;
46-
console.log(context.state);
44+
// console.log(context.state);
4745
};
4846

4947
resolve(app);

src/theme/AppLayout.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<div>
2+
<div id="app">
33
<app-header></app-header>
44

55
<router-view></router-view>

src/vuex-state/modules/posts/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import actions from './actions';
66

77
Vue.use(Vuex);
88

9-
const state = {
9+
const state = () => ({
1010
posts: []
11-
};
11+
});
1212

1313
const getters = {
1414
posts: state => state.posts

template/index.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
<head>
55
<meta charset="UTF-8">
66
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7-
<title>Document</title>
8-
{{STATE}}
7+
<title>Vue SSR</title>
8+
<link href="/icon/favicon.png" rel="icon">
9+
<link href="/icon/favicon.png" rel="apple-touch-icon">
910
</head>
1011

1112
<body>
12-
<div id="app">{{APP}}</div>
13+
<!--vue-ssr-outlet-->
1314
</body>
1415

1516
</html>

0 commit comments

Comments
 (0)