auto-components.js 3.0 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1 2
const path = require('path')

fxy060608's avatar
fxy060608 已提交
3
const {
4
  hyphenate,
fxy060608's avatar
fxy060608 已提交
5 6 7
  isComponent
} = require('./util')

fxy060608's avatar
fxy060608 已提交
8 9
const {
  removeExt
fxy060608's avatar
fxy060608 已提交
10
} = require('@dcloudio/uni-cli-shared/lib/util')
fxy060608's avatar
fxy060608 已提交
11 12 13

const {
  getAutoComponents
fxy060608's avatar
fxy060608 已提交
14
} = require('@dcloudio/uni-cli-shared/lib/pages')
fxy060608's avatar
fxy060608 已提交
15 16 17

const {
  updateUsingAutoImportComponents
fxy060608's avatar
fxy060608 已提交
18
} = require('@dcloudio/uni-cli-shared/lib/cache')
fxy060608's avatar
fxy060608 已提交
19 20 21 22 23

function formatSource (source) {
  if (source.indexOf('@/') === 0) { // 根目录
    source = source.replace('@/', '')
  } else { // node_modules
fxy060608's avatar
fxy060608 已提交
24 25 26 27 28
    if (process.env.UNI_PLATFORM === 'mp-alipay') {
      if (source.indexOf('@') === 0) {
        source = source.replace('@', 'npm-scope-')
      }
    }
fxy060608's avatar
fxy060608 已提交
29 30 31 32 33 34 35 36 37 38
    source = 'node-modules/' + source
  }
  return removeExt(source)
}

function getWebpackChunkName (source) {
  return formatSource(source)
}

function updateMPUsingAutoImportComponents (autoComponents, options) {
39 40 41
  if (!options.resourcePath) {
    return
  }
fxy060608's avatar
fxy060608 已提交
42
  const resourcePath = options.resourcePath.replace(path.extname(options.resourcePath), '')
X
xlfsummer 已提交
43
  if (resourcePath === 'App') {
44 45
    return
  }
fxy060608's avatar
fxy060608 已提交
46 47 48 49 50
  const usingAutoImportComponents = Object.create(null)
  autoComponents.forEach(({
    name,
    source
  }) => {
51 52
    // 自定义组件统一格式化为 kebab-case
    usingAutoImportComponents[hyphenate(name)] = '/' + formatSource(source)
fxy060608's avatar
fxy060608 已提交
53 54 55 56 57 58 59 60 61 62 63
  })
  updateUsingAutoImportComponents(resourcePath, usingAutoImportComponents) // 更新json
}

function generateAutoComponentsCode (autoComponents, dynamic = false) {
  const components = []
  autoComponents.forEach(({
    name,
    source
  }) => {
    if (dynamic) {
fxy060608's avatar
fxy060608 已提交
64
      components.push(`'${name}': function(){return import(/* webpackChunkName: "${getWebpackChunkName(source)}" */'${source}')}`)
fxy060608's avatar
fxy060608 已提交
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
    } else {
      components.push(`'${name}': require('${source}').default`)
    }
  })
  return `var components = {${components.join(',')}}`
}

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 = {
fxy060608's avatar
fxy060608 已提交
88
  preTransformNode (el, options) {
fxy060608's avatar
fxy060608 已提交
89 90 91 92
    if (process.env.UNI_PLATFORM === 'quickapp') {
      // 排查所有标签
      (options.isUnaryTag.autoComponents || (options.isUnaryTag.autoComponents = new Set())).add(el.tag)
    } else if (isComponent(el.tag) && el.tag !== 'App') { // App.vue
fxy060608's avatar
fxy060608 已提交
93 94
      // 挂在 isUnaryTag 上边,可以保证外部访问到
      (options.isUnaryTag.autoComponents || (options.isUnaryTag.autoComponents = new Set())).add(el.tag)
fxy060608's avatar
fxy060608 已提交
95 96
    }
  }
fxy060608's avatar
fxy060608 已提交
97 98 99 100
}
module.exports = {
  compileTemplate,
  module: compilerModule
fxy060608's avatar
fxy060608 已提交
101
}