场景
一个大体量的项目,会用到 基础元组件样式,公共样式,已经模块样式等,这些样式在经过webpack编译后,会直接呈现在页面上(如下图一所示),造成页面感官凌乱,查阅样式多次css,style复写,造成样式浪费,增加问题排查难度,于是,一个共有的css需求便 应运而生;
图一.png
webpack 对css的一系列插件
webpack 作为资源整合的打包工具, 会从一个入口出发,根据 配合解析的各种loader的一系列配置,如 less-loader, postcss-loader,css-loader,style-loader 之后,再配合插件,与出口进行输出;
// webpack.less.js 标准的common.js 写法
// webpack4+
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); // 压缩工具
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // css解析压缩工具
const { CleanWebpackPlugin } = require('clean-webpack-plugin'); // webpack 打包清除
// path获取
const path = require('path');
// 顶级
const resolveTop = function (dir) {
return path.join(__dirname, '../../..', dir);
};
// css文件存放的目录
const cssPath = resolveLoc('./public/theme');
// 参数动态打包 (多文件打包)
var arguments = process.argv;
const entryObj = {};
const setting = arguments[4];
// console.log("arguments ", arguments);
if (!setting) {
entryObj['theme'] = resolveTop(`./assets/less/theme.less`);
} else {
try {
const list = (setting.split('=')[1]).split(',');
console.log(list);
list.forEach(theme => {
entryObj[theme] = resolveTop(`./assets/less/theme/${theme}.less`)
});
} catch (error) {
throw error;
}
}
const cssConfig = {
mode: 'production',
// 单入口
// entry: {
// theme: resolveTop('./assets/less/theme.less')
// },
entry: entryObj,
resolve: {
alias: {
'@': resolveLoc('./src'),
}
},
optimization: {
minimizer: [
new OptimizeCssAssetsPlugin({}),
],
},
module: {
rules: [
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
// 'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
],
},
{
test: /\.(jpg|png)$/,
use: [
// 'file-loader',
'url-loader'
],
},
],
},
// css输出目录
output: {
path: cssPath
},
plugins: [
new MiniCssExtractPlugin({
filename: `[name].css` // 同名输出css
}),
new CleanWebpackPlugin()
]
};
module.exports = cssConfig;
命令行使用
// 根据webpack 特性直接调用打包
webpack --config webpack.less.js
// 多文件打包 theme1,theme2 可根据内容文件名自定义,输出与输入同名
webpack --config webpack.less.js --cumstom=theme1,theme2
引入css
直接引入对应的css,如图二
图二.png
多主题引入
// 使用的是vue,但是本身代码和vue无关
// 代码使用link获取与style 直接加载两种方式,各有利弊,请适量取用
// 换肤
async _changeThemeFun(type) {
// 不存在则渲染 + 加载
// 存在则清除后渲染 + 加载
const theme = document.querySelector('#theme-link');
console.log('theme', theme);
// css link
// this.loadCSS(`/theme/theme${type}.css`);
// style
// axios.get(`/theme/theme${type}.css`).then(res => {
// const cssText = res.data || '';
// this.loadStyle(cssText);
// })
// 请求优化
const cssText = await this.getCssTextFun(type);
this.loadStyle(cssText);
},
async getCssTextFun(type) {
if (!this.theme[type]) {
return axios.get(`/theme/theme${type}.css`).then(res => {
const cssText = res.data || '';
this.theme[type] = cssText;
return Promise.resolve(this.theme[type]);
});
} else {
return Promise.resolve(this.theme[type]);
}
},
loadStyle(cssText) {
const STYLE_ID = 'style-css';
const target = document.getElementById(STYLE_ID);
const setCssTxt = (style, cssText) => {
try {
// firefox、safari、chrome和Opera
// style.clear();
console.log('style', style);
// style.innerText = '';
// style.appendChild(document.createTextNode(cssText));
style.innerText = cssText;
} catch (ex) {
// IE早期的浏览器 ,需要使用style元素的stylesheet属性的cssText属性
style.styleSheet.cssText = cssText;
}
};
if (target) {
setCssTxt(target, cssText);
return;
}
const style = document.createElement('style');
style.setAttribute('id', STYLE_ID);
setCssTxt(style, cssText);
document.head.appendChild(style);
},
loadCSS(url) {
const LINK_ID = 'url-link';
// 存在
const target = document.getElementById(LINK_ID);
if (target) {
target.setAttribute('href', url);
return;
}
// 不存在
const element = document.createElement('link');
element.setAttribute('rel', 'stylesheet');
element.setAttribute('type', 'text/css');
element.setAttribute('id', LINK_ID);
element.setAttribute('href', url);
document.head.appendChild(element);
// element.addEventListener('load', (a, b, c) => {
// debugger;
// console.log('a,b,c', a,b,c);
// }, false);
},
网友评论