diff --git a/lib/loader.js b/lib/loader.js index 35f85c1..704c17f 100644 --- a/lib/loader.js +++ b/lib/loader.js @@ -101,7 +101,7 @@ module.exports = function (content) { var output = '' var parts = parse(content, fileName, this.sourceMap) - // fix #153: 根组件没有 style 模块,不生成页面的 wxss,补齐内容方便加载 vendor.wxss + // fix #153: 根组件没有 style 模块,不生成页面的样式文件,补齐内容方便加载 vendor if (!parts.styles.length) { parts.styles.push(defaultPart('style')) } @@ -119,6 +119,11 @@ module.exports = function (content) { hasComment: hasComment, transformToRequire: options.transformToRequire, preserveWhitespace: options.preserveWhitespace, + fileExt: options.fileExt || { + template: 'wxml', + style: 'wxss', + script: 'js' + }, buble: options.buble, // only pass compilerModules if it's a path string compilerModules: typeof options.compilerModules === 'string' @@ -258,7 +263,7 @@ module.exports = function (content) { var script = parts.script if (script) { // for mp js - // 需要解析组件的 components 给 wxml 生成用 + // 需要解析组件的 components 给 mpml 生成用 script = compileMPScript.call(this, script, mpOptions, moduleId) if (options.esModule) { diff --git a/lib/mp-compiler/index.js b/lib/mp-compiler/index.js index 2938960..9a02ef7 100644 --- a/lib/mp-compiler/index.js +++ b/lib/mp-compiler/index.js @@ -1,19 +1,17 @@ -// for mp -const compiler = require('mpvue-template-compiler') - const babel = require('babel-core') const path = require('path') const fs = require('fs') const deepEqual = require('deep-equal') +const compiler = require('mpvue-template-compiler') const { parseConfig, parseComponentsDeps, parseGlobalComponents, clearGlobalComponents } = require('./parse') const { parseComponentsDeps: parseComponentsDepsTs } = require('./parse-ts') -const { genPageWxml } = require('./templates') +const { genPageML } = require('./templates') const { cacheFileInfo, getFileInfo, - getCompNameAndSrc, + getCompInfo, resolveTarget, covertCCVar, cacheSlots, @@ -22,60 +20,44 @@ const { getBabelrc } = require('./util') -let slotsHookAdded = false - -// 调用 compiler 生成 wxml -function genComponentWxml (compiled, options, emitFile, emitError, emitWarning) { +function genComponentMPML (compiled, options, emitFile, emitError, emitWarning, fileExt) { options.components['slots'] = { src: '/components/slots', name: 'slots' } - const { code: wxmlCodeStr, compiled: cp, slots, importCode } = compiler.compileToWxml(compiled, options) - const { mpErrors, mpTips } = cp + const { code: mpmlContent, compiled: compiledResult, slots, importCode } = compiler.compileToWxml(compiled, options, fileExt) + const { mpErrors, mpTips } = compiledResult // 缓存 slots,延迟编译 cacheSlots(slots, importCode) if (mpErrors && mpErrors.length) { - emitError( - `\n Error compiling template:\n` + - mpErrors.map(e => ` - ${e}`).join('\n') + '\n' - ) + emitError('\n Error compiling template:\n' + mpErrors.map(e => ` - ${e}`).join('\n') + '\n') } if (mpTips && mpTips.length) { - emitWarning( - mpTips.map(e => ` - ${e}`).join('\n') + '\n' - ) + emitWarning(mpTips.map(e => ` - ${e}`).join('\n') + '\n') } - return htmlBeautify(wxmlCodeStr) + return htmlBeautify(mpmlContent) } -function createAppWxml (emitFile, resourcePath, rootComponent, context) { +function createPageMPML (emitFile, resourcePath, rootComponent, context, fileExt) { const { src } = getFileInfo(resourcePath) || {} - const { name: componentName, filePath: wxmlSrc } = getCompNameAndSrc(context, rootComponent) - const wxmlContent = genPageWxml(componentName, wxmlSrc) - emitFile(`${src}.wxml`, wxmlContent) + const { name, filePath } = getCompInfo(context, rootComponent, fileExt) + const MPMLContent = genPageML(name, filePath, fileExt) + emitFile(`${src}.${fileExt.template}`, MPMLContent) } -// 更新全局组件时,需要重新生成wxml,用这个字段保存所有需要更新的页面及其参数 -const cacheCreateWxmlFns = {} -function createWxml ({ emitWarning, emitError, emitFile, resourcePath, context, compiled }) { - cacheCreateWxmlFns[resourcePath] = arguments - const { pageType, moduleId, components } = getFileInfo(resourcePath) || {} +// 更新全局组件时,需要重新生成 mpml,用这个字段保存所有需要更新的页面及其参数 +const cacheCreateMPMLFns = {} - // TODO, 这儿传 options 进去 - // { - // components: { - // 'com-a': { src: '../../components/comA$hash', name: 'comA$hash' } - // }, - // pageType: 'component', - // name: 'comA$hash', - // moduleId: 'moduleId' - // } - const { name, filePath: wxmlSrc } = getCompNameAndSrc(context, resourcePath) +function createComponentMPML ({ emitWarning, emitError, emitFile, resourcePath, context, compiled, fileExt }) { + cacheCreateMPMLFns[resourcePath] = arguments + const { pageType, moduleId, components } = getFileInfo(resourcePath) || {} + const { name, filePath } = getCompInfo(context, resourcePath, fileExt) const options = { components, pageType, name, moduleId } - const wxmlContent = genComponentWxml(compiled, options, emitFile, emitError, emitWarning) - emitFile(wxmlSrc, wxmlContent) + const MPMLContent = genComponentMPML(compiled, options, emitFile, emitError, emitWarning, fileExt) + emitFile(filePath, MPMLContent) } -// 编译出 wxml -function compileWxml (compiled, html) { +let slotsHookAdded = false +function compileMPML (compiled, html, options) { + const fileExt = options.fileExt if (!slotsHookAdded) { // avoid add hook several times during compilation slotsHookAdded = true @@ -83,12 +65,12 @@ function compileWxml (compiled, html) { this._compilation.plugin('seal', () => { const content = getSlots() if (content.trim()) { - this.emitFile('components/slots.wxml', htmlBeautify(content)) + this.emitFile(`components/slots.${fileExt.template}`, htmlBeautify(content)) } - // reset flag after slots file emited slotsHookAdded = false }) } + return new Promise(resolve => { const pollComponentsStatus = () => { const { pageType, components } = getFileInfo(this.resourcePath) || {} @@ -99,18 +81,18 @@ function compileWxml (compiled, html) { } } pollComponentsStatus() - }) - .then(() => { - createWxml({ - emitWarning: this.emitWarning, - emitError: this.emitError, - emitFile: this.emitFile, - resourcePath: this.resourcePath, - context: this.options.context, - rootComponent: null, - compiled, html - }) + }).then(() => { + createComponentMPML({ + emitWarning: this.emitWarning, + emitError: this.emitError, + emitFile: this.emitFile, + resourcePath: this.resourcePath, + context: this.options.context, + rootComponent: null, + compiled, html, + fileExt }) + }) } // 针对 .vue 单文件的脚本逻辑的处理 @@ -118,47 +100,47 @@ function compileWxml (compiled, html) { function compileMPScript (script, mpOptioins, moduleId) { const { resourcePath, options, resolve, context } = this const babelrc = getBabelrc(mpOptioins.globalBabelrc) - let result, metadata + let scriptContent = script.content const babelOptions = { extends: babelrc, plugins: [parseComponentsDeps] } - if (script.src) { // 处理src + if (script.src) { const scriptpath = path.join(path.dirname(resourcePath), script.src) scriptContent = fs.readFileSync(scriptpath).toString() } - if (script.lang === 'ts') { // 处理ts + + let metadata + if (script.lang === 'ts') { metadata = parseComponentsDepsTs(scriptContent) } else { - result = babel.transform(scriptContent, babelOptions) + const result = babel.transform(scriptContent, babelOptions) metadata = result.metadata } - // metadata: importsMap, components const { importsMap, components: originComponents } = metadata // 处理子组件的信息 const components = {} const fileInfo = resolveTarget(resourcePath, options.entry) + + const callback = () => resolveComponent(resourcePath, fileInfo, importsMap, components, moduleId) if (originComponents) { - resolveSrc(originComponents, components, resolve, context, options.context).then(() => { - resolveComponent(resourcePath, fileInfo, importsMap, components, moduleId) - }).catch(err => { - console.error(err) - resolveComponent(resourcePath, fileInfo, importsMap, components, moduleId) - }) + resolveSrc(originComponents, components, resolve, context, options.context, mpOptioins.fileExt) + .then(() => callback()) + .catch(err => { + console.error(err) + callback() + }) } else { - resolveComponent(resourcePath, fileInfo, importsMap, components, moduleId) + callback() } return script } -// checkMPEntry 针对 entry main.js 的入口处理 -// 编译出 app, page 的入口js/wxml/json - +// checkMPEntry 针对 entry main.js 的入口处理: 编译出 app, page 的入口js、mpml、json let globalComponents function compileMP (content, mpOptioins) { const { resourcePath, emitFile, resolve, context, options } = this - const fileInfo = resolveTarget(resourcePath, options.entry) cacheFileInfo(resourcePath, fileInfo) const { isApp, isPage } = fileInfo @@ -182,7 +164,7 @@ function compileMP (content, mpOptioins) { // 解析全局组件的路径 const components = {} - resolveSrc(globalComps, components, resolve, context, options.context).then(() => { + resolveSrc(globalComps, components, resolve, context, options.context, mpOptioins.fileExt).then(() => { handleResult(components) }).catch(err => { console.error(err) @@ -190,15 +172,15 @@ function compileMP (content, mpOptioins) { }) const handleResult = components => { globalComponents = components - // 热更时,如果全局组件更新,需要重新生成所有的wxml + // 热更时,如果全局组件更新,需要重新生成所有的 mpml if (oldGlobalComponents && !deepEqual(oldGlobalComponents, globalComponents)) { // 更新所有页面的组件 Object.keys(cacheResolveComponents).forEach(k => { resolveComponent(...cacheResolveComponents[k]) }) - // 重新生成所有wxml - Object.keys(cacheCreateWxmlFns).forEach(k => { - createWxml(...cacheCreateWxmlFns[k]) + // 重新生成所有 mpml + Object.keys(cacheCreateMPMLFns).forEach(k => { + createComponentMPML(...cacheCreateMPMLFns[k]) }) } } @@ -206,12 +188,12 @@ function compileMP (content, mpOptioins) { if (isApp || isPage) { // 这儿应该异步在所有的模块都清晰后再生成 - // 生成入口 wxml + // 生成入口 mpml if (isPage && rootComponent) { resolve(context, rootComponent, (err, rootComponentSrc) => { if (err) return // 这儿需要搞定 根组件的 路径 - createAppWxml(emitFile, resourcePath, rootComponentSrc, this.options.context) + createPageMPML(emitFile, resourcePath, rootComponentSrc, this.options.context, mpOptioins.fileExt) }) } } @@ -219,13 +201,13 @@ function compileMP (content, mpOptioins) { return content } -function resolveSrc (originComponents, components, resolveFn, context, projectRoot) { +function resolveSrc (originComponents, components, resolveFn, context, projectRoot, fileExt) { return Promise.all(Object.keys(originComponents).map(k => { return new Promise((resolve, reject) => { resolveFn(context, originComponents[k], (err, realSrc) => { if (err) return reject(err) const com = covertCCVar(k) - const { filePath, name } = getCompNameAndSrc(projectRoot, realSrc) + const { filePath, name } = getCompInfo(projectRoot, realSrc, fileExt) components[com] = { src: filePath, name } resolve() }) @@ -247,4 +229,8 @@ function resolveComponent (resourcePath, fileInfo, importsMap, localComponents, } } -module.exports = { compileWxml, compileMPScript, compileMP } +module.exports = { + compileMP, + compileMPML, + compileMPScript +} diff --git a/lib/mp-compiler/templates.js b/lib/mp-compiler/templates.js index d6680c9..a01ce94 100644 --- a/lib/mp-compiler/templates.js +++ b/lib/mp-compiler/templates.js @@ -1,5 +1,24 @@ -function genPageWxml (templateName, src) { +function genWXML (templateName, src) { return `