UNPKG

@mpxjs/webpack-plugin

Version:

mpx compile core

353 lines (325 loc) 11 kB
const async = require('async') const path = require('path') const JSON5 = require('json5') const loaderUtils = require('loader-utils') const parseRequest = require('../utils/parse-request') const toPosix = require('../utils/to-posix') const addQuery = require('../utils/add-query') const parseComponent = require('../parser') const getJSONContent = require('../utils/get-json-content') const resolve = require('../utils/resolve') const createJSONHelper = require('../json-compiler/helper') const getRulesRunner = require('../platform/index') const { RESOLVE_IGNORED_ERR } = require('../utils/const') const RecordResourceMapDependency = require('../dependencies/RecordResourceMapDependency') module.exports = function (jsonContent, { loaderContext, ctorType, pagesMap, componentsMap }, rawCallback) { const localPagesMap = {} const localComponentsMap = {} const output = '/* json */\n' let jsonObj = {} let tabBarMap let tabBarStr const mpx = loaderContext.getMpx() const { mode, srcMode, env, projectRoot } = mpx const context = loaderContext.context const emitWarning = (msg) => { loaderContext.emitWarning( new Error('[json processor][' + loaderContext.resource + ']: ' + msg) ) } const emitError = (msg) => { loaderContext.emitError( new Error('[json compiler][' + loaderContext.resource + ']: ' + msg) ) } const stringifyRequest = r => loaderUtils.stringifyRequest(loaderContext, r) const { isUrlRequest, urlToRequest, processPage, processComponent } = createJSONHelper({ loaderContext, emitWarning, emitError, customGetDynamicEntry (resource, type, outputPath, packageRoot) { return { resource, // 输出web时组件outputPath不需要拼接packageRoot outputPath: type === 'page' ? toPosix(path.join(packageRoot, outputPath)) : outputPath, packageRoot } } }) const callback = (err) => { return rawCallback(err, { output, jsonObj, localPagesMap, localComponentsMap, tabBarMap, tabBarStr }) } if (!jsonContent) { return callback() } try { jsonObj = JSON5.parse(jsonContent) // 处理runner const rulesRunnerOptions = { mode, srcMode, type: 'json', waterfall: true, warn: emitWarning, error: emitError, data: { // polyfill global usingComponents globalComponents: mpx.globalComponents } } if (ctorType !== 'app') { rulesRunnerOptions.mainKey = ctorType } const rulesRunner = getRulesRunner(rulesRunnerOptions) if (rulesRunner) { rulesRunner(jsonObj) } } catch (e) { return callback(e) } const fs = loaderContext._compiler.inputFileSystem const defaultTabbar = { borderStyle: 'black', position: 'bottom', custom: false, isShow: true } const processTabBar = (tabBar, callback) => { if (tabBar) { tabBar = Object.assign({}, defaultTabbar, tabBar) tabBarMap = {} jsonObj.tabBar.list.forEach(({ pagePath }) => { tabBarMap[pagePath] = true }) tabBarStr = JSON.stringify(tabBar) tabBarStr = tabBarStr.replace(/"(iconPath|selectedIconPath)":"([^"]+)"/g, function (matched, $1, $2) { if (isUrlRequest($2, projectRoot)) { return `"${$1}":require(${stringifyRequest(urlToRequest($2, projectRoot))})` } return matched }) } callback() } const processPackages = (packages, context, callback) => { if (packages) { async.each(packages, (packagePath, callback) => { const { queryObj } = parseRequest(packagePath) async.waterfall([ (callback) => { resolve(context, packagePath, loaderContext, (err, result) => { if (err) return callback(err) const { rawResourcePath } = parseRequest(result) callback(err, rawResourcePath) }) }, (result, callback) => { fs.readFile(result, (err, content) => { if (err) return callback(err) callback(err, result, content.toString('utf-8')) }) }, (result, content, callback) => { const extName = path.extname(result) if (extName === '.mpx') { const parts = parseComponent(content, { filePath: result, needMap: loaderContext.sourceMap, mode, env }) getJSONContent(parts.json || {}, result, loaderContext, (err, content) => { callback(err, result, content) }) } else { callback(null, result, content) } }, (result, content, callback) => { try { content = JSON5.parse(content) } catch (err) { return callback(err) } const processSelfQueue = [] const context = path.dirname(result) if (content.pages) { const tarRoot = queryObj.root if (tarRoot) { delete queryObj.root const subPackage = { tarRoot, pages: content.pages, ...queryObj } if (content.plugins) { subPackage.plugins = content.plugins } processSelfQueue.push((callback) => { processSubPackage(subPackage, context, callback) }) } else { processSelfQueue.push((callback) => { processPages(content.pages, context, '', callback) }) } } if (content.packages) { processSelfQueue.push((callback) => { processPackages(content.packages, context, callback) }) } if (processSelfQueue.length) { async.parallel(processSelfQueue, callback) } else { callback() } } ], (err) => { callback(err === RESOLVE_IGNORED_ERR ? null : err) }) }, callback) } else { callback() } } const pageKeySet = new Set() const processPages = (pages, context, tarRoot = '', callback) => { if (pages) { async.each(pages, (page, callback) => { processPage(page, context, tarRoot, (err, { resource, outputPath } = {}, { isFirst, key } = {}) => { if (err) return callback(err === RESOLVE_IGNORED_ERR ? null : err) if (pageKeySet.has(key)) return callback() pageKeySet.add(key) const { resourcePath, queryObj } = parseRequest(resource) if (localPagesMap[outputPath]) { const { resourcePath: oldResourcePath } = parseRequest(localPagesMap[outputPath].resource) if (oldResourcePath !== resourcePath) { const oldOutputPath = outputPath outputPath = mpx.getOutputPath(resourcePath, 'page', { conflictPath: outputPath }) emitWarning(new Error(`Current page [${resourcePath}] is registered with a conflict outputPath [${oldOutputPath}] which is already existed in system, will be renamed with [${outputPath}], use ?resolve to get the real outputPath!`)) } } pagesMap[resourcePath] = outputPath loaderContext._module && loaderContext._module.addPresentationalDependency(new RecordResourceMapDependency(resourcePath, 'page', outputPath)) localPagesMap[outputPath] = { resource: addQuery(resource, { isPage: true }), async: queryObj.async || tarRoot, isFirst } callback() }) }, callback) } else { callback() } } const processSubPackage = (subPackage, context, callback) => { if (subPackage) { if (typeof subPackage.root === 'string' && subPackage.root.startsWith('.')) { emitError(`Current subpackage root [${subPackage.root}] is not allow starts with '.'`) return callback() } const tarRoot = subPackage.tarRoot || subPackage.root || '' const srcRoot = subPackage.srcRoot || subPackage.root || '' if (!tarRoot) return callback() context = path.join(context, srcRoot) processPages(subPackage.pages, context, tarRoot, callback) } else { callback() } } const processSubPackages = (subPackages, context, callback) => { if (subPackages) { async.each(subPackages, (subPackage, callback) => { processSubPackage(subPackage, context, callback) }, callback) } else { callback() } } const processComponents = (components, context, callback) => { if (components) { async.eachOf(components, (component, name, callback) => { processComponent(component, context, {}, (err, { resource, outputPath } = {}, { tarRoot } = {}) => { if (err) return callback(err === RESOLVE_IGNORED_ERR ? null : err) const { resourcePath, queryObj } = parseRequest(resource) componentsMap[resourcePath] = outputPath loaderContext._module && loaderContext._module.addPresentationalDependency(new RecordResourceMapDependency(resourcePath, 'component', outputPath)) localComponentsMap[name] = { resource: addQuery(resource, { isComponent: true, outputPath }), async: queryObj.async || tarRoot } callback() }) }, callback) } else { callback() } } const processGenerics = (generics, context, callback) => { if (generics) { const genericsComponents = {} Object.keys(generics).forEach((name) => { const generic = generics[name] if (generic.default) genericsComponents[`${name}default`] = generic.default }) processComponents(genericsComponents, context, callback) } else { callback() } } async.parallel([ (callback) => { // 添加首页标识 if (jsonObj.pages && jsonObj.pages[0]) { if (typeof jsonObj.pages[0] !== 'string') { jsonObj.pages[0].src = addQuery(jsonObj.pages[0].src, { isFirst: true }) } else { jsonObj.pages[0] = addQuery(jsonObj.pages[0], { isFirst: true }) } } processPages(jsonObj.pages, context, '', callback) }, (callback) => { processComponents(jsonObj.usingComponents, context, callback) }, (callback) => { processPackages(jsonObj.packages, context, callback) }, (callback) => { processSubPackages(jsonObj.subPackages || jsonObj.subpackages, context, callback) }, (callback) => { processGenerics(jsonObj.componentGenerics, context, callback) }, (callback) => { processTabBar(jsonObj.tabBar, callback) } ], callback) }