Skip to content
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

Merged
merged 18 commits into from
Apr 1, 2017
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
11 changes: 7 additions & 4 deletions packages/wepy-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,17 @@
"babel-preset-stage-1": "^6.16.0"
},
"dependencies": {
"js-base64": "^2.1.9",
"chokidar": "^1.6.1",
"colors": "^1.1.2",
"commander": "^2.9.0",
"mkdirp": "^0.5.1",
"compare-versions": "^3.0.0",
"hash-sum": "^1.0.2",
"ignore": "^3.2.0",
"js-base64": "^2.1.9",
"mkdirp": "^0.5.1",
"postcss": "^5.2.16",
"postcss-selector-parser": "^2.2.3",
"update-notifier": "^1.0.2",
"xmldom": "^0.1.22",
"compare-versions": "^3.0.0"
"xmldom": "^0.1.22"
}
}
59 changes: 43 additions & 16 deletions packages/wepy-cli/src/compile-style.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,64 @@ import util from './util';
import cache from './cache';

import loader from './loader';

import scopedHandler from './style-compiler/scoped';

const LANG_MAP = {
'less': '.less',
'sass': '.sass;.scss'
};

export default {
compile (lang, content, requires, opath) {
compile (styles, requires, opath, moduleId) {
let config = util.getConfig();
let src = cache.getSrc();
let dist = cache.getDist();
let ext = cache.getExt();

if (arguments.length === 2) {
if (typeof styles === 'string') {
// .compile('less', opath) 这种形式
opath = requires;
requires = [];
opath = content;
content = util.readFile(path.join(opath.dir, opath.base));
moduleId = '';
styles = [{
type: styles,
scoped: false,
code: util.readFile(path.join(opath.dir, opath.base)) || ''
}];
}
let allPromises = [];

if (lang === 'scss')
lang = 'sass';
// styles can be an empty array
styles.forEach((style) => {
let lang = style.type || 'css';
const content = style.code;
const scoped = style.scoped;

let compiler = loader.loadCompiler(lang);
if (lang === 'scss')
lang = 'sass';

if (!compiler) {
throw `未发现相关 ${lang} 编译器配置,请检查wepy.config.js文件。`;
}
let compiler = loader.loadCompiler(lang);

compiler(content, config.compilers[lang] || {}, path.join(opath.dir, opath.base)).then((css) => {
if (!compiler) {
throw `未发现相关 ${lang} 编译器配置,请检查wepy.config.js文件。`;
}

const p = compiler(content, config.compilers[lang] || {}, path.join(opath.dir, opath.base)).then((css) => {
// 处理 scoped
if (scoped) {
// 存在有 scoped 的 style
return scopedHandler(moduleId, css).then((cssContent) => {
return cssContent;
});
} else {
return css;
}
});

allPromises.push(p);
});
Promise.all(allPromises).then((rets) => {
let allContent = rets.join('');
if (requires && requires.length) {
requires.forEach((r) => {
let comsrc = util.findComponent(r);
Expand All @@ -51,24 +79,23 @@ export default {
let code = util.readFile(comsrc);
if (isNPM || /<style/.test(code)) {
relative = relative.replace(ext, '.wxss').replace(/\\/ig, '/').replace('../', './');
css = '@import "' + relative + '";\n' + css;
allContent = '@import "' + relative + '";\n' + allContent;
}
}
});
}

let target = util.getDistPath(opath, 'wxss', src, dist);

let plg = new loader.PluginHelper(config.plugins, {
type: 'css',
code: content,
code: allContent,
file: target,
output (p) {
util.output(p.action, p.file);
},
done (rst) {
util.output('写入', rst.file);
util.writeFile(target, css);
util.writeFile(target, rst.code);
}
});
}).catch((e) => {
Expand Down
181 changes: 120 additions & 61 deletions packages/wepy-cli/src/compile-wpy.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,71 +68,101 @@ 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 (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);

if (content === null) {
util.error('打开文件失败: ' + filepath)
return;
}
let startlen = content.indexOf('<script') + 7;
while(content[startlen++] !== '>') {
// do nothing;
// 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 = {
moduleId: moduleId,
style: [],
template: {
code: '',
src: '',
type: ''
},
script: {
code: '',
src: '',
type: ''
}
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);

xml = this.createParser().parseFromString(content);
}
[].slice.call(xml.childNodes || []).forEach((child) => {
const nodeName = child.nodeName;
if (nodeName === 'style' || nodeName === 'template' || nodeName === 'script') {
let rstTypeObj;

let rst = {style: {code: ''}, template: {code: ''}, script: {code: ''}};
if (nodeName === 'style') {
rstTypeObj = {code: ''};
rst[nodeName].push(rstTypeObj);
} else {
rstTypeObj = rst[nodeName];
}

[].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');
rstTypeObj.src = child.getAttribute('src');
rstTypeObj.type = child.getAttribute('lang') || child.getAttribute('type');
if (nodeName === 'style') {
// 针对于 style 增加是否包含 scoped 属性
rstTypeObj.scoped = child.getAttribute('scoped') ? true : false;
}

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.mergeWpy(rst);

/*
Use components instead
Expand All @@ -141,7 +171,6 @@ export default {
}*/

// default type
rst.style.type = rst.style.type || 'css';
rst.template.type = rst.template.type || 'wxml';
rst.script.type = rst.script.type || 'babel';

Expand Down Expand Up @@ -275,6 +304,14 @@ export default {
}
})();

if (rst.style.some(v => v.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;
},

Expand All @@ -301,9 +338,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)) {
Expand All @@ -329,30 +363,42 @@ export default {

if (type === 'app') { // 第一个编译
cache.setPages(wpy.config.pages.map(v => path.join(src, v + wpyExt)));

// scoped 设置无效
wpy.style.forEach(rst => rst.scoped = false);

// 无template
delete wpy.template;

} else if (type === 'component') {
delete wpy.config;
}

if (wpy.config) {
cConfig.compile(wpy.config, opath);
} else {
this.remove(opath, 'json');
}
if (wpy.style.code || Object.keys(wpy.template.components).length) {

if (wpy.style.length || (wpy.template && Object.keys(wpy.template.components).length)) {
let requires = [];
let k, tmp;
for (k in wpy.template.components) {
tmp = wpy.template.components[k];
if (tmp.indexOf('.') === -1) {
requires.push(tmp); // 第三方组件
} else {
requires.push(path.join(opath.dir, wpy.template.components[k]));
if (wpy.template) {
for (k in wpy.template.components) {
tmp = wpy.template.components[k];
if (tmp.indexOf('.') === -1) {
requires.push(tmp); // 第三方组件
} else {
requires.push(path.join(opath.dir, wpy.template.components[k]));
}
}
}
cStyle.compile(wpy.style.type, wpy.style.code, requires, opath);
cStyle.compile(wpy.style, requires, opath, wpy.moduleId);
} else {
this.remove(opath, 'wxss');
}

if (wpy.template.code && (type !== 'app' && type !== 'component')) { // App 和 Component 不编译 wxml
if (wpy.template && wpy.template.code && type !== 'component') { // App 和 Component 不编译 wxml
//cTemplate.compile(wpy.template.type, wpy.template.code, opath);
cTemplate.compile(wpy.template);
}
Expand All @@ -362,3 +408,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);
}
});
}
}
Loading