@mpxjs/webpack-plugin
Version:
mpx compile core
118 lines (115 loc) • 4.66 kB
JavaScript
const RecordGlobalComponentsDependency = require('../dependencies/RecordGlobalComponentsDependency')
const JSON5 = require('json5')
const isUrlRequest = require('./is-url-request')
const parseRequest = require('./parse-request')
const addQuery = require('./add-query')
const resolve = require('./resolve')
const getJSONContent = require('./get-json-content')
const getRulesRunner = require('../platform')
const { matchCondition } = require('./match-condition')
const async = require('async')
module.exports = function ({
json,
srcMode,
emitWarning,
emitError,
ctorType,
resourcePath,
loaderContext
}, callback) {
const mpx = loaderContext.getMpx()
const context = loaderContext.context
const { mode, pagesMap, autoVirtualHostRules } = mpx
async.waterfall([
(callback) => {
getJSONContent(json, null, loaderContext, callback)
},
(jsonContent, callback) => {
if (!jsonContent) return callback(null, {})
let componentPlaceholder = []
let componentGenerics = {}
const usingComponentsInfo = {}
const usingComponents = {}
const finalCallback = (err) => {
if (err) return callback(err)
if (ctorType === 'app') {
// 在 rulesRunner 运行后保存全局注册组件
// todo 其余地方在使用mpx.globalComponents时存在缓存问题,要规避该问题需要在所有使用mpx.globalComponents的loader中添加app resourcePath作为fileDependency,但对于缓存有效率影响巨大
// todo 需要考虑一种精准控制缓存的方式,仅在全局组件发生变更时才使相关使用方的缓存失效,例如按需在相关模块上动态添加request query?
loaderContext._module.addPresentationalDependency(new RecordGlobalComponentsDependency(usingComponents, usingComponentsInfo, context))
}
callback(null, {
componentPlaceholder,
componentGenerics,
usingComponentsInfo: Object.assign({}, usingComponentsInfo, mpx.globalComponentsInfo),
jsonContent
})
}
try {
const ret = JSON5.parse(jsonContent)
const rulesMeta = {}
const rulesRunnerOptions = {
mode,
srcMode,
type: 'json',
waterfall: true,
warn: emitWarning,
error: emitError,
meta: rulesMeta
}
if (ctorType !== 'app') {
rulesRunnerOptions.mainKey = pagesMap[resourcePath] ? 'page' : 'component'
}
const rulesRunner = getRulesRunner(rulesRunnerOptions)
try {
if (rulesRunner) rulesRunner(ret)
} catch (e) {
return finalCallback(e)
}
// 不支持全局组件的平台,runRules 时会删除 app.json 中的 usingComponents, 同时 fillGlobalComponents 方法会对 rulesMeta 赋值 usingComponents,通过 rulesMeta 来重新获取 globalComponents
// page | component 时 直接获取 ret.usingComponents 内容
Object.assign(usingComponents, ret.usingComponents || rulesMeta.usingComponents)
if (ret.componentPlaceholder) {
componentPlaceholder = componentPlaceholder.concat(Object.values(ret.componentPlaceholder))
}
if (ret.componentGenerics) {
componentGenerics = Object.assign({}, ret.componentGenerics)
}
if (usingComponents) {
const setUsingComponentInfo = (name, info) => {
usingComponentsInfo[name] = info
}
async.eachOf(usingComponents, (component, name, callback) => {
if (ctorType === 'app') {
usingComponents[name] = addQuery(component, {
context
})
}
if (!isUrlRequest(component)) {
const moduleId = mpx.getModuleId(component, ctorType === 'app')
setUsingComponentInfo(name, moduleId)
return callback()
}
resolve(context, component, loaderContext, (err, resource) => {
if (err) return callback(err)
const { rawResourcePath } = parseRequest(resource)
const moduleId = mpx.getModuleId(rawResourcePath, ctorType === 'app')
const hasVirtualHost = matchCondition(rawResourcePath, autoVirtualHostRules)
setUsingComponentInfo(name, {
mid: moduleId,
hasVirtualHost
})
callback()
})
}, (err) => {
finalCallback(err)
})
} else {
finalCallback()
}
} catch (err) {
finalCallback(err)
}
}
], callback)
}