@mpxjs/webpack-plugin
Version:
mpx compile core
229 lines (219 loc) • 9.16 kB
JavaScript
const loaderUtils = require('loader-utils')
const normalize = require('../utils/normalize')
const createHelpers = require('../helpers')
const tabBarContainerPath = normalize.lib('runtime/components/web/mpx-tab-bar-container.vue')
const tabBarPath = normalize.lib('runtime/components/web/mpx-tab-bar.vue')
const addQuery = require('../utils/add-query')
const parseRequest = require('../utils/parse-request')
const shallowStringify = require('../utils/shallow-stringify')
function stringifyRequest (loaderContext, request) {
return loaderUtils.stringifyRequest(loaderContext, request)
}
function getAsyncChunkName (chunkName) {
if (chunkName && typeof chunkName !== 'boolean') {
return `/* webpackChunkName: "${chunkName}/index" */`
}
return ''
}
function buildComponentsMap ({ localComponentsMap, builtInComponentsMap, loaderContext, jsonConfig }) {
const componentsMap = {}
if (localComponentsMap) {
Object.keys(localComponentsMap).forEach((componentName) => {
const componentCfg = localComponentsMap[componentName]
const componentRequest = stringifyRequest(loaderContext, componentCfg.resource)
if (componentCfg.async) {
// todo 暂时只处理局部注册的组件作为componentPlaceholder,暂不支持全局组件和原生组件,如使用了支持范围外的组件将不进行placeholder渲染及替换
if (jsonConfig.componentPlaceholder && jsonConfig.componentPlaceholder[componentName] && localComponentsMap[jsonConfig.componentPlaceholder[componentName]]) {
const placeholder = jsonConfig.componentPlaceholder[componentName]
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!`)
)
}
componentsMap[componentName] = `function(){return {component: import(${getAsyncChunkName(componentCfg.async)}${componentRequest}).then(function(res){return getComponent(res)}), loading: getComponent(require(${placeholderRequest}))}}`
} else {
componentsMap[componentName] = `function(){return import(${getAsyncChunkName(componentCfg.async)}${componentRequest}).then(function(res){return getComponent(res)})}`
}
} else {
componentsMap[componentName] = `getComponent(require(${componentRequest}))`
}
})
}
if (builtInComponentsMap) {
Object.keys(builtInComponentsMap).forEach((componentName) => {
const componentCfg = builtInComponentsMap[componentName]
const componentRequest = stringifyRequest(loaderContext, componentCfg.resource)
componentsMap[componentName] = `getComponent(require(${componentRequest}), {__mpxBuiltIn: true})`
})
}
return componentsMap
}
function buildPagesMap ({ localPagesMap, loaderContext, tabBar, tabBarMap, tabBarStr, jsonConfig }) {
let globalTabBar = ''
let firstPage = ''
const pagesMap = {}
const tabBarPagesMap = {}
if (tabBar && tabBarMap) {
// 挂载tabBar组件
const tabBarRequest = stringifyRequest(loaderContext, addQuery(tabBar.custom ? './custom-tab-bar/index' : tabBarPath, { isComponent: true }))
tabBarPagesMap['mpx-tab-bar'] = `getComponent(require(${tabBarRequest}))`
// 挂载tabBar页面
Object.keys(tabBarMap).forEach((pagePath) => {
const pageCfg = localPagesMap[pagePath]
if (pageCfg) {
const pageRequest = stringifyRequest(loaderContext, pageCfg.resource)
if (pageCfg.async) {
tabBarPagesMap[pagePath] = `function(){return import(${getAsyncChunkName(pageCfg.async)}${pageRequest}).then(function(res) {return getComponent(res, {__mpxPageRoute: ${JSON.stringify(pagePath)}})})}`
} else {
tabBarPagesMap[pagePath] = `getComponent(require(${pageRequest}), {__mpxPageRoute: ${JSON.stringify(pagePath)}})`
}
} else {
loaderContext.emitWarning(
new Error(`[json processor][${loaderContext.resource}]: TabBar page path ${pagePath} is not exist in local page map, please check!`)
)
}
})
}
if (tabBarStr && tabBarPagesMap) {
globalTabBar += `
global.__tabBar = ${tabBarStr}
Vue.observable(global.__tabBar)
// @ts-ignore
global.__tabBarPagesMap = ${shallowStringify(tabBarPagesMap)}\n`
}
Object.keys(localPagesMap).forEach((pagePath) => {
const pageCfg = localPagesMap[pagePath]
const pageRequest = stringifyRequest(loaderContext, pageCfg.resource)
if (tabBarMap && tabBarMap[pagePath]) {
pagesMap[pagePath] = `getComponent(require(${stringifyRequest(loaderContext, tabBarContainerPath)}), {__mpxBuiltIn: true})`
} else {
if (pageCfg.async) {
pagesMap[pagePath] = `function(){return import(${getAsyncChunkName(pageCfg.async)} ${pageRequest}).then(function(res){return getComponent(res, {__mpxPageRoute: ${JSON.stringify(pagePath)}})})}`
} else {
// 为了保持小程序中app->page->component的js执行顺序,所有的page和component都改为require引入
pagesMap[pagePath] = `getComponent(require(${pageRequest}), {__mpxPageRoute: ${JSON.stringify(pagePath)}})`
}
}
if (pagePath === jsonConfig.entryPagePath) {
firstPage = pagePath
}
if (!firstPage && pageCfg.isFirst) {
firstPage = pagePath
}
})
return {
pagesMap,
firstPage,
globalTabBar
}
}
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,
jsonConfig,
webConfig,
isMain,
globalTabBar,
hasApp
}) {
let content = ''
if (isMain) {
content += `
global.getApp = function () {}
global.getCurrentPages = function () {
if (!(typeof window !== 'undefined')) {
console.error('[Mpx runtime error]: Dangerous API! global.getCurrentPages is running in non browser environment, It may cause some problems, please use this method with caution')
}
var router = global.__mpxRouter
if (!router) return []
// @ts-ignore
return (router.lastStack || router.stack).map(function (item) {
var page
var vnode = item.vnode
if (vnode && vnode.componentInstance) {
page = vnode.tag.endsWith('mpx-tab-bar-container') ? vnode.componentInstance.$refs.tabBarPage : vnode.componentInstance
}
return page || { route: item.path.slice(1) }
})
}
global.__networkTimeout = ${JSON.stringify(jsonConfig.networkTimeout)}
global.__mpxGenericsMap = {}
global.__mpxOptionsMap = {}
global.__style = ${JSON.stringify(jsonConfig.style || 'v1')}
global.__mpxPageConfig = ${JSON.stringify(jsonConfig.window)}
global.__mpxTransRpxFn = ${webConfig.transRpxFn}\n`
if (globalTabBar) {
content += globalTabBar
}
} else {
if (!hasApp) {
content += ' global.__mpxGenericsMap = global.__mpxGenericsMap || {}\n'
content += ' global.__mpxOptionsMap = global.__mpxOptionsMap || {}\n'
content += ` global.__mpxTransRpxFn = ${webConfig.transRpxFn}\n`
}
content += ` global.currentModuleId = ${JSON.stringify(moduleId)}\n`
content += ` global.currentSrcMode = ${JSON.stringify(scriptSrcMode)}\n`
content += ` global.currentInject = ${JSON.stringify({ moduleId })}\n`
if (!isProduction) {
content += ` global.currentResource = ${JSON.stringify(loaderContext.resourcePath)}\n`
}
}
return content
}
function buildI18n ({ i18n, isMain, loaderContext }) {
let i18nContent = ''
const i18nObj = Object.assign({}, i18n)
if (!isMain) {
i18nContent += `import Vue from 'vue'
import Mpx from '@mpxjs/core'\n`
}
i18nContent += `import VueI18n from 'vue-i18n'
import { createI18n } from 'vue-i18n-bridge'
if (!Mpx.i18n) {
Vue.use(VueI18n , { bridge: true })\n`
const requestObj = {}
const i18nKeys = ['messages', 'dateTimeFormats', 'numberFormats']
i18nKeys.forEach((key) => {
if (i18nObj[`${key}Path`]) {
requestObj[key] = stringifyRequest(loaderContext, i18nObj[`${key}Path`])
delete i18nObj[`${key}Path`]
}
})
i18nContent += ` var i18nCfg = ${JSON.stringify(i18nObj)}\n`
Object.keys(requestObj).forEach((key) => {
i18nContent += ` i18nCfg.${key} = require(${requestObj[key]})\n`
})
i18nContent += `
i18nCfg.legacy = false
var i18n = createI18n(i18nCfg, VueI18n)
Vue.use(i18n)
Mpx.i18n = i18n
}\n`
return i18nContent
}
module.exports = {
buildPagesMap,
buildComponentsMap,
getRequireScript,
buildGlobalParams,
stringifyRequest,
buildI18n
}