提交 0216627a 编写于 作者: fxy060608's avatar fxy060608

wip(mp): slot

上级 bd3b4b6a
因为 它太大了无法显示 source diff 。你可以改为 查看blob
import { import { isNativeTag, isCustomElement } from '@dcloudio/uni-shared'
isServiceNativeTag,
isServiceCustomElement,
} from '@dcloudio/uni-shared'
import { compileI18nJsonStr } from '@dcloudio/uni-i18n' import { compileI18nJsonStr } from '@dcloudio/uni-i18n'
import { UniVitePlugin, initI18nOptions } from '@dcloudio/uni-cli-shared' import { UniVitePlugin, initI18nOptions } from '@dcloudio/uni-cli-shared'
...@@ -29,8 +26,8 @@ export function uniOptions(): UniVitePlugin['uni'] { ...@@ -29,8 +26,8 @@ export function uniOptions(): UniVitePlugin['uni'] {
} }
}, },
compilerOptions: { compilerOptions: {
isNativeTag: isServiceNativeTag, isNativeTag,
isCustomElement: isServiceCustomElement, isCustomElement,
}, },
transformEvent: { transformEvent: {
tap: 'click', tap: 'click',
......
...@@ -50,8 +50,10 @@ function parsePagesJson( ...@@ -50,8 +50,10 @@ function parsePagesJson(
} }
function addPageJson(pagePath: string, style: UniApp.PagesJsonPageStyle) { function addPageJson(pagePath: string, style: UniApp.PagesJsonPageStyle) {
const filename = path.join(process.env.UNI_INPUT_DIR, pagePath)
if ( if (
fs.existsSync(path.join(process.env.UNI_INPUT_DIR, pagePath + '.nvue')) fs.existsSync(filename + '.nvue') &&
!fs.existsSync(filename + '.vue')
) { ) {
nvuePages.push(pagePath) nvuePages.push(pagePath)
} }
......
...@@ -2,7 +2,7 @@ import path from 'path' ...@@ -2,7 +2,7 @@ import path from 'path'
import fs from 'fs-extra' import fs from 'fs-extra'
import { extend, isArray, isString, NormalizedStyle } from '@vue/shared' import { extend, isArray, isString, NormalizedStyle } from '@vue/shared'
import { import {
isNativeTag, isH5NativeTag,
createRpx2Unit, createRpx2Unit,
Rpx2UnitOptions, Rpx2UnitOptions,
} from '@dcloudio/uni-shared' } from '@dcloudio/uni-shared'
...@@ -128,7 +128,7 @@ export function rewriteSsrNativeTag() { ...@@ -128,7 +128,7 @@ export function rewriteSsrNativeTag() {
const { parserOptions } = require('@vue/compiler-dom') const { parserOptions } = require('@vue/compiler-dom')
// TODO compiler-ssr时,传入的 isNativeTag 会被 @vue/compiler-dom 的 isNativeTag 覆盖 // TODO compiler-ssr时,传入的 isNativeTag 会被 @vue/compiler-dom 的 isNativeTag 覆盖
// https://github.com/vuejs/vue-next/blob/master/packages/compiler-ssr/src/index.ts#L36 // https://github.com/vuejs/vue-next/blob/master/packages/compiler-ssr/src/index.ts#L36
parserOptions.isNativeTag = isNativeTag parserOptions.isNativeTag = isH5NativeTag
} }
export function rewriteSsrRenderStyle(inputDir: string) { export function rewriteSsrRenderStyle(inputDir: string) {
......
此差异已折叠。
此差异已折叠。
import { assert } from './testUtils'
describe('compiler: transform slot', () => {
test('basic', () => {
assert(
`<button><slot/></button>`,
`<button><slot/></button>`,
`(_ctx, _cache) => {
return {}
}`
)
})
test('fallback content', () => {
assert(
`<button><slot>Submit</slot></button>`,
`<button><block wx:if="{{$slots.default}}"><slot></slot></block><block wx:else>Submit</block></button>`,
`(_ctx, _cache) => {
return {}
}`
)
})
test('names slots', () => {
assert(
`<button><slot name="text"/></button>`,
`<button><slot name="text"/></button>`,
`(_ctx, _cache) => {
return {}
}`
)
})
test('names slots with fallback content', () => {
assert(
`<button><slot name="text">Submit</slot></button>`,
`<button><block wx:if="{{$slots.text}}"><slot name="text"></slot></block><block wx:else>Submit</block></button>`,
`(_ctx, _cache) => {
return {}
}`
)
})
})
...@@ -14,6 +14,9 @@ function assert( ...@@ -14,6 +14,9 @@ function assert(
prefixIdentifiers: true, prefixIdentifiers: true,
inline: true, inline: true,
miniProgram: { miniProgram: {
slot: {
fallback: false,
},
directive: 'wx:', directive: 'wx:',
emitFile({ source }) { emitFile({ source }) {
console.log(source) console.log(source)
...@@ -34,10 +37,10 @@ function assert( ...@@ -34,10 +37,10 @@ function assert(
describe('compiler', () => { describe('compiler', () => {
test('scope', () => { test('scope', () => {
assert( assert(
`<view :style="{ color: \`\${green}px\` }"/>`, `<template v-if="ok"><view/>hello<view/></template>`,
`<view style="{{'color:' + a}}"/>`, `<view style="{{'color:' + a}}"/>`,
`(_ctx, _cache) => { `(_ctx, _cache) => {
return { a: \`\${_ctx.green}px\` } return { a: _ctx.ok, ...(_ctx.ok ? {} : {}) }
}` }`
) )
}) })
......
import { isCustomElement, isNativeTag } from '@dcloudio/uni-shared'
import { compile } from '../src/index' import { compile } from '../src/index'
import { CompilerOptions } from '../src/options' import { CompilerOptions } from '../src/options'
export const miniProgram = {
slot: {
fallback: false,
},
directive: 'wx:',
} as const
export function inspect(obj: any) { export function inspect(obj: any) {
console.log(require('util').inspect(obj, { colors: true, depth: null })) console.log(require('util').inspect(obj, { colors: true, depth: null }))
} }
export function assert( export function assert(
template: string, template: string,
templateCode: string, templateCode: string,
...@@ -14,7 +24,12 @@ export function assert( ...@@ -14,7 +24,12 @@ export function assert(
filename: 'foo.vue', filename: 'foo.vue',
prefixIdentifiers: true, prefixIdentifiers: true,
inline: true, inline: true,
isNativeTag,
isCustomElement,
miniProgram: { miniProgram: {
slot: {
fallback: false,
},
directive: 'wx:', directive: 'wx:',
emitFile({ source }) { emitFile({ source }) {
// console.log(source) // console.log(source)
......
...@@ -2,7 +2,7 @@ import { ElementNode, ErrorCodes } from '@vue/compiler-core' ...@@ -2,7 +2,7 @@ import { ElementNode, ErrorCodes } from '@vue/compiler-core'
import { compile } from '../src' import { compile } from '../src'
import { MPErrorCodes } from '../src/errors' import { MPErrorCodes } from '../src/errors'
import { CompilerOptions } from '../src/options' import { CompilerOptions } from '../src/options'
import { assert } from './testUtils' import { assert, miniProgram } from './testUtils'
function parseWithVBind(template: string, options: CompilerOptions = {}) { function parseWithVBind(template: string, options: CompilerOptions = {}) {
const { ast, code } = compile(template, options) const { ast, code } = compile(template, options)
...@@ -30,7 +30,7 @@ describe('compiler: transform v-bind', () => { ...@@ -30,7 +30,7 @@ describe('compiler: transform v-bind', () => {
onError, onError,
filename: 'foo.vue', filename: 'foo.vue',
miniProgram: { miniProgram: {
directive: 'wx:', ...miniProgram,
emitFile({ source }) { emitFile({ source }) {
expect(source).toBe(`<view/>`) expect(source).toBe(`<view/>`)
return '' return ''
...@@ -54,7 +54,7 @@ describe('compiler: transform v-bind', () => { ...@@ -54,7 +54,7 @@ describe('compiler: transform v-bind', () => {
onError, onError,
filename: 'foo.vue', filename: 'foo.vue',
miniProgram: { miniProgram: {
directive: 'wx:', ...miniProgram,
emitFile({ source }) { emitFile({ source }) {
expect(source).toBe(`<view/>`) expect(source).toBe(`<view/>`)
return '' return ''
...@@ -125,7 +125,7 @@ describe('compiler: transform v-bind', () => { ...@@ -125,7 +125,7 @@ describe('compiler: transform v-bind', () => {
prefixIdentifiers: false, prefixIdentifiers: false,
filename: 'foo.vue', filename: 'foo.vue',
miniProgram: { miniProgram: {
directive: 'wx:', ...miniProgram,
emitFile({ source }) { emitFile({ source }) {
expect(source).toBe(`<view/>`) expect(source).toBe(`<view/>`)
return '' return ''
...@@ -154,7 +154,7 @@ describe('compiler: transform v-bind', () => { ...@@ -154,7 +154,7 @@ describe('compiler: transform v-bind', () => {
prefixIdentifiers: true, prefixIdentifiers: true,
filename: 'foo.vue', filename: 'foo.vue',
miniProgram: { miniProgram: {
directive: 'wx:', ...miniProgram,
emitFile({ source }) { emitFile({ source }) {
expect(source).toBe(`<view/>`) expect(source).toBe(`<view/>`)
return '' return ''
...@@ -201,7 +201,7 @@ describe('compiler: transform v-bind', () => { ...@@ -201,7 +201,7 @@ describe('compiler: transform v-bind', () => {
filename: 'foo.vue', filename: 'foo.vue',
prefixIdentifiers: false, prefixIdentifiers: false,
miniProgram: { miniProgram: {
directive: 'wx:', ...miniProgram,
emitFile({ source }) { emitFile({ source }) {
expect(source).toBe(`<view/>`) expect(source).toBe(`<view/>`)
return '' return ''
...@@ -230,7 +230,7 @@ describe('compiler: transform v-bind', () => { ...@@ -230,7 +230,7 @@ describe('compiler: transform v-bind', () => {
prefixIdentifiers: true, prefixIdentifiers: true,
filename: 'foo.vue', filename: 'foo.vue',
miniProgram: { miniProgram: {
directive: 'wx:', ...miniProgram,
emitFile({ source }) { emitFile({ source }) {
expect(source).toBe(`<view/>`) expect(source).toBe(`<view/>`)
return '' return ''
...@@ -258,7 +258,7 @@ describe('compiler: transform v-bind', () => { ...@@ -258,7 +258,7 @@ describe('compiler: transform v-bind', () => {
onWarn, onWarn,
filename: 'foo.vue', filename: 'foo.vue',
miniProgram: { miniProgram: {
directive: 'wx:', ...miniProgram,
emitFile({ source }) { emitFile({ source }) {
expect(source).toBe(`<view fooBar="{{a}}"/>`) expect(source).toBe(`<view fooBar="{{a}}"/>`)
return '' return ''
...@@ -286,7 +286,7 @@ describe('compiler: transform v-bind', () => { ...@@ -286,7 +286,7 @@ describe('compiler: transform v-bind', () => {
onWarn, onWarn,
filename: 'foo.vue', filename: 'foo.vue',
miniProgram: { miniProgram: {
directive: 'wx:', ...miniProgram,
emitFile({ source }) { emitFile({ source }) {
expect(source).toBe(`<view foo-bar="{{a}}"/>`) expect(source).toBe(`<view foo-bar="{{a}}"/>`)
return '' return ''
......
...@@ -2,6 +2,7 @@ import { ElementNode } from '@vue/compiler-core' ...@@ -2,6 +2,7 @@ import { ElementNode } from '@vue/compiler-core'
import { compile } from '../src' import { compile } from '../src'
import { MPErrorCodes } from '../src/errors' import { MPErrorCodes } from '../src/errors'
import { CompilerOptions } from '../src/options' import { CompilerOptions } from '../src/options'
import { assert } from './testUtils'
function parseWithVOn(template: string, options: CompilerOptions = {}) { function parseWithVOn(template: string, options: CompilerOptions = {}) {
const { ast } = compile(template, options) const { ast } = compile(template, options)
...@@ -12,6 +13,22 @@ function parseWithVOn(template: string, options: CompilerOptions = {}) { ...@@ -12,6 +13,22 @@ function parseWithVOn(template: string, options: CompilerOptions = {}) {
} }
describe('compiler(mp): transform v-on', () => { describe('compiler(mp): transform v-on', () => {
test('lazy element', () => {
assert(
`<editor/>`,
`<editor/>`,
`(_ctx, _cache) => {
return {}
}`
)
assert(
`<editor @ready="ready"/>`,
`<block wx:if="{{r0}}"><editor bindready="{{a}}"/></block>`,
`(_ctx, _cache) => {
return { a: _vOn(_ctx.ready) }
}`
)
})
test('should error if dynamic event', () => { test('should error if dynamic event', () => {
const onError = jest.fn() const onError = jest.fn()
parseWithVOn(`<div v-on:[event]="onClick" />`, { onError }) parseWithVOn(`<div v-on:[event]="onClick" />`, { onError })
......
...@@ -3,27 +3,34 @@ import { assert } from './testUtils' ...@@ -3,27 +3,34 @@ import { assert } from './testUtils'
describe('compiler: transform v-slot', () => { describe('compiler: transform v-slot', () => {
test('default slot', () => { test('default slot', () => {
assert( assert(
`<template v-slot/>`, `<custom><template v-slot/></custom>`,
`<block />`, `<custom vue-slots="{{['default']}}"><view /></custom>`,
`(_ctx, _cache) => {
return {}
}`
)
assert(
`<custom>test</custom>`,
`<custom vue-slots="{{['default']}}">test</custom>`,
`(_ctx, _cache) => { `(_ctx, _cache) => {
return {} return {}
}` }`
) )
}) })
test('named slot', () => { test('named slots', () => {
assert( assert(
`<template v-slot:header/><template v-slot:default/><template v-slot:footer/>`, `<custom><template v-slot:header/><template v-slot:default/><template v-slot:footer/></custom>`,
`<block slot="header"/><block slot="default"/><block slot="footer"/>`, `<custom vue-slots="{{['header','default','footer']}}"><view slot="header"/><view slot="default"/><view slot="footer"/></custom>`,
`(_ctx, _cache) => { `(_ctx, _cache) => {
return {} return {}
}` }`
) )
}) })
// TODO 还未实现scoped slot // TODO 还未实现scoped slot
test('named slot', () => { test('scoped slots', () => {
assert( assert(
`<template v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template>`, `<custom><template v-slot:default="slotProps"><view>{{ slotProps.item }}</view></template></custom>`,
`<block slot="default"><view>{{a}}</view></block>`, `<custom vue-slots="{{['default']}}"><view slot="default"><view>{{a}}</view></view></custom>`,
`(_ctx, _cache) => { `(_ctx, _cache) => {
return { a: _toDisplayString(_ctx.slotProps.item), b: slotProps } return { a: _toDisplayString(_ctx.slotProps.item), b: slotProps }
}` }`
......
...@@ -32,9 +32,14 @@ import { ...@@ -32,9 +32,14 @@ import {
isNullLiteral, isNullLiteral,
} from '@babel/types' } from '@babel/types'
import { import {
AttributeNode,
createCompilerError, createCompilerError,
createSimpleExpression,
DirectiveNode,
ErrorCodes, ErrorCodes,
ExpressionNode, ExpressionNode,
locStub,
NodeTypes,
} from '@vue/compiler-core' } from '@vue/compiler-core'
import { CodegenScope, CodegenVForScope, CodegenVIfScope } from './options' import { CodegenScope, CodegenVForScope, CodegenVIfScope } from './options'
import { TransformContext } from './transform' import { TransformContext } from './transform'
...@@ -193,3 +198,33 @@ export function parseStringLiteral( ...@@ -193,3 +198,33 @@ export function parseStringLiteral(
} }
return stringLiteral('') return stringLiteral('')
} }
export function createBindDirectiveNode(
name: string,
value: string
): DirectiveNode {
return {
type: NodeTypes.DIRECTIVE,
name: 'bind',
modifiers: [],
loc: locStub,
arg: createSimpleExpression(name, true),
exp: createSimpleExpression(value, false),
}
}
export function createAttributeNode(
name: string,
content: string
): AttributeNode {
return {
type: NodeTypes.ATTRIBUTE,
loc: locStub,
name,
value: {
type: NodeTypes.TEXT,
loc: locStub,
content,
},
}
}
...@@ -72,6 +72,7 @@ export function baseCompile(template: string, options: CompilerOptions = {}) { ...@@ -72,6 +72,7 @@ export function baseCompile(template: string, options: CompilerOptions = {}) {
filename: options.filename, filename: options.filename,
directive: options.miniProgram.directive, directive: options.miniProgram.directive,
emitFile: options.miniProgram.emitFile, emitFile: options.miniProgram.emitFile,
slot: options.miniProgram.slot,
}) })
} }
......
...@@ -19,6 +19,21 @@ export interface ErrorHandlingOptions { ...@@ -19,6 +19,21 @@ export interface ErrorHandlingOptions {
onError?: (error: CompilerError) => void onError?: (error: CompilerError) => void
} }
interface ParserOptions {
/**
* e.g. platform native elements, e.g. `<div>` for browsers
*/
isNativeTag?: (tag: string) => boolean
/**
* e.g. native elements that can self-close, e.g. `<img>`, `<br>`, `<hr>`
*/
isVoidTag?: (tag: string) => boolean
/**
* Separate option for end users to extend the native elements list
*/
isCustomElement?: (tag: string) => boolean | void
}
interface SharedTransformCodegenOptions { interface SharedTransformCodegenOptions {
inline?: boolean inline?: boolean
isTS?: boolean isTS?: boolean
...@@ -73,16 +88,22 @@ export interface CodegenOptions extends SharedTransformCodegenOptions { ...@@ -73,16 +88,22 @@ export interface CodegenOptions extends SharedTransformCodegenOptions {
runtimeModuleName?: string runtimeModuleName?: string
runtimeGlobalName?: string runtimeGlobalName?: string
miniProgram?: { miniProgram?: {
slot: {
fallback: boolean
}
directive: string directive: string
emitFile?: (emittedFile: EmittedFile) => string emitFile?: (emittedFile: EmittedFile) => string
} }
} }
export interface TemplateCodegenOptions { export interface TemplateCodegenOptions {
slot: {
fallback: boolean
}
scopeId?: string | null scopeId?: string | null
filename: string filename: string
directive: string directive: string
emitFile: (emittedFile: EmittedFile) => string emitFile: (emittedFile: EmittedFile) => string
} }
export type CompilerOptions = TransformOptions & CodegenOptions export type CompilerOptions = ParserOptions & TransformOptions & CodegenOptions
...@@ -17,18 +17,23 @@ import { TemplateCodegenOptions } from '../options' ...@@ -17,18 +17,23 @@ import { TemplateCodegenOptions } from '../options'
import { genExpr } from '../codegen' import { genExpr } from '../codegen'
import { isForElementNode, VForOptions } from '../transforms/vFor' import { isForElementNode, VForOptions } from '../transforms/vFor'
import { IfElementNode, isIfElementNode } from '../transforms/vIf' import { IfElementNode, isIfElementNode } from '../transforms/vIf'
import { createBindDirectiveNode } from '../ast'
interface TemplateCodegenContext { interface TemplateCodegenContext {
code: string code: string
directive: string directive: string
scopeId?: string | null scopeId?: string | null
slot: {
fallback: boolean
}
push(code: string): void push(code: string): void
} }
export function generate( export function generate(
{ children }: RootNode, { children }: RootNode,
{ scopeId, emitFile, filename, directive }: TemplateCodegenOptions { slot, scopeId, emitFile, filename, directive }: TemplateCodegenOptions
) { ) {
const context: TemplateCodegenContext = { const context: TemplateCodegenContext = {
slot,
code: '', code: '',
scopeId, scopeId,
directive, directive,
...@@ -49,13 +54,23 @@ export function genNode( ...@@ -49,13 +54,23 @@ export function genNode(
switch (node.type) { switch (node.type) {
case NodeTypes.IF: case NodeTypes.IF:
return node.branches.forEach((node) => { return node.branches.forEach((node) => {
genElement(node as unknown as IfElementNode, context) genNode(node as unknown as IfElementNode, context)
}) })
case NodeTypes.TEXT: case NodeTypes.TEXT:
return genText(node, context) return genText(node, context)
case NodeTypes.INTERPOLATION: case NodeTypes.INTERPOLATION:
return genExpression(node.content, context) return genExpression(node.content, context)
case NodeTypes.ELEMENT: case NodeTypes.ELEMENT:
if (node.tagType === ElementTypes.SLOT) {
return genSlot(node, context)
} else if (node.tagType === ElementTypes.COMPONENT) {
return genComponent(node, context)
} else if (node.tagType === ElementTypes.TEMPLATE) {
return genTemplate(node, context)
} else if (isLazyElement(node)) {
return genLazyElement(node, context)
}
return genElement(node, context) return genElement(node, context)
} }
} }
...@@ -94,12 +109,123 @@ function genVFor( ...@@ -94,12 +109,123 @@ function genVFor(
node.props.splice(node.props.indexOf(keyProp), 1) node.props.splice(node.props.indexOf(keyProp), 1)
} }
} }
const tagMap: Record<string, string> = {
template: 'block', function genSlot(node: ElementNode, context: TemplateCodegenContext) {
if (!node.children.length) {
return genElement(node, context)
}
const children = node.children.slice()
node.children.length = 0
const { push } = context
push(`<block`)
const nameProp = findProp(node, 'name')
genVIf(
`$slots.` +
(nameProp?.type === NodeTypes.ATTRIBUTE && nameProp.value?.content
? nameProp.value.content
: 'default'),
context
)
push(`>`)
genElement(node, context)
push(`</block>`)
push(`<block`)
genVElse(context)
push(`>`)
children.forEach((node) => {
genNode(node, context)
})
push(`</block>`)
}
function findSlotName(node: ElementNode) {
const slotProp = node.props.find(
(prop) => prop.type === NodeTypes.DIRECTIVE && prop.name === 'slot'
) as DirectiveNode | undefined
if (slotProp) {
const { arg } = slotProp
if (!arg) {
return 'default'
}
if (arg.type === NodeTypes.SIMPLE_EXPRESSION && arg.isStatic) {
return arg.content
}
}
} }
export function genElement(node: ElementNode, context: TemplateCodegenContext) {
function genTemplate(node: ElementNode, context: TemplateCodegenContext) {
const slotName = findSlotName(node)
if (slotName) {
/**
* 仅百度、字节支持使用 block 作为命名插槽根节点
* 此处为了统一仅默认替换为view
* <template v-slot/> => <view slot="">
*/
node.tag = 'view'
} else {
// <template/> => <block/>
node.tag = 'block'
}
node.tagType = ElementTypes.ELEMENT
return genElement(node, context)
}
function genComponent(node: ElementNode, context: TemplateCodegenContext) {
const slots = new Set<string>()
if (!node.children.length) {
return genElement(node, context)
}
node.children.forEach((child) => {
if (child.type === NodeTypes.ELEMENT) {
slots.add(findSlotName(child) || 'default')
} else if (child.type === NodeTypes.TEXT) {
slots.add('default')
}
})
node.props.unshift(
createBindDirectiveNode(
'vue-slots',
`[${[...slots].map((name) => `'${name}'`).join(',')}]`
)
)
return genElement(node, context)
}
const lazyElementMap: Record<string, string[]> = {
editor: ['ready'],
}
function isLazyElement(node: ElementNode) {
const events = lazyElementMap[node.tag]
return (
events &&
node.props.some(
(prop) =>
prop.type === NodeTypes.DIRECTIVE &&
prop.name === 'on' &&
prop.arg?.type === NodeTypes.SIMPLE_EXPRESSION &&
events.includes(prop.arg.content)
)
)
}
/**
* 部分内置组件的部分事件在初始化时会立刻触发,但标准事件需要等首次渲染才能确认事件函数,故增加wx:if="{{r0}}"
* @param node
* @param context
*/
function genLazyElement(node: ElementNode, context: TemplateCodegenContext) {
const { push } = context
push(`<block`)
// r0 => ready 首次渲染
genVIf(`r0`, context)
push(`>`)
genElement(node, context)
push(`</block>`)
}
function genElement(node: ElementNode, context: TemplateCodegenContext) {
const { children, isSelfClosing, props } = node const { children, isSelfClosing, props } = node
let tag = tagMap[node.tag] || node.tag let tag = node.tag
if (node.tagType === ElementTypes.COMPONENT) { if (node.tagType === ElementTypes.COMPONENT) {
tag = hyphenate(tag) tag = hyphenate(tag)
} }
......
...@@ -24,6 +24,7 @@ import { ...@@ -24,6 +24,7 @@ import {
NodeTransform, NodeTransform,
TransformContext, TransformContext,
} from '../transform' } from '../transform'
import { createAttributeNode } from '../ast'
export interface DirectiveTransformResult { export interface DirectiveTransformResult {
props: Property[] props: Property[]
...@@ -58,17 +59,9 @@ export const transformElement: NodeTransform = (node, context) => { ...@@ -58,17 +59,9 @@ export const transformElement: NodeTransform = (node, context) => {
} }
function createClassAttribute(clazz: string): AttributeNode { function createClassAttribute(clazz: string): AttributeNode {
return { return createAttributeNode('class', clazz)
type: NodeTypes.ATTRIBUTE,
loc: locStub,
name: 'class',
value: {
type: NodeTypes.TEXT,
loc: locStub,
content: clazz,
},
}
} }
function addScopeId(node: ElementNode, scopeId: string) { function addScopeId(node: ElementNode, scopeId: string) {
const classProp = node.props.find( const classProp = node.props.find(
(prop) => prop.type === NodeTypes.ATTRIBUTE && prop.name === 'class' (prop) => prop.type === NodeTypes.ATTRIBUTE && prop.name === 'class'
......
...@@ -38,6 +38,10 @@ export interface UniMiniProgramPluginOptions { ...@@ -38,6 +38,10 @@ export interface UniMiniProgramPluginOptions {
template: { template: {
extname: string extname: string
directive: string directive: string
slot: {
// 是否支持fallback content
fallback: boolean
}
} }
style: { style: {
extname: string extname: string
...@@ -83,7 +87,11 @@ export function uniMiniProgramPlugin( ...@@ -83,7 +87,11 @@ export function uniMiniProgramPlugin(
name: 'vite:uni-mp', name: 'vite:uni-mp',
uni: uniOptions({ uni: uniOptions({
copyOptions, copyOptions,
miniProgram: { directive: template.directive, emitFile }, miniProgram: {
directive: template.directive,
emitFile,
slot: template.slot,
},
}), }),
config() { config() {
return { return {
......
import { import { isNativeTag, isCustomElement } from '@dcloudio/uni-shared'
isServiceNativeTag,
isServiceCustomElement,
} from '@dcloudio/uni-shared'
import { EmittedFile } from 'rollup' import { EmittedFile } from 'rollup'
import { CopyOptions, UniVitePlugin } from '@dcloudio/uni-cli-shared' import { CopyOptions, UniVitePlugin } from '@dcloudio/uni-cli-shared'
import { TemplateCompiler } from '@vue/compiler-sfc' import { TemplateCompiler } from '@vue/compiler-sfc'
...@@ -14,6 +11,9 @@ export function uniOptions({ ...@@ -14,6 +11,9 @@ export function uniOptions({
}: { }: {
copyOptions: CopyOptions copyOptions: CopyOptions
miniProgram: { miniProgram: {
slot: {
fallback: boolean
}
directive: string directive: string
emitFile?: (emittedFile: EmittedFile) => string emitFile?: (emittedFile: EmittedFile) => string
} }
...@@ -23,8 +23,8 @@ export function uniOptions({ ...@@ -23,8 +23,8 @@ export function uniOptions({
compiler: compiler as TemplateCompiler, compiler: compiler as TemplateCompiler,
compilerOptions: { compilerOptions: {
miniProgram, miniProgram,
isNativeTag: isServiceNativeTag, isNativeTag,
isCustomElement: isServiceCustomElement, isCustomElement,
}, },
} }
} }
...@@ -87,7 +87,10 @@ export function uniPagesJsonPlugin( ...@@ -87,7 +87,10 @@ export function uniPagesJsonPlugin(
function importPagesCode(pagesJson: AppJson) { function importPagesCode(pagesJson: AppJson) {
const importPagesCode: string[] = [] const importPagesCode: string[] = []
function importPageCode(pagePath: string) { function importPageCode(pagePath: string) {
const pagePathWithExtname = normalizePagePath(pagePath, 'app') const pagePathWithExtname = normalizePagePath(
pagePath,
process.env.UNI_PLATFORM
)
if (pagePathWithExtname) { if (pagePathWithExtname) {
importPagesCode.push(`import('${virtualPagePath(pagePathWithExtname)}')`) importPagesCode.push(`import('${virtualPagePath(pagePathWithExtname)}')`)
} }
......
...@@ -4551,6 +4551,7 @@ function patch(instance, data) { ...@@ -4551,6 +4551,7 @@ function patch(instance, data) {
const ctx = instance.ctx; const ctx = instance.ctx;
const mpType = ctx.mpType; const mpType = ctx.mpType;
if (mpType === 'page' || mpType === 'component') { if (mpType === 'page' || mpType === 'component') {
data.r0 = 1; // ready
const start = Date.now(); const start = Date.now();
const mpInstance = ctx.$scope; const mpInstance = ctx.$scope;
const keys = Object.keys(data); const keys = Object.keys(data);
......
...@@ -4483,6 +4483,7 @@ function patch(instance, data) { ...@@ -4483,6 +4483,7 @@ function patch(instance, data) {
const ctx = instance.ctx; const ctx = instance.ctx;
const mpType = ctx.mpType; const mpType = ctx.mpType;
if (mpType === 'page' || mpType === 'component') { if (mpType === 'page' || mpType === 'component') {
data.r0 = 1; // ready
const start = Date.now(); const start = Date.now();
const mpInstance = ctx.$scope; const mpInstance = ctx.$scope;
const keys = Object.keys(data); const keys = Object.keys(data);
......
...@@ -107,6 +107,9 @@ const options = { ...@@ -107,6 +107,9 @@ const options = {
source, source,
}, },
template: { template: {
slot: {
fallback: false,
},
extname: '.wxml', extname: '.wxml',
directive: 'wx:', directive: 'wx:',
}, },
......
...@@ -61,6 +61,9 @@ const options: UniMiniProgramPluginOptions = { ...@@ -61,6 +61,9 @@ const options: UniMiniProgramPluginOptions = {
source, source,
}, },
template: { template: {
slot: {
fallback: false,
},
extname: '.wxml', extname: '.wxml',
directive: 'wx:', directive: 'wx:',
}, },
......
...@@ -72,16 +72,16 @@ const TAGS = [ ...@@ -72,16 +72,16 @@ const TAGS = [
function isBuiltInComponent(tag) { function isBuiltInComponent(tag) {
return BUILT_IN_TAGS.indexOf('uni-' + tag) !== -1; return BUILT_IN_TAGS.indexOf('uni-' + tag) !== -1;
} }
function isCustomElement(tag) { function isH5CustomElement(tag) {
return TAGS.indexOf(tag) !== -1 || BUILT_IN_TAGS.indexOf(tag) !== -1; return TAGS.indexOf(tag) !== -1 || BUILT_IN_TAGS.indexOf(tag) !== -1;
} }
function isNativeTag(tag) { function isH5NativeTag(tag) {
return (shared.isHTMLTag(tag) || shared.isSVGTag(tag)) && !isBuiltInComponent(tag); return (shared.isHTMLTag(tag) || shared.isSVGTag(tag)) && !isBuiltInComponent(tag);
} }
function isServiceNativeTag(tag) { function isNativeTag(tag) {
return shared.isHTMLTag(tag) || shared.isSVGTag(tag) || isBuiltInComponent(tag); return shared.isHTMLTag(tag) || shared.isSVGTag(tag) || isBuiltInComponent(tag);
} }
function isServiceCustomElement(_tag) { function isCustomElement(_tag) {
return false; return false;
} }
const COMPONENT_SELECTOR_PREFIX = 'uni-'; const COMPONENT_SELECTOR_PREFIX = 'uni-';
...@@ -1233,10 +1233,10 @@ exports.initCustomDataset = initCustomDataset; ...@@ -1233,10 +1233,10 @@ exports.initCustomDataset = initCustomDataset;
exports.invokeArrayFns = invokeArrayFns; exports.invokeArrayFns = invokeArrayFns;
exports.isBuiltInComponent = isBuiltInComponent; exports.isBuiltInComponent = isBuiltInComponent;
exports.isCustomElement = isCustomElement; exports.isCustomElement = isCustomElement;
exports.isH5CustomElement = isH5CustomElement;
exports.isH5NativeTag = isH5NativeTag;
exports.isNativeTag = isNativeTag; exports.isNativeTag = isNativeTag;
exports.isRootHook = isRootHook; exports.isRootHook = isRootHook;
exports.isServiceCustomElement = isServiceCustomElement;
exports.isServiceNativeTag = isServiceNativeTag;
exports.normalizeDataset = normalizeDataset; exports.normalizeDataset = normalizeDataset;
exports.normalizeEventType = normalizeEventType; exports.normalizeEventType = normalizeEventType;
exports.normalizeTarget = normalizeTarget; exports.normalizeTarget = normalizeTarget;
......
...@@ -206,15 +206,15 @@ export declare const invokeArrayFns: (fns: Function[], arg?: any) => any; ...@@ -206,15 +206,15 @@ export declare const invokeArrayFns: (fns: Function[], arg?: any) => any;
export declare function isBuiltInComponent(tag: string): boolean; export declare function isBuiltInComponent(tag: string): boolean;
export declare function isCustomElement(tag: string): boolean; export declare function isCustomElement(_tag: string): boolean;
export declare function isNativeTag(tag: string): boolean; export declare function isH5CustomElement(tag: string): boolean;
export declare function isRootHook(name: string): boolean; export declare function isH5NativeTag(tag: string): boolean;
export declare function isServiceCustomElement(_tag: string): boolean; export declare function isNativeTag(tag: string): boolean;
export declare function isServiceNativeTag(tag: string): boolean; export declare function isRootHook(name: string): boolean;
export declare interface IUniPageNode { export declare interface IUniPageNode {
pageId: number; pageId: number;
......
...@@ -68,16 +68,16 @@ const TAGS = [ ...@@ -68,16 +68,16 @@ const TAGS = [
function isBuiltInComponent(tag) { function isBuiltInComponent(tag) {
return BUILT_IN_TAGS.indexOf('uni-' + tag) !== -1; return BUILT_IN_TAGS.indexOf('uni-' + tag) !== -1;
} }
function isCustomElement(tag) { function isH5CustomElement(tag) {
return TAGS.indexOf(tag) !== -1 || BUILT_IN_TAGS.indexOf(tag) !== -1; return TAGS.indexOf(tag) !== -1 || BUILT_IN_TAGS.indexOf(tag) !== -1;
} }
function isNativeTag(tag) { function isH5NativeTag(tag) {
return (isHTMLTag(tag) || isSVGTag(tag)) && !isBuiltInComponent(tag); return (isHTMLTag(tag) || isSVGTag(tag)) && !isBuiltInComponent(tag);
} }
function isServiceNativeTag(tag) { function isNativeTag(tag) {
return isHTMLTag(tag) || isSVGTag(tag) || isBuiltInComponent(tag); return isHTMLTag(tag) || isSVGTag(tag) || isBuiltInComponent(tag);
} }
function isServiceCustomElement(_tag) { function isCustomElement(_tag) {
return false; return false;
} }
const COMPONENT_SELECTOR_PREFIX = 'uni-'; const COMPONENT_SELECTOR_PREFIX = 'uni-';
...@@ -1115,4 +1115,4 @@ function getEnvLocale() { ...@@ -1115,4 +1115,4 @@ function getEnvLocale() {
return (lang && lang.replace(/[.:].*/, '')) || 'en'; return (lang && lang.replace(/[.:].*/, '')) || 'en';
} }
export { ACTION_TYPE_ADD_EVENT, ACTION_TYPE_ADD_WXS_EVENT, ACTION_TYPE_CREATE, ACTION_TYPE_EVENT, ACTION_TYPE_INSERT, ACTION_TYPE_PAGE_CREATE, ACTION_TYPE_PAGE_CREATED, ACTION_TYPE_PAGE_SCROLL, ACTION_TYPE_REMOVE, ACTION_TYPE_REMOVE_ATTRIBUTE, ACTION_TYPE_REMOVE_EVENT, ACTION_TYPE_SET_ATTRIBUTE, ACTION_TYPE_SET_TEXT, ATTR_CHANGE_PREFIX, ATTR_CLASS, ATTR_INNER_HTML, ATTR_STYLE, ATTR_TEXT_CONTENT, ATTR_V_OWNER_ID, ATTR_V_RENDERJS, ATTR_V_SHOW, BACKGROUND_COLOR, BUILT_IN_TAGS, COMPONENT_NAME_PREFIX, COMPONENT_PREFIX, COMPONENT_SELECTOR_PREFIX, DATA_RE, EventChannel, EventModifierFlags, I18N_JSON_DELIMITERS, JSON_PROTOCOL, LINEFEED, NAVBAR_HEIGHT, NODE_TYPE_COMMENT, NODE_TYPE_ELEMENT, NODE_TYPE_PAGE, NODE_TYPE_TEXT, ON_ADD_TO_FAVORITES, ON_APP_ENTER_BACKGROUND, ON_APP_ENTER_FOREGROUND, ON_BACK_PRESS, ON_ERROR, ON_HIDE, ON_KEYBOARD_HEIGHT_CHANGE, ON_LAUNCH, ON_LOAD, ON_NAVIGATION_BAR_BUTTON_TAP, ON_NAVIGATION_BAR_SEARCH_INPUT_CHANGED, ON_NAVIGATION_BAR_SEARCH_INPUT_CLICKED, ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED, ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED, ON_PAGE_NOT_FOUND, ON_PAGE_SCROLL, ON_PULL_DOWN_REFRESH, ON_REACH_BOTTOM, ON_REACH_BOTTOM_DISTANCE, ON_READY, ON_RESIZE, ON_SHARE_APP_MESSAGE, ON_SHARE_TIMELINE, ON_SHOW, ON_TAB_ITEM_TAP, ON_THEME_CHANGE, ON_UNHANDLE_REJECTION, ON_UNLOAD, ON_WEB_INVOKE_APP_SERVICE, ON_WXS_INVOKE_CALL_METHOD, PLUS_RE, PRIMARY_COLOR, RENDERJS_MODULES, RESPONSIVE_MIN_WIDTH, SCHEME_RE, SELECTED_COLOR, TABBAR_HEIGHT, TAGS, UNI_SSR, UNI_SSR_DATA, UNI_SSR_GLOBAL_DATA, UNI_SSR_STORE, UNI_SSR_TITLE, UniBaseNode, UniCommentNode, UniElement, UniEvent, UniInputElement, UniLifecycleHooks, UniNode, UniTextAreaElement, UniTextNode, WEB_INVOKE_APPSERVICE, WXS_MODULES, WXS_PROTOCOL, addFont, cache, cacheStringFunction, callOptions, createRpx2Unit, createUniEvent, debounce, decode, decodedQuery, defaultMiniProgramRpx2Unit, defaultRpx2Unit, formatAppLog, formatDateTime, formatLog, getCustomDataset, getEnvLocale, getLen, getValueByDataPath, initCustomDataset, invokeArrayFns, isBuiltInComponent, isCustomElement, isNativeTag, isRootHook, isServiceCustomElement, isServiceNativeTag, normalizeDataset, normalizeEventType, normalizeTarget, once, parseEventName, parseQuery, parseUrl, passive, plusReady, removeLeadingSlash, resolveOwnerEl, resolveOwnerVm, sanitise, scrollTo, stringifyQuery, updateElementStyle }; export { ACTION_TYPE_ADD_EVENT, ACTION_TYPE_ADD_WXS_EVENT, ACTION_TYPE_CREATE, ACTION_TYPE_EVENT, ACTION_TYPE_INSERT, ACTION_TYPE_PAGE_CREATE, ACTION_TYPE_PAGE_CREATED, ACTION_TYPE_PAGE_SCROLL, ACTION_TYPE_REMOVE, ACTION_TYPE_REMOVE_ATTRIBUTE, ACTION_TYPE_REMOVE_EVENT, ACTION_TYPE_SET_ATTRIBUTE, ACTION_TYPE_SET_TEXT, ATTR_CHANGE_PREFIX, ATTR_CLASS, ATTR_INNER_HTML, ATTR_STYLE, ATTR_TEXT_CONTENT, ATTR_V_OWNER_ID, ATTR_V_RENDERJS, ATTR_V_SHOW, BACKGROUND_COLOR, BUILT_IN_TAGS, COMPONENT_NAME_PREFIX, COMPONENT_PREFIX, COMPONENT_SELECTOR_PREFIX, DATA_RE, EventChannel, EventModifierFlags, I18N_JSON_DELIMITERS, JSON_PROTOCOL, LINEFEED, NAVBAR_HEIGHT, NODE_TYPE_COMMENT, NODE_TYPE_ELEMENT, NODE_TYPE_PAGE, NODE_TYPE_TEXT, ON_ADD_TO_FAVORITES, ON_APP_ENTER_BACKGROUND, ON_APP_ENTER_FOREGROUND, ON_BACK_PRESS, ON_ERROR, ON_HIDE, ON_KEYBOARD_HEIGHT_CHANGE, ON_LAUNCH, ON_LOAD, ON_NAVIGATION_BAR_BUTTON_TAP, ON_NAVIGATION_BAR_SEARCH_INPUT_CHANGED, ON_NAVIGATION_BAR_SEARCH_INPUT_CLICKED, ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED, ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED, ON_PAGE_NOT_FOUND, ON_PAGE_SCROLL, ON_PULL_DOWN_REFRESH, ON_REACH_BOTTOM, ON_REACH_BOTTOM_DISTANCE, ON_READY, ON_RESIZE, ON_SHARE_APP_MESSAGE, ON_SHARE_TIMELINE, ON_SHOW, ON_TAB_ITEM_TAP, ON_THEME_CHANGE, ON_UNHANDLE_REJECTION, ON_UNLOAD, ON_WEB_INVOKE_APP_SERVICE, ON_WXS_INVOKE_CALL_METHOD, PLUS_RE, PRIMARY_COLOR, RENDERJS_MODULES, RESPONSIVE_MIN_WIDTH, SCHEME_RE, SELECTED_COLOR, TABBAR_HEIGHT, TAGS, UNI_SSR, UNI_SSR_DATA, UNI_SSR_GLOBAL_DATA, UNI_SSR_STORE, UNI_SSR_TITLE, UniBaseNode, UniCommentNode, UniElement, UniEvent, UniInputElement, UniLifecycleHooks, UniNode, UniTextAreaElement, UniTextNode, WEB_INVOKE_APPSERVICE, WXS_MODULES, WXS_PROTOCOL, addFont, cache, cacheStringFunction, callOptions, createRpx2Unit, createUniEvent, debounce, decode, decodedQuery, defaultMiniProgramRpx2Unit, defaultRpx2Unit, formatAppLog, formatDateTime, formatLog, getCustomDataset, getEnvLocale, getLen, getValueByDataPath, initCustomDataset, invokeArrayFns, isBuiltInComponent, isCustomElement, isH5CustomElement, isH5NativeTag, isNativeTag, isRootHook, normalizeDataset, normalizeEventType, normalizeTarget, once, parseEventName, parseQuery, parseUrl, passive, plusReady, removeLeadingSlash, resolveOwnerEl, resolveOwnerVm, sanitise, scrollTo, stringifyQuery, updateElementStyle };
...@@ -71,19 +71,19 @@ export function isBuiltInComponent(tag: string) { ...@@ -71,19 +71,19 @@ export function isBuiltInComponent(tag: string) {
return BUILT_IN_TAGS.indexOf('uni-' + tag) !== -1 return BUILT_IN_TAGS.indexOf('uni-' + tag) !== -1
} }
export function isCustomElement(tag: string) { export function isH5CustomElement(tag: string) {
return TAGS.indexOf(tag) !== -1 || BUILT_IN_TAGS.indexOf(tag) !== -1 return TAGS.indexOf(tag) !== -1 || BUILT_IN_TAGS.indexOf(tag) !== -1
} }
export function isNativeTag(tag: string) { export function isH5NativeTag(tag: string) {
return (isHTMLTag(tag) || isSVGTag(tag)) && !isBuiltInComponent(tag) return (isHTMLTag(tag) || isSVGTag(tag)) && !isBuiltInComponent(tag)
} }
export function isServiceNativeTag(tag: string) { export function isNativeTag(tag: string) {
return isHTMLTag(tag) || isSVGTag(tag) || isBuiltInComponent(tag) return isHTMLTag(tag) || isSVGTag(tag) || isBuiltInComponent(tag)
} }
export function isServiceCustomElement(_tag: string) { export function isCustomElement(_tag: string) {
return false return false
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册