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
      const resolve = async (
        source: string,
        importer?: string,
        options?: {
          custom?: CustomPluginOptions
          isEntry?: boolean
          skipSelf?: boolean
        }
      ): Promise<ResolvedId | null> => {
        const id = resolveUtsModule(
          source,
fxy060608's avatar
fxy060608 已提交
65
          importer || process.env.UNI_INPUT_DIR
fxy060608's avatar
fxy060608 已提交
66 67 68 69 70 71
        )
        if (id) {
          source = id
        }
        return this.resolve(source, importer, options)
      }
fxy060608's avatar
fxy060608 已提交
72
      if (query.vue) {
fxy060608's avatar
fxy060608 已提交
73 74 75 76 77 78 79
        if (query.type === 'script') {
          // 需要主动监听
          this.addWatchFile(filename)
          const descriptor = await parseScriptDescriptor(
            filename,
            parseAst(source, id),
            {
fxy060608's avatar
fxy060608 已提交
80
              resolve,
fxy060608's avatar
fxy060608 已提交
81 82 83
              isExternal: true,
            }
          )
84 85 86 87 88
          updateMiniProgramComponentsByScriptFilename(
            filename,
            inputDir,
            normalizeComponentName
          )
fxy060608's avatar
fxy060608 已提交
89 90 91
          return transformDynamicImports(
            source,
            descriptor.imports,
fxy060608's avatar
fxy060608 已提交
92
            dynamicImportOptions
fxy060608's avatar
fxy060608 已提交
93 94 95 96 97 98 99 100
          )
        } else if (query.type === 'template') {
          // 需要主动监听
          this.addWatchFile(filename)
          const descriptor = await parseTemplateDescriptor(
            filename,
            parseAst(source, id),
            {
fxy060608's avatar
fxy060608 已提交
101
              resolve,
fxy060608's avatar
fxy060608 已提交
102 103 104
              isExternal: true,
            }
          )
105 106 107 108 109
          updateMiniProgramComponentsByTemplateFilename(
            filename,
            inputDir,
            normalizeComponentName
          )
fxy060608's avatar
fxy060608 已提交
110 111 112
          return transformDynamicImports(
            source,
            descriptor.imports,
fxy060608's avatar
fxy060608 已提交
113
            dynamicImportOptions
fxy060608's avatar
fxy060608 已提交
114 115
          )
        }
fxy060608's avatar
fxy060608 已提交
116 117 118 119 120 121
        return null
      }
      if (!EXTNAME_VUE.includes(path.extname(filename))) {
        return null
      }

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

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

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

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

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