简简单单的 spa + vercel + serverless function 居然有这么多坑

手上没活不太行,所以我想整个活。

整个小网站吧,要有路由,要有域名,要有接口,要有数据库。还要 不花钱

我看中了 vercel

天下没有免费的午餐,vercel 有,不花钱的 Hobby Plan 足够整活用了,但是不要效仿"Java之父"把自己的站点交给网友压测。

Feature Hobby Pro
Projects 200 Unlimited
Bandwidth 100 GB 1 TB
Edge Functions execution units 500,000 1 million
Edge Middleware invocations 1 million 2 million
Serverless Function maximum duration 10 seconds 15s (default) - configurable up to 300s
Serverless Function execution 100 GB-hours 1,000 GB-hours
Build execution minutes 6,000 24,000
Image Optimization source images 1,000 5,000
Team collaboration features - Yes
Remote Cache artifact downloads 10 GB 20 GB
Domains per project 50 Unlimited
Deployments per day 100 6,000
Analytics - Limited
Email support - Yes

它提供了 templates

各种用途风格框架的项目模板都有

点进去可以预览 demo,也可以一键部署

支持多种 Git Provider

后面就是傻瓜式操作,选个 Provider,选个账号,选个项目名,Create 就完了,你会得到一个代码仓库和 vercel 白给的域名,点进去就可以预览你的网站了。

它支持了 serverless function

vercel 支持用 Node.js, Go, Python, Ruby 写 serverless function,具体请参考文档。

同时还提供了一些模板

它集成了 storage

在这里选个喜欢的,连接到项目就行了,文档在这里 👉🏻 vercel.com/docs/storag...

它连接了 GitHub

在 dashboard 里 create new project,会被引导创建项目,可以轻松地连接到 GitHub 项目并部署

它还整了 持续集成

当你 project settings 中监听的分支有变更时,vercel 会自动构建,这里可以查看构建历史

我遇到了 坑

看了文档和模板示例,我说快整吧,我感觉我现在强得不行。然而,事情并不顺利,最简单的起步,让我踩了仿佛两年半的坑。

线上非默认路由刷新 404 了

我用的 React 的 BrowserRouter,想必开发过 spa 的鸽鸽们都遇到过,本地没问题,到线上刷新非默认路由 404.

这种情况如果没有 nginx 反向代理之类的配置,通常访问默认路由没问题,跳转非默认路由也没问题,但是当在非默认路由页面刷新时就会 404,是因为请求不到资源,spa 中就一个 html,没其他页面,请求不到也正常。

我们要想办法把这个请求定向到 index.html,这就妥了。

Stack Overflow 和 vercel 文档上都有方法,不赘述了,直接贴解决办法

在项目根目录中创建 vercel.json,甚至可以在这个配置文件里设置反向代理。然后部署项目就好了

json 复制代码
{
  "rewrites": [
    {
      "source": "/(.*)",
      "destination": "/index.html"
    }
  ]
}

本地调接口进到路由里了

到这里先说怎么加接口,整个最简单的 Hello World 接口,参考 👉🏻 Quickstartexample 原来加个接口这么简单。

加了接口之后,为什么线上能访问,本地接口一访问就进路由了呢?

原来不能用 pnpm dev 启动服务,需要用 vercel dev,它才会把 serverless function 跑起来,同时还要改造下 vercel.json,用负向前行断言或叫否定前瞻断言 告诉 vercel 把别的路由定向到 /index.html 得了,api 开头的是接口,不要这么处理。

json 复制代码
{
  "rewrites": [
    {
      "source": "/((?!api\/.*).*)",
      "destination": "/index.html"
    }
  ]
}

这么一来在本地也把 api 开头的请求当做接口处理了。

调接口 FUNCTION_INVOCATION_FAILED

但是,为啥一调用接口就报错了呢?

查了一大圈,Stack Overflow、GitHub issues、discussions、vercel 文档都看遍了,配置也是一顿改,没用。然后问了 GPT,它最没用,说你看日志去吧,问题是根本没日志。

然后我想,既然本地和线上环境是有差异的,保不齐线上能行呢?发了下线上,调接口,还不行。但是,不同的是线上有日志,在这个地方

没想到从最没用的回答中找到了最朴素的解决方法。按照日志提示,在 package.json 中设置 type: module 解决问题。

调接口返回内容异常了

此时应该没有什么幺蛾子了,继续调试,发现线上好的,本地访问接口也能访问,但是返回的响应有点不对劲。

仔细一看,没有返回 Hello World,而是把 api/hello.ts 中的 file content 返回出来了,这也没用啊,肯定是配置问题。

配置改来改去,用过 rewrites, redirects, functions 等等都没用。

又找来找去,找到个方法,说在 vercel.json 中用 routes 字段替换 rewrites 字段,虽说文档不建议使用这个字段,但是没办法,试试吧

json 复制代码
{
  "routes": [
    {
      "src": "/((?!api\/.*).*)",
      "dest": "/index.html"
    }
  ]
}

结果改成这样还真行,欢欢喜喜部署到线上。

本地好了,线上不行了

又出问题了,本地行了,线上不行了,访问页面加载不出来了,一看是加载 js 资源文件出问题了,响应头 Content-Type 变成 text/html 了,怪不得不行了,记得文档上有在 vercel.json 中设置 headers 的选项。

针对 dist/assets/**/*.js 资源设置了正确的响应头,线上倒是能访问页面了,但是样式没了,项目中用了 unocss。这怎么行?

我们已经知道用 vercel 运行项目时需要 vercel.json 配置文件,能不能像加载 .env 文件似的在不同环境加载不同的配置?查了下没有这种写法,但是从 vercel help dev 命令中找到了希望。

bash 复制代码
➜ ~ vercel help dev
Vercel CLI 33.4.1

  ▲ vercel dev [dir] [options]

  Starts the `vercel dev` server.                                           

  Options:

   --listen <uri>  Specify a URI endpoint on which to listen [0.0.0.0:3000]  


  Global Options:

       --cwd <DIR>            Sets the current working directory for a      
                              single run of a command                       
  -d,  --debug                Debug mode (default off)                      
  -Q,  --global-config <DIR>  Path to the global `.vercel` directory        
  -h,  --help                 Output usage information                      
  -A,  --local-config <FILE>  Path to the local `vercel.json` file          
       --no-color             No color mode (default off)                   
  -S,  --scope                Set a custom scope                            
  -t,  --token <TOKEN>        Login token                                   
  -v,  --version              Output the version number                     


  Examples:

  - Start the `vercel dev` server on port 8080

    $ vercel dev --listen 8080

  - Make the `vercel dev` server bind to localhost on port 5000

    $ vercel dev --listen 127.0.0.1:5000 

可以看到我们能使用 -A 参数指定配置文件,默认是 vercel.json,那好,我在项目根目录准备了两个文件:

vercel.json

json 复制代码
{
  "rewrites": [
    {
      "source": "/((?!api\/.*).*)",
      "destination": "/index.html"
    }
  ]
}

vercel.local.json

json 复制代码
{
  "routes": [
    {
      "src": "/((?!api\/.*).*)",
      "dest": "/index.html"
    }
  ]
}

在本地启动时用命令 vercel -A vercel.local.json dev,本地没问题了。

部署到线上,测试也没问题。

问题解决了

到现在问题是解决了,我明白,虽然这么整有点丑,但是我还没找到更体面的方法,先这么地吧。

希望能帮大家在整活路上踩坑时间少一点,有经验一起分享。

最后祝各位鸽鸽回家路上平平安安

相关推荐
阿里云云原生8 小时前
阿里云 Serverless 重塑创蓝云智通信底座,引领行业变革!
serverless
阿里云云原生3 天前
GPU 降成本免运维,睿观 AI 助手选择函数计算
云原生·serverless
zzywxc7876 天前
云原生 Serverless 架构下的智能弹性伸缩与成本优化实践
云原生·架构·serverless
moppol7 天前
Serverless 数据库来了?无服务器数据库 vs 传统数据库有何不同?
数据库·云原生·serverless
moppol12 天前
Serverless 架构入门与实战:AWS Lambda、Azure Functions、Cloudflare Workers 对比
云原生·serverless·aws
阿里云云原生22 天前
语音生成+情感复刻,Cosyvoice2.0 极简云端部署
云原生·serverless
Jeaten25 天前
Cross-Edge Orchestration of Serverless Functions With Probabilistic Caching
edge·serverless·cache
阿里云云原生1 个月前
Function AI 工作流发布:以 AI 重塑企业流程自动化
云原生·serverless
Serverless社区1 个月前
亚太唯一!阿里云Serverless计算产品进入Forrester领导者象限
阿里云·云原生·serverless·函数计算