基于 Vite 从 0 到 1 启动一个 React 项目

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情

如果不使用 Vite 官方提供的 template 选项,要如何从一个 Vite 依赖的情况下逐步配置启动一个 React?如何实现 Webpack 的静态资源服务,如何实现基于 WebpackloaderJSX 的自动转换

下面是这个项目运行效果,以及完整的示例源代码

IMG

普通启动

如果你是刚开始接触 HTML/CSS/JavaScript 三件套开始接触的前端,那么你可能比较熟悉或者比较能接受的引入 React 的方式可能是使用 CDN 的方式,大概如下(下面这个是我要介绍的例子)

<head>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
</head>
<body>
  <div id="root"></div>
</body>
<script>
  const useState = React.useState;
  const createElement = React.createElement;

  function App() {
    const [count, setCount] = useState(0);

    const handleClick = () => {
     setCount((count) => count + 1);
    };

    return createElement("div", {
      children: [
        "count:" + count,
        createElement(
          "button",
          {
            key: "2",
            onClick: handleClick,
          },
          "click + 1"
        ),
      ],
    });
  }

  const root = ReactDOM.createRoot(document.getElementById("root"));
  root.render(
    createElement(React.StrictMode, {
      children: [createElement(App, { key: "1" })],
    })
  );
</script>

但这种方式是基于 React.createElement 去编写 DOM 的代码的,React 中比较常用的是 JSX 语法,它们的文档认为 JSX

它有助于编写UI代码 – 无论是使用 React 还是其他库。

React 的文档推荐使用 JSX 的方式是使用 babel 转换,其实使用 babel 这已经涉及到前端工程化的初步阶段了,因为使用 babel 需要使用 node.js,毕竟你知道了 node.js 后就会知道 npm 就会知道 webpack 就会知道 create-react-app

所以一般来说接触 React 的同学很快会过度到基于 Node.js 的现代前端工程化开发

关于什么是基于 Node.js 的现代前端工程化开发?也许就是下面的 Vite

IMG

Vite 启动

在进入 Vite 配置之前先做好基于 Node.js 环境的配置

“Node.js” 配置

先找个位置并在终端(或者命令行)初始化一个项目

npm init

初始化后会有一些选项,可以直接回车全部忽略,也可以根据自己意向填写

IMG

选择完成之后

IMG

这个时候系统会创建一个 package.json 文件

IMG

喜欢记录的同学可以添加 git(记得添加 .gitignore 避免添加 node_modules/.vscode/.idea 进入版本依赖)

git init

然后将上面的 HTML 例子的 CDN 切换成 npm 包,比如在终端/命令行执行以下命令

npm install react react-dom

解构 “HTML”

下载完 React 系列套件的依赖后,就需要将上面的 html 例子进行解构,创建 ./src/index.js./src/App.js./index.html

./ 指代当前工作目录(根目录)

将上面的 html 的例子转换成下面的结构

// App.js
import { useState, createElement } from "react";

function App() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount((count) => count + 1);
  };

  return createElement("div", {
    children: [
      "count:" + count,
      createElement(
        "button",
        {
          key: "2",
          onClick: handleClick,
        },
        "click + 1"
      ),
    ],
  });
}

export default App;
// index.js
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  React.createElement(React.StrictMode, {
    children: [React.createElement(App, { key: "1" })],
  })
);

注意,在 .js 文件中都是使用的 ES Module 而不是 Commonjs 规范是因为此处编写的 .js 将直接在浏览器中运行并且不会配置类似 Webpack 提供的统一规范配置和转换

<!-- index.html -->
<body>
  <div id="root"></div>
</body>
<script src="./src/index.js"></script>

此时的文件目录结构

├── node_modules
├── public
|  └── index.html
├── src
|  ├── App.js 
|  └── index.js
├── package-lock.json
├── package.json

配置 Vite

  1. 下载 Vite 依赖
npm install -D vite
  1. 在根目录创建 Vite 配置文件,vite.config.js
// vite.config.js
import { defineConfig } from "vite";

// https://vitejs.dev/config/
export default defineConfig({
  // root 默认值是 process.cwd(), 即当前工作文件夹
  // index.html 中引用的 .js 需要在同一个 root 目录下
  root: process.cwd(),
  server: {
    port: 5173, // 默认端口是 5173
  },
});

注意,Vite关于运行配置里只有 index.html 需要指定,并不像 webpack 那样需要指定一个 .js 的入口文件,这是因为 Wepback 需要打包模块至一个 .js 文件而 Vite 是采用逐个请求处理后的模块

  1. 配置 package.json 的脚本
{
  // ..
  "scripts": {
    // 新增部分
    "dev": "vite",
  },
  // ...
  "dependencies": {
    "vite": "^3.2.4",
    // ...
  }
  // ...
}
  1. 运行 npm run start,得到预期效果

IMG

配置 JSX

JSXReact 的地位等同于 VueSFC,项目里面不配置一下完全无法展开呀!可以看到上面的 HTML 例子其实使用了 React.createElement 代替 JSX,接下来就为了更好的开发体验配置一下 JSX

  1. 下载 @vitejs/plugin-react 依赖
npm install -D @vitejs/plugin-react
  1. vite.config.js 新增以下内容
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  // ...
  plugins: [react()],
});

@vitejs/plugin-react 的底层其实是 @babel/plugin-transform-react-jsx,和 WebpackJSX 配置中 @babel/preset-react 用的是同一个,@vitejs/plugin-react 同样也支持 .babelrcbabel.config.js 配置

  1. 修改项目中关于 React.createElementJSX,并修改文件后缀为 .jsx
// index.js -> index.jsx
// ...
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
// App.js -> App.jsx
import { useState } from "react";

function App() {
  // ...

  return (
    <div>
      {"count:" + count}
      <button onClick={handleClick}>click + 1</button>
    </div>
  );
}

export default App;
<!-- index.html -->
<body>
  <div id="root"></div>
</body>
<script src="./src/index.jsx"></script>
  1. 运行 npm run start,得到预期效果

IMG

留空问题

在阅读文章的时候可以去思考一些问题,比如

  1. Webpack 在打包的过程中会有转换(transform)的流程,这是 loaderplugin 干的事,比如 .vue to .js,又比如 html-webpack-plugin 会对打包 .js 对静态资源服务的 index.html 的变量自动导入,那么 Vite 是如何解决这些问题的呢?
    1. Vite 实际请求的 module 是否有经过 transform

附带 Vite 原理图

IMG

参考资料

  1. @vitejs/plugin-react – npm
© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容