csmall-theme
Version:
自用资源,不负责对外的使用解答
222 lines (190 loc) • 6.87 kB
JavaScript
/**
加载不同的主题样式
如果是当前主题中的样式,不做特殊处理
如果是主题路径下的文件,替换为当前主题的文件
如果是第三方样式:
首先查看在当前主题下是否有此文件,如有则在之后插入当前主题下的文件
如没有则再查看custom下是否有,如有则在之后插入
**/
const path = require('path');
const fs = require('fs');
let options = {},
resolve = {alias: {}, aliasKeys: []},
sourcePath = path.resolve(process.cwd(), './src');
const defaultOptions = {
styleLibrary: 'style',
customLibrary: 'custom',
themeLibrary: 'theme',
sourcePath: sourcePath,
third: []
};
let stylePath, themePath, customPath, themeLibrary;
const pathDelimiterRegExp = /[\/\\]/;
let addNormalizedDependency;
function loadThemeSource(file, desc){
//console.log('Load style ' + desc + ': ' + file);
return fs.readFileSync(file, 'utf-8');// + "\n/** Theme-loader insert **/\n" + source;
}
function replaceThirdLibrary(file){
if(file.slice(-4) === '.vue'){
return '';
}
for(let i = 0, l = options.third.length; i < l; i++){
if(file.indexOf(options.third[i]) === 0){
let themeFile = path.resolve(themePath, file.slice(options.third[i].length + 1));
themeFile = appendFileExt(themeFile);
if(themeFile){
return themeFile;
}
themeFile = path.resolve(customPath, file.slice(options.third[i].length + 1));
themeFile = appendFileExt(themeFile);
if(themeFile){
return themeFile;
}
return '';
}
}
}
function isFile(file){
try{
return fs.statSync(file).isFile();
}catch(e){
return false;
}
}
function appendFileExt(file){
if(isFile(file)){
return file;
}
if(path.basename(file).charAt(0) !== '_'){
let f = path.resolve(path.dirname(file), '_' + path.basename(file));
if(isFile(f)){
return f;
}
}
if(!path.extname(file)){
file += '.scss';
if(isFile(file)){
return file;
}else{
file = path.resolve(path.dirname(file), '_' + path.basename(file));
if(isFile(file)){
return file;
}
}
}
return '';
}
function replaceThemeFile(file, prev){
if(file.indexOf(themeLibrary) === 0 && file.indexOf(themePath) !== 0){
let fileSuffix = file.slice(themeLibrary.length + 1);
const pathPart = fileSuffix.split(pathDelimiterRegExp);
if(pathPart.length >= 2){
pathPart.shift();
file = path.resolve(themePath, pathPart.join('/'));
let currentFile = appendFileExt(file);
if(currentFile){
return currentFile;
}else{
console.warn('>>>Please edit ' + file + ' for: ' + prev);
}
}
}
return '';
}
function applyTheme(file, source, map){
let themeFile = replaceThemeFile(file, 'entry');
if(themeFile){//加载当前主题的样式
return [themeFile, loadThemeSource(themeFile, 'current[entry]'), map];
}
//看是否是第三方库的样式,尝试替换为自有样式
let thirdFile = replaceThirdLibrary(file);
if(thirdFile){
return [thirdFile, loadThemeSource(thirdFile, 'replace from third[entry]'), map];
}
return [file, source, map];
}
function convertUrlToFile(url, prev){
let replaceEnable = true;
if(url.charAt(0) === '~'){
url = url.slice(1);
let dir = url.split(pathDelimiterRegExp)[0];
if(resolve.alias[dir]){
url = url.slice(dir.length + 1);
prev = resolve.alias[dir];
}else{
prev = path.resolve(path.dirname(sourcePath), resolve.modules[0]);
replaceEnable = false;
}
}else{
prev = path.dirname(prev);
}
return [path.resolve(prev, url), replaceEnable];
}
function addSassLoaderHook(sassLoader){
if(!sassLoader.options){
sassLoader.options = {};
}
if(!sassLoader.options.sassOptions){
sassLoader.options.sassOptions = {};
}
sassLoader.options.sassOptions.importer = function(url, prev, done){
let [file, replaceAble] = convertUrlToFile(url, prev);
if(!replaceAble){//强制加载第三方库样式,为避免循环引入,不允许替换
let fullFile = appendFileExt(file);
addNormalizedDependency(file);
return {file: fullFile, contents: loadThemeSource(fullFile, 'not allow replace')};
}
let fullFile = replaceThemeFile(file, prev);
if(fullFile){//加载当前主题样式
addNormalizedDependency(file);
return {file: fullFile, contents: loadThemeSource(fullFile, 'current')};
}
let source = '';
let thirdFile = replaceThirdLibrary(file);//看是否是第三方库的样式,尝试替换为自有样式
if(thirdFile){//将第三方样式替换为自有样式
source = loadThemeSource(thirdFile, 'replace from third');
file = thirdFile;
}else{//直接加载
fullFile = appendFileExt(file);
if(fullFile){
source = loadThemeSource(fullFile, 'fallback');
}else{
console.warn('Theme file not exists: ' + file + ' for: ' + prev);
}
}
addNormalizedDependency(file);
return {file: file, contents: source};
};
}
function processOptions(loader){
options = loader.options || {};
Object.keys(defaultOptions).map(key => {
if(!options[key]){
options[key] = defaultOptions[key];
}
});
if(!options.theme){
console.warn('The theme-loader\'s option "theme" not defined');
}
sourcePath = path.resolve(options['sourcePath'], './');
stylePath = path.resolve(sourcePath + '/' + options.styleLibrary, './');
themeLibrary = path.resolve(stylePath + '/' + options.themeLibrary, './');
themePath = path.resolve(themeLibrary + '/' + options.theme, './');
customPath = path.resolve(stylePath + '/' + options.customLibrary, './');
}
module.exports = function(source, map){
const processed = applyTheme(this.resourcePath, source, map);
this.resourcePath = processed[0];
this.callback(null, processed[1], processed[2]);
};
module.exports.pitch = function(){
resolve = this._compiler.options.resolve;
resolve.aliasKeys = Object.keys(resolve.alias);
addNormalizedDependency = file => {
// node-sass returns POSIX paths
this.dependency(path.normalize(file));
};
processOptions(this.loaders[this.loaderIndex]);
addSassLoaderHook(this.loaders[this.loaderIndex - 1]);
};