mirror of
https://github.com/tenrok/vue-meta.git
synced 2026-06-25 09:00:33 +03:00
test: add render tests
fix: webpack dev server chore: use eslint not prettier unfeat: remove support for comments (its brokenn in Vue, maybe later)
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
test/old
|
||||||
|
__build__
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
"@nuxtjs/eslint-config-typescript"
|
||||||
|
],
|
||||||
|
"globals": {
|
||||||
|
"__DEV__": true
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"examples/**"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"no-console": "off",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
node_modules
|
|
||||||
__build__
|
|
||||||
dist
|
|
||||||
.vue-meta
|
|
||||||
_old
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"semi": false,
|
|
||||||
"trailingComma": "es5",
|
|
||||||
"singleQuote": true,
|
|
||||||
"arrowParens": "avoid"
|
|
||||||
}
|
|
||||||
+14
-1
@@ -1,4 +1,16 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
["@babel/preset-env", {
|
||||||
|
useBuiltIns: 'usage',
|
||||||
|
corejs: 3,
|
||||||
|
targets: {
|
||||||
|
ie: 9
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
"dynamic-import-node"
|
||||||
|
],
|
||||||
env: {
|
env: {
|
||||||
test: {
|
test: {
|
||||||
plugins: [
|
plugins: [
|
||||||
@@ -10,7 +22,8 @@ module.exports = {
|
|||||||
targets: {
|
targets: {
|
||||||
node: 'current'
|
node: 'current'
|
||||||
}
|
}
|
||||||
}]
|
}],
|
||||||
|
'@babel/preset-typescript'
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
-1924
File diff suppressed because it is too large
Load Diff
Vendored
-1550
File diff suppressed because it is too large
Load Diff
Vendored
-10
File diff suppressed because one or more lines are too long
Vendored
-1920
File diff suppressed because it is too large
Load Diff
Vendored
-1643
File diff suppressed because it is too large
Load Diff
Vendored
-10
File diff suppressed because one or more lines are too long
@@ -10,14 +10,14 @@ window.users.push({
|
|||||||
zipcode: '92998-3874',
|
zipcode: '92998-3874',
|
||||||
geo: {
|
geo: {
|
||||||
lat: '-37.3159',
|
lat: '-37.3159',
|
||||||
lng: '81.1496',
|
lng: '81.1496'
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
phone: '1-770-736-8031 x56442',
|
phone: '1-770-736-8031 x56442',
|
||||||
website: 'hildegard.org',
|
website: 'hildegard.org',
|
||||||
company: {
|
company: {
|
||||||
name: 'Romaguera-Crona',
|
name: 'Romaguera-Crona',
|
||||||
catchPhrase: 'Multi-layered client-server neural-net',
|
catchPhrase: 'Multi-layered client-server neural-net',
|
||||||
bs: 'harness real-time e-markets',
|
bs: 'harness real-time e-markets'
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ window.users.push({
|
|||||||
zipcode: '90566-7771',
|
zipcode: '90566-7771',
|
||||||
geo: {
|
geo: {
|
||||||
lat: '-43.9509',
|
lat: '-43.9509',
|
||||||
lng: '-34.4618',
|
lng: '-34.4618'
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
phone: '010-692-6593 x09125',
|
phone: '010-692-6593 x09125',
|
||||||
website: 'anastasia.net',
|
website: 'anastasia.net',
|
||||||
company: {
|
company: {
|
||||||
name: 'Deckow-Crist',
|
name: 'Deckow-Crist',
|
||||||
catchPhrase: 'Proactive didactic contingency',
|
catchPhrase: 'Proactive didactic contingency',
|
||||||
bs: 'synergize scalable supply-chains',
|
bs: 'synergize scalable supply-chains'
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ window.users.push({
|
|||||||
zipcode: '59590-4157',
|
zipcode: '59590-4157',
|
||||||
geo: {
|
geo: {
|
||||||
lat: '-68.6102',
|
lat: '-68.6102',
|
||||||
lng: '-47.0653',
|
lng: '-47.0653'
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
phone: '1-463-123-4447',
|
phone: '1-463-123-4447',
|
||||||
website: 'ramiro.info',
|
website: 'ramiro.info',
|
||||||
company: {
|
company: {
|
||||||
name: 'Romaguera-Jacobson',
|
name: 'Romaguera-Jacobson',
|
||||||
catchPhrase: 'Face to face bifurcated interface',
|
catchPhrase: 'Face to face bifurcated interface',
|
||||||
bs: 'e-enable strategic applications',
|
bs: 'e-enable strategic applications'
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ window.users.push({
|
|||||||
zipcode: '53919-4257',
|
zipcode: '53919-4257',
|
||||||
geo: {
|
geo: {
|
||||||
lat: '29.4572',
|
lat: '29.4572',
|
||||||
lng: '-164.2990',
|
lng: '-164.2990'
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
phone: '493-170-9623 x156',
|
phone: '493-170-9623 x156',
|
||||||
website: 'kale.biz',
|
website: 'kale.biz',
|
||||||
company: {
|
company: {
|
||||||
name: 'Robel-Corkery',
|
name: 'Robel-Corkery',
|
||||||
catchPhrase: 'Multi-tiered zero tolerance productivity',
|
catchPhrase: 'Multi-tiered zero tolerance productivity',
|
||||||
bs: 'transition cutting-edge web services',
|
bs: 'transition cutting-edge web services'
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -16,30 +16,30 @@ new Vue({
|
|||||||
vmid: 'potatoes',
|
vmid: 'potatoes',
|
||||||
src: '/user-3.js',
|
src: '/user-3.js',
|
||||||
async: true,
|
async: true,
|
||||||
callback: this.updateCounter,
|
callback: this.updateCounter
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
skip: this.count < 1,
|
skip: this.count < 1,
|
||||||
vmid: 'vegetables',
|
vmid: 'vegetables',
|
||||||
src: '/user-2.js',
|
src: '/user-2.js',
|
||||||
async: true,
|
async: true,
|
||||||
callback: this.updateCounter,
|
callback: this.updateCounter
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
vmid: 'meat',
|
vmid: 'meat',
|
||||||
src: '/user-1.js',
|
src: '/user-1.js',
|
||||||
async: true,
|
async: true,
|
||||||
callback: el => this.loadCallback(el.getAttribute('data-vmid')),
|
callback: el => this.loadCallback(el.getAttribute('data-vmid'))
|
||||||
},
|
},
|
||||||
...this.scripts,
|
...this.scripts
|
||||||
],
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
count: 0,
|
count: 0,
|
||||||
scripts: [],
|
scripts: [],
|
||||||
users: window.users,
|
users: window.users
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -47,7 +47,7 @@ new Vue({
|
|||||||
if (val === 3) {
|
if (val === 3) {
|
||||||
this.addScript()
|
this.addScript()
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateCounter () {
|
updateCounter () {
|
||||||
@@ -58,14 +58,14 @@ new Vue({
|
|||||||
src: '/user-4.js',
|
src: '/user-4.js',
|
||||||
callback: () => {
|
callback: () => {
|
||||||
this.updateCounter()
|
this.updateCounter()
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
loadCallback (vmid) {
|
loadCallback (vmid) {
|
||||||
if (vmid === 'meat') {
|
if (vmid === 'meat') {
|
||||||
this.updateCounter()
|
this.updateCounter()
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
template: `
|
template: `
|
||||||
<div id="app">
|
<div id="app">
|
||||||
@@ -84,5 +84,5 @@ new Vue({
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`
|
||||||
}).$mount('#app')
|
}).$mount('#app')
|
||||||
|
|||||||
@@ -8,17 +8,17 @@ Vue.component('child', {
|
|||||||
props: {
|
props: {
|
||||||
page: {
|
page: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: ''
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
render (h) {
|
render (h) {
|
||||||
return h('h3', null, this.page)
|
return h('h3', null, this.page)
|
||||||
},
|
},
|
||||||
metaInfo () {
|
metaInfo () {
|
||||||
return {
|
return {
|
||||||
title: this.page,
|
title: this.page
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
@@ -28,5 +28,5 @@ new Vue({
|
|||||||
<p>Inspect Element to see the meta info</p>
|
<p>Inspect Element to see the meta info</p>
|
||||||
<child page="This is a prop"></child>
|
<child page="This is a prop"></child>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`
|
||||||
}).$mount('#app')
|
}).$mount('#app')
|
||||||
|
|||||||
@@ -15,24 +15,24 @@ new Vue({
|
|||||||
titleTemplate: '%s | Vue Meta Examples',
|
titleTemplate: '%s | Vue Meta Examples',
|
||||||
htmlAttrs: {
|
htmlAttrs: {
|
||||||
lang: 'en',
|
lang: 'en',
|
||||||
amp: undefined,
|
amp: undefined
|
||||||
},
|
},
|
||||||
headAttrs: {
|
headAttrs: {
|
||||||
test: true,
|
test: true
|
||||||
},
|
},
|
||||||
meta: [{ name: 'description', content: 'Hello', vmid: 'test' }],
|
meta: [{ name: 'description', content: 'Hello', vmid: 'test' }],
|
||||||
script: [
|
script: [
|
||||||
{
|
{
|
||||||
innerHTML:
|
innerHTML:
|
||||||
'{ "@context": "http://www.schema.org", "@type": "Organization" }',
|
'{ "@context": "http://www.schema.org", "@type": "Organization" }',
|
||||||
type: 'application/ld+json',
|
type: 'application/ld+json'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
innerHTML: '{ "body": "yes" }',
|
innerHTML: '{ "body": "yes" }',
|
||||||
body: true,
|
body: true,
|
||||||
type: 'application/ld+json',
|
type: 'application/ld+json'
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
__dangerouslyDisableSanitizers: ['script'],
|
__dangerouslyDisableSanitizers: ['script']
|
||||||
}),
|
})
|
||||||
}).$mount('#app')
|
}).$mount('#app')
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ Vue.use(VueMeta)
|
|||||||
Vue.component('foo', {
|
Vue.component('foo', {
|
||||||
template: '<p>Foo component</p>',
|
template: '<p>Foo component</p>',
|
||||||
metaInfo: {
|
metaInfo: {
|
||||||
title: 'Keep me Foo',
|
title: 'Keep me Foo'
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
@@ -17,7 +17,7 @@ new Vue({
|
|||||||
methods: {
|
methods: {
|
||||||
show () {
|
show () {
|
||||||
this.showFoo = !this.showFoo
|
this.showFoo = !this.showFoo
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
template: `
|
template: `
|
||||||
<div id="app">
|
<div id="app">
|
||||||
@@ -29,6 +29,6 @@ new Vue({
|
|||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
metaInfo: () => ({
|
metaInfo: () => ({
|
||||||
title: 'Keep-alive',
|
title: 'Keep-alive'
|
||||||
}),
|
})
|
||||||
}).$mount('#app')
|
}).$mount('#app')
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const {
|
|||||||
processIf,
|
processIf,
|
||||||
getBaseTransformPreset,
|
getBaseTransformPreset,
|
||||||
createObjectExpression,
|
createObjectExpression,
|
||||||
createObjectProperty,
|
createObjectProperty
|
||||||
} = require('@vue/compiler-core')
|
} = require('@vue/compiler-core')
|
||||||
|
|
||||||
const { parse } = require('@vue/compiler-dom')
|
const { parse } = require('@vue/compiler-dom')
|
||||||
@@ -35,13 +35,13 @@ module.exports = function (source, map) {
|
|||||||
// console.log('AST', ast)
|
// console.log('AST', ast)
|
||||||
|
|
||||||
const [nodeTransforms, directiveTransforms] = getBaseTransformPreset({
|
const [nodeTransforms, directiveTransforms] = getBaseTransformPreset({
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true
|
||||||
})
|
})
|
||||||
|
|
||||||
transform(ast, {
|
transform(ast, {
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
nodeTransforms: [...nodeTransforms, headTransform],
|
nodeTransforms: [...nodeTransforms, headTransform],
|
||||||
directiveTransforms,
|
directiveTransforms
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = generate(ast, { mode: 'module' })
|
const result = generate(ast, { mode: 'module' })
|
||||||
|
|||||||
@@ -10,46 +10,46 @@ const app1 = new Vue({
|
|||||||
return {
|
return {
|
||||||
title: 'App 1 title',
|
title: 'App 1 title',
|
||||||
bodyAttrs: {
|
bodyAttrs: {
|
||||||
class: 'app-1',
|
class: 'app-1'
|
||||||
},
|
},
|
||||||
meta: [
|
meta: [
|
||||||
{ name: 'description', content: 'Hello from app 1', vmid: 'test' },
|
{ name: 'description', content: 'Hello from app 1', vmid: 'test' },
|
||||||
{ name: 'og:description', content: this.ogContent },
|
{ name: 'og:description', content: this.ogContent }
|
||||||
],
|
],
|
||||||
script: [
|
script: [
|
||||||
{ innerHTML: 'var appId=1.1', body: true },
|
{ innerHTML: 'var appId=1.1', body: true },
|
||||||
{ innerHTML: 'var appId=1.2', vmid: 'app-id-body' },
|
{ innerHTML: 'var appId=1.2', vmid: 'app-id-body' }
|
||||||
],
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
ogContent: 'Hello from ssr app',
|
ogContent: 'Hello from ssr app'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `
|
template: `
|
||||||
<div id="app1"><h1>App 1</h1></div>
|
<div id="app1"><h1>App 1</h1></div>
|
||||||
`,
|
`
|
||||||
})
|
})
|
||||||
|
|
||||||
const app2 = new Vue({
|
const app2 = new Vue({
|
||||||
metaInfo: () => ({
|
metaInfo: () => ({
|
||||||
title: 'App 2 title',
|
title: 'App 2 title',
|
||||||
bodyAttrs: {
|
bodyAttrs: {
|
||||||
class: 'app-2',
|
class: 'app-2'
|
||||||
},
|
},
|
||||||
meta: [
|
meta: [
|
||||||
{ name: 'description', content: 'Hello from app 2', vmid: 'test' },
|
{ name: 'description', content: 'Hello from app 2', vmid: 'test' },
|
||||||
{ name: 'og:description', content: 'Hello from app 2' },
|
{ name: 'og:description', content: 'Hello from app 2' }
|
||||||
],
|
],
|
||||||
script: [
|
script: [
|
||||||
{ innerHTML: 'var appId=2.1', body: true },
|
{ innerHTML: 'var appId=2.1', body: true },
|
||||||
{ innerHTML: 'var appId=2.2', vmid: 'app-id-body', body: true },
|
{ innerHTML: 'var appId=2.2', vmid: 'app-id-body', body: true }
|
||||||
],
|
]
|
||||||
}),
|
}),
|
||||||
template: `
|
template: `
|
||||||
<div id="app2"><h1>App 2</h1></div>
|
<div id="app2"><h1>App 2</h1></div>
|
||||||
`,
|
`
|
||||||
}).$mount('#app2')
|
}).$mount('#app2')
|
||||||
|
|
||||||
app1.$mount('#app1')
|
app1.$mount('#app1')
|
||||||
@@ -57,7 +57,7 @@ app1.$mount('#app1')
|
|||||||
const app3 = new Vue({
|
const app3 = new Vue({
|
||||||
template: `
|
template: `
|
||||||
<div id="app3"><h1>App 3 (empty metaInfo)</h1></div>
|
<div id="app3"><h1>App 3 (empty metaInfo)</h1></div>
|
||||||
`,
|
`
|
||||||
}).$mount('#app3')
|
}).$mount('#app3')
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
+3
-3
@@ -16,14 +16,14 @@ app.use(
|
|||||||
writeToDisk: true,
|
writeToDisk: true,
|
||||||
stats: {
|
stats: {
|
||||||
colors: true,
|
colors: true,
|
||||||
chunks: false,
|
chunks: false
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
fs.readdirSync(__dirname)
|
fs.readdirSync(__dirname)
|
||||||
.filter(file => file !== 'ssr')
|
.filter(file => file !== 'ssr')
|
||||||
.forEach(file => {
|
.forEach((file) => {
|
||||||
if (fs.statSync(path.join(__dirname, file)).isDirectory()) {
|
if (fs.statSync(path.join(__dirname, file)).isDirectory()) {
|
||||||
app.use(rewrite(`/${file}/*`, `/${file}/index.html`))
|
app.use(rewrite(`/${file}/*`, `/${file}/index.html`))
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-26
@@ -19,15 +19,15 @@ export default function createMyApp() {
|
|||||||
{
|
{
|
||||||
hid: 'og:title',
|
hid: 'og:title',
|
||||||
name: 'og:title',
|
name: 'og:title',
|
||||||
content: 'Hello World',
|
content: 'Hello World'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hid: 'description',
|
hid: 'description',
|
||||||
name: 'description',
|
name: 'description',
|
||||||
content: 'Hello World',
|
content: 'Hello World'
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const About = {
|
const About = {
|
||||||
@@ -42,23 +42,23 @@ export default function createMyApp() {
|
|||||||
{
|
{
|
||||||
hid: 'og:title',
|
hid: 'og:title',
|
||||||
name: 'og:title',
|
name: 'og:title',
|
||||||
content: 'About World',
|
content: 'About World'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hid: 'description',
|
hid: 'description',
|
||||||
name: 'description',
|
name: 'description',
|
||||||
content: 'About World',
|
content: 'About World'
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createMemoryHistory('/ssr'),
|
history: createMemoryHistory('/ssr'),
|
||||||
routes: [
|
routes: [
|
||||||
{ path: '/', component: Home },
|
{ path: '/', component: Home },
|
||||||
{ path: '/about', component: About },
|
{ path: '/about', component: About }
|
||||||
],
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
const app = createSSRApp({
|
const app = createSSRApp({
|
||||||
@@ -74,55 +74,55 @@ export default function createMyApp() {
|
|||||||
hid: 'og:title',
|
hid: 'og:title',
|
||||||
name: 'og:title',
|
name: 'og:title',
|
||||||
template: chunk => `${chunk} - My Site`,
|
template: chunk => `${chunk} - My Site`,
|
||||||
content: 'Default Title',
|
content: 'Default Title'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hid: 'description',
|
hid: 'description',
|
||||||
name: 'description',
|
name: 'description',
|
||||||
content: 'Say something',
|
content: 'Say something'
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
script: [
|
script: [
|
||||||
{
|
{
|
||||||
hid: 'ldjson-schema',
|
hid: 'ldjson-schema',
|
||||||
type: 'application/ld+json',
|
type: 'application/ld+json',
|
||||||
innerHTML:
|
innerHTML:
|
||||||
'{ "@context": "http://www.schema.org", "@type": "Organization" }',
|
'{ "@context": "http://www.schema.org", "@type": "Organization" }'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'application/ld+json',
|
type: 'application/ld+json',
|
||||||
innerHTML: '{ "body": "yes" }',
|
innerHTML: '{ "body": "yes" }',
|
||||||
body: true,
|
body: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hid: 'my-async-script-with-load-callback',
|
hid: 'my-async-script-with-load-callback',
|
||||||
src: '/user-1.js',
|
src: '/user-1.js',
|
||||||
body: true,
|
body: true,
|
||||||
defer: true,
|
defer: true,
|
||||||
callback: this.loadCallback,
|
callback: this.loadCallback
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
skip: this.count < 1,
|
skip: this.count < 1,
|
||||||
src: '/user-2.js',
|
src: '/user-2.js',
|
||||||
body: true,
|
body: true,
|
||||||
callback: this.loadCallback,
|
callback: this.loadCallback
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
__dangerouslyDisableSanitizersByTagID: {
|
__dangerouslyDisableSanitizersByTagID: {
|
||||||
'ldjson-schema': ['innerHTML'],
|
'ldjson-schema': ['innerHTML']
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
count: 0,
|
count: 0,
|
||||||
users: process.server ? [] : window.users,
|
users: process.server ? [] : window.users
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
const { set, remove } = this.$meta().addApp('client-only')
|
const { set, remove } = this.$meta().addApp('client-only')
|
||||||
set({
|
set({
|
||||||
bodyAttrs: { class: 'client-only' },
|
bodyAttrs: { class: 'client-only' }
|
||||||
})
|
})
|
||||||
|
|
||||||
setTimeout(() => remove(), 3000)
|
setTimeout(() => remove(), 3000)
|
||||||
@@ -130,7 +130,7 @@ export default function createMyApp() {
|
|||||||
methods: {
|
methods: {
|
||||||
loadCallback () {
|
loadCallback () {
|
||||||
this.count++
|
this.count++
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
template: `
|
template: `
|
||||||
<div id="app">
|
<div id="app">
|
||||||
@@ -146,7 +146,7 @@ export default function createMyApp() {
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<router-view />
|
<router-view />
|
||||||
</div>`,
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
|||||||
@@ -30,17 +30,17 @@ export async function renderPage({ url }) {
|
|||||||
const pageHtml = compiled({
|
const pageHtml = compiled({
|
||||||
app: appHtml,
|
app: appHtml,
|
||||||
htmlAttrs: {
|
htmlAttrs: {
|
||||||
text: () => {},
|
text: () => {}
|
||||||
},
|
},
|
||||||
headAttrs: {
|
headAttrs: {
|
||||||
text: () => {},
|
text: () => {}
|
||||||
},
|
},
|
||||||
bodyAttrs: {
|
bodyAttrs: {
|
||||||
text: () => {},
|
text: () => {}
|
||||||
},
|
},
|
||||||
head: () => {},
|
head: () => {},
|
||||||
bodyPrepend: () => {},
|
bodyPrepend: () => {},
|
||||||
bodyAppend: () => {},
|
bodyAppend: () => {}
|
||||||
// ...app.$meta().inject()
|
// ...app.$meta().inject()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -27,5 +27,3 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
useMeta()
|
|
||||||
|
|||||||
+46
-46
@@ -6,10 +6,10 @@ import {
|
|||||||
inject,
|
inject,
|
||||||
toRefs,
|
toRefs,
|
||||||
h,
|
h,
|
||||||
watch,
|
watch
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
import { createManager, useMeta, useMetainfo } from '../../src'
|
import { createManager, useMeta, useMetainfo } from 'vue-meta'
|
||||||
// import About from './about.vue'
|
// import About from './about.vue'
|
||||||
|
|
||||||
const metaUpdated = 'no'
|
const metaUpdated = 'no'
|
||||||
@@ -17,7 +17,7 @@ const metaUpdated = 'no'
|
|||||||
const ChildComponent = defineComponent({
|
const ChildComponent = defineComponent({
|
||||||
name: 'child-component',
|
name: 'child-component',
|
||||||
props: {
|
props: {
|
||||||
page: String,
|
page: String
|
||||||
},
|
},
|
||||||
template: `
|
template: `
|
||||||
<div>
|
<div>
|
||||||
@@ -27,24 +27,24 @@ const ChildComponent = defineComponent({
|
|||||||
setup (props) {
|
setup (props) {
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
date: null,
|
date: null,
|
||||||
metaUpdated,
|
metaUpdated
|
||||||
})
|
})
|
||||||
|
|
||||||
const title = props.page[0].toUpperCase() + props.page.slice(1)
|
const title = props.page[0].toUpperCase() + props.page.slice(1)
|
||||||
console.log('ChildComponent Setup')
|
console.log('ChildComponent Setup')
|
||||||
useMeta({
|
/* useMeta({
|
||||||
charset: 'utf16',
|
charset: 'utf16',
|
||||||
title,
|
title,
|
||||||
description: 'Description ' + props.page,
|
description: 'Description ' + props.page,
|
||||||
og: {
|
og: {
|
||||||
title: 'Og Title ' + props.page,
|
title: 'Og Title ' + props.page,
|
||||||
},
|
},
|
||||||
})
|
}) */
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...toRefs(state),
|
...toRefs(state)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
function view (page) {
|
function view (page) {
|
||||||
@@ -52,7 +52,7 @@ function view(page) {
|
|||||||
name: `section-${page}`,
|
name: `section-${page}`,
|
||||||
render () {
|
render () {
|
||||||
return h(ChildComponent, { page })
|
return h(ChildComponent, { page })
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,69 +69,69 @@ const App = {
|
|||||||
description: 'Bla bla',
|
description: 'Bla bla',
|
||||||
image: [
|
image: [
|
||||||
'https://picsum.photos/600/400/?image=80',
|
'https://picsum.photos/600/400/?image=80',
|
||||||
'https://picsum.photos/600/400/?image=82',
|
'https://picsum.photos/600/400/?image=82'
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
title: 'Twitter Title',
|
title: 'Twitter Title'
|
||||||
},
|
},
|
||||||
noscript: [
|
noscript: [
|
||||||
'<!-- // A code comment -->',
|
//'<!-- // A code comment -->',
|
||||||
{ tag: 'link', rel: 'stylesheet', href: 'style.css' },
|
{ tag: 'link', rel: 'stylesheet', href: 'style.css' }
|
||||||
],
|
],
|
||||||
otherNoscript: {
|
otherNoscript: {
|
||||||
tag: 'noscript',
|
tag: 'noscript',
|
||||||
'data-test': 'hello',
|
'data-test': 'hello',
|
||||||
content: [
|
children: [
|
||||||
'<!-- // Another code comment -->',
|
//'<!-- // Another code comment -->',
|
||||||
{ tag: 'link', rel: 'stylesheet', href: 'style2.css' },
|
{ tag: 'link', rel: 'stylesheet', href: 'style2.css' }
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
body: 'body-script1.js',
|
body: 'body-script1.js',
|
||||||
script: [
|
script: [
|
||||||
'<!--[if IE]>',
|
//'<!--[if IE]>',
|
||||||
{ src: 'head-script1.js' },
|
{ src: 'head-script1.js' },
|
||||||
'<![endif]-->',
|
//'<![endif]-->',
|
||||||
{ src: 'body-script2.js', target: 'body' },
|
{ src: 'body-script2.js', to: 'body' },
|
||||||
{ src: 'body-script3.js', target: '#put-it-here' },
|
{ src: 'body-script3.js', to: '#put-it-here' }
|
||||||
],
|
],
|
||||||
esi: {
|
esi: {
|
||||||
content: [
|
children: [
|
||||||
{
|
{
|
||||||
tag: 'choose',
|
tag: 'choose',
|
||||||
content: [
|
children: [
|
||||||
{
|
{
|
||||||
tag: 'when',
|
tag: 'when',
|
||||||
test: '$(HTTP_COOKIE{group})=="Advanced"',
|
test: '$(HTTP_COOKIE{group})=="Advanced"',
|
||||||
content: [
|
children: [
|
||||||
{
|
{
|
||||||
tag: 'include',
|
tag: 'include',
|
||||||
src: 'http://www.example.com/advanced.html',
|
src: 'http://www.example.com/advanced.html'
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
setTimeout(() => (meta.title = 'My Updated Title'), 2000)
|
setTimeout(() => (meta.title = 'My Updated Title'), 2000)
|
||||||
|
|
||||||
const metainfo = useMetainfo()
|
const metadata = useMetainfo()
|
||||||
|
|
||||||
window.$metainfo = metainfo
|
window.$metainfo = metadata
|
||||||
|
|
||||||
watch(metainfo, (newValue, oldValue) => {
|
watch(metadata, (newValue, oldValue) => {
|
||||||
console.log('UPDATE', newValue)
|
console.log('UPDATE', newValue)
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
metainfo,
|
metadata
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `
|
template: `
|
||||||
<metainfo :metainfo="metainfo">
|
<metainfo :metainfo="metadata">
|
||||||
<template v-slot:base="{ content, metainfo }">http://nuxt.dev:3000{{ content }}</template>
|
<template v-slot:base="{ content, metainfo }">http://nuxt.dev:3000{{ content }}</template>
|
||||||
<template v-slot:title="{ content, metainfo }">{{ content }} - {{ metainfo.description }} - Hello</template>
|
<template v-slot:title="{ content, metainfo }">{{ content }} - {{ metainfo.description }} - Hello</template>
|
||||||
<template v-slot:og(title)="{ content, metainfo, og }">
|
<template v-slot:og(title)="{ content, metainfo, og }">
|
||||||
@@ -148,7 +148,7 @@ const App = {
|
|||||||
</transition>
|
</transition>
|
||||||
<p>Inspect Element to see the meta info</p>
|
<p>Inspect Element to see the meta info</p>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
function decisionMaker5000000 (key, pathSegments, getOptions, getCurrentValue) {
|
function decisionMaker5000000 (key, pathSegments, getOptions, getCurrentValue) {
|
||||||
@@ -177,26 +177,26 @@ const metaManager = createManager({
|
|||||||
esi: {
|
esi: {
|
||||||
group: true,
|
group: true,
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
contentAttributes: ['src', 'test', 'text'],
|
attributes: ['src', 'test', 'text']
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
useMeta(
|
/* useMeta(
|
||||||
{
|
{
|
||||||
og: {
|
og: {
|
||||||
something: 'test',
|
something: 'test',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
metaManager
|
metaManager
|
||||||
)
|
) */
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory('/vue-router'),
|
history: createWebHistory('/vue-router'),
|
||||||
routes: [
|
routes: [
|
||||||
{ name: 'home', path: '/', component: view('home') },
|
{ name: 'home', path: '/', component: view('home') },
|
||||||
{ name: 'about', path: '/about', component: view('about') },
|
{ name: 'about', path: '/about', component: view('about') }
|
||||||
],
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ export default new Router({
|
|||||||
base: '/vuex-async',
|
base: '/vuex-async',
|
||||||
routes: [
|
routes: [
|
||||||
{ path: '/', component: Home },
|
{ path: '/', component: Home },
|
||||||
{ path: '/posts/:slug', component: Post },
|
{ path: '/posts/:slug', component: Post }
|
||||||
],
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -14,28 +14,28 @@ export default new Vuex.Store({
|
|||||||
title: '',
|
title: '',
|
||||||
content: '',
|
content: '',
|
||||||
slug: '',
|
slug: '',
|
||||||
published: false,
|
published: false
|
||||||
},
|
},
|
||||||
posts: [
|
posts: [
|
||||||
{
|
{
|
||||||
slug: 'a-sample-blog-post',
|
slug: 'a-sample-blog-post',
|
||||||
title: 'A Sample Blog Post',
|
title: 'A Sample Blog Post',
|
||||||
content: 'This is the blog post content',
|
content: 'This is the blog post content',
|
||||||
published: true,
|
published: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
slug: 'an-unpublished-blog-post',
|
slug: 'an-unpublished-blog-post',
|
||||||
title: 'An Unpublished Blog Post',
|
title: 'An Unpublished Blog Post',
|
||||||
content: 'This is the blog post content',
|
content: 'This is the blog post content',
|
||||||
published: false,
|
published: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
slug: 'another-blog-post',
|
slug: 'another-blog-post',
|
||||||
title: 'Another Blog Post',
|
title: 'Another Blog Post',
|
||||||
content: 'This is the blog post content',
|
content: 'This is the blog post content',
|
||||||
published: true,
|
published: true
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
// GETTERS
|
// GETTERS
|
||||||
@@ -51,7 +51,7 @@ export default new Vuex.Store({
|
|||||||
},
|
},
|
||||||
publishedPostsCount (state, getters) {
|
publishedPostsCount (state, getters) {
|
||||||
return getters.publishedPosts.length
|
return getters.publishedPosts.length
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// MUTATIONS
|
// MUTATIONS
|
||||||
@@ -61,7 +61,7 @@ export default new Vuex.Store({
|
|||||||
},
|
},
|
||||||
getPost (state, { slug }) {
|
getPost (state, { slug }) {
|
||||||
state.post = state.posts.find(post => post.slug === slug)
|
state.post = state.posts.find(post => post.slug === slug)
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// ACTIONS
|
// ACTIONS
|
||||||
@@ -72,6 +72,6 @@ export default new Vuex.Store({
|
|||||||
commit('getPost', payload)
|
commit('getPost', payload)
|
||||||
commit('loadingState', { isLoading: false })
|
commit('loadingState', { isLoading: false })
|
||||||
}, 2000)
|
}, 2000)
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ export default new Router({
|
|||||||
base: '/vuex',
|
base: '/vuex',
|
||||||
routes: [
|
routes: [
|
||||||
{ path: '/', component: Home },
|
{ path: '/', component: Home },
|
||||||
{ path: '/posts/:slug', component: Post },
|
{ path: '/posts/:slug', component: Post }
|
||||||
],
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
+10
-10
@@ -14,28 +14,28 @@ export default new Vuex.Store({
|
|||||||
title: '',
|
title: '',
|
||||||
content: '',
|
content: '',
|
||||||
slug: '',
|
slug: '',
|
||||||
published: false,
|
published: false
|
||||||
},
|
},
|
||||||
posts: [
|
posts: [
|
||||||
{
|
{
|
||||||
slug: 'a-sample-blog-post',
|
slug: 'a-sample-blog-post',
|
||||||
title: 'A Sample Blog Post',
|
title: 'A Sample Blog Post',
|
||||||
content: 'This is the blog post content',
|
content: 'This is the blog post content',
|
||||||
published: true,
|
published: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
slug: 'an-unpublished-blog-post',
|
slug: 'an-unpublished-blog-post',
|
||||||
title: 'An Unpublished Blog Post',
|
title: 'An Unpublished Blog Post',
|
||||||
content: 'This is the blog post content',
|
content: 'This is the blog post content',
|
||||||
published: false,
|
published: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
slug: 'another-blog-post',
|
slug: 'another-blog-post',
|
||||||
title: 'Another Blog Post',
|
title: 'Another Blog Post',
|
||||||
content: 'This is the blog post content',
|
content: 'This is the blog post content',
|
||||||
published: true,
|
published: true
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
// GETTERS
|
// GETTERS
|
||||||
@@ -48,20 +48,20 @@ export default new Vuex.Store({
|
|||||||
},
|
},
|
||||||
publishedPostsCount (state, getters) {
|
publishedPostsCount (state, getters) {
|
||||||
return getters.publishedPosts.length
|
return getters.publishedPosts.length
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// MUTATIONS
|
// MUTATIONS
|
||||||
mutations: {
|
mutations: {
|
||||||
getPost (state, { slug }) {
|
getPost (state, { slug }) {
|
||||||
state.post = state.posts.find(post => post.slug === slug)
|
state.post = state.posts.find(post => post.slug === slug)
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// ACTIONS
|
// ACTIONS
|
||||||
actions: {
|
actions: {
|
||||||
getPost ({ commit }, payload) {
|
getPost ({ commit }, payload) {
|
||||||
commit('getPost', payload)
|
commit('getPost', payload)
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import fs from 'fs'
|
||||||
|
import path from 'path'
|
||||||
|
import webpack from 'webpack'
|
||||||
|
import WebpackBar from 'webpackbar'
|
||||||
|
import { VueLoaderPlugin } from 'vue-loader'
|
||||||
|
|
||||||
|
// const srcDir = path.join(__dirname, '..', 'src')
|
||||||
|
|
||||||
|
export default {
|
||||||
|
devtool: 'inline-source-map',
|
||||||
|
mode: 'development',
|
||||||
|
entry: fs.readdirSync(__dirname)
|
||||||
|
.reduce((entries, dir) => {
|
||||||
|
const fullDir = path.join(__dirname, dir)
|
||||||
|
|
||||||
|
if (dir === 'ssr') {
|
||||||
|
entries[dir] = path.join(fullDir, 'browser.js')
|
||||||
|
} else if (dir === 'vue-router') {
|
||||||
|
const entry = path.join(fullDir, 'app.js')
|
||||||
|
if (fs.statSync(fullDir).isDirectory() && fs.existsSync(entry)) {
|
||||||
|
entries[dir] = entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entries
|
||||||
|
}, {}),
|
||||||
|
output: {
|
||||||
|
path: path.join(__dirname, '__build__'),
|
||||||
|
filename: '[name].js',
|
||||||
|
chunkFilename: '[id].chunk.js',
|
||||||
|
publicPath: '/__build__/'
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/,
|
||||||
|
use: 'ts-loader',
|
||||||
|
exclude: /node_modules/
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: {
|
||||||
|
loader: 'babel-loader',
|
||||||
|
options: {
|
||||||
|
presets: [
|
||||||
|
['@babel/preset-env', {
|
||||||
|
useBuiltIns: 'usage',
|
||||||
|
corejs: '3',
|
||||||
|
targets: { ie: 9, safari: '5.1' }
|
||||||
|
}]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resourceQuery: /blockType=head/,
|
||||||
|
loader: require.resolve('./meta-loader.js')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.vue$/,
|
||||||
|
use: 'vue-loader'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.tsx', '.ts', '.js'],
|
||||||
|
alias: {
|
||||||
|
// this isn't technically needed, since the default `vue` entry for bundlers
|
||||||
|
// is a simple `export * from '@vue/runtime-dom`. However having this
|
||||||
|
// extra re-export somehow causes webpack to always invalidate the module
|
||||||
|
// on the first HMR update and causes the page to reload.
|
||||||
|
vue: 'vue/dist/vue.esm-bundler.js',
|
||||||
|
'vue-meta': path.resolve(__dirname, '../src/')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Expose __dirname to allow automatically setting basename.
|
||||||
|
context: __dirname,
|
||||||
|
node: {
|
||||||
|
__dirname: true
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new WebpackBar(),
|
||||||
|
new VueLoaderPlugin(),
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
|
||||||
|
__DEV__: process.env.NODE_ENV !== 'production'
|
||||||
|
})
|
||||||
|
],
|
||||||
|
devServer: {
|
||||||
|
inline: true,
|
||||||
|
hot: true,
|
||||||
|
stats: 'minimal',
|
||||||
|
contentBase: __dirname,
|
||||||
|
overlay: true
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-3
@@ -14,7 +14,7 @@ module.exports = {
|
|||||||
coverageDirectory: './coverage',
|
coverageDirectory: './coverage',
|
||||||
|
|
||||||
collectCoverageFrom: [
|
collectCoverageFrom: [
|
||||||
'**/src/**/*.js'
|
'**/src/**/*.[tj]s'
|
||||||
],
|
],
|
||||||
|
|
||||||
coveragePathIgnorePatterns: [
|
coveragePathIgnorePatterns: [
|
||||||
@@ -30,7 +30,7 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
|
|
||||||
transform: {
|
transform: {
|
||||||
'^.+\\.js$': 'babel-jest',
|
'^.+\\.[tj]s$': 'babel-jest',
|
||||||
'.*\\.(vue)$': 'vue-jest'
|
'.*\\.(vue)$': 'vue-jest'
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -38,5 +38,9 @@ module.exports = {
|
|||||||
'ts',
|
'ts',
|
||||||
'js',
|
'js',
|
||||||
'json'
|
'json'
|
||||||
]
|
],
|
||||||
|
|
||||||
|
globals: {
|
||||||
|
__DEV__: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-23
@@ -32,10 +32,10 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rimraf dist && rollup -c scripts/rollup.config.js",
|
"build": "rimraf dist && rollup -c scripts/rollup.config.js",
|
||||||
"coverage": "codecov",
|
"coverage": "codecov",
|
||||||
"dev": "webpack-dev-server --mode=development",
|
"dev": "babel-node examples/server.js",
|
||||||
"docs": "vuepress dev --host 0.0.0.0 --port 3000 docs",
|
"docs": "vuepress dev --host 0.0.0.0 --port 3000 docs",
|
||||||
"docs:build": "vuepress build docs",
|
"docs:build": "vuepress build docs",
|
||||||
"lint": "prettier -c --parser typescript \"{examples,src,test,e2e}/**/*.[jt]s?(x)\"",
|
"lint": "eslint --ext .js,.ts examples src test",
|
||||||
"prerelease": "git checkout master && git pull -r",
|
"prerelease": "git checkout master && git pull -r",
|
||||||
"release": "yarn lint && yarn test && standard-version",
|
"release": "yarn lint && yarn test && standard-version",
|
||||||
"test": "yarn test:unit && yarn test:e2e-ssr && yarn test:e2e-browser",
|
"test": "yarn test:unit && yarn test:e2e-ssr && yarn test:e2e-browser",
|
||||||
@@ -48,27 +48,40 @@
|
|||||||
"vue": "next"
|
"vue": "next"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/webpack": "^4.41.16",
|
"@babel/core": "^7.10.5",
|
||||||
|
"@babel/node": "^7.10.5",
|
||||||
|
"@babel/preset-env": "^7.10.4",
|
||||||
|
"@babel/preset-typescript": "^7.10.4",
|
||||||
|
"@nuxtjs/eslint-config-typescript": "^2.0.0",
|
||||||
|
"@types/webpack": "^4.41.21",
|
||||||
"@types/webpack-env": "^1.15.2",
|
"@types/webpack-env": "^1.15.2",
|
||||||
"@vue/compiler-sfc": "^3.0.0-beta.14",
|
"@typescript-eslint/eslint-plugin": "^3.7.0",
|
||||||
|
"@typescript-eslint/parser": "^3.7.0",
|
||||||
|
"@vue/compiler-sfc": "^3.0.0-rc.4",
|
||||||
|
"@vue/server-renderer": "^3.0.0-rc.4",
|
||||||
"@vue/server-test-utils": "^1.0.3",
|
"@vue/server-test-utils": "^1.0.3",
|
||||||
"@vue/test-utils": "^1.0.3",
|
"@vue/test-utils": "^1.0.3",
|
||||||
"@wishy-gift/html-include-chunks-webpack-plugin": "^0.1.5",
|
"@wishy-gift/html-include-chunks-webpack-plugin": "^0.1.5",
|
||||||
|
"babel-jest": "^26.1.0",
|
||||||
|
"babel-loader": "^8.1.0",
|
||||||
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||||
"browserstack-local": "^1.4.5",
|
"browserstack-local": "^1.4.5",
|
||||||
"chromedriver": "^83.0.0",
|
"chromedriver": "^84.0.1",
|
||||||
"codecov": "^3.7.0",
|
"codecov": "^3.7.2",
|
||||||
|
"consola": "^2.14.0",
|
||||||
|
"eslint": "^7.5.0",
|
||||||
|
"express-urlrewrite": "^1.3.0",
|
||||||
"geckodriver": "^1.19.1",
|
"geckodriver": "^1.19.1",
|
||||||
"html-webpack-plugin": "^4.3.0",
|
"html-webpack-plugin": "^4.3.0",
|
||||||
"jest": "^26.0.1",
|
"jest": "^26.1.0",
|
||||||
"jest-environment-jsdom": "^26.0.1",
|
"jest-environment-jsdom": "^26.1.0",
|
||||||
"jest-environment-jsdom-global": "^2.0.2",
|
"jest-environment-jsdom-global": "^2.0.4",
|
||||||
"jsdom": "^16.2.2",
|
"jsdom": "^16.3.0",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.19",
|
||||||
"node-env-file": "^0.1.8",
|
"node-env-file": "^0.1.8",
|
||||||
"prettier": "^2.0.5",
|
"puppeteer-core": "^5.2.1",
|
||||||
"puppeteer-core": "^3.2.0",
|
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"rollup": "^2.11.2",
|
"rollup": "^2.23.0",
|
||||||
"rollup-plugin-babel": "^4.4.0",
|
"rollup-plugin-babel": "^4.4.0",
|
||||||
"rollup-plugin-commonjs": "^10.1.0",
|
"rollup-plugin-commonjs": "^10.1.0",
|
||||||
"rollup-plugin-json": "^4.0.0",
|
"rollup-plugin-json": "^4.0.0",
|
||||||
@@ -76,20 +89,21 @@
|
|||||||
"rollup-plugin-replace": "^2.2.0",
|
"rollup-plugin-replace": "^2.2.0",
|
||||||
"rollup-plugin-terser": "^6.1.0",
|
"rollup-plugin-terser": "^6.1.0",
|
||||||
"rollup-plugin-typescript2": "^0.27.1",
|
"rollup-plugin-typescript2": "^0.27.1",
|
||||||
"selenium-webdriver": "^4.0.0-alpha.5",
|
"selenium-webdriver": "^4.0.0-alpha.7",
|
||||||
"standard-version": "^8.0.0",
|
"standard-version": "^8.0.2",
|
||||||
"tib": "^0.7.4",
|
"tib": "^0.7.4",
|
||||||
"ts-jest": "^26.1.0",
|
"ts-jest": "^26.1.3",
|
||||||
"ts-loader": "^7.0.5",
|
"ts-loader": "^8.0.1",
|
||||||
"ts-node": "^8.10.2",
|
"ts-node": "^8.10.2",
|
||||||
"typescript": "^3.9.3",
|
"typescript": "^3.9.7",
|
||||||
"vue": "next",
|
"vue": "next",
|
||||||
"vue-jest": "^3.0.5",
|
"vue-jest": "^3.0.6",
|
||||||
"vue-loader": "^16.0.0-beta.2",
|
"vue-loader": "^16.0.0-beta.2",
|
||||||
"vue-router": "next",
|
"vue-router": "next",
|
||||||
"webpack": "^4.43.0",
|
"webpack": "^4.44.0",
|
||||||
"webpack-bundle-analyzer": "^3.8.0",
|
"webpack-bundle-analyzer": "^3.8.0",
|
||||||
"webpack-cli": "^3.3.11",
|
"webpack-cli": "^3.3.12",
|
||||||
"webpack-dev-server": "^3.11.0"
|
"webpack-dev-server": "^3.11.0",
|
||||||
|
"webpackbar": "^4.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-17
@@ -8,12 +8,12 @@ export interface MetainfoProps {
|
|||||||
metainfo: MetainfoActive
|
metainfo: MetainfoActive
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addVnode(targets: any, target: string, vnode: VNode) {
|
export function addVnode (teleports: any, to: string, vnode: VNode) {
|
||||||
if (!targets[target]) {
|
if (!teleports[to]) {
|
||||||
targets[target] = []
|
teleports[to] = []
|
||||||
}
|
}
|
||||||
|
|
||||||
targets[target].push(vnode)
|
teleports[to].push(vnode)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MetainfoImpl = defineComponent({
|
export const MetainfoImpl = defineComponent({
|
||||||
@@ -21,12 +21,12 @@ export const MetainfoImpl = defineComponent({
|
|||||||
props: {
|
props: {
|
||||||
metainfo: {
|
metainfo: {
|
||||||
type: Object as PropType<MetainfoActive>,
|
type: Object as PropType<MetainfoActive>,
|
||||||
required: true,
|
required: true
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
setup ({ metainfo }, { slots }) {
|
setup ({ metainfo }, { slots }) {
|
||||||
return () => {
|
return () => {
|
||||||
const targets: any = {}
|
const teleports: any = {}
|
||||||
|
|
||||||
const manager = getCurrentManager()
|
const manager = getCurrentManager()
|
||||||
|
|
||||||
@@ -39,26 +39,29 @@ export const MetainfoImpl = defineComponent({
|
|||||||
metainfo[key],
|
metainfo[key],
|
||||||
config
|
config
|
||||||
)
|
)
|
||||||
let defaultTarget =
|
console.log('RENDERED VNODES', vnodes)
|
||||||
(key !== 'base' && metainfo[key].target) || config.target || 'head'
|
const defaultTo =
|
||||||
|
(key !== 'base' && metainfo[key].to) || config.to || 'head'
|
||||||
|
|
||||||
if (isArray(vnodes)) {
|
if (isArray(vnodes)) {
|
||||||
for (const { target, vnode } of vnodes) {
|
for (const { to, vnode } of vnodes) {
|
||||||
addVnode(targets, target || defaultTarget, vnode)
|
console.log('VNODE 1', vnode)
|
||||||
|
addVnode(teleports, to || defaultTo, vnode)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const { target, vnode } = vnodes
|
const { to, vnode } = vnodes
|
||||||
addVnode(targets, target || defaultTarget, vnode)
|
console.log('VNODE 2', vnode)
|
||||||
|
addVnode(teleports, to || defaultTo, vnode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log('TARGETS', targets)
|
console.log('TARGETS', teleports)
|
||||||
return Object.keys(targets).map(target => {
|
return Object.keys(teleports).map((to) => {
|
||||||
return h(Teleport, { to: target }, targets[target])
|
return h(Teleport, { to }, teleports[to])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export const Metainfo = (MetainfoImpl as any) as {
|
export const Metainfo = (MetainfoImpl as any) as {
|
||||||
|
|||||||
+18
-23
@@ -4,10 +4,10 @@ import { TODO } from './types'
|
|||||||
|
|
||||||
export interface ConfigOption {
|
export interface ConfigOption {
|
||||||
tag?: string
|
tag?: string
|
||||||
target?: string
|
to?: string
|
||||||
group?: boolean
|
group?: boolean
|
||||||
nameAttribute?: string
|
keyAttribute?: string
|
||||||
contentAttribute?: string
|
valueAttribute?: string
|
||||||
nameless?: boolean
|
nameless?: boolean
|
||||||
namespaced?: boolean
|
namespaced?: boolean
|
||||||
namespacedAttribute?: boolean
|
namespacedAttribute?: boolean
|
||||||
@@ -16,30 +16,30 @@ export interface ConfigOption {
|
|||||||
const defaultMapping: { [key: string]: ConfigOption } = {
|
const defaultMapping: { [key: string]: ConfigOption } = {
|
||||||
body: {
|
body: {
|
||||||
tag: 'script',
|
tag: 'script',
|
||||||
target: 'body',
|
to: 'body'
|
||||||
},
|
},
|
||||||
base: {
|
base: {
|
||||||
contentAttribute: 'href',
|
valueAttribute: 'href'
|
||||||
},
|
},
|
||||||
charset: {
|
charset: {
|
||||||
tag: 'meta',
|
tag: 'meta',
|
||||||
nameless: true,
|
nameless: true,
|
||||||
contentAttribute: 'charset',
|
valueAttribute: 'charset'
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
tag: 'meta',
|
tag: 'meta'
|
||||||
},
|
},
|
||||||
og: {
|
og: {
|
||||||
group: true,
|
group: true,
|
||||||
namespacedAttribute: true,
|
namespacedAttribute: true,
|
||||||
tag: 'meta',
|
tag: 'meta',
|
||||||
nameAttribute: 'property',
|
keyAttribute: 'property'
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
group: true,
|
group: true,
|
||||||
namespacedAttribute: true,
|
namespacedAttribute: true,
|
||||||
tag: 'meta',
|
tag: 'meta'
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { defaultMapping }
|
export { defaultMapping }
|
||||||
@@ -49,31 +49,26 @@ export function hasConfig(name: string): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getConfigKey (
|
export function getConfigKey (
|
||||||
name: string | Array<string>,
|
tagOrName: string | Array<string>,
|
||||||
key: string,
|
key: string,
|
||||||
config: TODO,
|
config: TODO
|
||||||
dontLog?: boolean
|
|
||||||
): any {
|
): any {
|
||||||
if (!dontLog) {
|
|
||||||
// console.log('getConfigKey', name, key, getConfigKey(name, key, config, true), config)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config && key in config) {
|
if (config && key in config) {
|
||||||
return config[key]
|
return config[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isArray(name)) {
|
if (isArray(tagOrName)) {
|
||||||
for (const _name of name) {
|
for (const name of tagOrName) {
|
||||||
if (_name && _name in tags) {
|
if (name && name in tags) {
|
||||||
return tags[_name][key]
|
return tags[name][key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name in tags) {
|
if (tagOrName in tags) {
|
||||||
const tag = tags[name]
|
const tag = tags[tagOrName]
|
||||||
return tag[key]
|
return tag[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-15
@@ -1,22 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* This is a fixed config for real HTML tags
|
||||||
|
*
|
||||||
|
* TODO: we probably dont need all attributes
|
||||||
|
*/
|
||||||
|
|
||||||
export interface TagConfig {
|
export interface TagConfig {
|
||||||
nameAttribute?: string
|
keyAttribute?: string
|
||||||
contentAttributes: boolean | Array<string>
|
attributes: boolean | Array<string>
|
||||||
[key: string]: any
|
[key: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
const tags: { [key: string]: TagConfig } = {
|
const tags: { [key: string]: TagConfig } = {
|
||||||
title: {
|
title: {
|
||||||
contentAttributes: false,
|
attributes: false
|
||||||
},
|
},
|
||||||
base: {
|
base: {
|
||||||
contentAttributes: ['href', 'target'],
|
attributes: ['href', 'target']
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
nameAttribute: 'name',
|
keyAttribute: 'name',
|
||||||
contentAttributes: ['content', 'name', 'http-equiv', 'charset'],
|
attributes: ['content', 'name', 'http-equiv', 'charset']
|
||||||
},
|
},
|
||||||
link: {
|
link: {
|
||||||
contentAttributes: [
|
attributes: [
|
||||||
'href',
|
'href',
|
||||||
'crossorigin',
|
'crossorigin',
|
||||||
'rel',
|
'rel',
|
||||||
@@ -29,14 +35,14 @@ const tags: { [key: string]: TagConfig } = {
|
|||||||
'imagesrcset',
|
'imagesrcset',
|
||||||
'imagesizes',
|
'imagesizes',
|
||||||
'as',
|
'as',
|
||||||
'color',
|
'color'
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
contentAttributes: ['media'],
|
attributes: ['media']
|
||||||
},
|
},
|
||||||
script: {
|
script: {
|
||||||
contentAttributes: [
|
attributes: [
|
||||||
'src',
|
'src',
|
||||||
'type',
|
'type',
|
||||||
'nomodule',
|
'nomodule',
|
||||||
@@ -44,12 +50,12 @@ const tags: { [key: string]: TagConfig } = {
|
|||||||
'defer',
|
'defer',
|
||||||
'crossorigin',
|
'crossorigin',
|
||||||
'integrity',
|
'integrity',
|
||||||
'referrerpolicy',
|
'referrerpolicy'
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
noscript: {
|
noscript: {
|
||||||
contentAttributes: false,
|
attributes: false
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { tags }
|
export { tags }
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
// Global compile-time constants
|
// Global compile-time constants
|
||||||
declare var __DEV__: boolean
|
declare let __DEV__: boolean
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
import { setByObject } from './set'
|
|
||||||
import { MetaContext } from '../types'
|
import { MetaContext } from '../types'
|
||||||
|
import { setByObject } from './set'
|
||||||
|
|
||||||
export function remove (context: MetaContext) {
|
export function remove (context: MetaContext) {
|
||||||
setByObject(context, {})
|
setByObject(context, {})
|
||||||
|
|||||||
+4
-4
@@ -1,7 +1,7 @@
|
|||||||
import { isPlainObject, hasOwn } from '@vue/shared'
|
import { isPlainObject, hasOwn } from '@vue/shared'
|
||||||
|
import { ActiveNode, MetaContext, PathSegments, ShadowNode } from '../types'
|
||||||
import { shadow, active } from './globals'
|
import { shadow, active } from './globals'
|
||||||
import { resolveActive } from './resolve'
|
import { resolveActive } from './resolve'
|
||||||
import { ActiveNode, MetaContext, PathSegments, ShadowNode } from '../types'
|
|
||||||
|
|
||||||
export function set (
|
export function set (
|
||||||
context: MetaContext,
|
context: MetaContext,
|
||||||
@@ -70,14 +70,14 @@ export function setByObject(
|
|||||||
if (isPlainObject(shadowParent[key])) {
|
if (isPlainObject(shadowParent[key])) {
|
||||||
setByObject(context, {}, shadowParent[key], activeParent[key], [
|
setByObject(context, {}, shadowParent[key], activeParent[key], [
|
||||||
...pathSegments,
|
...pathSegments,
|
||||||
key,
|
key
|
||||||
])
|
])
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
set(context, key, undefined, shadowParent, activeParent, [
|
set(context, key, undefined, shadowParent, activeParent, [
|
||||||
...pathSegments,
|
...pathSegments,
|
||||||
key,
|
key
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ export function setByObject(
|
|||||||
for (const key in value) {
|
for (const key in value) {
|
||||||
set(context, key, value[key], shadowParent, activeParent, [
|
set(context, key, value[key], shadowParent, activeParent, [
|
||||||
...pathSegments,
|
...pathSegments,
|
||||||
key,
|
key
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
|
import { MetaContext, PathSegments, ShadowNode, ActiveNode } from '../types'
|
||||||
import { shadow, active } from './globals'
|
import { shadow, active } from './globals'
|
||||||
import { set } from './set'
|
import { set } from './set'
|
||||||
import { MetaContext, PathSegments, ShadowNode, ActiveNode } from '../types'
|
|
||||||
|
|
||||||
export function update (
|
export function update (
|
||||||
context: MetaContext,
|
context: MetaContext,
|
||||||
|
|||||||
+3
-3
@@ -40,15 +40,15 @@ export function createManager(options: TODO = {}): Manager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return resolver.resolve(key, pathSegments, getShadow, getActive)
|
return resolver.resolve(key, pathSegments, getShadow, getActive)
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
...defaultMapping,
|
...defaultMapping,
|
||||||
...options.config,
|
...options.config
|
||||||
},
|
},
|
||||||
install (app: App) {
|
install (app: App) {
|
||||||
applyMetaPlugin(app, this)
|
applyMetaPlugin(app, this)
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return manager
|
return manager
|
||||||
|
|||||||
+4
-5
@@ -4,7 +4,7 @@ import { update } from './info/update'
|
|||||||
import { MetaContext, MetainfoInput, PathSegments } from './types'
|
import { MetaContext, MetainfoInput, PathSegments } from './types'
|
||||||
|
|
||||||
interface Target extends MetainfoInput {
|
interface Target extends MetainfoInput {
|
||||||
__vm_proxy?: any
|
__vm_proxy?: any // eslint-disable-line camelcase
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createProxy (
|
export function createProxy (
|
||||||
@@ -36,13 +36,12 @@ export function createHandler(
|
|||||||
return value.__vm_proxy
|
return value.__vm_proxy
|
||||||
},
|
},
|
||||||
set (
|
set (
|
||||||
target: object,
|
target: object, // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||||
key: string,
|
key: string,
|
||||||
value: unknown,
|
value: unknown
|
||||||
receiver: object
|
|
||||||
): boolean {
|
): boolean {
|
||||||
update(context, pathSegments, key, value)
|
update(context, pathSegments, key, value)
|
||||||
return true
|
return true
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+48
-48
@@ -24,7 +24,7 @@ export interface SlotScopeProperties {
|
|||||||
|
|
||||||
export type RenderedMetainfoNode = {
|
export type RenderedMetainfoNode = {
|
||||||
vnode: VNode
|
vnode: VNode
|
||||||
target?: string
|
to?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RenderedMetainfo = Array<RenderedMetainfoNode>
|
export type RenderedMetainfo = Array<RenderedMetainfoNode>
|
||||||
@@ -35,7 +35,7 @@ export function renderMeta(
|
|||||||
data: TODO,
|
data: TODO,
|
||||||
config: TODO
|
config: TODO
|
||||||
): RenderedMetainfo | RenderedMetainfoNode {
|
): RenderedMetainfo | RenderedMetainfoNode {
|
||||||
// console.info('renderMeta', key, data, config)
|
console.info('renderMeta', key, data, config)
|
||||||
|
|
||||||
if (config.group) {
|
if (config.group) {
|
||||||
return renderGroup(context, key, data, config)
|
return renderGroup(context, key, data, config)
|
||||||
@@ -50,27 +50,26 @@ export function renderGroup(
|
|||||||
data: TODO,
|
data: TODO,
|
||||||
config: TODO
|
config: TODO
|
||||||
): RenderedMetainfo | RenderedMetainfoNode {
|
): RenderedMetainfo | RenderedMetainfoNode {
|
||||||
// console.info('renderGroup', key, data, config)
|
console.info('renderGroup', key, data, config)
|
||||||
|
|
||||||
if (isArray(data)) {
|
if (isArray(data)) {
|
||||||
config.contentAttributes = getConfigKey(
|
if (__DEV__) {
|
||||||
[key, config.tag],
|
// eslint-disable-next-line no-console
|
||||||
'contentAttributes',
|
console.warn('Specifying an array for group properties isnt supported as we didnt found a use-case for this yet. If you have one, please create an issue on the vue-meta repo')
|
||||||
config
|
}
|
||||||
)
|
// config.attributes = getConfigKey([key, config.tag], 'attributes', config)
|
||||||
return data.map(_data => renderTag(context, key, _data, config)).flat()
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.keys(data)
|
return Object.keys(data)
|
||||||
.map(childKey => {
|
.map((childKey) => {
|
||||||
const groupConfig: GroupConfig = {
|
const groupConfig: GroupConfig = {
|
||||||
group: key,
|
group: key,
|
||||||
data,
|
data
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.namespaced) {
|
if (config.namespaced) {
|
||||||
groupConfig.tagNamespace =
|
groupConfig.tagNamespace = config.namespaced === true ? key : config.namespaced
|
||||||
config.namespaced === true ? key : config.namespaced
|
|
||||||
} else if (config.namespacedAttribute) {
|
} else if (config.namespacedAttribute) {
|
||||||
const namespace =
|
const namespace =
|
||||||
config.namespacedAttribute === true ? key : config.namespacedAttribute
|
config.namespacedAttribute === true ? key : config.namespacedAttribute
|
||||||
@@ -91,24 +90,30 @@ export function renderTag(
|
|||||||
config: TODO = {},
|
config: TODO = {},
|
||||||
groupConfig?: GroupConfig
|
groupConfig?: GroupConfig
|
||||||
): RenderedMetainfo | RenderedMetainfoNode {
|
): RenderedMetainfo | RenderedMetainfoNode {
|
||||||
|
console.info('renderTag', key, data, config, groupConfig)
|
||||||
|
|
||||||
|
/* TODO: not needed I think
|
||||||
if (!config.group && isArray(data)) {
|
if (!config.group && isArray(data)) {
|
||||||
data = { content: data }
|
data = { children: data }
|
||||||
}
|
} */
|
||||||
|
|
||||||
let content, hasChilds
|
let content, hasChilds
|
||||||
|
|
||||||
if (isArray(data)) {
|
if (isArray(data)) {
|
||||||
return data
|
return data
|
||||||
.map(child => {
|
.map((child) => {
|
||||||
return renderTag(context, key, child, config, groupConfig)
|
return renderTag(context, key, child, config, groupConfig)
|
||||||
})
|
})
|
||||||
.flat()
|
.flat()
|
||||||
} else if (data.content && isArray(data.content)) {
|
} else if (data.children && isArray(data.children)) {
|
||||||
content = data.content.map((child: string | TODO) => {
|
content = data.children.map((child: string | TODO) => {
|
||||||
if (typeof child === 'string') {
|
const data = renderTag(context, key, child, config, groupConfig)
|
||||||
return child
|
|
||||||
|
if (isArray(data)) {
|
||||||
|
return data.map(({ vnode }) => vnode)
|
||||||
}
|
}
|
||||||
return renderTag(context, key, child, config, groupConfig)
|
|
||||||
|
return data.vnode
|
||||||
})
|
})
|
||||||
hasChilds = true
|
hasChilds = true
|
||||||
} else {
|
} else {
|
||||||
@@ -125,36 +130,35 @@ export function renderTag(
|
|||||||
attributes = { ...data }
|
attributes = { ...data }
|
||||||
|
|
||||||
delete attributes.tag
|
delete attributes.tag
|
||||||
delete attributes.content
|
delete attributes.children
|
||||||
delete attributes.target
|
delete attributes.to
|
||||||
} else {
|
} else {
|
||||||
attributes = {}
|
attributes = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasChilds) {
|
if (hasChilds) {
|
||||||
content = getSlotContent(context, slotName, content, config, data)
|
content = getSlotContent(context, slotName, content, data)
|
||||||
} else {
|
} else {
|
||||||
const contentAttributes = getConfigKey(tag, 'contentAttributes', config)
|
const tagAttributes = getConfigKey([tag, config.tag], 'attributes', config)
|
||||||
|
console.log('tagAttributes', tagAttributes, config, tag)
|
||||||
if (contentAttributes) {
|
if (tagAttributes) {
|
||||||
if (!config.nameless) {
|
if (!config.nameless) {
|
||||||
const nameAttribute = getConfigKey(tag, 'nameAttribute', config)
|
const keyAttribute = getConfigKey([tag, config.tag], 'keyAttribute', config)
|
||||||
if (nameAttribute) {
|
if (keyAttribute) {
|
||||||
attributes[nameAttribute] = fullName
|
attributes[keyAttribute] = fullName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const contentAttribute = config.contentAttribute || contentAttributes[0]
|
const valueAttribute = config.valueAttribute || tagAttributes[0]
|
||||||
attributes[contentAttribute] = getSlotContent(
|
attributes[valueAttribute] = getSlotContent(
|
||||||
context,
|
context,
|
||||||
slotName,
|
slotName,
|
||||||
attributes[contentAttribute] || content,
|
attributes[valueAttribute] || content,
|
||||||
config,
|
|
||||||
groupConfig
|
groupConfig
|
||||||
)
|
)
|
||||||
content = undefined
|
content = undefined
|
||||||
} else {
|
} else {
|
||||||
content = getSlotContent(context, slotName, content, config, data)
|
content = getSlotContent(context, slotName, content, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,11 +174,8 @@ export function renderTag(
|
|||||||
|
|
||||||
if (hasChilds) {
|
if (hasChilds) {
|
||||||
for (const child of content) {
|
for (const child of content) {
|
||||||
if (typeof child === 'string') {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if (child.type === finalTag) {
|
if (child.type === finalTag) {
|
||||||
|
// TODO: what was this about again?!?!?!?!
|
||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,8 +186,8 @@ export function renderTag(
|
|||||||
const vnode = h(finalTag, attributes, content)
|
const vnode = h(finalTag, attributes, content)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
target: data.target,
|
to: data.to,
|
||||||
vnode,
|
vnode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,27 +195,26 @@ export function getSlotContent(
|
|||||||
{ metainfo, slots }: RenderContext,
|
{ metainfo, slots }: RenderContext,
|
||||||
slotName: string,
|
slotName: string,
|
||||||
content: any,
|
content: any,
|
||||||
config: TODO,
|
|
||||||
groupConfig?: GroupConfig
|
groupConfig?: GroupConfig
|
||||||
): TODO {
|
): TODO {
|
||||||
if (!slots[slotName]) {
|
if (!slots || !slots[slotName]) {
|
||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
|
|
||||||
const slotProps: SlotScopeProperties = {
|
const slotProps: SlotScopeProperties = {
|
||||||
content,
|
content,
|
||||||
metainfo,
|
metainfo
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupConfig && groupConfig.group) {
|
if (groupConfig && groupConfig.group) {
|
||||||
slotProps[groupConfig.group] = groupConfig.data
|
slotProps[groupConfig.group] = groupConfig.data
|
||||||
}
|
}
|
||||||
|
|
||||||
content = slots[slotName](slotProps)
|
const slotContent = slots[slotName](slotProps)
|
||||||
|
|
||||||
if (content.length) {
|
if (slotContent && slotContent.length) {
|
||||||
return content[0].children
|
return slotContent[0].children
|
||||||
}
|
}
|
||||||
|
|
||||||
return ''
|
return content
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {
|
|||||||
ActiveNode,
|
ActiveNode,
|
||||||
/* ActiveResolverSetup, ActiveResolverMethod, */ MetaContext,
|
/* ActiveResolverSetup, ActiveResolverMethod, */ MetaContext,
|
||||||
PathSegments,
|
PathSegments,
|
||||||
ShadowNode,
|
ShadowNode
|
||||||
} from '../types'
|
} from '../types'
|
||||||
|
|
||||||
export function setup (context: MetaContext): void {}
|
export function setup (context: MetaContext): void {}
|
||||||
|
|||||||
+3
-4
@@ -17,16 +17,15 @@ export function useMeta(obj: MetainfoInput, manager?: Manager) {
|
|||||||
if (!manager) {
|
if (!manager) {
|
||||||
// oopsydoopsy
|
// oopsydoopsy
|
||||||
throw new Error('No manager or current instance')
|
throw new Error('No manager or current instance')
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const context: MetaContext = {
|
const context: MetaContext = {
|
||||||
id: PolySymbol(`context ${contextCounter++}`),
|
id: PolySymbol(`context ${contextCounter++}`),
|
||||||
vm,
|
vm,
|
||||||
manager,
|
manager
|
||||||
}
|
}
|
||||||
|
|
||||||
let unmount = <T extends Function = () => any>() => remove(context)
|
const unmount = <T extends Function = () => any>() => remove(context)
|
||||||
if (vm) {
|
if (vm) {
|
||||||
onUnmounted(unmount)
|
onUnmounted(unmount)
|
||||||
}
|
}
|
||||||
@@ -42,7 +41,7 @@ export function useMeta(obj: MetainfoInput, manager?: Manager) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
meta,
|
meta,
|
||||||
unmount,
|
unmount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
process.server = true
|
||||||
|
|
||||||
|
jest.useFakeTimers()
|
||||||
|
jest.setTimeout(30000)
|
||||||
@@ -0,0 +1,432 @@
|
|||||||
|
import * as render from '../../src/render'
|
||||||
|
|
||||||
|
// Note: testing isnt rly independent as they also rely on ./src/config/tags
|
||||||
|
|
||||||
|
describe('render', () => {
|
||||||
|
test('render key-string element (without value attribute)', () => {
|
||||||
|
const context = {}
|
||||||
|
const key = 'TitleTest'
|
||||||
|
const data = 'my title'
|
||||||
|
const config = {
|
||||||
|
tag: 'title'
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = render.renderMeta(context, key, data, config)
|
||||||
|
// console.log('RES', res)
|
||||||
|
|
||||||
|
expect(res.to).toBeUndefined()
|
||||||
|
expect(res.vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
|
||||||
|
expect(res.vnode.type).toEqual('title')
|
||||||
|
expect(res.vnode.props).toEqual({})
|
||||||
|
|
||||||
|
expect(res.vnode.children).toEqual('my title')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('render key-string element (without name attribute)', () => {
|
||||||
|
const context = {}
|
||||||
|
const key = 'CharsetTest'
|
||||||
|
const data = 'utf8'
|
||||||
|
const config = {
|
||||||
|
tag: 'meta',
|
||||||
|
nameless: true,
|
||||||
|
valueAttribute: 'charset'
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = render.renderMeta(context, key, data, config)
|
||||||
|
// console.log('RES', res)
|
||||||
|
|
||||||
|
expect(res.to).toBeUndefined()
|
||||||
|
expect(res.vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
|
||||||
|
expect(res.vnode.type).toEqual('meta')
|
||||||
|
expect(res.vnode.props).toMatchObject({ charset: 'utf8' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('render key-string element (with name attribute)', () => {
|
||||||
|
const context = {}
|
||||||
|
const key = 'DescriptionTest'
|
||||||
|
const data = 'my description'
|
||||||
|
const config = {
|
||||||
|
tag: 'meta'
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = render.renderMeta(context, key, data, config)
|
||||||
|
// console.log('RES', res)
|
||||||
|
|
||||||
|
expect(res.to).toBeUndefined()
|
||||||
|
expect(res.vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
|
||||||
|
expect(res.vnode.type).toEqual('meta')
|
||||||
|
expect(res.vnode.props).toMatchObject({ name: 'DescriptionTest', content: 'my description' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('render key-object element', () => {
|
||||||
|
const context = {}
|
||||||
|
const key = 'DescriptionTest2'
|
||||||
|
const data = { content: 'my description 2' }
|
||||||
|
const config = {
|
||||||
|
tag: 'meta'
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = render.renderMeta(context, key, data, config)
|
||||||
|
// console.log('RES', res)
|
||||||
|
|
||||||
|
expect(res.to).toBeUndefined()
|
||||||
|
expect(res.vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
|
||||||
|
expect(res.vnode.type).toEqual('meta')
|
||||||
|
expect(res.vnode.props).toMatchObject({ name: 'DescriptionTest2', content: 'my description 2' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('render array<key-string> elements', () => {
|
||||||
|
const context = {}
|
||||||
|
const key = 'kal-el'
|
||||||
|
const data = [
|
||||||
|
'man',
|
||||||
|
'woman'
|
||||||
|
]
|
||||||
|
const config = {
|
||||||
|
tag: 'meta',
|
||||||
|
valueAttribute: 'super'
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = render.renderMeta(context, key, data, config)
|
||||||
|
// console.log('RES', res)
|
||||||
|
|
||||||
|
expect(res).toBeInstanceOf(Array)
|
||||||
|
expect(res.length).toBe(2)
|
||||||
|
|
||||||
|
expect(res[0].to).toBeUndefined()
|
||||||
|
expect(res[0].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[0].vnode.type).toEqual('meta')
|
||||||
|
expect(res[0].vnode.props).toMatchObject({ super: 'man' })
|
||||||
|
|
||||||
|
expect(res[1].to).toBeUndefined()
|
||||||
|
expect(res[1].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[1].vnode.type).toEqual('meta')
|
||||||
|
expect(res[1].vnode.props).toMatchObject({ super: 'woman' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('render array<key-object> elements', () => {
|
||||||
|
const context = {}
|
||||||
|
const key = 'kal-el'
|
||||||
|
const data = [
|
||||||
|
{ super: 'man' },
|
||||||
|
{ clark: 'kent' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const config = {}
|
||||||
|
|
||||||
|
const res = render.renderMeta(context, key, data, config)
|
||||||
|
// console.log(res)
|
||||||
|
|
||||||
|
expect(res).toBeInstanceOf(Array)
|
||||||
|
expect(res.length).toBe(2)
|
||||||
|
|
||||||
|
expect(res[0].to).toBeUndefined()
|
||||||
|
expect(res[0].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[0].vnode.type).toEqual('kal-el')
|
||||||
|
expect(res[0].vnode.props).toMatchObject({ super: 'man' })
|
||||||
|
|
||||||
|
expect(res[1].to).toBeUndefined()
|
||||||
|
expect(res[1].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[1].vnode.type).toEqual('kal-el')
|
||||||
|
expect(res[1].vnode.props).toMatchObject({ clark: 'kent' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('render custom group', () => {
|
||||||
|
const context = {}
|
||||||
|
const key = 'customGroup'
|
||||||
|
const data = {
|
||||||
|
title: 'my custom title',
|
||||||
|
description: 'my custom description'
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
group: true,
|
||||||
|
tag: 'meta'
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = render.renderMeta(context, key, data, config)
|
||||||
|
// console.log('RES', res, res[0])
|
||||||
|
|
||||||
|
expect(res).toBeInstanceOf(Array)
|
||||||
|
expect(res.length).toBe(2)
|
||||||
|
|
||||||
|
expect(res[0].to).toBeUndefined()
|
||||||
|
expect(res[0].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[0].vnode.type).toEqual('meta')
|
||||||
|
expect(res[0].vnode.props).toMatchObject({ content: 'my custom title' })
|
||||||
|
|
||||||
|
expect(res[1].to).toBeUndefined()
|
||||||
|
expect(res[1].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[1].vnode.type).toEqual('meta')
|
||||||
|
expect(res[1].vnode.props).toMatchObject({ content: 'my custom description' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('render custom group (namespaced tag)', () => {
|
||||||
|
const context = {}
|
||||||
|
const key = 'og'
|
||||||
|
const data = {
|
||||||
|
title: 'my og title',
|
||||||
|
description: 'my og description',
|
||||||
|
image: [
|
||||||
|
'img1',
|
||||||
|
'img2'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
group: true,
|
||||||
|
keyAttribute: 'property',
|
||||||
|
namespacedAttribute: true,
|
||||||
|
tag: 'meta'
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = render.renderMeta(context, key, data, config)
|
||||||
|
// console.log('RES', res, res[0])
|
||||||
|
|
||||||
|
expect(res).toBeInstanceOf(Array)
|
||||||
|
expect(res.length).toBe(4)
|
||||||
|
|
||||||
|
expect(res[0].to).toBeUndefined()
|
||||||
|
expect(res[0].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[0].vnode.type).toEqual('meta')
|
||||||
|
expect(res[0].vnode.props).toMatchObject({ property: 'og:title', content: 'my og title' })
|
||||||
|
|
||||||
|
expect(res[1].to).toBeUndefined()
|
||||||
|
expect(res[1].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[1].vnode.type).toEqual('meta')
|
||||||
|
expect(res[1].vnode.props).toMatchObject({ property: 'og:description', content: 'my og description' })
|
||||||
|
|
||||||
|
expect(res[2].to).toBeUndefined()
|
||||||
|
expect(res[2].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[2].vnode.type).toEqual('meta')
|
||||||
|
expect(res[2].vnode.props).toMatchObject({ property: 'og:image', content: 'img1' })
|
||||||
|
|
||||||
|
expect(res[3].to).toBeUndefined()
|
||||||
|
expect(res[3].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[3].vnode.type).toEqual('meta')
|
||||||
|
expect(res[3].vnode.props).toMatchObject({ property: 'og:image', content: 'img2' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('render custom group (namespaced attribute and name attribute)', () => {
|
||||||
|
const context = {}
|
||||||
|
const key = 'og'
|
||||||
|
const data = {
|
||||||
|
title: 'my og title',
|
||||||
|
description: 'my og description',
|
||||||
|
image: [
|
||||||
|
'img1',
|
||||||
|
'img2'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
group: true,
|
||||||
|
keyAttribute: 'property',
|
||||||
|
namespacedAttribute: true,
|
||||||
|
tag: 'meta'
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = render.renderMeta(context, key, data, config)
|
||||||
|
// console.log('RES', res, res[0])
|
||||||
|
|
||||||
|
expect(res).toBeInstanceOf(Array)
|
||||||
|
expect(res.length).toBe(4)
|
||||||
|
|
||||||
|
expect(res[0].to).toBeUndefined()
|
||||||
|
expect(res[0].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[0].vnode.type).toEqual('meta')
|
||||||
|
expect(res[0].vnode.props).toMatchObject({ property: 'og:title', content: 'my og title' })
|
||||||
|
|
||||||
|
expect(res[1].to).toBeUndefined()
|
||||||
|
expect(res[1].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[1].vnode.type).toEqual('meta')
|
||||||
|
expect(res[1].vnode.props).toMatchObject({ property: 'og:description', content: 'my og description' })
|
||||||
|
|
||||||
|
expect(res[2].to).toBeUndefined()
|
||||||
|
expect(res[2].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[2].vnode.type).toEqual('meta')
|
||||||
|
expect(res[2].vnode.props).toMatchObject({ property: 'og:image', content: 'img1' })
|
||||||
|
|
||||||
|
expect(res[3].to).toBeUndefined()
|
||||||
|
expect(res[3].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[3].vnode.type).toEqual('meta')
|
||||||
|
expect(res[3].vnode.props).toMatchObject({ property: 'og:image', content: 'img2' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('render custom group (array)', () => {
|
||||||
|
const spy = jest.spyOn(console, 'warn').mockImplementation(_ => _)
|
||||||
|
const context = {}
|
||||||
|
const key = 'og'
|
||||||
|
const data = ['data']
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
group: true,
|
||||||
|
keyAttribute: 'property',
|
||||||
|
namespacedAttribute: true,
|
||||||
|
tag: 'meta'
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = render.renderMeta(context, key, data, config)
|
||||||
|
// console.log('RES', res, res[0])
|
||||||
|
|
||||||
|
expect(res).toBeInstanceOf(Array)
|
||||||
|
expect(res.length).toBe(0)
|
||||||
|
|
||||||
|
expect(spy).toHaveBeenCalledTimes(1)
|
||||||
|
expect(spy).toHaveBeenCalledWith(expect.stringContaining('Specifying an array for group properties isnt supported'))
|
||||||
|
spy.mockRestore()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('render custom group (tag namespaced)', () => {
|
||||||
|
const context = {}
|
||||||
|
const key = 'esi'
|
||||||
|
const data = {
|
||||||
|
children: [{
|
||||||
|
tag: 'choose',
|
||||||
|
children: [{
|
||||||
|
tag: 'when',
|
||||||
|
test: '$(HTTP_COOKIE{group})=="Advanced"',
|
||||||
|
children: [{
|
||||||
|
tag: 'include',
|
||||||
|
src: 'http://www.example.com/advanced.html'
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
group: true,
|
||||||
|
namespaced: true,
|
||||||
|
attributes: ['src', 'test', 'text']
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = render.renderMeta(context, key, data, config)
|
||||||
|
// console.log('RES', res)
|
||||||
|
|
||||||
|
expect(res).toBeInstanceOf(Array)
|
||||||
|
expect(res.length).toBe(1)
|
||||||
|
|
||||||
|
expect(res[0].to).toBeUndefined()
|
||||||
|
expect(res[0].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[0].vnode.type).toEqual('esi:choose')
|
||||||
|
expect(res[0].vnode.props).toEqual({})
|
||||||
|
|
||||||
|
expect(res[0].vnode.children).toBeInstanceOf(Array)
|
||||||
|
expect(res[0].vnode.children.length).toBe(1)
|
||||||
|
|
||||||
|
expect(res[0].vnode.children[0]).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[0].vnode.children[0].type).toEqual('esi:when')
|
||||||
|
expect(res[0].vnode.children[0].props).toEqual({ test: '$(HTTP_COOKIE{group})=="Advanced"' })
|
||||||
|
|
||||||
|
expect(res[0].vnode.children[0].children).toBeInstanceOf(Array)
|
||||||
|
expect(res[0].vnode.children[0].children.length).toBe(1)
|
||||||
|
|
||||||
|
expect(res[0].vnode.children[0].children[0]).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[0].vnode.children[0].children[0].type).toEqual('esi:include')
|
||||||
|
expect(res[0].vnode.children[0].children[0].props).toEqual({ src: 'http://www.example.com/advanced.html' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('customized render with slot', () => {
|
||||||
|
const key = 'title'
|
||||||
|
const data = 'my title'
|
||||||
|
const config = {
|
||||||
|
tag: 'title'
|
||||||
|
}
|
||||||
|
|
||||||
|
const slot = jest.fn().mockReturnValue([{ children: 'slot title' }])
|
||||||
|
const context = {
|
||||||
|
metainfo: { [key]: data },
|
||||||
|
slots: { title: slot }
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = render.renderMeta(context, key, data, config)
|
||||||
|
// console.log('RES', res)
|
||||||
|
|
||||||
|
expect(res.to).toBeUndefined()
|
||||||
|
expect(res.vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
|
||||||
|
expect(res.vnode.type).toEqual('title')
|
||||||
|
expect(res.vnode.props).toEqual({})
|
||||||
|
|
||||||
|
expect(res.vnode.children).toEqual('slot title')
|
||||||
|
|
||||||
|
expect(slot).toHaveBeenCalledTimes(1)
|
||||||
|
expect(slot).toHaveBeenCalledWith({
|
||||||
|
content: data,
|
||||||
|
metainfo: context.metainfo
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('customized render with slot (group)', () => {
|
||||||
|
const key = 'og'
|
||||||
|
const data = {
|
||||||
|
title: 'my og title'
|
||||||
|
}
|
||||||
|
|
||||||
|
const slot = jest.fn().mockReturnValue([{ children: 'og slot title' }])
|
||||||
|
const context = {
|
||||||
|
metainfo: { [key]: data },
|
||||||
|
slots: { 'og(title)': slot }
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
group: true,
|
||||||
|
keyAttribute: 'property',
|
||||||
|
namespacedAttribute: true,
|
||||||
|
tag: 'meta'
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = render.renderMeta(context, key, data, config)
|
||||||
|
// console.log('RES', res, res[0])
|
||||||
|
|
||||||
|
expect(res).toBeInstanceOf(Array)
|
||||||
|
expect(res.length).toBe(1)
|
||||||
|
|
||||||
|
expect(res[0].to).toBeUndefined()
|
||||||
|
expect(res[0].vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
expect(res[0].vnode.type).toEqual('meta')
|
||||||
|
expect(res[0].vnode.props).toMatchObject({ property: 'og:title', content: 'og slot title' })
|
||||||
|
|
||||||
|
expect(slot).toHaveBeenCalledTimes(1)
|
||||||
|
expect(slot).toHaveBeenCalledWith({
|
||||||
|
content: data.title,
|
||||||
|
[key]: data,
|
||||||
|
metainfo: context.metainfo
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('customized render with slot (fallsback to original content)', () => {
|
||||||
|
const key = 'title'
|
||||||
|
const data = 'my title'
|
||||||
|
const config = {
|
||||||
|
tag: 'title'
|
||||||
|
}
|
||||||
|
|
||||||
|
const slot = jest.fn().mockReturnValue(undefined) // slot returns nothing
|
||||||
|
const context = {
|
||||||
|
metainfo: { [key]: data },
|
||||||
|
slots: { title: slot }
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = render.renderMeta(context, key, data, config)
|
||||||
|
// console.log('RES', res)
|
||||||
|
|
||||||
|
expect(res.to).toBeUndefined()
|
||||||
|
expect(res.vnode).toMatchObject({ __v_isVNode: true })
|
||||||
|
|
||||||
|
expect(res.vnode.type).toEqual('title')
|
||||||
|
expect(res.vnode.props).toEqual({})
|
||||||
|
|
||||||
|
expect(res.vnode.children).toEqual('my title')
|
||||||
|
|
||||||
|
expect(slot).toHaveBeenCalledTimes(1)
|
||||||
|
expect(slot).toHaveBeenCalledWith({
|
||||||
|
content: data,
|
||||||
|
metainfo: context.metainfo
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
process.server = true
|
|
||||||
|
|
||||||
jest.useFakeTimers()
|
|
||||||
jest.setTimeout(30000)
|
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
const fs = require('fs')
|
|
||||||
const path = require('path')
|
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
|
||||||
// https://github.com/jantimon/html-webpack-plugin/issues/1372
|
|
||||||
const HtmlIncludeChunksWebpackPlugin = require('@wishy-gift/html-include-chunks-webpack-plugin')
|
|
||||||
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
|
|
||||||
const { VueLoaderPlugin } = require('vue-loader')
|
|
||||||
const webpack = require('webpack')
|
|
||||||
|
|
||||||
const r = (...paths) => path.resolve(__dirname, 'examples', ...paths)
|
|
||||||
|
|
||||||
/** @type {import('webpack').ConfigurationFactory} */
|
|
||||||
const config = (env = {}) => {
|
|
||||||
const extraPlugins = env.prod ? [new BundleAnalyzerPlugin()] : []
|
|
||||||
|
|
||||||
return {
|
|
||||||
mode: env.prod ? 'production' : 'development',
|
|
||||||
devtool: env.prod ? 'source-map' : 'inline-source-map',
|
|
||||||
|
|
||||||
devServer: {
|
|
||||||
contentBase: r(),
|
|
||||||
historyApiFallback: true,
|
|
||||||
hot: true,
|
|
||||||
stats: 'minimal',
|
|
||||||
},
|
|
||||||
|
|
||||||
output: {
|
|
||||||
path: r('/__build__/'),
|
|
||||||
publicPath: '/__build__/',
|
|
||||||
filename: '[name].js',
|
|
||||||
},
|
|
||||||
|
|
||||||
entry: fs.readdirSync(r())
|
|
||||||
.reduce((entries, entryPath) => {
|
|
||||||
if (entryPath !== 'vue-router') {
|
|
||||||
return entries
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entryPath === 'ssr') {
|
|
||||||
entries[entryPath] = r(entryPath, 'browser.js')
|
|
||||||
} else {
|
|
||||||
const entry = r(entryPath, 'app.js')
|
|
||||||
if (fs.existsSync(entry)) {
|
|
||||||
entries[entryPath] = entry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extraPlugins.push(
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
entryKey: entryPath,
|
|
||||||
filename: r(entryPath, 'index.html')
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
return entries
|
|
||||||
}, {}),
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.ts$/,
|
|
||||||
use: 'ts-loader',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.vue$/,
|
|
||||||
use: 'vue-loader',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
// this isn't technically needed, since the default `vue` entry for bundlers
|
|
||||||
// is a simple `export * from '@vue/runtime-dom`. However having this
|
|
||||||
// extra re-export somehow causes webpack to always invalidate the module
|
|
||||||
// on the first HMR update and causes the page to reload.
|
|
||||||
vue: '@vue/runtime-dom',
|
|
||||||
vue: 'vue/dist/vue.esm-bundler.js',
|
|
||||||
},
|
|
||||||
// Add `.ts` and `.tsx` as a resolvable extension.
|
|
||||||
extensions: ['.ts', 'd.ts', '.tsx', '.js', '.vue'],
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new VueLoaderPlugin(),
|
|
||||||
/*new HtmlWebpackPlugin({
|
|
||||||
template: r(__dirname, 'examples/index.html'),
|
|
||||||
}),*/
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
__DEV__: JSON.stringify(!env.prod),
|
|
||||||
__BROWSER__: 'true',
|
|
||||||
'process.env': {
|
|
||||||
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
...extraPlugins,
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = config
|
|
||||||
Reference in New Issue
Block a user