npm安装本地依赖运行时返回TypeError报错问题咨询
使用npm官方仓库提供的默认datetimepicker模块构建项目时,所有功能可正常运行。使用本地存储的GitHub克隆版本构建时,页面加载后抛出如下错误,即便本地包代码和npm发布的对应版本完全一致,问题仍存在:
Uncaught TypeError: eo.datetimepicker is not a function
已知业务代码和datetimepicker组件都依赖jquery。
- 正常运行的构建命令:
npm install npm run build
- 触发报错的安装构建流程:
npm install --save ../../datetimepicker npm run build
已确认node_modules目录中jquery-datetimepicker模块为软链接,正确指向本地克隆仓库所在的../../datetimepicker文件夹。
对应业务代码如下:
"use strict"; import 'bootstrap'; import 'bootstrap-toggle'; import '<package name>' import 'bootstrap/dist/css/bootstrap.min.css'; import 'bootstrap-toggle/css/bootstrap-toggle.min.css' import 'jquery-datetimepicker/jquery.datetimepicker.css'
出问题时使用的webpack配置:
module.exports = { output: { path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] } ] }, plugins: [ new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery" }) ] };
npm通过软链接方式安装本地依赖时,不会对本地包的依赖做扁平化提升,会在本地datetimepicker包的目录下单独安装一份它依赖的jquery。最终webpack打包时会引入两份独立的jquery实例:一份是业务代码、其他UI组件引用的根目录node_modules下的jquery,另一份是datetimepicker包自身目录下node_modules里的jquery。
datetimepicker会把自身方法挂载到它依赖的那份jquery原型上,业务代码调用时使用的是另一份没有挂载方法的jquery实例,自然找不到datetimepicker方法,抛出类型错误。
而从npm官方源安装依赖时,所有包依赖的jquery会被扁平化提升到根目录node_modules,全项目共用同一份jquery实例,因此不会出现该问题。
优先选择配置webpack强制全局使用同一份jquery的方案,稳定性最高,不需要额外维护操作:
在webpack配置中新增resolve.alias规则,将所有对jquery的引用都指向项目根目录下的jquery包,修改后的配置如下:
const path = require('path'); const webpack = require('webpack'); module.exports = { output: { path: path.resolve(__dirname, 'dist') }, // 新增resolve配置强制统一jquery实例 resolve: { alias: { 'jquery': path.resolve(__dirname, 'node_modules/jquery') } }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] } ] }, plugins: [ new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery" }) ] };
其他可选方案(维护成本更高,不推荐优先使用):
- 安装本地包时增加
--install-links=true参数,让npm把本地包文件复制到node_modules而非创建软链接,依赖会正常走扁平化逻辑,但每次本地包代码更新都需要重新执行安装命令。 - 进入本地克隆的datetimepicker目录,执行
npm link 项目根目录的绝对路径/node_modules/jquery,将本地包的jquery依赖软链接到项目的jquery实例,但切换开发环境、重装依赖后需要重新执行link操作。
内容的提问来源于stack exchange,提问作者ventsyv

