template.ts 3.2 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1
import path from 'path'
fxy060608's avatar
fxy060608 已提交
2 3 4 5 6 7 8 9 10 11 12 13
import { EmittedAsset } from 'rollup'
import { isComponentTag, LINEFEED } from '@dcloudio/uni-shared'
import {
  createSimpleExpression,
  ElementTypes,
  isCoreComponent,
  locStub,
  NodeTypes,
  RootNode,
  TemplateChildNode,
  TransformContext,
} from '@vue/compiler-core'
fxy060608's avatar
fxy060608 已提交
14
import { normalizeMiniProgramFilename } from '../utils'
fxy060608's avatar
fxy060608 已提交
15

fxy060608's avatar
fxy060608 已提交
16 17 18 19 20 21 22 23 24 25
export interface MiniProgramCompilerOptions {
  slot: {
    fallback: boolean
  }
  filter?: {
    lang: string
  }
  directive: string
  emitFile?: (emittedFile: EmittedAsset) => string
}
fxy060608's avatar
fxy060608 已提交
26 27 28 29 30 31 32 33
export interface MiniProgramFilterOptions {
  id: string
  type: 'wxs'
  name: string
  src?: string
  code: string
}

fxy060608's avatar
fxy060608 已提交
34 35 36 37
type GenFilterFn = (
  filter: MiniProgramFilterOptions,
  filename: string
) => string | void
fxy060608's avatar
fxy060608 已提交
38 39

const templateFilesCache = new Map<string, string>()
fxy060608's avatar
fxy060608 已提交
40
const templateFiltersCache = new Map<string, MiniProgramFilterOptions[]>()
fxy060608's avatar
fxy060608 已提交
41

fxy060608's avatar
fxy060608 已提交
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
function relativeFilterFilename(
  filename: string,
  filter: MiniProgramFilterOptions
) {
  if (!filter.src) {
    return ''
  }
  return (
    './' +
    normalizeMiniProgramFilename(
      path.relative(path.dirname(filename), filter.src)
    )
  )
}

fxy060608's avatar
fxy060608 已提交
57 58 59 60 61 62 63
export function findMiniProgramTemplateFiles(genFilter?: GenFilterFn) {
  const files: Record<string, string> = Object.create(null)
  templateFilesCache.forEach((code, filename) => {
    if (!genFilter) {
      files[filename] = code
    } else {
      const filters = getMiniProgramTemplateFilters(filename)
fxy060608's avatar
fxy060608 已提交
64
      if (filters && filters.length) {
fxy060608's avatar
fxy060608 已提交
65
        files[filename] =
fxy060608's avatar
fxy060608 已提交
66 67 68 69 70
          filters
            .map((filter) =>
              genFilter(filter, relativeFilterFilename(filename, filter))
            )
            .join(LINEFEED) +
fxy060608's avatar
fxy060608 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
          LINEFEED +
          code
      } else {
        files[filename] = code
      }
    }
  })
  return files
}

export function clearMiniProgramTemplateFiles() {
  templateFilesCache.clear()
}

export function addMiniProgramTemplateFile(filename: string, code: string) {
  templateFilesCache.set(filename, code)
}

function getMiniProgramTemplateFilters(filename: string) {
fxy060608's avatar
fxy060608 已提交
90
  return templateFiltersCache.get(filename)
fxy060608's avatar
fxy060608 已提交
91 92 93 94 95 96 97 98 99 100 101 102
}

export function clearMiniProgramTemplateFilter(filename: string) {
  templateFiltersCache.delete(filename)
}

export function addMiniProgramTemplateFilter(
  filename: string,
  filter: MiniProgramFilterOptions
) {
  const filters = templateFiltersCache.get(filename)
  if (filters) {
fxy060608's avatar
fxy060608 已提交
103 104 105 106 107 108
    const filterIndex = filters.findIndex((f) => f.id === filter.id)
    if (filterIndex > -1) {
      filters.splice(filterIndex, 1, filter)
    } else {
      filters.push(filter)
    }
fxy060608's avatar
fxy060608 已提交
109
  } else {
fxy060608's avatar
fxy060608 已提交
110
    templateFiltersCache.set(filename, [filter])
fxy060608's avatar
fxy060608 已提交
111 112
  }
}
fxy060608's avatar
fxy060608 已提交
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139

export function addComponentBindLink(
  node: RootNode | TemplateChildNode,
  context: TransformContext
) {
  if (
    node.type === NodeTypes.ELEMENT &&
    node.tagType === ElementTypes.COMPONENT
  ) {
    const { tag } = node
    if (
      isComponentTag(tag) ||
      isCoreComponent(tag) ||
      context.isBuiltInComponent(tag)
    ) {
      return
    }
    node.props.push({
      type: NodeTypes.DIRECTIVE,
      name: 'on',
      modifiers: [],
      loc: locStub,
      arg: createSimpleExpression('__l', true),
      exp: createSimpleExpression('__l', true),
    })
  }
}