Created
July 28, 2024 20:14
-
-
Save somenugget/acc052a3680921354ecaa2c17fb7b27d to your computer and use it in GitHub Desktop.
Rails template with Vite, Tailwind, Devise
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# rails new app_name -m ./template.rb | |
self.instance_variable_set(:@options, self.instance_variable_get(:@options).merge( | |
skip_javascript: true, | |
skip_hotwire: true, | |
skip_action_mailbox: true, | |
skip_action_text: true, | |
database: 'postgres' | |
)) | |
remove_file 'Gemfile' | |
create_file 'Gemfile', <<-RUBY | |
source "https://rubygems.org" | |
ruby "3.2.2" | |
# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" | |
gem "rails", "~> 7.1.3", ">= 7.1.3.4" | |
gem "pg", "~> 1.1" | |
# Use the Puma web server [https://github.com/puma/puma] | |
gem "puma", ">= 5.0" | |
# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev] | |
gem "turbo-rails" | |
gem "stimulus-rails" | |
gem "devise" | |
gem "good_job" | |
gem "vite_rails" | |
gem "service_actor" | |
# Use Redis adapter to run Action Cable in production | |
# gem "redis", ">= 4.0.1" | |
# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis] | |
# gem "kredis" | |
# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] | |
# gem "bcrypt", "~> 3.1.7" | |
# Reduces boot times through caching; required in config/boot.rb | |
gem "bootsnap", require: false | |
# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] | |
# gem "image_processing", "~> 1.2" | |
group :development, :test do | |
gem "byebug" | |
gem 'dotenv-rails' | |
gem 'bundle-audit', require: false | |
gem 'rubocop' | |
gem 'rubocop-factory_bot' | |
gem 'rubocop-rails' | |
gem 'rubocop-rspec' | |
gem 'factory_bot' | |
gem 'rspec-rails', '~> 6.0.0' | |
end | |
group :development do | |
# Use console on exceptions pages [https://github.com/rails/web-console] | |
gem "web-console" | |
end | |
RUBY | |
inside('config') do | |
# Use PostgreSQL as the database | |
remove_file 'database.yml' | |
create_file 'database.yml', <<-YAML | |
default: &default | |
adapter: postgresql | |
encoding: unicode | |
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> | |
username: <%= ENV.fetch("DATABASE_USERNAME") { 'postgres' } %> | |
password: <%= ENV.fetch("DATABASE_PASSWORD") { '' } %> | |
host: <%= ENV.fetch("DATABASE_HOST") { 'localhost' } %> | |
development: | |
<<: *default | |
database: #{app_name}_development | |
test: | |
<<: *default | |
database: #{app_name}_test | |
production: | |
<<: *default | |
database: #{app_name}_production | |
username: #{app_name} | |
password: <%= ENV['#{app_name.upcase}_DATABASE_PASSWORD'] %> | |
YAML | |
create_file 'vite.json', <<-JSON | |
{ | |
"all": { | |
"sourceCodeDir": "app/frontend", | |
"watchAdditionalPaths": ["app/views/**/*"] | |
}, | |
"development": { | |
"autoBuild": true, | |
"publicOutputDir": "vite-dev", | |
"port": 3036 | |
}, | |
"test": { | |
"autoBuild": true, | |
"publicOutputDir": "vite-test", | |
"port": 3037 | |
} | |
} | |
JSON | |
# Add custom generator configuration and ActiveJob queue adapter to application.rb | |
inject_into_file 'application.rb', after: "# config.eager_load_paths << Rails.root.join(\"extras\")\n" do | |
<<-RUBY | |
config.generators do |g| | |
g.helper false | |
g.system_tests false | |
g.test_framework :rspec, | |
view_specs: false, | |
helper_specs: false, | |
routing_specs: false | |
end | |
config.active_job.queue_adapter = :good_job | |
RUBY | |
end | |
inside('initializers') do | |
remove_file 'assets.rb' | |
end | |
inside('environments') do | |
gsub_file('development.rb', "# Suppress logger output for asset requests.\n", '') | |
gsub_file('development.rb', "config.assets.quiet = true\n", '') | |
gsub_file('production.rb', "# Compress CSS using a preprocessor.\n", '') | |
gsub_file('production.rb', "# config.assets.css_compressor = :sass\n", '') | |
gsub_file('production.rb', "# Do not fall back to assets pipeline if a precompiled asset is missed.\n", '') | |
gsub_file('production.rb', "config.assets.compile = false\n", '') | |
end | |
end | |
create_file '.rubocop.yml', <<-YAML | |
require: | |
- rubocop-factory_bot | |
- rubocop-rails | |
- rubocop-rspec | |
AllCops: | |
NewCops: enable | |
DisplayStyleGuide: true | |
Exclude: | |
- 'bin/**/*' | |
- 'db/**/*' | |
- 'vendor/**/*' | |
Layout/LineLength: | |
Exclude: | |
- 'config/**/*' | |
Layout/FirstArgumentIndentation: | |
EnforcedStyle: consistent | |
Lint/MissingSuper: | |
Exclude: | |
- 'spec/**/*' | |
Metrics/BlockLength: | |
Exclude: | |
- 'spec/**/*' | |
- 'config/**/*' | |
- 'db/**/*' | |
- 'vendor/**/*' | |
Metrics/MethodLength: | |
Max: 15 | |
Naming/BlockForwarding: | |
Enabled: false | |
Rails/I18nLocaleTexts: | |
Enabled: false | |
Style/ArgumentsForwarding: | |
Enabled: false | |
Style/ClassAndModuleChildren: | |
Enabled: false | |
Style/Documentation: | |
Enabled: false | |
Style/DocumentationMethod: | |
Enabled: true | |
Include: | |
- 'app/models/**/*.rb' | |
- 'app/services/**/*.rb' | |
- 'app/components/**/*.rb' | |
- 'app/jobs/**/*.rb' | |
- 'app/mailers/**/*.rb' | |
- 'app/channels/**/*.rb' | |
Style/HashSyntax: | |
Enabled: false | |
Style/FetchEnvVar: | |
Enabled: false | |
Style/FrozenStringLiteralComment: | |
Enabled: false | |
Style/TrailingCommaInHashLiteral: | |
Enabled: false | |
YAML | |
create_file '.env' | |
create_file '.env.example' | |
# Run bundle install | |
run 'bundle install' | |
# Initialize Vite | |
run 'bundle exec vite install' | |
# Initialize the database | |
rails_command 'db:drop' | |
rails_command 'db:create' | |
rails_command 'db:migrate' | |
# Initialize GoodJob | |
generate 'good_job:install' | |
rails_command 'db:migrate' | |
# Initialize Devise | |
generate 'devise:install' | |
generate 'devise User' | |
rails_command 'db:migrate' | |
# Initialize RSpec | |
generate 'rspec:install' | |
# Create a home controller with an index action | |
generate(:controller, 'home', 'index') | |
# Set up the root route | |
route "root to: 'home#index'" | |
remove_file 'vite.config.ts' | |
create_file 'vite.config.mjs', <<-JS | |
import { defineConfig } from 'vite' | |
import FullReload from 'vite-plugin-full-reload' | |
import RubyPlugin from 'vite-plugin-ruby' | |
export default defineConfig({ | |
plugins: [ | |
RubyPlugin(), | |
FullReload( | |
[ | |
'config/routes.rb', | |
'config/locales/**/*', | |
'app/views/**/*', | |
'app/components/**/*', | |
], | |
{ | |
delay: 250, | |
}, | |
), | |
], | |
server: { | |
hmr: { | |
port: 3036, | |
}, | |
}, | |
}) | |
JS | |
run 'npm install vite-plugin-full-reload -D' | |
# Install Tailwind CSS manually | |
run 'npm install tailwindcss postcss autoprefixer' | |
run 'npx tailwindcss init' | |
# Configure Tailwind CSS | |
remove_file 'tailwind.config.js' | |
create_file 'tailwind.config.js', <<-JS | |
module.exports = { | |
content: [ | |
'./app/frontend/**/*.js', | |
'./app/views/**/*' | |
], | |
theme: { | |
extend: {}, | |
}, | |
plugins: [], | |
} | |
JS | |
create_file 'postcss.config.js', <<-JS | |
module.exports = { | |
plugins: { | |
tailwindcss: {}, | |
autoprefixer: {}, | |
}, | |
} | |
JS | |
# Create the Tailwind CSS input file | |
create_file 'app/frontend/entrypoints/application.css', <<-CODE | |
@import "tailwindcss/base"; | |
@import "tailwindcss/components"; | |
@import "tailwindcss/utilities"; | |
CODE | |
gsub_file 'app/views/layouts/application.html.erb', | |
'<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>', | |
'<%= vite_stylesheet_tag "entrypoints/application", "data-turbo-track": "reload" %>' | |
gsub_file 'package.json', "\"private\": true,\n", '' | |
gsub_file 'package.json', "\"type\": \"module\",\n", '' | |
# Create BaseService file | |
create_file 'app/services/base_service.rb', <<-RUBY | |
class BaseService | |
module DefaultOutput | |
# save service call output to the `output` attribute | |
# to not define output variable in every service | |
def _call | |
self.output = super | |
end | |
end | |
# Essential mechanics | |
include(ServiceActor::Core) | |
include(ServiceActor::Configurable) | |
include(ServiceActor::Attributable) | |
include(ServiceActor::Playable) | |
# @!attribute output | |
# @return [Any] the result of the service call | |
output :output, allow_nil: true, default: -> {} | |
include(DefaultOutput) | |
# Extra concerns | |
include(ServiceActor::Checkable) | |
include(ServiceActor::Defaultable) | |
include(ServiceActor::Failable) | |
end | |
RUBY | |
run 'rm -rf ./test' | |
run 'rm -rf ./vendor' | |
run 'bundle exec rubocop -A' | |
after_bundle do | |
# Git initialization | |
git :init | |
git add: '.' | |
git commit: "-m 'Initial commit with GoodJob, Vite, Tailwind CSS (manual), Devise, ServiceActor, RSpec, and PostgreSQL setup'" | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment