使用Grunt打包优化Bootstrap 5 JavaScript时出现'bootstrap未定义'错误的问题咨询
bootstrap is not defined的问题 你遇到的这个问题核心原因很明确:你直接引入的Bootstrap 5 JS文件是ESM模块格式,它们默认不会在全局作用域暴露bootstrap对象,而官方提供的bundle版本是特意做了全局挂载处理的,所以直接用官方包没问题,自己打包就找不到变量了。
下面给你两种可行的解决办法,推荐第一种更通用的方案:
方案一:用Babel转换模块格式为UMD
ESM模块不会自动注册全局变量,我们可以用Babel把这些模块转换成UMD格式,让它们主动暴露全局的bootstrap对象。
步骤1:安装依赖
先在项目里安装所需的Grunt插件和Babel工具:
npm install grunt-babel @babel/core @babel/plugin-transform-modules-umd --save-dev
步骤2:配置Grunt的Babel任务
在你的Gruntfile.js里添加babel任务,把Bootstrap和Popper的ESM文件转换成UMD格式:
babel: { options: { plugins: ['@babel/plugin-transform-modules-umd'], moduleId: 'bootstrap' // 指定全局模块ID,转换后会自动挂载到window.bootstrap }, dist: { files: [ // 转换Bootstrap的所有dist/js文件 { expand: true, cwd: 'node_modules/bootstrap/js/dist/', src: ['*.js'], dest: '.tmp/bootstrap-umd/' }, // 转换Popper的UMD文件(统一转换更稳妥) { expand: true, cwd: 'node_modules/@popperjs/core/dist/umd/', src: ['popper.js'], dest: '.tmp/popper-umd/' } ] } }
步骤3:修改Uglify任务的文件路径
把原来直接指向node_modules的路径改成转换后的临时目录:
uglify: { site: { options: { sourcemap: false }, files: { 'example/static/example/assets/js/example.min.js': [ // 转换后的Popper '.tmp/popper-umd/popper.js', // 转换后的Bootstrap核心文件 '.tmp/bootstrap-umd/data.js', '.tmp/bootstrap-umd/event-handler.js', '.tmp/bootstrap-umd/manipulator.js', '.tmp/bootstrap-umd/selector-engine.js', // 转换后的组件文件(保持原有顺序) '.tmp/bootstrap-umd/base-component.js', '.tmp/bootstrap-umd/alert.js', '.tmp/bootstrap-umd/button.js', '.tmp/bootstrap-umd/carousel.js', '.tmp/bootstrap-umd/collapse.js', '.tmp/bootstrap-umd/dropdown.js', '.tmp/bootstrap-umd/modal.js', '.tmp/bootstrap-umd/offcanvas.js', '.tmp/bootstrap-umd/scrollspy.js', '.tmp/bootstrap-umd/tab.js', '.tmp/bootstrap-umd/toast.js', '.tmp/bootstrap-umd/tooltip.js', '.tmp/bootstrap-umd/popover.js', // 自定义JS 'example/src/js/**/*.js' ] } }, }
步骤4:调整任务执行顺序
确保Babel转换在Uglify压缩之前执行,注册一个合并任务:
grunt.registerTask('build-js', ['babel', 'uglify']);
之后运行grunt build-js就能得到可以全局访问bootstrap的打包文件了。
方案二:手动添加全局暴露代码
如果你不想引入Babel工具链,可以手动写一段代码把Bootstrap组件挂载到全局。
- 创建一个
expose-bootstrap.js文件,内容如下(把你用到的组件都列出来):
// 手动将Bootstrap组件挂载到window全局 window.bootstrap = { Offcanvas: window.bootstrap.Offcanvas, Alert: window.bootstrap.Alert, Button: window.bootstrap.Button, Carousel: window.bootstrap.Carousel, Collapse: window.bootstrap.Collapse, Dropdown: window.bootstrap.Dropdown, Modal: window.bootstrap.Modal, Scrollspy: window.bootstrap.Scrollspy, Tab: window.bootstrap.Tab, Toast: window.bootstrap.Toast, Tooltip: window.bootstrap.Tooltip, Popover: window.bootstrap.Popover };
- 把这个文件添加到Uglify任务的文件列表最后:
// ... 其他文件路径 'expose-bootstrap.js', 'example/src/js/**/*.js'
这种方法的缺点是需要你手动维护所有用到的组件,不如方案一灵活,但胜在简单。
为什么官方Bundle能正常运行?
官方的bootstrap.bundle.js是Bootstrap团队预先打包好的IIFE格式文件,在打包时特意添加了代码把bootstrap对象挂载到window上,所以你直接引入就能全局访问。而node_modules/bootstrap/js/dist/下的文件是原生ESM模块,遵循模块化规范,不会自动污染全局作用域,这也是你自己打包后找不到bootstrap变量的根本原因。
内容的提问来源于stack exchange,提问作者Itergator

