1、版本
webpack: 4.42.1
html-webpack-plugin: 4.0.4
mini-css-extract-plugin: 0.9.0
2、方案
換膚分為白、黑兩種風格。
(1)顏色變量定義
白色風格新增顏色變量文件/src/style/skin/white/white.less,文件內容定義需要換膚的顏色變量:
@body-background-color:#000;
@boder-color: #aaa;
同理黑色風格新增顏色變量文件/src/style/skin/black/black.less。
(2)樣式文件定義
新增樣式文件/src/style/components/home.less:
.page{
background-color: @body-background-color;
}
(3)樣式整合
白色風格樣式整合,新增文件/src/style/skin/white/index.less:
@import './white.less';
@import '../components/home.less';
同理黑色風格樣式整合/src/style/skin/black/index.less。
(4)entry入口增加css
entry: {
'bundle': './src/index.js',
'white.css': './src/style/skin/white/index.less',
'black.css': './src/style/skin/black/index.less'
}
(5)使用插件mini-css-extract-plugin抽取css樣式
plugins: [
new MiniCssExtractPlugin({
filename: '[name]',
chunkFilename: '[id]'
})
],
module: {
rules: [
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
}
]
}
打包后生成white.css、black.css文件,并自動插入到<head>中的<link>標簽中。入口文件打包后都會生成.js文件,使用插件mini-css-extract-plugin后,還是會有white.css.js、black.css.js文件,這兩個文件又被插入到<script>標簽中,所以要將white.css.js、black.css.js這兩個文件刪除,并且將對應的<script>標簽中刪除。
(6)自定義插件css-entry-plugin
const RE_CSS = /\.css$/i;
const RE_JS_MAP = /\.js(|map)$/i;
const HtmlWebpackPlugin = require('html-webpack-plugin');
function CssEntryPlugin(options) {
this.options = options;
}
// 刪除.css.js文件
CssEntryPlugin.prototype.apply = function(compiler) {
compiler.hooks.emit.tapAsync('CssEntryPlugin', (compilation, callback) => {
compilation.chunks.filter(chunk => {
return RE_CSS.test(chunk.name);
}).forEach(chunk => {
chunk.files.forEach(file => {
if(RE_JS_MAP.test(file)) {
delete compilation.assets[file];
}
})
})
})
// 刪除script標簽
compiler.hooks.compilation.tag('CssEntryPlugin', (compilation, callback) => {
HtmlWebpackPlugin.getHooks(compilation).alterAssetTags.tapAsync('CssEntryPlugin', (data, callback) => {
let scripts = data.assetTags.scripts;
if(Array.isArray(scripts)) {
let newScripts = [];
for(let i = 0; i < scripts.length; i++) {
let src = scripts[i].attributes.src;
src = src.substr(0, src.length - 3);
if(!RE_CSS.test(src)) {
newScripts.push(scripts[i]);
}
}
data.assetsTags.scripts = newScripts;
}
callback(null, data);
})
})
}
module.exports = CssEntryPlugin
(7)換膚控制
兩種風格的css都被加載到<link>標簽上,通過改變<link>的disabled屬性進行換膚。
let allLinks = document.querySelectorAll('link');
allLinlks.forEach(item => {
……
item.setAttribute('disabled', 'disabled');
……
item.removeAttribute('disabled');
……
})