我的问题与Using Rails 3.1, where do you put your "page specific" JavaScript code?相同,仅适用于Rails 6而不是Rails 3.1。
假设我有一些要用于帖子索引页面的JavaScript。该文件放在哪里,如何包含它?
在上一个问题中,答案通常使用Rails资产管道。但是,对于Rails 6,我的理解是,它使用webpacker代替了JavaScript文件的Asset Pipeline。
注意:我不希望文件始终包含在 中。例如。如果我在作者索引页面上,则不希望包含帖子索引页面的JavaScript文件。为什么?假设我的帖子索引页面的JS文件中有$('li').on('click', changeColor);
。我可能不希望该代码在作者索引页面上运行,但是如果包含该文件,它将可以运行。您可以通过命名空间来解决此问题,但我认为不包含不必要的文件会更干净(并且性能更高)。
答案 0 :(得分:2)
让我们在一个空的Rails 6应用程序中浏览此目录的内容。
▶ tree app/javascript
app/javascript
├── channels
│ ├── consumer.js
│ └── index.js
└── packs
└── application.js
2 directories, 3 files
packs目录对我们很重要,所以让我们看看它包含的内容。
// app/javascript/application.js
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
webpack具有入口点的概念,入口点是开始编译JavaScript代码时首先查找的文件。
Webpacker gem以app / javascript / packs下的application.js文件的形式创建应用程序包。如果您还记得资产管道,那么此文件等效于app / assets / javascripts / application.js文件
app/javascript
中创建文件夹,例如:“ post” post
-> app/javascript/application.js
require('post')
模块
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("post")
▶ tree app/javascript
app/javascript
├── channels
│ ├── consumer.js
│ └── index.js
└── packs
| └── application.js
|ـــ post
|__ index.js
这种使用webpack的简单方法与以前的rails风格相同。
答案 1 :(得分:0)
我会尝试用咖啡脚本回答您的问题 因为它更容易理解 关键是使用事件“ turbolinks:load”检查内容 如果rails使用新方法加载帖子页面,则默认情况下该页面基本上将具有.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()
如果我将咖啡脚本转换为js,则为post.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();
}
});
答案 2 :(得分:0)
我将按照提高使用Webpack和Webpacker的难度的难度来描述一些选项。
忘记页面特定的JavaScript,并将所有内容放入application.js
捆绑包中。这绝对是最容易理解的方法。对于小型应用程序,折衷可能是值得的,因为拥有易于维护的应用程序可能会超过学习如何最好地利用Webpack最好地拆分JS代码而不增加性能的代价。
使用dynamic imports延迟加载特定于页面的代码。在这种情况下,您仍将所有JavaScript放在application.js
依赖关系图中,但并非所有这些代码都将被预先加载。 Webpack会在编译JS时识别动态import()
函数,并将导入的块拆分成一个单独的文件,该文件可以使用JS框架路由器或简单触发器按需在浏览器中加载。
例如,您可能具有如下代码:
if (document.querySelectorAll(".post-index").length) {
import("./post/index") // webpack will load this JS async
}
splitChunks
configuration API。在这种情况下,您无需为每个页面都构造一个页面,而不必使用application.js
包,例如posts.js
,admin.js
等。使用splitChunks插件意味着您的捆绑包可以正确共享代码。我强烈建议您谨慎使用此方法,直到您了解Webpack的工作方式或愿意学习选择此路径的Webpack的过程。 Webpack通常在假设您每个页面仅使用一个入口点的情况下效果最好,否则,除非您知道自己在做什么,否则最终可能会导致捆绑包中的代码重复。答案 3 :(得分:0)
这是我通过Turbolinks提供页面特定代码的方式:
# 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编译到一个文件中,并根据需要执行它们。
以下是post_show的示例:
# 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_menu_init
模块。如果我需要在页面之间共享某些方法,则将它们存储在模块中,并且Webpack非常聪明,不会创建重复项(如果我两次将其导入posts_show和其他页面中),它将仅组织文件,因此我的{{1} }可以使用此方法。
posts_show
不确定是提供网页特定代码的最佳方法,如果有更好的方法,我想听听。
答案 4 :(得分:0)
您可以使用$.getScript
https://coderwall.com/p/xubjcq/handling-large-javascript-files-with-turbolinks
(function(){
var requiredScripts = [];
window.requireOnce = function (path, cb) {
if ($.inArray(path, requiredScripts) == -1) {
requiredScripts.push(path)
$.getScript(path, cb)
} else {
cb()
}
}
})();
像这样使用它:
requireOnce('wysiwyg.js', function(){
$('textarea').wysiwyg()
});
答案 5 :(得分:0)
您应该这样做的方法是创建一个文件夹结构以匹配您的视图:
app/javascript
├── channels
│ ├── consumer.js
│ └── index.js
└── packs
└── application.js
└── post
└── index.js
然后在您想要包含的视图 index.js
中:
<%= javascript_pack_tag('post/index') %>
添加后,在您的 application.rb
中添加:
config.assets.precompile += ['listings/index.js']
这样你只在你需要的特定视图中加载它,你可以在创建视图特定的 JS 时继续附加更多资产。
注意事项:
参考文献: