UNPKG

webpack-theme-color-replacer

Version:

A webpack plugin designed to dynamicly change the theme colors at runtime. 实现运行时快速动态替换主题色的webpack插件.

130 lines (117 loc) 5.61 kB
'use strict'; var webpack = require('webpack') var AssetsExtractor = require('./AssetsExtractor') var replaceFileName = require('./replaceFileName') var LineReg = /\n/g var wpSources = webpack.sources if (!wpSources) { wpSources = require('webpack-sources') // for webpack 4 } module.exports = class Handler { constructor(options) { // Default options this.options = Object.assign({ fileName: 'css/theme-colors-[contenthash:8].css', matchColors: [], isJsUgly: !(process.env.NODE_ENV === 'development' || process.argv.find(arg => arg.match(/\bdev/))), // 开发环境,由于webpack有代码编译缓存,会导致configVar不匹配先前编译缓存的代码,而出现win()[WP_THEME_CONFIG]为空。故开发环境固定使用tc_cfg_dev。 // 如需要多个插件并存可显式传入options.configVer configVar: process.env.NODE_ENV === 'development' ? 'tc_cfg_dev' : ('tc_cfg_' + Math.random().toString().slice(2)), }, options); this.assetsExtractor = new AssetsExtractor(this.options) } // Add Webpack5 Support emitSource(compilation, name, source) { var exists = compilation.assets[name] if (compilation.updateAsset) { // webpack.version[0] >= '5' if (exists) compilation.updateAsset(name, source) else compilation.emitAsset(name, source); } else { if (exists) delete compilation.assets[name] compilation.assets[name] = source; } } handle(compilation) { var output = this.assetsExtractor.extractAssets(compilation.assets); console.log('Extracted theme color css content length: ' + output.length); //Add to assets for output var outputName = getFileName(this.options.fileName, output) this.emitSource(compilation, outputName, new wpSources.RawSource(output)) var injectToHtmlReg = this.options.injectToHtml; if (injectToHtmlReg) { //injectToHtml配置一个正则表达式或true if (!injectToHtmlReg.test) injectToHtmlReg = /index\.html?$/i // 解决 webpack splitchunks导致chunk缓存不生效问题 this.addToHtml(outputName, compilation, output, injectToHtmlReg); } else { // 记录动态的文件名,到每个入口js this.addToEntryJs(outputName, compilation, output) } function getFileName(fileName, src) { return compilation.getPath(replaceFileName(fileName, src), {}) } } addToHtml(outputName, compilation, cssCode, injectToHtmlReg) { var assetsNames = Object.keys(compilation.assets).filter((assetName) => { return injectToHtmlReg.test(assetName); }); assetsNames.map(name => { var source = compilation.assets[name]; var configJs = this.getConfigJs(outputName, cssCode) var content = source.source().replace(/(\<|\\x3C)script/i, m => '<script>' + configJs + '</script>\n' + m); this.emitSource(compilation, name, new wpSources.RawSource(content)) }); } // 自动注入js代码,设置css文件名 addToEntryJs(outputName, compilation, cssCode) { var onlyEntrypoints = { entrypoints: true, errorDetails: false, modules: false, assets: false, children: false, chunks: false, chunkGroups: false } var entrypoints = compilation.getStats().toJson(onlyEntrypoints).entrypoints; Object.keys(entrypoints).forEach(entryName => { var entryAssets = entrypoints[entryName].assets for (var i = 0, l = entryAssets.length; i < l; i++) { var assetName = entryAssets[i].name || entryAssets[i]; if (assetName.slice(-3) === '.js' && assetName.indexOf('manifest.') === -1) { // var assetSource = compilation.assets[assetName] if (assetSource && !assetSource._isThemeJsInjected) { var cSrc = this.getEntryJs(outputName, assetSource, cssCode) cSrc._isThemeJsInjected = true this.emitSource(compilation, assetName, cSrc) break; } } } }) } getConfigJs(outputName, cssCode) { var config = { url: outputName, colors: this.options.matchColors } if (this.options.injectCss) { config.cssCode = cssCode.replace(LineReg, ''); } return '\n(typeof window==\'undefined\'?global:window).' + this.options.configVar + '=' + JSON.stringify(config) + ';\n' } getEntryJs(outputName, assetSource, cssCode) { var ConcatSource = wpSources.ConcatSource var CachedSource = wpSources.CachedSource var configJs = this.getConfigJs(outputName, cssCode) if (assetSource instanceof CachedSource) { // CachedSource没有node方法,会报错 return new CachedSource(concatSrc(((typeof assetSource._source === 'function') ? assetSource._source() : assetSource._source) || assetSource.source(), configJs)) } return concatSrc(assetSource, configJs) function concatSrc(assetSource, configJs) { if (assetSource instanceof ConcatSource) { assetSource.add(configJs) return assetSource } else { return new ConcatSource(assetSource, configJs) } } } }