首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何确保rails 7、cssbundling rails、jsbundling rails在测试模式(RSpec)中都有资产?

如何确保rails 7、cssbundling rails、jsbundling rails在测试模式(RSpec)中都有资产?
EN

Stack Overflow用户
提问于 2022-02-25 08:02:40
回答 2查看 1.6K关注 0票数 4

我正在将一个大型的商业(专有) Rails 6应用程序升级到Rails 7,我们从未使用过Webpacker,而是直接从捆绑的gems到Rails 7 way。

事实证明,Rails 7的“Node”工作流对于同时包含CSS和JS组件的组件没有很好的解决方案。在我们的案例中,最明显的违法者是Bootstrap。面对通过导入映射维护引导带的JS“一半”,以及通过类似于旧的Bootstrap创业板或手动实现(是的,没有Node,真的没有其他解决方案。)之类的东西来维护CSS“一半”,我们最终回到了一个完整的节点工作流中。

这件事要走到一起了。所有提供CSS和/或JS的前端组件都已经在NPM中很好地获得了,所以现在这一切都是通过package.json和Yarn管理的,由bin/dev驱动从app/assetsapp/javascriptnode_modules/...中提取的SCSS和JS组件的Sass &esbuild编译;因此,资产管道manifest.js只包含对app/assets中的buildimages文件夹的引用。

随着文件名列表的所有重量级手动维护(不再支持通配符导入),以及现在在Foreman vs下运行的多个进程的复杂性,这似乎有点倒退了,因为在每个请求的基础上,在链轮上同步处理这些东西,但是随着所有这些东西被废弃/放弃,显然是时候更新了。

在开发和生产模式中,这一切都很好,但是测试呢?我们使用RSpec;在CI中,没有构建的资产,开发人员不希望每次运行rspec时都记得运行esbuildassets:precompile或任何其他类似的操作。除了其他的,它是相当慢的。

在使用最新资产运行测试时,使用cssbundling-railsjsbundling-rails的基于Yarn/Node的工作流中的官方的、惯用的Rails 7解决方案是什么?

EN

回答 2

Stack Overflow用户

发布于 2022-02-28 00:07:46

这是很有前景的,但现在还比没有好;它将确保CI总是构建资产,并确保本地开发始终拥有最新的资产,即使在例如bin/dev没有运行时已经修改了。

代码语言:javascript
复制
# Under Rails 7 with 'cssbundling-rails' and/or the 'jsbundling-rails' gems,
# entirely external systems are used for asset management. With Sprockets no
# longer synchronously building assets on-demand and only when the source files
# changed, compiled assets might be (during local development) or will almost
# always be (CI systems) either out of date or missing when tests are run.
#
# People are used to "bundle exec rspec" and things working. The out-of-box gem
# 'cssbundling-rails' hooks into a vanilla Rails "prepare" task, running a full
# "css:build" task in response. This is quite slow and generates console spam
# on every test run, but points to a slightly better solution for RSpec.
#
# This class is a way of packaging that solution. The class wrapper is really
# just a namespace / container for the code.
#
# First, if you aren't already doing this, add the folllowing lines to
# "spec_helper.rb" somewhere *after* the "require 'rspec/rails'" line:
#
#     require 'rake'
#     YourAppName::Application.load_tasks
#
# ...and call MaintainTestAssets::maintain! (see that method's documentation
# for details). See also constants MaintainTestAssets::ASSET_SOURCE_FOLDERS and
# MaintainTestAssets::EXPECTED_ASSETS for things you may want to customise.
#
class MaintainTestAssets

  # All the places where you have asset files of any kind that you expect to be
  # dynamically compiled/transpiled/etc. via external tooling. The given arrays
  # are passed to "Rails.root.join..." to generate full pathnames.
  #
  # Folders are checked recursively. If any file timestamp therein is greater
  # than (newer than) any of EXPECTED_ASSETS, a rebuild is triggered.
  #
  ASSET_SOURCE_FOLDERS = [
    ['app', 'assets', 'stylesheets'],
    ['app', 'javascript'],
    ['vendor']
  ]

  # The leaf files that ASSET_SOURCE_FOLDERS will build. These are all checked
  # for in "File.join(Rails.root, 'app', 'assets', 'builds')". Where files are
  # written together - e.g. a ".js" and ".js.map" file - you only need to list
  # any one of the group of concurrently generated files.
  #
  # In a standard JS / CSS combination this would just be 'application.css' and
  # 'application.js', but more complex applications might have added or changed
  # entries in the "scripts" section of 'package.json'.
  #
  EXPECTED_ASSETS = %w{
    application.js
    application.css
  }

  # Call this method somewhere at test startup, e.g. in "spec_helper.rb" before
  # tests are actually run (just above "RSpec.configure..." works reasonably).
  #
  def self.maintain!
    run_build    = false
    newest_mtime = Time.now - 100.years

    # Find the newest modificaftion time across all source files of any type -
    # for simplicity, timestamps of JS vs CSS aren't considered
    #
    ASSET_SOURCE_FOLDERS.each do | relative_array |
      glob_path = Rails.root.join(*relative_array, '**', '*')

      Dir[glob_path].each do | filename |
        next if File.directory?(filename) # NOTE EARLY LOOP RESTART

        source_mtime = File.mtime(filename)
        newest_mtime = source_mtime if source_mtime > newest_mtime
      end
    end

    # Compile the built asset leaf names into full file names for convenience.
    #
    built_assets = EXPECTED_ASSETS.map do | leaf |
      Rails.root.join('app', 'assets', 'builds', leaf)
    end

    # If any of the source files are newer than expected built assets, or if
    # any of those assets are missing, trigger a rebuild task *and* force a new
    # timestamp on all output assets (just in case build script optimisations
    # result in a file being skipped as "already up to date", which would cause
    # the code here to otherwise keep trying to rebuild it on every run).
    #
    run_build = built_assets.any? do | filename |
      File.exist?(filename) == false || File.mtime(filename) < newest_mtime
    end

    if run_build
      Rake::Task['javascript:build'].invoke()
      Rake::Task[       'css:build'].invoke()

      built_assets.each { | filename | FileUtils.touch(filename, nocreate: true) }
    end
  end
end

(编辑)正如下面的评论所指出的,您需要确保在spec_helper.rb中加载Rake任务,例如:

代码语言:javascript
复制
require 'rake'
Rails.application.load_tasks
票数 3
EN

Stack Overflow用户

发布于 2022-03-21 23:06:26

jsbundling-railscssbundling-rails都将自己附加到一个名为test:prepare的rake任务中。

有几种方法可以使test:prepare运行,这取决于您的整个构建过程。

  1. 直接称之为: bundle exec rails test:prepare test 或者,如果在rails命令之外运行rspec: bundle exec rails test:prepare && bundle exec rspec
  2. 使用已经调用test:prepare的测试任务。 奇怪的是,只有一些测试任务调用(依赖) test:prepare,而另一些(包括默认的test任务)则不调用。 bundle exec rails test:all
  3. 使test:prepare成为您首选测试任务的依赖项。 例如,如果您通常通过运行spec来使用bundle exec rails spec任务,那么将其添加到新的或现有的任务文件(例如lib/tasks/tests.rake)中: task spec: ['css:build', 'javascript:build']

背景

test:prepare是Rails定义的空任务。cssbundling-railsjsbundling-rails都将自己添加为该任务的依赖项。

通常,test:prepare是添加运行测试所需的任何依赖项的有用地方,但需要注意的是,只有某些Rails的默认测试任务依赖于它。但是,如上所述,您可以直接调用它或添加您自己的依赖项。

在大多数情况下,调用test:prepare相当于调用css:buildjavascript:build,这就是为什么我在上面的大多数示例中向test:prepare展示的原因。有时,其他的gems或你的应用程序也可以使用附加的命令扩展test:prepare,在这种情况下,这些命令也会运行(并且可能会被需要)。

还请注意,assets:precompile也依赖于css:buildjavascript:build。根据我的经验,test:prepare (或css:buildjavascript:build分别运行)比assets:precompile运行得更快,这可能是因为我们正在运行sprockets-rails (而不是propshaft)的轻量级配置,assets:precompile运行整个链轮编译过程。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71262775

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档