美文网首页
如何基于 Vite 开发 React 和 Koa 全栈程序

如何基于 Vite 开发 React 和 Koa 全栈程序

作者: 一蓑烟雨任平生_cui | 来源:发表于2022-07-18 18:49 被阅读0次

    基于 Vite 开发 React 和 Koa 全栈程序

    创建一个新的 Vite 应用

    pnpm create vite react-kao-app -- --template react
    

    进入项目安装依赖:

    cd react-koa-app
    pnpm i
    

    项目结构如下:


    image.png

    配置 vite

    修改包的入口配置为 src/main.jsx,而不是根目录下默认的 index.html

    import { defineConfig } from 'vite'
    import react from '@vitejs/plugin-react'
    
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [react()],
      // 新增 build 配置
      build: {
        manifest: true,
        rollupOptions: {
          input: './src/main.jsx'
        }
      }
    })
    

    重新组织项目结构

    mv index.html public/
    

    然后覆盖 index.html 文件的内容为:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <link rel="icon" type="image/svg+xml" href="/vite.svg" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Vite App</title>
      </head>
      <body>
        <div id="root"></div>
        <script type="module">
          import RefreshRuntime from 'http://localhost:5173/@react-refresh'
          RefreshRuntime.injectIntoGlobalHook(window)
          window.$RefreshReg$ = () => {}
          window.$RefreshSig$ = () => type => type
          window.__vite_plugin_react_preamble_installed__ = true
        </script>
        <script type="module" src="http://localhost:5173/src/main.jsx"></script>
      </body>
    </html>
    

    @react-refresh相关的代码是因为vite启动后在index.html中注入这些代码来实现HMR,因为我是通过node的服务读取的html文件,所以需要手动注入。

    创建服务

    touch server.js
    pnpm add koa
    

    编写 server.js

    const Koa = require('koa')
    const path = require('path')
    const sendfile = require('koa-sendfile')
    const serve = require('koa-static')
    const app = new Koa()
    
    // static
    app.use(serve(path.join(__dirname, 'public')))
    
    // 404
    app.use(async (ctx, next) => {
      await next()
    
      if (ctx.status === 404) {
        await sendfile(ctx, path.resolve(__dirname, 'public/index.html'))
      }
    })
    
    app.listen(5000, () => {
      console.log()
      console.log('App runing in port 5000...')
      console.log()
      console.log(`  > Local: \x1b[36mhttp://localhost:\x1b[1m5000/\x1b[0m`)
    })
    

    这样启动服务后,读取的是前端的 html 文件。但是有个问题,静态资源(图片、视频等)vite会处理成URL,比如 import logo from './assets/react.svg'会处理成/src/assets/react.svg,但是node服务下没有该目录,所以我通过正则匹配路由然后重新指向vite服务来解决这个问题。定义特定格式的路由处理中间件:

    const Router = require('@koa/router')
    
    const staticReg = /\/.+\.(svg|png|jpg|png|jpeg|mp4|ogv)$/ // 还可以添加其他格式
    const router = new Router()
    
    router.get(staticReg, (ctx, next) => {
      ctx.redirect(`http://localhost:5173${ctx.path}`)
    })
    
    module.exports = router
    

    在 server 中添加:

    const assets = require('./server/assets-router')
    // assets
    app.use(assets.routes()).use(assets.allowedMethods())
    

    创建 API 接口

    const Router = require('@koa/router')
    const router = new Router()
    
    router.get('/api/v1', (ctx, next) => {
      ctx.body = [
        {
          id: 1,
          name: 'jack',
          age: 11
        },
        {
          id: 2,
          name: 'rose',
          age: 12
        },
        {
          id: 3,
          name: 'mike',
          age: 13
        }
      ]
    })
    
    module.exports = router
    

    server.js 中添加:

    const router = require('./server/api-router.js')
    // api
    app.use(router.routes()).use(router.allowedMethods())
    

    获取接口信息

    App.jsx 中调用接口:

    import { useState, useEffect } from 'react'
    
    function App() {
      const [list, setList] = useState([])
    
      useEffect(() => {
        fetch('/api/v1')
          .then(res => res.json())
          .then(res => setList(res))
      }, [])
    
      return (
        <div className='App'>
          <ul>
            {list.map(({ id, name, age }) => (
              <li key={id}>
                id: {id} -- name: {name} -- age: {age}
              </li>
            ))}
          </ul>
        </div>
      )
    }
    
    export default App
    

    nodemon 和 concurrently

    nodemon 可以实时重启服务,concurrently 可以同时运行多个命令:

    pnpm add concurrently nodemon -D
    

    运行程序

    在 package.json 文件中添加下一个 scripts:

    "dev": "clear & concurrently 'vite' 'nodemon server.js'"
    

    运行程序:

    pnpm dev
    

    浏览器打开 http://localhost:5000。页面展示和接口调用均正常:

    image.png

    至此,基于 vite 的 react + koa 的全栈项目搭建完成。

    问题:为什么要单独处理 img video 等静态资源,而 js 以及 在 js 中引入的 css 不需要处理?

    这是因为静态资源在 js 导入后被 vite 解析成 URL,比如:/src/assets/react.svg,在 html 中加载的时候该路径的根目录是基于端口 5000 的后端服务的,所以单独做了处理,判断如果是静态资源就转发到客户端服务上,而 js 导入的 js、css 是基于 script 的 src 的,所以资源从前端 vite 起的服务中加载:

    <script type='module' src='http://localhost:5173/src/main.jsx'>
      import foo from './foo.js'
    </script>
    

    import foo from './foo.js' 会被 vite 处理成 /src/foo.js,浏览器获取该资源的完整地址是基于 script 的 src 的,即:http://localhost:5173/src/foo.js

    image.png

    ps:为了避免与其他构建工具的端口产生冲突,vite3.0 默认的端口由之前的 3000 改为 5173。

    通过 github 获取完整代码代码

    相关文章

      网友评论

          本文标题:如何基于 Vite 开发 React 和 Koa 全栈程序

          本文链接:https://www.haomeiwen.com/subject/kqydirtx.html