'f'
mh-two-thousand-and-two
2024-04-12 26f2711ef9461961fb953e2b497bd314ef95e345
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
const fs = require('fs')
const path = require('path')
 
const loaderUtils = require('loader-utils')
 
const parser = require('@babel/parser')
 
const {
  removeExt,
  hyphenate,
  normalizePath,
  getComponentName,
  jsPreprocessOptions
} = require('@dcloudio/uni-cli-shared')
 
const {
  getBabelParserOptions
} = require('@dcloudio/uni-cli-shared/lib/platform')
 
const {
  updateUsingComponents
} = require('@dcloudio/uni-cli-shared/lib/cache')
 
const preprocessor = require('@dcloudio/vue-cli-plugin-uni/packages/webpack-preprocess-loader/preprocess')
 
const {
  resolve,
  normalizeNodeModules
} = require('./shared')
 
const {
  findBabelLoader,
  addDynamicImport
} = require('./babel/util')
 
const traverse = require('./babel/global-component-traverse')
 
const babelPluginCreateApp = require.resolve('./babel/plugin-create-app')
 
const uniI18n = require('@dcloudio/uni-cli-i18n')
 
function addCreateApp (babelLoader) {
  babelLoader.options = babelLoader.options || {}
  if (!babelLoader.options.plugins) {
    babelLoader.options.plugins = []
  }
  babelLoader.options.plugins.push([babelPluginCreateApp])
}
 
module.exports = function (content, map) {
  this.cacheable && this.cacheable()
 
  if (this.resourceQuery) {
    const params = loaderUtils.parseQuery(this.resourceQuery)
    if (params && params.page) {
      params.page = decodeURIComponent(params.page)
      // import Vue from 'vue'是为了触发 vendor 合并
      let ext = '.vue'
      // nvue 跨平台编译,理论上不需要这么麻烦,直接不指定后缀即可,但可能开发者有同名 js 文件,导致引用错误
      if (process.env.UNI_USING_NVUE_COMPILER) {
        const vuePagePath = path.resolve(process.env.UNI_INPUT_DIR, normalizePath(params.page) + '.vue')
        if (!fs.existsSync(vuePagePath)) {
          const nvuePagePath = path.resolve(process.env.UNI_INPUT_DIR, normalizePath(params.page) +
            '.nvue')
          if (fs.existsSync(nvuePagePath)) {
            ext = '.nvue'
          }
        }
      }
      return this.callback(null,
        `
import Vue from 'vue'
import Page from './${normalizePath(params.page)}${ext}'
createPage(Page)
`, map)
    }
  } else {
    content = preprocessor.preprocess(content, jsPreprocessOptions.context, {
      type: jsPreprocessOptions.type
    })
 
    if (process.env.UNI_USING_VUE3) {
      if (content.indexOf('createSSRApp') !== -1) {
        content = content + ';createApp().app.mount(\'#app\');'
      }
    }
 
    const resourcePath = 'app'
 
    const {
      state: {
        components
      }
    } = traverse(parser.parse(content, getBabelParserOptions()), {
      filename: this.resourcePath,
      components: []
    })
 
    let babelLoader = findBabelLoader(this.loaders)
    if (!babelLoader) {
      throw new Error(uniI18n.__('mpLoader.findFail', {
        0: 'babel-loader'
      }))
    } else {
      const webpack = require('webpack')
      if (webpack.version[0] > 4) {
        // clone babelLoader and options
        const index = this.loaders.indexOf(babelLoader)
        const newBabelLoader = Object.assign({}, babelLoader)
        Object.assign(newBabelLoader, { options: Object.assign({}, babelLoader.options) })
        this.loaders.splice(index, 1, newBabelLoader)
        babelLoader = newBabelLoader
      }
      addCreateApp(babelLoader)
    }
 
    if (!components.length) {
      // 防止组件从有到无
      updateUsingComponents(resourcePath, Object.create(null), 'App')
      return this.callback(null, content, map)
    }
 
    const callback = this.async()
 
    const dynamicImports = Object.create(null)
 
    Promise.all(components.map(component => {
      return resolve.call(this, component.source).then(resolved => {
        component.name = getComponentName(hyphenate(component.name))
        const source = component.source
        component.source = normalizeNodeModules(removeExt(path.relative(process.env.UNI_INPUT_DIR,
          resolved)))
        // 非页面组件才需要 dynamic import
        if (!process.UNI_ENTRY[component.source]) {
          dynamicImports[source] = {
            identifier: component.value,
            chunkName: component.source,
            source
          }
        }
      })
    })).then(() => {
      const usingComponents = Object.create(null)
      components.forEach(({
        name,
        source
      }) => {
        usingComponents[name] = `/${source}`
      })
 
      addDynamicImport(babelLoader, resourcePath, dynamicImports)
 
      updateUsingComponents(resourcePath, usingComponents, 'App')
      callback(null, content, map)
    }, err => {
      callback(err, content, map)
    })
  }
}