Replace webpack with importmapped Hotwire as default js (#42999)

* Turbolinks is being replaced with Hotwire

* Make --webpack opt-in

* Don't use specific webpacker installers any more in preparation for next Webpacker

* Update railties/lib/rails/app_updater.rb

Co-authored-by: Alex Ghiculescu <alex@tanda.co>

* Trailing whitespace

* Convert to Turbo data attribute for tracking

* Default is no webpack, no hotwire

* Swap out turbolinks references for hotwire

* Drop explicit return

* Only generate package.json if using webpack

* Only create package.json in webpack mode

* Only create app/javascript in webpack mode

* Generate correct style/js links based on js mode

* Fix tests from changed output format

Not sure why these are showing up in this PR, though.

* Rubocopping

* Stick with webpack for the test app for now

* Adjust tests

* Replace minitest-reporters with minitest-ci (#43016)

minitest-reporters is used to create junit xml reports on CI.

But when it loads before rails minitest plugin makes
`Rails::TestUnitReporter` not being added as a reporter.

minitest-ci is now only loaded at ci and does not interferes with
rails minitest plugins. And keeps junit reports workings

* Too heavy handed to actually run bundle

Just like we don't auto-migrate

* Pin js frameworks in importmap

Instead of having importmap preconfigure it.

* Match updated app/javascript path

* No need for the explaining comment

* Fixes test cases for replace webpack with importmapped Hotwire as default js (#42999)

* Fix rubocop issues

* Fix more railities test cases

* Fix plugin generator railties shared test cases

* Fix Action Text install generator asset pipeline spec

* They're modules, not files

* Let dev use the latest release as well

So we don't have to replace unexisting dev releases with latest release

* Make Webpack responsible for generating all the JS files it needs

Webpacker 6 has already moved from app/javascript to app/packs.

* Don't add rails/ujs by default any longer

All the ajax/form functionality has been superseded by Turbo. The rest lives in a weird inbetween land we need to address through other means.

* Use new importmap location

* Switch to using turbo-rails and stimulus-rails directly

The hotwire-rails gem does not offer enough value for its indirection

* Use latest Webpacker

* Prevent version resolution requests from getting swallowed

* Use ESM syntax for imports

* Move management of yarn, package.json, etc to Webpacker 6

* Update for Webpacker 6

* Move bin/setup addition to Webpacker as well

* Remove dead tests

* Bump to Webpacker 6.0.0.rc.2

* No longer relevant given the new default is no webpacker

* Rely on Webpacker 6

* No longer relevant

* No longer relevant

* Make cable channel generator work for both webpacker and importmap setups

* Fix tests

* For tests testing importmap way

* Use Webpacker 6 dummy

* RuboCopping

* One more bump to fix webpack-dev-server

* Another bump. Hopefully the last one!

* Also enough to not want turbo tracking on

* Fix tests

* Latest

* Fix tests

* Fix more tests

* Fix tests

Co-authored-by: Alex Ghiculescu <alex@tanda.co>
Co-authored-by: André Luis Leal Cardoso Junior <andrehjr@gmail.com>
Co-authored-by: Abhay Nikam <nikam.abhay1@gmail.com>
Co-authored-by: Guillermo Iguaran <guilleiguaran@gmail.com>
This commit is contained in:
David Heinemeier Hansson 2021-08-26 10:39:36 +02:00 committed by GitHub
parent 39f15e163d
commit af7428c4ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 333 additions and 1487 deletions

View File

@ -14,8 +14,10 @@ gem "selenium-webdriver", ">= 4.0.0.alpha7"
gem "rack-cache", "~> 1.2"
gem "sass-rails"
gem "turbolinks", "~> 5"
gem "webpacker", "~> 5.0", require: ENV["SKIP_REQUIRE_WEBPACKER"] != "true"
gem "stimulus-rails"
gem "turbo-rails"
gem "webpacker", "~> 6.0.0.rc.5", require: ENV["SKIP_REQUIRE_WEBPACKER"] != "true"
gem "importmap-rails"
# require: false so bcrypt is loaded only when has_secure_password is used.
# This is to avoid Active Model (and by extension the entire framework)
# being dependent on a binary library.
@ -111,8 +113,8 @@ instance_eval File.read local_gemfile if File.exist? local_gemfile
group :test do
gem "minitest-bisect"
gem "minitest-ci", require: false
gem "minitest-retry"
gem "minitest-reporters"
platforms :mri do
gem "stackprof"

View File

@ -110,7 +110,6 @@ GEM
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
amq-protocol (2.3.2)
ansi (1.5.0)
ast (2.4.2)
aws-eventstream (1.1.1)
aws-partitions (1.469.0)
@ -287,6 +286,8 @@ GEM
image_processing (1.12.1)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
importmap-rails (0.3.4)
rails (>= 6.0.0)
jmespath (1.4.0)
json (2.5.1)
jwt (2.2.3)
@ -312,11 +313,8 @@ GEM
minitest-bisect (1.5.1)
minitest-server (~> 1.0)
path_expander (~> 1.1)
minitest-reporters (1.4.3)
ansi
builder
minitest (>= 5.0)
ruby-progressbar
minitest-ci (3.4.0)
minitest (>= 5.0.6)
minitest-retry (0.2.2)
minitest (>= 5.0)
minitest-server (1.0.6)
@ -479,6 +477,8 @@ GEM
sprockets (>= 3.0.0)
sqlite3 (1.4.2)
stackprof (0.2.17)
stimulus-rails (0.3.9)
rails (>= 6.0.0)
sucker_punch (3.0.1)
concurrent-ruby (~> 1.0)
terser (1.1.4)
@ -490,9 +490,8 @@ GEM
thor (1.1.0)
tilt (2.0.10)
trailblazer-option (0.1.1)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
turbo-rails (0.7.4)
rails (>= 6.0.0)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
uber (0.1.0)
@ -512,7 +511,7 @@ GEM
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
webpacker (5.4.0)
webpacker (6.0.0.rc.5)
activesupport (>= 5.2)
rack-proxy (>= 0.6.1)
railties (>= 5.2)
@ -553,12 +552,13 @@ DEPENDENCIES
google-cloud-storage (~> 1.11)
hiredis
image_processing (~> 1.2)
importmap-rails
json (>= 2.0.0)
kindlerb (~> 1.2.0)
libxml-ruby
listen (~> 3.3)
minitest-bisect
minitest-reporters
minitest-ci
minitest-retry
mysql2 (~> 0.5)!
nokogiri (>= 1.8.1, != 1.11.0)
@ -592,17 +592,18 @@ DEPENDENCIES
sprockets-export
sqlite3 (~> 1.4)
stackprof
stimulus-rails
sucker_punch
terser (>= 1.1.4)
turbolinks (~> 5)
turbo-rails
tzinfo-data
w3c_validators (~> 1.3.6)
wdm (>= 0.1.0)
webdrivers
webmock
webpacker (~> 5.0)
webpacker (~> 6.0.0.rc.5)
webrick
websocket-client-simple!
BUNDLED WITH
2.2.19
2.2.25

View File

@ -8,14 +8,15 @@ module ActionCable
#
# <head>
# <%= action_cable_meta_tag %>
# <%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload' %>
# <%= javascript_include_tag 'application', 'data-turbo-track' => 'reload' %>
# </head>
#
# This is then used by Action Cable to determine the URL of your WebSocket server.
# Your JavaScript can then connect to the server without needing to specify the
# URL directly:
#
# window.Cable = require("@rails/actioncable")
# import Cable from "@rails/actioncable"
# window.Cable = Cable
# window.App = {}
# App.cable = Cable.createConsumer()
#

View File

@ -10,4 +10,4 @@ Example:
creates a Chat channel class, test and JavaScript asset:
Channel: app/channels/chat_channel.rb
Test: test/channels/chat_channel_test.rb
Assets: app/javascript/channels/chat_channel.js
Assets: $JAVASCRIPT_PATH/channels/chat_channel.js

View File

@ -18,11 +18,23 @@ module Rails
if options[:assets]
if behavior == :invoke
template "javascript/index.js", "app/javascript/channels/index.js"
template "javascript/consumer.js", "app/javascript/channels/consumer.js"
if defined?(Webpacker::Engine)
template "javascript/index.js", "#{Webpacker.config.source_path}/channels/index.js"
template "javascript/consumer.js", "#{Webpacker.config.source_path}/channels/consumer.js"
else
template "javascript/consumer.js", "app/javascript/channels/consumer.js"
end
end
js_template "javascript/channel", File.join("app/javascript/channels", class_path, "#{file_name}_channel")
if defined?(Webpacker::Engine)
js_template "javascript/channel", File.join(Webpacker.config.source_path, "channels", class_path, "#{file_name}_channel")
else
channel_js_path = File.join("app/javascript/channels", class_path, "#{file_name}_channel")
js_template "javascript/channel", channel_js_path
gsub_file "#{channel_js_path}.js", /\.\/consumer/, "channels/consumer"
append_to_file "app/javascript/application.js", %(\nimport "channels/#{file_name}_channel"\n)
end
end
generate_application_cable_files

View File

@ -10,45 +10,52 @@ module ActionText
def install_javascript_dependencies
if defined?(Webpacker::Engine)
rails_command "app:binstub:yarn", inline: true
say "Installing JavaScript dependencies", :green
yarn_command "add #{js_dependencies.map { |name, version| "#{name}@#{version}" }.join(" ")}", capture: true
yarn_command "add #{js_dependencies.map { |name, version| "#{name}@#{version}" }.join(" ")}"
end
end
def append_javascript_dependencies
if defined?(Webpacker::Engine)
in_root do
if (app_javascript_pack_path = Pathname.new("app/javascript/packs/application.js")).exist?
js_dependencies.each_key do |dependency|
line = %[require("#{dependency}")]
if (app_javascript_pack_path = Pathname.new("#{Webpacker.config.source_entry_path}/application.js")).exist?
js_dependencies.each_key do |dependency|
line = %[import "#{dependency}"]
unless app_javascript_pack_path.read.include? line
say "Adding #{dependency} to #{app_javascript_pack_path}", :green
append_to_file app_javascript_pack_path, "\n#{line}"
end
unless app_javascript_pack_path.read.include? line
say "Adding #{dependency} to #{app_javascript_pack_path}", :green
append_to_file app_javascript_pack_path, "\n#{line}"
end
else
say <<~WARNING, :red
WARNING: Action Text can't locate your JavaScript bundle to add its package dependencies.
Add these lines to any bundles:
require("trix")
require("@rails/actiontext")
Alternatively, install and setup the webpacker gem then rerun `bin/rails action_text:install`
to have these dependencies added automatically.
WARNING
end
else
say <<~WARNING, :red
WARNING: Action Text can't locate your JavaScript bundle to add its package dependencies.
Add these lines to any bundles:
import "trix"
import "@rails/actiontext"
Alternatively, install and setup the webpacker gem then rerun `bin/rails action_text:install`
to have these dependencies added automatically.
WARNING
end
else
if (application_javascript_path = Rails.root.join("app/assets/javascripts/application.js")).exist?
if (application_javascript_path = Rails.root.join("app/javascript/application.js")).exist?
insert_into_file application_javascript_path.to_s, %(\nimport "trix"\nimport "@rails/actiontext")
else
say <<~INSTRUCTIONS, :green
You must import the @rails/actiontext.js and trix.js JavaScript files in your application entrypoint.
You must import the @rails/actiontext and trix JavaScript modules in your application entrypoint.
INSTRUCTIONS
end
if (importmap_path = Rails.root.join("config/importmap.rb")).exist?
insert_into_file \
importmap_path.to_s,
%( pin "trix"\n pin "@rails/actiontext", to: "actiontext.js"\n\n),
after: "Rails.application.config.importmap.draw do\n"
else
say <<~INSTRUCTIONS, :green
You must add @rails/actiontext and trix to your importmap to reference them via ESM.
INSTRUCTIONS
end
end
@ -66,9 +73,8 @@ module ActionText
def enable_image_processing_gem
if (gemfile_path = Rails.root.join("Gemfile")).exist?
say "Ensure image_processing gem has been enabled so image uploads will work"
say "Ensure image_processing gem has been enabled so image uploads will work (remember to bundle!)"
uncomment_lines gemfile_path, /gem "image_processing"/
run "bundle install"
end
end

View File

@ -55,8 +55,8 @@ After the installation is complete, a Rails app using Webpacker should have the
```js
// application.js
require("trix")
require("@rails/actiontext")
import "trix"
import "@rails/actiontext"
```
2. The `trix` stylesheet should be imported into `actiontext.scss`.

View File

@ -317,12 +317,12 @@ familiar `javascript_include_tag` and `stylesheet_link_tag`:
```
If using the turbolinks gem, which is included by default in Rails, then
include the 'data-turbolinks-track' option which causes turbolinks to check if
include the 'data-turbo-track' option which causes Turbo to check if
an asset has been updated and if so loads it into the page:
```erb
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => "reload" %>
<%= javascript_include_tag "application", "data-turbolinks-track" => "reload" %>
<%= stylesheet_link_tag "application", media: "all", "data-turbo-track" => "reload" %>
<%= javascript_include_tag "application", "data-turbo-track" => "reload" %>
```
In regular views you can access images in the `app/assets/images` directory

View File

@ -206,7 +206,6 @@ of the files and folders that Rails creates by default:
|Gemfile<br>Gemfile.lock|These files allow you to specify what gem dependencies are needed for your Rails application. These files are used by the Bundler gem. For more information about Bundler, see the [Bundler website](https://bundler.io).|
|lib/|Extended modules for your application.|
|log/|Application log files.|
|package.json|This file allows you to specify what npm dependencies are needed for your Rails application. This file is used by Yarn. For more information about Yarn, see the [Yarn website](https://yarnpkg.com/lang/en/).|
|public/|Contains static files and compiled assets. When your app is running, this directory will be exposed as-is.|
|Rakefile|This file locates and loads tasks that can be run from the command line. The task definitions are defined throughout the components of Rails. Rather than changing `Rakefile`, you should add your own tasks by adding files to the `lib/tasks` directory of your application.|
|README.md|This is a brief instruction manual for your application. You should edit this file to tell others what your application does, how to set it up, and so on.|

View File

@ -44,7 +44,7 @@ Repeat this process until you reach your target Rails version.
To move between versions:
1. Change the Rails version number in the `Gemfile` and run `bundle update`.
2. Change the versions for Rails JavaScript packages in `package.json` and run `yarn install`.
2. Change the versions for Rails JavaScript packages in `package.json` and run `yarn install`, if running on Webpacker.
3. Run the [Update task](#the-update-task).
4. Run your tests.

View File

@ -21,13 +21,13 @@ module Rails
private
def generator_options
options = { api: !!Rails.application.config.api_only, update: true }
options[:skip_javascript] = !File.exist?(Rails.root.join("bin", "yarn"))
options[:skip_active_record] = !defined?(ActiveRecord::Railtie)
options[:skip_active_storage] = !defined?(ActiveStorage::Engine) || !defined?(ActiveRecord::Railtie)
options[:skip_action_mailer] = !defined?(ActionMailer::Railtie)
options[:skip_action_cable] = !defined?(ActionCable::Engine)
options[:skip_sprockets] = !defined?(Sprockets::Railtie)
options[:skip_bootsnap] = !defined?(Bootsnap)
options[:webpack] = File.exist?(Rails.root.join("config", "webpacker.yml"))
options[:updating] = true
options
end

View File

@ -64,8 +64,8 @@ module Rails
class_option :skip_javascript, type: :boolean, aliases: "-J", default: name == "plugin",
desc: "Skip JavaScript files"
class_option :skip_turbolinks, type: :boolean, default: false,
desc: "Skip turbolinks gem"
class_option :skip_hotwire, type: :boolean, default: false,
desc: "Skip Hotwire integration"
class_option :skip_jbuilder, type: :boolean, default: false,
desc: "Skip jbuilder gem"
@ -296,9 +296,7 @@ module Rails
# * This makes it a prerelease. That's bad, but we haven't come up with
# a better solution at the moment.
def npm_version
# TODO: support `options.dev?`
if options.edge? || options.main?
if options.edge? || options.main? || options.dev?
# TODO: ideally this would read from Github
# https://github.com/rails/rails/blob/main/actioncable/app/assets/javascripts/action_cable.js
# https://github.com/rails/rails/blob/main/activestorage/app/assets/javascripts/activestorage.js
@ -309,16 +307,6 @@ module Rails
end
end
def turbolinks_npm_version
# since Turbolinks is deprecated, let's just always point to main.
# expect this to be replaced with Hotwire at some point soon.
if options.main? || options.edge?
"turbolinks/turbolinks#master"
else
"^5.2.0"
end
end
def assets_gemfile_entry
return [] if options[:skip_sprockets]
@ -326,9 +314,11 @@ module Rails
end
def webpacker_gemfile_entry
return [] if options[:skip_javascript]
GemfileEntry.version "webpacker", "~> 5.0", "Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker"
if options[:webpack]
GemfileEntry.version "webpacker", "~> 6.0.0.rc.5", "Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker"
else
[]
end
end
def jbuilder_gemfile_entry
@ -338,11 +328,21 @@ module Rails
end
def javascript_gemfile_entry
if options[:skip_javascript] || options[:skip_turbolinks]
importmap_rails_entry =
GemfileEntry.version("importmap-rails", ">= 0.3.4", "Manage modern JavaScript using ESM without transpiling or bundling")
turbo_rails_entry =
GemfileEntry.version("turbo-rails", ">= 0.7.4", "Hotwire's SPA-like page accelerator. Read more: https://turbo.hotwired.dev")
stimulus_rails_entry =
GemfileEntry.version("stimulus-rails", ">= 0.3.9", "Hotwire's modest JavaScript framework for the HTML you already have. Read more: https://stimulus.hotwired.dev")
if options[:skip_javascript]
[]
elsif options[:skip_hotwire]
[ importmap_rails_entry ]
else
[ GemfileEntry.version("turbolinks", "~> 5",
"Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks") ]
[ importmap_rails_entry, turbo_rails_entry, stimulus_rails_entry ]
end
end
@ -393,7 +393,15 @@ module Rails
end
def webpack_install?
!(options[:skip_javascript] || options[:skip_webpack_install])
options[:webpack]
end
def importmap_install?
!(options[:skip_javascript] || options[:webpack])
end
def hotwire_install?
!(options[:skip_javascript] || options[:skip_hotwire])
end
def depends_on_system_test?
@ -420,9 +428,34 @@ module Rails
end
rails_command "webpacker:install"
if options[:webpack] && options[:webpack] != "webpack"
rails_command "webpacker:install:#{options[:webpack]}"
end
def run_importmap
return unless importmap_install?
unless bundle_install?
say <<~EXPLAIN
Skipping `rails importmap:install` because `bundle install` was skipped.
To complete setup, you must run `bundle install` followed by `rails importmap:install`.
EXPLAIN
return
end
rails_command "importmap:install"
end
def run_hotwire
return unless hotwire_install?
unless bundle_install?
say <<~EXPLAIN
Skipping `rails turbo:install stimulus:install` because `bundle install` was skipped.
To complete setup, you must run `bundle install` followed by `rails turbo:install stimulus:install`.
EXPLAIN
return
end
rails_command "turbo:install stimulus:install"
end
def generate_bundler_binstub

View File

@ -79,10 +79,6 @@ module Rails
end
end
def package_json
template "package.json"
end
def app
directory "app"
@ -97,22 +93,12 @@ module Rails
"#{shebang}\n" + content
end
chmod "bin", 0755 & ~File.umask, verbose: false
remove_file "bin/yarn" if options[:skip_javascript]
end
def bin_when_updating
bin
end
def yarn_when_updating
template "bin/yarn", force: true do |content|
"#{shebang}\n" + content
end
chmod "bin", 0755 & ~File.umask, verbose: false
end
def config
empty_directory "config"
@ -278,8 +264,6 @@ module Rails
class AppGenerator < AppBase
# :stopdoc:
WEBPACKS = %w( react vue angular elm stimulus )
add_shared_options_for "application"
# Add rails command options
@ -295,11 +279,8 @@ module Rails
class_option :skip_bundle, type: :boolean, aliases: "-B", default: false,
desc: "Don't run bundle install"
class_option :webpack, type: :string, aliases: "--webpacker", default: nil,
desc: "Preconfigure Webpack with a particular framework (options: #{WEBPACKS.join(", ")})"
class_option :skip_webpack_install, type: :boolean, default: false,
desc: "Don't run Webpack install"
class_option :webpack, type: :boolean, aliases: "--webpacker", default: false,
desc: "Preconfigure Webpack"
def initialize(*args)
super
@ -308,7 +289,7 @@ module Rails
raise Error, "Invalid value for --database option. Supported preconfigurations are: #{DATABASES.join(", ")}."
end
# Force sprockets and yarn to be skipped when generating API only apps.
# Force sprockets and JavaScript to be skipped when generating API only apps.
# Can't modify options hash as it's frozen by default.
if options[:api]
self.options = options.merge(skip_sprockets: true, skip_javascript: true).freeze
@ -327,10 +308,8 @@ module Rails
skip_javascript: true,
skip_jbuilder: true,
skip_system_test: true,
skip_webpack_install: true,
skip_turbolinks: true).tap do |option|
skip_hotwire: true).tap do |option|
if option[:webpack]
option[:skip_webpack_install] = false
option[:skip_javascript] = false
end
end.freeze
@ -355,7 +334,6 @@ module Rails
build(:gemfile)
build(:version_control)
build(:package_json) unless options[:skip_javascript]
end
def create_app_files
@ -371,11 +349,6 @@ module Rails
end
remove_task :update_bin_files
def update_bin_yarn
build(:yarn_when_updating)
end
remove_task :update_bin_yarn
def update_active_storage
unless skip_active_storage?
rails_command "active_storage:update", inline: true
@ -487,19 +460,6 @@ module Rails
end
end
def delete_js_folder_skipping_javascript
if options[:skip_javascript] && !options[:minimal]
remove_dir "app/javascript"
end
end
def delete_js_packs_when_minimal_skipping_webpack
if options[:minimal] && options[:skip_webpack_install]
remove_dir "app/javascript/packs"
keep_file "app/javascript"
end
end
def delete_assets_initializer_skipping_sprockets
if options[:skip_sprockets]
remove_file "config/initializers/assets.rb"
@ -564,6 +524,8 @@ module Rails
public_task :apply_rails_template, :run_bundle
public_task :generate_bundler_binstub
public_task :run_webpack
public_task :run_importmap
public_task :run_hotwire
def run_after_bundle_callbacks
@after_bundle_callbacks.each(&:call)

View File

@ -1,6 +0,0 @@
// Action Cable provides the framework to deal with WebSockets in Rails.
// You can generate new channels where WebSocket features live using the `bin/rails generate channel` command.
import { createConsumer } from "@rails/actioncable"
export default createConsumer()

View File

@ -1,5 +0,0 @@
// Load all the channels within this directory and all subdirectories.
// Channel files must be named *_channel.js.
const channels = require.context('.', true, /_channel\.js$/)
channels.keys().forEach(channels)

View File

@ -1,23 +0,0 @@
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
import Rails from "@rails/ujs"
<%- unless options[:skip_turbolinks] -%>
import Turbolinks from "turbolinks"
<%- end -%>
<%- unless skip_active_storage? -%>
import * as ActiveStorage from "@rails/activestorage"
<%- end -%>
<%- unless options[:skip_action_cable] -%>
import "channels"
<%- end -%>
Rails.start()
<%- unless options[:skip_turbolinks] -%>
Turbolinks.start()
<%- end -%>
<%- unless skip_active_storage? -%>
ActiveStorage.start()
<%- end -%>

View File

@ -5,16 +5,10 @@
<%%= csrf_meta_tags %>
<%%= csp_meta_tag %>
<%- if options[:skip_javascript] -%>
<%- if options[:skip_hotwire] || options[:skip_javascript] -%>
<%%= stylesheet_link_tag "application" %>
<%- else -%>
<%- unless options[:skip_turbolinks] -%>
<%%= stylesheet_link_tag "application", "data-turbolinks-track": "reload" %>
<%%= javascript_pack_tag "application", "data-turbolinks-track": "reload" %>
<%- else -%>
<%%= stylesheet_link_tag "application" %>
<%%= javascript_pack_tag "application" %>
<%- end -%>
<%%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<%- end -%>
</head>

View File

@ -15,11 +15,6 @@ FileUtils.chdir APP_ROOT do
puts "== Installing dependencies =="
system! "gem install bundler --conservative"
system("bundle check") || system!("bundle install")
<% unless options.skip_javascript? -%>
# Install JavaScript dependencies
system! "bin/yarn"
<% end -%>
<% unless options.skip_active_record? -%>
# puts "\n== Copying sample files =="

View File

@ -1,16 +0,0 @@
APP_ROOT = File.expand_path("..", __dir__)
Dir.chdir(APP_ROOT) do
yarn = ENV["PATH"].split(File::PATH_SEPARATOR).
select { |dir| File.expand_path(dir) != __dir__ }.
product(["yarn", "yarnpkg", "yarn.cmd", "yarn.ps1"]).
map { |dir, file| File.expand_path(file, dir) }.
find { |file| File.executable?(file) }
if yarn
exec yarn, *ARGV
else
$stderr.puts "Yarn executable was not detected in the system."
$stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
exit 1
end
end

View File

@ -5,10 +5,6 @@ Rails.application.config.assets.version = "1.0"
# Add additional assets to the asset load path.
# Rails.application.config.assets.paths << Emoji.images_path
<%- unless options[:skip_javascript] -%>
# Add Yarn node_modules folder to the asset load path.
Rails.application.config.assets.paths << Rails.root.join("node_modules")
<%- end -%>
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in the app/assets

View File

@ -11,7 +11,7 @@
# policy.object_src :none
# policy.script_src :self, :https
# policy.style_src :self, :https
<%- unless options[:skip_javascript] -%>
<%- if options[:webpack] -%>
# # If you are using webpack-dev-server then specify webpack-dev-server host
# policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?
<%- end -%>

View File

@ -5,7 +5,7 @@
db/schema.rb linguist-generated
<% end -%>
<% unless options[:skip_javascript] -%>
<% if options[:webpack] -%>
# Mark the yarn lockfile as having been generated.
yarn.lock linguist-generated
<% end -%>

View File

@ -1,11 +0,0 @@
{
"name": "<%= app_name.underscore.dasherize %>",
"private": true,
"dependencies": {
"@rails/ujs": "<%= npm_version %>"<% unless options[:skip_turbolinks] %>,
"turbolinks": "<%= turbolinks_npm_version %>"<% end -%><% unless skip_active_storage? %>,
"@rails/activestorage": "<%= npm_version %>"<% end -%><% unless options[:skip_action_cable] %>,
"@rails/actioncable": "<%= npm_version %>"<% end %>
},
"version": "0.1.0"
}

View File

@ -121,8 +121,7 @@ module Rails
opts[:force] = force
opts[:skip_bundle] = true
opts[:skip_git] = true
opts[:skip_turbolinks] = true
opts[:skip_webpack_install] = true
opts[:skip_hotwire] = true
opts[:dummy_app] = true
invoke Rails::Generators::AppGenerator,
@ -148,10 +147,6 @@ module Rails
end
end
def test_dummy_webpacker_assets
template "rails/javascripts.js", "#{dummy_path}/app/javascript/packs/application.js", force: true
end
def test_dummy_sprocket_assets
template "rails/stylesheets.css", "#{dummy_path}/app/assets/stylesheets/application.css", force: true
template "rails/dummy_manifest.js", "#{dummy_path}/app/assets/config/manifest.js", force: true

View File

@ -6,9 +6,6 @@
<%%= csp_meta_tag %>
<%%= stylesheet_link_tag "<%= namespaced_name %>/application", media: "all" %>
<%- unless options[:skip_javascript] -%>
<%%= javascript_include_tag "<%= namespaced_name %>/application" %>
<%- end -%>
</head>
<body>

View File

@ -9,7 +9,7 @@
/<%= dummy_path %>/db/*.sqlite3-*
<% end -%>
/<%= dummy_path %>/log/*.log
<% unless options[:skip_javascript] -%>
<% if options[:webpack] -%>
/<%= dummy_path %>/node_modules/
/<%= dummy_path %>/yarn-error.log
<% end -%>

View File

@ -68,7 +68,6 @@ module Rails
capture(:stdout) do
args += ["--skip-bundle"] unless args.include? "--dev"
args |= ["--skip-bootsnap"] unless args.include? "--no-skip-bootsnap"
args |= ["--skip-webpack-install"] unless args.include? "--no-skip-webpack-install"
generator_class.start(args, config.reverse_merge(destination_root: destination_root))
end

View File

@ -59,10 +59,4 @@ namespace :app do
Rails::AppUpdater.invoke_from_app_generator :display_upgrade_guide_info
end
end
namespace :binstub do
task :yarn do
Rails::AppUpdater.invoke_from_app_generator :update_bin_yarn
end
end
end

View File

@ -51,10 +51,6 @@ module ApplicationTests
assert_equal(<<~OUTPUT, output)
== Installing dependencies ==
The Gemfile's dependencies are satisfied
yarn install
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.00s.
== Preparing database ==
Created database 'app_development'

View File

@ -25,7 +25,6 @@ module ApplicationTests
boot!
assert_equal [
"Webpacker::DevServerProxy",
"ActionDispatch::HostAuthorization",
"Rack::Sendfile",
"ActionDispatch::Static",
@ -60,7 +59,6 @@ module ApplicationTests
boot!
assert_equal [
"Webpacker::DevServerProxy",
"ActionDispatch::HostAuthorization",
"Rack::Sendfile",
"ActionDispatch::Static",
@ -95,7 +93,6 @@ module ApplicationTests
boot!
assert_equal [
"Webpacker::DevServerProxy",
"ActionDispatch::HostAuthorization",
"Rack::Sendfile",
"ActionDispatch::Static",
@ -179,7 +176,7 @@ module ApplicationTests
add_to_config "config.ssl_options = { redirect: { host: 'example.com' } }"
boot!
assert_equal [{ redirect: { host: "example.com" }, ssl_default_redirect_status: 308 }], Rails.application.middleware[2].args
assert_equal [{ redirect: { host: "example.com" }, ssl_default_redirect_status: 308 }], Rails.application.middleware[1].args
end
test "removing Active Record omits its middleware" do
@ -263,32 +260,32 @@ module ApplicationTests
test "insert middleware after" do
add_to_config "config.middleware.insert_after Rack::Sendfile, Rack::Config"
boot!
assert_equal "Rack::Config", middleware.fourth
assert_equal "Rack::Config", middleware.third
end
test "unshift middleware" do
add_to_config "config.middleware.unshift Rack::Config"
boot!
assert_equal "Rack::Config", middleware.second
assert_equal "Rack::Config", middleware.first
end
test "Rails.cache does not respond to middleware" do
add_to_config "config.cache_store = :memory_store, { timeout: 10 }"
boot!
assert_equal "ActionDispatch::MiddlewareStack::FakeRuntime", middleware[5]
assert_equal "ActionDispatch::MiddlewareStack::FakeRuntime", middleware[4]
assert_instance_of ActiveSupport::Cache::MemoryStore, Rails.cache
end
test "Rails.cache does respond to middleware" do
boot!
assert_equal "ActiveSupport::Cache::Strategy::LocalCache", middleware[5]
assert_equal "ActionDispatch::MiddlewareStack::FakeRuntime", middleware[6]
assert_equal "ActiveSupport::Cache::Strategy::LocalCache", middleware[4]
assert_equal "ActionDispatch::MiddlewareStack::FakeRuntime", middleware[5]
end
test "insert middleware before" do
add_to_config "config.middleware.insert_before Rack::Sendfile, Rack::Config"
boot!
assert_equal "Rack::Config", middleware.third
assert_equal "Rack::Config", middleware.second
end
test "can't change middleware after it's built" do

View File

@ -182,7 +182,7 @@ module ApplicationTests
end
def test_code_statistics_sanity
assert_match "Code LOC: 73 Test LOC: 3 Code to Test Ratio: 1:0.0",
assert_match "Code LOC: 61 Test LOC: 3 Code to Test Ratio: 1:0.0",
rails("stats")
end
@ -310,22 +310,6 @@ module ApplicationTests
end
end
test "app:binstub:yarn generates bin/yarn" do
yarn_binstub = File.join(app_path, "bin/yarn")
rails "app:binstub:yarn"
assert_path_exists yarn_binstub
assert_match %r/\A#!/, File.read(yarn_binstub)
end
test "app:binstub:yarn overwrites existing bin/yarn" do
yarn_binstub = File.join(app_path, "bin/yarn")
File.write(yarn_binstub, "existing")
rails "app:binstub:yarn"
assert_match %r/\A#!/, File.read(yarn_binstub)
end
def test_template_load_initializers
app_file "config/initializers/dummy.rb", "puts 'Hello, World!'"
app_file "template.rb", ""

View File

@ -502,7 +502,7 @@ module ApplicationTests
create_test_file :models, "post", pass: false, print: false
output = run_test_command("test/models/post_test.rb")
expect = %r{Running:\n\nF\n\nFailure:\nPostTest#test_truth \[[^\]]+test/models/post_test.rb:6\]:\nwups!\n\nrails test test/models/post_test.rb:4\n\n\n\n}
expect = /Failure.*PostTest#test_truth.*wups!/m
assert_match expect, output
end
@ -510,7 +510,7 @@ module ApplicationTests
create_test_file :models, "post", pass: false
output = run_test_command("test/models/post_test.rb")
assert_match %r{Finished in.*\n1 runs, 1 assertions}, output
assert_match(/Finished in.*1 runs, 1 assertions/m, output)
end
def test_fail_fast
@ -566,7 +566,7 @@ module ApplicationTests
output = run_test_command(file_name)
assert_match %r{Finished in.*\n2 runs, 2 assertions}, output
assert_match(/Finished in.*2 runs, 2 assertions/m, output)
assert_match %r{Running \d+ tests in parallel using \d+ processes}, output
assert_no_match "create_table(:users)", output
end
@ -645,7 +645,7 @@ module ApplicationTests
output = run_test_command(file_name)
assert_match %r{Finished in.*\n2 runs, 2 assertions}, output
assert_match(/Finished in.*2 runs, 2 assertions/m, output)
assert_no_match "create_table(:users)", output
end

View File

@ -3,7 +3,21 @@
require "generators/generators_test_helper"
require "generators/action_text/install/install_generator"
module Webpacker; end
module Webpacker
extend self
def config
Class.new do
def source_path
"app/packs"
end
def source_entry_path
"app/packs/entrypoints"
end
end.new
end
end
class ActionText::Generators::InstallGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
@ -19,12 +33,6 @@ class ActionText::Generators::InstallGeneratorTest < Rails::Generators::TestCase
run_under_asset_pipeline
end
test "creates bin/yarn" do
run_generator_instance
assert_file "bin/yarn"
end
test "installs JavaScript dependencies" do
run_generator_instance
yarn_commands = @yarn_commands.join("\n")
@ -41,14 +49,16 @@ class ActionText::Generators::InstallGeneratorTest < Rails::Generators::TestCase
end
test "loads JavaScript dependencies in application.js" do
application_js = Pathname("app/javascript/packs/application.js").expand_path(destination_root)
application_js = Pathname("app/javascript/application.js").expand_path(destination_root)
application_js.dirname.mkpath
application_js.write("\n")
run_under_asset_pipeline
run_generator_instance
assert_file application_js do |content|
assert_match %r"^#{Regexp.escape 'require("@rails/actiontext")'}", content
assert_match %r"^#{Regexp.escape 'require("trix")'}", content
assert_match %r"^#{Regexp.escape 'import "@rails/actiontext"'}", content
assert_match %r"^#{Regexp.escape 'import "trix"'}", content
end
end
@ -89,21 +99,10 @@ class ActionText::Generators::InstallGeneratorTest < Rails::Generators::TestCase
end
end
test "#yarn_command runs bin/yarn via Ruby" do
ran = nil
run_stub = -> (command, *) { ran = command }
generator.stub(:run, run_stub) do
generator.send(:yarn_command, "foo")
end
assert_match %r"\S bin/yarn foo$", ran
end
test "run just for asset pipeline" do
run_under_asset_pipeline
application_js = Pathname("app/assets/javascripts/application.js").expand_path(destination_root)
application_js = Pathname("app/javascript/application.js").expand_path(destination_root)
application_js.dirname.mkpath
application_js.write ""

View File

@ -105,8 +105,6 @@ class ApiAppGeneratorTest < Rails::Generators::TestCase
generator = Rails::Generators::AppGenerator.new ["rails"],
{ api: true, update: true }, { destination_root: destination_root, shell: @shell }
quietly { generator.update_bin_files }
assert_no_file "bin/yarn"
end
private
@ -181,7 +179,6 @@ class ApiAppGeneratorTest < Rails::Generators::TestCase
public/apple-touch-icon-precomposed.png
public/apple-touch-icon.png
public/favicon.ico
package.json
)
end
end

View File

@ -14,11 +14,6 @@ DEFAULT_APP_FILES = %w(
config.ru
app/assets/config/manifest.js
app/assets/images
app/javascript
app/javascript/channels
app/javascript/channels/consumer.js
app/javascript/channels/index.js
app/javascript/packs/application.js
app/assets/stylesheets
app/assets/stylesheets/application.css
app/channels/application_cable/channel.rb
@ -42,7 +37,6 @@ DEFAULT_APP_FILES = %w(
bin/rails
bin/rake
bin/setup
bin/yarn
config/application.rb
config/boot.rb
config/cable.yml
@ -73,7 +67,6 @@ DEFAULT_APP_FILES = %w(
lib/tasks
lib/assets
log
package.json
public
storage
test/application_system_test_case.rb
@ -101,27 +94,31 @@ class AppGeneratorTest < Rails::Generators::TestCase
# brings setup, teardown, and some tests
include SharedGeneratorTests
setup do
ENV["SKIP_REQUIRE_WEBPACKER"] = "true"
end
teardown do
ENV["SKIP_REQUIRE_WEBPACKER"] = nil
end
def default_files
::DEFAULT_APP_FILES
end
def test_skip_bundle
generator([destination_root], skip_bundle: true)
output = run_generator_instance
run_generator_instance
assert_empty @bundle_commands
# skip_bundle is only about running bundle install so ensure the Gemfile is still generated
assert_file "Gemfile"
assert_webpack_installation_skipped(output)
end
def test_assets
run_generator
assert_file("app/views/layouts/application.html.erb", /stylesheet_link_tag\s+"application", "data-turbolinks-track": "reload"/)
assert_file("app/views/layouts/application.html.erb", /javascript_pack_tag\s+"application", "data-turbolinks-track": "reload"/)
assert_file("app/assets/stylesheets/application.css")
assert_file("app/javascript/packs/application.js")
end
def test_application_job_file_present
@ -212,9 +209,10 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
def test_csp_initializer_include_connect_src_example
run_generator
app_root = File.join(destination_root, "myapp")
run_generator [app_root, "--webpack"]
assert_file "config/initializers/content_security_policy.rb" do |content|
assert_file "#{app_root}/config/initializers/content_security_policy.rb" do |content|
assert_match(/# policy\.connect_src/, content)
end
end
@ -287,34 +285,6 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
end
def test_adds_bin_yarn_into_setup_script
run_generator
assert_file "bin/yarn"
assert_file "bin/setup" do |content|
# Does not comment yarn install
assert_match(/(?=[^#]*?) system! "bin\/yarn"/, content)
end
end
def test_app_update_does_not_generate_yarn_contents_when_bin_yarn_is_not_used
app_root = File.join(destination_root, "myapp")
run_generator [app_root, "--skip-javascript"]
stub_rails_application(app_root) do
generator = Rails::Generators::AppGenerator.new ["rails"], { update: true, skip_javascript: true }, { destination_root: app_root, shell: @shell }
generator.send(:app_const)
quietly { generator.update_bin_files }
assert_no_file "#{app_root}/bin/yarn"
assert_file "#{app_root}/bin/setup" do |content|
assert_no_match(/system! "bin\/yarn"/, content)
end
end
end
def test_app_update_does_not_generate_assets_initializer_when_skip_sprockets_is_given
app_root = File.join(destination_root, "myapp")
run_generator [app_root, "--skip-sprockets"]
@ -508,54 +478,6 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
end
def test_package_json_uses_current_versions_and_set_version_of_turbolinks
run_generator
generator = Rails::Generators::AppBase.new ["rails"]
version = generator.send(:npm_version)
assert_file "package.json" do |content|
assert_match(/"@rails\/ujs": "#{version}"/, content)
assert_match(/"@rails\/activestorage": "#{version}"/, content)
assert_match(/"@rails\/actioncable": "#{version}"/, content)
assert_match(/"turbolinks": "\^5.2.0"/, content)
end
end
def test_package_json_uses_edge_versions
run_generator [destination_root, "--main"]
assert_file "package.json" do |content|
assert_match(/"@rails\/ujs": "latest"/, content)
assert_match(/"@rails\/activestorage": "latest"/, content)
assert_match(/"@rails\/actioncable": "latest"/, content)
assert_match(/"turbolinks": "turbolinks\/turbolinks#master"/, content)
end
end
def test_package_json_excludes_activestorage_if_skipped
run_generator [destination_root, "--skip-active-storage"]
assert_file "package.json" do |content|
assert_not content.include?("activestorage")
end
end
def test_package_json_excludes_actioncable_if_skipped
run_generator [destination_root, "--skip-action-cable"]
assert_file "package.json" do |content|
assert_not content.include?("actioncable")
end
end
def test_package_json_excludes_turbolinks_if_skipped
run_generator [destination_root, "--skip-turbolinks"]
assert_file "package.json" do |content|
assert_not content.include?("turbolinks")
end
end
def test_config_database_is_added_by_default
run_generator
assert_file "config/database.yml", /sqlite3/
@ -697,7 +619,6 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_file "app/views/layouts/application.html.erb" do |contents|
assert_match(/stylesheet_link_tag\s+"application" %>/, contents)
assert_no_match(/javascript_pack_tag\s+'application'/, contents)
end
end
@ -801,14 +722,14 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
def test_generation_runs_bundle_install
generator([destination_root], skip_webpack_install: true)
generator([destination_root])
run_generator_instance
assert_equal 1, @bundle_commands.count("install")
end
def test_generation_use_original_bundle_environment
generator([destination_root], skip_webpack_install: true)
generator([destination_root])
mock_original_env = -> do
{ "BUNDLE_RUBYONRAILS__ORG" => "user:pass" }
@ -826,7 +747,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
def test_dev_option
generator([destination_root], dev: true, skip_webpack_install: true)
generator([destination_root], dev: true)
run_generator_instance
assert_equal 1, @bundle_commands.count("install")
@ -836,7 +757,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
def test_edge_option
Rails.stub(:gem_version, Gem::Version.new("2.1.0")) do
generator([destination_root], edge: true, skip_webpack_install: true)
generator([destination_root], edge: true)
run_generator_instance
end
@ -846,7 +767,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
def test_edge_option_during_alpha
Rails.stub(:gem_version, Gem::Version.new("2.1.0.alpha")) do
generator([destination_root], edge: true, skip_webpack_install: true)
generator([destination_root], edge: true)
run_generator_instance
end
@ -860,7 +781,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
def test_main_option
generator([destination_root], main: true, skip_webpack_install: true)
generator([destination_root], main: true)
run_generator_instance
assert_equal 1, @bundle_commands.count("install")
@ -868,7 +789,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
def test_bundler_binstub
generator([destination_root], skip_webpack_install: true)
generator([destination_root])
run_generator_instance
assert_equal 1, @bundle_commands.count("binstubs bundler")
@ -906,17 +827,14 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
end
def test_webpack_option_with_js_framework
generator([destination_root], webpack: "react")
def test_webpack_option
generator([destination_root], webpack: true)
webpacker_called = 0
react_called = 0
command_check = -> command, *_ do
case command
when "webpacker:install"
webpacker_called += 1
when "webpacker:install:react"
react_called += 1
end
end
@ -925,47 +843,32 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
assert_equal 1, webpacker_called, "`webpacker:install` expected to be called once, but was called #{webpacker_called} times."
assert_equal 1, react_called, "`webpacker:install:react` expected to be called once, but was called #{react_called} times."
assert_gem "webpacker"
end
def test_skip_webpack_install
generator([destination_root], skip_webpack_install: true)
command_check = -> command do
if command == "webpacker:install"
flunk "`webpacker:install` expected to not be called."
end
end
generator.stub(:rails_command, command_check) do
run_generator_instance
end
assert_gem "webpacker"
assert_no_file "config/webpacker.yml"
output = Dir.chdir(destination_root) do
`bin/rails help`
end
assert_match(/The most common rails commands are:/, output)
assert_match(/webpacker:install/, output)
assert_equal true, $?.success?
end
def test_generator_if_skip_turbolinks_is_given
run_generator [destination_root, "--skip-turbolinks"]
assert_no_gem "turbolinks"
def test_hotwire
run_generator [destination_root, "--dev"]
assert_gem "turbo-rails"
assert_gem "stimulus-rails"
assert_file "app/views/layouts/application.html.erb" do |content|
assert_no_match(/data-turbolinks-track/, content)
assert_match(/data-turbo-track/, content)
end
assert_file "app/javascript/packs/application.js" do |content|
assert_no_match(/turbolinks/, content)
assert_file "app/javascript/application.js" do |content|
assert_match(/turbo/, content)
assert_match(/stimulus/, content)
end
end
def test_skip_hotwire
run_generator [destination_root, "--skip-hotwire"]
assert_no_gem "turbo-rails"
assert_file "app/views/layouts/application.html.erb" do |content|
assert_no_match(/data-turbo-track/, content)
end
assert_no_file "app/javascript/application.js"
end
def test_bootsnap
run_generator [destination_root, "--no-skip-bootsnap"]
@ -1096,7 +999,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
def test_after_bundle_callback
generator([destination_root], skip_webpack_install: true).send(:after_bundle) do
generator([destination_root]).send(:after_bundle) do
@bundle_commands_before_callback = @bundle_commands.dup
end
@ -1135,13 +1038,11 @@ class AppGeneratorTest < Rails::Generators::TestCase
run_generator [app_root, "--minimal"]
assert_no_file "#{app_root}/config/storage.yml"
assert_no_file "#{app_root}/config/webpacker.yml"
assert_no_file "#{app_root}/config/cable.yml"
assert_no_file "#{app_root}/bin/yarn"
assert_no_file "#{app_root}/views/layouts/mailer.html.erb"
assert_no_file "#{app_root}/app/jobs/application.rb"
assert_file "#{app_root}/app/views/layouts/application.html.erb" do |content|
assert_no_match(/data-turbolinks-track/, content)
assert_no_match(/data-turbo-track/, content)
end
assert_file "#{app_root}/config/environments/development.rb" do |content|
assert_no_match(/config\.active_storage/, content)
@ -1162,7 +1063,6 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_match(/\s+require\s+["']sprockets\/railtie["']/, content)
end
assert_no_gem "webpacker", app_root
assert_no_gem "jbuilder", app_root
assert_no_gem "web-console", app_root
end
@ -1192,22 +1092,4 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_no_match(gem, content)
end
end
def assert_webpack_installation_skipped(output)
assert_match(/^Skipping `rails webpacker:install`/, output)
%w(
.browserslistrc
babel.config.js
bin/webpack
bin/webpack-dev-server
config/webpack
config/webpack/development.js
config/webpack/environment.js
config/webpack/production.js
config/webpack/test.js
config/webpacker.yml
postcss.config.js
).each { |f| assert_no_file(f) }
end
end

View File

@ -7,6 +7,11 @@ class ChannelGeneratorTest < Rails::Generators::TestCase
include GeneratorsTestHelper
tests Rails::Generators::ChannelGenerator
setup do
FileUtils.mkdir_p("#{destination_root}/app/javascript")
FileUtils.touch("#{destination_root}/app/javascript/application.js")
end
def test_application_cable_skeleton_is_created
run_generator ["books"]
@ -27,7 +32,7 @@ class ChannelGeneratorTest < Rails::Generators::TestCase
end
assert_file "app/javascript/channels/chat_channel.js" do |channel|
assert_match(/import consumer from "\.\/consumer"\s+consumer\.subscriptions\.create\("ChatChannel/, channel)
assert_match(/import consumer from "channels\/consumer"\s+consumer\.subscriptions\.create\("ChatChannel/, channel)
end
end
@ -41,7 +46,7 @@ class ChannelGeneratorTest < Rails::Generators::TestCase
end
assert_file "app/javascript/channels/chat_channel.js" do |channel|
assert_match(/import consumer from "\.\/consumer"\s+consumer\.subscriptions\.create\("ChatChannel/, channel)
assert_match(/import consumer from "channels\/consumer"\s+consumer\.subscriptions\.create\("ChatChannel/, channel)
assert_match(/,\n\n speak/, channel)
assert_match(/,\n\n mute: function\(\) \{\n return this\.perform\('mute'\);\n \}\n\}\);/, channel)
end
@ -59,11 +64,9 @@ class ChannelGeneratorTest < Rails::Generators::TestCase
def test_consumer_js_is_created_if_not_present_already
run_generator ["chat"]
FileUtils.rm("#{destination_root}/app/javascript/channels/index.js")
FileUtils.rm("#{destination_root}/app/javascript/channels/consumer.js")
run_generator ["camp"]
assert_file "app/javascript/channels/index.js"
assert_file "app/javascript/channels/consumer.js"
end
@ -87,7 +90,6 @@ class ChannelGeneratorTest < Rails::Generators::TestCase
assert_file "app/channels/application_cable/channel.rb"
assert_file "app/channels/application_cable/connection.rb"
assert_file "app/javascript/channels/index.js"
assert_file "app/javascript/channels/consumer.js"
end

View File

@ -7,7 +7,7 @@ class PluginTestRunnerTest < ActiveSupport::TestCase
def setup
@destination_root = Dir.mktmpdir("bukkits")
Dir.chdir(@destination_root) { `bundle exec rails plugin new bukkits --skip-bundle` }
Dir.chdir(@destination_root) { `bundle exec rails plugin new bukkits --skip-bundle --webpack` }
plugin_file "test/dummy/db/schema.rb", ""
end

View File

@ -83,7 +83,7 @@ module SharedGeneratorTests
def test_template_is_executed_when_supplied_an_https_path
url = "https://gist.github.com/josevalim/103208/raw/"
generator([destination_root], template: url, skip_webpack_install: true)
generator([destination_root], template: url)
applied = nil
apply_stub = -> (path, *) { applied = path }
@ -189,14 +189,7 @@ module SharedGeneratorTests
end
def test_generator_for_active_storage
run_generator
unless generator_class.name == "Rails::Generators::PluginGenerator"
assert_file "#{application_path}/app/javascript/packs/application.js" do |content|
assert_match(/^import \* as ActiveStorage from "@rails\/activestorage"/, content)
assert_match(/^ActiveStorage.start\(\)/, content)
end
end
run_generator([destination_root])
assert_file "#{application_path}/config/environments/development.rb" do |content|
assert_match(/config\.active_storage/, content)
@ -224,10 +217,6 @@ module SharedGeneratorTests
assert_file "#{application_path}/config/application.rb", /#\s+require\s+["']active_storage\/engine["']/
assert_file "#{application_path}/app/javascript/packs/application.js" do |content|
assert_no_match(/activestorage/, content)
end
assert_file "#{application_path}/config/environments/development.rb" do |content|
assert_no_match(/config\.active_storage/, content)
end
@ -254,10 +243,6 @@ module SharedGeneratorTests
assert_file "#{application_path}/config/application.rb", /#\s+require\s+["']active_storage\/engine["']/
assert_file "#{application_path}/app/javascript/packs/application.js" do |content|
assert_no_match(/activestorage/i, content)
end
assert_file "#{application_path}/config/environments/development.rb" do |content|
assert_no_match(/config\.active_storage/, content)
end
@ -296,7 +281,7 @@ module SharedGeneratorTests
end
def test_generator_if_skip_action_cable_is_given
run_generator [destination_root, "--skip-action-cable"]
run_generator [destination_root, "--skip-action-cable", "--webpack"]
assert_file "#{application_path}/config/application.rb", /#\s+require\s+["']action_cable\/engine["']/
assert_no_file "#{application_path}/config/cable.yml"
assert_no_file "#{application_path}/app/javascript/consumer.js"
@ -331,24 +316,6 @@ module SharedGeneratorTests
end
end
def test_generator_for_yarn
skip "#34009 disabled JS by default for plugins" if generator_class.name == "Rails::Generators::PluginGenerator"
run_generator
assert_file "#{application_path}/package.json", /dependencies/
assert_file "#{application_path}/bin/yarn"
assert_file "#{application_path}/config/initializers/assets.rb", /node_modules/
end
def test_generator_for_yarn_skipped
run_generator([destination_root, "--skip-javascript"])
assert_no_file "#{application_path}/package.json"
assert_no_file "#{application_path}/bin/yarn"
assert_file "#{application_path}/config/initializers/assets.rb" do |content|
assert_no_match(/node_modules/, content)
end
end
private
def run_generator_instance
@bundle_commands = []

View File

@ -511,7 +511,7 @@ Module.new do
FileUtils.rm_rf(app_template_path)
FileUtils.mkdir_p(app_template_path)
sh "#{Gem.ruby} #{RAILS_FRAMEWORK_ROOT}/railties/exe/rails new #{app_template_path} --skip-bundle --no-rc --skip-webpack-install --quiet"
sh "#{Gem.ruby} #{RAILS_FRAMEWORK_ROOT}/railties/exe/rails new #{app_template_path} --skip-bundle --no-rc --quiet"
File.open("#{app_template_path}/config/boot.rb", "w") do |f|
f.puts 'require "rails/all"'
end
@ -529,26 +529,13 @@ Module.new do
end
end
# Fix relative file paths
package_json = File.read("#{assets_path}/package.json")
package_json.gsub!(%r{"file:(\.\./[^"]+)"}) do
path = Pathname.new($1).expand_path(assets_path).relative_path_from(Pathname.new(app_template_path))
"\"file:#{path}\""
end
File.write("#{app_template_path}/package.json", package_json)
FileUtils.cp("#{assets_path}/config/webpacker.yml", "#{app_template_path}/config/webpacker.yml")
FileUtils.cp_r("#{assets_path}/config/webpack", "#{app_template_path}/config/webpack")
FileUtils.ln_s("#{assets_path}/node_modules", "#{app_template_path}/node_modules")
FileUtils.chdir(app_template_path) do
sh "yarn install"
sh "bin/rails webpacker:binstubs"
end
FileUtils.mkdir_p "#{app_template_path}/app/javascript"
File.write("#{app_template_path}/app/javascript/application.js", "\n")
# Fake 'Bundler.require' -- we run using the repo's Gemfile, not an
# app-specific one: we don't want to require every gem that lists.
contents = File.read("#{app_template_path}/config/application.rb")
contents.sub!(/^Bundler\.require.*/, "%w(turbolinks webpacker).each { |r| require r }")
contents.sub!(/^Bundler\.require.*/, "%w(importmap-rails).each { |r| require r }")
File.write("#{app_template_path}/config/application.rb", contents)
require "rails"

View File

@ -0,0 +1,3 @@
const { webpackConfig } = require('@rails/webpacker')
module.exports = webpackConfig

View File

@ -1,3 +1,5 @@
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const { environment } = require('@rails/webpacker')
module.exports = environment.toWebpackConfig()
const webpackConfig = require('./base')
module.exports = webpackConfig

View File

@ -1,3 +1,5 @@
process.env.NODE_ENV = process.env.NODE_ENV || 'production'
const { environment } = require('@rails/webpacker')
module.exports = environment.toWebpackConfig()
const webpackConfig = require('./base')
module.exports = webpackConfig

View File

@ -1,3 +1,5 @@
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const { environment } = require('@rails/webpacker')
module.exports = environment.toWebpackConfig()
const webpackConfig = require('./base')
module.exports = webpackConfig

View File

@ -1,9 +1,61 @@
# Note: You must restart bin/webpack-dev-server for changes to take effect
default: &default
source_path: app/javascript
check_yarn_integrity: false
source_path: app/packs
source_entry_path: entrypoints
public_root_path: public
public_output_path: packs
cache_path: tmp/webpacker
webpack_compile_output: true
# Additional paths webpack should look up modules
# ['app/assets', 'engine/foo/app/assets']
additional_paths: []
# Reload manifest.json on all requests so we reload latest compiled packs
cache_manifest: false
development:
<<: *default
compile: true
# Reference: https://webpack.js.org/configuration/dev-server/
dev_server:
https: false
host: localhost
port: 3035
public: localhost:3035
# Hot Module Replacement updates modules while the application is running without a full reload
hmr: false
# Should we show a full-screen overlay in the browser when there are compiler errors or warnings?
overlay: true
# Should we use gzip compression?
compress: true
# Note that apps that do not check the host are vulnerable to DNS rebinding attacks
disable_host_check: true
# This option lets the browser open with your local IP
use_local_ip: false
# When enabled, nothing except the initial startup information will be written to the console.
# This also means that errors or warnings from webpack are not visible.
quiet: false
pretty: true
headers:
'Access-Control-Allow-Origin': '*'
watch_options:
ignored: '**/node_modules/**'
test:
<<: *default
compile: true
# Compile test packs to a separate directory
public_output_path: packs-test
production:
<<: *default
# Production depends on precompilation of packs prior to booting for performance.
compile: false
# Cache manifest.json for performance
cache_manifest: true

View File

@ -5,7 +5,6 @@
"@rails/actioncable": "file:../../../../actioncable",
"@rails/activestorage": "file:../../../../activestorage",
"@rails/ujs": "file:../../../../actionview",
"@rails/webpacker": "^5.2.1",
"turbolinks": "^5.2.0"
"@rails/webpacker": "^6.0.0-rc.5"
}
}

View File

@ -1,17 +1,7 @@
# frozen_string_literal: true
if ENV["BUILDKITE"]
require "minitest/reporters"
require "fileutils"
require "minitest-ci"
module Minitest
def self.plugin_rails_ci_junit_format_test_report_for_buildkite_init(*)
dir = File.join(__dir__, "../test-reports/#{ENV['BUILDKITE_JOB_ID']}")
reporter << Minitest::Reporters::JUnitReporter.new(dir, false)
FileUtils.mkdir_p(dir)
end
end
Minitest.load_plugins
Minitest.extensions.unshift "rails_ci_junit_format_test_report_for_buildkite"
Minitest::Ci.report_dir = File.join(__dir__, "../test-reports/#{ENV['BUILDKITE_JOB_ID']}")
end

988
yarn.lock

File diff suppressed because it is too large Load Diff