React应用加载外部脚本遇Unexpected token '<'错误的排查与解决
React项目加载外部脚本遇「Unexpected token '<'」问题排查与解决
问题概述
在React项目中自定义了ScriptLoader组件用于加载外部脚本文件,加载时浏览器控制台抛出「Unexpected token '<'」错误,网络面板显示脚本请求返回的是HTML内容而非预期的JavaScript文件。
期望结果
外部JavaScript文件能无错误加载,可在React组件中正常调用。
相关代码
App组件代码
import React from 'react'; import Layout from './components/Layout'; import Index from './pages/Index'; import ScriptLoader from './components/ScriptLoader'; const scripts = [ "./rooteFile/assets/js/jquery.min.js", "./rooteFile/assets/js/bootstrap.min.js", "./rooteFile/assets/js/waves.js", "./rooteFile/assets/js/wow.min.js", "./rooteFile/assets/js/jquery.nicescroll.js", "./rooteFile/assets/js/jquery.scrollTo.min.js", "./rooteFile/assets/chat/moment-2.2.1.js", "./rooteFile/assets/jquery-sparkline/jquery.sparkline.min.js", ]; function App() { return ( <> <Layout> <ScriptLoader scripts={scripts} /> <Index /> </Layout> </> ); } export default App;
ScriptLoader组件代码
import React, { useEffect } from 'react'; function loadScript(src) { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = src; script.async = true; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); } const ScriptLoader = ({ scripts }) => { useEffect(() => { scripts.reduce((prev, src) => { return prev.then(() => loadScript(src)); }, Promise.resolve()); }, [scripts]); return null; }; export default ScriptLoader;
已尝试操作
- 验证脚本路径的拼写正确性
- 确认同路径下的CSS文件可正常加载
- 检查网络请求,发现JS文件请求返回HTML内容
问题成因
这个错误的核心原因是脚本文件的请求路径不正确,导致服务器无法找到对应的JS文件,返回了404错误页面(HTML格式)。浏览器尝试把HTML内容当作JavaScript解析,自然会遇到开头的<符号,抛出「Unexpected token '<'」错误。
在React项目(尤其是Create React App创建的项目)中,静态资源需要放在public目录下才能被正确访问,你的rooteFile文件夹大概率不在public目录内,所以服务器无法定位到脚本文件,返回了默认的HTML错误页。
解决方案
1. 调整静态资源位置
将rooteFile文件夹移动到项目的public目录下,确保静态资源处于React规定的可访问路径中。
2. 修改脚本路径
调整scripts数组中的路径,去掉开头的./,直接以根路径开头(因为public目录是项目的静态资源根目录):
const scripts = [ "/rooteFile/assets/js/jquery.min.js", "/rooteFile/assets/js/bootstrap.min.js", // 其他脚本路径同理修改 ];
3. 优化ScriptLoader组件(可选)
为了避免重复加载相同脚本,可以在loadScript函数中增加判断逻辑,检查脚本是否已存在:
function loadScript(src) { // 先检查是否已加载过该脚本 if (document.querySelector(`script[src="${src}"]`)) { return Promise.resolve(); } return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = src; script.async = true; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); }
4. 优先使用npm包(推荐)
如果这些脚本对应的库有npm包(比如jquery、bootstrap、moment等),更推荐通过npm安装后直接import使用,这样能避免路径问题,还能享受打包优化:
npm install jquery bootstrap moment
然后在组件中导入:
import $ from 'jquery'; import 'bootstrap'; import moment from 'moment';
内容的提问来源于stack exchange,提问作者Naved
相关产品推荐
相关产品推荐

