Next.js财务仪表板教程第11章:搜索分页部署报错求助
Next.js仪表板教程第11章部署报错排查:
'import', and 'export' cannot be used outside of module code 问题背景
正在学习Next.js财务仪表板教程第11章(添加搜索和分页功能),部署到Vercel时失败,GitHub报错:
x 'import', and 'export' cannot be used outside of module code
-[/vercel/path0/app/dashboard/invoices/page.tsx:17:1]
此前步骤执行正常,控制台日志数据符合预期;当前只能通过GitHub UI编写代码,使用已部署应用的PostgreSQL而非本地数据库。已浏览论坛,但相关讨论针对其他项目,解决方法不适用当前分页与搜索场景。
报错文件代码
/app/dashboard/invoices/page.tsx
import Pagination from '@/app/ui/invoices/pagination'; import Search from '@/app/ui/search'; import Table from '@/app/ui/invoices/table'; import { CreateInvoice } from '@/app/ui/invoices/buttons'; import { lusitana } from '@/app/ui/fonts'; import { fetchLatestInvoices} from '@/app/lib/data'; import { Suspense } from 'react'; export default async function Page({ searchParams, }: { searchParams?: { query?: string; page?: string; }; }) { const query = searchParams?.query || ''; const currentPage = Number(searchParams?.page) || 1; export default async function Page() { return ( <div className="w-full"> <div className="flex w-full items-center justify-between"> <h1 className={`${lusitana.className} text-2xl`}>Invoices</h1> </div> <div className="mt-4 flex items-center justify-between gap-2 md:mt-8"> <Search placeholder="Search invoices..." /> <CreateInvoice /> </div> { <Suspense key={query + currentPage} fallback={<InvoicesTableSkeleton />}> <Table query={query} currentPage={currentPage} /> </Suspense> } <div className="mt-5 flex w-full justify-center"> { <Pagination totalPages={totalPages} /> } </div> </div> ); }
/app/ui/search.tsx
'use client'; import { MagnifyingGlassIcon } from '@heroicons/react/24/outline'; import { useSearchParams, usePathname, useRouter } from 'next/navigation'; export default function Search({ placeholder }: { placeholder: string }) { const searchParams = useSearchParams(); const pathname = usePathname(); const { replace } = useRouter(); function handleSearch(term: string) { const params = new URLSearchParams(searchParams); if (term) { params.set('query', term); } else { params.delete('query'); } replace(`${pathname}?${params.toString()}`); console.log(term); } return ( <div className="relative flex flex-1 flex-shrink-0"> <label htmlFor="search" className="sr-only"> Search </label> <input className="peer block w-full rounded-md border border-gray-200 py-[9px] pl-10 text-sm outline-2 placeholder:text-gray-500" placeholder={placeholder} onChange={(e) => { handleSearch(e.target.value); }} defaultValue={searchParams.get('query')?.toString()} /> <MagnifyingGlassIcon className="absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500 peer-focus:text-gray-900" /> </div> ); }
排查与修复指导
- 核心错误原因:
page.tsx中存在重复定义的export default函数——第8行定义了带searchParams参数的Page函数,第17行又重新定义了无参数的Page函数,导致语法解析失败,触发了模块代码外使用import/export的误报。 - 修复步骤:
- 删除第17行的
export default async function Page()重复定义 - 将return语句移到第一个
Page函数的内部(即第14行之后) - 补充缺失变量:
totalPages需通过数据查询获取(比如调用接口计算总页数),当前代码未定义该变量,会导致渲染错误 - 补全组件导入:
InvoicesTableSkeleton未在当前代码中导入,需添加对应的import语句
- 删除第17行的
- 验证方式:修复后通过GitHub UI提交代码,重新触发Vercel部署,检查语法错误是否消除
内容的提问来源于stack exchange,提问作者Ayanda Gatsha
相关产品推荐
相关产品推荐

