webpack-theme-color-replacer
Version:
A webpack plugin designed to dynamicly change the theme colors at runtime. 实现运行时快速动态替换主题色的webpack插件.
121 lines (107 loc) • 4.85 kB
JavaScript
var path = require('path')
var fs = require('fs')
var Extractor = require('./Extractor')
/* emit钩子的代码处理 */
// Module\nexports.push([module.i, \"h1... ;\\n}\\n\", \"\",{\"version\":3,\"
//css-loader 2: \n// Module\nexports.push([module.i, \"a{ ...... }\\n\", \"\",{\"version\":3,
//css-loader 1: \n// module\nexports.push([module.i, \"a{ ...... }\\n\", \"\"]);
//css-loader 2@srcmap: // Module\nexports.push([module.i, "a{ ..... }\n", "",{"version":3
//css-loader@srcmap.less // Module\nexports.push([module.i, "a{ ..... ;\n }\n}\n\n\n/*# sourceMappingURL=antd.css.map*/", "",{"version":3,"
//css-loader 5.1: ___CSS_LOADER_EXPORT___.push([module.id, "a {\n ... \n }\n}\n"],"sourceRoot":""}]);
/*css-loader 6.8: ___CSS_LOADER_EXPORT___.push([module.id, `.c222 {
border: 1px #ADF solid;;
}
`, ""]);*/
//css-loader 6.8 debug: // Module\n___CSS_LOADER_EXPORT___.push([module.id, `.test-class {... }\n`, \"\"]);\n
var Css_Loader_Reg_DEV = /\bn?(?:exports|___CSS_LOADER_EXPORT___)\.push\(\[module\.id?, \\*["`]([\s\S]+?\})(?:\\*\\n)?(?:[\\n]*\/\*#\s*sourceMappingURL=.+?\*\/)?\s*\\*["`], \\*"\\*"(?:\]\)|,\s*\{)/g;
//css-loader: n.exports=t("FZ+f")(!1)).push([n.i,"\n.payment-type[data-v-ffb10066] {......}\n",""])
var Css_Loader_Reg_UGLY = /\.push\(\[\w+\.i,['"](.+?\})[\\rn]*['"],['"]['"](?:\]\)|,\{)/g;
var CssExtReg = /\.css$/i, JsExtReg = /\.js$/i
module.exports = function AssetsExtractor(options) {
this.extractor = new Extractor(options)
this.extractAssets = function (assets) {
var srcArray = this.extractToArray(assets);
// 外部的css文件。如cdn加载的
if (options.externalCssFiles) {
[].concat(options.externalCssFiles).map(file => {
var src = fs.readFileSync(file, 'utf-8')
var css = this.extractor.extractColors(src)
srcArray = srcArray.concat(css)
})
}
var output = dropDuplicate(srcArray).join('\n');
// 自定义后续处理
if (options.resolveCss) {
output = options.resolveCss(output, srcArray)
}
return output
}
this.extractToArray = function (assets) {
var srcArray = extractAll(this)
if (srcArray.length === 0 && !this._uglyChanged) {
// 容错一次
this._uglyChanged = true
options.isJsUgly = !options.isJsUgly
//清空缓存
Object.keys(assets).map(fn => assets[fn]._themeCssCache = 0)
srcArray = extractAll(this)
}
return srcArray;
function extractAll(that) {
var cssSrcs = [];
Object.keys(assets).map(fn => {
// 原本每修改一点源码,都需要对整个项目的assets翻一遍css,影响性能。
// 故改为在asset上缓存上一次的结果,对没发生变化的asset直接取缓存(已发生变化的asset已经是新对象,无缓存)。
var asset = assets[fn]
var cssRules = asset._themeCssCache || that.extractAsset(fn, asset)
asset._themeCssCache = cssRules
cssSrcs = cssSrcs.concat(cssRules)
});
return cssSrcs
}
}
this.extractAsset = function (fn, asset) {debugger
if (fn.match(CssExtReg)) {
var src = assetToStr(asset);
writeFileForDebugIf(fn, src, this.extractor)
return this.extractor.extractColors(src);
} else if (fn.match(JsExtReg)) {
src = assetToStr(asset);
writeFileForDebugIf(fn, src, this.extractor)
var cssSrcs = []
var CssCodeReg = options.isJsUgly ? Css_Loader_Reg_UGLY : Css_Loader_Reg_DEV;
src.replace(CssCodeReg, (match, $1) => {
cssSrcs = cssSrcs.concat(this.extractor.extractColors($1));
});
return cssSrcs
}
return []
function writeFileForDebugIf(fn, src, extractor) {
// `npm run dev --theme_debug` to write asset files for debug
if (process.env.npm_config_theme_debug) {
try {
if (extractor.testCssCode(src)) {
var info = '/*var theme_cfg=' + JSON.stringify(options) + '*/\n' + src
fs.writeFileSync(path.join(process.cwd(), '_tmp_' + path.basename(fn)), info)
}
} catch (e) {
}
}
}
}
};
function assetToStr(asset) {
var src = asset.source() || '';
return src.toString();
}
function dropDuplicate(arr) {
var map = {}
var r = []
for (var s of arr) {
if (!map[s]) {
r.push(s)
map[s] = 1
}
}
return r
}