Ruby on rails 使用Rails 6,您将“;页面特定”;JavaScript代码?

Ruby on rails 使用Rails 6,您将“;页面特定”;JavaScript代码?,ruby-on-rails,ruby-on-rails-6,webpacker,Ruby On Rails,Ruby On Rails 6,Webpacker,我这里的问题与Rails 6相同,而不是Rails 3.1 假设我有一些JavaScript,我想用于我的帖子索引页面。我应该将该文件放在哪里,如何将其包括在内 在前面的问题中,答案通常使用Rails资产管道。然而,对于Rails6,我的理解是它使用webpacker而不是JavaScript文件的资产管道 注意:我不希望总是包含该文件。如果我在作者索引页面上,我不希望包含帖子索引页面的JavaScript文件。为什么?假设我有$('li')。在('click',changeColor')在JS

我这里的问题与Rails 6相同,而不是Rails 3.1

假设我有一些JavaScript,我想用于我的帖子索引页面。我应该将该文件放在哪里,如何将其包括在内

在前面的问题中,答案通常使用Rails资产管道。然而,对于Rails6,我的理解是它使用webpacker而不是JavaScript文件的资产管道


注意:我不希望总是包含该文件。如果我在作者索引页面上,我不希望包含帖子索引页面的JavaScript文件。为什么?假设我有
$('li')。在('click',changeColor')在JS文件中,用于posts索引页面。我可能不希望在authors索引页上运行该代码,但如果包含该文件,它会运行。您可以通过名称空间来解决这个问题,但我认为不包含不必要的文件会更干净(而且性能更高)。

让我们在一个空的Rails 6应用程序中浏览一下这个目录的内容

▶ tree app/javascript
app/javascript
├── channels
│   ├── consumer.js
│   └── index.js
└── packs
    └── application.js

2 directories, 3 files
packs目录对我们很重要,让我们看看它包含什么

//app/javascript/application.js
需要(“@rails/ujs”).start()
需要(“TurboLink”).start()
需要(“@rails/activestorage”).start()
要求(“渠道”)
webpack有一个入口点的概念,即它开始编译JavaScript代码时首先查找的文件

Webpacker gem以app/javascript/packs下的application.js文件的形式创建应用程序包。如果您还记得资产管道,那么这个文件相当于app/assets/javascripts/application.js文件

简单例子 如何将Javascript添加到RubyonRails(将Javascript添加为模块):

  • 在Javascript路径
    app/Javascript
    ex:'post'中创建文件夹

  • 将javascript文件添加到index.js这样的文件夹中

  • app/javascript/application.js
    ->
    require('post')

    需要(“@rails/ujs”).start() 需要(“TurboLink”).start() 需要(“@rails/activestorage”).start() 要求(“渠道”) 要求(“职位”)

  • 在添加post模块之后,让我们在Rails6应用程序中浏览一下该目录的内容
    这是一种使用网页包的简单方法,与以前的rails风格相同。

    我将尝试用咖啡脚本回答您的问题 因为它更容易理解, 关键是使用事件“turbolinks:load”检查内容 如果rails使用新方法加载post页面,则默认情况下该页面将具有class.posts.new

    在你的app.post.coffee中

    class App.Post
      render: ->
        console.log "Post Edit / new render"
        console.log "all this script below will only run"
        console.log "if you open Post with new or edit method"
    
    $(document).on "turbolinks:load", ->
      if $(".posts.new")[0] || $(".posts.edit")[0]  
        post = new App.Post
        post.render()
    
    在你的app.author.coffee中

    class App.Author
      render: ->
        console.log "Author Edit / newrender"
        console.log "all this script below will only run"
        console.log "if you open Author with new or edit method"
    
    $(document).on "turbolinks:load", ->
      if $(".authors.new")[0] || $(".authors.edit")[0]  
        author = new App.Author
        author.render()
    
    这里是post.js,如果我将我的咖啡脚本转换为js

    App.Post = class Post {
      render() {
        console.log("Post Edit / new render");
        console.log("all this script below will only run");
        return console.log("if you open Post with new or edit method");
      }
    
    };
    
    $(document).on("turbolinks:load", function() {
      var post;
      if ($(".posts.new")[0] || $(".posts.edit")[0]) {
        post = new App.Post;
        return post.render();
      }
    });
    

    我将描述一些选项,以增加与Webpack和Webpack相关的体验的难度

  • 忘记特定于页面的JavaScript,将所有内容都放在
    application.js
    包中。这无疑是最容易理解的方法。对于一个小型应用程序来说,这种折衷可能是值得的,因为拥有一个更易于维护的应用程序可能会超过学习如何最好地将JS代码与Webpack分离的额外成本,而性能增益很小

  • 用于延迟加载页面特定的代码。在这个场景中,您仍然会将所有JavaScript放在
    application.js
    依赖关系图中,但并非所有代码都会预先加载。Webpack在编译您的JS时识别动态
    import()
    函数,并将导入的区块分割成单独的文件,可使用JS框架路由器或简单触发器在浏览器中按需加载

    例如,您可能有如下代码:

    requireOnce('wysiwyg.js', function(){
      $('textarea').wysiwyg()
    });
    
    if(document.queryselectoral(“.post index”).length){
    导入(“./post/index”)//网页包将加载此JS异步
    }
    
  • 结合使用页面特定的“包”。在这种情况下,您不需要使用
    application.js
    包,而是为每个需要区别对待的页面构建一个包,例如,
    posts.js
    admin.js
    等。使用splitChunks插件意味着您的包可以正确地共享代码。我强烈建议您谨慎使用这种方法,直到您了解Webpack是如何工作的,或者在选择这条道路时愿意经历学习Webpack的过程。Webpack通常在假设每页只使用一个入口点的情况下工作得最好,否则,除非您知道自己在做什么,否则可能会在捆绑包中重复代码

  • 以下是我如何使用TurboLink提供特定于页面的代码:

    # javascript/packs/application.js
    import {posts_show              } from '../per_page/posts_show';
    import {users_new               } from '../per_page/users_new';
    const pages = {posts_show, users_new};
    document.addEventListener("turbolinks:load", () => {
        # I am using gon to save the page name, but you can add page name to document body and then const page = document.body.className
        const page = gon.controller_full
        # check if method exist if true execute
        if ('function' === typeof pages[page]){
          new pages[page]
        }
    });
    
    正如您所注意到的,我正在一个文件中编译所有的js,并根据需要执行它们

    以下是一个后期展示的示例:

    # javascript/per_page/posts_show.js
    import {default as share_menu_init} from './methods/share_menu_init.js'
    export class posts_show {
        constructor() {
            share_menu_init()
            ... # some other code here
        }
    }
    
    您可以看到我正在导入
    share\u menu\u init
    模块。如果我需要在页面之间共享一些方法,我会将它们存储在模块中,Webpack足够智能,不会创建重复的方法(如果我在posts\u show和其他页面中导入两次),它只会组织文件,以便我的
    posts\u show
    可以访问此方法

    const share_menu_init = () => {
        ... # some code here
    }
    export default share_menu_init
    

    不确定这是否是提供页面特定代码的最佳方式,如果您有更好的方式,我想听听。

    您可以使用
    $。getScript

    (函数(){
    var requiredScripts=[];
    window.requirence=函数(路径,cb){
    if($.inArray(路径,requiredScripts)==-1){
    requiredScripts.push(路径)
    $.getScript(路径,cb)
    }否则{
    cb()
    }
    }
    })();
    
    像这样使用它:

    requireOnce('wysiwyg.js', function(){
      $('textarea').wysiwyg()
    });
    

    我忘了在问题中提到这一点(我会更新问题以包含它),但通过这种方法,
    app/javascript/post/index.js
    似乎会一直包含在内,而我只希望在您位于特定页面时包含它。例如,我不希望在您访问a时将其包括在内