@mpxjs/webpack-plugin
Version:
mpx compile core
225 lines (209 loc) • 8.69 kB
JavaScript
const loaderUtils = require('loader-utils')
const createHelpers = require('../helpers')
const parseRequest = require('../utils/parse-request')
const shallowStringify = require('../utils/shallow-stringify')
const normalize = require('../utils/normalize')
const addQuery = require('../utils/add-query')
const { isBuildInReactTag } = require('../utils/dom-tag-config')
function stringifyRequest (loaderContext, request) {
return loaderUtils.stringifyRequest(loaderContext, request)
}
function getBuiltInComponentRequest (component) {
return JSON.stringify(addQuery(`@mpxjs/webpack-plugin/lib/runtime/components/react/dist/${component}`, { isComponent: true }))
}
function getAsyncChunkName (chunkName) {
if (chunkName && typeof chunkName !== 'boolean') {
return `/* webpackChunkName: "${chunkName}/index" */`
}
return ''
}
function getAsyncSuspense (type, moduleId, componentRequest, componentName, chunkName, getFallback, getLoading) {
return `getAsyncSuspense({
type: ${JSON.stringify(type)},
moduleId: ${JSON.stringify(moduleId)},
chunkName: ${JSON.stringify(chunkName)},
getFallback: ${getFallback},
getLoading: ${getLoading},
getChildren () {
return import(${getAsyncChunkName(chunkName)}${componentRequest}).then(function (res) {
return getComponent(res, {displayName: ${JSON.stringify(componentName)}})
})
}
})`
}
function getComponent (componentRequest, componentName) {
return `getComponent(require(${componentRequest}), {displayName: ${JSON.stringify(componentName)}})`
}
function getBuiltInComponent (componentRequest) {
return `getComponent(require(${componentRequest}), {__mpxBuiltIn: true})`
}
// function getLazyPage (componentRequest) {
// return `getLazyPage(${getComponentGetter(getComponent(componentRequest, 'Page'))})`
// }
function getComponentGetter (component) {
return `function(){ return ${component} }`
}
function buildPagesMap ({ localPagesMap, loaderContext, jsonConfig, rnConfig }) {
let firstPage = ''
const pagesMap = {}
const mpx = loaderContext.getMpx()
Object.keys(localPagesMap).forEach((pagePath) => {
const pageCfg = localPagesMap[pagePath]
const pageRequest = stringifyRequest(loaderContext, pageCfg.resource)
if (pageCfg.async) {
const moduleId = mpx.getModuleId(pageCfg.resource)
const getFallback = rnConfig.asyncChunk && rnConfig.asyncChunk.fallback && getComponentGetter(getComponent(stringifyRequest(loaderContext, addQuery(rnConfig.asyncChunk.fallback, { isComponent: true })), 'PageFallback'))
const getLoading = rnConfig.asyncChunk && rnConfig.asyncChunk.loading && getComponentGetter(getComponent(stringifyRequest(loaderContext, addQuery(rnConfig.asyncChunk.loading, { isComponent: true })), 'PageLoading'))
pagesMap[pagePath] = getAsyncSuspense('page', moduleId, pageRequest, 'Page', pageCfg.async, getFallback, getLoading)
} else {
// 为了保持小程序中app->page->component的js执行顺序,所有的page和component都改为require引入
pagesMap[pagePath] = getComponentGetter(getComponent(pageRequest, 'Page'))
}
if (pagePath === jsonConfig.entryPagePath) {
firstPage = pagePath
}
if (!firstPage && pageCfg.isFirst) {
firstPage = pagePath
}
})
return {
pagesMap,
firstPage
}
}
function buildComponentsMap ({ localComponentsMap, builtInComponentsMap, loaderContext, jsonConfig }) {
const componentsMap = {}
const mpx = loaderContext.getMpx()
if (localComponentsMap) {
Object.keys(localComponentsMap).forEach((componentName) => {
const componentCfg = localComponentsMap[componentName]
const componentRequest = stringifyRequest(loaderContext, componentCfg.resource)
if (componentCfg.async) {
const moduleId = mpx.getModuleId(componentCfg.resource)
const placeholder = jsonConfig.componentPlaceholder && jsonConfig.componentPlaceholder[componentName]
let getFallback
if (placeholder) {
if (localComponentsMap[placeholder]) {
const placeholderCfg = localComponentsMap[placeholder]
const placeholderRequest = stringifyRequest(loaderContext, placeholderCfg.resource)
if (placeholderCfg.async) {
loaderContext.emitWarning(
new Error(`[json processor][${loaderContext.resource}]: componentPlaceholder ${placeholder} should not be a async component, please check!`)
)
}
getFallback = getComponentGetter(getComponent(placeholderRequest, placeholder))
} else {
const tag = `mpx-${placeholder}`
if (isBuildInReactTag(tag)) {
getFallback = getComponentGetter(getBuiltInComponent(getBuiltInComponentRequest(tag)))
} else {
loaderContext.emitError(
new Error(`[json processor][${loaderContext.resource}]: componentPlaceholder ${placeholder} is not built-in component, please check!`)
)
}
}
} else {
loaderContext.emitError(
new Error(`[json processor][${loaderContext.resource}]: ${componentName} has no componentPlaceholder, please check!`)
)
}
componentsMap[componentName] = getAsyncSuspense('component', moduleId, componentRequest, componentName, componentCfg.async, getFallback)
} else {
componentsMap[componentName] = getComponentGetter(getComponent(componentRequest, componentName))
}
})
}
if (builtInComponentsMap) {
Object.keys(builtInComponentsMap).forEach((componentName) => {
const componentCfg = builtInComponentsMap[componentName]
const componentRequest = stringifyRequest(loaderContext, componentCfg.resource)
componentsMap[componentName] = getComponentGetter(getBuiltInComponent(componentRequest))
})
}
return componentsMap
}
function getRequireScript ({ script, ctorType, loaderContext }) {
let content = '/** script content **/\n'
const { getRequire } = createHelpers(loaderContext)
const { resourcePath, queryObj } = parseRequest(loaderContext.resource)
const extraOptions = {
...script.src
? { ...queryObj, resourcePath }
: null,
ctorType,
lang: script.lang || 'js'
}
content += `${getRequire('script', script, extraOptions)}\n`
return content
}
function buildGlobalParams ({
moduleId,
scriptSrcMode,
loaderContext,
isProduction,
ctorType,
jsonConfig,
componentsMap,
pagesMap,
firstPage,
outputPath,
genericsInfo,
hasApp
}) {
let content = ''
if (ctorType === 'app') {
content += `
global.getApp = function () {}
global.getCurrentPages = function () { return [] }
global.__networkTimeout = ${JSON.stringify(jsonConfig.networkTimeout)}
global.__mpxGenericsMap = {}
global.__mpxOptionsMap = {}
global.__mpxPagesMap = {}
global.__style = ${JSON.stringify(jsonConfig.style || 'v1')}
global.__mpxPageConfig = ${JSON.stringify(jsonConfig.window)}
global.__appComponentsMap = ${shallowStringify(componentsMap)}
global.__preloadRule = ${JSON.stringify(jsonConfig.preloadRule)}
global.currentInject.pagesMap = ${shallowStringify(pagesMap)}
global.currentInject.firstPage = ${JSON.stringify(firstPage)}\n`
} else {
if (ctorType === 'page') {
const pageConfig = Object.assign({}, jsonConfig)
delete pageConfig.usingComponents
content += `global.currentInject.pageConfig = ${JSON.stringify(pageConfig)}\n`
}
content += `
var componentsMap = ${shallowStringify(componentsMap)}
global.currentInject.componentsMap = componentsMap\n`
if (genericsInfo) {
if (!hasApp) {
content += 'global.__mpxGenericsMap = global.__mpxGenericsMap || {}\n'
}
content += `
const genericHash = ${JSON.stringify(genericsInfo.hash)}\n
global.__mpxGenericsMap[genericHash] = componentsMap\n`
}
if (ctorType === 'component') {
content += `global.currentInject.componentPath = '/' + ${JSON.stringify(outputPath)}\n`
}
}
content += `global.currentModuleId = ${JSON.stringify(moduleId)}\n`
content += `global.currentSrcMode = ${JSON.stringify(scriptSrcMode)}\n`
if (!isProduction) {
content += `global.currentResource = ${JSON.stringify(loaderContext.resourcePath)}\n`
}
return content
}
function buildI18n ({ loaderContext }) {
const i18nWxsPath = normalize.lib('runtime/i18n.wxs')
const i18nWxsLoaderPath = normalize.lib('wxs/i18n-loader.js')
const i18nWxsRequest = i18nWxsLoaderPath + '!' + i18nWxsPath
return `require(${stringifyRequest(loaderContext, i18nWxsRequest)})\n`
}
module.exports = {
buildPagesMap,
buildComponentsMap,
getRequireScript,
buildGlobalParams,
stringifyRequest,
buildI18n
}