Skip to content

Commit b702b09

Browse files
committed
improvements for handling functional components with styles
1 parent 354f063 commit b702b09

File tree

7 files changed

+113
-52
lines changed

7 files changed

+113
-52
lines changed

lib/component-normalizer.js

+20-15
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ module.exports = function normalizeComponent (
4040
if (moduleIdentifier) { // server build
4141
hook = function (context) {
4242
// 2.3 injection
43-
context = context || (this.$vnode && this.$vnode.ssrContext)
43+
context =
44+
context || // cached call
45+
(this.$vnode && this.$vnode.ssrContext) || // stateful
46+
(this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional
4447
// 2.2 with runInNewContext: true
4548
if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
4649
context = __VUE_SSR_CONTEXT__
@@ -61,23 +64,25 @@ module.exports = function normalizeComponent (
6164
hook = injectStyles
6265
}
6366

64-
var existing = options.functional ? options.render : options.beforeCreate
65-
66-
if (hook && options.functional && injectStyles) {
67-
// inject styles for functioal component in vue file
68-
options.render = function renderWithStyleInjection (h, context) {
69-
hook(context)
70-
return existing(h, context)
67+
if (hook) {
68+
var functional = options.functional
69+
var existing = functional
70+
? options.render
71+
: options.beforeCreate
72+
if (!functional) {
73+
// inject component registration as beforeCreate hook
74+
options.beforeCreate = existing
75+
? [].concat(existing, hook)
76+
: [hook]
77+
} else {
78+
// register for functioal component in vue file
79+
options.render = function renderWithStyleInjection (h, context) {
80+
hook.call(context)
81+
return existing(h, context)
82+
}
7183
}
7284
}
7385

74-
if (hook && !options.functional) {
75-
// inject component registration as beforeCreate hook
76-
options.beforeCreate = existing
77-
? [].concat(existing, hook)
78-
: [hook]
79-
}
80-
8186
return {
8287
esModule: esModule,
8388
exports: scriptExports,

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@
7878
"stylus-loader": "^2.0.0",
7979
"sugarss": "^0.2.0",
8080
"url-loader": "^0.5.7",
81-
"vue": "^2.3.0-beta.1",
82-
"vue-server-renderer": "^2.3.0-beta.1",
83-
"vue-template-compiler": "^2.3.0-beta.1",
81+
"vue": "^2.3.2",
82+
"vue-server-renderer": "^2.3.2",
83+
"vue-template-compiler": "^2.3.2",
8484
"webpack": "^2.2.0"
8585
}
8686
}

test/fixtures/functional-style.vue

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script>
2+
export default {
3+
functional: true,
4+
render (h) {
5+
return h('div', { class: 'foo' }, ['functional'])
6+
}
7+
}
8+
</script>
9+
10+
<style>
11+
.foo { color: red; }
12+
</style>

test/fixtures/ssr-style.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
var Vue = require('vue')
22
var App = require('./ssr-style.vue')
33

4-
module.exports = new Vue(App)
4+
module.exports = () => new Vue({
5+
render: h => h(App)
6+
})

test/fixtures/ssr-style.vue

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@
22
<div>
33
<h1>Hello</h1>
44
<basic/>
5+
<functional-style/>
56
</div>
67
</template>
78

89
<script>
910
import Basic from './basic.vue'
11+
import FunctionalStyle from './functional-style.vue'
1012
1113
export default {
12-
components: { Basic }
14+
components: {
15+
Basic,
16+
FunctionalStyle
17+
}
1318
}
1419
</script>
1520

test/test.js

+38-15
Original file line numberDiff line numberDiff line change
@@ -84,29 +84,30 @@ function test (options, assert) {
8484
}
8585

8686
function mockRender (options, data) {
87+
function h (tag, data, children) {
88+
if (Array.isArray(data)) {
89+
children = data
90+
data = null
91+
}
92+
return {
93+
tag: tag,
94+
data: data,
95+
children: children
96+
}
97+
}
8798
return options.render.call(Object.assign({
8899
_v (val) {
89100
return val
90101
},
91102
_self: {},
92-
$createElement (tag, data, children) {
93-
if (Array.isArray(data)) {
94-
children = data
95-
data = null
96-
}
97-
return {
98-
tag: tag,
99-
data: data,
100-
children: children
101-
}
102-
},
103+
$createElement: h,
103104
_m (index) {
104105
return options.staticRenderFns[index].call(this)
105106
},
106107
_s (str) {
107108
return String(str)
108109
}
109-
}, data))
110+
}, data), h)
110111
}
111112

112113
function interopDefault (module) {
@@ -611,24 +612,28 @@ describe('vue-loader', function () {
611612
}
612613
}, code => {
613614
const renderer = SSR.createBundleRenderer(code, {
614-
basedir: __dirname
615+
basedir: __dirname,
616+
runInNewContext: 'once'
615617
})
616618
const context = {
617619
_registeredComponents: new Set()
618620
}
619621
renderer.renderToString(context, (err, res) => {
620622
if (err) return done(err)
621-
expect(res).to.contain('server-rendered')
623+
expect(res).to.contain('data-server-rendered')
622624
expect(res).to.contain('<h1>Hello</h1>')
623625
expect(res).to.contain('Hello from Component A!')
626+
expect(res).to.contain('<div class="foo">functional</div>')
624627
// from main component
625628
expect(context.styles).to.contain('h1 { color: green;')
626629
// from imported child component
627630
expect(context.styles).to.contain('comp-a h2 {\n color: #f00;')
628631
// from imported css file
629632
expect(context.styles).to.contain('h1 { color: red;')
633+
// from imported functional component
634+
expect(context.styles).to.contain('.foo { color: red;')
630635
// collect component identifiers during render
631-
expect(Array.from(context._registeredComponents).length).to.equal(2)
636+
expect(Array.from(context._registeredComponents).length).to.equal(3)
632637
done()
633638
})
634639
})
@@ -834,4 +839,22 @@ describe('vue-loader', function () {
834839
done()
835840
})
836841
})
842+
843+
it('functional component with styles', done => {
844+
test({
845+
entry: './test/fixtures/functional-style.vue'
846+
}, (window, module, rawModule) => {
847+
expect(module.functional).to.equal(true)
848+
var vnode = mockRender(module)
849+
// <div class="foo">hi</div>
850+
expect(vnode.tag).to.equal('div')
851+
expect(vnode.data.class).to.equal('foo')
852+
expect(vnode.children[0]).to.equal('functional')
853+
854+
var style = window.document.querySelector('style').textContent
855+
style = normalizeNewline(style)
856+
expect(style).to.contain('.foo { color: red;\n}')
857+
done()
858+
})
859+
})
837860
})

yarn.lock

+31-17
Original file line numberDiff line numberDiff line change
@@ -2497,6 +2497,10 @@ lodash._isiterateecall@^3.0.0:
24972497
version "3.0.9"
24982498
resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c"
24992499

2500+
lodash._reinterpolate@~3.0.0:
2501+
version "3.0.0"
2502+
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
2503+
25002504
lodash.camelcase@^4.3.0:
25012505
version "4.3.0"
25022506
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
@@ -2533,6 +2537,19 @@ lodash.memoize@^4.1.2:
25332537
version "4.1.2"
25342538
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
25352539

2540+
lodash.template@^4.4.0:
2541+
version "4.4.0"
2542+
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0"
2543+
dependencies:
2544+
lodash._reinterpolate "~3.0.0"
2545+
lodash.templatesettings "^4.0.0"
2546+
2547+
lodash.templatesettings@^4.0.0:
2548+
version "4.1.0"
2549+
resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316"
2550+
dependencies:
2551+
lodash._reinterpolate "~3.0.0"
2552+
25362553
lodash.uniq@^4.5.0:
25372554
version "4.5.0"
25382555
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
@@ -4137,21 +4154,18 @@ vue-hot-reload-api@^2.1.0:
41374154
version "2.1.0"
41384155
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.1.0.tgz#9ca58a6e0df9078554ce1708688b6578754d86de"
41394156

4140-
vue-server-renderer@^2.3.0:
4141-
version "2.2.6"
4142-
resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.2.6.tgz#0a20535544b6948bca076380d058e19bb1304eef"
4157+
vue-server-renderer@^2.3.2:
4158+
version "2.3.2"
4159+
resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.3.2.tgz#01bfde9c524ef041873f1e2d18f9356c620b4f8c"
41434160
dependencies:
4144-
de-indent "^1.0.2"
4161+
chalk "^1.1.3"
4162+
hash-sum "^1.0.2"
41454163
he "^1.1.0"
4164+
lodash.template "^4.4.0"
4165+
lodash.uniq "^4.5.0"
41464166
resolve "^1.2.0"
4147-
source-map "0.5.6"
4148-
vue-ssr-html-stream "^2.1.0"
4149-
4150-
vue-ssr-html-stream@^2.1.0:
4151-
version "2.2.0"
4152-
resolved "https://registry.yarnpkg.com/vue-ssr-html-stream/-/vue-ssr-html-stream-2.2.0.tgz#56d78b96c9c172b43749a324c156e888aca96d92"
4153-
dependencies:
41544167
serialize-javascript "^1.3.0"
4168+
source-map "0.5.6"
41554169

41564170
vue-style-loader@^3.0.0:
41574171
version "3.0.1"
@@ -4160,9 +4174,9 @@ vue-style-loader@^3.0.0:
41604174
hash-sum "^1.0.2"
41614175
loader-utils "^1.0.2"
41624176

4163-
vue-template-compiler@^2.3.0:
4164-
version "2.2.6"
4165-
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.2.6.tgz#2e2928daf0cd0feca9dfc35a9729adeae173ec68"
4177+
vue-template-compiler@^2.3.2:
4178+
version "2.3.2"
4179+
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.3.2.tgz#d48a7f53df5f497033827182ceb4f0d340803017"
41664180
dependencies:
41674181
de-indent "^1.0.2"
41684182
he "^1.1.0"
@@ -4171,9 +4185,9 @@ vue-template-es2015-compiler@^1.2.2:
41714185
version "1.5.2"
41724186
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.5.2.tgz#a0a6c50c941d2a4abda963f2f42c337ac450ee95"
41734187

4174-
vue@^2.3.0:
4175-
version "2.2.6"
4176-
resolved "https://registry.yarnpkg.com/vue/-/vue-2.2.6.tgz#451714b394dd6d4eae7b773c40c2034a59621aed"
4188+
vue@^2.3.2:
4189+
version "2.3.2"
4190+
resolved "https://registry.yarnpkg.com/vue/-/vue-2.3.2.tgz#9e52aae3593480be235ff227557837e69f98203a"
41774191

41784192
watchpack@^1.3.1:
41794193
version "1.3.1"

0 commit comments

Comments
 (0)