浅谈create-react-app和vite两种不同手脚架下的常用配置

841 阅读4分钟

一、前言

本文主要记录create-react-appvite这两种不同手脚架下的常用配置,如配置别名路径打包体积分析按需导入CSS样式配置CDN路由懒加载等。

二、create-react-app的常用配置

  • create-react-app 将所有工程化配置,都隐藏在了 react-scripts 包中,所以项目中看不到任何配置信息
  • 如果要修改 create-react-app 的默认配置,有以下几种方案:
    • 通过第三方库来修改,比如,@craco/craco  (推荐
    • 通过执行 pnpm run eject 命令,释放 react-scripts 中的所有配置到项目中

2.1 配置别名路径

实现步骤

  1. 安装修改 CRA 配置的包:pnpm i -D @craco/craco
  2. 在项目根目录中创建 craco 的配置文件:craco.config.js,并在配置文件中配置路径别名
  3. 修改 package.json 中的脚本命令
  4. 在代码中,就可以通过 @ 来表示 src 目录的绝对路径
  5. 重启项目,让配置生效

代码实现

craco.config.js

const path = require('path')

module.exports = {
  // webpack 配置
  webpack: {
    // 配置别名
    alias: {
      // 约定:使用 @ 表示 src 文件所在路径
      '@': path.resolve(__dirname, 'src')
    }
  }
}

package.json

// 将 start/build/test 三个命令修改为 craco 方式
"scripts": {
  "start": "craco start",
  "build": "craco build",
  "test": "craco test",
  "eject": "react-scripts eject"
}

IDE之@别名路径提示

为了能够让VSCode/WebStorm等IDE识别@路径并给出路径提示,需要:

  1. 在项目根目录创建 jsconfig.json 配置文件
  2. jsconfig.json文件中添加以下配置
{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

2.2 打包体积分析

使用步骤

  1. 安装分析打包体积的包:pnpm i -D source-map-explorer
  2. package.json 中的 scripts 标签中,添加分析打包体积的命令
  3. 对项目打包:pnpm run build(如果已经打过包,可省略这一步)
  4. 运行分析命令:pnpm analyze
  5. 通过浏览器打开的页面,分析图表中的包体积

核心代码

package.json

"scripts": {
  "analyze": "source-map-explorer 'build/static/js/*.js' --html stats.html"
}

2.3 按需导入CSS样式

craco社区有提供相关插件,可实现按需导入CSS样式,下面以antd为例

使用步骤

  1. 安装相关包craco-antdpnpm i -D craco-antd (注意:该包对react-scripts@craco/craco的版本有要求,详见插件说明文档)
  2. craco.config.js文件中新增配置

核心代码

const CracoAntDesignPlugin = require('craco-antd')

module.exports = {
  plugins: [
    {
      plugin: CracoAntDesignPlugin,
      options: {
        babelPluginImportOptions: {
          libraryDirectory: 'es',
        },
      },
    },
  ],
}

2.4 配置CDN

分析说明:通过 craco 来修改 webpack 配置,从而实现 CDN 优化

核心代码

craco.config.js

const { whenProd, getPlugin, pluginByName } = require('@craco/craco')

module.exports = {
  webpack: {
    // 配置CDN
    configure: (webpackConfig) => {
      // webpackConfig自动注入的webpack配置对象
      // 可以在这个函数中对它进行详细的自定义配置
      // 只要最后return出去就行
      let cdn = {
        js: [],
        css: [],
      }
      // 只有生产环境才配置
      whenProd(() => {
        // key:需要不参与打包的具体的包
        // value: cdn文件中 挂载于全局的变量名称 为了替换之前在开发环境下
        // 通过import 导入的 react / react-dom
        webpackConfig.externals = {
          echarts: 'echarts',
        }
        // 配置现成的cdn 资源数组 现在是公共为了测试
        // 实际开发的时候 用公司自己花钱买的cdn服务器
        cdn = {
          js: [
            'https://cdn.jsdelivr.net/npm/echarts@5.4.1/dist/echarts.min.js',
          ],
          css: [],
        }
      })

      // 都是为了将来配置 htmlWebpackPlugin插件 将来在public/index.html注入
      // cdn资源数组时 准备好的一些现成的资源
      const { isFound, match } = getPlugin(
        webpackConfig,
        pluginByName('HtmlWebpackPlugin')
      )

      if (isFound) {
        // 找到了HtmlWebpackPlugin的插件
        match.userOptions.cdn = cdn
      }

      return webpackConfig
    }
  }
}

public/index.html

<body>
    <div id="root"></div>
    <!-- 加载第三发包的 CDN 链接 -->
    <% htmlWebpackPlugin.options.cdn.js.forEach(cdnURL => { %>
    <script src="<%= cdnURL %>"></script>
    <% }) %>
</body>

三、vite的常用配置

3.1 配置别名路径

vite.config.js

import path from 'path'
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [
    react(),
  ],
  resolve: {
    alias: {
      // 约定:使用 @ 表示 src 文件所在路径
      '@': path.resolve(__dirname, './src'),
    },
  },
})

3.2 打包体积分析

使用步骤

  1. 安装分析打包体积的包:pnpm i -D rollup-plugin-visualizer
  2. vite.config.js文件中新增配置
  3. 对项目打包:pnpm run build
  4. 通过浏览器打开的页面,分析图表中的包体积

核心代码

vite.config.js

import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
  plugins: [
    visualizer(),
  ],
})

3.3 按需导入CSS样式

以antd为例

使用步骤

  1. 安装相关包vite-plugin-style-importlesspnpm i -D vite-plugin-style-import less
  2. vite.config.js文件中新增配置

核心代码

import { createStyleImportPlugin, AntdResolve } from 'vite-plugin-style-import'

export default defineConfig({
plugins: [
    createStyleImportPlugin({ resolves: [AntdResolve()] }),
  ],
  css: {
    preprocessorOptions: {
      less: {
        javascriptEnabled: true,
      },
    },
  },
})

3.4 配置CDN

使用步骤

  1. 安装包:pnpm i -D vite-plugin-cdn-import
  2. vite.config.js文件中新增配置

核心代码

import { Plugin as importToCDN } from 'vite-plugin-cdn-import'

export default defineConfig({
  plugins: [
    importToCDN({
      modules: [
        {
          name: 'echarts',
          var: 'echarts',
          path: 'https://cdn.jsdelivr.net/npm/echarts@5.4.1/dist/echarts.min.js'
        }
      ]
    })
  ]
})

四、其他

4.1 路由懒加载

目标

能够对路由进行懒加载实现代码分隔

使用步骤

  1. 在 App 组件中,导入 Suspense 组件
  2. 在 路由Router 内部,使用 Suspense 组件包裹组件内容
  3. 为 Suspense 组件提供 fallback 属性,指定 loading 占位内容
  4. 导入 lazy 函数,并修改为懒加载方式导入路由组件

代码实现

App.jsx

import { Route, Routes } from 'react-router-dom'
import { AuthRoute } from '@/components/AuthRoute'
import { HistoryRouter, history } from '@/utils'
import { Spin } from 'antd'
// 导入必要组件
import { lazy, Suspense } from 'react'
// 按需导入路由组件
const Login = lazy(() => import('@/pages/Login'))
const Layout = lazy(() => import('@/pages/Layout'))
const Home = lazy(() => import('@/pages/Home'))
const Article = lazy(() => import('@/pages/Article'))
const Publish = lazy(() => import('@/pages/Publish'))

function App() {
  return (
    <HistoryRouter history={history}>
      <div className="app">
        <Suspense fallback={<Spin className="spin" size="large" />}>
          <Routes>
            {/* 需要鉴权的路由 */}
            <Route
              path="/"
              element={
                <AuthRoute>
                  <Layout />
                </AuthRoute>
              }
            >
              {/* 二级路由默认页面 */}
              <Route index element={<Home />} />
              <Route path="article" element={<Article />} />
              <Route path="publish" element={<Publish />} />
            </Route>
            {/* 不需要鉴权的路由 */}
            <Route path="/login" element={<Login />}></Route>
          </Routes>
        </Suspense>
      </div>
    </HistoryRouter>
  )
}

export default App