UNPKG

@mpxjs/webpack-plugin

Version:

mpx compile core

186 lines (164 loc) 6.29 kB
const compiler = require('./compiler') const bindThis = require('./bind-this') const parseRequest = require('../utils/parse-request') const { matchCondition } = require('../utils/match-condition') const loaderUtils = require('loader-utils') const { MPX_DISABLE_EXTRACTOR_CACHE } = require('../utils/const') const RecordRuntimeInfoDependency = require('../dependencies/RecordRuntimeInfoDependency') const { createTemplateEngine, createSetupTemplate } = require('@mpxjs/template-engine') const { stringify } = require('./dynamic') module.exports = function (raw) { this.cacheable() const { resourcePath, queryObj, rawResourcePath } = parseRequest(this.resource) const mpx = this.getMpx() const projectRoot = mpx.projectRoot const mode = mpx.mode const env = mpx.env const defs = mpx.defs const i18n = mpx.i18n const externalClasses = mpx.externalClasses const decodeHTMLText = mpx.decodeHTMLText const globalSrcMode = mpx.srcMode const localSrcMode = queryObj.mode const packageName = queryObj.packageRoot || mpx.currentPackageRoot || 'main' const wxsContentMap = mpx.wxsContentMap const optimizeRenderRules = mpx.optimizeRenderRules const usingComponentsInfo = queryObj.usingComponentsInfo || {} const componentPlaceholder = queryObj.componentPlaceholder || [] const hasComment = queryObj.hasComment const isNative = queryObj.isNative const ctorType = queryObj.ctorType const hasScoped = queryObj.hasScoped const runtimeCompile = queryObj.isDynamic const moduleId = queryObj.moduleId || mpx.getModuleId(resourcePath) let optimizeRenderLevel = 0 for (const rule of optimizeRenderRules) { if (matchCondition(resourcePath, rule)) { optimizeRenderLevel = rule.level || 1 break } } const warn = (msg) => { this.emitWarning( new Error('[template compiler][' + this.resource + ']: ' + msg) ) } const error = (msg) => { this.emitError( new Error('[template compiler][' + this.resource + ']: ' + msg) ) } const { root, meta } = compiler.parse(raw, { warn, error, runtimeCompile, componentPlaceholder, hasComment, isNative, ctorType, mode, env, srcMode: localSrcMode || globalSrcMode, defs, decodeHTMLText, externalClasses, hasScoped, moduleId, usingComponentsInfo, // 这里需传递rawResourcePath和wxsContentMap保持一致 filePath: rawResourcePath, i18n, checkUsingComponents: matchCondition(resourcePath, mpx.checkUsingComponentsRules), globalComponents: Object.keys(mpx.globalComponents), forceProxyEvent: matchCondition(resourcePath, mpx.forceProxyEventRules) || runtimeCompile, hasVirtualHost: matchCondition(resourcePath, mpx.autoVirtualHostRules), dynamicTemplateRuleRunner: mpx.dynamicTemplateRuleRunner }) if (meta.wxsContentMap) { for (const module in meta.wxsContentMap) { wxsContentMap[`${rawResourcePath}~${module}`] = meta.wxsContentMap[module] } } let result = runtimeCompile ? '' : compiler.serialize(root) if (isNative) { return result } let resultSource = '' for (const module in meta.wxsModuleMap) { const src = loaderUtils.urlToRequest(meta.wxsModuleMap[module], projectRoot) resultSource += `var ${module} = require(${loaderUtils.stringifyRequest(this, src)});\n` } resultSource += `global.currentInject = { moduleId: ${JSON.stringify(moduleId)} };\n` if (runtimeCompile) { resultSource += 'global.currentInject.dynamic = true;\n' } const rawCode = runtimeCompile ? '' : compiler.genNode(root) if (rawCode) { try { const ignoreMap = Object.assign({ _i: true, _c: true, _sc: true, _r: true }, meta.wxsModuleMap) const bindResult = optimizeRenderLevel === 2 ? bindThis.transformSimple(rawCode, { ignoreMap }) : bindThis.transform(rawCode, { needCollect: true, renderReduce: optimizeRenderLevel === 1, ignoreMap }) resultSource += `global.currentInject.render = function (_i, _c, _r, _sc) { ${bindResult.code} _r(${optimizeRenderLevel === 2 ? 'true' : ''}); };\n` if ((mode === 'tt' || mode === 'swan') && bindResult.propKeys) { resultSource += `global.currentInject.propKeys = ${JSON.stringify(bindResult.propKeys)};\n` } } catch (e) { error(`Invalid render function generated by the template, please check! Template result: ${result} Error code: ${rawCode} Error Detail: ${e.stack}`) return result } } if (meta.computed) { resultSource += bindThis.transform(`global.currentInject.injectComputed = {${meta.computed.join(',')}};`).code + '\n' } if (meta.refs) { resultSource += `global.currentInject.getRefsData = function () { return ${JSON.stringify(meta.refs)}; };\n` } if (meta.options) { resultSource += `global.currentInject.injectOptions = ${JSON.stringify(meta.options)};\n` } this.emitFile(resourcePath, '', undefined, { skipEmit: true, extractedResultSource: resultSource }) if (queryObj.mpxCustomElement) { this.cacheable(false) const templateEngine = createTemplateEngine(mpx.mode) result += `${createSetupTemplate()}\n` + templateEngine.buildTemplate(mpx.getPackageInjectedTemplateConfig(packageName)) } // 运行时编译的组件直接返回基础模板的内容,并产出动态文本内容 if (runtimeCompile) { // 包含了运行时组件的template模块必须每次都创建(但并不是每次都需要build),用于收集组件节点信息,传递信息以禁用父级extractor的缓存 this.emitFile(MPX_DISABLE_EXTRACTOR_CACHE, '', undefined, { skipEmit: true }) const templateInfo = { templateAst: stringify(root), ...meta.runtimeInfo } // 以 package 为维度存储,meta 上的数据也只是存储了这个组件的 template 上获取的信息,需要在 dependency 里面再次进行合并操作 this._module.addPresentationalDependency(new RecordRuntimeInfoDependency(packageName, resourcePath, { type: 'template', info: templateInfo })) // 运行时组件的模版直接返回空,在生成模版静态文件的时候(beforeModuleAssets)再动态注入 } return result }