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

CSS 提取策略

MiniCssExtractPlugin 配置

  1. // webpack.config.js
  2. const MiniCssExtractPlugin = require('mini-css-extract-plugin')
  3. module.exports = {
  4. module: {
  5. rules: [
  6. {
  7. test: /\.css$/,
  8. use: [
  9. MiniCssExtractPlugin.loader,
  10. 'css-loader',
  11. 'postcss-loader'
  12. ]
  13. }
  14. ]
  15. },
  16. plugins: [
  17. new MiniCssExtractPlugin({
  18. filename: process.env.NODE_ENV === 'production'
  19. ? 'css/[name].[contenthash].css'
  20. : 'css/[name].css'
  21. })
  22. ]
  23. }

分层提取

  1. /* styles/base.css */
  2. @tailwind base;
  3. /* styles/components.css */
  4. @tailwind components;
  5. @layer components {
  6. .btn { /* ... */
  7. }
  8. .card { /* ... */
  9. }
  10. }
  11. /* styles/utilities.css */
  12. @tailwind utilities;
  13. @layer utilities {
  14. .custom-scroll { /* ... */
  15. }
  16. }
  1. // webpack.config.js
  2. module.exports = {
  3. entry: {
  4. base: './src/styles/base.css',
  5. components: './src/styles/components.css',
  6. utilities: './src/styles/utilities.css'
  7. }
  8. }

打包优化

CSS 压缩配置

  1. // webpack.config.js
  2. const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
  3. module.exports = {
  4. optimization: {
  5. minimize: true,
  6. minimizer: [
  7. new CssMinimizerPlugin({
  8. minimizerOptions: {
  9. preset: [
  10. 'default',
  11. {
  12. discardComments: {removeAll: true},
  13. normalizeWhitespace: false
  14. }
  15. ]
  16. },
  17. minify: [
  18. CssMinimizerPlugin.cssnanoMinify,
  19. CssMinimizerPlugin.cleanCssMinify
  20. ]
  21. })
  22. ]
  23. }
  24. }

分块策略

  1. // webpack.config.js
  2. module.exports = {
  3. optimization: {
  4. splitChunks: {
  5. cacheGroups: {
  6. styles: {
  7. name: 'styles',
  8. test: /\.css$/,
  9. chunks: 'all',
  10. enforce: true
  11. },
  12. tailwindBase: {
  13. name: 'tailwind-base',
  14. test: /base\.css$/,
  15. chunks: 'all',
  16. enforce: true
  17. },
  18. tailwindComponents: {
  19. name: 'tailwind-components',
  20. test: /components\.css$/,
  21. chunks: 'all',
  22. enforce: true
  23. }
  24. }
  25. }
  26. }
  27. }

条件加载

按需加载样式

  1. // src/utils/loadStyles.js
  2. export const loadStyles = (name) => {
  3. return import(
  4. /* webpackChunkName: "styles/[request]" */
  5. `../styles/${name}.css`
  6. )
  7. }
  8. // 使用示例
  9. if (process.env.NODE_ENV === 'development') {
  10. loadStyles('debug')
  11. }

路由级别分割

  1. // routes/Home.js
  2. import {lazy} from 'react'
  3. import loadStyles from '../utils/loadStyles'
  4. const Home = lazy(async () => {
  5. await loadStyles('home')
  6. return import('./HomeComponent')
  7. })
  8. export default Home

缓存优化

持久化缓存

  1. // webpack.config.js
  2. module.exports = {
  3. output: {
  4. filename: '[name].[contenthash].js',
  5. path: path.resolve(__dirname, 'dist'),
  6. clean: true
  7. },
  8. cache: {
  9. type: 'filesystem',
  10. buildDependencies: {
  11. config: [__filename]
  12. },
  13. name: 'production-cache'
  14. }
  15. }

模块标识符

  1. // webpack.config.js
  2. const webpack = require('webpack')
  3. module.exports = {
  4. plugins: [
  5. new webpack.ids.HashedModuleIdsPlugin({
  6. context: __dirname,
  7. hashFunction: 'sha256',
  8. hashDigest: 'hex',
  9. hashDigestLength: 8
  10. })
  11. ]
  12. }

生产环境优化

CSS 提取配置

  1. // webpack.prod.js
  2. module.exports = {
  3. module: {
  4. rules: [
  5. {
  6. test: /\.css$/,
  7. use: [
  8. MiniCssExtractPlugin.loader,
  9. {
  10. loader: 'css-loader',
  11. options: {
  12. importLoaders: 1,
  13. modules: {
  14. localIdentName: '[hash:base64:8]'
  15. }
  16. }
  17. },
  18. 'postcss-loader'
  19. ]
  20. }
  21. ]
  22. }
  23. }

资源优化

  1. // webpack.prod.js
  2. module.exports = {
  3. optimization: {
  4. moduleIds: 'deterministic',
  5. runtimeChunk: 'single',
  6. splitChunks: {
  7. chunks: 'all',
  8. maxInitialRequests: Infinity,
  9. minSize: 0,
  10. cacheGroups: {
  11. vendor: {
  12. test: /[\\/]node_modules[\\/]/,
  13. name(module) {
  14. const packageName = module.context.match(
  15. /[\\/]node_modules[\\/](.*?)([\\/]|$)/
  16. )[1]
  17. return `vendor.${packageName.replace('@', '')}`
  18. }
  19. }
  20. }
  21. }
  22. }
  23. }

开发环境优化

快速构建配置

  1. // webpack.dev.js
  2. module.exports = {
  3. mode: 'development',
  4. devtool: 'eval-cheap-module-source-map',
  5. module: {
  6. rules: [
  7. {
  8. test: /\.css$/,
  9. use: [
  10. 'style-loader',
  11. {
  12. loader: 'css-loader',
  13. options: {
  14. importLoaders: 1,
  15. modules: {
  16. localIdentName: '[name]__[local]--[hash:base64:5]'
  17. }
  18. }
  19. },
  20. 'postcss-loader'
  21. ]
  22. }
  23. ]
  24. }
  25. }

热模块替换

  1. // webpack.dev.js
  2. module.exports = {
  3. devServer: {
  4. hot: true,
  5. static: {
  6. directory: path.join(__dirname, 'public')
  7. },
  8. client: {
  9. overlay: true
  10. }
  11. }
  12. }

监控与分析

包体积分析

  1. // webpack.config.js
  2. const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer')
  3. module.exports = {
  4. plugins: [
  5. new BundleAnalyzerPlugin({
  6. analyzerMode: 'static',
  7. reportFilename: 'css-bundle-report.html',
  8. openAnalyzer: false,
  9. generateStatsFile: true,
  10. statsFilename: 'css-bundle-stats.json'
  11. })
  12. ]
  13. }

性能监控

  1. // webpack.config.js
  2. module.exports = {
  3. performance: {
  4. hints: 'warning',
  5. maxAssetSize: 250000,
  6. maxEntrypointSize: 250000,
  7. assetFilter: function (assetFilename) {
  8. return assetFilename.endsWith('.css')
  9. }
  10. }
  11. }

最佳实践

  1. 提取策略

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

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

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

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