拿来吧你!从零搭建一个Vite-React脚手架(附源码)

写在开头(边听歌边看效果更佳)
  • 在之前,已经很多朋友已经升级到了vite,但是大部分都是vue的项目,那么今天我们把之前webpackreact项目升级到vite!

  • 为此,为了让大家少踩坑,我先把china-dev.cn这个网站项目升级到了vite

  • 对于在线画图功能,可能没有什么影响,但是跟在线编写javascript这个功能影响挺大,因为之前使用的库,会跟webpack绑定,目前不支持vite,于是我更换了技术栈,但是效果反而更好了~,这说明,跟webpack强绑定是一个伪命题,办法总比困难多,构建工具只是一种选择而已~

正式开始

如果你没看过我之前写的:webpack和vite的核心区别,建议你先看一遍,再来看这篇文章

  • Vite和Webpack的核心差异

  • webpack迁移到vite,最先要解决的事情:

    • 把跟webpack强关联的插件&技术栈解耦,任何时候,跟一个第三方工具&环境强依赖,都不是一件好事,这一点,做过重型系统部署的架构师,相信都有这个感触

    • 将项目中除了import引入方式的,全部替换成通过import引入。可以这样说,esm就是一种趋势,因为它就是一个规范。vue3已经不支持ie11,替换国内老旧系统只是时间而已,这是一个大趋势,深圳官方的一些网站已经开始推荐你使用新的浏览器了~

    • 规范你的代码,不能出现typescript的类型错误等和其他警告等,vite的热更新非常脆弱,有可能你一个小的警告或不规范写法,就会导致热更新失效,而且报错定位不准,或者直接不报错,而是失效(下面会说这些坑)

  • 接下来 克隆我的脚手架到本地

    • 地址 https://github.com/JinJieTan/Peter-/tree/master/vite-react-ts-antd

    • 将你的src源码目录植入我的项目模板中

    • 项目根目录执行yarn安装依赖

    • index.hmtl入口文件,我这里默认是去加载src/index.tsx文件

    • 执行 yarn dev, 启动项目 ,如果此时你的代码没问题,已经run起来了(我项目中默认是react17.x,ts4.x版本,如果需要降级,请你安装指定依赖)


脚手架说明:
  • 通过husky在每次git commit 时候使用prettier统一美化代码,再通过eslint进行代码检测,最终使用commitlint提交信息是否符合要求,以此保证代码质量

这几十条规则,都是我一条一条精挑细选出来的,因为我不喜欢用不清楚别人细节的东西,这套规则我也希望大家用下去,每一条都有注释

 rules: {
        semi: ['error', 'always'], // 该规则强制使用一致的分号
        'no-unused-vars': 'off', // 禁止未使用过的变量
        'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', //生产环境禁用 debugger
        'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', //生产环境禁用 console
        'default-case': ['warn', { commentPattern: '^no default$' }], //要求 Switch 语句中有 Default
        'dot-location': ['warn', 'property'], // 强制在点号之前或之后换行
        eqeqeq: ['error', 'allow-null'], //要求使用 === 和 !==
        'new-parens': 'warn', //要求调用无参构造函数时带括号
        'no-caller': 'error', // 禁用 caller 或 callee
        'no-const-assign': 'error', //不允许改变用 const 声明的变量
        'no-dupe-args': 'error', //禁止在 function 定义中出现重复的参数
        'no-dupe-class-members': 'error', //不允许类成员中有重复的名称
        'no-dupe-keys': 'warn', //禁止在对象字面量中出现重复的键
        'no-extend-native': 'warn', //禁止扩展原生对象
        'no-extra-bind': 'warn', //禁止不必要的函数绑定
        'no-fallthrough': 'error', //禁止 case 语句落空
        'no-func-assign': 'warn', //禁止对 function 声明重新赋值
        'no-implied-eval': 'error', //禁用隐式的 eval()
        'no-label-var': 'error', //禁用与变量同名的标签
        'no-loop-func': 'error', //禁止循环中存在函数
        'no-mixed-operators': [
            'warn',
            {
                groups: [
                    ['&', '|', '^', '~', '<<', '>>', '>>>'],
                    ['==', '!=', '===', '!==', '>', '>=', '<', '<='],
                    ['&&', '||'],
                    ['in', 'instanceof'],
                ],
                allowSamePrecedence: false,
            },
        ], //禁止混合使用不同的操作符
        'no-multi-str': 'warn', //禁止多行字符串 (需要多行时用\n)
        'no-native-reassign': 'warn', //禁止重新分配本地对象
        'no-obj-calls': 'warn', //禁止将全局对象当作函数进行调用
        'no-redeclare': 'error', //禁止重新声明变量
        'no-script-url': 'warn', //禁用 Script URL
        'no-shadow-restricted-names': 'warn', //关键字不能被遮蔽
        'no-sparse-arrays': 'warn', //禁用稀疏数组
        'no-this-before-super': 'warn', //在构造函数中禁止在调用 super()之前使用 this 或 super
        'no-undef': 'error', //禁用未声明的变量
        'no-unexpected-multiline': 'warn', //禁止使用令人困惑的多行表达式
        'no-use-before-define': [
            'warn',
            {
                functions: false,
                classes: false,
                variables: false,
            },
        ], //禁止定义前使用
        'no-with': 'error', //禁用 with 语句
        radix: 'error', //禁用函数内没有 yield 的 generator 函数
        'rest-spread-spacing': ['warn', 'never'], //强制限制扩展运算符及其表达式之间的空格
        'react/jsx-no-undef': 'error', //在 JSX 中禁止未声明的变量
        'react/no-direct-mutation-state': 'error', //禁止 this.state 的直接变化
        'react/jsx-uses-react': 'warn', //防止 React 被错误地标记为未使用
        'no-alert': 0, //禁止使用alert confirm prompt
        'no-duplicate-case': 2, //switch中的case标签不能重复
        'no-eq-null': 2, //禁止对null使用==或!=运算符
        'no-inner-declarations': [2, 'functions'], //禁止在块语句中使用声明(变量或函数)
        'no-iterator': 2, //禁止使用__iterator__ 属性
        'no-negated-in-lhs': 2, //in 操作符的左边不能有!
        'no-octal-escape': 2, //禁止使用八进制转义序列
        'no-plusplus': 0, //禁止使用++,--
        'no-self-compare': 2, //不能比较自身
        'no-undef-init': 2, //变量初始化时不能直接给它赋值为undefined
        'no-useless-call': 2, //禁止不必要的call和apply
        'init-declarations': 0, //声明时必须赋初值
        'prefer-const': 0, //首选const
        'use-isnan': 2, //禁止比较时使用NaN,只能用isNaN()
        'vars-on-top': 2, //var必须放在作用域顶部
    },
  • 支持ant-design按需加载

import vitePluginImp from "vite-plugin-imp";
plugins:[
...,
 vitePluginImp({
      libList: [
        {
          libName: "antd",
          style(name) {
            if (/CompWithoutStyleFile/i.test(name)) {
              return false;
            }
            return `antd/es/${name}/style/index.css`;
          },
        },
      ],
    }),
]
  • 执行无感知热更新:

import reactRefresh from "@vitejs/plugin-react-refresh";
plugins:[
  ...,
  reactRefresh(),
]
  • 兼容不支持esm的浏览器

import legacy from "@vitejs/plugin-legacy";

plugins:[
...,
 legacy({
      targets: ["defaults", "not IE 11"],
    }),
]
  • 支持ts在vite中的alias配置

vite.config.ts
resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
      "@c": path.resolve(__dirname, "./src/components"),
      "@s": path.resolve(__dirname, "./src/service"),
      "@m": path.resolve(__dirname, "./src/model"),
    },
  },
  
tsconfig.json中
"baseUrl": "./",
    "paths": {
      "@/*": ["./src/*"],
      "@c/*": ["./src/components/*"],
      "@m/*": ["./src/model/*"],
      "@s/*": ["./src/service/*"],
      "@t/*": ["./src/types/*"]
    }
遇到的问题
  • 第三方库之前跟webpack插件有绑定,而vite不支持,最后更换了技术栈

  • vite热更新问题,这个问题应该很多人都会遇到,但是我踩坑一天后,就没有再遇到了。viteprod模式构建,是通过tsc转换成js后,再通过rollup进行打包,但是先yarn build后,就会在tsx附近产生js文件,例如:

在这个时候,无论是热更新模式,还是prod构建,都是会去打包js文件,后面我删除后就解决了这个问题。

  • 当然,vite热更新还有一个问题,就是你可能会因为一个警告,就热更新失效,而且报错定位也不准确,当系统变得极度复杂的时候,这个问题就很致命。

  • 原生不支持less,需要安装以下依赖,即可直接引入使用less,这点我觉得优于webpack

yarn add less less-loader -D
使用下来感受
  • 开发模式,比webpack好太多。基本上毫秒级别的启动和热更新速度

  • 配置也比较简单,没有webpack那一大堆东西

  • 纯粹,干净。没有require.context这种黑魔法,没有上面是import,下面代码里面是require。全部都是import

有人会问,如果老的库不兼容esm,怎么办,例如dva

module.exports = require('./lib');
module.exports.connect = require('react-redux').connect;
  • 这就有一个问题,esm在生产模式中无法直接引入dva,这个时候可以做一个简单的处理,可以优先取default属性,如果取不到,就取默认的

import dva from "dva";
let tag = dva.default || dva;
const app = test({
  history: createHistory(),
});
写在最后

看得再多,不如直接动手实践,克隆我这个模板下来试试吧。别忘了给个star,开源不易,里面还有其他的源码,https://github.com/JinJieTan/Peter-/tree/master/vite-react-ts-antd

往期推荐

Vite 太快了,烦死了,是时候该小睡一会了。


如何实现比 setTimeout 快 80 倍的定时器?


万字长文!总结Vue 性能优化方式及原理


90 行代码的 webpack,你确定不学吗?


如果你觉得这篇内容对你挺有启发,我想邀请你帮我三个小忙:

  1. 点个「在看」,让更多的人也能看到这篇内容(喜欢不点在看,都是耍流氓 -_-)

  2. 欢迎加我微信「huab119」拉你进技术群,长期交流学习...

    关注公众号「前端劝退师」,持续为你推送精选好文,也可以加我为好友,随时聊骚。

点个在看支持我吧,转发就更好了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值