refactor(ssr): adjust helper structure + renderList
This commit is contained in:
parent
889a0276eb
commit
2ad0eed5cd
@ -5,7 +5,8 @@ export const SSR_RENDER_COMPONENT = Symbol(`renderComponent`)
|
||||
export const SSR_RENDER_SLOT = Symbol(`renderSlot`)
|
||||
export const SSR_RENDER_CLASS = Symbol(`renderClass`)
|
||||
export const SSR_RENDER_STYLE = Symbol(`renderStyle`)
|
||||
export const SSR_RENDER_PROPS = Symbol(`renderProps`)
|
||||
export const SSR_RENDER_ATTRS = Symbol(`renderAttrs`)
|
||||
export const SSR_RENDER_ATTR = Symbol(`renderAttr`)
|
||||
export const SSR_RENDER_LIST = Symbol(`renderList`)
|
||||
|
||||
// Note: these are helpers imported from @vue/server-renderer
|
||||
@ -16,6 +17,7 @@ registerRuntimeHelpers({
|
||||
[SSR_RENDER_SLOT]: `_renderSlot`,
|
||||
[SSR_RENDER_CLASS]: `_renderClass`,
|
||||
[SSR_RENDER_STYLE]: `_renderStyle`,
|
||||
[SSR_RENDER_PROPS]: `_renderProps`,
|
||||
[SSR_RENDER_ATTRS]: `renderAttrs`,
|
||||
[SSR_RENDER_ATTR]: `renderAttr`,
|
||||
[SSR_RENDER_LIST]: `_renderList`
|
||||
})
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { _interpolate } from '../src'
|
||||
import { interpolate } from '../src/helpers/interpolate'
|
||||
import { escapeHtml } from '@vue/shared'
|
||||
|
||||
test('ssr: interpolate', () => {
|
||||
expect(_interpolate(0)).toBe(`0`)
|
||||
expect(_interpolate(`foo`)).toBe(`foo`)
|
||||
expect(_interpolate(`<div>`)).toBe(`<div>`)
|
||||
expect(interpolate(0)).toBe(`0`)
|
||||
expect(interpolate(`foo`)).toBe(`foo`)
|
||||
expect(interpolate(`<div>`)).toBe(`<div>`)
|
||||
// should escape interpolated values
|
||||
expect(_interpolate([1, 2, 3])).toBe(
|
||||
expect(interpolate([1, 2, 3])).toBe(
|
||||
escapeHtml(JSON.stringify([1, 2, 3], null, 2))
|
||||
)
|
||||
expect(
|
||||
_interpolate({
|
||||
interpolate({
|
||||
foo: 1,
|
||||
bar: `<div>`
|
||||
})
|
||||
|
3
packages/server-renderer/__tests__/renderList.spec.ts
Normal file
3
packages/server-renderer/__tests__/renderList.spec.ts
Normal file
@ -0,0 +1,3 @@
|
||||
test('ssr: renderList', () => {
|
||||
// TODO
|
||||
})
|
@ -1,9 +1,13 @@
|
||||
import { renderProps, renderClass, renderStyle } from '../src/renderProps'
|
||||
import {
|
||||
renderAttrs,
|
||||
renderClass,
|
||||
renderStyle
|
||||
} from '../src/helpers/renderAttrs'
|
||||
|
||||
describe('ssr: renderProps', () => {
|
||||
test('ignore reserved props', () => {
|
||||
expect(
|
||||
renderProps({
|
||||
renderAttrs({
|
||||
key: 1,
|
||||
ref: () => {},
|
||||
onClick: () => {}
|
||||
@ -13,7 +17,7 @@ describe('ssr: renderProps', () => {
|
||||
|
||||
test('normal attrs', () => {
|
||||
expect(
|
||||
renderProps({
|
||||
renderAttrs({
|
||||
id: 'foo',
|
||||
title: 'bar'
|
||||
})
|
||||
@ -22,7 +26,7 @@ describe('ssr: renderProps', () => {
|
||||
|
||||
test('escape attrs', () => {
|
||||
expect(
|
||||
renderProps({
|
||||
renderAttrs({
|
||||
id: '"><script'
|
||||
})
|
||||
).toBe(` id=""><script"`)
|
||||
@ -30,7 +34,7 @@ describe('ssr: renderProps', () => {
|
||||
|
||||
test('boolean attrs', () => {
|
||||
expect(
|
||||
renderProps({
|
||||
renderAttrs({
|
||||
checked: true,
|
||||
multiple: false
|
||||
})
|
||||
@ -39,7 +43,7 @@ describe('ssr: renderProps', () => {
|
||||
|
||||
test('ignore falsy values', () => {
|
||||
expect(
|
||||
renderProps({
|
||||
renderAttrs({
|
||||
foo: false,
|
||||
title: null,
|
||||
baz: undefined
|
||||
@ -49,7 +53,7 @@ describe('ssr: renderProps', () => {
|
||||
|
||||
test('props to attrs', () => {
|
||||
expect(
|
||||
renderProps({
|
||||
renderAttrs({
|
||||
readOnly: true, // simple lower case conversion
|
||||
htmlFor: 'foobar' // special cases
|
||||
})
|
||||
@ -58,7 +62,7 @@ describe('ssr: renderProps', () => {
|
||||
|
||||
test('preserve name on custom element', () => {
|
||||
expect(
|
||||
renderProps(
|
||||
renderAttrs(
|
||||
{
|
||||
fooBar: 'ok'
|
||||
},
|
||||
@ -71,7 +75,7 @@ describe('ssr: renderProps', () => {
|
||||
describe('ssr: renderClass', () => {
|
||||
test('via renderProps', () => {
|
||||
expect(
|
||||
renderProps({
|
||||
renderAttrs({
|
||||
class: ['foo', 'bar']
|
||||
})
|
||||
).toBe(` class="foo bar"`)
|
||||
@ -92,7 +96,7 @@ describe('ssr: renderClass', () => {
|
||||
describe('ssr: renderStyle', () => {
|
||||
test('via renderProps', () => {
|
||||
expect(
|
||||
renderProps({
|
||||
renderAttrs({
|
||||
style: {
|
||||
color: 'red'
|
||||
}
|
||||
|
5
packages/server-renderer/src/helpers/interpolate.ts
Normal file
5
packages/server-renderer/src/helpers/interpolate.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { escapeHtml, toDisplayString } from '@vue/shared'
|
||||
|
||||
export function interpolate(value: unknown): string {
|
||||
return escapeHtml(toDisplayString(value))
|
||||
}
|
@ -14,7 +14,7 @@ import {
|
||||
|
||||
const shouldIgnoreProp = makeMap(`key,ref,innerHTML,textContent`)
|
||||
|
||||
export function renderProps(
|
||||
export function renderAttrs(
|
||||
props: Record<string, unknown>,
|
||||
tag?: string
|
||||
): string {
|
||||
@ -32,23 +32,30 @@ export function renderProps(
|
||||
ret += ` class="${renderClass(value)}"`
|
||||
} else if (key === 'style') {
|
||||
ret += ` style="${renderStyle(value)}"`
|
||||
} else if (value != null) {
|
||||
const attrKey =
|
||||
tag && tag.indexOf('-') > 0
|
||||
? key // preserve raw name on custom elements
|
||||
: propsToAttrMap[key] || key.toLowerCase()
|
||||
if (isBooleanAttr(attrKey)) {
|
||||
if (value !== false) {
|
||||
ret += ` ${attrKey}`
|
||||
}
|
||||
} else if (isSSRSafeAttrName(attrKey)) {
|
||||
ret += ` ${attrKey}="${escapeHtml(value)}"`
|
||||
}
|
||||
} else {
|
||||
ret += renderAttr(key, value, tag)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
export function renderAttr(key: string, value: unknown, tag?: string): string {
|
||||
if (value == null) {
|
||||
return ``
|
||||
}
|
||||
const attrKey =
|
||||
tag && tag.indexOf('-') > 0
|
||||
? key // preserve raw name on custom elements
|
||||
: propsToAttrMap[key] || key.toLowerCase()
|
||||
if (isBooleanAttr(attrKey)) {
|
||||
return value === false ? `` : ` ${attrKey}`
|
||||
} else if (isSSRSafeAttrName(attrKey)) {
|
||||
return ` ${attrKey}="${escapeHtml(value)}"`
|
||||
} else {
|
||||
return ``
|
||||
}
|
||||
}
|
||||
|
||||
export function renderClass(raw: unknown): string {
|
||||
return escapeHtml(normalizeClass(raw))
|
||||
}
|
29
packages/server-renderer/src/helpers/renderList.ts
Normal file
29
packages/server-renderer/src/helpers/renderList.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { isArray, isString, isObject } from '@vue/shared'
|
||||
|
||||
export function renderList(
|
||||
source: unknown,
|
||||
renderItem: (value: unknown, key: string | number, index?: number) => void
|
||||
) {
|
||||
if (isArray(source) || isString(source)) {
|
||||
for (let i = 0, l = source.length; i < l; i++) {
|
||||
renderItem(source[i], i)
|
||||
}
|
||||
} else if (typeof source === 'number') {
|
||||
for (let i = 0; i < source; i++) {
|
||||
renderItem(i + 1, i)
|
||||
}
|
||||
} else if (isObject(source)) {
|
||||
if (source[Symbol.iterator as any]) {
|
||||
const arr = Array.from(source as Iterable<any>)
|
||||
for (let i = 0, l = arr.length; i < l; i++) {
|
||||
renderItem(arr[i], i)
|
||||
}
|
||||
} else {
|
||||
const keys = Object.keys(source)
|
||||
for (let i = 0, l = keys.length; i < l; i++) {
|
||||
const key = keys[i]
|
||||
renderItem(source[key], key, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
// public
|
||||
export { renderToString } from './renderToString'
|
||||
|
||||
// internal
|
||||
// internal runtime helpers
|
||||
export {
|
||||
renderComponent as _renderComponent,
|
||||
renderSlot as _renderSlot
|
||||
@ -9,12 +9,7 @@ export {
|
||||
export {
|
||||
renderClass as _renderClass,
|
||||
renderStyle as _renderStyle,
|
||||
renderProps as _renderProps
|
||||
} from './renderProps'
|
||||
|
||||
// utils
|
||||
import { escapeHtml, toDisplayString } from '@vue/shared'
|
||||
|
||||
export function _interpolate(value: unknown): string {
|
||||
return escapeHtml(toDisplayString(value))
|
||||
}
|
||||
renderAttrs as _renderAttrs
|
||||
} from './helpers/renderAttrs'
|
||||
export { interpolate as _interpolate } from './helpers/interpolate'
|
||||
export { renderList as _renderList } from './helpers/renderList'
|
||||
|
@ -19,10 +19,10 @@ import {
|
||||
isPromise,
|
||||
isArray,
|
||||
isFunction,
|
||||
isVoidTag
|
||||
isVoidTag,
|
||||
escapeHtml
|
||||
} from '@vue/shared'
|
||||
import { renderProps } from './renderProps'
|
||||
import { escapeHtml } from '@vue/shared'
|
||||
import { renderAttrs } from './helpers/renderAttrs'
|
||||
|
||||
const {
|
||||
isVNode,
|
||||
@ -213,7 +213,7 @@ function renderElement(
|
||||
// TODO directives
|
||||
|
||||
if (props !== null) {
|
||||
openTag += renderProps(props, tag)
|
||||
openTag += renderAttrs(props, tag)
|
||||
}
|
||||
|
||||
if (scopeId !== null) {
|
||||
|
Loading…
Reference in New Issue
Block a user