Skip to content

Commit

Permalink
feat(cli): 增加快应用子组件定制规则,减少快应用端的预览错误 (#4436)
Browse files Browse the repository at this point in the history
  • Loading branch information
Qiyu8 authored and luckyadam committed Sep 19, 2019
1 parent 54b3daa commit 708ceb9
Show file tree
Hide file tree
Showing 20 changed files with 283 additions and 1 deletion.
1 change: 1 addition & 0 deletions packages/taro-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
"prop-types": "^15.6.2",
"request": "^2.88.0",
"resolve": "^1.6.0",
"sax": "^1.2.4",
"semver": "^5.5.0",
"shelljs": "^0.8.1",
"stylelint": "9.3.0",
Expand Down
3 changes: 2 additions & 1 deletion packages/taro-cli/src/mini/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { compileDepStyles } from './compileStyle'
import { transfromNativeComponents, processNativeWxml } from './native'
import { buildDepComponents } from './component'
import { parseAst } from './astProcess'
import rewriterTemplate from '../quickapp/template-rewriter'

// 小程序页面编译
export async function buildSinglePage (page: string) {
Expand Down Expand Up @@ -193,7 +194,7 @@ export async function buildSinglePage (page: string) {
script: resCode,
style: styleRelativePath,
imports: new Set([...importTaroSelfComponents, ...importCustomComponents, ...importUsingComponent]),
template: pageWXMLContent
template: rewriterTemplate(pageWXMLContent)
})
fs.writeFileSync(outputPageWXMLPath, uxTxt)
printLog(processTypeEnum.GENERATE, '页面文件', `${outputDirName}/${page}${outputFilesTypes.TEMPL}`)
Expand Down
13 changes: 13 additions & 0 deletions packages/taro-cli/src/quickapp/template-rewriter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import parseXml from './template/parser'
import rewriteNode from './template/node'
import serialize from './template/serialize'

export default function rewriterTemplate(code : string): string {
// 解析Code
const viewNodes = parseXml(`<root>${code}</root>`).children
// 解析视图组件
const retNodes = rewriteNode(viewNodes)
// 生成xml代码
const templateCode = serialize(retNodes)
return templateCode
}
14 changes: 14 additions & 0 deletions packages/taro-cli/src/quickapp/template/constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

interface Location {
line: number;
column: number;
}

export interface NodeType {
attributes: object;
children: object[];
isSelfClosing: boolean;
location: Location;
name: string;
parent?: object;
}
45 changes: 45 additions & 0 deletions packages/taro-cli/src/quickapp/template/node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import parserTag from './tag'
import {uniqTypeof} from './utils'
import { NodeType } from './constant'

const walk = (node) => {
// 获取quickapp需处理的组件名称
const tags = parserTag('.', {})
const component = tags[node.name]
if (component) {
// 组件不支持子组件,则将子组件注释
if (component.subcomponent && (node.children && node.children.length)) {
node.$delete = true
node.url = component.url || 'https://doc.quickapp.cn/widgets/common-events.html'
return
}

if (uniqTypeof(component.name) === 'function') {
node.name = component.name(node)
const children = node.children
children && children.forEach(childNode => {
if (childNode.parent && childNode.parent.name) {
childNode.parent.name = node.name
}
})
} else {
node.name = component.name
}
}
const children = node.children
if (children.length) {
children.forEach(childNode => {
walk(childNode)
})
}
}

export default function rewriteNode (nodes) {
const retNodes: NodeType[] = []
nodes.forEach(node => {
retNodes.push(node)
})
retNodes.forEach(node => walk(node))
return retNodes

}
52 changes: 52 additions & 0 deletions packages/taro-cli/src/quickapp/template/parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const sax = require('sax')
import { NodeType } from './constant'

export default function parseCode (code: string): NodeType {
const parser = sax.parser(false, {
trim: true,
lowercase: true,
position: true
})

let root
let currentParent
const stack: any[] = []

parser.onerror = function(e) {
console.log(e)
}

parser.oncdata = function(t) {
currentParent && (currentParent.content = t.trim() || '')
}

parser.ontext = function(t) {
currentParent && (currentParent.content = t.trim() || '')
}

parser.onopentag = function (node) {
node.children = []
node.location = {
line: this.line,
column: this.column
}
if (!root) {
root = node
}
if (currentParent) {
node.parent = currentParent
currentParent.children.push(node)
}
currentParent = node
stack.push(currentParent)
}

parser.onclosetag = function() {
stack.length -= 1
currentParent = stack[stack.length - 1]
}

parser.write(code).close()

return root
}
50 changes: 50 additions & 0 deletions packages/taro-cli/src/quickapp/template/serialize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { addComment } from "./utils";

const ATTRS_NAME = ['checked', 'disabled']

const createAttrsCode = (attrs) => {
if (!attrs) {
return ''
}
let attrsCode = ''
const attrsKey = Object.keys(attrs)
if (attrsKey.length) {
attrsCode = ' ' + attrsKey.map(name => {
if (!attrs[name] && ~ATTRS_NAME.indexOf(name)) {
return `${name}='true'`
}
return name === 'else' ? `${name}` : `${name}='${attrs[name]}'`
}).join(' ')
}
return attrsCode
}

const createNodeCode = (name, children, content, attrsCode, $delete, url) => {
let childrenNodes = children.map(childNode => {
return walk(childNode)
}).join('')
// 针对不支持子组件的组件,子组件需注释
childrenNodes = $delete ? addComment(childrenNodes, url) : childrenNodes
return `<${name}${attrsCode}>${content || ''}${childrenNodes}</${name}>`
}

const walk = (node) => {
const attrsCode = createAttrsCode(node.attributes)
const nodeCode = createNodeCode(
node.name,
node.children,
node.content,
attrsCode,
node.$delete,
node.url
)
return nodeCode
}

export default function serialize(nodes) {
if (!Array.isArray(nodes)) {
nodes = [nodes]
}
const code = nodes.map(node => walk(node)).join('\r\n')
return code
}
23 changes: 23 additions & 0 deletions packages/taro-cli/src/quickapp/template/tag/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import * as fs from 'fs-extra'
import * as path from 'path'

export default function parseTag (dir: string, tags={}) {
dir = dir || '.'
const dirPath = path.join(__dirname, dir)
const walk = (file) => {
const filePath = path.join(dirPath, file)
if (fs.statSync(filePath).isFile()) {
if (path.extname(filePath) === '.js') {
const tagName = path.basename(path.dirname(filePath))
if (tagName !== 'tag') {
const component = require(filePath)['default']
tags[tagName] = component
}
}
} else {
parseTag(path.join(dir, file), tags)
}
}
fs.readdirSync(dirPath).forEach(walk)
return tags
}
8 changes: 8 additions & 0 deletions packages/taro-cli/src/quickapp/template/tag/span/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default {
name (node) {
if (node.parent && node.parent.name === 'div') {
return 'text'
}
return node.name
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
name: 'taro-camera',
subcomponent: 'I:',
url: 'https://doc.quickapp.cn/widgets/camera.html'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
name: 'taro-canvas',
subcomponent: 'I:',
url: 'https://doc.quickapp.cn/widgets/canvas.html'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
name: 'taro-image',
subcomponent: 'I:',
url: 'https://doc.quickapp.cn/widgets/image.html'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
name: 'taro-input',
subcomponent: 'I:',
url: 'https://doc.quickapp.cn/widgets/input.html'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
name: 'taro-label',
subcomponent: 'I:',
url: 'https://doc.quickapp.cn/widgets/label.html'
}
5 changes: 5 additions & 0 deletions packages/taro-cli/src/quickapp/template/tag/taro-map/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
name: 'taro-map',
subcomponent: 'I:',
url: 'https://doc.quickapp.cn/widgets/map.html'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
name: 'taro-picker',
subcomponent: 'I:',
url: 'https://doc.quickapp.cn/widgets/picker.html'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
name: 'taro-textarea',
subcomponent: 'I:',
url: 'https://doc.quickapp.cn/widgets/textarea.html'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
name: 'taro-video',
subcomponent: 'I:',
url: 'https://doc.quickapp.cn/widgets/video.html'
}
8 changes: 8 additions & 0 deletions packages/taro-cli/src/quickapp/template/tag/text/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default {
name (node) {
if (node.parent && ['text', 'span'].includes(node.parent.name)) {
return 'span'
}
return node.name
}
}
22 changes: 22 additions & 0 deletions packages/taro-cli/src/quickapp/template/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

const comment = (msg, url) => 'Taro comment: ' + msg + '.' + (url ? '[兼容写法参考](' + url + ')' : '')

// 注释子组件
export const addComment = (childNode, url) => `<!--${comment('unsupported subcomponent', url)}${childNode}-->`

export const uniqTypeof = (name: string) => {
const typeMap = {
'[object Boolean]': 'boolean',
'[object String]': 'string',
'[object Number]': 'number',
'[object Function]': 'function',
'[object Array]': 'array',
'[object Date]': 'date',
'[object RegExp]': 'regExp',
'[object Null]': 'null',
'[object Undefined]': 'undefined',
'[object Symbol]': 'symbol',
'[object Object]': 'object',
}
return typeMap[Object.prototype.toString.call(name)]
}

0 comments on commit 708ceb9

Please sign in to comment.