san-loader
Version:
San single-file loader for Webpack
80 lines (70 loc) • 2.24 kB
JavaScript
/**
* Copyright (c) Baidu Inc. All rights reserved.
*
* This source code is licensed under the MIT license.
* See LICENSE file in the project root for license information.
*
* @file preparse.js
* @author wangjinghao <wangjinghao@baidu.com>
*/
const hash = require('hash-sum');
const postcss = require('postcss').default;
const render = require('dom-serializer').default;
const {getAST} = require('./helper');
const postcssPlugin = require('./set-scope-id');
const addId = (node, id) => {
if (!node.attribs) {
node.attribs = {};
}
node.attribs[`data-s-${id}`] = '';
if (node.children) {
node.children.map(c => addId(c, id));
}
return node;
};
/**
* 预处理template增加属性,读出设置scoped的style模块重写选择器
*
* @param {string} source .san代码文本
* @param {string} resourcePath 资源路径 for preparse
* @param {boolean} autoAddScriptTag 是否自动添加script标签
* @return {string} 转换完的代码文本
*/
module.exports = function(source, resourcePath, autoAddScriptTag) {
const id = hash(resourcePath);
let ast = getAST(source);
let hasScope = false;
let noScript = true;
for (let node of ast) {
if (node.name === 'script') {
noScript = false;
}
if (node.name === 'style' && node.attribs && Reflect.has(node.attribs, 'scoped')) {
hasScope = true;
if (node.children && node.children.length) {
node.children[0].data = postcss([postcssPlugin(`data-s-${id}`)]).process(node.children[0].data).css;
}
}
}
for (let node of ast) {
if (hasScope && node.name === 'template' && node.children && node.children.length) {
for (let tag of node.children) {
tag.type === 'tag' && addId(tag, id);
}
}
}
// 这里可以通过自己配置是否要补全script
if (autoAddScriptTag && noScript) {
ast.push({
type: 'tag',
name: 'script',
children: [{
type: 'text',
data: 'export default {};'
}]
});
}
return render(ast, {
decodeEntities: false
});
};