usingComponents.ts 4.1 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1
import path from 'path'
fxy060608's avatar
fxy060608 已提交
2
import type { Plugin, ResolvedConfig } from 'vite'
fxy060608's avatar
fxy060608 已提交
3
import type { SFCScriptCompileOptions } from '@vue/compiler-sfc'
fxy060608's avatar
fxy060608 已提交
4 5 6
import {
  EXTNAME_VUE,
  parseVueRequest,
fxy060608's avatar
fxy060608 已提交
7
  isMiniProgramPageFile,
fxy060608's avatar
fxy060608 已提交
8 9 10 11 12 13 14 15
  parseProgram,
  parseScriptDescriptor,
  parseTemplateDescriptor,
  parseMainDescriptor,
  updateMiniProgramComponentsByMainFilename,
  transformDynamicImports,
  updateMiniProgramComponentsByScriptFilename,
  updateMiniProgramComponentsByTemplateFilename,
16
  withSourcemap,
fxy060608's avatar
fxy060608 已提交
17
  resolveUtsModule,
fxy060608's avatar
fxy060608 已提交
18
} from '@dcloudio/uni-cli-shared'
fxy060608's avatar
fxy060608 已提交
19
import { virtualComponentPath, virtualPagePath } from './entry'
fxy060608's avatar
fxy060608 已提交
20
import { CustomPluginOptions, ResolvedId } from 'rollup'
fxy060608's avatar
fxy060608 已提交
21 22

export function uniUsingComponentsPlugin(
23 24 25 26
  options: {
    normalizeComponentName?: (name: string) => string
    babelParserPlugins?: SFCScriptCompileOptions['babelParserPlugins']
  } = {}
fxy060608's avatar
fxy060608 已提交
27
): Plugin {
28 29
  const normalizeComponentName =
    options.normalizeComponentName || ((name: string) => name)
fxy060608's avatar
fxy060608 已提交
30 31 32 33 34 35
  const parseAst = (source: string, id: string) => {
    return parseProgram(source, id, {
      babelParserPlugins: options.babelParserPlugins,
    })
  }
  const inputDir = process.env.UNI_INPUT_DIR
fxy060608's avatar
fxy060608 已提交
36
  let resolvedConfig: ResolvedConfig
fxy060608's avatar
fxy060608 已提交
37
  return {
fxy060608's avatar
fxy060608 已提交
38
    name: 'uni:mp-using-component',
39
    enforce: 'post',
fxy060608's avatar
fxy060608 已提交
40 41 42
    configResolved(config) {
      resolvedConfig = config
    },
fxy060608's avatar
fxy060608 已提交
43 44
    async transform(source, id) {
      const { filename, query } = parseVueRequest(id)
fxy060608's avatar
fxy060608 已提交
45 46 47
      if (filename.endsWith('App.vue')) {
        return null
      }
48
      const sourceMap = withSourcemap(resolvedConfig)
fxy060608's avatar
fxy060608 已提交
49 50 51 52 53
      const dynamicImportOptions = {
        id,
        sourceMap,
        dynamicImport,
      }
fxy060608's avatar
fxy060608 已提交
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
      const resolve = async (
        source: string,
        importer?: string,
        options?: {
          custom?: CustomPluginOptions
          isEntry?: boolean
          skipSelf?: boolean
        }
      ): Promise<ResolvedId | null> => {
        const id = resolveUtsModule(
          source,
          importer || process.env.UNI_INPUT_DIR,
          process.env.UNI_UTS_PLATFORM
        )
        if (id) {
          source = id
        }
        return this.resolve(source, importer, options)
      }
fxy060608's avatar
fxy060608 已提交
73
      if (query.vue) {
fxy060608's avatar
fxy060608 已提交
74 75 76 77 78 79 80
        if (query.type === 'script') {
          // 需要主动监听
          this.addWatchFile(filename)
          const descriptor = await parseScriptDescriptor(
            filename,
            parseAst(source, id),
            {
fxy060608's avatar
fxy060608 已提交
81
              resolve,
fxy060608's avatar
fxy060608 已提交
82 83 84
              isExternal: true,
            }
          )
85 86 87 88 89
          updateMiniProgramComponentsByScriptFilename(
            filename,
            inputDir,
            normalizeComponentName
          )
fxy060608's avatar
fxy060608 已提交
90 91 92
          return transformDynamicImports(
            source,
            descriptor.imports,
fxy060608's avatar
fxy060608 已提交
93
            dynamicImportOptions
fxy060608's avatar
fxy060608 已提交
94 95 96 97 98 99 100 101
          )
        } else if (query.type === 'template') {
          // 需要主动监听
          this.addWatchFile(filename)
          const descriptor = await parseTemplateDescriptor(
            filename,
            parseAst(source, id),
            {
fxy060608's avatar
fxy060608 已提交
102
              resolve,
fxy060608's avatar
fxy060608 已提交
103 104 105
              isExternal: true,
            }
          )
106 107 108 109 110
          updateMiniProgramComponentsByTemplateFilename(
            filename,
            inputDir,
            normalizeComponentName
          )
fxy060608's avatar
fxy060608 已提交
111 112 113
          return transformDynamicImports(
            source,
            descriptor.imports,
fxy060608's avatar
fxy060608 已提交
114
            dynamicImportOptions
fxy060608's avatar
fxy060608 已提交
115 116
          )
        }
fxy060608's avatar
fxy060608 已提交
117 118 119 120 121 122
        return null
      }
      if (!EXTNAME_VUE.includes(path.extname(filename))) {
        return null
      }

fxy060608's avatar
fxy060608 已提交
123
      const ast = parseAst(source, id)
fxy060608's avatar
fxy060608 已提交
124

fxy060608's avatar
fxy060608 已提交
125
      const descriptor = await parseMainDescriptor(filename, ast, resolve)
fxy060608's avatar
fxy060608 已提交
126

127 128 129 130 131
      updateMiniProgramComponentsByMainFilename(
        filename,
        inputDir,
        normalizeComponentName
      )
fxy060608's avatar
fxy060608 已提交
132

fxy060608's avatar
fxy060608 已提交
133 134 135 136 137
      return transformDynamicImports(
        source,
        descriptor.imports,
        dynamicImportOptions
      )
fxy060608's avatar
fxy060608 已提交
138 139 140 141
    },
  }
}

fxy060608's avatar
fxy060608 已提交
142
export function dynamicImport(name: string, value: string) {
fxy060608's avatar
fxy060608 已提交
143
  // 开发者可能将页面作为组件来引用
fxy060608's avatar
fxy060608 已提交
144
  if (isMiniProgramPageFile(value)) {
fxy060608's avatar
fxy060608 已提交
145 146
    return `const ${name} = ()=>import('${virtualPagePath(value)}')`
  }
fxy060608's avatar
fxy060608 已提交
147 148
  return `const ${name} = ()=>import('${virtualComponentPath(value)}')`
}