Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
6f6bcef
fix(package): update babel-eslint to version 8.0.0
greenkeeper[bot] Sep 12, 2017
c505250
Merge pull request #84 from express-vue/greenkeeper/babel-eslint-8.0.0
danielcherubini Sep 12, 2017
dca3763
chore(package): update generate-release to version 0.14.0
greenkeeper[bot] Sep 19, 2017
bbef04c
chore(package): update flow-bin to version 0.55.0
greenkeeper[bot] Sep 20, 2017
97ccbb2
Merge branch 'develop' into greenkeeper/flow-bin-0.55.0
danielcherubini Sep 21, 2017
890238e
Merge pull request #88 from express-vue/greenkeeper/flow-bin-0.55.0
danielcherubini Sep 21, 2017
a9e98d6
Merge branch 'develop' into greenkeeper/generate-release-0.14.0
danielcherubini Sep 21, 2017
25f75c6
Merge pull request #87 from express-vue/greenkeeper/generate-release-…
danielcherubini Sep 21, 2017
3f3b22b
chore(package): update coveralls to version 3.0.0
greenkeeper[bot] Sep 28, 2017
a9fabb3
chore(package): update flow-bin to version 0.56.0
greenkeeper[bot] Sep 28, 2017
4da1b46
Merge branch 'develop' into greenkeeper/flow-bin-0.56.0
danielcherubini Sep 29, 2017
22221a2
Merge pull request #91 from express-vue/greenkeeper/flow-bin-0.56.0
danielcherubini Sep 29, 2017
5fc1533
Merge branch 'develop' into greenkeeper/coveralls-3.0.0
danielcherubini Sep 29, 2017
7421bef
Merge pull request #90 from express-vue/greenkeeper/coveralls-3.0.0
danielcherubini Sep 29, 2017
6fe4868
Merge branch 'develop' into feature/source-string
danielcherubini Sep 29, 2017
81a0ab6
prop object, and source string contents
danielcherubini Sep 29, 2017
0a522c8
fix issue with custom layout attributes being ignored
Oct 5, 2017
729b6ad
Merge branch 'develop' into feature/render-custom-layout
onebesky Oct 5, 2017
02dfadb
Merge pull request #93 from onebesky/feature/render-custom-layout
danielcherubini Oct 6, 2017
1735e64
Merge branch 'develop' into feature/source-string
danielcherubini Oct 6, 2017
a4f1dcb
Merge pull request #92 from express-vue/feature/source-string
danielcherubini Oct 6, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18,805 changes: 9,717 additions & 9,088 deletions package-lock.json

Large diffs are not rendered by default.

39 changes: 21 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,41 +66,44 @@
"repository": "express-vue/express-vue-renderer",
"license": "Apache-2.0",
"dependencies": {
"babel-eslint": "^7.2.3",
"babel-core": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"butternut": "^0.4.6",
"camel-case": "^3.0.0",
"clean-css": "^4.1.7",
"clean-css": "^4.1.9",
"debug": "^2.6.9",
"dedupe": "^2.1.0",
"deepmerge": "^1.5.1",
"html-minifier": "^3.5.3",
"deepmerge": "^1.5.2",
"html-minifier": "^3.5.5",
"lru-cache": "^4.1.1",
"pug": "^2.0.0-rc.3",
"require-from-string": "^1.2.1",
"no-case": "^2.3.2",
"pug": "^2.0.0-rc.4",
"require-from-string": "^2.0.1",
"string-hash": "^1.1.3",
"vue": "^2.4.2",
"vue-server-renderer": "^2.4.2",
"vue-template-compiler": "^2.4.2",
"vue": "^2.4.4",
"vue-server-renderer": "^2.4.4",
"vue-template-compiler": "^2.4.4",
"xss": "^0.3.4"
},
"devDependencies": {
"ava": "^0.22.0",
"babel-cli": "^6.26.0",
"babel-eslint": "^8.0.0",
"babel-plugin-transform-flow-strip-types": "^6.22.0",
"babel-preset-env": "^1.6.0",
"babel-preset-flow": "^6.23.0",
"codecov": "^2.3.0",
"coveralls": "^2.13.1",
"eslint": "^4.5.0",
"coveralls": "^3.0.0",
"eslint": "^4.7.2",
"eslint-config-xo-space": "^0.16.0",
"eslint-plugin-flowtype": "^2.35.0",
"express": "^4.15.4",
"flow-bin": "^0.54.0",
"eslint-plugin-flowtype": "^2.36.0",
"express": "^4.16.0",
"flow-bin": "^0.56.0",
"flow-remove-types": "^1.2.1",
"generate-release": "^0.13.1",
"nodemon": "^1.11.0",
"nsp": "^2.7.0",
"nyc": "^11.1.0",
"generate-release": "^0.14.0",
"nodemon": "^1.12.1",
"nsp": "^2.8.1",
"nyc": "^11.2.1",
"uuid": "^3.1.0"
}
}
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ class ExpressVueRenderer {
// Options.mergeDataObject(data);
if (vueOptions) {
Options.vue = Models.Defaults.mergeObjects(Options.vue, vueOptions);
if (vueOptions.layout) {
Options.layout = Models.Defaults.mergeObjects(Options.layout, vueOptions.layout);
}
}
Options.component = componentPath;

Expand Down
2 changes: 2 additions & 0 deletions src/utils/head.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class HeadUtil {
const href = metaItem.href ? `href="${metaItem.href}" ` : '';
const sizes = metaItem.sizes ? `sizes="${metaItem.sizes}" ` : '';
this.metaTags += `<link ${rel}${type}${href}${sizes}>\n`;
} else if (metaItem.srcContents) {
this.metaTags += `${metaItem.srcContents}\n`;
}
}
}
Expand Down
83 changes: 59 additions & 24 deletions src/utils/string.js
Original file line number Diff line number Diff line change
@@ -1,69 +1,104 @@
// @flow
const xss = require('xss');

class PropClass {
type: any;
required: boolean;
default: any;
constructor(prop: any) {
prop.required ? this.required = prop.required : null;
prop.default ? this.default = prop.default : null;
}
}

function routesToString(routes: Object[]): string {
let string = '';
routes.forEach(script => string += scriptToString(script) + ',');
return `[${string}]`;
let routeString = '';
routes.forEach(script => routeString += scriptToString(script) + ',');
return `[${routeString}]`.replace(new RegExp(/,}/, 'g'), '}').replace(new RegExp(/,]/, 'g'), ']');
}

function routeComponentsToString(script: Object): string {
let string = '';
let componentString = '';
for (let member in script) {
string += member + ': __' + script[member] + ',';
componentString += member + ': __' + script[member] + ',';
}
return `{${string}}`;
return `{${componentString}}`;
}

function mixinsToString(mixins: Array < Object > ): string {
var string = '';
var mixinString = '';
for (var mixin of mixins) {
string += `${scriptToString(mixin)},`;
mixinString += `${scriptToString(mixin)},`;
}
return string;
return mixinString;
}

function scriptToString(script: Object): string {
let string = '';
function propsToString(props: Object): string {
let propString = '';
if (props[Object.keys(props)[0]].type === null) {
var propsArray = Object.keys(props);
propString = xss(JSON.stringify(propsArray));
} else {
let tempProp = {};
for (var prop in props) {
if (props.hasOwnProperty(prop)) {
var element = new PropClass(props[prop]);
tempProp[prop] = element;
}
}
propString = scriptToString(tempProp);
}
return propString;
}

function scriptToString(script: Object | any): string {
let scriptString = '';
for (let member in script) {
switch (typeof script[member]) {
case 'function':
if (member === 'data') {
const dataObj = xss(JSON.stringify(script[member]()));
string += `${member}: function(){return ${dataObj}},`;
scriptString += `${member}: function(){return ${dataObj}},`;
} else {
string += member + ': ' + String(script[member]) + ',';
scriptString += member + ': ' + String(script[member]) + ',';
}
break;
case 'object':
if (member === 'data') {
string += member + ': ' + xss(JSON.stringify(script[member])) + ',';
scriptString += member + ': ' + xss(JSON.stringify(script[member])) + ',';
} else if (member === 'routes' || member === 'children') {
string += member + ': ' + routesToString(script[member]) + ',';
scriptString += member + ': ' + routesToString(script[member]) + ',';
} else if (member === 'components' && script['path'] !== undefined) { // Checks if 'components' is in a route object
string += member + ': ' + routeComponentsToString(script[member]) + ',';
scriptString += member + ': ' + routeComponentsToString(script[member]) + ',';
} else if (member === 'mixins') {
string += member + ': [' + mixinsToString(script[member]) + '],';
scriptString += member + ': [' + mixinsToString(script[member]) + '],';
} else if (script[member].constructor === Array) {
string += member + ': ' + xss(JSON.stringify(script[member])) + ',';
scriptString += member + ': ' + xss(JSON.stringify(script[member])) + ',';
} else if (member === 'props') {
const propsArray = Object.keys(script[member]);
string += member + ': ' + xss(JSON.stringify(propsArray)) + ',';
if (script[member][Object.keys(script[member])[0]].type === null) {
var propsArray = Object.keys(script[member]);
scriptString += member + ': ' + xss(JSON.stringify(propsArray)) + ',';
} else {
// scriptString += member + ': ' + scriptToString(script[member]) + ',';
const propsString = propsToString(script[member]);
scriptString += `${member}: ${propsString},`;
}

} else {
string += member + ': ' + scriptToString(script[member]) + ',';
scriptString += member + ': ' + scriptToString(script[member]) + ',';
}
break;
default:
if (member === 'component' && script['path'] !== undefined) { // Checks if 'component' is in a route object
string += member + ': __' + script[member] + ',';
scriptString += member + ': __' + script[member] + ',';
} else {
string += member + ': ' + JSON.stringify(script[member]) + ',';
scriptString += member + ': ' + JSON.stringify(script[member]) + ',';
}
break;
}
}
return `{${string}}`;
let finalScriptString = `{${scriptString}}`.replace(new RegExp(/,}/, 'g'), '}').replace(new RegExp(/,]/, 'g'), ']');
return finalScriptString;
}

module.exports.scriptToString = scriptToString;
Expand Down
2 changes: 1 addition & 1 deletion tests/example/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const options = {
content: 'Page Title'
},
{
script: 'https://unpkg.com/vue@2.4.2/dist/vue.js'
script: 'https://unpkg.com/vue@2.4.4/dist/vue.js'
}, {
name: 'viewport',
content: 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'
Expand Down
8 changes: 7 additions & 1 deletion tests/example/components/uuid.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@
<script>
import inner from '../components/inner.vue';
export default {
props: ['uuid'],
props: {
uuid: {
type: String,
default: 'missing',
required: true
}
},
data: function () {
return {}
},
Expand Down
35 changes: 34 additions & 1 deletion tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const vueOptions = {
}

const exampleHead = `<head>\n<title>Page Title</title>\n<style>.red{color:#9acd32}.pink{color:pink;text-decoration:underline}.test{color:#00f}</style></head>`;
const exampleScript = `<script>(function(){"use strict";var t=function(){return new Vue({mixins:[{methods:{hello:function(){console.log('Hello')}}}],data:function(){return{"title":"Express Vue","message":"Hello world","uuid":"farts"}},methods:{test:function(){console.error('test')}},components:{uuid:{props:["uuid"],data:function(){return{}},components:{inner:{data:function(){return{}},template:"<div><p class=\\"pink\\">Inner Text</p></div>"}},styles:".pink{color:pink;text-decoration:underline}",template:"<div><inner></inner><h2 class=\\"test\\">Uuid: {{uuid ? uuid : 'no uuid'}}</h2></div>"},uuid2:{props:["uuid2"],data:function(){return{}},template:"<div><h3 class=\\"red\\">Uuid2: {{uuid2 ? uuid2 : 'no uuid'}}</h3></div>"}},styles:".pink{color:pink;text-decoration:underline}.test{color:#00f}.red{color:#9acd32}",template:"<div><h1>{{title}}</h1><p>Welcome to the {{title}} demo. Click a link:</p><input v-model=\\"message\\" placeholder=\\"edit me\\"><p>{{message}}</p><uuid :uuid=\\"uuid\\"></uuid><uuid2 :uuid2=\\"uuid2\\"></uuid2><button type=\\"button\\" name=\\"button\\" v-on:click=\\"this.hello\\">Test mixin</button> <button type=\\"button\\" name=\\"button\\" v-on:click=\\"this.test\\">Test method</button></div>"})};typeof module!=='undefined'&&module.exports?(module.exports=t):(this.app=t())}).call(this),app.$mount('#app')</script>`;
const exampleScript = `<script>(function(){"use strict";var t=function(){return new Vue({mixins:[{methods:{hello:function(){console.log('Hello')}}}],data:function(){return{"title":"Express Vue","message":"Hello world","uuid":"farts"}},methods:{test:function(){console.error('test')}},components:{uuid:{props:{uuid:{required:!0,default:"missing"}},data:function(){return{}},components:{inner:{data:function(){return{}},template:"<div><p class=\\"pink\\">Inner Text</p></div>"}},styles:".pink{color:pink;text-decoration:underline}",template:"<div><inner></inner><h2 class=\\"test\\">Uuid: {{uuid ? uuid : 'no uuid'}}</h2></div>"},uuid2:{props:["uuid2"],data:function(){return{}},template:"<div><h3 class=\\"red\\">Uuid2: {{uuid2 ? uuid2 : 'no uuid'}}</h3></div>"}},styles:".pink{color:pink;text-decoration:underline}.test{color:#00f}.red{color:#9acd32}",template:"<div><h1>{{title}}</h1><p>Welcome to the {{title}} demo. Click a link:</p><input v-model=\\"message\\" placeholder=\\"edit me\\"><p>{{message}}</p><uuid :uuid=\\"uuid\\"></uuid><uuid2 :uuid2=\\"uuid2\\"></uuid2><button type=\\"button\\" name=\\"button\\" v-on:click=\\"this.hello\\">Test mixin</button> <button type=\\"button\\" name=\\"button\\" v-on:click=\\"this.test\\">Test method</button></div>"})};typeof module!=='undefined'&&module.exports?(module.exports=t):(this.app=t())}).call(this),app.$mount('#app')</script>`;

test('renders App object', t => {
const renderer = new ExpressVueRenderer(options);
Expand All @@ -34,3 +34,36 @@ test('renders App object', t => {
t.fail(error.stack);
});
});


test('renders App object with custom layout', t => {
const vueOptionsWithLayout = {
layout: {
html: {
start: 'html-start',
end: 'html-end',
},
body: {
start: 'body-start',
end: 'body-end'
},
template: {
start: "template-start",
end: "template-end"
},
}
};
const renderer = new ExpressVueRenderer(options);
return renderer.createAppObject('main', data, vueOptionsWithLayout)
.then(app => {
t.is(app.template.html.start, "html-start");
t.is(app.template.html.end, "html-end");
t.is(app.template.body.start, "body-start");
t.is(app.template.body.end, "body-end");
t.is(app.template.template.start, "template-start");
t.is(app.template.template.end, "template-end");
})
.catch(error => {
t.fail(error.stack);
});
});
10 changes: 9 additions & 1 deletion tests/utils/head.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ const newHead = {
type: 'image/png',
href: '/assets/favicons/favicon-32x32.png',
sizes: '32x32'
},
{
srcContents: '<script>var foo = false;</script>'
}
],
structuredData: {
Expand All @@ -57,13 +60,14 @@ const newHead = {
const newMetaString = new HeadUtils(newHead).toString();

//New Tests
const newStringIsCorrect = '<head>\n<title>It was a Pleasure</title>\n<meta name="application-name" content="Name of my application"/>\n<meta name="description" content="A description of the page"/>\n<meta name="twitter:title" content="Content Title"/>\n<meta property="fb:app_id" content="123456789"/>\n<meta property="og:title" content="Content Title"/>\n<script src="/assets/scripts/hammer.min.js" charset="utf-8"></script>\n<script src="/assets/scripts/vue-touch.min.js" charset="utf-8"></script>\n<link rel="stylesheet" type="text/css" href="/assets/rendered/style.css">\n<link rel="stylesheet" type="text/css" href="/assets/rendered/style.css">\n<link rel="icon" type="image/png" href="/assets/favicons/favicon-32x32.png" sizes="32x32" >\n<script type="application/ld+json">\n{"foo":true}\n</script>\n</head>'
const newStringIsCorrect = '<head>\n<title>It was a Pleasure</title>\n<meta name="application-name" content="Name of my application"/>\n<meta name="description" content="A description of the page"/>\n<meta name="twitter:title" content="Content Title"/>\n<meta property="fb:app_id" content="123456789"/>\n<meta property="og:title" content="Content Title"/>\n<script src="/assets/scripts/hammer.min.js" charset="utf-8"></script>\n<script src="/assets/scripts/vue-touch.min.js" charset="utf-8"></script>\n<link rel="stylesheet" type="text/css" href="/assets/rendered/style.css">\n<link rel="stylesheet" type="text/css" href="/assets/rendered/style.css">\n<link rel="icon" type="image/png" href="/assets/favicons/favicon-32x32.png" sizes="32x32" >\n<script>var foo = false;</script>\n<script type="application/ld+json">\n{"foo":true}\n</script>\n</head>'
const newHasTitle = newMetaString.includes('<title>It was a Pleasure</title>');
const newHasMetaName = newMetaString.includes(`<meta name="application-name" content="Name of my application"/>`);
const newHasMetaProperty = newMetaString.includes(`<meta property="og:title" content="Content Title"/>`);
const newHasScript = newMetaString.includes(`<script src="/assets/scripts/hammer.min.js" charset="utf-8">`)
const newHasStyle = newMetaString.includes(`<link rel="stylesheet" type="text/css" href="/assets/rendered/style.css">`)
const newHasStructured = newMetaString.includes(`<script type="application/ld+json">\n{"foo":true}\n</script>`);
const newHasSrcContents = newMetaString.includes(`<script>var foo = false;</script>`);

test('Head is correct', t => {
t.is(newMetaString, newStringIsCorrect);
Expand Down Expand Up @@ -92,3 +96,7 @@ test('Head has style 🎷', t => {
test('Head has Structured Data', t => {
t.is(newHasStructured, true);
});

test('Head has srcContents', t => {
t.is(newHasSrcContents, true);
});
Loading