generate-component.js 6.8 KB
Newer Older
1
const fs = require('fs')
fxy060608's avatar
fxy060608 已提交
2
const path = require('path')
Q
qiang 已提交
3
const webpack = require('webpack')
fxy060608's avatar
fxy060608 已提交
4 5
const {
  removeExt,
Q
qiang 已提交
6
  normalizePath
fxy060608's avatar
fxy060608 已提交
7 8
} = require('@dcloudio/uni-cli-shared')
const {
9
  getComponentSet
fxy060608's avatar
fxy060608 已提交
10 11
} = require('@dcloudio/uni-cli-shared/lib/cache')

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

fxy060608's avatar
fxy060608 已提交
16
const {
Q
qiang 已提交
17 18 19
  restoreNodeModules,
  createSource,
  getModuleId
fxy060608's avatar
fxy060608 已提交
20 21
} = require('../shared')

fxy060608's avatar
fxy060608 已提交
22 23
const EMPTY_COMPONENT_LEN = 'Component({})'.length

fxy060608's avatar
fxy060608 已提交
24
const uniPath = normalizePath(require('@dcloudio/uni-cli-shared/lib/platform').getMPRuntimePath())
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

function findModule (modules, resource, altResource) {
  return modules.find(
    module => {
      let moduleResource = module.resource
      if (
        !moduleResource ||
        (
          moduleResource.indexOf('.vue') === -1 &&
          moduleResource.indexOf('.nvue') === -1
        )
      ) {
        return
      }
      moduleResource = removeExt(module.resource)
      return moduleResource === resource || moduleResource === altResource
    }
  )
}

Q
qiang 已提交
45
function findModuleId (compilation, modules, resource, altResource) {
46
  const module = findModule(modules, resource, altResource)
Q
qiang 已提交
47
  return module && getModuleId(compilation, module)
48 49
}

Q
qiang 已提交
50
function findModuleIdFromConcatenatedModules (compilation, modules, resource, altResource) {
51 52 53
  const module = modules.find(module => {
    return findModule(module.modules, resource, altResource)
  })
Q
qiang 已提交
54
  return module && getModuleId(compilation, module)
55 56
}

Q
qiang 已提交
57 58 59
function findComponentModuleId (compilation, modules, concatenatedModules, resource, altResource) {
  return findModuleId(compilation, modules, resource, altResource) ||
    findModuleIdFromConcatenatedModules(compilation, concatenatedModules, resource, altResource) ||
60 61 62
    resource
}

63
let lastComponents = []
fxy060608's avatar
fxy060608 已提交
64
// TODO 解决方案不太理想
fxy060608's avatar
fxy060608 已提交
65
module.exports = function generateComponent (compilation, jsonpFunction = 'webpackJsonp') {
66
  const curComponents = []
67
  const componentChunkNameMap = {}
fxy060608's avatar
fxy060608 已提交
68 69
  const components = getComponentSet()
  if (components.size) {
Q
qiang 已提交
70
    const modules = Array.from(compilation.modules)
fxy060608's avatar
fxy060608 已提交
71

72
    const concatenatedModules = modules.filter(module => module.modules)
Q
qiang 已提交
73 74 75 76
    let uniModule = modules.find(module => module.resource && normalizePath(module.resource) === uniPath)
    if (!uniModule && webpack.version[0] > 4) {
      uniModule = modules.find(module => module.rootModule && module.rootModule.resource && normalizePath(module.rootModule.resource) === uniPath)
    }
Q
qiang 已提交
77
    const uniModuleId = getModuleId(compilation, uniModule)
78
    const vueOuterComponentSting = 'vueOuterComponents'
fxy060608's avatar
fxy060608 已提交
79

Q
qiang 已提交
80 81
    compilation.getAssets().forEach(asset => {
      const name = asset.name
82 83 84 85 86
      // 判断是不是vue
      const isVueComponent = components.has(name.replace('.js', ''))
      // 独立分包外面的组件,复制到独立分包内,在components中看不到,所以需要单独处理
      const isVueOuterComponent = Boolean(name.endsWith('.js') && name.indexOf(vueOuterComponentSting) >= 0)
      if (isVueComponent || isVueOuterComponent) {
87
        curComponents.push(name.replace('.js', ''))
fxy060608's avatar
fxy060608 已提交
88

Q
qiang 已提交
89
        if (asset.source.__$wrappered) {
fxy060608's avatar
fxy060608 已提交
90 91 92
          return
        }

fxy060608's avatar
fxy060608 已提交
93 94 95 96 97
        const chunkName = name.replace('.js', '-create-component')

        let moduleId = ''
        if (name.indexOf('node-modules') === 0) {
          const modulePath = removeExt(restoreNodeModules(name))
fxy060608's avatar
fxy060608 已提交
98
          let resource = normalizePath(path.resolve(process.env.UNI_INPUT_DIR, '..', modulePath))
fxy060608's avatar
fxy060608 已提交
99
          const altResource = normalizePath(path.resolve(process.env.UNI_INPUT_DIR, modulePath))
fxy060608's avatar
fxy060608 已提交
100

Q
qiang 已提交
101
          if (modulePath.includes('@dcloudio') && isBuiltInComponentPath(modulePath)) {
fxy060608's avatar
fxy060608 已提交
102 103 104
            resource = normalizePath(path.resolve(process.env.UNI_CLI_CONTEXT, modulePath))
          }

Q
qiang 已提交
105
          moduleId = findComponentModuleId(compilation, modules, concatenatedModules, resource, altResource)
fxy060608's avatar
fxy060608 已提交
106 107
        } else {
          const resource = removeExt(path.resolve(process.env.UNI_INPUT_DIR, name))
Q
qiang 已提交
108
          moduleId = findComponentModuleId(compilation, modules, concatenatedModules, resource)
fxy060608's avatar
fxy060608 已提交
109 110
        }

Q
qiang 已提交
111
        const origSource = asset.source.source()
S
songyu 已提交
112

113 114 115
        if (isVueComponent) {
          componentChunkNameMap[name] = moduleId
        } else if (isVueOuterComponent) {
S
songyu 已提交
116
          const startIndex = name.indexOf(vueOuterComponentSting) + vueOuterComponentSting.length + 1
117 118 119 120
          const rightOriginalComponentName = name.substring(startIndex)
          moduleId = componentChunkNameMap[rightOriginalComponentName]
        }

fxy060608's avatar
fxy060608 已提交
121
        if (origSource.length !== EMPTY_COMPONENT_LEN) { // 不是空组件
fxy060608's avatar
fxy060608 已提交
122 123 124 125 126 127
          const globalVar = process.env.UNI_PLATFORM === 'mp-alipay' ? 'my' : 'global'
          // 主要是为了解决支付宝旧版本, Component 方法只在组件 js 里有,需要挂在 my.defineComponent
          let beforeCode = ''
          if (process.env.UNI_PLATFORM === 'mp-alipay') {
            beforeCode = ';my.defineComponent || (my.defineComponent = Component);'
          }
Q
qiang 已提交
128 129 130 131 132 133 134 135 136 137 138
          const source = beforeCode + origSource + (webpack.version[0] > 4
            ? `
;(${globalVar}["${jsonpFunction}"] = ${globalVar}["${jsonpFunction}"] || []).push([
    ['${chunkName}'],
    {},
    function(__webpack_require__){
      __webpack_require__('${uniModuleId}')['createComponent'](__webpack_require__(${JSON.stringify(moduleId)}))
    }
]);
`
            : `
fxy060608's avatar
fxy060608 已提交
139
;(${globalVar}["${jsonpFunction}"] = ${globalVar}["${jsonpFunction}"] || []).push([
fxy060608's avatar
fxy060608 已提交
140 141 142
    '${chunkName}',
    {
        '${chunkName}':(function(module, exports, __webpack_require__){
fxy060608's avatar
fxy060608 已提交
143
            __webpack_require__('${uniModuleId}')['createComponent'](__webpack_require__(${JSON.stringify(moduleId)}))
fxy060608's avatar
fxy060608 已提交
144 145 146
        })
    },
    [['${chunkName}']]
147
]);
fxy060608's avatar
fxy060608 已提交
148
`
Q
qiang 已提交
149
          )
Q
qiang 已提交
150 151 152
          const newSource = createSource(source)
          newSource.__$wrappered = true
          compilation.updateAsset(name, newSource)
153 154
        }
      }
fxy060608's avatar
fxy060608 已提交
155 156
    })
  }
fxy060608's avatar
fxy060608 已提交
157
  if (process.env.UNI_FEATURE_OBSOLETE !== 'false') {
158 159 160
    if (lastComponents.length) {
      for (const name of lastComponents) {
        if (!curComponents.includes(name)) {
fxy060608's avatar
fxy060608 已提交
161
          removeUnusedComponent(name) // 组件被移除
162 163
        }
      }
fxy060608's avatar
fxy060608 已提交
164 165 166 167 168
    }
    for (const name of curComponents) {
      if (!lastComponents.includes(name)) {
        addComponent(name) // 新增组件
      }
169 170 171 172 173
    }
    lastComponents = curComponents
  }
}

fxy060608's avatar
fxy060608 已提交
174 175 176 177 178
function addComponent (name) {
  const bakJson = path.join(process.env.UNI_OUTPUT_DIR, name + '.bak.json')
  if (fs.existsSync(bakJson)) {
    try {
      fs.renameSync(bakJson, path.join(process.env.UNI_OUTPUT_DIR, name + '.json'))
179
    } catch (e) { }
fxy060608's avatar
fxy060608 已提交
180 181 182
  }
}

183 184
function removeUnusedComponent (name) {
  try {
185 186
    fs.renameSync(path.join(process.env.UNI_OUTPUT_DIR, name + '.json'), path.join(process.env.UNI_OUTPUT_DIR, name +
      '.bak.json'))
187 188
  } catch (e) { }
}