From 07e557399ee4c844d7d9dd8efda94b32e4d650e0 Mon Sep 17 00:00:00 2001 From: JingkaiZhao Date: Mon, 7 May 2018 21:45:38 +0800 Subject: [PATCH 1/3] refactor: use async strategy intead of timeout --- lib/mp-compiler/index.js | 18 ++++--- lib/template-compiler/index.js | 98 +++++++++++++++++----------------- 2 files changed, 62 insertions(+), 54 deletions(-) diff --git a/lib/mp-compiler/index.js b/lib/mp-compiler/index.js index d714eba..89b7d82 100644 --- a/lib/mp-compiler/index.js +++ b/lib/mp-compiler/index.js @@ -65,11 +65,6 @@ function genComponentWxml (compiled, options, emitFile, emitError, emitWarning) function createWxml (emitWarning, emitError, emitFile, resourcePath, rootComponent, compiled, html) { const { pageType, moduleId, components, src } = getFileInfo(resourcePath) || {} - // 这儿一个黑魔法,和 webpack 约定的规范写法有点偏差! - if (!pageType || (components && !components.isCompleted)) { - return setTimeout(createWxml, 20, ...arguments) - } - let wxmlContent = '' let wxmlSrc = '' @@ -98,7 +93,18 @@ function createWxml (emitWarning, emitError, emitFile, resourcePath, rootCompone // 编译出 wxml function compileWxml (compiled, html) { - return createWxml(this.emitWarning, this.emitError, this.emitFile, this.resourcePath, null, compiled, html) + return new Promise(resolve => { + const tryCreateWxml = () => { + const { pageType, components } = getFileInfo(this.resourcePath) || {} + if (!pageType || (components && !components.isCompleted)) { + setTimeout(tryCreateWxml, 20) + } else { + createWxml(this.emitWarning, this.emitError, this.emitFile, this.resourcePath, null, compiled, html) + resolve() + } + } + tryCreateWxml() + }) } // 针对 .vue 单文件的脚本逻辑的处理 diff --git a/lib/template-compiler/index.js b/lib/template-compiler/index.js index 9dfacd8..0fab149 100644 --- a/lib/template-compiler/index.js +++ b/lib/template-compiler/index.js @@ -10,6 +10,7 @@ var transformRequire = require('./modules/transform-require') var compileWxml = require('../mp-compiler').compileWxml module.exports = function (html) { + this.async() this.cacheable() var isServer = this.target === 'node' var isProduction = this.minimize || process.env.NODE_ENV === 'production' @@ -38,56 +39,57 @@ module.exports = function (html) { // for mp => *.wxml compileWxml.call(this, compiled, html) + .then(() => { + // tips + if (compiled.tips && compiled.tips.length) { + compiled.tips.forEach(tip => { + this.emitWarning(tip) + }) + } - // tips - if (compiled.tips && compiled.tips.length) { - compiled.tips.forEach(tip => { - this.emitWarning(tip) - }) - } - - var code - if (compiled.errors && compiled.errors.length) { - this.emitError( - `\n Error compiling template:\n${pad(html)}\n` + - compiled.errors.map(e => ` - ${e}`).join('\n') + '\n' - ) - code = vueOptions.esModule - ? `var esExports = {render:function(){},staticRenderFns: []}\nexport default esExports` - : 'module.exports={render:function(){},staticRenderFns:[]}' - } else { - var bubleOptions = options.buble - code = transpile( - 'var render = ' + toFunction(compiled.render) + '\n' + - 'var staticRenderFns = [' + compiled.staticRenderFns.map(toFunction).join(',') + ']', - bubleOptions - ) + '\n' - // mark with stripped (this enables Vue to use correct runtime proxy detection) - if (!isProduction && ( - !bubleOptions || - !bubleOptions.transforms || - bubleOptions.transforms.stripWith !== false - )) { - code += `render._withStripped = true\n` - } - var exports = `{ render: render, staticRenderFns: staticRenderFns }` - code += vueOptions.esModule - ? `var esExports = ${exports}\nexport default esExports` - : `module.exports = ${exports}` - } - // hot-reload - if (!isServer && !isProduction) { - var exportsName = vueOptions.esModule ? 'esExports' : 'module.exports' - code += - '\nif (module.hot) {\n' + - ' module.hot.accept()\n' + - ' if (module.hot.data) {\n' + - ' require("' + hotReloadAPIPath + '").rerender("' + options.id + '", ' + exportsName + ')\n' + - ' }\n' + - '}' - } + var code + if (compiled.errors && compiled.errors.length) { + this.emitError( + `\n Error compiling template:\n${pad(html)}\n` + + compiled.errors.map(e => ` - ${e}`).join('\n') + '\n' + ) + code = vueOptions.esModule + ? `var esExports = {render:function(){},staticRenderFns: []}\nexport default esExports` + : 'module.exports={render:function(){},staticRenderFns:[]}' + } else { + var bubleOptions = options.buble + code = transpile( + 'var render = ' + toFunction(compiled.render) + '\n' + + 'var staticRenderFns = [' + compiled.staticRenderFns.map(toFunction).join(',') + ']', + bubleOptions + ) + '\n' + // mark with stripped (this enables Vue to use correct runtime proxy detection) + if (!isProduction && ( + !bubleOptions || + !bubleOptions.transforms || + bubleOptions.transforms.stripWith !== false + )) { + code += `render._withStripped = true\n` + } + var exports = `{ render: render, staticRenderFns: staticRenderFns }` + code += vueOptions.esModule + ? `var esExports = ${exports}\nexport default esExports` + : `module.exports = ${exports}` + } + // hot-reload + if (!isServer && !isProduction) { + var exportsName = vueOptions.esModule ? 'esExports' : 'module.exports' + code += + '\nif (module.hot) {\n' + + ' module.hot.accept()\n' + + ' if (module.hot.data) {\n' + + ' require("' + hotReloadAPIPath + '").rerender("' + options.id + '", ' + exportsName + ')\n' + + ' }\n' + + '}' + } - return code + this.callback(null, code) + }) } function toFunction (code) { From bf63db05f043d0a915c73afa3aaa54a1df40fafc Mon Sep 17 00:00:00 2001 From: JingkaiZhao Date: Mon, 7 May 2018 22:05:05 +0800 Subject: [PATCH 2/3] refactor: remove timeout in createSlotWxml --- lib/mp-compiler/index.js | 61 +++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/lib/mp-compiler/index.js b/lib/mp-compiler/index.js index 89b7d82..a30cd4f 100644 --- a/lib/mp-compiler/index.js +++ b/lib/mp-compiler/index.js @@ -22,20 +22,12 @@ const { getPageSrc } = require('./util') -let emitFileTimer = null - function createSlotsWxml (emitFile, slots, importCode) { cacheSlots(slots, importCode) const content = getSlots() // 100 delay 比较符合当前策略 - const delay = 100 if (content.trim()) { - if (emitFileTimer) { - clearTimeout(emitFileTimer) - } - emitFileTimer = setTimeout(function () { - emitFile('components/slots.wxml', htmlBeautify(content)) - }, delay) + emitFile('components/slots.wxml', htmlBeautify(content)) } } @@ -62,31 +54,30 @@ function genComponentWxml (compiled, options, emitFile, emitError, emitWarning) return htmlBeautify(wxmlCodeStr) } -function createWxml (emitWarning, emitError, emitFile, resourcePath, rootComponent, compiled, html) { - const { pageType, moduleId, components, src } = getFileInfo(resourcePath) || {} - - let wxmlContent = '' - let wxmlSrc = '' +function createAppWxml (emitFile, resourcePath, rootComponent) { + const { src } = getFileInfo(resourcePath) || {} + const componentName = getCompNameBySrc(rootComponent) + const wxmlContent = genPageWxml(componentName, src) + const wxmlSrc = src + emitFile(`${wxmlSrc}.wxml`, wxmlContent) +} - if (rootComponent) { - const componentName = getCompNameBySrc(rootComponent) - wxmlContent = genPageWxml(componentName, src) - wxmlSrc = src - } else { - // TODO, 这儿传 options 进去 - // { - // components: { - // 'com-a': { src: '../../components/comA$hash', name: 'comA$hash' } - // }, - // pageType: 'component', - // name: 'comA$hash', - // moduleId: 'moduleId' - // } - const name = getCompNameBySrc(resourcePath) - const options = { components, pageType, name, moduleId } - wxmlContent = genComponentWxml(compiled, options, emitFile, emitError, emitWarning) - wxmlSrc = `components/${name}` - } +function createWxml (emitWarning, emitError, emitFile, resourcePath, rootComponent, compiled, html) { + const { pageType, moduleId, components } = getFileInfo(resourcePath) || {} + + // TODO, 这儿传 options 进去 + // { + // components: { + // 'com-a': { src: '../../components/comA$hash', name: 'comA$hash' } + // }, + // pageType: 'component', + // name: 'comA$hash', + // moduleId: 'moduleId' + // } + const name = getCompNameBySrc(resourcePath) + const options = { components, pageType, name, moduleId } + const wxmlContent = genComponentWxml(compiled, options, emitFile, emitError, emitWarning) + const wxmlSrc = `components/${name}` emitFile(`${wxmlSrc}.wxml`, wxmlContent) } @@ -166,7 +157,7 @@ function compileMPScript (script, mpOptioins, moduleId) { const startPageReg = /^\^/ function compileMP (content, mpOptioins) { - const { resourcePath, emitError, emitFile, emitWarning, resolve, context, options } = this + const { resourcePath, emitFile, resolve, context, options } = this const babelrc = getBabelrc(mpOptioins.globalBabelrc) const { metadata } = babel.transform(content, { extends: babelrc, plugins: [parseConfig] }) @@ -211,7 +202,7 @@ function compileMP (content, mpOptioins) { resolve(context, rootComponent, (err, rootComponentSrc) => { if (err) return // 这儿需要搞定 根组件的 路径 - createWxml(emitWarning, emitError, emitFile, resourcePath, rootComponentSrc) + createAppWxml(emitFile, resourcePath, rootComponentSrc) }) } } From f71a0a756f2e0e5ce219fa0456cf6076bd518f55 Mon Sep 17 00:00:00 2001 From: JingkaiZhao Date: Tue, 8 May 2018 12:37:55 +0800 Subject: [PATCH 3/3] refactor: use compilation hook to create slots file --- lib/mp-compiler/index.js | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/lib/mp-compiler/index.js b/lib/mp-compiler/index.js index a30cd4f..a6ac0f0 100644 --- a/lib/mp-compiler/index.js +++ b/lib/mp-compiler/index.js @@ -22,14 +22,7 @@ const { getPageSrc } = require('./util') -function createSlotsWxml (emitFile, slots, importCode) { - cacheSlots(slots, importCode) - const content = getSlots() - // 100 delay 比较符合当前策略 - if (content.trim()) { - emitFile('components/slots.wxml', htmlBeautify(content)) - } -} +let slotsHookAdded = false // 调用 compiler 生成 wxml function genComponentWxml (compiled, options, emitFile, emitError, emitWarning) { @@ -38,7 +31,7 @@ function genComponentWxml (compiled, options, emitFile, emitError, emitWarning) const { mpErrors, mpTips } = cp // 缓存 slots,延迟编译 - createSlotsWxml(emitFile, slots, importCode) + cacheSlots(slots, importCode) if (mpErrors && mpErrors.length) { emitError( @@ -84,18 +77,33 @@ function createWxml (emitWarning, emitError, emitFile, resourcePath, rootCompone // 编译出 wxml function compileWxml (compiled, html) { + if (!slotsHookAdded) { + // avoid add hook several times during compilation + slotsHookAdded = true + // TODO: support webpack4 + this._compilation.plugin('seal', () => { + const content = getSlots() + if (content.trim()) { + this.emitFile('components/slots.wxml', htmlBeautify(content)) + } + // reset flag after slots file emited + slotsHookAdded = false + }) + } return new Promise(resolve => { - const tryCreateWxml = () => { + const pollComponentsStatus = () => { const { pageType, components } = getFileInfo(this.resourcePath) || {} if (!pageType || (components && !components.isCompleted)) { - setTimeout(tryCreateWxml, 20) + setTimeout(pollComponentsStatus, 20) } else { - createWxml(this.emitWarning, this.emitError, this.emitFile, this.resourcePath, null, compiled, html) resolve() } } - tryCreateWxml() + pollComponentsStatus() }) + .then(() => { + createWxml(this.emitWarning, this.emitError, this.emitFile, this.resourcePath, null, compiled, html) + }) } // 针对 .vue 单文件的脚本逻辑的处理