结合 Vite 和 Webpack 说一说打包工具都做了什么

1) 入口与模块图:把项目“地图”画出来 功能: 告诉工具“从哪儿开始找代码”,再顺着每个文件里的 import/require() 把所有会用到的文件串成一张网(依赖图)。 直觉类比: 从首页(入口)出发,顺着“超链接”(import)把整站爬一遍,得到网站地图。 Vite: Dev:浏览器请求哪个模块,就现查现用地把它和它的依赖挂到图上。 Build:交给 Rollup 从入口把整张图一次走完。 Webpack: 不分 Dev/Prod,都是先把整张图建好再工作。 常用配置: Vite:resolve.alias、build.rollupOptions.input Webpack:entry、resolve.alias、resolve.extensions、resolve.mainFields 2) 模块解析与格式兼容:不同“口味”的文件都能吃 功能: 让 ESM、CommonJS、CSS、图片、JSON… 这些不同格式都能作为“模块”被导入。 直觉类比: 餐厅后厨收菜,有中餐配料、西餐配料、饮料、甜点——都要能接收并分门别类。 Vite: Dev 期用原生 ESM;遇到 CJS 用 esbuild 转成 ESM;CSS/图片会被转成“虚拟模块”。 Webpack: 用 loader 把各种格式变成 JS 能理解的模块;静态资源用 asset/* 类型统一管理。 配置抓手: Vite:多数开箱即用;特殊包用 optimizeDeps.include/exclude。 Webpack:module.rules(css-loader/file-loader 等已被 asset 取代)、type:'asset/resource|inline|source'。 3) 源码转换(TS/JSX/ESNext):把“新语法”变成“大家都懂的” 功能: 把 TS、JSX、以及浏览器还不完全支持的新 JS 语法,变成兼容目标环境的普通 JS。 直觉类比: 把方言翻译成普通话;再按不同城市口音做点适配。 Vite: Dev 用 esbuild 快速转;Build 用 Rollup 插件链 + esbuild;必要时再上 Babel。 Webpack: 常用 swc-loader / esbuild-loader(快)或 ts-loader + babel-loader(灵活)。 配置抓手: ...

2025年11月5日

jsconfig 配置及注意事项

jsconfig 配置的作用 在某个目录放一个 jsconfig.json,VS Code 就把它当作JavaScript 项目根。文件里定义项目包含的源文件与语言服务选项,从而影响智能提示、自动导入、转到定义、错误检查等编辑器体验。(Visual Studio Code) VS Code 没有 jsconfig 也能工作,但当你的工作区里并非所有 JS 文件都属于同一个项目,或需要路径别名/包含范围等配置时,就应该创建它。(Visual Studio Code) 它本质上是 tsconfig.json 的“JS 版变体”,只作用于编辑器的 JS/JSX 语言服务(不参与打包)。(Visual Studio Code) 为什么/什么时候需要 VS Code JS 支持有两种模式: File Scope(无 jsconfig):每个文件独立,没有统一的项目上下文。 Explicit Project(有 jsconfig):用 jsconfig.json 明确项目边界与解析规则。 当你需要更准确的 IntelliSense、跨文件跳转、非相对导入/别名,建议使用 jsconfig。(GitHub) 常用配置项(高频) include / exclude:工程边界。只把 src/ 等需要的目录纳入项目。(Visual Studio Code) compilerOptions.baseUrl + paths:配置路径别名(如 @/),让 VS Code 能解析到定义并提供自动导入。(Visual Studio Code) checkJs:对 .js/.jsx 做 TS 级别类型检查(配合 JSDoc 与 .d.ts)以发现更多类型错误。(Visual Studio Code) jsx:设置 JSX 处理方式(如 React 17+ 的 react-jsx)。(Visual Studio Code) 其他常见:module、moduleResolution、resolveJsonModule、types 等,影响编辑器如何解析模块与可见的全局类型(例如 Node/React)。(Visual Studio Code) 小技巧:用命令面板 JavaScript: Go to Project Configuration 可检查当前文件是否被某个 jsconfig.json 管理。(Visual Studio Code) ...

2025年11月3日

为什么不应该在 Sidebar 组件中直接使用 useSessions Hook

引言 在 React 开发中,我们经常面临一个重要的架构决策:是否应该让组件直接使用业务逻辑 hooks,还是通过 props 传递数据和回调函数?本文将通过一个实际的聊天应用案例,分析为什么建议保持组件的数据流清晰,而不是在组件中直接使用业务逻辑 hooks。 问题背景 在我们的聊天应用中,有一个 Sidebar 组件负责显示聊天会话列表。最初的设计是: // 当前架构:通过 props 传递数据 <Sidebar sessions={sessions} currentSessionId={currentSessionId} onSelectSession={selectSession} onNewSession={createNewSession} onDeleteSession={deleteSession} isOpen={sidebarOpen} onToggle={() => setSidebarOpen(!sidebarOpen)} /> 有人可能会问:为什么不直接在 Sidebar 组件中使用 useSessions hook 呢? // 不推荐的架构:直接在组件中使用 hook export function Sidebar() { const { sessions, currentSessionId, selectSession, createNewSession, deleteSession, } = useSessions(); // ... } 为什么不建议在组件中直接使用业务逻辑 Hooks? 1. 关注点分离 (Separation of Concerns) 组件应该专注于 UI 渲染,而不是业务逻辑 // ✅ 好的做法:纯展示组件 export function Sidebar({ sessions, onSelectSession, onNewSession, onDeleteSession, }) { return ( <div> {sessions.map((session) => ( <button key={session.id} onClick={() => onSelectSession(session.id)}> {session.title} </button> ))} </div> ); } // ❌ 不好的做法:组件混合了业务逻辑 export function Sidebar() { const { sessions, selectSession } = useSessions(); // 业务逻辑混入组件 // ... } 2. 可测试性 (Testability) 纯组件更容易进行单元测试 ...

2025年8月21日

Zustand Store 状态同步问题分析与解决方案

问题背景 在使用 Zustand 构建复杂状态管理时,经常会遇到需要组合多个子 store 的场景。本文通过一个实际案例,分析了在组合 store 时遇到的状态同步问题,并提供了相应的解决方案。 问题描述 原始代码结构 const useDeviceStore = create((set, get) => ({ // 问题:这种方式只获取初始状态,不会响应子store的变化 ...useDeviceIdentityStore.getState(), ...useNetworkStatusStore.getState(), ...useOperationStatusStore.getState(), ...useDeviceInfoStore.getState(), _initialized: false, init: async () => { // 初始化逻辑 await useDeviceIdentityStore.getState().init(); set({ _initialized: true }); }, })); // src/pages/mainTab/index.jsx - 组件使用 const MainTab = () => { const deviceId = useDeviceStore((state) => state.deviceId); // 始终为空 const accessCode = useDeviceStore((state) => state.accessCode); // 始终为空 // ... }; 问题现象 设备初始化成功(控制台显示 deviceId: 'E00E40', accessCode: 'CJRA88') 但组件中获取到的 deviceId 和 accessCode 始终为空字符串 子 store 状态正常,主 store 状态不同步 问题根源 状态组合方式错误:使用 ...useDeviceIdentityStore.getState() 只会在 store 创建时获取一次初始状态,不会建立响应式连接。当子 store 状态更新时,主 store 不会自动同步。 ...

2025年8月2日