diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cba1105238..de63e924ac 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,6 +42,11 @@ jobs: orm: active_record adapter: postgresql asset: sprockets + - ruby: "3.0" + gemfile: gemfiles/rails_7.0.gemfile + orm: active_record + adapter: sqlite3 + asset: vite - ruby: "3.0" gemfile: gemfiles/composite_primary_keys.gemfile orm: active_record diff --git a/Gemfile b/Gemfile index f082488ee5..651b893fb7 100644 --- a/Gemfile +++ b/Gemfile @@ -6,6 +6,7 @@ gem 'appraisal', '>= 2.0' gem 'devise' gem 'net-smtp', require: false gem 'rails' +gem 'vite_rails', require: false gem 'webpacker', require: false gem 'webrick' diff --git a/gemfiles/composite_primary_keys.gemfile b/gemfiles/composite_primary_keys.gemfile index b8638ea0af..0fb1481bfb 100644 --- a/gemfiles/composite_primary_keys.gemfile +++ b/gemfiles/composite_primary_keys.gemfile @@ -6,6 +6,7 @@ gem "appraisal", ">= 2.0" gem "devise", "~> 4.8" gem "net-smtp", require: false gem "rails", "~> 7.0.0" +gem "vite_rails", require: false gem "webpacker", require: false gem "webrick" gem "sassc-rails", "~> 2.1" diff --git a/gemfiles/rails_6.0.gemfile b/gemfiles/rails_6.0.gemfile index a90ab17b1b..0e3b837443 100644 --- a/gemfiles/rails_6.0.gemfile +++ b/gemfiles/rails_6.0.gemfile @@ -6,6 +6,7 @@ gem "appraisal", ">= 2.0" gem "devise", "~> 4.7" gem "net-smtp", require: false gem "rails", "~> 6.0.0" +gem "vite_rails", require: false gem "webpacker", require: false gem "webrick" gem "sassc-rails", "~> 2.1" diff --git a/gemfiles/rails_6.1.gemfile b/gemfiles/rails_6.1.gemfile index c50190341f..3c3e2d854c 100644 --- a/gemfiles/rails_6.1.gemfile +++ b/gemfiles/rails_6.1.gemfile @@ -6,6 +6,7 @@ gem "appraisal", ">= 2.0" gem "devise", "~> 4.7" gem "net-smtp", require: false gem "rails", "~> 6.1.0" +gem "vite_rails", require: false gem "webpacker", require: false gem "webrick" gem "sassc-rails", "~> 2.1" diff --git a/gemfiles/rails_7.0.gemfile b/gemfiles/rails_7.0.gemfile index f5c10b0bfd..f5644bfa47 100644 --- a/gemfiles/rails_7.0.gemfile +++ b/gemfiles/rails_7.0.gemfile @@ -6,6 +6,7 @@ gem "appraisal", ">= 2.0" gem "devise", "~> 4.8" gem "net-smtp", require: false gem "rails", "~> 7.0.0" +gem "vite_rails", require: false gem "webpacker", require: false gem "webrick" gem "importmap-rails", require: false diff --git a/lib/generators/rails_admin/install_generator.rb b/lib/generators/rails_admin/install_generator.rb index dfe931d1c4..ca86af7bfc 100644 --- a/lib/generators/rails_admin/install_generator.rb +++ b/lib/generators/rails_admin/install_generator.rb @@ -74,8 +74,9 @@ def configure_for_webpacker5 def configure_for_vite vite_source_code_dir = ViteRuby.config.source_code_dir - run "yarn add rails_admin@#{RailsAdmin::Version.js}" + run "yarn add rails_admin@#{RailsAdmin::Version.js} sass" template('rails_admin.vite.js', File.join(vite_source_code_dir, 'entrypoints', 'rails_admin.js')) + @fa_font_path = '@fortawesome/fontawesome-free/webfonts' template('rails_admin.scss.erb', File.join(vite_source_code_dir, 'stylesheets', 'rails_admin.scss')) end diff --git a/lib/generators/rails_admin/templates/rails_admin.vite.js b/lib/generators/rails_admin/templates/rails_admin.vite.js index 2f1a99b505..1248edc4ba 100644 --- a/lib/generators/rails_admin/templates/rails_admin.vite.js +++ b/lib/generators/rails_admin/templates/rails_admin.vite.js @@ -1,3 +1,2 @@ -import '~/stylesheets/rails_admin.scss' -import "@fortawesome/fontawesome-free/css/all.css" -import 'rails_admin/src/rails_admin/base'; +import "~/stylesheets/rails_admin.scss"; +import "rails_admin/src/rails_admin/base"; diff --git a/spec/dummy_app/.gitignore b/spec/dummy_app/.gitignore index 0551f0914c..8a791fb421 100644 --- a/spec/dummy_app/.gitignore +++ b/spec/dummy_app/.gitignore @@ -22,6 +22,7 @@ /public/assets /public/packs /public/packs-test +/public/vite* /node_modules /yarn-error.log /yarn.lock diff --git a/spec/dummy_app/Gemfile b/spec/dummy_app/Gemfile index 29abc1be1a..d60b801f63 100644 --- a/spec/dummy_app/Gemfile +++ b/spec/dummy_app/Gemfile @@ -31,6 +31,7 @@ gem 'mlb', '>= 0.7', github: 'mshibuya/mlb', branch: 'ruby-3' gem 'paperclip', '>= 3.4' gem 'rails_admin', path: '../../' gem 'shrine', '~> 3.0' +gem 'vite_rails', require: false gem 'webpacker', require: false gem 'webrick' diff --git a/spec/dummy_app/Procfile.dev b/spec/dummy_app/Procfile.dev index 0c4b7357b9..38f2b2dabb 100644 --- a/spec/dummy_app/Procfile.dev +++ b/spec/dummy_app/Procfile.dev @@ -1,2 +1,3 @@ web: bin/rails server -p 3000 css: yarn build:css --watch +vite: bin/vite dev diff --git a/spec/dummy_app/app/frontend/entrypoints/application.js b/spec/dummy_app/app/frontend/entrypoints/application.js new file mode 100644 index 0000000000..7bb62d5763 --- /dev/null +++ b/spec/dummy_app/app/frontend/entrypoints/application.js @@ -0,0 +1,2 @@ +import "@rails/ujs"; +import "@hotwired/turbo-rails"; diff --git a/spec/dummy_app/app/frontend/entrypoints/rails_admin.js b/spec/dummy_app/app/frontend/entrypoints/rails_admin.js new file mode 100644 index 0000000000..08b5caf6e6 --- /dev/null +++ b/spec/dummy_app/app/frontend/entrypoints/rails_admin.js @@ -0,0 +1,17 @@ +import "~/stylesheets/rails_admin.scss"; +import "rails_admin/src/rails_admin/base"; +import "flatpickr/dist/l10n/fr.js"; +import "trix"; +import "@rails/actiontext"; +import * as ActiveStorage from "@rails/activestorage"; +ActiveStorage.start(); + +window.domReadyTriggered = []; + +document.addEventListener("rails_admin.dom_ready", function () { + window.domReadyTriggered.push("plainjs/dot"); +}); + +$(document).on("rails_admin.dom_ready", function () { + window.domReadyTriggered.push("jquery/dot"); +}); diff --git a/spec/dummy_app/app/frontend/stylesheets/rails_admin.scss b/spec/dummy_app/app/frontend/stylesheets/rails_admin.scss new file mode 100644 index 0000000000..eb98071c79 --- /dev/null +++ b/spec/dummy_app/app/frontend/stylesheets/rails_admin.scss @@ -0,0 +1,2 @@ +$fa-font-path: "@fortawesome/fontawesome-free/webfonts"; +@import "rails_admin/src/rails_admin/styles/base"; diff --git a/spec/dummy_app/app/views/layouts/application.html.erb b/spec/dummy_app/app/views/layouts/application.html.erb index ddf532edd0..680c846ac5 100644 --- a/spec/dummy_app/app/views/layouts/application.html.erb +++ b/spec/dummy_app/app/views/layouts/application.html.erb @@ -7,6 +7,9 @@ <%= javascript_pack_tag "application" %> <% when :importmap %> <%= javascript_importmap_tags %> + <% when :vite %> + <%= vite_client_tag %> + <%= vite_javascript_tag 'application' %> <% else %> <%= stylesheet_link_tag "application", media: "all" %> <%= javascript_include_tag "application", type: 'module' %> diff --git a/spec/dummy_app/bin/bundle b/spec/dummy_app/bin/bundle index 66e9889e8b..981e650b68 100755 --- a/spec/dummy_app/bin/bundle +++ b/spec/dummy_app/bin/bundle @@ -1,3 +1,114 @@ #!/usr/bin/env ruby -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) -load Gem.bin_path('bundler', 'bundle') +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'bundle' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "rubygems" + +m = Module.new do + module_function + + def invoked_as_script? + File.expand_path($0) == File.expand_path(__FILE__) + end + + def env_var_version + ENV["BUNDLER_VERSION"] + end + + def cli_arg_version + return unless invoked_as_script? # don't want to hijack other binstubs + return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` + bundler_version = nil + update_index = nil + ARGV.each_with_index do |a, i| + if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN + bundler_version = a + end + next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ + bundler_version = $1 + update_index = i + end + bundler_version + end + + def gemfile + gemfile = ENV["BUNDLE_GEMFILE"] + return gemfile if gemfile && !gemfile.empty? + + File.expand_path("../Gemfile", __dir__) + end + + def lockfile + lockfile = + case File.basename(gemfile) + when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) + else "#{gemfile}.lock" + end + File.expand_path(lockfile) + end + + def lockfile_version + return unless File.file?(lockfile) + lockfile_contents = File.read(lockfile) + return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ + Regexp.last_match(1) + end + + def bundler_requirement + @bundler_requirement ||= + env_var_version || cli_arg_version || + bundler_requirement_for(lockfile_version) + end + + def bundler_requirement_for(version) + return "#{Gem::Requirement.default}.a" unless version + + bundler_gem_version = Gem::Version.new(version) + + requirement = bundler_gem_version.approximate_recommendation + + return requirement unless Gem.rubygems_version < Gem::Version.new("2.7.0") + + requirement += ".a" if bundler_gem_version.prerelease? + + requirement + end + + def load_bundler! + ENV["BUNDLE_GEMFILE"] ||= gemfile + + activate_bundler + end + + def activate_bundler + gem_error = activation_error_handling do + gem "bundler", bundler_requirement + end + return if gem_error.nil? + require_error = activation_error_handling do + require "bundler/version" + end + return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) + warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" + exit 42 + end + + def activation_error_handling + yield + nil + rescue StandardError, LoadError => e + e + end +end + +m.load_bundler! + +if m.invoked_as_script? + load Gem.bin_path("bundler", "bundle") +end diff --git a/spec/dummy_app/bin/vite b/spec/dummy_app/bin/vite new file mode 100755 index 0000000000..7527d097eb --- /dev/null +++ b/spec/dummy_app/bin/vite @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'vite' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("vite_ruby", "vite") diff --git a/spec/dummy_app/config/application.rb b/spec/dummy_app/config/application.rb index df869eced1..dfc27a6b74 100644 --- a/spec/dummy_app/config/application.rb +++ b/spec/dummy_app/config/application.rb @@ -23,6 +23,8 @@ when :importmap require 'sprockets/railtie' require 'importmap-rails' +when :vite + require 'vite_rails' end # Require the gems listed in Gemfile, including any gems diff --git a/spec/dummy_app/config/vite.json b/spec/dummy_app/config/vite.json new file mode 100644 index 0000000000..227b1370f6 --- /dev/null +++ b/spec/dummy_app/config/vite.json @@ -0,0 +1,15 @@ +{ + "all": { + "sourceCodeDir": "app/frontend", + "watchAdditionalPaths": ["../../src"] + }, + "development": { + "autoBuild": true, + "publicOutputDir": "vite", + "port": 3036 + }, + "test": { + "autoBuild": false, + "publicOutputDir": "vite" + } +} diff --git a/spec/dummy_app/package.json b/spec/dummy_app/package.json index 348aedd3ea..d89e3f8021 100644 --- a/spec/dummy_app/package.json +++ b/spec/dummy_app/package.json @@ -14,6 +14,8 @@ "webpack-cli": "^3.3.12" }, "devDependencies": { + "vite": "^4.3.0", + "vite-plugin-ruby": "^3.2.0", "webpack-dev-server": "^3" }, "scripts": { diff --git a/spec/dummy_app/vite.config.ts b/spec/dummy_app/vite.config.ts new file mode 100644 index 0000000000..ebd34ec97c --- /dev/null +++ b/spec/dummy_app/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from "vite"; +import RubyPlugin from "vite-plugin-ruby"; + +export default defineConfig({ + plugins: [RubyPlugin()], +}); diff --git a/spec/rails_admin/install_generator_spec.rb b/spec/rails_admin/install_generator_spec.rb index 3d5333f3a0..1d819c0a82 100644 --- a/spec/rails_admin/install_generator_spec.rb +++ b/spec/rails_admin/install_generator_spec.rb @@ -87,6 +87,18 @@ contains 'webpack --config webpack.config.js' contains 'sass ./app/assets/stylesheets/rails_admin.scss:./app/assets/builds/rails_admin.css' end + when :vite + file 'app/frontend/entrypoints/rails_admin.js' do + contains 'import "~/stylesheets/rails_admin.scss"' + contains 'import "rails_admin/src/rails_admin/base"' + end + file 'app/frontend/stylesheets/rails_admin.scss' do + contains '$fa-font-path: "@fortawesome/fontawesome-free/webfonts";' + contains '@import "rails_admin/src/rails_admin/styles/base"' + end + file 'package.json' do + contains 'sass' + end end end, ) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 96846770d8..1bed7f5025 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -79,7 +79,12 @@ end config.before(:all) do - Webpacker.instance.compiler.compile if CI_ASSET == :webpacker + case CI_ASSET + when :webpacker + Webpacker.instance.compiler.compile + when :vite + ViteRuby.instance.commands.build + end end config.before do |example| diff --git a/src/rails_admin/base.js b/src/rails_admin/base.js index 39624bdffb..8e2685bab5 100644 --- a/src/rails_admin/base.js +++ b/src/rails_admin/base.js @@ -27,4 +27,6 @@ import "./sidescroll"; import "./ui"; import "./widgets"; -Rails.start(); +if (!window._rails_loaded) { + Rails.start(); +}