-
Notifications
You must be signed in to change notification settings - Fork 3k
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
add style scoped #86
add style scoped #86
Changes from 6 commits
1f01ad7
c4efd50
131e194
61b0471
8fab9a6
76236bd
5f96600
2863978
2f1e347
e3583f0
93eb497
c398708
b17ccda
809d6f5
41c1ff1
81e332a
5101076
d7ab267
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,72 +68,106 @@ export default { | |
let config = util.getConfig(); | ||
let filepath; | ||
|
||
if (arguments.length === 1) { | ||
|
||
if (typeof(xml) === 'object' && xml.dir) { | ||
opath = xml; | ||
filepath = path.join(xml.dir, xml.base); | ||
} else { | ||
opath = path.parse(xml); | ||
filepath = xml; | ||
} | ||
let content = util.readFile(filepath); | ||
|
||
if (content === null) { | ||
util.error('打开文件失败: ' + filepath) | ||
return; | ||
} | ||
let startlen = content.indexOf('<script') + 7; | ||
while(content[startlen++] !== '>') { | ||
// do nothing; | ||
} | ||
content = util.encode(content, startlen, content.indexOf('</script>') - 1); | ||
|
||
// replace :attr to v-bind:attr | ||
/*content = content.replace(/<[\w-\_]*\s[^>]*>/ig, (tag) => { | ||
return tag.replace(/\s+:([\w-_]*)([\.\w]*)\s*=/ig, (attr, name, type) => { // replace :param.sync => v-bind:param.sync | ||
if (type === '.once' || type === '.sync') { | ||
} | ||
else | ||
type = '.once'; | ||
return ` v-bind:${name}${type}=`; | ||
}).replace(/\s+\@([\w-_]*)\s*=/ig, (attr, name) => { // replace @change => v-on:change | ||
return `v-on:${name}`; | ||
}); | ||
})*/ | ||
|
||
content = util.attrReplace(content); | ||
if (typeof(xml) === 'object' && xml.dir) { | ||
opath = xml; | ||
filepath = path.join(xml.dir, xml.base); | ||
} else { | ||
opath = path.parse(xml); | ||
filepath = xml; | ||
} | ||
let content = util.readFile(filepath); | ||
|
||
xml = this.createParser().parseFromString(content); | ||
if (content === null) { | ||
util.error('打开文件失败: ' + filepath) | ||
return; | ||
} | ||
let startlen = content.indexOf('<script') + 7; | ||
while(content[startlen++] !== '>') { | ||
// do nothing; | ||
} | ||
content = util.encode(content, startlen, content.indexOf('</script>') - 1); | ||
|
||
let rst = {style: {code: ''}, template: {code: ''}, script: {code: ''}}; | ||
// replace :attr to v-bind:attr | ||
/*content = content.replace(/<[\w-\_]*\s[^>]*>/ig, (tag) => { | ||
return tag.replace(/\s+:([\w-_]*)([\.\w]*)\s*=/ig, (attr, name, type) => { // replace :param.sync => v-bind:param.sync | ||
if (type === '.once' || type === '.sync') { | ||
} | ||
else | ||
type = '.once'; | ||
return ` v-bind:${name}${type}=`; | ||
}).replace(/\s+\@([\w-_]*)\s*=/ig, (attr, name) => { // replace @change => v-on:change | ||
return `v-on:${name}`; | ||
}); | ||
})*/ | ||
|
||
content = util.attrReplace(content); | ||
|
||
xml = this.createParser().parseFromString(content); | ||
|
||
const moduleId = util.genId(filepath); | ||
|
||
let rst = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 其实对于 template 和 script 来说,多个标签完全是没有意义的事情,所以我觉得这里完全可以将 style 定义为数组,其它的就定义成 object There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这里其实做的时候考虑 把他们合并成一块,我觉得如果要约定的话,就可以直接约定死 style 可以是多个,template 和 script 最多只能有一个,如果发现出现多个,是否可以直接强制报错了? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 对的。这样实现最好,如果不报错,那默认也是被覆盖。 |
||
moduleId: moduleId, | ||
style: { | ||
code: '', | ||
src: '', | ||
type: '', | ||
blocks: [] | ||
}, | ||
template: { | ||
code: '', | ||
src: '', | ||
type: '', | ||
blocks: [] | ||
}, | ||
script: { | ||
code: '', | ||
src: '', | ||
type: '', | ||
blocks: [] | ||
} | ||
}; | ||
|
||
[].slice.call(xml.childNodes || []).forEach((child) => { | ||
if (child.nodeName === 'style' || child.nodeName === 'template' || child.nodeName === 'script') { | ||
rst[child.nodeName].src = child.getAttribute('src'); | ||
rst[child.nodeName].type = child.getAttribute('lang') || child.getAttribute('type'); | ||
const nodeName = child.nodeName; | ||
if (nodeName === 'style' || nodeName === 'template' || nodeName === 'script') { | ||
const blocks = rst[nodeName].blocks; | ||
const rstTypeObj = { | ||
code: '' | ||
}; | ||
blocks.push(rstTypeObj); | ||
|
||
rstTypeObj.src = child.getAttribute('src'); | ||
rstTypeObj.type = child.getAttribute('lang') || child.getAttribute('type'); | ||
if (nodeName === 'style') { | ||
// 针对于 style 增加是否包含 scoped 属性 | ||
rstTypeObj.scoped = child.getAttribute('scoped'); | ||
} | ||
|
||
if (rst[child.nodeName].src) { | ||
rst[child.nodeName].src = path.resolve(opath.dir, rst[child.nodeName].src); | ||
if (rstTypeObj.src) { | ||
rstTypeObj.src = path.resolve(opath.dir, rstTypeObj.src); | ||
} | ||
|
||
if (rst[child.nodeName].src && util.isFile(rst[child.nodeName].src)) { | ||
rst[child.nodeName].code = util.readFile(rst[child.nodeName].src, 'utf-8'); | ||
if (rst[child.nodeName].code === null) { | ||
throw '打开文件失败: ' + rst[child.nodeName].src; | ||
if (rstTypeObj.src && util.isFile(rstTypeObj.src)) { | ||
const fileCode = util.readFile(rstTypeObj.src, 'utf-8'); | ||
if (fileCode === null) { | ||
throw '打开文件失败: ' + rstTypeObj.src; | ||
} else { | ||
rstTypeObj.code += fileCode; | ||
} | ||
} else { | ||
[].slice.call(child.childNodes || []).forEach((c) => { | ||
rst[child.nodeName].code += util.decode(c.toString()); | ||
rstTypeObj.code += util.decode(c.toString()); | ||
}); | ||
} | ||
|
||
if (!rst[child.nodeName].src) | ||
rst[child.nodeName].src = path.join(opath.dir, opath.name + opath.ext); | ||
if (!rstTypeObj.src) | ||
rstTypeObj.src = path.join(opath.dir, opath.name + opath.ext); | ||
} | ||
}); | ||
|
||
util.computedWpyFile(rst); | ||
|
||
/* | ||
Use components instead | ||
if (rst.template.code) { | ||
|
@@ -275,6 +309,14 @@ export default { | |
} | ||
})(); | ||
|
||
if (rst.style.scoped && rst.template.code) { | ||
// 存在有 scoped 部分就需要 更新 template.code | ||
var node = this.createParser().parseFromString(rst.template.code); | ||
walkNode(node, rst.moduleId); | ||
// 更新 template.code | ||
rst.template.code = node.toString(); | ||
} | ||
|
||
return rst; | ||
}, | ||
|
||
|
@@ -301,9 +343,6 @@ export default { | |
let pages = cache.getPages(); | ||
|
||
let type = ''; | ||
|
||
let rst = {style: {code: ''}, template: {code: ''}, script: {code: ''}}; | ||
|
||
let relative = path.relative(util.currentDir, filepath); | ||
|
||
if (filepath === path.join(util.currentDir, src, 'app' + wpyExt)) { | ||
|
@@ -343,7 +382,13 @@ export default { | |
requires.push(path.join(opath.dir, wpy.template.components[k])); | ||
} | ||
} | ||
cStyle.compile(wpy.style.type, wpy.style.code, requires, opath); | ||
if (type === 'app') { | ||
// 如果是 app 没有 wxml 所以这里不能做替换 | ||
// 强制 scoped = '' 也就是在 app.wpy 中 | ||
// 设置 scoped 无效 | ||
wpy.style.scoped = ''; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. scoped 目前只存在两个值, true or false, 所以使用 boolean 写代码时可能更好理解。 |
||
} | ||
cStyle.compile(wpy.style, requires, opath, wpy.moduleId); | ||
} else { | ||
this.remove(opath, 'wxss'); | ||
} | ||
|
@@ -358,3 +403,16 @@ export default { | |
} | ||
} | ||
}; | ||
|
||
function walkNode (node, moduleId) { | ||
if (node.childNodes) { | ||
[].slice.call(node.childNodes || []).forEach((child) => { | ||
if (child.tagName) { | ||
// 是标签 则增加class | ||
const cls = child.getAttribute('class'); | ||
child.setAttribute('class', (cls + ' ' + moduleId).trim()); | ||
walkNode(child, moduleId); | ||
} | ||
}); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// copy https://github.com/vuejs/vue-loader/blob/master/lib/style-compiler/plugins/scope-id.js and fix by wepy | ||
|
||
import postcss from 'postcss'; | ||
import selectorParser from 'postcss-selector-parser'; | ||
|
||
export default postcss.plugin('add-id', function (id) { | ||
return function (root) { | ||
root.each(function rewriteSelector (node) { | ||
if (!node.selector) { | ||
// handle media queries | ||
if (node.type === 'atrule' && node.name === 'media') { | ||
node.each(rewriteSelector); | ||
} | ||
return; | ||
} | ||
node.selector = selectorParser(function (selectors) { | ||
selectors.each(function (selector) { | ||
var node = null; | ||
selector.each(function (n) { | ||
if (n.type !== 'pseudo') node = n; | ||
}); | ||
selector.insertAfter(node, selectorParser.className({ | ||
value: id | ||
})); | ||
}); | ||
}).process(node.selector).result; | ||
}); | ||
}; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typeof 为 string 时 filepath 此时应该是undefined吧,这里应该是个BUG
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我的锅