index.js 9.3 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 = {
41 42 43
  compile (source, options = {}) {
    options.modules.push(compilerModuleUniad)

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

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

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

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

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

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

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

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

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

    options.mp.scopeId = options.scopeId

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

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

    options.mp.filterModules = Object.keys(options.filterModules || {})
fxy060608's avatar
fxy060608 已提交
122 123

    // (可用的原生微信小程序组件,global+scoped)
d-u-a's avatar
d-u-a 已提交
124 125 126 127
    options.mp.wxComponents = options.wxComponents || Object.create(null)
    Object.assign(options.mp.wxComponents, {
      'uniad-plugin': 'plugin://uni-ad/ad'
    })
fxy060608's avatar
fxy060608 已提交
128 129 130 131 132 133 134 135 136 137 138

    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}}`)
139 140 141 142 143 144 145 146 147 148 149 150
    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 已提交
151 152 153 154 155 156 157 158

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

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

    // resolve scoped slots
P
panyiming.325 已提交
159
    res.generic = state.generic || []
fxy060608's avatar
fxy060608 已提交
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
    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`)
    })

    /**
180 181 182 183 184 185
     * 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 已提交
186
    if (options.emitFile) {
fxy060608's avatar
fxy060608 已提交
187 188 189 190 191 192 193 194 195 196 197
      // 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 已提交
198 199 200
      if (options.updateSpecialMethods) {
        options.updateSpecialMethods(resourcePath, [...res.specialMethods])
      }
201 202
      const filterTemplate = []
      options.mp.filterModules.forEach(name => {
fxy060608's avatar
fxy060608 已提交
203 204
        const filterModule = options.filterModules[name]
        if (filterModule.type !== 'renderjs' && filterModule.attrs.lang !== 'renderjs') {
fxy060608's avatar
fxy060608 已提交
205 206 207 208 209 210 211 212 213 214
          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 已提交
215 216 217
          filterTemplate.push(
            options.mp.platform.createFilterTag(
              options.filterTagName,
fxy060608's avatar
fxy060608 已提交
218
              filterModule
fxy060608's avatar
fxy060608 已提交
219
            )
fxy060608's avatar
fxy060608 已提交
220
          )
fxy060608's avatar
fxy060608 已提交
221
        }
222
      })
fxy060608's avatar
fxy060608 已提交
223

fxy060608's avatar
fxy060608 已提交
224 225 226 227
      if (filterTemplate.length) {
        template = filterTemplate.join('\n') + '\n' + template
      }

fxy060608's avatar
fxy060608 已提交
228 229
      if (
        process.UNI_ENTRY[resourcePath] &&
230 231
        process.env.UNI_PLATFORM !== 'app-plus' &&
        process.env.UNI_PLATFORM !== 'h5'
fxy060608's avatar
fxy060608 已提交
232 233 234 235 236 237 238 239 240
      ) {
        // 检查是否启用 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' &&
241 242
                windowJson.navigationBarShadow &&
                windowJson.navigationBarShadow.colorType
fxy060608's avatar
fxy060608 已提交
243 244
            } else {
              colorType = windowJson.disableScroll &&
245 246
                windowJson.navigationBarShadow &&
                windowJson.navigationBarShadow.colorType
fxy060608's avatar
fxy060608 已提交
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
            }
          } 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 &&
271 272
        res.generic.length &&
        options.updateGenericComponents
fxy060608's avatar
fxy060608 已提交
273 274 275 276 277 278 279 280
      ) {
        options.updateGenericComponents(
          resourcePath,
          res.generic
        )
      }
      if (
        res.componentGenerics &&
281 282
        Object.keys(res.componentGenerics).length &&
        options.updateComponentGenerics
fxy060608's avatar
fxy060608 已提交
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
      ) {
        options.updateComponentGenerics(
          resourcePath,
          res.componentGenerics
        )
      }
    } else {
      res.template = template
    }
    return res
  },
  parseComponent,
  compileToFunctions,
  ssrCompile,
  ssrCompileToFunctions,
  generateCodeFrame
P
panyiming.325 已提交
299
}