Skip to content

Commit 4933275

Browse files
jkzinghucq
authored andcommitted
refactor: 移除timeout魔法 (#21)
* refactor: use async strategy intead of timeout * refactor: remove timeout in createSlotWxml * refactor: use compilation hook to create slots file
1 parent 275c32d commit 4933275

File tree

2 files changed

+103
-97
lines changed

2 files changed

+103
-97
lines changed

lib/mp-compiler/index.js

+53-49
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,7 @@ const {
2323
getPageSrc
2424
} = require('./util')
2525

26-
let emitFileTimer = null
27-
28-
function createSlotsWxml (emitFile, slots, importCode) {
29-
cacheSlots(slots, importCode)
30-
const content = getSlots()
31-
// 100 delay 比较符合当前策略
32-
const delay = 100
33-
if (content.trim()) {
34-
if (emitFileTimer) {
35-
clearTimeout(emitFileTimer)
36-
}
37-
emitFileTimer = setTimeout(function () {
38-
emitFile('components/slots.wxml', htmlBeautify(content))
39-
}, delay)
40-
}
41-
}
26+
let slotsHookAdded = false
4227

4328
// 调用 compiler 生成 wxml
4429
function genComponentWxml (compiled, options, emitFile, emitError, emitWarning) {
@@ -47,7 +32,7 @@ function genComponentWxml (compiled, options, emitFile, emitError, emitWarning)
4732
const { mpErrors, mpTips } = cp
4833

4934
// 缓存 slots,延迟编译
50-
createSlotsWxml(emitFile, slots, importCode)
35+
cacheSlots(slots, importCode)
5136

5237
if (mpErrors && mpErrors.length) {
5338
emitError(
@@ -63,47 +48,66 @@ function genComponentWxml (compiled, options, emitFile, emitError, emitWarning)
6348
return htmlBeautify(wxmlCodeStr)
6449
}
6550

51+
function createAppWxml (emitFile, resourcePath, rootComponent) {
52+
const { src } = getFileInfo(resourcePath) || {}
53+
const componentName = getCompNameBySrc(rootComponent)
54+
const wxmlContent = genPageWxml(componentName, src)
55+
const wxmlSrc = src
56+
emitFile(`${wxmlSrc}.wxml`, wxmlContent)
57+
}
6658
// 更新全局组件时,需要重新生成wxml,用这个字段保存所有需要更新的页面及其参数
6759
const cacheCreateWxmlFns = {}
6860

6961
function createWxml (emitWarning, emitError, emitFile, resourcePath, rootComponent, compiled, html) {
7062
cacheCreateWxmlFns[resourcePath] = arguments
71-
const { pageType, moduleId, components, src } = getFileInfo(resourcePath) || {}
72-
73-
// 这儿一个黑魔法,和 webpack 约定的规范写法有点偏差!
74-
if (!pageType || (components && !components.isCompleted)) {
75-
return setTimeout(createWxml, 20, ...arguments)
76-
}
77-
78-
let wxmlContent = ''
79-
let wxmlSrc = ''
80-
81-
if (rootComponent) {
82-
const componentName = getCompNameBySrc(rootComponent)
83-
wxmlContent = genPageWxml(componentName, src)
84-
wxmlSrc = src
85-
} else {
86-
// TODO, 这儿传 options 进去
87-
// {
88-
// components: {
89-
// 'com-a': { src: '../../components/comA$hash', name: 'comA$hash' }
90-
// },
91-
// pageType: 'component',
92-
// name: 'comA$hash',
93-
// moduleId: 'moduleId'
94-
// }
95-
const name = getCompNameBySrc(resourcePath)
96-
const options = { components, pageType, name, moduleId }
97-
wxmlContent = genComponentWxml(compiled, options, emitFile, emitError, emitWarning)
98-
wxmlSrc = `components/${name}`
99-
}
63+
const { pageType, moduleId, components } = getFileInfo(resourcePath) || {}
64+
65+
// TODO, 这儿传 options 进去
66+
// {
67+
// components: {
68+
// 'com-a': { src: '../../components/comA$hash', name: 'comA$hash' }
69+
// },
70+
// pageType: 'component',
71+
// name: 'comA$hash',
72+
// moduleId: 'moduleId'
73+
// }
74+
const name = getCompNameBySrc(resourcePath)
75+
const options = { components, pageType, name, moduleId }
76+
const wxmlContent = genComponentWxml(compiled, options, emitFile, emitError, emitWarning)
77+
const wxmlSrc = `components/${name}`
10078

10179
emitFile(`${wxmlSrc}.wxml`, wxmlContent)
10280
}
10381

10482
// 编译出 wxml
10583
function compileWxml (compiled, html) {
106-
return createWxml(this.emitWarning, this.emitError, this.emitFile, this.resourcePath, null, compiled, html)
84+
if (!slotsHookAdded) {
85+
// avoid add hook several times during compilation
86+
slotsHookAdded = true
87+
// TODO: support webpack4
88+
this._compilation.plugin('seal', () => {
89+
const content = getSlots()
90+
if (content.trim()) {
91+
this.emitFile('components/slots.wxml', htmlBeautify(content))
92+
}
93+
// reset flag after slots file emited
94+
slotsHookAdded = false
95+
})
96+
}
97+
return new Promise(resolve => {
98+
const pollComponentsStatus = () => {
99+
const { pageType, components } = getFileInfo(this.resourcePath) || {}
100+
if (!pageType || (components && !components.isCompleted)) {
101+
setTimeout(pollComponentsStatus, 20)
102+
} else {
103+
resolve()
104+
}
105+
}
106+
pollComponentsStatus()
107+
})
108+
.then(() => {
109+
createWxml(this.emitWarning, this.emitError, this.emitFile, this.resourcePath, null, compiled, html)
110+
})
107111
}
108112

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

155159
const fileInfo = resolveTarget(resourcePath, options.entry)
156160
cacheFileInfo(resourcePath, fileInfo)
@@ -230,7 +234,7 @@ function compileMP (content, mpOptioins) {
230234
resolve(context, rootComponent, (err, rootComponentSrc) => {
231235
if (err) return
232236
// 这儿需要搞定 根组件的 路径
233-
createWxml(emitWarning, emitError, emitFile, resourcePath, rootComponentSrc)
237+
createAppWxml(emitFile, resourcePath, rootComponentSrc)
234238
})
235239
}
236240
}

lib/template-compiler/index.js

+50-48
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ var transformRequire = require('./modules/transform-require')
1010
var compileWxml = require('../mp-compiler').compileWxml
1111

1212
module.exports = function (html) {
13+
this.async()
1314
this.cacheable()
1415
var isServer = this.target === 'node'
1516
var isProduction = this.minimize || process.env.NODE_ENV === 'production'
@@ -38,56 +39,57 @@ module.exports = function (html) {
3839

3940
// for mp => *.wxml
4041
compileWxml.call(this, compiled, html)
42+
.then(() => {
43+
// tips
44+
if (compiled.tips && compiled.tips.length) {
45+
compiled.tips.forEach(tip => {
46+
this.emitWarning(tip)
47+
})
48+
}
4149

42-
// tips
43-
if (compiled.tips && compiled.tips.length) {
44-
compiled.tips.forEach(tip => {
45-
this.emitWarning(tip)
46-
})
47-
}
48-
49-
var code
50-
if (compiled.errors && compiled.errors.length) {
51-
this.emitError(
52-
`\n Error compiling template:\n${pad(html)}\n` +
53-
compiled.errors.map(e => ` - ${e}`).join('\n') + '\n'
54-
)
55-
code = vueOptions.esModule
56-
? `var esExports = {render:function(){},staticRenderFns: []}\nexport default esExports`
57-
: 'module.exports={render:function(){},staticRenderFns:[]}'
58-
} else {
59-
var bubleOptions = options.buble
60-
code = transpile(
61-
'var render = ' + toFunction(compiled.render) + '\n' +
62-
'var staticRenderFns = [' + compiled.staticRenderFns.map(toFunction).join(',') + ']',
63-
bubleOptions
64-
) + '\n'
65-
// mark with stripped (this enables Vue to use correct runtime proxy detection)
66-
if (!isProduction && (
67-
!bubleOptions ||
68-
!bubleOptions.transforms ||
69-
bubleOptions.transforms.stripWith !== false
70-
)) {
71-
code += `render._withStripped = true\n`
72-
}
73-
var exports = `{ render: render, staticRenderFns: staticRenderFns }`
74-
code += vueOptions.esModule
75-
? `var esExports = ${exports}\nexport default esExports`
76-
: `module.exports = ${exports}`
77-
}
78-
// hot-reload
79-
if (!isServer && !isProduction) {
80-
var exportsName = vueOptions.esModule ? 'esExports' : 'module.exports'
81-
code +=
82-
'\nif (module.hot) {\n' +
83-
' module.hot.accept()\n' +
84-
' if (module.hot.data) {\n' +
85-
' require("' + hotReloadAPIPath + '").rerender("' + options.id + '", ' + exportsName + ')\n' +
86-
' }\n' +
87-
'}'
88-
}
50+
var code
51+
if (compiled.errors && compiled.errors.length) {
52+
this.emitError(
53+
`\n Error compiling template:\n${pad(html)}\n` +
54+
compiled.errors.map(e => ` - ${e}`).join('\n') + '\n'
55+
)
56+
code = vueOptions.esModule
57+
? `var esExports = {render:function(){},staticRenderFns: []}\nexport default esExports`
58+
: 'module.exports={render:function(){},staticRenderFns:[]}'
59+
} else {
60+
var bubleOptions = options.buble
61+
code = transpile(
62+
'var render = ' + toFunction(compiled.render) + '\n' +
63+
'var staticRenderFns = [' + compiled.staticRenderFns.map(toFunction).join(',') + ']',
64+
bubleOptions
65+
) + '\n'
66+
// mark with stripped (this enables Vue to use correct runtime proxy detection)
67+
if (!isProduction && (
68+
!bubleOptions ||
69+
!bubleOptions.transforms ||
70+
bubleOptions.transforms.stripWith !== false
71+
)) {
72+
code += `render._withStripped = true\n`
73+
}
74+
var exports = `{ render: render, staticRenderFns: staticRenderFns }`
75+
code += vueOptions.esModule
76+
? `var esExports = ${exports}\nexport default esExports`
77+
: `module.exports = ${exports}`
78+
}
79+
// hot-reload
80+
if (!isServer && !isProduction) {
81+
var exportsName = vueOptions.esModule ? 'esExports' : 'module.exports'
82+
code +=
83+
'\nif (module.hot) {\n' +
84+
' module.hot.accept()\n' +
85+
' if (module.hot.data) {\n' +
86+
' require("' + hotReloadAPIPath + '").rerender("' + options.id + '", ' + exportsName + ')\n' +
87+
' }\n' +
88+
'}'
89+
}
8990

90-
return code
91+
this.callback(null, code)
92+
})
9193
}
9294

9395
function toFunction (code) {

0 commit comments

Comments
 (0)