webpack less 抽取小技巧(獨立前端技術框架版)

場景

一個大體量的項目,會用到 基礎元組件樣式,公共樣式,已經模塊樣式等,這些樣式在經過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);
            },
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容