在现代前端工程中,CSS 的提取和打包优化对于项目性能至关重要。本节将详细介绍如何在使用 Tailwind CSS 的项目中实现 CSS 的高效提取和打包优化。

CSS 提取策略

MiniCssExtractPlugin 配置

// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'postcss-loader'
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: process.env.NODE_ENV === 'production'
                ? 'css/[name].[contenthash].css'
                : 'css/[name].css'
        })
    ]
}

分层提取

/* styles/base.css */
@tailwind base;

/* styles/components.css */
@tailwind components;
@layer components {
    .btn { /* ... */
    }

    .card { /* ... */
    }
}

/* styles/utilities.css */
@tailwind utilities;
@layer utilities {
    .custom-scroll { /* ... */
    }
}
// webpack.config.js
module.exports = {
    entry: {
        base: './src/styles/base.css',
        components: './src/styles/components.css',
        utilities: './src/styles/utilities.css'
    }
}

打包优化

CSS 压缩配置

// webpack.config.js
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

module.exports = {
    optimization: {
        minimize: true,
        minimizer: [
            new CssMinimizerPlugin({
                minimizerOptions: {
                    preset: [
                        'default',
                        {
                            discardComments: {removeAll: true},
                            normalizeWhitespace: false
                        }
                    ]
                },
                minify: [
                    CssMinimizerPlugin.cssnanoMinify,
                    CssMinimizerPlugin.cleanCssMinify
                ]
            })
        ]
    }
}

分块策略

// webpack.config.js
module.exports = {
    optimization: {
        splitChunks: {
            cacheGroups: {
                styles: {
                    name: 'styles',
                    test: /\.css$/,
                    chunks: 'all',
                    enforce: true
                },
                tailwindBase: {
                    name: 'tailwind-base',
                    test: /base\.css$/,
                    chunks: 'all',
                    enforce: true
                },
                tailwindComponents: {
                    name: 'tailwind-components',
                    test: /components\.css$/,
                    chunks: 'all',
                    enforce: true
                }
            }
        }
    }
}

条件加载

按需加载样式

// src/utils/loadStyles.js
export const loadStyles = (name) => {
    return import(
        /* webpackChunkName: "styles/[request]" */
        `../styles/${name}.css`
        )
}

// 使用示例
if (process.env.NODE_ENV === 'development') {
    loadStyles('debug')
}

路由级别分割

// routes/Home.js
import {lazy} from 'react'
import loadStyles from '../utils/loadStyles'

const Home = lazy(async () => {
    await loadStyles('home')
    return import('./HomeComponent')
})

export default Home

缓存优化

持久化缓存

// webpack.config.js
module.exports = {
    output: {
        filename: '[name].[contenthash].js',
        path: path.resolve(__dirname, 'dist'),
        clean: true
    },
    cache: {
        type: 'filesystem',
        buildDependencies: {
            config: [__filename]
        },
        name: 'production-cache'
    }
}

模块标识符

// webpack.config.js
const webpack = require('webpack')

module.exports = {
    plugins: [
        new webpack.ids.HashedModuleIdsPlugin({
            context: __dirname,
            hashFunction: 'sha256',
            hashDigest: 'hex',
            hashDigestLength: 8
        })
    ]
}

生产环境优化

CSS 提取配置

// webpack.prod.js
module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    {
                        loader: 'css-loader',
                        options: {
                            importLoaders: 1,
                            modules: {
                                localIdentName: '[hash:base64:8]'
                            }
                        }
                    },
                    'postcss-loader'
                ]
            }
        ]
    }
}

资源优化

// webpack.prod.js
module.exports = {
    optimization: {
        moduleIds: 'deterministic',
        runtimeChunk: 'single',
        splitChunks: {
            chunks: 'all',
            maxInitialRequests: Infinity,
            minSize: 0,
            cacheGroups: {
                vendor: {
                    test: /[\\/]node_modules[\\/]/,
                    name(module) {
                        const packageName = module.context.match(
                            /[\\/]node_modules[\\/](.*?)([\\/]|$)/
                        )[1]
                        return `vendor.${packageName.replace('@', '')}`
                    }
                }
            }
        }
    }
}

开发环境优化

快速构建配置

// webpack.dev.js
module.exports = {
    mode: 'development',
    devtool: 'eval-cheap-module-source-map',
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            importLoaders: 1,
                            modules: {
                                localIdentName: '[name]__[local]--[hash:base64:5]'
                            }
                        }
                    },
                    'postcss-loader'
                ]
            }
        ]
    }
}

热模块替换

// webpack.dev.js
module.exports = {
    devServer: {
        hot: true,
        static: {
            directory: path.join(__dirname, 'public')
        },
        client: {
            overlay: true
        }
    }
}

监控与分析

包体积分析

// webpack.config.js
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer')

module.exports = {
    plugins: [
        new BundleAnalyzerPlugin({
            analyzerMode: 'static',
            reportFilename: 'css-bundle-report.html',
            openAnalyzer: false,
            generateStatsFile: true,
            statsFilename: 'css-bundle-stats.json'
        })
    ]
}

性能监控

// webpack.config.js
module.exports = {
    performance: {
        hints: 'warning',
        maxAssetSize: 250000,
        maxEntrypointSize: 250000,
        assetFilter: function (assetFilename) {
            return assetFilename.endsWith('.css')
        }
    }
}

最佳实践

  1. 提取策略

    • 合理分层
    • 按需加载
    • 模块化组织
  2. 打包优化

    • 压缩配置
    • 分块策略
    • 缓存利用
  3. 环境配置

    • 开发效率
    • 生产性能
    • 调试便利
  4. 监控维护

    • 体积控制
    • 性能指标
    • 持续优化

Devlive开源社区
1.1k 声望29 粉丝

我们是专注于开源项目的社区,在这里您可以发现最新、最伟大的开源项目并参与其中,共同促进开源生态的繁荣与发展。