From 7afb68b401040dea5c324528c915dc0cc1be7599 Mon Sep 17 00:00:00 2001 From: Pawel Osiczko Date: Wed, 31 Aug 2022 18:45:15 -0600 Subject: [PATCH 01/17] Fix importmap/esbuild conflict during rails new (#186) --- template.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/template.rb b/template.rb index 66132cd..11775c4 100644 --- a/template.rb +++ b/template.rb @@ -111,8 +111,11 @@ def add_authorization generate 'pundit:install' end -def add_jsbundling - rails_command "javascript:install:esbuild" +def default_to_esbuild + return if options[:javascript] == "esbuild" + unless options[:skip_javascript] + @options = options.merge(javascript: "esbuild") + end end def add_javascript @@ -233,14 +236,13 @@ def gem_exists?(name) # Main setup add_template_repository_to_source_path - +default_to_esbuild add_gems after_bundle do set_application_name add_users add_authorization - add_jsbundling add_javascript add_announcements add_notifications From 349723624bcd9171874e336dd76d057927a8d30e Mon Sep 17 00:00:00 2001 From: Jamie Macey Date: Tue, 8 Nov 2022 11:03:10 -0800 Subject: [PATCH 02/17] Update Pundit include (#188) The old usage was deprecated in 2.2.0 (Feb 2022) and now emits a warning, see changelog: https://github.com/varvet/pundit/blob/main/CHANGELOG.md --- app/controllers/application_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index eb0ef89..ce537e9 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,6 +1,6 @@ class ApplicationController < ActionController::Base impersonates :user - include Pundit + include Pundit::Authorization protect_from_forgery with: :exception From 3273e7a5b105e69fbf0afa6d955a9013cf1be60a Mon Sep 17 00:00:00 2001 From: Shawn Aukstakalnis Date: Wed, 30 Nov 2022 12:18:00 -0500 Subject: [PATCH 03/17] Replace old turbolinks attribute (#189) Use the new `data-turbo-track` attribute replacing old `data-turbolinks-track` --- app/views/shared/_head.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/_head.html.erb b/app/views/shared/_head.html.erb index da9c5e9..1bc68f4 100644 --- a/app/views/shared/_head.html.erb +++ b/app/views/shared/_head.html.erb @@ -6,5 +6,5 @@ <%= csp_meta_tag %> -<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> +<%= stylesheet_link_tag "application", media: "all", "data-turbo-track": "reload" %> <%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %> From b5c7f063df5393c768061489470b1e2c2ff8dd00 Mon Sep 17 00:00:00 2001 From: fiveNinePlusR Date: Thu, 12 Jan 2023 18:21:10 -0800 Subject: [PATCH 04/17] Re-order instructions (#191) Re-order the instructions so that you only have to migrate once because noticed:model requires a migration. --- template.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template.rb b/template.rb index 11775c4..6229bf2 100644 --- a/template.rb +++ b/template.rb @@ -281,8 +281,8 @@ def gem_exists?(name) say say " # Update config/database.yml with your database credentials" say - say " rails db:create db:migrate" say " rails g noticed:model" + say " rails db:create db:migrate" say " rails g madmin:install # Generate admin dashboards" say " gem install foreman" say " bin/dev" From 51ea60f697156336e7807ffcaeb61f2ed7fbec86 Mon Sep 17 00:00:00 2001 From: Chris Oliver Date: Tue, 17 Jan 2023 16:59:38 -0600 Subject: [PATCH 05/17] Update npx command. Fixes #190 --- template.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/template.rb b/template.rb index 6229bf2..c503c86 100644 --- a/template.rb +++ b/template.rb @@ -215,10 +215,15 @@ def add_announcements_css def add_esbuild_script build_script = "node esbuild.config.js" - if (`npx -v`.to_f < 7.1 rescue "Missing") - say %(Add "scripts": { "build": "#{build_script}" } to your package.json), :green - else + case `npx -v`.to_f + when 7.1...8.0 run %(npm set-script build "#{build_script}") + run %(yarn build) + when (8.0..) + run %(npm pkg set scripts.build="#{build_script}") + run %(yarn build) + else + say %(Add "scripts": { "build": "#{build_script}" } to your package.json), :green end end From 734f74326ff576fd3e9c4296c2e3b43b18410d5d Mon Sep 17 00:00:00 2001 From: Chris Oliver Date: Tue, 17 Jan 2023 17:07:15 -0600 Subject: [PATCH 06/17] Install lts nodejs for CI --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 31f4cc5..1cce66d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,9 +45,9 @@ jobs: ruby-version: '3.0' - name: Setup Node - uses: actions/setup-node@v1 + uses: actions/setup-node@v3 with: - node-version: '16.x' + node-version: 'lts/*' - name: Install dependencies run: | From 0282168085a7092d0884f376768944550560b897 Mon Sep 17 00:00:00 2001 From: Chris Oliver Date: Tue, 17 Jan 2023 17:13:01 -0600 Subject: [PATCH 07/17] Fix esbuild.config.js for latest esbuild 0.17 which removes the watch option --- esbuild.config.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/esbuild.config.js b/esbuild.config.js index ba42641..006bfe5 100644 --- a/esbuild.config.js +++ b/esbuild.config.js @@ -1,18 +1,10 @@ const path = require('path') const rails = require('esbuild-rails') -const watch = process.argv.includes("--watch") && { - onRebuild(error) { - if (error) console.error("[watch] build failed", error); - else console.log("[watch] build finished"); - }, -}; - require("esbuild").build({ entryPoints: ["application.js"], bundle: true, outdir: path.join(process.cwd(), "app/assets/builds"), absWorkingDir: path.join(process.cwd(), "app/javascript"), - watch: watch, plugins: [rails()], }).catch(() => process.exit(1)); From 0fd77d5aa39ac85c19cee1cd59f1642f3b450320 Mon Sep 17 00:00:00 2001 From: Chris Oliver Date: Tue, 17 Jan 2023 17:13:17 -0600 Subject: [PATCH 08/17] Copy templates over before setting esbuild script --- template.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/template.rb b/template.rb index c503c86..edd6bbc 100644 --- a/template.rb +++ b/template.rb @@ -258,7 +258,6 @@ def gem_exists?(name) add_whenever add_sitemap add_announcements_css - add_esbuild_script rails_command "active_storage:install" # Make sure Linux is in the Gemfile.lock for deploying @@ -266,6 +265,8 @@ def gem_exists?(name) copy_templates + add_esbuild_script + # Commit everything to git unless ENV["SKIP_GIT"] git :init From 7092b6849c74d4cb1d08a517feb9d2566bc090c7 Mon Sep 17 00:00:00 2001 From: Chris Oliver Date: Mon, 30 Jan 2023 09:17:03 -0600 Subject: [PATCH 09/17] esbuild 0.17+ compatibility --- esbuild.config.js | 10 ----- esbuild.config.mjs | 96 ++++++++++++++++++++++++++++++++++++++++++++++ template.rb | 4 +- 3 files changed, 98 insertions(+), 12 deletions(-) delete mode 100644 esbuild.config.js create mode 100644 esbuild.config.mjs diff --git a/esbuild.config.js b/esbuild.config.js deleted file mode 100644 index 006bfe5..0000000 --- a/esbuild.config.js +++ /dev/null @@ -1,10 +0,0 @@ -const path = require('path') -const rails = require('esbuild-rails') - -require("esbuild").build({ - entryPoints: ["application.js"], - bundle: true, - outdir: path.join(process.cwd(), "app/assets/builds"), - absWorkingDir: path.join(process.cwd(), "app/javascript"), - plugins: [rails()], -}).catch(() => process.exit(1)); diff --git a/esbuild.config.mjs b/esbuild.config.mjs new file mode 100644 index 0000000..9242d0c --- /dev/null +++ b/esbuild.config.mjs @@ -0,0 +1,96 @@ +#!/usr/bin/env node + +// Esbuild is configured with 3 modes: +// +// `yarn build` - Build JavaScript and exit +// `yarn build --watch` - Rebuild JavaScript on change +// `yarn build --reload` - Reloads page when views, JavaScript, or stylesheets change +// +// Minify is enabled when "RAILS_ENV=production" +// Sourcemaps are enabled in non-production environments + +import * as esbuild from "esbuild" +import path from "path" +import rails from "esbuild-rails" +import chokidar from "chokidar" +import http from "http" +import { setTimeout } from "timers/promises" + +const clients = [] +const entryPoints = [ + "application.js" +] +const watchDirectories = [ + "./app/javascript/**/*.js", + "./app/views/**/*.html.erb", + "./app/assets/builds/**/*.css", // Wait for cssbundling changes +] +const config = { + absWorkingDir: path.join(process.cwd(), "app/javascript"), + bundle: true, + entryPoints: entryPoints, + minify: process.env.RAILS_ENV == "production", + outdir: path.join(process.cwd(), "app/assets/builds"), + plugins: [rails()], + sourcemap: process.env.RAILS_ENV != "production" +} + +async function buildAndReload() { + // Foreman & Overmind assign a separate PORT for each process + const port = parseInt(process.env.PORT) + const context = await esbuild.context({ + ...config, + banner: { + js: ` (() => new EventSource("http://localhost:${port}").onmessage = () => location.reload())();`, + } + }) + + // Reload uses an HTTP server as an even stream to reload the browser + http + .createServer((req, res) => { + return clients.push( + res.writeHead(200, { + "Content-Type": "text/event-stream", + "Cache-Control": "no-cache", + "Access-Control-Allow-Origin": "*", + Connection: "keep-alive", + }) + ) + }) + .listen(port) + + await context.rebuild() + console.log("[reload] initial build succeeded") + + let ready = false + chokidar + .watch(watchDirectories) + .on("ready", () => { + console.log("[reload] ready") + ready = true + }) + .on("all", async (event, path) => { + if (ready === false) return + + if (path.includes("javascript")) { + try { + await setTimeout(20) + await context.rebuild() + console.log("[reload] build succeeded") + } catch (error) { + console.error("[reload] build failed", error) + } + } + clients.forEach((res) => res.write("data: update\n\n")) + clients.length = 0 + }) +} + +if (process.argv.includes("--reload")) { + buildAndReload() +} else if (process.argv.includes("--watch")) { + let context = await esbuild.context({...config, logLevel: 'info'}) + context.watch() +} else { + esbuild.build(config) +} diff --git a/template.rb b/template.rb index edd6bbc..9adb55f 100644 --- a/template.rb +++ b/template.rb @@ -131,7 +131,7 @@ def copy_templates copy_file "Procfile" copy_file "Procfile.dev" copy_file ".foreman" - copy_file "esbuild.config.js" + copy_file "esbuild.config.mjs" copy_file "app/javascript/application.js" copy_file "app/javascript/controllers/index.js" @@ -213,7 +213,7 @@ def add_announcements_css end def add_esbuild_script - build_script = "node esbuild.config.js" + build_script = "node esbuild.config.mjs" case `npx -v`.to_f when 7.1...8.0 From 09eaffca674712de9c18eca1449334d220f74eb7 Mon Sep 17 00:00:00 2001 From: Chris Oliver Date: Fri, 17 Feb 2023 08:50:44 -0600 Subject: [PATCH 10/17] =?UTF-8?q?Upgrade=20to=20Devise=204.9=20with=20Turb?= =?UTF-8?q?o=20support=20=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template.rb | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/template.rb b/template.rb index 9adb55f..65d9dd9 100644 --- a/template.rb +++ b/template.rb @@ -35,7 +35,7 @@ def rails_6_or_newer? def add_gems add_gem 'cssbundling-rails' - add_gem 'devise', '~> 4.8', '>= 4.8.0' + add_gem 'devise', '~> 4.9' add_gem 'friendly_id', '~> 5.4' add_gem 'jsbundling-rails' add_gem 'madmin' @@ -64,33 +64,6 @@ def add_users route "root to: 'home#index'" generate "devise:install" - # Configure Devise to handle TURBO_STREAM requests like HTML requests - inject_into_file "config/initializers/devise.rb", " config.navigational_formats = ['/', :html, :turbo_stream]", after: "Devise.setup do |config|\n" - - inject_into_file 'config/initializers/devise.rb', after: "# frozen_string_literal: true\n" do <<~EOF - class TurboFailureApp < Devise::FailureApp - def respond - if request_format == :turbo_stream - redirect - else - super - end - end - - def skip_format? - %w(html turbo_stream */*).include? request_format.to_s - end - end - EOF - end - - inject_into_file 'config/initializers/devise.rb', after: "# ==> Warden configuration\n" do <<-EOF - config.warden do |manager| - manager.failure_app = TurboFailureApp - end - EOF - end - environment "config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }", env: 'development' generate :devise, "User", "first_name", "last_name", "announcements_last_read_at:datetime", "admin:boolean" From ca0251e3eac825237c14c59c4a6d0ff9bf654941 Mon Sep 17 00:00:00 2001 From: Jorge Najera Date: Mon, 13 Mar 2023 18:52:43 -0600 Subject: [PATCH 11/17] Min fix on template.rb (#193) * Update template.rb Min fix to suggest first create the db and after generate the noticed model * Update template.rb Fix order steps to start the app --- template.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/template.rb b/template.rb index 65d9dd9..23c48cb 100644 --- a/template.rb +++ b/template.rb @@ -260,8 +260,9 @@ def gem_exists?(name) say say " # Update config/database.yml with your database credentials" say + say " rails db:create" say " rails g noticed:model" - say " rails db:create db:migrate" + say " rails db:migrate" say " rails g madmin:install # Generate admin dashboards" say " gem install foreman" say " bin/dev" From 45ea464f27f35643e2aca5e5d420745f40abd08d Mon Sep 17 00:00:00 2001 From: Chuck Date: Mon, 27 Mar 2023 09:42:27 -0400 Subject: [PATCH 12/17] Update esbuild configuration for HMR (#194) Co-authored-by: Chuck Smith --- Procfile.dev | 2 +- template.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Procfile.dev b/Procfile.dev index 68a69c6..d44b54d 100644 --- a/Procfile.dev +++ b/Procfile.dev @@ -1,4 +1,4 @@ web: bin/rails server -p 3000 worker: bundle exec sidekiq -js: yarn build --watch +js: yarn build --reload css: yarn build:css --watch diff --git a/template.rb b/template.rb index 23c48cb..c5caf22 100644 --- a/template.rb +++ b/template.rb @@ -92,7 +92,7 @@ def default_to_esbuild end def add_javascript - run "yarn add local-time esbuild-rails trix @hotwired/stimulus @hotwired/turbo-rails @rails/activestorage @rails/ujs @rails/request.js" + run "yarn add local-time esbuild-rails trix @hotwired/stimulus @hotwired/turbo-rails @rails/activestorage @rails/ujs @rails/request.js chokidar" end def copy_templates From 3268d26180a6355cd9eb018f6908837cf5349e72 Mon Sep 17 00:00:00 2001 From: Fig Date: Tue, 7 Nov 2023 13:56:23 +0000 Subject: [PATCH 13/17] Relax watchDirectories glob (#202) * Relax watchDirectories glob The previous glob was a little too restrictive and would not watch files target at request variants e.g. `app/views/things/show.html+phone.erb` * Update esbuild.config.mjs --------- Co-authored-by: Chris Oliver --- esbuild.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esbuild.config.mjs b/esbuild.config.mjs index 9242d0c..2fe760b 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -22,7 +22,7 @@ const entryPoints = [ ] const watchDirectories = [ "./app/javascript/**/*.js", - "./app/views/**/*.html.erb", + "./app/views/**/*.erb", "./app/assets/builds/**/*.css", // Wait for cssbundling changes ] const config = { From 67583ce48f91d6e46275e1bc4aaac62197d9aaa5 Mon Sep 17 00:00:00 2001 From: Chris Oliver Date: Tue, 7 Nov 2023 08:11:22 -0600 Subject: [PATCH 14/17] Update ci.yml --- .github/workflows/ci.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1cce66d..399d48d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest services: postgres: - image: postgres:14 + image: postgres:latest env: POSTGRES_DB: test_app_production POSTGRES_USER: test_app @@ -37,17 +37,19 @@ jobs: options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 steps: - - uses: actions/checkout@master + - uses: actions/checkout@v4 - name: Setup Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '3.0' + ruby-version: '3.2' + bundler-cache: true - name: Setup Node uses: actions/setup-node@v3 with: node-version: 'lts/*' + cache: yarn - name: Install dependencies run: | From 0ee9e5c0cae9ba6486d02b80ec67d77940701df2 Mon Sep 17 00:00:00 2001 From: Chris Oliver Date: Tue, 7 Nov 2023 08:19:17 -0600 Subject: [PATCH 15/17] Update ci.yml --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 399d48d..bd480de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,6 @@ jobs: uses: actions/setup-node@v3 with: node-version: 'lts/*' - cache: yarn - name: Install dependencies run: | From 7bd143dafcc904d788619b829522a27233c83e9b Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 7 Nov 2023 09:30:52 -0500 Subject: [PATCH 16/17] Update Rails version check if Rails 7 or newer is not being used. (#199) * Update Rails version check if Rails 7 or newer is not being used. * Add check for rails 6 edge case * Update template.rb * Update template.rb --------- Co-authored-by: Chris Oliver --- template.rb | 56 +++++++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/template.rb b/template.rb index c5caf22..e5ddc69 100644 --- a/template.rb +++ b/template.rb @@ -25,12 +25,24 @@ def add_template_repository_to_source_path end end +def read_gemfile? + File.open("Gemfile").each_line do |line| + return true if line.strip.start_with?("rails") && line.include?("6.") + end +end + def rails_version - @rails_version ||= Gem::Version.new(Rails::VERSION::STRING) + @rails_version ||= Gem::Version.new(Rails::VERSION::STRING) || read_gemfile? +end + +def rails_7_or_newer? + Gem::Requirement.new(">= 7.0.0.alpha").satisfied_by? rails_version end -def rails_6_or_newer? - Gem::Requirement.new(">= 6.0.0.alpha").satisfied_by? rails_version +unless rails_7_or_newer? + say "\nJumpstart requires Rails 7 or newer. You are using #{rails_version}.", :green + say "Please remove partially installed Jumpstart files #{original_app_name} and try again.", :green + exit 1 end def add_gems @@ -69,13 +81,11 @@ def add_users # Set admin default to false in_root do - migration = Dir.glob("db/migrate/*").max_by{ |f| File.mtime(f) } + migration = Dir.glob("db/migrate/*").max_by { |f| File.mtime(f) } gsub_file migration, /:admin/, ":admin, default: false" end - if Gem::Requirement.new("> 5.2").satisfied_by? rails_version - gsub_file "config/initializers/devise.rb", / # config.secret_key = .+/, " config.secret_key = Rails.application.credentials.secret_key_base" - end + gsub_file "config/initializers/devise.rb", / # config.secret_key = .+/, " config.secret_key = Rails.application.credentials.secret_key_base" inject_into_file("app/models/user.rb", "omniauthable, :", after: "devise :") end @@ -120,21 +130,21 @@ def add_sidekiq environment "config.active_job.queue_adapter = :sidekiq" insert_into_file "config/routes.rb", - "require 'sidekiq/web'\n\n", - before: "Rails.application.routes.draw do" + "require 'sidekiq/web'\n\n", + before: "Rails.application.routes.draw do" content = <<~RUBY - authenticate :user, lambda { |u| u.admin? } do - mount Sidekiq::Web => '/sidekiq' - - namespace :madmin do - resources :impersonates do - post :impersonate, on: :member - post :stop_impersonating, on: :collection - end - end - end - RUBY + authenticate :user, lambda { |u| u.admin? } do + mount Sidekiq::Web => '/sidekiq' + + namespace :madmin do + resources :impersonates do + post :impersonate, on: :member + post :stop_impersonating, on: :collection + end + end + end + RUBY insert_into_file "config/routes.rb", "#{content}\n", after: "Rails.application.routes.draw do\n" end @@ -170,7 +180,7 @@ def add_whenever def add_friendly_id generate "friendly_id" - insert_into_file( Dir["db/migrate/**/*friendly_id_slugs.rb"].first, "[5.2]", after: "ActiveRecord::Migration") + insert_into_file(Dir["db/migrate/**/*friendly_id_slugs.rb"].first, "[5.2]", after: "ActiveRecord::Migration") end def add_sitemap @@ -208,10 +218,6 @@ def gem_exists?(name) IO.read("Gemfile") =~ /^\s*gem ['"]#{name}['"]/ end -unless rails_6_or_newer? - puts "Please use Rails 6.0 or newer to create a Jumpstart application" -end - # Main setup add_template_repository_to_source_path default_to_esbuild From 80980bce233bbebec78a1b13fdf3113d9eda31bd Mon Sep 17 00:00:00 2001 From: Andy Waite <13400+andyw8@users.noreply.github.com> Date: Tue, 7 Nov 2023 09:31:56 -0500 Subject: [PATCH 17/17] Run `yarn build` as part of template test (#173) Co-authored-by: Andy Waite --- test/template_test.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/template_test.rb b/test/template_test.rb index a71004a..234dd1b 100644 --- a/test/template_test.rb +++ b/test/template_test.rb @@ -10,10 +10,15 @@ def teardown end def test_generator_succeeds - output, err = capture_subprocess_io do + output, _err = capture_subprocess_io do system("DISABLE_SPRING=1 SKIP_GIT=1 rails new test_app -m template.rb") end assert_includes output, "Jumpstart app successfully created!" + + output, _err = capture_subprocess_io do + system("cd test_app && yarn build") + end + assert_includes output, "Done in " end # TODO: Fix these tests on CI so they don't fail on db:create