Visual Studio TypeScript项目中jQuery模块解析失败及$函数未定义问题求助
问题场景描述
我在Visual Studio里维护一个项目,wwwroot下TS文件的结构如下:
wwwroot └── assets └── js └── test.ts
我的test.ts初始代码是这样的:
import * as $ from 'jquery'; import * as bootstrap from 'bootstrap'; $(document).ready(function () { console.log('jQuery is ready!'); });
对应的tsconfig.json配置内容:
{ "compilerOptions": { "noEmitOnError": true, "noImplicitAny": false, "removeComments": false, "sourceMap": true, "target": "es6", "moduleResolution": "node", "module": "ES6", //"strict": true, "types": [ "bootstrap", "jquery" ], "typeRoots": [ "./node_modules/@types", // Default path to search typings. "./lib/types" // Directory of typings that located by Libman. ] }, "include": [ "../wwwroot/assets/js/*.ts" ], "exclude": [ "node_modules" ] }
项目构建成功后生成了test.js,我在test.html的</body>标签前引入了该文件:
<!-- Vendor JS Files --> <script src="~/assets/vendor/apexcharts/apexcharts.min.js"></script> <script src="~/assets/vendor/bootstrap/js/bootstrap.bundle.min.js"></script> <script src="~/assets/vendor/quill/quill.min.js"></script> <!-- Template Main JS File --> <script src="~/assets/js/main.js"></script> <script type="module" src="~/assets/js/test.js"></script>
运行项目后控制台出现第一个错误:
Failed to resolve module specifier "jquery". Relative references must start with either "/", "./", or "../".
更新尝试后的新问题
我改成用绝对路径导入jQuery:
import * as $ from '../../lib/jquery/dist/jquery.js'; import * as bootstrap from 'bootstrap'; $(document).ready(function () { console.log('jQuery is ready!'); });
现在模块解析的错误消失了,但又出现新的报错:
Uncaught TypeError: $ is not a function
at test.ts:5:1
有没有大佬能帮忙解决这个问题呀?
解决方案思路
这里的问题核心是ES模块环境下jQuery的导出逻辑和全局变量绑定的问题,给你几个可行的解决办法:
方法1:调整jQuery导入方式并绑定全局变量
jQuery的ES模块默认导出的是函数实例,但用import * as $会把整个模块对象赋值给$,导致$不是可调用的函数。改成默认导入,同时把$绑定到全局window对象(避免局部作用域或Bootstrap依赖全局$的问题):
import $ from '../../lib/jquery/dist/jquery.js'; import * as bootstrap from 'bootstrap'; // 绑定到全局,确保Bootstrap等依赖能识别到$ window.$ = $; window.jQuery = $; $(document).ready(function () { console.log('jQuery is ready!'); });
方法2:改用全局引入jQuery的方式
如果你的项目里有jQuery的UMD版本(比如jquery.min.js),可以直接在HTML里先导入它,TS代码里就不用再import,直接用全局的$即可:
- 在HTML里把jQuery的引入放在
test.js之前:
<script src="~/lib/jquery/dist/jquery.min.js"></script> <script type="module" src="~/assets/js/test.js"></script>
- 修改
test.ts去掉jQuery的import语句:
import * as bootstrap from 'bootstrap'; $(document).ready(function () { console.log('jQuery is ready!'); });
这种方式下,TS会通过你tsconfig.json里配置的@types/jquery识别$的类型,不会出现类型报错。
方法3:调整tsconfig的模块配置
如果坚持用ES模块导入,可以把tsconfig.json里的module改成CommonJS,同时用require方式导入:
"module": "CommonJS"
然后修改test.ts的导入语句:
const $ = require('jquery'); import * as bootstrap from 'bootstrap'; $(document).ready(function () { console.log('jQuery is ready!'); });
不过这种方式需要确保项目能处理CommonJS模块,可能需要配合Webpack等打包工具。
关键原因说明
- 第一个错误是因为浏览器原生ES模块不支持“裸模块名”(比如直接写
jquery),必须使用相对路径或绝对路径来指定模块位置,你改成路径导入的思路是对的。 - 第二个错误是因为jQuery的ES模块导出逻辑:它的默认导出是可调用的jQuery函数,而
import * as $会把整个模块对象(包含default等属性)赋值给$,导致$不是可调用的函数,改用默认导入import $ from '...'就能拿到正确的函数引用。
备注:内容来源于stack exchange,提问作者VAAA

