Shim Twitter Bootstrap for RequireJS

Posted

技术标签:

【中文标题】Shim Twitter Bootstrap for RequireJS【英文标题】: 【发布时间】:2012-11-02 20:43:30 【问题描述】:

RequireJS docs说要支持老版本的IE,需要配置enforceDefine: true

因此,如果您想支持 Internet Explorer、捕获加载错误并通过直接 define() 调用或 shim 配置来编写模块化代码,请始终将 enforceDefine 设置为 true。有关示例,请参见下一节。

注意:如果你确实设置了 enforceDefine: true,并且你使用 data-main="" 来加载你的主 JS 模块,那么那个主 JS 模块必须调用 define() 而不是 require() 来加载它需要的代码.主 JS 模块仍然可以调用 require/requirejs 来设置配置值,但是对于加载模块,它应该使用 define()。

由于 Twitter Bootstrap 不是 AMD 模块,我需要对其进行填充以使其工作。 我就是这样配置的;

<script type="text/javascript">
    var require = 
        paths: 
            "bootstrap": "../bootstrap",
            "jquery": "../jquery-1.8.2"
        ,
        shim: 
            "bootstrap": ["jquery"]
        ,
        enforceDefine: true
    ;
</script>

后来当我的模块想要将引导程序作为依赖项时,我仍然会收到一条错误消息;

Error: No define call for bootstrap

http://requirejs.org/docs/errors.html#nodefine

如果我对文档的理解正确,enforceDefine应该忽略垫片,但事实并非如此。

我在这里做错了什么?

【问题讨论】:

【参考方案1】:

根据文档,如果“脚本是 shim 配置的一部分,该配置指定了可以检查加载的全局字符串属性,并且该检查失败,则会引发错误。”

要解决此问题,您需要在 shim 配置中添加导出值,以便 RequireJS 可以检查脚本是否已成功加载。如果 Bootstrap 有点棘手,因为 Bootstrap 不会“导出”属性全局变量,只有一堆 jquery 插件,但您可以使用这些插件中的任何一个作为导出值,例如$.fn.popover:


    paths: 
        "bootstrap": "../bootstrap",
        "jquery": "../jquery-1.8.2"
    ,
    shim: 
        "bootstrap": 
          deps: ["jquery"],
          exports: "$.fn.popover"
        
    ,
    enforceDefine: true

【讨论】:

对于我们这些不熟悉 JS 的人,您将如何在自己的代码中使用弹出框?使用 require 我可以说 "var $ = require('jquery') 我会写 "var popover = require("$.fn.popover") 吗? 没有。 require 将文件系统中的模块路径作为参数。在这种情况下,您只能执行 require("bootstrap"),然后使用 $("#example").popover()。如果您使用未连接的版本,则可能需要单独的引导插件,但这需要更多设置。一般来说,附加到 $.fn 的 jQuery 插件与 CJS/AMD 模块理念不太兼容。 如果您需要访问多个插件怎么办?有没有办法使用requirejs进行多次导出?还是每个插件都有多个垫片?还是别的什么? Bootstrap 扩展了 jQuery(和 $),因此在“导出”中您可以简单地使用“$”(我一直在使用它)另外我认为“导出”值可能是一个函数您可以在其中将所有引导插件分组到一个新的命名空间中。我还没试过。【参考方案2】:

我没有用 shim 做魔法,而是将引导 JS 转换为一个模块:

define([ "jquery" ], function($) 
  // bootstrap JS code
);

我在论坛和 *** 上找到的所有其他内容都对我不起作用,因为我从 CDN 获得了 jQuery。我假设是因为我遇到了http://requirejs.org/docs/api.html上的requireJS文档中描述的问题

不要在构建中混合使用 CDN 加载和 shim 配置。示例场景: 你从 CDN 加载 jQuery,但使用 shim 配置加载一些东西 就像依赖 jQuery 的 Backbone 的股票版本一样。当你这样做 构建,确保在构建文件中内联 jQuery 并且不要加载 它来自 CDN。否则,Backbone 将内联在构建的文件中 它将在加载 CDN 的 jQuery 加载之前执行。这是 因为 shim 配置只是延迟加载文件,直到 依赖项已加载,但不会对定义进行任何自动包装。 构建后,依赖项已经内联,垫片配置 不能延迟执行未定义()的代码,直到以后。 构建后定义()的模块确实可以与 CDN 加载的代码一起工作,因为 他们正确地将源代码包装在定义工厂函数中 在加载依赖项之前不执行。所以教训:垫片配置 是针对非模块化代码、遗留代码的权宜之计。 define() 的模块更好。

将引导程序转换为普通的 AMD 模块并删除 shim 配置为我解决了这个问题。唯一的缺点:您无法从引导 CDN 中检索引导。

【讨论】:

那么最好不要使用 CDN 引导程序,因为它不允许您运行闭包编译器来消除未使用的函数等。 注意,当前版本的 Bootstrap 3 引用 jQuery 而不是 $,所以现在你实际上必须传入:define('bootstrap', ['jquery'], function(jQuery) 【参考方案3】:

我在我的项目中使用这个配置:

startup.js

require.config(
    paths: 
        /* other paths are omitted */
        'bootstrap': '../libs/bootstrap'
    ,
    shim: 
        'bootstrap/bootstrap-slider':  deps: ['jquery'], exports: '$.fn.slider' , 
        'bootstrap/bootstrap-affix':  deps: ['jquery'], exports: '$.fn.affix' ,
        'bootstrap/bootstrap-alert':  deps: ['jquery'], exports: '$.fn.alert' ,
        'bootstrap/bootstrap-button':  deps: ['jquery'], exports: '$.fn.button' ,
        'bootstrap/bootstrap-carousel':  deps: ['jquery'], exports: '$.fn.carousel' ,
        'bootstrap/bootstrap-collapse':  deps: ['jquery'], exports: '$.fn.collapse' ,
        'bootstrap/bootstrap-dropdown':  deps: ['jquery'], exports: '$.fn.dropdown' ,
        'bootstrap/bootstrap-modal':  deps: ['jquery'], exports: '$.fn.modal' ,
        'bootstrap/bootstrap-popover':  deps: ['jquery'], exports: '$.fn.popover' ,
        'bootstrap/bootstrap-scrollspy':  deps: ['jquery'], exports: '$.fn.scrollspy'        ,
        'bootstrap/bootstrap-tab':  deps: ['jquery'], exports: '$.fn.tab' ,
        'bootstrap/bootstrap-tooltip':  deps: ['jquery'], exports: '$.fn.tooltip' ,
        'bootstrap/bootstrap-transition':  deps: ['jquery'], exports: '$.support.transition' ,
        'bootstrap/bootstrap-typeahead':  deps: ['jquery'], exports: '$.fn.typeahead'  ,
    
);

require(['domReady', 'app'], function(domReady, app) 
    domReady(function() 
        app.init();
    );
);

然后在我的代码中我使用这个:

define(['jquery', 'underscore', 'backbone', 'text!templates/photos-list.html'], function($, _, Backbone, html) 
    var PhotosListView = Backbone.View.extend(
        viewImageFullscreen: function(e) 
            e.preventDefault();

            require(['bootstrap/bootstrap-modal', 'text!templates/photo-modal.html'], function(modal, htmlModal) 
                 var modalTemplate = _.template(htmlModal, options);
                 $('body').append(modalTemplate);

                 // setup
                 $(selector + '_modal').modal(
                     backdrop: true,
                     keyboard: true,
                     show: false
                 ).css(
                     'width': function()  return ($(document).width() * 0.55) + 'px'; ,
                     'margin-left': function()  return -($(this).width() * 0.5); 
                 );

                 // trigger `modal` 
                 $(selector + '_modal').modal('show');
             ); // require() call
         // ...

【讨论】:

我喜欢这种方法,这里是 bootstrap 3 的更新垫片 - gist.github.com/benfoxall/8844292 @benjaminbenben 最近我发现了这个很酷的资源:@​​987654322@ 还有这个:matznermatzner.de/en/bernd/2013/12/… 虽然它们是关于 Zurb Foundation / JQuery UI 他们真的值得一读! 这些太棒了,谢谢分享。使用这些库的更好方法;您将能够从一开始就创建优化的构建 - 而不是追溯优化。 JQuery itself 现在使用 AMD - 能够融入其中真是太棒了。【参考方案4】:

@lexeme 和@benjaminbenben 如何将此概念包装在 RequireJS 插件中,该插件创建 shim,需要 jQuery 并返回 jQuery,这样您就不需要手动包含它?

要使用引导组件,您只需使用:

define(['bootstrap!tooltip'], function($)
  $('[data-toggle="tooltip"]').tooltip();
);

您将使用此require-bootstrap-plugin 使其工作。

【讨论】:

这很漂亮。但是,请谨慎使用,因为如果插件具有依赖项,这将不起作用。例如,popover 需要 tooltip。

以上是关于Shim Twitter Bootstrap for RequireJS的主要内容,如果未能解决你的问题,请参考以下文章

如何创建可打印的 Twitter-Bootstrap 页面

视频分享Twitter前端CSS框架Bootstrap视频教程

Twitter bootstrap 浮动 div 右

为 Twitter 的 Bootstrap 3.x 按钮设计样式

html HTML,CSS,Bootstrap:使用Twitter Bootstrap进行5列布局

如何让 twitter-bootstrap 导航栏子项在小屏幕上折叠/展开?