乐闻世界logo
搜索文章和话题

面试题手册

如何在 Jest 中测试 Redux 相关代码?如何测试 Actions、Reducers 和 Selectors?

在 Jest 中测试 Redux 相关代码需要 Mock store 和 actions:1. 测试 Redux Actions:// actions.jsexport const increment = () => ({ type: 'INCREMENT' });export const addValue = (value) => ({ type: 'ADD_VALUE', payload: value });// actions.test.jsimport { increment, addValue } from './actions';describe('Actions', () => { test('creates increment action', () => { expect(increment()).toEqual({ type: 'INCREMENT' }); }); test('creates add value action', () => { expect(addValue(5)).toEqual({ type: 'ADD_VALUE', payload: 5 }); });});2. 测试 Redux Reducers:// reducer.jsconst initialState = { count: 0 };export default function counterReducer(state = initialState, action) { switch (action.type) { case 'INCREMENT': return { count: state.count + 1 }; case 'ADD_VALUE': return { count: state.count + action.payload }; default: return state; }}// reducer.test.jsimport counterReducer from './reducer';describe('Counter Reducer', () => { test('returns initial state', () => { expect(counterReducer(undefined, {})).toEqual({ count: 0 }); }); test('handles INCREMENT', () => { const state = counterReducer({ count: 0 }, { type: 'INCREMENT' }); expect(state).toEqual({ count: 1 }); });});3. 测试 Redux Selectors:// selectors.jsexport const selectCount = (state) => state.counter.count;// selectors.test.jsimport { selectCount } from './selectors';test('selects count from state', () => { const state = { counter: { count: 5 } }; expect(selectCount(state)).toBe(5);});4. 测试 Redux Thunks:// thunks.jsexport const fetchUser = (id) => async (dispatch) => { const response = await fetch(`/api/users/${id}`); const user = await response.json(); dispatch({ type: 'FETCH_USER_SUCCESS', payload: user });};// thunks.test.jsimport configureMockStore from 'redux-mock-store';import thunk from 'redux-thunk';import { fetchUser } from './thunks';const mockStore = configureMockStore([thunk]);test('fetches user successfully', async () => { global.fetch = jest.fn(() => Promise.resolve({ json: () => Promise.resolve({ id: 1, name: 'John' }) }) ); const expectedActions = [ { type: 'FETCH_USER_SUCCESS', payload: { id: 1, name: 'John' } } ]; const store = mockStore({}); await store.dispatch(fetchUser(1)); expect(store.getActions()).toEqual(expectedActions);});5. 测试 React-Redux 组件:import { render, screen } from '@testing-library/react';import { Provider } from 'react-redux';import Counter from './Counter';import { createStore } from 'redux';import reducer from './reducer';test('renders counter with initial state', () => { const store = createStore(reducer); render( <Provider store={store}> <Counter /> </Provider> ); expect(screen.getByText('Count: 0')).toBeInTheDocument();});最佳实践:单独测试 actions、reducers 和 selectors使用 redux-mock-store 测试异步 actionsMock API 调用以隔离测试测试组件时提供 mock store保持测试简单和独立避免测试 Redux 内部实现细节
阅读 0·2月19日 19:15

如何在 Jest 中测试 Vue 组件?如何使用 @vue/test-utils?

在 Jest 中测试 Vue 组件需要使用 @vue/test-utils:1. 安装依赖:npm install --save-dev @vue/test-utils jest vue-jest2. 配置 Jest:// jest.config.jsmodule.exports = { preset: '@vue/cli-plugin-unit-jest', moduleFileExtensions: ['js', 'json', 'vue'], transform: { '^.+\\.vue$': 'vue-jest', '^.+\\.js$': 'babel-jest', },};3. 测试 Vue 组件:import { mount } from '@vue/test-utils';import Counter from '@/components/Counter.vue';describe('Counter.vue', () => { test('renders initial count', () => { const wrapper = mount(Counter); expect(wrapper.text()).toContain('Count: 0'); }); test('increments count when button clicked', async () => { const wrapper = mount(Counter); const button = wrapper.find('button'); await button.trigger('click'); expect(wrapper.text()).toContain('Count: 1'); });});4. 测试 Props:test('renders with props', () => { const wrapper = mount(Counter, { propsData: { initialCount: 5 } }); expect(wrapper.text()).toContain('Count: 5');});5. 测试事件:test('emits increment event', async () => { const wrapper = mount(Counter); const button = wrapper.find('button'); await button.trigger('click'); expect(wrapper.emitted('increment')).toBeTruthy(); expect(wrapper.emitted('increment').length).toBe(1);});6. 测试计算属性:test('computes double count', () => { const wrapper = mount(Counter, { data() { return { count: 5 }; } }); expect(wrapper.vm.doubleCount).toBe(10);});7. 测试插槽:test('renders slot content', () => { const wrapper = mount(MyComponent, { slots: { default: 'Custom content' } }); expect(wrapper.text()).toContain('Custom content');});最佳实践:使用 mount 进行完整渲染,shallowMount 进行浅渲染测试用户交互和事件验证 props 和 emitted 事件测试计算属性和方法使用 setData 和 setProps 更新状态保持测试简单和可维护
阅读 0·2月19日 19:15

如何开发一个 Vite 插件?有哪些常用的钩子函数?

Vite 提供了丰富的插件系统,开发者可以通过插件扩展 Vite 的功能。以下是 Vite 插件开发的关键点:插件基本结构:Vite 插件是一个对象,包含 name 属性和各种钩子函数:export default function myPlugin() { return { name: 'my-plugin', // 钩子函数 config(config) { // 修改配置 }, resolveId(source) { // 解析模块 ID }, load(id) { // 加载模块内容 }, transform(code, id) { // 转换代码 } }}常用钩子函数:config:修改 Vite 配置,在配置解析后调用configResolved:配置解析完成后调用configureServer:配置开发服务器,可以添加中间件resolveId:自定义模块解析逻辑load:自定义模块加载逻辑transform:转换代码内容(最常用)buildStart/buildEnd:构建开始/结束时调用generateBundle:生成 bundle 时调用Rollup 插件兼容性:Vite 插件与 Rollup 插件兼容,大部分 Rollup 插件可以直接在 Vite 中使用。但需要注意:Vite 插件在开发环境和生产环境都运行某些 Rollup 特定钩子只在生产环境生效开发环境特有钩子:handleHotUpdate:自定义 HMR 更新逻辑configureServer:配置开发服务器transformIndexHtml:转换 HTML 文件插件示例:export default function myTransformPlugin() { return { name: 'my-transform', transform(code, id) { if (id.endsWith('.js')) { return code.replace(/foo/g, 'bar') } } }}插件配置:在 vite.config.js 中使用插件:import myPlugin from './my-plugin'export default { plugins: [myPlugin()]}最佳实践:插件应该有清晰的命名和文档使用 enforce 选项控制插件执行顺序(pre、post)只处理目标文件,避免不必要的转换提供合理的默认配置和选项
阅读 0·2月19日 19:15

Vite 有哪些性能优化策略?如何提升构建速度?

Vite 提供了多种性能优化策略,可以帮助开发者提升项目的构建和运行性能。以下是 Vite 性能优化的关键方法:依赖预构建优化:合理配置 optimizeDeps:export default { optimizeDeps: { include: ['lodash'], // 强制预构建 exclude: ['some-large-lib'] // 排除大型库 }}使用缓存:Vite 会缓存预构建结果,避免重复构建构建优化:代码分割:export default { build: { rollupOptions: { output: { manualChunks: { vendor: ['react', 'react-dom'], utils: ['lodash', 'axios'] } } } }}Tree-shaking:Vite 自动移除未使用的代码压缩优化:export default { build: { minify: 'terser', // 或 'esbuild' terserOptions: { compress: { drop_console: true // 移除 console } } }}开发环境优化:禁用 Source Map:export default { build: { sourcemap: false }}减少文件监听:export default { server: { watch: { ignored: ['**/node_modules/**', '**/.git/**'] } }}资源优化:调整内联阈值:export default { build: { assetsInlineLimit: 4096 // 小于 4KB 的资源内联 }}使用 CDN:将大型依赖放到 CDN图片优化:使用 WebP 等现代格式CSS 优化:CSS 代码分割:Vite 自动提取 CSS 到独立文件CSS 压缩:export default { build: { cssCodeSplit: true, cssMinify: 'lightningcss' // 更快的 CSS 压缩 }}插件优化:按需加载插件:只在需要时加载插件使用轻量级插件:选择性能更好的替代方案缓存策略:文件名 Hash:使用 [hash] 实现长期缓存HTTP 缓存:配置服务器缓存策略性能监控:构建分析:npm run build -- --mode analyze使用 rollup-plugin-visualizer 分析打包结果最佳实践:避免过度优化,先分析瓶颈使用最新的 Vite 版本合理配置,避免不必要的优化定期审查依赖,移除未使用的包使用 CDN 加速静态资源
阅读 0·2月19日 19:14

Vite 如何支持 TypeScript?如何配置类型检查?

Vite 提供了完善的 TypeScript 支持,开发者可以在 Vite 项目中无缝使用 TypeScript。以下是 Vite 中 TypeScript 的使用和配置方法:基本支持:Vite 开箱即支持 TypeScript,无需额外配置。可以直接使用 .ts、.tsx 文件,Vite 会自动处理类型检查和转译。配置文件:tsconfig.json:TypeScript 配置文件vite.config.ts:Vite 配置文件(TypeScript 版本)类型检查:开发环境:Vite 默认不进行类型检查,以保持快速的开发体验可以通过 vite-plugin-checker 插件实现类型检查或者在单独的进程中运行 tsc --noEmit生产构建:Vite 构建时会使用 esbuild 进行转译esbuild 的类型检查功能有限,建议在 CI/CD 中运行 tsc配置示例:// tsconfig.json{ "compilerOptions": { "target": "ES2020", "useDefineForClassFields": true, "module": "ESNext", "lib": ["ES2020", "DOM", "DOM.Iterable"], "skipLibCheck": true, "moduleResolution": "bundler", "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, "include": ["src"], "references": [{ "path": "./tsconfig.node.json" }]}路径别名:// vite.config.tsimport { defineConfig } from 'vite'import path from 'path'export default defineConfig({ resolve: { alias: { '@': path.resolve(__dirname, './src') } }})// tsconfig.json{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["src/*"] } }}环境变量类型定义:// src/vite-env.d.tsinterface ImportMetaEnv { readonly VITE_API_URL: string readonly VITE_APP_TITLE: string}interface ImportMeta { readonly env: ImportMetaEnv}类型检查插件:// vite.config.tsimport { defineConfig } from 'vite'import checker from 'vite-plugin-checker'export default defineConfig({ plugins: [ checker({ typescript: true, eslint: { lintCommand: 'eslint "./src/**/*.{ts,tsx}"' } }) ]})最佳实践:在开发环境中使用 vite-plugin-checker 进行实时类型检查在 CI/CD 流程中运行 tsc --noEmit 确保类型安全使用 strict 模式启用所有严格类型检查合理配置 skipLibCheck 提升构建速度为环境变量定义类型,避免类型错误
阅读 0·2月19日 19:14

Vite 的配置文件有哪些常用选项?如何配置路径别名?

Vite 提供了多种配置方式来满足不同项目的需求。以下是 Vite 配置的详细说明:配置文件:Vite 会自动从以下位置加载配置文件(按优先级排序):vite.config.jsvite.config.mjsvite.config.tsvite.config.cjs基本配置结构:import { defineConfig } from 'vite'import react from '@vitejs/plugin-react'export default defineConfig({ plugins: [react()], server: { port: 3000, open: true }, build: { outDir: 'dist', sourcemap: true }})常用配置选项:开发服务器配置(server):port:指定开发服务器端口host:指定服务器主机名open:启动时自动打开浏览器proxy:配置代理,解决跨域问题cors:配置 CORS 策略https:启用 HTTPS构建配置(build):outDir:输出目录assetsDir:静态资源目录sourcemap:是否生成 source mapminify:压缩方式(terser、esbuild)target:构建目标浏览器rollupOptions:Rollup 配置选项chunkSizeWarningLimit:chunk 大小警告阈值路径别名(resolve.alias):resolve: { alias: { '@': '/src', '@components': '/src/components' }}CSS 配置(css):preprocessorOptions:预处理器选项modules:CSS Modules 配置postcss:PostCSS 配置依赖优化配置(optimizeDeps):include:强制包含的依赖exclude:排除的依赖esbuildOptions:esbuild 选项环境变量:Vite 支持通过 .env 文件配置环境变量:.env:所有环境.env.development:开发环境.env.production:生产环境.env.local:本地覆盖环境变量必须以 VITE_ 开头才能在客户端代码中访问。条件配置:export default defineConfig(({ command, mode }) => { if (command === 'serve') { return { /* dev config */ } } else { return { /* build config */ } }})TypeScript 支持:使用 defineConfig 可以获得完整的类型提示和智能补全。
阅读 0·2月19日 19:14

Vite 如何与 Vue、React 等框架集成?

Vite 支持多种前端框架,包括 Vue、React、Svelte、Solid 等。以下是 Vite 与不同框架的集成方法:Vue 集成:创建 Vue 项目:npm create vite@latest my-vue-app -- --template vue配置文件:// vite.config.jsimport { defineConfig } from 'vite'import vue from '@vitejs/plugin-vue'export default defineConfig({ plugins: [vue()]})支持 JSX:import vueJsx from '@vitejs/plugin-vue-jsx'export default defineConfig({ plugins: [vue(), vueJsx()]})React 集成:创建 React 项目:npm create vite@latest my-react-app -- --template react配置文件:// vite.config.jsimport { defineConfig } from 'vite'import react from '@vitejs/plugin-react'export default defineConfig({ plugins: [react()]})Fast Refresh:Vite 的 React 插件自动支持 Fast RefreshSvelte 集成:创建 Svelte 项目:npm create vite@latest my-svelte-app -- --template svelte配置文件:// vite.config.jsimport { defineConfig } from 'vite'import { svelte } from '@sveltejs/vite-plugin-svelte'export default defineConfig({ plugins: [svelte()]})Solid 集成:创建 Solid 项目:npm create vite@latest my-solid-app -- --template solid配置文件:// vite.config.jsimport { defineConfig } from 'vite'import solid from 'vite-plugin-solid'export default defineConfig({ plugins: [solid()]})通用配置:路径别名:import path from 'path'export default defineConfig({ resolve: { alias: { '@': path.resolve(__dirname, './src') } }})环境变量:export default defineConfig(({ mode }) => { return { define: { __APP_ENV__: JSON.stringify(mode) } }})CSS 预处理器:export default defineConfig({ css: { preprocessorOptions: { scss: { additionalData: `$injectedColor: orange;` } } }})最佳实践:使用官方模板创建项目,确保最佳配置根据框架特性选择合适的插件合理配置路径别名,简化导入利用环境变量管理不同环境配置使用框架特定的优化插件框架特定优化:Vue:使用 @vitejs/plugin-vue 的 script 选项优化React:配置 @vitejs/plugin-react 的 jsxImportSourceSvelte:配置 @sveltejs/vite-plugin-svelte 的 preprocessSolid:使用 vite-plugin-solid 的 solid 选项
阅读 0·2月19日 19:14

Vite 如何使用环境变量?有哪些内置的环境变量?

Vite 提供了强大的环境变量支持,开发者可以通过环境变量管理不同环境的配置。以下是 Vite 环境变量的使用方法:环境变量文件:Vite 支持以下环境变量文件(按优先级从高到低):.env.local:本地覆盖,不应提交到版本控制.env.[mode].local:特定模式的本地覆盖.env.[mode]:特定模式的环境变量.env:所有环境通用的环境变量其中 [mode] 可以是 development、production 或自定义模式。环境变量定义:# .envVITE_APP_TITLE=My AppVITE_API_URL=https://api.example.com# .env.developmentVITE_API_URL=https://dev-api.example.com# .env.productionVITE_API_URL=https://prod-api.example.com客户端访问:只有以 VITE_ 开头的环境变量才能在客户端代码中访问:// 在客户端代码中console.log(import.meta.env.VITE_APP_TITLE)console.log(import.meta.env.VITE_API_URL)服务端访问:在 vite.config.js 中可以访问所有环境变量:import { defineConfig, loadEnv } from 'vite'export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), '') return { define: { 'import.meta.env.API_URL': JSON.stringify(env.VITE_API_URL) } }})内置环境变量:Vite 提供了一些内置环境变量:import.meta.env.MODE:当前模式(development/production)import.meta.env.BASE_URL:部署的基础 URLimport.meta.env.PROD:是否为生产环境import.meta.env.DEV:是否为开发环境import.meta.env.SSR:是否为服务端渲染使用示例:// 根据环境配置 APIconst API_URL = import.meta.env.VITE_API_URL || 'https://api.example.com'// 条件渲染{import.meta.env.DEV && <DebugPanel />}// 动态导入const module = import.meta.env.PROD ? await import('./prod-module') : await import('./dev-module')TypeScript 类型定义:// src/vite-env.d.tsinterface ImportMetaEnv { readonly VITE_APP_TITLE: string readonly VITE_API_URL: string}interface ImportMeta { readonly env: ImportMetaEnv}最佳实践:敏感信息(如 API 密钥)不应放在 .env 文件中提交到版本控制使用 .env.example 提供环境变量模板为环境变量定义 TypeScript 类型使用 VITE_ 前缀区分客户端和服务端变量在 CI/CD 中通过环境变量注入配置
阅读 0·2月19日 19:14

Vite 是什么?它相比 Webpack 有哪些优势?

Vite 是一个基于浏览器原生 ES 模块(ESM)的新一代前端构建工具,它利用了浏览器对 ESM 的原生支持,在开发环境中不需要打包即可直接运行代码。Vite 的核心优势在于:开发服务器启动速度:Vite 使用 esbuild 预构建依赖,esbuild 是用 Go 语言编写的,比传统的 JavaScript 打包工具(如 Webpack)快 10-100 倍。这使得 Vite 的冷启动时间通常在几百毫秒内,而 Webpack 可能需要几秒甚至更长时间。热模块替换(HMR)性能:Vite 的 HMR 基于原生 ESM,无论项目规模多大,HMR 更新都能保持快速。当文件修改时,Vite 只需要重新编译该文件,浏览器通过 ESM 动态导入机制获取更新,无需重新打包整个应用。生产环境构建:在生产环境中,Vite 使用 Rollup 进行打包,Rollup 能够生成优化的静态资源,包括代码分割、tree-shaking、CSS 代码分割等,确保生产环境的性能和加载速度。开箱即用的配置:Vite 提供了合理的默认配置,支持 TypeScript、JSX、CSS 预处理器、PostCSS 等现代前端技术栈,大部分情况下无需额外配置即可开始开发。插件生态:Vite 兼容 Rollup 插件,同时拥有丰富的官方和社区插件,可以轻松扩展功能。与传统构建工具对比:Webpack:需要打包整个依赖图,启动慢,HMR 在大型项目中性能下降Parcel:零配置但启动速度仍不如 ViteSnowpack:与 Vite 类似但 Vite 的生态和性能更优
阅读 0·2月19日 19:14

Vite 的依赖预构建(Dependency Pre-bundling)有什么作用?

Vite 的依赖预构建(Dependency Pre-bundling)是一个重要的优化机制,其作用和原理如下:为什么需要预构建:CommonJS 和 UMD 兼容性:许多 npm 包使用 CommonJS 或 UMD 格式,而 Vite 开发环境使用原生 ESM。预构建将这些模块转换为 ESM 格式,确保浏览器能够直接加载。性能优化:直接加载大量细粒度的 ESM 模块会导致数百个 HTTP 请求,严重影响性能。预构建将多个模块打包成单个 chunk,减少请求数量。ESM 转换:即使某些包已经是 ESM 格式,也可能包含不支持浏览器直接加载的特性(如裸模块导入),需要转换。预构建的工作流程:依赖扫描:Vite 扫描项目源代码,识别所有导入的依赖包。使用 esbuild 构建:Vite 使用 esbuild 将依赖打包到 node_modules/.vite 目录中,生成 ESM 格式的模块。缓存机制:预构建结果会被缓存,后续启动时如果依赖未变化,直接使用缓存,大幅提升启动速度。源码映射:生成 source map,确保调试时能定位到原始源码。配置选项:optimizeDeps.include:强制包含某些依赖进行预构建optimizeDeps.exclude:排除某些依赖不进行预构建optimizeDeps.esbuildOptions:自定义 esbuild 配置自动重新构建:当以下情况发生时,Vite 会自动重新预构建:package.json 中的依赖发生变化vite.config.js 配置文件变化手动删除 node_modules/.vite 缓存目录性能优势:通过依赖预构建,Vite 能够在保持快速开发体验的同时,解决 ESM 生态的兼容性和性能问题,这是 Vite 相比其他构建工具的核心优势之一。
阅读 0·2月19日 19:13