index.js 9.2 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1
const path = require('path')
fxy060608's avatar
fxy060608 已提交
2
const hash = require('hash-sum')
fxy060608's avatar
fxy060608 已提交
3 4 5 6 7 8 9 10
const parser = require('@babel/parser')

const {
  parseComponent,
  compile,
  compileToFunctions,
  ssrCompile,
  ssrCompileToFunctions
fxy060608's avatar
fxy060608 已提交
11
} = require('@dcloudio/vue-cli-plugin-uni/packages/vue-template-compiler')
fxy060608's avatar
fxy060608 已提交
12 13 14 15 16 17

const traverseScript = require('./script/traverse')
const generateScript = require('./script/generate')
const traverseTemplate = require('./template/traverse')
const generateTemplate = require('./template/generate')

d-u-a's avatar
d-u-a 已提交
18
const compilerModule = require('./module')
d-u-a's avatar
d-u-a 已提交
19
const compilerModuleUniad = require('./module.uniad')
fxy060608's avatar
fxy060608 已提交
20

fxy060608's avatar
fxy060608 已提交
21
const compilerAlipayModule = require('./module-alipay')
22
const compilerToutiaoModule = require('./module-toutiao')
fxy060608's avatar
fxy060608 已提交
23

fxy060608's avatar
fxy060608 已提交
24 25
const generateCodeFrame = require('./codeframe')

fxy060608's avatar
fxy060608 已提交
26
const {
fxy060608's avatar
fxy060608 已提交
27
  isComponent,
fxy060608's avatar
fxy060608 已提交
28
  isUnaryTag
fxy060608's avatar
fxy060608 已提交
29 30
} = require('./util')

fxy060608's avatar
fxy060608 已提交
31 32 33 34
const {
  module: autoComponentsModule,
  compileTemplate
} = require('./auto-components')
fxy060608's avatar
fxy060608 已提交
35

fxy060608's avatar
fxy060608 已提交
36 37 38 39
const isWin = /^win/.test(process.platform)

const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path)

fxy060608's avatar
fxy060608 已提交
40
module.exports = {
fxy060608's avatar
fxy060608 已提交
41
  compile (source, options = {}) {
fxy060608's avatar
fxy060608 已提交
42 43 44 45 46 47
    if ( // 启用摇树优化后,需要过滤内置组件
      !options.autoComponentResourcePath ||
      options.autoComponentResourcePath.indexOf('@dcloudio/uni-h5/src') === -1
    ) {
      (options.modules || (options.modules = [])).push(autoComponentsModule)
    }
fxy060608's avatar
fxy060608 已提交
48 49 50
    if (!options.modules) {
      options.modules = []
    }
51
    // transformAssetUrls
fxy060608's avatar
fxy060608 已提交
52 53
    options.modules.push(require('./asset-url'))
    options.modules.push(require('./bool-attr'))
fxy060608's avatar
fxy060608 已提交
54

fxy060608's avatar
fxy060608 已提交
55 56 57 58
    options.isUnaryTag = isUnaryTag
    // 将 autoComponents 挂在 isUnaryTag 上边
    options.isUnaryTag.autoComponents = new Set()

fxy060608's avatar
fxy060608 已提交
59
    options.preserveWhitespace = false
fxy060608's avatar
init v3  
fxy060608 已提交
60
    if (options.service) {
fxy060608's avatar
fxy060608 已提交
61
      options.modules.push(require('./app/service'))
fxy060608's avatar
fxy060608 已提交
62
      options.optimize = false // 启用 staticRenderFns
fxy060608's avatar
init v3  
fxy060608 已提交
63 64
      // domProps => attrs
      options.mustUseProp = () => false
fxy060608's avatar
fxy060608 已提交
65 66 67
      options.isReservedTag = (tagName) => !isComponent(tagName) // 非组件均为内置
      options.getTagNamespace = () => false

68
      try {
fxy060608's avatar
fxy060608 已提交
69
        return compileTemplate(source, options, compile)
70
      } catch (e) {
fxy060608's avatar
fxy060608 已提交
71 72
        console.error(source)
        throw e
73
      }
fxy060608's avatar
init v3  
fxy060608 已提交
74
    } else if (options.view) {
fxy060608's avatar
fxy060608 已提交
75
      options.modules.push(require('./app/view'))
fxy060608's avatar
fxy060608 已提交
76
      options.optimize = false // 暂不启用 staticRenderFns
fxy060608's avatar
fxy060608 已提交
77
      options.isUnaryTag = isUnaryTag
fxy060608's avatar
fxy060608 已提交
78
      options.isReservedTag = (tagName) => false // 均为组件
79
      try {
fxy060608's avatar
fxy060608 已提交
80
        return compileTemplate(source, options, compile)
81
      } catch (e) {
fxy060608's avatar
fxy060608 已提交
82 83
        console.error(source)
        throw e
84
      }
fxy060608's avatar
fxy060608 已提交
85
    } else if (options['quickapp-native']) {
fxy060608's avatar
fxy060608 已提交
86
      // 后续改版,应统一由具体包实现
fxy060608's avatar
fxy060608 已提交
87
      options.modules.push(require('@dcloudio/uni-quickapp-native/lib/compiler-module'))
fxy060608's avatar
init v3  
fxy060608 已提交
88 89
    }

fxy060608's avatar
fxy060608 已提交
90
    if (!options.mp) { // h5,quickapp-native
fxy060608's avatar
fxy060608 已提交
91
      return compileTemplate(source, options, compile)
fxy060608's avatar
fxy060608 已提交
92 93
    }

d-u-a's avatar
d-u-a 已提交
94
    options.modules.push(compilerModule)
d-u-a's avatar
d-u-a 已提交
95
    options.modules.push(compilerModuleUniad)
fxy060608's avatar
fxy060608 已提交
96

fxy060608's avatar
fxy060608 已提交
97 98
    if (options.mp.platform === 'mp-alipay') {
      options.modules.push(compilerAlipayModule)
P
panyiming.325 已提交
99
    } else if (options.mp.platform === 'mp-toutiao' || options.mp.platform === 'mp-lark') {
100
      options.modules.push(compilerToutiaoModule)
fxy060608's avatar
fxy060608 已提交
101 102
    }

fxy060608's avatar
fxy060608 已提交
103
    const res = compileTemplate(source, Object.assign(options, {
fxy060608's avatar
fxy060608 已提交
104
      optimize: false
fxy060608's avatar
fxy060608 已提交
105
    }), compile)
fxy060608's avatar
fxy060608 已提交
106

fxy060608's avatar
fxy060608 已提交
107
    options.mp.platform = require('./mp')(options.mp.platform)
fxy060608's avatar
fxy060608 已提交
108 109 110 111

    options.mp.scopeId = options.scopeId

    options.mp.resourcePath = options.resourcePath
fxy060608's avatar
fxy060608 已提交
112 113 114 115 116
    if (options.resourcePath) {
      options.mp.hashId = hash(options.resourcePath)
    } else {
      options.mp.hashId = ''
    }
fxy060608's avatar
fxy060608 已提交
117 118

    options.mp.globalUsingComponents = options.globalUsingComponents || Object.create(null)
119 120

    options.mp.filterModules = Object.keys(options.filterModules || {})
fxy060608's avatar
fxy060608 已提交
121 122 123 124 125 126 127 128 129 130 131 132 133 134

    // (可用的原生微信小程序组件,global+scoped)
    options.mp.wxComponents = options.wxComponents || Object.create(null)

    const state = {
      ast: {},
      script: '',
      template: '',
      errors: new Set(),
      tips: new Set(),
      options: options.mp
    }
    // console.log(`function render(){${res.render}}`)
    const ast = parser.parse(`function render(){${res.render}}`)
135 136 137 138 139 140 141 142 143 144 145 146
    let template = ''

    try {
      res.render = generateScript(traverseScript(ast, state), state)
      template = generateTemplate(traverseTemplate(ast, state), state)
    } catch (e) {
      console.error(e)
      throw new Error('Compile failed at ' + options.resourcePath.replace(
        path.extname(options.resourcePath),
        '.vue'
      ))
    }
fxy060608's avatar
fxy060608 已提交
147 148 149 150 151 152 153 154

    res.specialMethods = state.options.specialMethods || new Set()
    delete state.options.specialMethods

    res.files = state.files || {}
    delete state.files

    // resolve scoped slots
P
panyiming.325 已提交
155
    res.generic = state.generic || []
fxy060608's avatar
fxy060608 已提交
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
    delete state.generic

    // define scoped slots
    res.componentGenerics = state.componentGenerics || {}
    delete state.componentGenerics

    state.errors.forEach(msg => {
      res.errors.push({
        msg
      })
    })

    const resourcePath = options.resourcePath.replace(path.extname(options.resourcePath), '')

    state.tips.forEach(msg => {
      console.log(`提示:${msg}
at ${resourcePath}.vue:1`)
    })

    /**
176 177 178 179 180 181
     * TODO
     * 方案0.最佳方案是在 loader 中直接 emitFile,但目前 vue template-loader 不好介入,自定义的 compiler 结果又无法顺利返回给 loader
     * 方案1.通过 loader 传递 emitFile 来提交生成 wxml,需要一个 template loader 来给自定义 compier 增加 emitFile
     * 方案2.缓存 wxml 内容,由 plugin 生成 assets 来提交生成 wxml
     * ...暂时使用方案1
     */
fxy060608's avatar
fxy060608 已提交
182
    if (options.emitFile) {
fxy060608's avatar
fxy060608 已提交
183 184 185 186 187 188 189 190 191 192 193
      // cache
      if (process.env.UNI_USING_CACHE) {
        const oldEmitFile = options.emitFile
        process.UNI_CACHE_TEMPLATES = {}
        options.emitFile = function emitFile (name, content) {
          const absolutePath = path.resolve(process.env.UNI_OUTPUT_DIR, name)
          process.UNI_CACHE_TEMPLATES[absolutePath] = content
          oldEmitFile(name, content)
        }
      }

fxy060608's avatar
fxy060608 已提交
194 195 196
      if (options.updateSpecialMethods) {
        options.updateSpecialMethods(resourcePath, [...res.specialMethods])
      }
197 198
      const filterTemplate = []
      options.mp.filterModules.forEach(name => {
fxy060608's avatar
fxy060608 已提交
199 200
        const filterModule = options.filterModules[name]
        if (filterModule.type !== 'renderjs' && filterModule.attrs.lang !== 'renderjs') {
fxy060608's avatar
fxy060608 已提交
201 202 203 204 205 206 207 208 209 210
          if (
            filterModule.attrs &&
            filterModule.attrs.src &&
            filterModule.attrs.src.indexOf('@/') === 0
          ) {
            const src = filterModule.attrs.src
            filterModule.attrs.src = normalizePath(path.relative(
              path.dirname(resourcePath), src.replace('@/', '')
            ))
          }
fxy060608's avatar
fxy060608 已提交
211 212 213
          filterTemplate.push(
            options.mp.platform.createFilterTag(
              options.filterTagName,
fxy060608's avatar
fxy060608 已提交
214
              filterModule
fxy060608's avatar
fxy060608 已提交
215
            )
fxy060608's avatar
fxy060608 已提交
216
          )
fxy060608's avatar
fxy060608 已提交
217
        }
218
      })
fxy060608's avatar
fxy060608 已提交
219

fxy060608's avatar
fxy060608 已提交
220 221 222 223
      if (filterTemplate.length) {
        template = filterTemplate.join('\n') + '\n' + template
      }

fxy060608's avatar
fxy060608 已提交
224 225
      if (
        process.UNI_ENTRY[resourcePath] &&
226 227
        process.env.UNI_PLATFORM !== 'app-plus' &&
        process.env.UNI_PLATFORM !== 'h5'
fxy060608's avatar
fxy060608 已提交
228 229 230 231 232 233 234 235 236
      ) {
        // 检查是否启用 shadow
        let colorType = false
        const pageJsonStr = options.getJsonFile(resourcePath)
        if (pageJsonStr) {
          try {
            const windowJson = JSON.parse(pageJsonStr)
            if (process.env.UNI_PLATFORM === 'mp-alipay') {
              colorType = windowJson.allowsBounceVertical === 'NO' &&
237 238
                windowJson.navigationBarShadow &&
                windowJson.navigationBarShadow.colorType
fxy060608's avatar
fxy060608 已提交
239 240
            } else {
              colorType = windowJson.disableScroll &&
241 242
                windowJson.navigationBarShadow &&
                windowJson.navigationBarShadow.colorType
fxy060608's avatar
fxy060608 已提交
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
            }
          } catch (e) {}
        }
        if (colorType) {
          template = options.getShadowTemplate(colorType) + template
        }
      }

      options.emitFile(options.resourcePath, template)
      if (res.files) {
        Object.keys(res.files).forEach(name => {
          options.emitFile(name, res.files[name])
        })
      }

      if (state.options.usingGlobalComponents) {
        options.updateUsingGlobalComponents(
          resourcePath,
          state.options.usingGlobalComponents
        )
      }

      if (
        res.generic &&
267 268
        res.generic.length &&
        options.updateGenericComponents
fxy060608's avatar
fxy060608 已提交
269 270 271 272 273 274 275 276
      ) {
        options.updateGenericComponents(
          resourcePath,
          res.generic
        )
      }
      if (
        res.componentGenerics &&
277 278
        Object.keys(res.componentGenerics).length &&
        options.updateComponentGenerics
fxy060608's avatar
fxy060608 已提交
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
      ) {
        options.updateComponentGenerics(
          resourcePath,
          res.componentGenerics
        )
      }
    } else {
      res.template = template
    }
    return res
  },
  parseComponent,
  compileToFunctions,
  ssrCompile,
  ssrCompileToFunctions,
  generateCodeFrame
P
panyiming.325 已提交
295
}