阅读 147

Vite零基础极速入门(vite和webpack的区别)

前言

作为前端开发者,或多或少都接触过打包工具,如 webpackRollupParcel等打包工具,它们极大地改善了前端开发者的开发体验。

然而,当我们开始构建越来越大型的应用时,需要处理的 JavaScript 代码量也呈指数级增长。包含数千个模块的大型项目相当普遍。我们开始遇到性能瓶颈 —— 使用 JavaScript 开发的工具通常需要很长时间(甚至是几分钟!)才能启动开发服务器,即使使用 HMR,文件修改后的效果也需要几秒钟才能在浏览器中反映出来。如此循环往复,迟钝的反馈会极大地影响开发者的开发效率和幸福感。

Vite 的出现就是想要解决上述的问题!

本文将分文两个大的部分:

  • Vite 概念和设计思想

  • Vite vs CRA

  • 使用 Vite + React 开发 ToDoList

正文

Vite 概念和设计思想

带着问题去思考:

  1. 什么是打包呢?

使用工具抓取、处理并将我们的源码模块串联成可以在浏览器中运行的文件。

  1. 那我们熟悉的常用的前端构建打包工具有哪些呢?:

webpack、rollup、pracel、gulp

  1. 这些传统的打包工具存在什么问题呢?

  • 缓慢的服务启动:当冷启动开发服务器时,基于打包器的方式启动必须优先抓取并构建你的整个应用,然后才能提供服务。

image.png

  • 缓慢的更新:基于打包器启动时,重建整个包的效率很低。原因显而易见:因为这样更新速度会随着应用体积增长而直线下降

  1. Vite 是怎么解决上述的问题?

  • Vite 通过在一开始将应用中的模块区分为 依赖 和 源码 两类,改进了开发服务器启动时间。

    • 依赖:Vite 将会使用 esbuild 预构建依赖。Esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍。

    • 源码:通常为JSX、CSS 或者 Vue SFC等,时常会被编辑,需要转换,基于路由拆分。

  • Vite 以 原生 ESM 方式提供源码。这实际上是让浏览器接管了打包程序的部分工作:Vite 只需要在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入代码,即只在当前屏幕上实际使用时才会被处理。

image.png

  • Vite 中,HMR 是在原生 ESM 上执行的。当编辑一个文件时,Vite 只需要精确地使已编辑的模块与其最近的 HMR 边界之间的链失活大多数时候只是模块本身),使得无论应用大小如何,HMR 始终能保持快速更新。

  • Vite 同时利用 HTTP 头来加速整个页面的重新加载(再次让浏览器为我们做更多事情):源码模块的请求会根据 304 Not Modified 进行协商缓存,而依赖模块请求则会通过 Cache-Control: max-age=31536000,immutable 进行强缓存,因此一旦被缓存它们将不需要再次请求。

最后再简单介绍一下, Vite 由两部分组成:

  • 一个开发服务,服务于开发环境,使用 ESM+HMR

  • 一套构建指令,服务于生产环境,使用 Rollup 打包

Vite vs CRA

你说好就好了?来点数据证明一下? 接下来使用 Vitecreate-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 复制代码

开始计时

image.png

*vanilla 是相当于原生 JS 不使用框架,其他几个应该都是框架,如图选择 react,然后输入以下命令

  cd vite-react   yarn   yarn dev 复制代码

执行以上命令,打开网页为止,停止计时 image.png

然后分别执行打包,进入package.json,查看打包命令,并执行:

yarn build 复制代码

分别记录时间,并查看打包产物的大小:Vite生成的工程,打包产物在dist 目录,CRA的在 build

表格记录对比:


ViteCRA
初始化时间48s1min 17s
打包时间3s11s
产物大小156kb565kb

结论:

以上只是在无业务代码的工程中测试,随着业务代码量级的提升,时间对比会更加的明显。

好了数据说话的过程也结束了,这下能放心了。

不过一学就会,一敲就废的情况我们还是要通过一些实战代码来避免一下。

使用 Vite + React 开发 ToDoList

复习一下刚才使用 Vite 来创建一个 React 工程:

个人的习惯,作者使用 Yarn:

$ yarn create vite 复制代码

framework 选择 reactvariant 根据个人是否启用 TS

推荐的一种目录,这些也因人而异,因项目大小而异:

image.png

接下来就是一些常规的 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 复制代码

image.png

域名会出现这这个位置:

image.png

结语

以上就是关于Vite快速入门的全部内容,欢迎大佬们指正。

天气转凉了,大家多喝热水,多注意保暖休息。


作者:推啊前端团队
链接:https://juejin.cn/post/7029204845802307598


文章分类
代码人生
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐