Webpack 优化细节详述

Webpack 优化细节详述

本地开发优化

开启模块热替换(HMR)使用 Source Maps 优化编译速度

模块热替换(HMR)配置

HMR 允许在运行时更新模块,无需完整刷新页面,大大提升开发效率。

javascript 复制代码
// webpack.dev.js
const webpack = require('webpack');

module.exports = {
  mode: 'development',
  devServer: {
    hot: true, // 启用 HMR
    port: 3000,
    open: true,
    compress: true,
    historyApiFallback: true,
    static: {
      directory: path.join(__dirname, 'public'),
    },
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
  ],
  // 快速的 source map,适合开发环境
  devtool: 'eval-cheap-module-source-map',
};
Source Maps 最佳配置

不同的 source map 类型对编译速度影响很大:

javascript 复制代码
// 开发环境 source map 配置选择
const sourceMapConfig = {
  // 最快,但质量较低
  fastest: 'eval',
  
  // 平衡速度和质量
  balanced: 'eval-cheap-module-source-map',
  
  // 高质量,但较慢
  quality: 'eval-source-map',
  
  // 生产环境
  production: 'source-map'
};

module.exports = {
  devtool: process.env.NODE_ENV === 'production' 
    ? sourceMapConfig.production 
    : sourceMapConfig.balanced,
};
HMR 工作流程
graph TD A[文件变更] --> B[Webpack 检测变化] B --> C[重新编译变更模块] C --> D[生成 Hot Update] D --> E[推送到浏览器] E --> F[HMR Runtime 接收] F --> G{模块支持 HMR?} G -->|是| H[模块热更新] G -->|否| I[页面刷新] H --> J[UI 更新完成] I --> J

使用持久化缓存

Webpack 5 引入的持久化缓存功能可以显著提升构建速度:

javascript 复制代码
// webpack.config.js
module.exports = {
  cache: {
    type: 'filesystem', // 使用文件系统缓存
    buildDependencies: {
      config: [__filename], // 当配置文件改变时,缓存失效
    },
    cacheDirectory: path.resolve(__dirname, '.webpack-cache'),
    store: 'pack', // 缓存存储方式
    version: '1.0', // 缓存版本
  },
  
  // 优化缓存命中率
  optimization: {
    moduleIds: 'deterministic',
    chunkIds: 'deterministic',
  },
};
缓存配置详解
javascript 复制代码
// 高级缓存配置
const cacheConfig = {
  cache: {
    type: 'filesystem',
    
    // 缓存版本管理
    version: createHash('md5')
      .update(JSON.stringify({
        nodeVersion: process.version,
        webpackVersion: require('webpack/package.json').version,
        configHash: getConfigHash(),
      }))
      .digest('hex'),
    
    // 缓存依赖项
    buildDependencies: {
      config: [
        __filename,
        path.resolve(__dirname, 'babel.config.js'),
        path.resolve(__dirname, 'postcss.config.js'),
      ],
    },
    
    // 自定义缓存目录
    cacheDirectory: path.resolve(__dirname, 'node_modules/.cache/webpack'),
    
    // 缓存策略
    managedPaths: [
      path.resolve(__dirname, 'node_modules'),
    ],
    
    // 缓存压缩
    compression: 'gzip',
  },
};

更快的增量编译

优化模块解析
javascript 复制代码
module.exports = {
  resolve: {
    // 减少文件扩展名解析
    extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
    
    // 优化模块查找路径
    modules: [
      path.resolve(__dirname, 'src'),
      'node_modules',
    ],
    
    // 设置别名减少查找时间
    alias: {
      '@': path.resolve(__dirname, 'src'),
      '@components': path.resolve(__dirname, 'src/components'),
      '@utils': path.resolve(__dirname, 'src/utils'),
    },
    
    // 优化解析器缓存
    unsafeCache: true,
    
    // 符合链接优化
    symlinks: false,
  },
  
  // 优化模块构建
  module: {
    // 明确不解析的模块
    noParse: /jquery|lodash/,
    
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        include: path.resolve(__dirname, 'src'),
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true, // 启用 Babel 缓存
            cacheCompression: false,
          },
        },
      },
    ],
  },
};
多进程构建
javascript 复制代码
const TerserPlugin = require('terser-webpack-plugin');
const HappyPack = require('happypack');
const os = require('os');

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        use: 'happypack/loader?id=babel',
        exclude: /node_modules/,
      },
    ],
  },
  
  plugins: [
    new HappyPack({
      id: 'babel',
      threads: os.cpus().length,
      loaders: ['babel-loader?cacheDirectory=true'],
    }),
  ],
  
  optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: true, // 启用多进程压缩
        terserOptions: {
          compress: {
            drop_console: true,
          },
        },
      }),
    ],
  },
};

线上产物构建优化

使用生产模式

javascript 复制代码
// webpack.prod.js
module.exports = {
  mode: 'production', // 自动启用多项优化
  
  // 生产环境优化配置
  optimization: {
    minimize: true,
    sideEffects: false, // 启用 Tree Shaking
    usedExports: true,
    
    // 代码分割配置
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10,
        },
        common: {
          name: 'common',
          minChunks: 2,
          priority: 5,
          reuseExistingChunk: true,
        },
      },
    },
    
    // 运行时代码单独打包
    runtimeChunk: {
      name: 'runtime',
    },
  },
  
  // 生产环境 source map
  devtool: 'source-map',
};

代码分割

动态导入实现代码分割
javascript 复制代码
// 路由级别的代码分割
const routes = [
  {
    path: '/home',
    component: () => import(/* webpackChunkName: "home" */ '@/views/Home.vue'),
  },
  {
    path: '/about',
    component: () => import(/* webpackChunkName: "about" */ '@/views/About.vue'),
  },
];

// 组件级别的代码分割
const LazyComponent = lazy(() => 
  import(/* webpackChunkName: "lazy-component" */ './LazyComponent')
);

// 工具库按需加载
async function loadUtility() {
  const { debounce } = await import(
    /* webpackChunkName: "lodash-debounce" */ 
    'lodash/debounce'
  );
  return debounce;
}
高级代码分割配置
javascript 复制代码
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      minSize: 20000,
      maxSize: 250000,
      
      cacheGroups: {
        // 第三方库分割
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10,
          chunks: 'all',
        },
        
        // React 相关库单独分割
        react: {
          test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
          name: 'react',
          priority: 20,
          chunks: 'all',
        },
        
        // 工具库分割
        utils: {
          test: /[\\/]node_modules[\\/](lodash|moment|axios)[\\/]/,
          name: 'utils',
          priority: 15,
          chunks: 'all',
        },
        
        // 公共代码分割
        common: {
          name: 'common',
          minChunks: 2,
          priority: 5,
          reuseExistingChunk: true,
        },
      },
    },
  },
};
代码分割流程
graph TD A[应用入口] --> B[分析依赖图] B --> C[识别分割点] C --> D[动态导入] C --> E[路由分割] C --> F[第三方库分割] D --> G[生成 Chunk] E --> G F --> G G --> H[文件命名] H --> I[输出文件] I --> J{需要时加载} J -->|是| K[异步加载 Chunk] J -->|否| L[保持空闲]

压缩 JavaScript

TerserPlugin 配置
javascript 复制代码
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: true, // 多进程压缩
        extractComments: false, // 不提取注释到单独文件
        
        terserOptions: {
          compress: {
            drop_console: true, // 移除 console
            drop_debugger: true, // 移除 debugger
            pure_funcs: ['console.log'], // 移除指定函数调用
            unused: true, // 移除未使用的代码
          },
          
          mangle: {
            safari10: true, // 兼容 Safari 10
          },
          
          format: {
            comments: false, // 移除注释
          },
        },
      }),
    ],
  },
};
高级 JavaScript 压缩
javascript 复制代码
// 自定义压缩配置
const compressionConfig = {
  // 生产环境压缩配置
  production: {
    compress: {
      arguments: false,
      dead_code: true,
      drop_console: true,
      drop_debugger: true,
      evaluate: true,
      hoist_funs: true,
      hoist_vars: false,
      if_return: true,
      join_vars: true,
      keep_fargs: false,
      loops: true,
      passes: 2, // 多次压缩
      pure_funcs: [
        'console.log',
        'console.info',
        'console.debug',
        'console.warn',
      ],
      reduce_vars: true,
      sequences: true,
      side_effects: false,
      typeofs: false,
      unused: true,
    },
    
    mangle: {
      properties: {
        regex: /^_/, // 混淆以 _ 开头的属性
      },
    },
  },
};

压缩 CSS

CSS 压缩配置
javascript 复制代码
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  ['autoprefixer'],
                  ['cssnano', { preset: 'default' }],
                ],
              },
            },
          },
        ],
      },
    ],
  },
  
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
      chunkFilename: '[id].[contenthash].css',
    }),
  ],
  
  optimization: {
    minimizer: [
      new CssMinimizerPlugin({
        parallel: true,
        minimizerOptions: {
          preset: [
            'default',
            {
              discardComments: { removeAll: true },
              normalizeWhitespace: true,
              colormin: true,
              convertValues: true,
              discardDuplicates: true,
              discardEmpty: true,
              mergeRules: true,
              minifyFontValues: true,
              minifySelectors: true,
            },
          ],
        },
      }),
    ],
  },
};

启用 Tree Shaking 持久化缓存

Tree Shaking 配置
javascript 复制代码
module.exports = {
  mode: 'production',
  
  optimization: {
    usedExports: true, // 标记使用的导出
    sideEffects: false, // 标记无副作用
  },
  
  // 在 package.json 中配置
  // {
  //   "sideEffects": [
  //     "*.css",
  //     "*.scss",
  //     "./src/polyfills.js"
  //   ]
  // }
};
ES6 模块最佳实践
javascript 复制代码
// 推荐:命名导出,支持 Tree Shaking
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export const multiply = (a, b) => a * b;

// 避免:默认导出整个对象
// export default { add, subtract, multiply };

// 使用时只导入需要的函数
import { add, subtract } from './math-utils';

// Lodash Tree Shaking 示例
import debounce from 'lodash/debounce';
import throttle from 'lodash/throttle';
// 而不是:import { debounce, throttle } from 'lodash';

Bundle 分析

Bundle 分析工具配置
javascript 复制代码
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin({
      analyzerMode: process.env.ANALYZE ? 'server' : 'disabled',
      analyzerHost: '127.0.0.1',
      analyzerPort: 8888,
      reportFilename: 'bundle-report.html',
      defaultSizes: 'parsed',
      openAnalyzer: true,
      generateStatsFile: true,
      statsFilename: 'bundle-stats.json',
    }),
  ],
};

// package.json scripts
// {
//   "analyze": "ANALYZE=true npm run build",
//   "build:stats": "webpack --profile --json > stats.json"
// }
性能监控配置
javascript 复制代码
module.exports = {
  performance: {
    hints: 'warning',
    maxEntrypointSize: 250000, // 入口文件大小限制
    maxAssetSize: 200000, // 单个资源大小限制
    
    assetFilter: function(assetFilename) {
      // 只监控 JS 和 CSS 文件
      return assetFilename.endsWith('.js') || assetFilename.endsWith('.css');
    },
  },
  
  // 输出构建信息
  stats: {
    assets: true,
    chunks: true,
    modules: false,
    reasons: false,
    usedExports: true,
    providedExports: true,
  },
};

懒加载和按需加载压缩图片

图片优化配置
javascript 复制代码
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|svg)$/i,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 8 * 1024, // 8KB 以下转为 base64
          },
        },
        generator: {
          filename: 'images/[name].[hash:8][ext]',
        },
      },
    ],
  },
  
  plugins: [
    new ImageMinimizerPlugin({
      minimizer: {
        implementation: ImageMinimizerPlugin.imageminMinify,
        options: {
          plugins: [
            ['imagemin-pngquant', { quality: [0.6, 0.8] }],
            ['imagemin-mozjpeg', { quality: 80 }],
            ['imagemin-svgo', {
              plugins: [
                { name: 'removeViewBox', active: false },
                { name: 'removeDimensions', active: true },
              ],
            }],
          ],
        },
      },
      
      generator: [
        {
          type: 'asset',
          preset: 'webp-custom-name',
          implementation: ImageMinimizerPlugin.imageminGenerate,
          options: {
            plugins: ['imagemin-webp'],
          },
        },
      ],
    }),
  ],
};
响应式图片加载
javascript 复制代码
// 图片懒加载组件
import { useState, useEffect, useRef } from 'react';

const LazyImage = ({ src, alt, className, placeholder }) => {
  const [imageSrc, setImageSrc] = useState(placeholder);
  const [imageRef, setImageRef] = useState();

  useEffect(() => {
    let observer;
    
    if (imageRef && imageSrc === placeholder) {
      observer = new IntersectionObserver(
        entries => {
          entries.forEach(entry => {
            if (entry.isIntersecting) {
              setImageSrc(src);
              observer.unobserve(imageRef);
            }
          });
        },
        { threshold: 0.1 }
      );
      observer.observe(imageRef);
    }
    
    return () => {
      if (observer && observer.unobserve) {
        observer.unobserve(imageRef);
      }
    };
  }, [imageRef, imageSrc, placeholder, src]);

  return (
    <img
      ref={setImageRef}
      src={imageSrc}
      alt={alt}
      className={className}
      loading="lazy"
    />
  );
};

// WebP 支持检测
const supportsWebP = () => {
  return new Promise(resolve => {
    const webP = new Image();
    webP.onload = webP.onerror = () => {
      resolve(webP.height === 2);
    };
    webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA';
  });
};

内联 CSS 和 JavaScript

关键资源内联
javascript 复制代码
const HtmlWebpackPlugin = require('html-webpack-plugin');
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: 'public/index.html',
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeRedundantAttributes: true,
        useShortDoctype: true,
        removeEmptyAttributes: true,
        removeStyleLinkTypeAttributes: true,
        keepClosingSlash: true,
        minifyJS: true,
        minifyCSS: true,
        minifyURLs: true,
      },
    }),
    
    // 内联运行时代码
    new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),
  ],
  
  optimization: {
    runtimeChunk: {
      name: 'runtime',
    },
  },
};
关键 CSS 内联
javascript 复制代码
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlCriticalWebpackPlugin = require('html-critical-webpack-plugin');

module.exports = {
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
    }),
    
    new HtmlCriticalWebpackPlugin({
      base: path.resolve(__dirname, 'dist'),
      src: 'index.html',
      dest: 'index.html',
      inline: true,
      minify: true,
      extract: true,
      width: 375,
      height: 565,
      penthouse: {
        blockJSRequests: false,
      },
    }),
  ],
};

完整示例配置

开发环境配置

javascript 复制代码
// webpack.dev.js
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  mode: 'development',
  
  entry: {
    main: './src/index.js',
  },
  
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].bundle.js',
    chunkFilename: '[name].chunk.js',
    publicPath: '/',
  },
  
  devtool: 'eval-cheap-module-source-map',
  
  devServer: {
    hot: true,
    port: 3000,
    open: true,
    compress: true,
    historyApiFallback: true,
    static: {
      directory: path.join(__dirname, 'public'),
    },
  },
  
  cache: {
    type: 'filesystem',
    buildDependencies: {
      config: [__filename],
    },
  },
  
  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
    alias: {
      '@': path.resolve(__dirname, 'src'),
      '@components': path.resolve(__dirname, 'src/components'),
      '@utils': path.resolve(__dirname, 'src/utils'),
    },
    modules: [
      path.resolve(__dirname, 'src'),
      'node_modules',
    ],
  },
  
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true,
            presets: ['@babel/preset-env', '@babel/preset-react'],
            plugins: ['@babel/plugin-syntax-dynamic-import'],
          },
        },
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader', 'postcss-loader'],
      },
      {
        test: /\.(png|jpe?g|gif|svg)$/i,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 8 * 1024,
          },
        },
      },
    ],
  },
  
  plugins: [
    new CleanWebpackPlugin(),
    
    new HtmlWebpackPlugin({
      template: 'public/index.html',
      inject: true,
    }),
    
    new webpack.HotModuleReplacementPlugin(),
    
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('development'),
    }),
  ],
  
  optimization: {
    moduleIds: 'named',
    chunkIds: 'named',
  },
};

生产环境配置

javascript 复制代码
// webpack.prod.js
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  mode: 'production',
  
  entry: {
    main: './src/index.js',
  },
  
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].[contenthash].chunk.js',
    publicPath: '/',
    clean: true,
  },
  
  devtool: 'source-map',
  
  cache: {
    type: 'filesystem',
    buildDependencies: {
      config: [__filename],
    },
    version: '1.0',
  },
  
  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
    alias: {
      '@': path.resolve(__dirname, 'src'),
      '@components': path.resolve(__dirname, 'src/components'),
      '@utils': path.resolve(__dirname, 'src/utils'),
    },
  },
  
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true,
            presets: [
              ['@babel/preset-env', {
                modules: false,
                useBuiltIns: 'usage',
                corejs: 3,
              }],
              '@babel/preset-react',
            ],
            plugins: ['@babel/plugin-syntax-dynamic-import'],
          },
        },
      },
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
        ],
      },
      {
        test: /\.(png|jpe?g|gif|svg)$/i,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 8 * 1024,
          },
        },
        generator: {
          filename: 'images/[name].[hash:8][ext]',
        },
      },
    ],
  },
  
  plugins: [
    new CleanWebpackPlugin(),
    
    new HtmlWebpackPlugin({
      template: 'public/index.html',
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeRedundantAttributes: true,
        useShortDoctype: true,
        removeEmptyAttributes: true,
        removeStyleLinkTypeAttributes: true,
        keepClosingSlash: true,
        minifyJS: true,
        minifyCSS: true,
        minifyURLs: true,
      },
    }),
    
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
      chunkFilename: '[id].[contenthash].css',
    }),
    
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production'),
    }),
    
    new CompressionPlugin({
      algorithm: 'gzip',
      test: /\.(js|css|html|svg)$/,
      threshold: 8192,
      minRatio: 0.8,
    }),
    
    process.env.ANALYZE && new BundleAnalyzerPlugin(),
  ].filter(Boolean),
  
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        parallel: true,
        extractComments: false,
        terserOptions: {
          compress: {
            drop_console: true,
            drop_debugger: true,
            pure_funcs: ['console.log'],
          },
          mangle: {
            safari10: true,
          },
          format: {
            comments: false,
          },
        },
      }),
      
      new CssMinimizerPlugin({
        parallel: true,
      }),
    ],
    
    moduleIds: 'deterministic',
    chunkIds: 'deterministic',
    
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10,
        },
        react: {
          test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
          name: 'react',
          priority: 20,
        },
        common: {
          name: 'common',
          minChunks: 2,
          priority: 5,
          reuseExistingChunk: true,
        },
      },
    },
    
    runtimeChunk: {
      name: 'runtime',
    },
    
    usedExports: true,
    sideEffects: false,
  },
  
  performance: {
    hints: 'warning',
    maxEntrypointSize: 250000,
    maxAssetSize: 200000,
  },
};
构建优化流程总览
graph TD A[开始构建] --> B{环境判断} B -->|开发环境| C[启用 HMR] B -->|生产环境| D[启用压缩] C --> E[快速 Source Map] C --> F[持久化缓存] D --> G[代码分割] D --> H[Tree Shaking] D --> I[资源压缩] E --> J[增量编译] F --> J G --> K[Bundle 分析] H --> K I --> K J --> L[开发服务器] K --> M[生产构建] L --> N[热更新] M --> O[部署优化] N --> P[开发完成] O --> Q[上线部署]

通过以上配置和优化策略,可以显著提升 Webpack 项目的构建性能和运行效率。开发环境注重快速编译和调试体验,生产环境则专注于代码质量和加载性能的优化。根据项目实际需求,可以灵活调整相关配置参数。

相关推荐
阿古达木1 分钟前
沉浸式改 bug,步步深入
前端·javascript·github
stoneSkySpace10 分钟前
react 自定义状态管理库
前端·react.js·前端框架
堕落年代23 分钟前
SpringAI1.0的MCPServer自动暴露Tool
前端
南囝coding39 分钟前
一篇文章带你了解清楚,Google Cloud 引发全球互联网服务大面积故障问题
前端·后端
Humbunklung1 小时前
DeepSeek辅助写一个Vue3页面
前端·javascript·vue.js
摸鱼仙人~1 小时前
ESLint从入门到实战
前端
CodeSheep1 小时前
稚晖君公司再获新投资,yyds!
前端·后端·程序员
知否技术1 小时前
放弃ECharts!3行代码DataV搞定Vue酷炫大屏,效率飙升300%!
前端·数据可视化
悟能不能悟1 小时前
Redis的GEO详解
前端·redis·bootstrap