Skip to content

Commit

Permalink
refactor: rename <portal> to <teleport>
Browse files Browse the repository at this point in the history
BREAKING CHANGE: `<portal>` has been renamed to `<teleport>`.

    `target` prop is also renmaed to `to`, so the new usage will be:

    ```html
    <Teleport to="#modal-layer" :disabled="isMobile">
      <div class="modal">
        hello
      </div>
    </Teleport>
    ```

    The primary reason for the renaming is to avoid potential naming
    conflict with [native portals](https://wicg.github.io/portals/).
  • Loading branch information
yyx990803 committed Apr 2, 2020
1 parent 8080c38 commit eee5095
Show file tree
Hide file tree
Showing 26 changed files with 291 additions and 284 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
RESOLVE_DIRECTIVE,
TO_HANDLERS,
helperNameMap,
PORTAL,
TELEPORT,
RESOLVE_DYNAMIC_COMPONENT,
SUSPENSE,
KEEP_ALIVE,
Expand Down Expand Up @@ -272,16 +272,16 @@ describe('compiler: element transform', () => {
})
})

test('should handle <Portal> with normal children', () => {
test('should handle <Teleport> with normal children', () => {
function assert(tag: string) {
const { root, node } = parseWithElementTransform(
`<${tag} target="#foo"><span /></${tag}>`
)
expect(root.components.length).toBe(0)
expect(root.helpers).toContain(PORTAL)
expect(root.helpers).toContain(TELEPORT)

expect(node).toMatchObject({
tag: PORTAL,
tag: TELEPORT,
props: createObjectMatcher({
target: '#foo'
}),
Expand All @@ -298,8 +298,8 @@ describe('compiler: element transform', () => {
})
}

assert(`portal`)
assert(`Portal`)
assert(`teleport`)
assert(`Teleport`)
})

test('should handle <Suspense>', () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/compiler-core/src/runtimeHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const FRAGMENT = Symbol(__DEV__ ? `Fragment` : ``)
export const PORTAL = Symbol(__DEV__ ? `Portal` : ``)
export const TELEPORT = Symbol(__DEV__ ? `Teleport` : ``)
export const SUSPENSE = Symbol(__DEV__ ? `Suspense` : ``)
export const KEEP_ALIVE = Symbol(__DEV__ ? `KeepAlive` : ``)
export const BASE_TRANSITION = Symbol(__DEV__ ? `BaseTransition` : ``)
Expand Down Expand Up @@ -33,7 +33,7 @@ export const WITH_CTX = Symbol(__DEV__ ? `withCtx` : ``)
// Using `any` here because TS doesn't allow symbols as index type.
export const helperNameMap: any = {
[FRAGMENT]: `Fragment`,
[PORTAL]: `Portal`,
[TELEPORT]: `Teleport`,
[SUSPENSE]: `Suspense`,
[KEEP_ALIVE]: `KeepAlive`,
[BASE_TRANSITION]: `BaseTransition`,
Expand Down
10 changes: 5 additions & 5 deletions packages/compiler-core/src/transforms/transformElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
RESOLVE_DYNAMIC_COMPONENT,
MERGE_PROPS,
TO_HANDLERS,
PORTAL,
TELEPORT,
KEEP_ALIVE
} from '../runtimeHelpers'
import {
Expand Down Expand Up @@ -124,8 +124,8 @@ export const transformElement: NodeTransform = (node, context) => {

const shouldBuildAsSlots =
isComponent &&
// Portal is not a real component and has dedicated runtime handling
vnodeTag !== PORTAL &&
// Teleport is not a real component and has dedicated runtime handling
vnodeTag !== TELEPORT &&
// explained above.
vnodeTag !== KEEP_ALIVE

Expand All @@ -135,7 +135,7 @@ export const transformElement: NodeTransform = (node, context) => {
if (hasDynamicSlots) {
patchFlag |= PatchFlags.DYNAMIC_SLOTS
}
} else if (node.children.length === 1 && vnodeTag !== PORTAL) {
} else if (node.children.length === 1 && vnodeTag !== TELEPORT) {
const child = node.children[0]
const type = child.type
// check for dynamic text children
Expand Down Expand Up @@ -217,7 +217,7 @@ export function resolveComponentType(
}
}

// 2. built-in components (Portal, Transition, KeepAlive, Suspense...)
// 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)
const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag)
if (builtIn) {
// built-ins are simply fallthroughs / have special handling during ssr
Expand Down
6 changes: 3 additions & 3 deletions packages/compiler-core/src/transforms/vIf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
FRAGMENT,
CREATE_COMMENT,
OPEN_BLOCK,
PORTAL
TELEPORT
} from '../runtimeHelpers'
import { injectProp } from '../utils'
import { PatchFlags, PatchFlagNames } from '@vue/shared'
Expand Down Expand Up @@ -218,8 +218,8 @@ function createChildrenCodegenNode(
// component vnodes are always tracked and its children are
// compiled into slots so no need to make it a block
((firstChild as ElementNode).tagType !== ElementTypes.COMPONENT ||
// portal has component type but isn't always tracked
vnodeCall.tag === PORTAL)
// teleport has component type but isn't always tracked
vnodeCall.tag === TELEPORT)
) {
vnodeCall.isBlock = true
helper(OPEN_BLOCK)
Expand Down
6 changes: 3 additions & 3 deletions packages/compiler-core/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
import { TransformContext } from './transform'
import {
MERGE_PROPS,
PORTAL,
TELEPORT,
SUSPENSE,
KEEP_ALIVE,
BASE_TRANSITION
Expand All @@ -38,8 +38,8 @@ export const isBuiltInType = (tag: string, expected: string): boolean =>
tag === expected || tag === hyphenate(expected)

export function isCoreComponent(tag: string): symbol | void {
if (isBuiltInType(tag, 'Portal')) {
return PORTAL
if (isBuiltInType(tag, 'Teleport')) {
return TELEPORT
} else if (isBuiltInType(tag, 'Suspense')) {
return SUSPENSE
} else if (isBuiltInType(tag, 'KeepAlive')) {
Expand Down
24 changes: 13 additions & 11 deletions packages/compiler-ssr/__tests__/ssrPortal.spec.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
import { compile } from '../src'

describe('ssr compile: portal', () => {
describe('ssr compile: teleport', () => {
test('should work', () => {
expect(compile(`<portal :target="target"><div/></portal>`).code)
expect(compile(`<teleport :target="target"><div/></teleport>`).code)
.toMatchInlineSnapshot(`
"const { ssrRenderPortal: _ssrRenderPortal } = require(\\"@vue/server-renderer\\")
"const { ssrRenderTeleport: _ssrRenderTeleport } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent) {
_ssrRenderPortal(_push, (_push) => {
_ssrRenderTeleport(_push, (_push) => {
_push(\`<div></div>\`)
}, _ctx.target, false, _parent)
}"
`)
})

test('disabled prop handling', () => {
expect(compile(`<portal :target="target" disabled><div/></portal>`).code)
.toMatchInlineSnapshot(`
"const { ssrRenderPortal: _ssrRenderPortal } = require(\\"@vue/server-renderer\\")
expect(
compile(`<teleport :target="target" disabled><div/></teleport>`).code
).toMatchInlineSnapshot(`
"const { ssrRenderTeleport: _ssrRenderTeleport } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent) {
_ssrRenderPortal(_push, (_push) => {
_ssrRenderTeleport(_push, (_push) => {
_push(\`<div></div>\`)
}, _ctx.target, true, _parent)
}"
`)

expect(
compile(`<portal :target="target" :disabled="foo"><div/></portal>`).code
compile(`<teleport :target="target" :disabled="foo"><div/></teleport>`)
.code
).toMatchInlineSnapshot(`
"const { ssrRenderPortal: _ssrRenderPortal } = require(\\"@vue/server-renderer\\")
"const { ssrRenderTeleport: _ssrRenderTeleport } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent) {
_ssrRenderPortal(_push, (_push) => {
_ssrRenderTeleport(_push, (_push) => {
_push(\`<div></div>\`)
}, _ctx.target, _ctx.foo, _parent)
}"
Expand Down
4 changes: 2 additions & 2 deletions packages/compiler-ssr/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ export function createSSRCompilerError(
export const enum SSRErrorCodes {
X_SSR_CUSTOM_DIRECTIVE_NO_TRANSFORM = DOMErrorCodes.__EXTEND_POINT__,
X_SSR_UNSAFE_ATTR_NAME,
X_SSR_NO_PORTAL_TARGET
X_SSR_NO_TELEPORT_TARGET
}

export const SSRErrorMessages: { [code: number]: string } = {
[SSRErrorCodes.X_SSR_CUSTOM_DIRECTIVE_NO_TRANSFORM]: `Custom directive is missing corresponding SSR transform and will be ignored.`,
[SSRErrorCodes.X_SSR_UNSAFE_ATTR_NAME]: `Unsafe attribute name for SSR.`,
[SSRErrorCodes.X_SSR_NO_PORTAL_TARGET]: `No target prop on portal element.`
[SSRErrorCodes.X_SSR_NO_TELEPORT_TARGET]: `No target prop on teleport element.`
}
4 changes: 2 additions & 2 deletions packages/compiler-ssr/src/runtimeHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const SSR_LOOSE_EQUAL = Symbol(`ssrLooseEqual`)
export const SSR_LOOSE_CONTAIN = Symbol(`ssrLooseContain`)
export const SSR_RENDER_DYNAMIC_MODEL = Symbol(`ssrRenderDynamicModel`)
export const SSR_GET_DYNAMIC_MODEL_PROPS = Symbol(`ssrGetDynamicModelProps`)
export const SSR_RENDER_PORTAL = Symbol(`ssrRenderPortal`)
export const SSR_RENDER_TELEPORT = Symbol(`ssrRenderTeleport`)
export const SSR_RENDER_SUSPENSE = Symbol(`ssrRenderSuspense`)

export const ssrHelpers = {
Expand All @@ -30,7 +30,7 @@ export const ssrHelpers = {
[SSR_LOOSE_CONTAIN]: `ssrLooseContain`,
[SSR_RENDER_DYNAMIC_MODEL]: `ssrRenderDynamicModel`,
[SSR_GET_DYNAMIC_MODEL_PROPS]: `ssrGetDynamicModelProps`,
[SSR_RENDER_PORTAL]: `ssrRenderPortal`,
[SSR_RENDER_TELEPORT]: `ssrRenderTeleport`,
[SSR_RENDER_SUSPENSE]: `ssrRenderSuspense`
}

Expand Down
8 changes: 4 additions & 4 deletions packages/compiler-ssr/src/transforms/ssrTransformComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
buildSlots,
FunctionExpression,
TemplateChildNode,
PORTAL,
TELEPORT,
createIfStatement,
createSimpleExpression,
getBaseTransformPreset,
Expand Down Expand Up @@ -39,7 +39,7 @@ import {
processChildren,
processChildrenAsStatement
} from '../ssrCodegenTransform'
import { ssrProcessPortal } from './ssrTransformPortal'
import { ssrProcessTeleport } from './ssrTransformTeleport'
import {
ssrProcessSuspense,
ssrTransformSuspense
Expand Down Expand Up @@ -146,8 +146,8 @@ export function ssrProcessComponent(
if (!node.ssrCodegenNode) {
// this is a built-in component that fell-through.
const component = componentTypeMap.get(node)!
if (component === PORTAL) {
return ssrProcessPortal(node, context)
if (component === TELEPORT) {
return ssrProcessTeleport(node, context)
} else if (component === SUSPENSE) {
return ssrProcessSuspense(node, context)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ import {
processChildrenAsStatement
} from '../ssrCodegenTransform'
import { createSSRCompilerError, SSRErrorCodes } from '../errors'
import { SSR_RENDER_PORTAL } from '../runtimeHelpers'
import { SSR_RENDER_TELEPORT } from '../runtimeHelpers'

// Note: this is a 2nd-pass codegen transform.
export function ssrProcessPortal(
export function ssrProcessTeleport(
node: ComponentNode,
context: SSRTransformContext
) {
const targetProp = findProp(node, 'target')
if (!targetProp) {
context.onError(
createSSRCompilerError(SSRErrorCodes.X_SSR_NO_PORTAL_TARGET, node.loc)
createSSRCompilerError(SSRErrorCodes.X_SSR_NO_TELEPORT_TARGET, node.loc)
)
return
}
Expand All @@ -37,7 +37,7 @@ export function ssrProcessPortal(
if (!target) {
context.onError(
createSSRCompilerError(
SSRErrorCodes.X_SSR_NO_PORTAL_TARGET,
SSRErrorCodes.X_SSR_NO_TELEPORT_TARGET,
targetProp.loc
)
)
Expand All @@ -60,7 +60,7 @@ export function ssrProcessPortal(
)
contentRenderFn.body = processChildrenAsStatement(node.children, context)
context.pushStatement(
createCallExpression(context.helper(SSR_RENDER_PORTAL), [
createCallExpression(context.helper(SSR_RENDER_TELEPORT), [
`_push`,
contentRenderFn,
target,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -731,5 +731,5 @@ describe('Suspense', () => {
expect(serializeInner(root)).toBe(`<div>Child A</div><div>Child B</div>`)
})

test.todo('portal inside suspense')
test.todo('teleport inside suspense')
})
Loading

0 comments on commit eee5095

Please sign in to comment.