前端面试题库 - 工程化与性能优化篇

一、构建工具

1. Webpack核心概念与配置

核心概念:

javascript 复制代码
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  // 1. 入口
  entry: {
    main: './src/index.js',
    vendor: './src/vendor.js'
  },
  
  // 2. 输出
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
    clean: true,
    publicPath: '/'
  },
  
  // 3. 模式
  mode: 'production', // development, production, none
  
  // 4. Loader
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      },
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader'
        ]
      },
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'sass-loader'
        ]
      },
      {
        test: /\.(png|jpg|gif|svg)$/,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 8 * 1024 // 8KB以下转base64
          }
        },
        generator: {
          filename: 'images/[name].[hash][ext]'
        }
      }
    ]
  },
  
  // 5. 插件
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        removeComments: true,
        collapseWhitespace: true
      }
    }),
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash].css'
    })
  ],
  
  // 6. 解析
  resolve: {
    extensions: ['.js', '.jsx', '.json'],
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
  },
  
  // 7. 优化
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10
        },
        common: {
          minChunks: 2,
          priority: 5,
          reuseExistingChunk: true
        }
      }
    },
    runtimeChunk: 'single'
  },
  
  // 8. DevServer
  devServer: {
    port: 3000,
    hot: true,
    open: true,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        pathRewrite: { '^/api': '' }
      }
    }
  },
  
  // 9. Source Map
  devtool: 'source-map' // eval, source-map, cheap-module-source-map
};

常用Loader:

Loader 作用
babel-loader 转译ES6+
css-loader 处理CSS
style-loader 注入CSS到DOM
sass-loader 编译Sass
less-loader 编译Less
postcss-loader CSS后处理(autoprefixer)
file-loader 处理文件
url-loader 转base64
vue-loader 处理.vue文件
ts-loader 编译TypeScript

常用Plugin:

Plugin 作用
HtmlWebpackPlugin 生成HTML
MiniCssExtractPlugin 提取CSS
CleanWebpackPlugin 清理输出目录
CopyWebpackPlugin 复制文件
DefinePlugin 定义全局常量
CompressionPlugin Gzip压缩
BundleAnalyzerPlugin 分析打包体积

2. Vite原理与优势

核心特点:

javascript 复制代码
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [vue(), react()],
  
  // 开发服务器
  server: {
    port: 3000,
    open: true,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  },
  
  // 构建选项
  build: {
    outDir: 'dist',
    assetsDir: 'assets',
    sourcemap: false,
    minify: 'terser',
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['vue', 'vue-router', 'pinia']
        }
      }
    }
  },
  
  // 路径别名
  resolve: {
    alias: {
      '@': '/src'
    }
  },
  
  // CSS配置
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@import "@/styles/variables.scss";`
      }
    }
  }
});

Vite vs Webpack:

特性 Vite Webpack
开发服务器启动 极快(无需打包) 慢(需要打包)
热更新速度 极快(ESM) 较慢
生产构建 Rollup Webpack
配置复杂度 简单 复杂
生态成熟度 较新 成熟
浏览器兼容性 现代浏览器 可配置

Vite原理:

javascript 复制代码
// 开发环境
// 1. 利用浏览器原生ESM,无需打包
import { createApp } from 'vue'; // 直接请求node_modules

// 2. 按需编译
// 只编译当前访问的模块,不是全量编译

// 3. HMR(热模块替换)
// 利用ESM的import.meta.hot实现精确更新

// 生产环境
// 使用Rollup打包,生成优化的bundles

3. Babel配置与原理

基本配置:

javascript 复制代码
// babel.config.js
module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        targets: '> 0.25%, not dead', // 目标浏览器
        useBuiltIns: 'usage', // 按需引入polyfill
        corejs: 3
      }
    ],
    '@babel/preset-react',
    '@babel/preset-typescript'
  ],
  
  plugins: [
    '@babel/plugin-proposal-class-properties',
    '@babel/plugin-proposal-optional-chaining',
    '@babel/plugin-transform-runtime'
  ]
};

编译过程:

复制代码
源代码 → 解析(Parse) → AST → 转换(Transform) → 新AST → 生成(Generate) → 目标代码

示例:

javascript 复制代码
// 源代码
const add = (a, b) => a + b;

// AST(简化)
{
  type: 'VariableDeclaration',
  declarations: [{
    type: 'VariableDeclarator',
    id: { type: 'Identifier', name: 'add' },
    init: {
      type: 'ArrowFunctionExpression',
      params: [
        { type: 'Identifier', name: 'a' },
        { type: 'Identifier', name: 'b' }
      ],
      body: {
        type: 'BinaryExpression',
        operator: '+',
        left: { type: 'Identifier', name: 'a' },
        right: { type: 'Identifier', name: 'b' }
      }
    }
  }]
}

// 转换后代码
var add = function(a, b) {
  return a + b;
};

二、性能优化

4. 首屏加载优化

优化策略:

javascript 复制代码
// 1. 代码分割
// 路由懒加载
const Home = () => import('./views/Home.vue');
const About = () => import('./views/About.vue');

// 动态导入
button.addEventListener('click', async () => {
  const module = await import('./heavy-module.js');
  module.init();
});

// 2. 资源压缩
// Webpack配置
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true
          }
        }
      }),
      new CssMinimizerPlugin()
    ]
  }
};

// 3. Gzip压缩
const CompressionPlugin = require('compression-webpack-plugin');

plugins: [
  new CompressionPlugin({
    algorithm: 'gzip',
    test: /\.(js|css|html)$/,
    threshold: 10240, // 10KB以上才压缩
    minRatio: 0.8
  })
];

// 4. Tree Shaking
// package.json
{
  "sideEffects": false // 标记无副作用
}

// 只导入需要的模块
import { debounce } from 'lodash-es';

// 5. 预加载关键资源
<link rel="preload" href="main.js" as="script">
<link rel="preload" href="styles.css" as="style">
<link rel="prefetch" href="next-page.js">

// 6. 图片优化
// WebP格式
<picture>
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="">
</picture>

// 懒加载
<img src="placeholder.jpg" data-src="real-image.jpg" loading="lazy">

// 7. CDN
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script>

// 8. 骨架屏
// 在首屏加载时显示占位内容
<div class="skeleton">
  <div class="skeleton-header"></div>
  <div class="skeleton-content"></div>
</div>

// 9. 服务端渲染(SSR)
// Nuxt.js (Vue) / Next.js (React)
export async function getServerSideProps() {
  const data = await fetchData();
  return { props: { data } };
}

性能指标:

javascript 复制代码
// 1. FCP (First Contentful Paint) - 首次内容绘制
// 目标: < 1.8s

// 2. LCP (Largest Contentful Paint) - 最大内容绘制
// 目标: < 2.5s

// 3. FID (First Input Delay) - 首次输入延迟
// 目标: < 100ms

// 4. CLS (Cumulative Layout Shift) - 累积布局偏移
// 目标: < 0.1

// 5. TTFB (Time to First Byte) - 首字节时间
// 目标: < 600ms

// 使用Performance API测量
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(entry.name, entry.startTime);
  }
});

observer.observe({ entryTypes: ['paint', 'largest-contentful-paint'] });

5. 运行时性能优化

JavaScript优化:

javascript 复制代码
// 1. 防抖
function debounce(fn, delay) {
  let timer = null;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

// 使用
input.addEventListener('input', debounce((e) => {
  fetchSearchResults(e.target.value);
}, 300));

// 2. 节流
function throttle(fn, interval) {
  let lastTime = 0;
  return function(...args) {
    const now = Date.now();
    if (now - lastTime >= interval) {
      fn.apply(this, args);
      lastTime = now;
    }
  };
}

// 使用
window.addEventListener('scroll', throttle(() => {
  console.log('scrolling');
}, 100));

// 3. 使用Web Workers处理密集计算
// main.js
const worker = new Worker('worker.js');

worker.postMessage({ numbers: largeArray });

worker.onmessage = (e) => {
  console.log('计算结果:', e.data);
};

// worker.js
self.onmessage = (e) => {
  const result = e.data.numbers.reduce((sum, num) => sum + num, 0);
  self.postMessage(result);
};

// 4. requestAnimationFrame优化动画
function animate() {
  element.style.transform = `translateX(${position}px)`;
  position += 1;
  
  if (position < 500) {
    requestAnimationFrame(animate);
  }
}

requestAnimationFrame(animate);

// 5. IntersectionObserver懒加载
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      observer.unobserve(img);
    }
  });
});

document.querySelectorAll('img[data-src]').forEach(img => {
  observer.observe(img);
});

// 6. 避免强制同步布局
// ❌ 强制同步布局(慢)
for (let i = 0; i < elements.length; i++) {
  const height = elements[i].offsetHeight; // 读取
  elements[i].style.height = height * 2 + 'px'; // 写入
}

// ✅ 批量读取,批量写入
const heights = elements.map(el => el.offsetHeight);
elements.forEach((el, i) => {
  el.style.height = heights[i] * 2 + 'px';
});

CSS优化:

css 复制代码
/* 1. 使用transform代替位置属性 */
/* ❌ 触发回流 */
.box {
  left: 100px;
  top: 100px;
}

/* ✅ 只触发合成 */
.box {
  transform: translate(100px, 100px);
}

/* 2. 使用will-change提示浏览器 */
.box {
  will-change: transform;
}

/* 3. 避免复杂选择器 */
/* ❌ 性能差 */
.container > .list li:nth-child(odd) .item .text {
  color: red;
}

/* ✅ 使用类名 */
.item-text-odd {
  color: red;
}

/* 4. 使用contain提高渲染性能 */
.card {
  contain: layout style paint;
}

/* 5. 使用content-visibility延迟渲染 */
.section {
  content-visibility: auto;
  contain-intrinsic-size: 0 500px;
}

6. 网络优化

HTTP优化:

javascript 复制代码
// 1. HTTP/2多路复用
// 服务器配置启用HTTP/2

// 2. 资源合并(HTTP/1.1)
// 合并CSS、JS文件

// 3. 域名分片(HTTP/1.1)
// 静态资源使用多个域名

// 4. 使用Service Worker缓存
// sw.js
const CACHE_NAME = 'v1';
const urlsToCache = [
  '/',
  '/styles.css',
  '/script.js',
  '/images/logo.png'
];

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(urlsToCache))
  );
});

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        if (response) {
          return response; // 缓存命中
        }
        return fetch(event.request); // 网络请求
      })
  );
});

// 5. 资源提示
<link rel="dns-prefetch" href="https://api.example.com">
<link rel="preconnect" href="https://cdn.example.com">
<link rel="prefetch" href="/next-page.js">
<link rel="preload" href="/critical.css" as="style">

// 6. 使用HTTP缓存
// 服务器响应头
Cache-Control: max-age=31536000, immutable // 静态资源
Cache-Control: no-cache // HTML文件

// 7. 启用Brotli压缩
// 服务器配置
Content-Encoding: br

API优化:

javascript 复制代码
// 1. 接口聚合
// ❌ 多个请求
const user = await fetch('/api/user/1');
const posts = await fetch('/api/user/1/posts');
const comments = await fetch('/api/user/1/comments');

// ✅ 单个请求
const data = await fetch('/api/user/1?include=posts,comments');

// 2. GraphQL按需查询
query {
  user(id: 1) {
    name
    email
    posts {
      title
    }
  }
}

// 3. 分页加载
async function loadMore() {
  const response = await fetch(`/api/posts?page=${page}&limit=20`);
  const posts = await response.json();
  appendPosts(posts);
  page++;
}

// 4. 请求取消
const controller = new AbortController();

fetch('/api/data', { signal: controller.signal })
  .then(response => response.json())
  .catch(error => {
    if (error.name === 'AbortError') {
      console.log('请求已取消');
    }
  });

// 取消请求
controller.abort();

// 5. 请求缓存
const cache = new Map();

async function fetchWithCache(url) {
  if (cache.has(url)) {
    return cache.get(url);
  }
  
  const response = await fetch(url);
  const data = await response.json();
  cache.set(url, data);
  
  return data;
}

7. 打包优化

Webpack优化:

javascript 复制代码
// webpack.config.js
module.exports = {
  // 1. 缩小构建目标
  resolve: {
    extensions: ['.js', '.jsx'], // 减少扩展名
    modules: [path.resolve(__dirname, 'src'), 'node_modules'], // 指定查找路径
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
  },
  
  // 2. noParse跳过解析
  module: {
    noParse: /jquery|lodash/
  },
  
  // 3. 多线程构建
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: 'thread-loader',
            options: { workers: 4 }
          },
          'babel-loader'
        ]
      }
    ]
  },
  
  // 4. 缓存
  cache: {
    type: 'filesystem'
  },
  
  // 5. DLL预编译
  // webpack.dll.config.js
  module.exports = {
    entry: {
      vendor: ['react', 'react-dom', 'lodash']
    },
    output: {
      path: path.join(__dirname, 'dll'),
      filename: '[name].dll.js',
      library: '[name]_library'
    },
    plugins: [
      new webpack.DllPlugin({
        path: path.join(__dirname, 'dll', '[name]-manifest.json'),
        name: '[name]_library'
      })
    ]
  };
  
  // webpack.config.js
  plugins: [
    new webpack.DllReferencePlugin({
      manifest: require('./dll/vendor-manifest.json')
    })
  ],
  
  // 6. 分析打包
  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
  
  plugins: [
    new BundleAnalyzerPlugin()
  ]
};

按需加载:

javascript 复制代码
// 1. React懒加载
import React, { lazy, Suspense } from 'react';

const LazyComponent = lazy(() => import('./LazyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
    </Suspense>
  );
}

// 2. Vue懒加载
const LazyComponent = () => import('./LazyComponent.vue');

// 3. 动态导入
button.addEventListener('click', async () => {
  const { default: module } = await import('./module.js');
  module.init();
});
相关推荐
Python大数据分析@2 小时前
HTML会代替Markdown吗?为什么?
前端·html
一棵树73512 小时前
js总结介绍
前端·javascript·html
暗冰ཏོ2 小时前
2026前端开发资源大全:工具、文档、框架、学习路线与实战指南
前端·前端开发工具·前端编程工具·前端资源·前端开发文档
踩着两条虫2 小时前
AI 低代码引擎可视化设计器交互机制实战
前端·vue.js·人工智能·低代码·架构
ZC跨境爬虫2 小时前
跟着 MDN 学CSS day_2:(连接样式表与选择器的实战艺术)
java·前端·css·ui·html·媒体
lichenyang4532 小时前
鸿蒙聊天 Demo 练习 01:发送消息、模拟 AI 回复与自动滚动
前端
李小狼lee2 小时前
《spring如此简单》第二节--IOC思想的实现,容器是什么
后端·面试
放下华子我只抽RuiKe53 小时前
React 从入门到生产(三):副作用与数据获取
前端·javascript·深度学习·react.js·开源·ecmascript·集成学习
微祎_3 小时前
写给前端的 CANN-ops-transformer:昇腾Transformer进阶算子库到底是啥?
前端·深度学习·transformer