You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的误报。
  • 修复步骤:
    1. 删除第17行的export default async function Page()重复定义
    2. 将return语句移到第一个Page函数的内部(即第14行之后)
    3. 补充缺失变量:totalPages需通过数据查询获取(比如调用接口计算总页数),当前代码未定义该变量,会导致渲染错误
    4. 补全组件导入:InvoicesTableSkeleton未在当前代码中导入,需添加对应的import语句
  • 验证方式:修复后通过GitHub UI提交代码,重新触发Vercel部署,检查语法错误是否消除

内容的提问来源于stack exchange,提问作者Ayanda Gatsha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 09:10:20