mh-two-thousand-and-two
2024-04-12 7fc6dbf547b8899d949b67cdec36b96a7d1701c7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
const path = require('path')
 
const {
  hyphenate,
  isComponent
} = require('./util')
 
const {
  removeExt
} = require('@dcloudio/uni-cli-shared/lib/util')
 
const {
  getAutoComponents
} = require('@dcloudio/uni-cli-shared/lib/pages')
 
const {
  updateUsingAutoImportComponents
} = require('@dcloudio/uni-cli-shared/lib/cache')
 
function formatSource (source) {
  if (source.indexOf('@/') === 0) { // 根目录
    source = source.replace('@/', '')
  } else { // node_modules
    if (process.env.UNI_PLATFORM === 'mp-alipay') {
      if (source.indexOf('@') === 0) {
        source = source.replace('@', 'npm-scope-')
      }
    }
    source = 'node-modules/' + source
  }
  return removeExt(source)
}
 
function getWebpackChunkName (source) {
  return formatSource(source)
}
 
function updateMPUsingAutoImportComponents (autoComponents, options) {
  if (!options.resourcePath) {
    return
  }
  const resourcePath = options.resourcePath.replace(path.extname(options.resourcePath), '')
  if (resourcePath === 'App') {
    return
  }
  const usingAutoImportComponents = Object.create(null)
  autoComponents.forEach(({
    name,
    source
  }) => {
    // 自定义组件统一格式化为 kebab-case
    usingAutoImportComponents[hyphenate(name)] = '/' + formatSource(source)
  })
  updateUsingAutoImportComponents(resourcePath, usingAutoImportComponents) // 更新json
}
 
function generateAutoComponentsCode (autoComponents, dynamic = false) {
  const components = []
  autoComponents.forEach(({
    name,
    source
  }) => {
    // 统一转换为驼峰命名
    name = name.replace(/-(\w)/g, (_, str) => str.toUpperCase())
    if (dynamic) {
      components.push(
        `'${name}': function(){return import(/* webpackChunkName: "${getWebpackChunkName(source)}" */'${source}')}`
      )
    } else {
      components.push(`'${name}': require('${source}').default`)
    }
  })
  if (process.env.NODE_ENV === 'production') {
    return `var components = {${components.join(',')}}`
  }
  return `var components;
try{
  components = {${components.join(',')}}
}catch(e){
  if(e.message.indexOf('Cannot find module') !== -1 && e.message.indexOf('.vue') !== -1){
    console.error(e.message)
    console.error('1. 排查组件名称拼写是否正确')
    console.error('2. 排查组件是否符合 easycom 规范,文档:https://uniapp.dcloud.net.cn/collocation/pages?id=easycom')
    console.error('3. 若组件不符合 easycom 规范,需手动引入,并在 components 中注册该组件')
  } else {
    throw e
  }
}`
}
 
function compileTemplate (source, options, compile) {
  const res = compile(source, options)
  const autoComponents = getAutoComponents([...(options.isUnaryTag.autoComponents || [])])
  if (autoComponents.length) {
    // console.log('检测到的自定义组件:' + JSON.stringify(autoComponents))
    res.components = generateAutoComponentsCode(autoComponents, options.mp)
  } else {
    res.components = 'var components;'
  }
  if (options.mp) { // 小程序 更新 json 每次编译都要调整,保证热更新时增减组件一致
    updateMPUsingAutoImportComponents(autoComponents || [], options)
  }
  return res
}
 
const compilerModule = {
  preTransformNode (el, options) {
    if (el.tag === 'match-media' && process.env.UNI_PLATFORM !== 'mp-weixin') {
      el.tag = 'uni-match-media'
    }
    if (process.env.UNI_PLATFORM === 'quickapp-native') {
      // 排查所有标签
      (options.isUnaryTag.autoComponents || (options.isUnaryTag.autoComponents = new Set())).add(el.tag)
    } else if (isComponent(el.tag) && el.tag !== 'App') { // App.vue
      // 挂在 isUnaryTag 上边,可以保证外部访问到
      (options.isUnaryTag.autoComponents || (options.isUnaryTag.autoComponents = new Set())).add(el.tag)
    }
  }
}
module.exports = {
  compileTemplate,
  module: compilerModule
}