在 Next.js 项目中,你经常会看到两种不同的导入写法:
import { useEffect, useState } from 'react'
import Button from '@/app/components/base/button'
这两种写法其实分别对应了第三方依赖导入和项目内部模块导入,它们的区别如下:
一、from 'react' —— 导入第三方包
import { useEffect, useState } from 'react'
'react'是一个 npm 包名。- Next.js(底层是 Node.js + Webpack/Turbopack)会自动到
node_modules/react里去找。 一般用于导入第三方库,例如:
import axios from 'axios' import dayjs from 'dayjs' import { useRouter } from 'next/navigation'
所以:
from 'xxx'通常指向node_modules里的依赖包。
二、from '@/app/components/base/button' —— 导入项目内部文件
import Button from '@/app/components/base/button'
- 这表示导入的是你自己项目里写的组件文件。
- 其中的
@是一个路径别名(alias),代表项目的根目录。 比如上面这行其实等价于:
import Button from './app/components/base/button'
这样写的好处是:
- 避免写很多
../../相对路径; - 结构清晰、跨目录导入更方便。
三、Next.js 的别名配置位置
Next.js 默认支持 jsconfig.json 或 tsconfig.json 来定义路径别名。
你的项目里已经有如下配置(在根目录的 tsconfig.json 文件中):
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./*"]
}
}
}
这行配置表示:
@= 项目根目录(./)
因此:
import Button from "@/app/components/base/button"
就等价于
import Button from "./app/components/base/button"
四、总结对比表
| 写法 | 含义 | 实际来源 | 是否需要配置 |
|---|---|---|---|
from 'react' |
导入第三方库 | node_modules |
❌ 不需要 |
from './Button' |
当前目录下文件 | 项目文件 | ❌ 不需要 |
from '../Button' |
上级目录文件 | 项目文件 | ❌ 不需要 |
from '@/components/Button' |
使用路径别名导入 | 项目文件 | ✅ 需要配置 paths |
五、可选改进(如果你有 src 目录)
如果你的源代码都在 src 下,可以把别名改成更规范的写法:
"paths": {
"@/*": ["src/*"]
}
这样 @/components/Button 就固定代表 src/components/Button,更清晰。
一句话总结:
from 'react'是从node_modules导包;from '@/xxx'是从你自己的项目目录导文件,@由tsconfig.json定义为别名。
更多场景
Next.js / ES Module 中 import ... from ... 的所有常见写法类型
| 类型 | 示例 | 含义 | 常见场景 |
|---|---|---|---|
| 1. 包名导入(模块导入) | import { useState } from 'react' |
从 node_modules 里加载 npm 包 |
React、axios、dayjs 等 |
| 2. 相对路径导入 | import Button from './Button' 或 import Button from '../components/Button' |
相对于当前文件所在目录 | 项目内部模块 |
| 3. 绝对路径导入 | import Button from 'app/components/Button' |
从项目根开始解析(部分 Next.js 自动支持) | src 模式项目常用 |
| 4. 路径别名导入 | import Button from '@/components/Button' |
使用在 tsconfig.json / jsconfig.json 里配置的 alias |
大型项目结构清晰 |
| 5. URL 导入(少见) | import data from 'https://example.com/data.js' |
直接从网络地址导入(仅浏览器原生 ESM 支持) | 纯原生浏览器 ESM 场景 |
| 6. 特定文件扩展名导入 | import style from './style.module.css' |
导入样式或资源文件 | Next.js 支持 CSS/SCSS 模块 |
| 7. 动态导入 | const Comp = dynamic(() => import('@/components/Comp')) |
运行时按需加载模块(代码分割) | Next.js 常用于懒加载组件 |
| 8. 通配导入(批量) | import * as utils from './utils' |
导入整个模块为一个对象 | 想批量访问多个导出时 |
| 9. 只执行不接收 | import './global.css' |
仅执行该模块,不接收导出内容 | 加载全局样式或副作用模块 |
补充说明
包名导入(最基础)
import React from 'react'
import { useEffect } from 'react'
从 node_modules 加载。最常见。
相对路径导入
import Button from './Button'
import utils from '../utils'
相对于当前文件路径。无需配置。
绝对路径导入(Next.js 特性)
如果你的项目根下有 src/ 目录,Next.js 会自动支持:
import Button from 'components/Button'
无需写 ./ 或配置别名。
如果没有 src/,那需要 baseUrl 或 paths 配置才行。
路径别名导入(推荐)
你项目的 tsconfig.json 已经配置了:
"baseUrl": ".",
"paths": { "@/*": ["./*"] }
所以:
import Button from '@/app/components/base/button'
就是从项目根目录开始找文件。最常见于中大型项目。
动态导入(Next.js 特有)
Next.js 提供 next/dynamic 实现组件懒加载:
import dynamic from 'next/dynamic'
const Chart = dynamic(() => import('@/components/Chart'))
可以延迟加载页面或组件。
样式导入(Next.js 原生支持)
import './globals.css'
import styles from './page.module.css'
可导入全局样式或 CSS Module。
通配导入
import * as math from './math'
console.log(math.add(1, 2))
将整个模块导出作为一个命名空间对象。
最后总结表
| 类别 | 示例 | 说明 |
|---|---|---|
| 第三方包 | from 'react' |
从 node_modules 导入 |
| 相对路径 | from './Button' |
当前目录相对路径 |
| 上级路径 | from '../utils' |
向上一级目录 |
| 项目别名 | from '@/components/Button' |
由 tsconfig.json 定义的别名 |
| 绝对路径 | from 'app/components/Button' |
若配置或 src 模式启用 |
| 动态导入 | import('path') 或 dynamic() |
懒加载 |
| 样式导入 | import './globals.css' |
执行样式或副作用模块 |
