diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..8668b5b --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,25 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/ruby +{ + "name": "Ruby", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/ruby:1-3-bookworm", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {} + } + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "ruby --version", + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/Gemfile.lock b/Gemfile.lock index 2644eb6..c1dd78c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - cssbundling-rails (1.2.0) + cssbundling-rails (1.3.0) railties (>= 6.0.0) GEM @@ -96,6 +96,8 @@ GEM mini_mime (1.0.3) minitest (5.14.4) nio4r (2.5.7) + nokogiri (1.15.2-aarch64-linux) + racc (~> 1.4) nokogiri (1.15.2-arm64-darwin) racc (~> 1.4) nokogiri (1.15.2-x86_64-darwin) @@ -167,6 +169,7 @@ GEM zeitwerk (2.4.2) PLATFORMS + aarch64-linux arm64-darwin-20 arm64-darwin-21 arm64-darwin-22 diff --git a/lib/cssbundling/version.rb b/lib/cssbundling/version.rb index 36f63c4..e7f28db 100644 --- a/lib/cssbundling/version.rb +++ b/lib/cssbundling/version.rb @@ -1,3 +1,3 @@ module Cssbundling - VERSION = "1.2.0" + VERSION = "1.3.0" end diff --git a/lib/install/Procfile.dev b/lib/install/Procfile.dev deleted file mode 100644 index 0fc822f..0000000 --- a/lib/install/Procfile.dev +++ /dev/null @@ -1,2 +0,0 @@ -web: unset PORT && env RUBY_DEBUG_OPEN=true bin/rails server -css: yarn build:css --watch diff --git a/lib/install/Procfile_for_bun.dev b/lib/install/Procfile_for_bun.dev new file mode 100644 index 0000000..7eaba23 --- /dev/null +++ b/lib/install/Procfile_for_bun.dev @@ -0,0 +1,2 @@ +web: env RUBY_DEBUG_OPEN=true bin/rails server +css: bun run build:css --watch diff --git a/lib/install/Procfile_for_node.dev b/lib/install/Procfile_for_node.dev new file mode 100644 index 0000000..34c1693 --- /dev/null +++ b/lib/install/Procfile_for_node.dev @@ -0,0 +1,2 @@ +web: env RUBY_DEBUG_OPEN=true bin/rails server +css: yarn build:css --watch diff --git a/lib/install/bootstrap/install.rb b/lib/install/bootstrap/install.rb index ac920f6..5966564 100644 --- a/lib/install/bootstrap/install.rb +++ b/lib/install/bootstrap/install.rb @@ -1,7 +1,10 @@ +require_relative "../helpers" +self.extend Helpers + say "Install Bootstrap with Bootstrap Icons, Popperjs/core and Autoprefixer" copy_file "#{__dir__}/application.bootstrap.scss", "app/assets/stylesheets/application.bootstrap.scss" -run "yarn add sass bootstrap bootstrap-icons @popperjs/core postcss postcss-cli autoprefixer nodemon" +run "#{bundler_cmd} add sass bootstrap bootstrap-icons @popperjs/core postcss postcss-cli autoprefixer nodemon" inject_into_file "config/initializers/assets.rb", after: /.*Rails.application.config.assets.paths.*\n/ do <<~RUBY @@ -16,32 +19,14 @@ say %(Add import * as bootstrap from "bootstrap" to your entry point JavaScript file), :red end -def add_npm_script(name, script, run_script=true) - case `npx -v`.to_f - when 7.1...8.0 - say "Add #{name} script" - run %(npm set-script #{name} "#{script}") - run %(yarn #{name}) if run_script - when (8.0..) - say "Add #{name} script" - run %(npm pkg set scripts.#{name}="#{script}") - run %(yarn #{name}) if run_script - else - say %(Add "scripts": { "#{name}": "#{script}" } to your package.json), :green - end -end - -add_npm_script("build:css:compile", "sass ./app/assets/stylesheets/application.bootstrap.scss:./app/assets/builds/application.css --no-source-map --load-path=node_modules") -add_npm_script("build:css:prefix", "postcss ./app/assets/builds/application.css --use=autoprefixer --output=./app/assets/builds/application.css") -add_npm_script("build:css", "yarn build:css:compile && yarn build:css:prefix") -add_npm_script("watch:css", "nodemon --watch ./app/assets/stylesheets/ --ext scss --exec \\\"yarn build:css\\\"", false) +add_package_json_script("build:css:compile", "sass ./app/assets/stylesheets/application.bootstrap.scss:./app/assets/builds/application.css --no-source-map --load-path=node_modules") +add_package_json_script("build:css:prefix", "postcss ./app/assets/builds/application.css --use=autoprefixer --output=./app/assets/builds/application.css") +add_package_json_script("build:css", "#{bundler_run_cmd} build:css:compile && #{bundler_run_cmd} build:css:prefix") +add_package_json_script("watch:css", "nodemon --watch ./app/assets/stylesheets/ --ext scss --exec \"#{bundler_run_cmd} build:css\"", false) gsub_file "Procfile.dev", "build:css --watch", "watch:css" -case `npx -v`.to_f -when (7.1..) - say "Add browserslist config" - run %(npm pkg set browserslist[]=defaults) -else - say %(Add "browserslist": ["defaults"] to your package.json), :green -end +package_json = JSON.parse(File.read("package.json")) +package_json["browserslist"] ||= {} +package_json["browserslist"] = ["defaults"] +File.write("package.json", JSON.pretty_generate(package_json)) diff --git a/lib/install/bulma/install.rb b/lib/install/bulma/install.rb index 96dc9be..c5276d0 100644 --- a/lib/install/bulma/install.rb +++ b/lib/install/bulma/install.rb @@ -1,18 +1,11 @@ +require_relative "../helpers" +self.extend Helpers + say "Install Bulma" copy_file "#{__dir__}/application.bulma.scss", "app/assets/stylesheets/application.bulma.scss" -run "yarn add sass bulma" +run "#{bundler_cmd} add sass bulma" say "Add build:css script" -build_script = "sass ./app/assets/stylesheets/application.bulma.scss:./app/assets/builds/application.css --no-source-map --load-path=node_modules" - -case `npx -v`.to_f -when 7.1...8.0 - run %(npm set-script build:css "#{build_script}") - run %(yarn build:css) -when (8.0..) - run %(npm pkg set scripts.build:css="#{build_script}") - run %(yarn build:css) -else - say %(Add "scripts": { "build:css": "#{build_script}" } to your package.json), :green -end +add_package_json_script "build:css", + "sass ./app/assets/stylesheets/application.bulma.scss:./app/assets/builds/application.css --no-source-map --load-path=node_modules" diff --git a/lib/install/dev b/lib/install/dev index 74ade16..a4e05fa 100755 --- a/lib/install/dev +++ b/lib/install/dev @@ -5,4 +5,7 @@ if ! gem list foreman -i --silent; then gem install foreman fi +# Default to port 3000 if not specified +export PORT="${PORT:-3000}" + exec foreman start -f Procfile.dev "$@" diff --git a/lib/install/helpers.rb b/lib/install/helpers.rb new file mode 100644 index 0000000..b8837f8 --- /dev/null +++ b/lib/install/helpers.rb @@ -0,0 +1,42 @@ +require 'json' + +module Helpers + def bundler_cmd + using_bun? ? "bun" : "yarn" + end + + def bundler_run_cmd + using_bun? ? "bun run" : "yarn" + end + + def using_bun? + File.exist?('bun.lockb') || (tool_exists?('bun') && !File.exist?('yarn.lock')) + end + + def tool_exists?(tool) + system "command -v #{tool} > /dev/null" + end + + def add_package_json_script(name, script, run_script=true) + if using_bun? + package_json = JSON.parse(File.read("package.json")) + package_json["scripts"] ||= {} + package_json["scripts"][name] = script + File.write("package.json", JSON.pretty_generate(package_json)) + run %(bun run #{name}) if run_script + else + case `npx -v`.to_f + when 7.1...8.0 + say "Add #{name} script" + run %(npm set-script #{name} "#{script}") + run %(yarn #{name}) if run_script + when (8.0..) + say "Add #{name} script" + run %(npm pkg set scripts.#{name}="#{script}") + run %(yarn #{name}) if run_script + else + say %(Add "scripts": { "#{name}": "#{script}" } to your package.json), :green + end + end + end +end diff --git a/lib/install/install.rb b/lib/install/install.rb index f02d3a0..321bbf7 100644 --- a/lib/install/install.rb +++ b/lib/install/install.rb @@ -1,3 +1,6 @@ +require_relative "helpers" +self.extend Helpers + say "Build into app/assets/builds" empty_directory "app/assets/builds" keep_file "app/assets/builds" @@ -41,10 +44,10 @@ end if Rails.root.join("Procfile.dev").exist? - append_to_file "Procfile.dev", "css: yarn build:css --watch\n" + append_to_file "Procfile.dev", "css: #{bundler_run_cmd} build:css --watch\n" else say "Add default Procfile.dev" - copy_file "#{__dir__}/Procfile.dev", "Procfile.dev" + copy_file "#{__dir__}/#{using_bun? ? "Procfile_for_bun" : "Procfile_for_node"}", "Procfile.dev" say "Ensure foreman is installed" run "gem install foreman" diff --git a/lib/install/postcss/install.rb b/lib/install/postcss/install.rb index fbad140..d9eb5bd 100644 --- a/lib/install/postcss/install.rb +++ b/lib/install/postcss/install.rb @@ -1,18 +1,11 @@ +require_relative "../helpers" +self.extend Helpers + say "Install PostCSS w/ nesting and autoprefixer" copy_file "#{__dir__}/postcss.config.js", "postcss.config.js" copy_file "#{__dir__}/application.postcss.css", "app/assets/stylesheets/application.postcss.css" -run "yarn add postcss postcss-cli postcss-nesting autoprefixer" +run "#{bundler_cmd} add postcss postcss-cli postcss-import postcss-nesting autoprefixer" say "Add build:css script" -build_script = "postcss ./app/assets/stylesheets/application.postcss.css -o ./app/assets/builds/application.css" - -case `npx -v`.to_f -when 7.1...8.0 - run %(npm set-script build:css "#{build_script}") - run %(yarn build:css) -when (8.0..) - run %(npm pkg set scripts.build:css="#{build_script}") - run %(yarn build:css) -else - say %(Add "scripts": { "build:css": "#{build_script}" } to your package.json), :green -end +add_package_json_script "build:css", + "postcss ./app/assets/stylesheets/application.postcss.css -o ./app/assets/builds/application.css" diff --git a/lib/install/postcss/postcss.config.js b/lib/install/postcss/postcss.config.js index aa18064..bc2a02e 100644 --- a/lib/install/postcss/postcss.config.js +++ b/lib/install/postcss/postcss.config.js @@ -1,5 +1,6 @@ module.exports = { plugins: [ + require('postcss-import'), require('postcss-nesting'), require('autoprefixer'), ], diff --git a/lib/install/sass/install.rb b/lib/install/sass/install.rb index dbdb4c5..692d60e 100644 --- a/lib/install/sass/install.rb +++ b/lib/install/sass/install.rb @@ -1,17 +1,10 @@ +require_relative "../helpers" +self.extend Helpers + say "Install Sass" copy_file "#{__dir__}/application.sass.scss", "app/assets/stylesheets/application.sass.scss" -run "yarn add sass" +run "#{bundler_cmd} add sass" say "Add build:css script" -build_script = "sass ./app/assets/stylesheets/application.sass.scss:./app/assets/builds/application.css --no-source-map --load-path=node_modules" - -case `npx -v`.to_f -when 7.1...8.0 - run %(npm set-script build:css "#{build_script}") - run %(yarn build:css) -when (8.0..) - run %(npm pkg set scripts.build:css="#{build_script}") - run %(yarn build:css) -else - say %(Add "scripts": { "build:css": "#{build_script}" } to your package.json), :green -end +add_package_json_script "build:css", + "sass ./app/assets/stylesheets/application.sass.scss:./app/assets/builds/application.css --no-source-map --load-path=node_modules" diff --git a/lib/install/tailwind/install.rb b/lib/install/tailwind/install.rb index bc7dfcc..7374ff4 100644 --- a/lib/install/tailwind/install.rb +++ b/lib/install/tailwind/install.rb @@ -1,18 +1,11 @@ +require_relative "../helpers" +self.extend Helpers + say "Install Tailwind (+PostCSS w/ autoprefixer)" copy_file "#{__dir__}/tailwind.config.js", "tailwind.config.js" copy_file "#{__dir__}/application.tailwind.css", "app/assets/stylesheets/application.tailwind.css" -run "yarn add tailwindcss@latest postcss@latest autoprefixer@latest" +run "#{bundler_cmd} add tailwindcss@latest postcss@latest autoprefixer@latest" say "Add build:css script" -build_script = "tailwindcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css --minify" - -case `npx -v`.to_f -when 7.1...8.0 - run %(npm set-script build:css "#{build_script}") - run %(yarn build:css) -when (8.0..) - run %(npm pkg set scripts.build:css="#{build_script}") - run %(yarn build:css) -else - say %(Add "scripts": { "build:css": "#{build_script}" } to your package.json), :green -end +add_package_json_script "build:css", + "tailwindcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css --minify" diff --git a/lib/tasks/cssbundling/build.rake b/lib/tasks/cssbundling/build.rake index 2c6a5ed..90033e2 100644 --- a/lib/tasks/cssbundling/build.rake +++ b/lib/tasks/cssbundling/build.rake @@ -1,10 +1,36 @@ namespace :css do + desc "Install JavaScript dependencies" + task :install do + command = install_command + unless system(command) + raise "cssbundling-rails: Command install failed, ensure #{command.split.first} is installed" + end + end + desc "Build your CSS bundle" - task :build do - unless system "yarn install && yarn build:css" - raise "cssbundling-rails: Command css:build failed, ensure yarn is installed and `yarn build:css` runs without errors or use SKIP_CSS_BUILD env variable" + build_task = task :build do + command = build_command + unless system(command) + raise "cssbundling-rails: Command build failed, ensure `#{command}` runs without errors" end end + build_task.prereqs << :install unless ENV["SKIP_YARN_INSTALL"] || ENV["SKIP_BUN_INSTALL"] +end + +def install_command + return "bun install" if File.exist?('bun.lockb') || (tool_exists?('bun') && !File.exist?('yarn.lock')) + return "yarn install" if File.exist?('yarn.lock') || tool_exists?('yarn') + raise "cssbundling-rails: No suitable tool found for installing JavaScript dependencies" +end + +def build_command + return "bun run build:css" if File.exist?('bun.lockb') || (tool_exists?('bun') && !File.exist?('yarn.lock')) + return "yarn build:css" if File.exist?('yarn.lock') || tool_exists?('yarn') + raise "cssbundling-rails: No suitable tool found for building CSS" +end + +def tool_exists?(tool) + system "command -v #{tool} > /dev/null" end unless ENV["SKIP_CSS_BUILD"]