Next.js 14动态导入外部脚本报错:无法找到模块
在Next.js 14中动态加载外部脚本的正确方式
你的问题核心在于import(props.scriptSrc)这种写法不符合ES模块动态导入的静态分析规则——Next.js的打包工具(Webpack/Turbopack)无法提前解析纯变量路径,导致找不到模块。下面给你两种可行的解决方案:
方案一:静态路径限定的动态导入(适合已知脚本列表)
通过模板字符串限定路径前缀,让打包工具能提前识别可能的脚本文件,再结合props传入的文件名动态加载:
组件代码(客户端组件)
'use client'; import { useEffect, useState } from 'react'; export default function DynamicScript({ scriptName }) { const [isLoaded, setIsLoaded] = useState(false); useEffect(() => { const loadScript = async () => { try { // 用模板字符串固定路径前缀,让打包工具能解析到目标脚本 const scriptModule = await import(`./scripts/${scriptName}.js`); // 执行脚本导出的初始化方法(需脚本对应导出) scriptModule.init?.(); setIsLoaded(true); } catch (err) { console.error('脚本加载失败:', err); } }; loadScript(); }, [scriptName]); return isLoaded ? <div>脚本已加载完成</div> : <div>脚本加载中...</div>; }
外部脚本示例(比如./scripts/hue_effect.js)
export function init() { // 这里写你的Hue效果逻辑 console.log('Hue特效脚本初始化完成'); }
方案二:DOM注入script标签(适合完全动态的外部脚本)
如果脚本不需要打包进应用bundle,而是作为静态资源放在public目录下,可以直接创建script标签插入DOM:
组件代码(客户端组件)
'use client'; import { useEffect, useState } from 'react'; export default function DynamicScript({ scriptSrc }) { const [isLoaded, setIsLoaded] = useState(false); useEffect(() => { const script = document.createElement('script'); script.src = scriptSrc; // 传入public下的绝对路径,比如'/scripts/hue_effect.js' script.async = true; script.onload = () => { setIsLoaded(true); // 调用脚本暴露的全局方法 window.hueEffectInit?.(); }; script.onerror = (err) => console.error('脚本加载失败:', err); document.body.appendChild(script); // 组件卸载时清理脚本 return () => document.body.removeChild(script); }, [scriptSrc]); return isLoaded ? <div>脚本已加载完成</div> : <div>脚本加载中...</div>; }
外部脚本示例(放在public/scripts/hue_effect.js)
function hueEffectInit() { // 这里写你的Hue效果逻辑 console.log('Hue特效脚本初始化完成(全局脚本)'); } // 暴露到全局供组件调用 window.hueEffectInit = hueEffectInit;
关键注意事项
- 所有涉及动态加载、DOM操作的组件必须加上
'use client'声明,Next.js 14 App Router默认是服务器组件,无法执行客户端逻辑。 - 方案一中的脚本路径是相对于组件文件的相对路径,不是
public的绝对路径,打包工具会将脚本整合进bundle。 - 方案二中的脚本放在
public目录下,访问路径是相对于域名根目录的绝对路径(比如/scripts/xxx.js),无需导出,通过全局变量调用方法。
内容的提问来源于stack exchange,提问作者Lefan
相关产品推荐
相关产品推荐

