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)
|
})
|
}
|
}
|