Vite开发复用组件时Next.js Link报push相关TypeError的问题
问题描述
发布用Vite开发的可复用React组件后,复用时报错:
TypeError: Cannot read properties of null (reading 'push')
组件代码:
import React from "react"; import Link from "next/link"; const ShowText = ({title})=>{ return( <Link href="/blog">{title}</Link> ) } export default ShowText
组件仅依赖Next.js的Link组件,以下是相关配置:
package.json
{ "name": "my-component-name", "version": "0.0.5", "description": "", "license": "MIT", "author": "", "keywords": [], "files": [ "dist", "README.md" ], "main": "./dist/my-component.umd.js", "module": "./dist/my-component.es.js", "exports": { ".": { "import": "./dist/my-component.es.js", "require": "./dist/my-component.umd.js" } }, "scripts": { "dev": "vite", "build": "vite build", "test": "vitest run", "watch": "vitest", "coverage": "vitest run --coverage" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "eslintConfig": { "env": { "browser": true, "node": true, "es2020": true }, "extends": [ "eslint:recommended", "plugin:react/recommended" ], "parserOptions": { "sourceType": "module" } }, "devDependencies": { "@testing-library/dom": "^8.16.0", "@testing-library/react": "^13.3.0", "@vitejs/plugin-react": "^2.0.0", "c8": "^7.12.0", "eslint-plugin-react": "^7.30.1", "jsdom": "^20.0.0", "next": "12.1.6", "react": "^18.2.0", "react-dom": "^18.2.0", "react-test-renderer": "^18.2.0", "vite": "^3.0.3", "eslint": "8.17.0", "eslint-config-next": "12.1.6", "vitest": "^0.19.1" } }
vite.config.js
import path from 'path' import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({ build: { lib: { entry: path.resolve(__dirname, 'src/lib/index.jsx'), name: 'my-component-mohammad', fileName: (format) => `my-component.${format}.js` }, rollupOptions: { external: ['react', 'react-dom','next'], output: { globals: { react: 'React' } } } }, plugins: [react()] })
问题分析
核心原因是Next.js的Link组件强依赖Next.js的路由上下文(Router实例),当前配置存在两个关键问题:
next被标记为external,意味着组件不会打包Next.js代码,完全依赖使用组件的项目提供Next.js环境。如果使用组件的项目不是Next.js项目,或者Next.js路由上下文未正确初始化,Link找不到Router实例就会抛出Cannot read 'push' of null错误。package.json中next仅在devDependencies里,发布后不会被安装,且未声明peerDependencies告知使用者需要手动安装Next.js,导致依赖缺失或版本不兼容。
修复方案
根据组件的使用场景,有两种修复方式:
方式一:让组件兼容非Next.js项目
修改组件,允许使用者传入自定义链接组件,不再强依赖Next.js的Link:
import React from "react"; const ShowText = ({ title, LinkComponent = 'a' }) => { return ( <LinkComponent href="/blog">{title}</LinkComponent> ) } export default ShowText
使用时,Next.js项目可以传入next/link:
import ShowText from 'my-component-name'; import Link from 'next/link'; <ShowText title="Blog" LinkComponent={Link} />
非Next.js项目直接使用默认的a标签即可。
方式二:组件仅针对Next.js项目使用
如果组件只打算在Next.js项目中复用,需要调整配置确保依赖正确:
- 在
package.json中添加peerDependencies,声明对Next.js和React的版本要求,让使用者明确需要安装的依赖:
"peerDependencies": { "next": "^12.0.0 || ^13.0.0", "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0" }
- 保留
vite.config.js中的external: ['react', 'react-dom','next']配置,因为peerDependencies的包由使用者项目提供,不需要打包进组件。 - 确保使用者的Next.js项目中
_app.js/_app.tsx保留了默认路由上下文(默认Next.js项目已包含,自定义_app时不要移除相关Provider)。
内容的提问来源于stack exchange,提问作者Mohammad Miras
相关产品推荐
相关产品推荐

