Skip to content

Commit dfc735d

Browse files
committed
initial commit
0 parents  commit dfc735d

19 files changed

+6268
-0
lines changed

.babelrc

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"presets": [
3+
["env", { "modules": false }],
4+
"stage-3"
5+
]
6+
}

.editorconfig

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
indent_style = space
6+
indent_size = 2
7+
end_of_line = lf
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true

.gitignore

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.DS_Store
2+
node_modules/
3+
dist/
4+
npm-debug.log
5+
yarn-error.log
6+
7+
# Editor directories and files
8+
.idea
9+
*.suo
10+
*.ntvs*
11+
*.njsproj
12+
*.sln

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Basic project to show issue with vue router in ssr mode when using non-ascii characters in routes

index.html

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<!-- use triple mustache for non-HTML-escaped interpolation -->
5+
{{{ meta }}}
6+
<!-- use double mustache for HTML-escaped interpolation -->
7+
<title>{{ title }}</title>
8+
</head>
9+
<body>
10+
<!--vue-ssr-outlet-->
11+
<script src="dist/build.js"></script>
12+
</body>
13+
</html>

package.json

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"name": "vue-ssr",
3+
"description": "A Vue.js project",
4+
"version": "1.0.0",
5+
"author": "Ejez <[email protected]>",
6+
"license": "MIT",
7+
"private": true,
8+
"scripts": {
9+
"start": "yarn build && yarn start-server",
10+
"build": "yarn build-client && yarn build-server",
11+
"build-client": "cross-env NODE_ENV=development webpack --progress --hide-modules",
12+
"build-server": "cross-env NODE_ENV=development webpack --config webpack.server.config.js --progress --hide-modules",
13+
"start-server": "node server.js"
14+
},
15+
"dependencies": {
16+
"express": "^4.17.1",
17+
"vue": "^2.5.11",
18+
"vue-router": "^3.1.5",
19+
"vue-server-renderer": "^2.6.11",
20+
"webpack-merge": "^4.2.2"
21+
},
22+
"browserslist": [
23+
"> 1%",
24+
"last 2 versions",
25+
"not ie <= 8"
26+
],
27+
"devDependencies": {
28+
"babel-core": "^6.26.0",
29+
"babel-loader": "^7.1.2",
30+
"babel-preset-env": "^1.6.0",
31+
"babel-preset-stage-3": "^6.24.1",
32+
"cross-env": "^5.0.5",
33+
"css-loader": "^0.28.7",
34+
"file-loader": "^1.1.4",
35+
"node-sass": "^4.5.3",
36+
"sass-loader": "^6.0.6",
37+
"vue-loader": "^13.0.5",
38+
"vue-template-compiler": "^2.4.4",
39+
"webpack": "^3.6.0",
40+
"webpack-dev-server": "^2.9.1"
41+
}
42+
}

server.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
const express = require('express');
2+
const server = express();
3+
const fs = require('fs');
4+
const path = require('path');
5+
//obtain bundle
6+
const bundle = require('./dist/server.bundle.js');
7+
//get renderer from vue server renderer
8+
const renderer = require('vue-server-renderer').createRenderer({
9+
//set template
10+
template: fs.readFileSync('./index.html', 'utf-8')
11+
});
12+
13+
server.use('/dist', express.static(path.join(__dirname, './dist')));
14+
15+
//start server
16+
server.get('*', (req, res) => {
17+
18+
bundle.default({ url: req.url }).then((app) => {
19+
//context to use as data source
20+
//in the template for interpolation
21+
const context = {
22+
title: 'Vue JS - Server Render',
23+
meta: `
24+
<meta description="vuejs server side render">
25+
`
26+
};
27+
28+
renderer.renderToString(app, context, function (err, html) {
29+
if (err) {
30+
if (err.code === 404) {
31+
res.status(404).end('Page not found')
32+
} else {
33+
res.status(500).end('Internal Server Error')
34+
}
35+
} else {
36+
res.end(html)
37+
}
38+
});
39+
}, (err) => {
40+
console.log(err);
41+
});
42+
});
43+
44+
server.listen(8080);

src/App.vue

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<template>
2+
<div id="app">
3+
Hello World!
4+
<p>
5+
<router-link to="/">Go To Home</router-link>
6+
<router-link to="/about">Go To About</router-link>
7+
<router-link to="/à-propos">Go To à-propos </router-link>
8+
</p>
9+
<router-view></router-view>
10+
</div>
11+
</template>
12+
<script>
13+
export default {
14+
};
15+
</script>

src/assets/logo.png

6.69 KB
Loading

src/client-entry.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { createApp } from './main.js';
2+
3+
const { app } = createApp()
4+
5+
// this assumes App.vue template root element has `id="app"`
6+
app.$mount('#app')

src/components/About.vue

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<template>
2+
<div>
3+
{{ aboutText }}
4+
</div>
5+
</template>
6+
<script>
7+
export default {
8+
data() {
9+
return {
10+
aboutText: 'Routes WITHOUT non-ascii characters are matched both in ssr and client'
11+
};
12+
}
13+
};
14+
</script>

src/components/Apropos.vue

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<template>
2+
<div>
3+
{{ aboutText }}
4+
</div>
5+
</template>
6+
<script>
7+
export default {
8+
data() {
9+
return {
10+
aboutText: 'Routes with non ascii characters are not matched when requested directly from server (404 in terminal), these routes are matched only on client (when clicking on links)'
11+
};
12+
}
13+
};
14+
</script>

src/components/Home.vue

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<template>
2+
<div>
3+
{{ homeText }}
4+
</div>
5+
</template>
6+
<script>
7+
export default {
8+
data() {
9+
return {
10+
homeText: 'Home Component'
11+
};
12+
}
13+
};
14+
</script>

src/main.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Vue from 'vue'
2+
import App from './App.vue'
3+
import { createRouter } from './router/router.js'
4+
5+
// export a factory function for creating fresh app, router and store
6+
// instances
7+
export function createApp () {
8+
// create router instance
9+
const router = createRouter();
10+
11+
const app = new Vue({
12+
router,
13+
// the root instance simply renders the App component.
14+
render: h => h(App)
15+
});
16+
17+
return { app, router };
18+
}

src/router/router.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Vue from 'vue';
2+
import Router from 'vue-router';
3+
import Home from '../components/Home.vue';
4+
import About from '../components/About.vue';
5+
import Apropos from '../components/Apropos.vue';
6+
7+
Vue.use(Router);
8+
9+
export function createRouter () {
10+
return new Router({
11+
mode: 'history',
12+
routes: [
13+
{ path: '/', component: Home },
14+
{ path: '/about', component: About },
15+
{ path: '/à-propos', component: Apropos }
16+
]
17+
});
18+
}

src/server-entry.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { createApp } from './main.js';
2+
3+
export default context => {
4+
// since there could potentially be asynchronous route hooks or components,
5+
// we will be returning a Promise so that the server can wait until
6+
// everything is ready before rendering.
7+
return new Promise((resolve, reject) => {
8+
const { app, router } = createApp();
9+
10+
// set server-side router's location
11+
router.push(context.url);
12+
13+
// wait until router has resolved possible async components and hooks
14+
router.onReady(() => {
15+
const matchedComponents = router.getMatchedComponents();
16+
// no matched routes, reject with 404
17+
if (!matchedComponents.length) {
18+
return reject({ code: 404 });
19+
}
20+
21+
// the Promise should resolve to the app instance so it can be rendered
22+
resolve(app);
23+
}, reject);
24+
});
25+
}

webpack.config.js

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
var path = require('path')
2+
var webpack = require('webpack')
3+
4+
module.exports = {
5+
entry: './src/client-entry.js',
6+
output: {
7+
path: path.resolve(__dirname, './dist'),
8+
publicPath: '/dist/',
9+
filename: 'build.js'
10+
},
11+
module: {
12+
rules: [
13+
{
14+
test: /\.css$/,
15+
use: [
16+
'vue-style-loader',
17+
'css-loader'
18+
],
19+
},
20+
{
21+
test: /\.scss$/,
22+
use: [
23+
'vue-style-loader',
24+
'css-loader',
25+
'sass-loader'
26+
],
27+
},
28+
{
29+
test: /\.sass$/,
30+
use: [
31+
'vue-style-loader',
32+
'css-loader',
33+
'sass-loader?indentedSyntax'
34+
],
35+
},
36+
{
37+
test: /\.vue$/,
38+
loader: 'vue-loader',
39+
options: {
40+
loaders: {
41+
// Since sass-loader (weirdly) has SCSS as its default parse mode, we map
42+
// the "scss" and "sass" values for the lang attribute to the right configs here.
43+
// other preprocessors should work out of the box, no loader config like this necessary.
44+
'scss': [
45+
'vue-style-loader',
46+
'css-loader',
47+
'sass-loader'
48+
],
49+
'sass': [
50+
'vue-style-loader',
51+
'css-loader',
52+
'sass-loader?indentedSyntax'
53+
]
54+
}
55+
// other vue-loader options go here
56+
}
57+
},
58+
{
59+
test: /\.js$/,
60+
loader: 'babel-loader',
61+
exclude: /node_modules/
62+
},
63+
{
64+
test: /\.(png|jpg|gif|svg)$/,
65+
loader: 'file-loader',
66+
options: {
67+
name: '[name].[ext]?[hash]'
68+
}
69+
}
70+
]
71+
},
72+
resolve: {
73+
alias: {
74+
'vue$': 'vue/dist/vue.esm.js'
75+
},
76+
extensions: ['*', '.js', '.vue', '.json']
77+
},
78+
devServer: {
79+
historyApiFallback: true,
80+
noInfo: true,
81+
overlay: true
82+
},
83+
performance: {
84+
hints: false
85+
},
86+
devtool: '#eval-source-map'
87+
}
88+
89+
if (process.env.NODE_ENV === 'production') {
90+
module.exports.devtool = '#source-map'
91+
// http://vue-loader.vuejs.org/en/workflow/production.html
92+
module.exports.plugins = (module.exports.plugins || []).concat([
93+
new webpack.DefinePlugin({
94+
'process.env': {
95+
NODE_ENV: '"production"'
96+
}
97+
}),
98+
new webpack.optimize.UglifyJsPlugin({
99+
sourceMap: true,
100+
compress: {
101+
warnings: false
102+
}
103+
}),
104+
new webpack.LoaderOptionsPlugin({
105+
minimize: true
106+
})
107+
])
108+
}

0 commit comments

Comments
 (0)