Skip to content

refactor: 移除timeout魔法 #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 53 additions & 49 deletions lib/mp-compiler/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,7 @@ 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)
}
}
let slotsHookAdded = false

// 调用 compiler 生成 wxml
function genComponentWxml (compiled, options, emitFile, emitError, emitWarning) {
Expand All @@ -47,7 +32,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(
Expand All @@ -63,47 +48,66 @@ function genComponentWxml (compiled, options, emitFile, emitError, emitWarning)
return htmlBeautify(wxmlCodeStr)
}

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)
}
// 更新全局组件时,需要重新生成wxml,用这个字段保存所有需要更新的页面及其参数
const cacheCreateWxmlFns = {}

function createWxml (emitWarning, emitError, emitFile, resourcePath, rootComponent, compiled, html) {
cacheCreateWxmlFns[resourcePath] = arguments
const { pageType, moduleId, components, src } = getFileInfo(resourcePath) || {}

// 这儿一个黑魔法,和 webpack 约定的规范写法有点偏差!
if (!pageType || (components && !components.isCompleted)) {
return setTimeout(createWxml, 20, ...arguments)
}

let wxmlContent = ''
let wxmlSrc = ''

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}`
}
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)
}

// 编译出 wxml
function compileWxml (compiled, html) {
return createWxml(this.emitWarning, this.emitError, this.emitFile, this.resourcePath, null, 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 pollComponentsStatus = () => {
const { pageType, components } = getFileInfo(this.resourcePath) || {}
if (!pageType || (components && !components.isCompleted)) {
setTimeout(pollComponentsStatus, 20)
} else {
resolve()
}
}
pollComponentsStatus()
})
.then(() => {
createWxml(this.emitWarning, this.emitError, this.emitFile, this.resourcePath, null, compiled, html)
})
}

// 针对 .vue 单文件的脚本逻辑的处理
Expand Down Expand Up @@ -150,7 +154,7 @@ function compileMPScript (script, mpOptioins, moduleId) {
const startPageReg = /^\^/
let globalComponents
function compileMP (content, mpOptioins) {
const { resourcePath, emitError, emitFile, emitWarning, resolve, context, options } = this
const { resourcePath, emitFile, resolve, context, options } = this

const fileInfo = resolveTarget(resourcePath, options.entry)
cacheFileInfo(resourcePath, fileInfo)
Expand Down Expand Up @@ -230,7 +234,7 @@ function compileMP (content, mpOptioins) {
resolve(context, rootComponent, (err, rootComponentSrc) => {
if (err) return
// 这儿需要搞定 根组件的 路径
createWxml(emitWarning, emitError, emitFile, resourcePath, rootComponentSrc)
createAppWxml(emitFile, resourcePath, rootComponentSrc)
})
}
}
Expand Down
98 changes: 50 additions & 48 deletions lib/template-compiler/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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) {
Expand Down