Vite零基础极速入门(vite和webpack的区别)
前言
作为前端开发者,或多或少都接触过打包工具,如 webpack
、Rollup
、Parcel
等打包工具,它们极大地改善了前端开发者的开发体验。
然而,当我们开始构建越来越大型的应用时,需要处理的 JavaScript
代码量也呈指数级增长。包含数千个模块的大型项目相当普遍。我们开始遇到性能瓶颈 —— 使用 JavaScript
开发的工具通常需要很长时间(甚至是几分钟!)才能启动开发服务器,即使使用 HMR
,文件修改后的效果也需要几秒钟才能在浏览器中反映出来。如此循环往复,迟钝的反馈会极大地影响开发者的开发效率和幸福感。
Vite
的出现就是想要解决上述的问题!
本文将分文两个大的部分:
Vite
概念和设计思想Vite
vsCRA
使用
Vite + React
开发ToDoList
正文
Vite
概念和设计思想
带着问题去思考:
什么是打包呢?
使用工具抓取、处理并将我们的源码模块串联成可以在浏览器中运行的文件。
那我们熟悉的常用的前端构建打包工具有哪些呢?:
webpack、rollup、pracel、gulp
这些传统的打包工具存在什么问题呢?
缓慢的服务启动:当冷启动开发服务器时,基于打包器的方式启动必须优先抓取并构建你的整个应用,然后才能提供服务。
缓慢的更新:基于打包器启动时,重建整个包的效率很低。原因显而易见:因为这样更新速度会随着应用体积增长而直线下降。
Vite
是怎么解决上述的问题?
Vite
通过在一开始将应用中的模块区分为 依赖 和 源码 两类,改进了开发服务器启动时间。依赖:Vite 将会使用
esbuild
预构建依赖。Esbuild
使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍。源码:通常为JSX、CSS 或者 Vue SFC等,时常会被编辑,需要转换,基于路由拆分。
Vite
以 原生 ESM 方式提供源码。这实际上是让浏览器接管了打包程序的部分工作:Vite 只需要在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入代码,即只在当前屏幕上实际使用时才会被处理。
在
Vite
中,HMR
是在原生ESM
上执行的。当编辑一个文件时,Vite
只需要精确地使已编辑的模块与其最近的 HMR 边界之间的链失活大多数时候只是模块本身),使得无论应用大小如何,HMR 始终能保持快速更新。Vite
同时利用HTTP
头来加速整个页面的重新加载(再次让浏览器为我们做更多事情):源码模块的请求会根据304 Not Modified
进行协商缓存,而依赖模块请求则会通过Cache-Control: max-age=31536000,immutable
进行强缓存,因此一旦被缓存它们将不需要再次请求。
最后再简单介绍一下, Vite
由两部分组成:
一个开发服务,服务于开发环境,使用
ESM+HMR
一套构建指令,服务于生产环境,使用
Rollup
打包
Vite
vs CRA
你说好就好了?来点数据证明一下? 接下来使用 Vite
和 create-react-app
来构建以及打包,并记录时间来对比一下:
首先使用create-react-app
创建一个空的React
工程:
开始计时
npx create-react-app my-app cd my-app npm start 复制代码
执行以上命令,打开网页为止,停止计时,记录构建时间
使用 Vite
创建一个空的React
工程(Vite
虽然是尤大大写的但是对 React
的支持甚至比 Vue
更好):
使用 NPM:
$ npm init vite@latest 复制代码
使用 Yarn:
$ yarn create vite 复制代码
使用 PNPM:
$ pnpm create vite 复制代码
开始计时
*vanilla
是相当于原生 JS
不使用框架,其他几个应该都是框架,如图选择 react,然后输入以下命令
cd vite-react yarn yarn dev 复制代码
执行以上命令,打开网页为止,停止计时
然后分别执行打包,进入package.json,查看打包命令,并执行:
yarn build 复制代码
分别记录时间,并查看打包产物的大小:Vite生成的工程,打包产物在dist
目录,CRA的在 build
;
表格记录对比:
Vite | CRA | |
---|---|---|
初始化时间 | 48s | 1min 17s |
打包时间 | 3s | 11s |
产物大小 | 156kb | 565kb |
结论:
以上只是在无业务代码的工程中测试,随着业务代码量级的提升,时间对比会更加的明显。
好了数据说话的过程也结束了,这下能放心了。
不过一学就会,一敲就废的情况我们还是要通过一些实战代码来避免一下。
使用 Vite + React
开发 ToDoList
复习一下刚才使用 Vite
来创建一个 React
工程:
个人的习惯,作者使用 Yarn:
$ yarn create vite 复制代码
framework
选择 react
,variant
根据个人是否启用 TS
:
推荐的一种目录,这些也因人而异,因项目大小而异:
接下来就是一些常规的 React
开发;
main.tsx
:
import React from "react"; import ReactDOM from "react-dom"; import App from "./App"; import 'antd/dist/antd.css'; import './index.css' ReactDOM.render(<App />, document.getElementById("root")); 复制代码
App.tsx
:
import { useState } from "react"; import ToDoItem from "../components/ToDoItem"; import ToDoContainer from '../components/ToDoContainer' import { TodoItemType } from "../constans"; function App() { const [todos,setTodos] = useState<TodoItemType[]|[]>([]) const handleSubmit = (todoItem: any)=>{ console.log(todoItem) setTodos([ ...todos, todoItem ]) } const handleOpreta =(todoItem:TodoItemType)=>{ const newTodos = todos.filter(todo =>todoItem.id !== todo.id) newTodos.push(todoItem) console.log(newTodos) setTodos(newTodos) } return ( <div className="todo-app"> <h2 className="todo-title">代办清单</h2> <ToDoItem onSubmit={handleSubmit} /> <ToDoContainer onOpreta={handleOpreta} todos={todos}/> </div> ); } export default App; 复制代码
/components/ToDoContainer/index.tsx
:
import { List, Radio } from "antd"; import { STATUS, TodoItemType } from "../../constans"; import { CheckOutlined, CloseCircleOutlined } from "@ant-design/icons"; import { useState } from "react"; const ToDoContainer = (props: { todos?: TodoItemType[] | undefined; onOpreta: (arg: TodoItemType) => void; }) => { const { todos = [], onOpreta } = props; const [optionsValue, setOptionsValue] = useState(STATUS.IS_CREATE); const options = [ { label: "全部", value: '' }, { label: "代办", value: STATUS.IS_CREATE }, { label: "已办", value: STATUS.IS_DONE }, { label: "已删除", value: STATUS.IS_DELETE }, ]; const handleChangeRadio = (e: any) => { console.log(e.target.value); setOptionsValue(e.target.value); }; const handleOpreta = (opretaType: string, todo: TodoItemType) => { switch (opretaType) { case "is-delete": onOpreta && onOpreta({ ...todo, status: STATUS.IS_DELETE, }); break; case "is-done": onOpreta && onOpreta({ ...todo, status: STATUS.IS_DONE, }); break; default: break; } }; return ( <div> <Radio.Group options={options} onChange={handleChangeRadio} value={optionsValue} optionType="button" buttonStyle="solid" /> <List className="todo" dataSource={todos} renderItem={(todo) => optionsValue === todo.status && ( <List.Item className="todo-list-item-container"> {todo.content} <div> <CloseCircleOutlined onClick={() => handleOpreta("is-delete", todo)} /> <CheckOutlined onClick={() => handleOpreta("is-done", todo)} /> </div> </List.Item> ) } /> </div> ); }; export default ToDoContainer; 复制代码
/components/ToDoItem/index.tsx
:
import { Button, Input } from "antd"; import { useState } from "react"; import { STATUS } from "../../constans"; const ToDoItem = (props: { onSubmit: (todoItem: any) => void }) => { const { onSubmit } = props; const [todoItem, setToDoItem] = useState({ id: Math.random(), content: "", status: STATUS.IS_CREATE, }); const handleSubmit = (e: any) => { onSubmit && onSubmit({ ...todoItem, id: Math.random() }); }; const handleInpurChange = (e: any) => { setToDoItem({ ...todoItem, content: e.target.value, }); }; return ( <div className="todo-item-input"> <Input value={todoItem.content} onPressEnter={handleSubmit} onChange={handleInpurChange} /> <Button size="large" type="primary" onClick={handleSubmit}> 提交 </Button> </div> ); }; export default ToDoItem; 复制代码
/constans/index.ts
:
export interface TodoItemType{ id:number, content:string, status:number } export const STATUS = { /** * 全部 */ /** * 代办 */ IS_CREATE:0, /** * 已解决 */ IS_DONE:1, /** * 假删除 */ IS_DELETE:2 } 复制代码
代码也没有完善,大家可以在我基础上进行完善。 ··· 开发完了,当然还有部署,推荐一个免费在线的部署网站:app.netlify.com/ ,使用github就能够直接登录
执行打包命令:
yarn build 复制代码
域名会出现这这个位置:
结语
以上就是关于Vite快速入门的全部内容,欢迎大佬们指正。
天气转凉了,大家多喝热水,多注意保暖休息。
作者:推啊前端团队
链接:https://juejin.cn/post/7029204845802307598