Make Webpacker the default JavaScript compiler for Rails 6 (#33079)

* Use Webpacker by default on new apps

* Stop including coffee-rails by default

* Drop using a js_compressor by default

* Drop extra test for coffeescript inclusion by default

* Stick with skip_javascript to signify skipping webpack

* Don't install a JS runtime by default any more

* app/javascript will be the new default directory for JS

* Make it clear that this is just for configuring the default Webpack framework setup now

* Start using the Webpack tag in the default layout

* Irrelevant test

* jQuery is long gone

* Stop having asset pipeline compile default application.js

* Add rails-ujs by default to the Webpack setup

* Add Active Storage JavaScript to application.js pack by default

* Consistent quoting

* Add Turbolinks to default pack

* Add Action Cable to default pack

Need some work on how to set the global consumer that channels will
work with. @javan?

* Require all channels by default and use a separate consumer stub

* Channel generator now targets Webpack style

* Update task docs to match new generator style

* Use uniform import style

* Drop the JS assets generator

It was barely helpful as it was. It’s no longer helpful in a Webpacked
world. Sayonara!

* Add app/javascript to the stats directories

* Simpler import style

Which match the other imports.

* Address test failures from dropping JS compilation (and compression)

* webpacker-default: Modify `AssetsGeneratorTest`

Before:

```
$ bin/test test/generators/assets_generator_test.rb
Run options: --seed 46201

F

Failure:
AssetsGeneratorTest#test_assets [/Users/ttanimichi/ghq/github.com/ttanimichi/rails/railties/test/generators/assets_generator_test.rb:12]:
Expected file "app/assets/javascripts/posts.js" to exist, but does not

bin/test /Users/ttanimichi/ghq/github.com/ttanimichi/rails/railties/test/generators/assets_generator_test.rb:10

.

Finished in 0.031343s, 63.8101 runs/s, 95.7152 assertions/s.
2 runs, 3 assertions, 1 failures, 0 errors, 0 skips
```

After:

```
$ bin/test test/generators/assets_generator_test.rb
Run options: --seed 43571

..

Finished in 0.030370s, 65.8545 runs/s, 65.8545 assertions/s.
2 runs, 2 assertions, 0 failures, 0 errors, 0 skips
```

* webpacker-default: Modify `ChannelGeneratorTest`

Before:

```
$ bin/test test/generators/channel_generator_test.rb
Run options: --seed 8986

.F

Failure:
ChannelGeneratorTest#test_channel_with_multiple_actions_is_created [/Users/ttanimichi/ghq/github.com/ttanimichi/rails/railties/test/generators/channel_generator_test.rb:43]:
Expected file "app/assets/javascripts/channels/chat.js" to exist, but does not

bin/test /Users/ttanimichi/ghq/github.com/ttanimichi/rails/railties/test/generators/channel_generator_test.rb:34

.F

Failure:
ChannelGeneratorTest#test_channel_is_created [/Users/ttanimichi/ghq/github.com/ttanimichi/rails/railties/test/generators/channel_generator_test.rb:29]:
Expected file "app/assets/javascripts/channels/chat.js" to exist, but does not

bin/test /Users/ttanimichi/ghq/github.com/ttanimichi/rails/railties/test/generators/channel_generator_test.rb:22

E

Error:
ChannelGeneratorTest#test_cable_js_is_created_if_not_present_already:
Errno::ENOENT: No such file or directory @ apply2files - /Users/ttanimichi/ghq/github.com/ttanimichi/rails/railties/test/fixtures/tmp/app/assets/javascripts/cable.js

bin/test /Users/ttanimichi/ghq/github.com/ttanimichi/rails/railties/test/generators/channel_generator_test.rb:60

F

Failure:
ChannelGeneratorTest#test_channel_suffix_is_not_duplicated [/Users/ttanimichi/ghq/github.com/ttanimichi/rails/railties/test/generators/channel_generator_test.rb:87]:
Expected file "app/assets/javascripts/channels/chat.js" to exist, but does not

bin/test /Users/ttanimichi/ghq/github.com/ttanimichi/rails/railties/test/generators/channel_generator_test.rb:80

F

Failure:
ChannelGeneratorTest#test_channel_on_revoke [/Users/ttanimichi/ghq/github.com/ttanimichi/rails/railties/test/generators/channel_generator_test.rb:77]:
Expected file "app/assets/javascripts/cable.js" to exist, but does not

bin/test /Users/ttanimichi/ghq/github.com/ttanimichi/rails/railties/test/generators/channel_generator_test.rb:68

Finished in 0.064384s, 108.7227 runs/s, 481.4861 assertions/s.
7 runs, 31 assertions, 4 failures, 1 errors, 0 skips
```

After:

```
$ bin/test test/generators/channel_generator_test.rb
Run options: --seed 44857

.......

Finished in 0.060243s, 116.1961 runs/s, 697.1764 assertions/s.
7 runs, 42 assertions, 0 failures, 0 errors, 0 skips
```

* Fix shared generator tests.

* webpacker-default: Modify `ControllerGeneratorTest`

The JS assets generator was dropped. ref. 46215b1794

* Revert "Simpler import style". It's currently failing with an error of "TypeError: undefined is not an object (evaluating '__WEBPACK_IMPORTED_MODULE_2_activestorage___default.a.start')". Waiting for @javan to have a look.

This reverts commit 5d3ebb71059f635d3756cbda4ab9752027e09256.

* require webpacker in test app

* Add webpacker without making the build hang/timeout. (#33640)

* use yarn workspaces to allow for installing unreleased packages and only generate js/bootsnap when required

* no longer need to have webpacker in env templates as webpacker moved this config to yml file

* Fix rubocop violation

* Got the test passing for the running scaffold

* update expected lines of code

* update middleware tests to account for webpacker

* disable js in plugins be default to get the tests passing (#34009)

* clear codeclimate report issues

* Anything newer than currently released is good

* Use Webpacker development version during development of Rails

* Edge should get development webpacker as well

* Add changelog entry for Webpacker change
This commit is contained in:
David Heinemeier Hansson 2018-09-30 22:31:21 -07:00 committed by GitHub
parent 6d40d2d3d1
commit 4838c1716a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 285 additions and 327 deletions

2
.gitignore vendored

@ -14,3 +14,5 @@ debug.log
node_modules/
package-lock.json
pkg/
/tmp/
/yarn.lock

@ -42,6 +42,11 @@ before_install:
- "[[ $GEM != 'av:ujs' ]] || nvm install node"
- "[[ $GEM != 'av:ujs' ]] || node --version"
- "[[ $GEM != 'av:ujs' ]] || (cd actionview && npm install)"
- "[[ $GEM != 'ar:mysql2' ]] || [[ $MYSQL == 'mariadb' ]] || sudo mysql -e \"use mysql; update user set authentication_string='' where User='root'; update user set plugin='mysql_native_password';FLUSH PRIVILEGES;\""
- "[[ $GEM != 'ar:mysql2' ]] || [[ $MYSQL == 'mariadb' ]] || sudo mysql_upgrade"
- "[[ $GEM != 'ar:mysql2' ]] || [[ $MYSQL == 'mariadb' ]] || sudo service mysql restart"
- "[[ $GEM != 'railties' ]] || (curl -o- -L https://yarnpkg.com/install.sh | bash)"
- "[[ $GEM != 'railties' ]] || export PATH=$HOME/.yarn/bin:$PATH"
before_script:
# Set Sauce Labs username and access key. Obfuscated, purposefully not encrypted.

2
.yarnrc Normal file

@ -0,0 +1,2 @@
workspaces-experimental true
--add.prefer-offline true

@ -15,7 +15,7 @@ gem "rack-cache", "~> 1.2"
gem "coffee-rails"
gem "sass-rails"
gem "turbolinks", "~> 5"
gem "webpacker", github: "rails/webpacker", require: ENV["SKIP_REQUIRE_WEBPACKER"] != "true"
# 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.

@ -30,6 +30,15 @@ GIT
queue_classic (3.2.0.RC1)
pg (>= 0.17, < 2.0)
GIT
remote: https://github.com/rails/webpacker.git
revision: 48d9fd52c3e9637dbb21e551b48c84c0f2dbb2ed
specs:
webpacker (4.0.0.pre.pre.2)
activesupport (>= 4.2)
rack-proxy (>= 0.6.1)
railties (>= 4.2)
PATH
remote: .
specs:
@ -364,6 +373,8 @@ GEM
rack (>= 0.4)
rack-protection (2.0.3)
rack
rack-proxy (0.6.5)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
rails-dom-testing (2.0.3)
@ -565,6 +576,7 @@ DEPENDENCIES
uglifier (>= 1.3.0)
w3c_validators
wdm (>= 0.1.0)
webpacker!
websocket-client-simple!
BUNDLED WITH

@ -1,14 +1,12 @@
Description:
============
Stubs out a new cable channel for the server (in Ruby) and client (in CoffeeScript).
Stubs out a new cable channel for the server (in Ruby) and client (in JavaScript).
Pass the channel name, either CamelCased or under_scored, and an optional list of channel actions as arguments.
Note: Turn on the cable connection in app/assets/javascripts/cable.js after generating any channels.
Example:
========
rails generate channel Chat speak
creates a Chat channel class and CoffeeScript asset:
creates a Chat channel class and JavaScript asset:
Channel: app/channels/chat_channel.rb
Assets: app/assets/javascripts/channels/chat.coffee
Assets: app/javascript/channels/chat_channel.js

@ -16,10 +16,11 @@ def create_channel_file
if options[:assets]
if behavior == :invoke
template "assets/cable.js", "app/assets/javascripts/cable.js"
template "javascript/index.js", "app/javascript/channels/index.js"
template "javascript/consumer.js", "app/javascript/channels/consumer.js"
end
js_template "assets/channel", File.join("app/assets/javascripts/channels", class_path, "#{file_name}")
js_template "javascript/channel", File.join("app/javascript/channels", class_path, "#{file_name}_channel")
end
generate_application_cable_files

@ -1,14 +0,0 @@
App.<%= class_name.underscore %> = App.cable.subscriptions.create "<%= class_name %>Channel",
connected: ->
# Called when the subscription is ready for use on the server
disconnected: ->
# Called when the subscription has been terminated by the server
received: (data) ->
# Called when there's incoming data on the websocket for this channel
<% actions.each do |action| -%>
<%= action %>: ->
@perform '<%= action %>'
<% end -%>

@ -1,4 +1,6 @@
App.<%= class_name.underscore %> = App.cable.subscriptions.create("<%= class_name %>Channel", {
import consumer from "./consumer"
consumer.subscriptions.create("<%= class_name %>Channel", {
connected: function() {
// Called when the subscription is ready for use on the server
},

@ -1,13 +1,6 @@
// Action Cable provides the framework to deal with WebSockets in Rails.
// You can generate new channels where WebSocket features live using the `rails generate channel` command.
//
//= require action_cable
//= require_self
//= require_tree ./channels
(function() {
this.App || (this.App = {});
import ActionCable from "actioncable"
App.cable = ActionCable.createConsumer();
}).call(this);
export default ActionCable.createConsumer()

@ -0,0 +1,5 @@
// 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)

@ -1,5 +1,3 @@
//= link_tree ../images
//= link_directory ../javascripts .js
//= link_directory ../stylesheets .css
//= link active_storage_manifest.js

@ -25,8 +25,7 @@
# Apache or NGINX already handles this.
config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present?
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
# Compress CSS using a preprocessor.
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.

@ -0,0 +1,72 @@
# Note: You must restart bin/webpack-dev-server for changes to take effect
default: &default
source_path: app/javascript
source_entry_path: packs
public_output_path: packs
cache_path: tmp/cache/webpacker
check_yarn_integrity: false
# Additional paths webpack should lookup modules
# ['app/assets', 'engine/foo/app/assets']
resolved_paths: []
# Reload manifest.json on all requests so we reload latest compiled packs
cache_manifest: false
extensions:
- .js
- .sass
- .scss
- .css
- .module.sass
- .module.scss
- .module.css
- .png
- .svg
- .gif
- .jpeg
- .jpg
development:
<<: *default
compile: true
# Verifies that versions and hashed value of the package contents in the project's package.json
check_yarn_integrity: true
# Reference: https://webpack.js.org/configuration/dev-server/
dev_server:
https: false
host: localhost
port: 3035
public: localhost:3035
hmr: false
# Inline should be set to true if using HMR
inline: true
overlay: true
compress: true
disable_host_check: true
use_local_ip: false
quiet: false
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

14
package.json Normal file

@ -0,0 +1,14 @@
{
"private": true,
"workspaces": [
"actioncable",
"activestorage",
"actionview",
"tmp/templates/app_template",
"railties/test/fixtures/tmp/bukkits/**/test/dummy",
"railties/test/fixtures/tmp/bukkits/**/spec/dummy"
],
"dependencies": {
"webpack": "^4.17.1"
}
}

@ -1,3 +1,11 @@
* Use Webpacker by default to manage app-level JavaScript through the new app/javascript directory.
Sprockets is now solely in charge, by default, of compiling CSS and other static assets.
Action Cable channel generators will create ES6 stubs rather than use CoffeeScript.
Active Storage, Action Cable, Turbolinks, and Rails-UJS are loaded by a new application.js pack.
Generators no longer generate JavaScript stubs.
*DHH*, *Lachlan Sylvester*
* Refactors `migrations_paths` command option in generators
to `database` (aliased as `db`). Now, the migrations paths
will be read from the specified database configuration in the

@ -28,6 +28,9 @@ namespace :test do
require "bundler/setup" unless defined?(Bundler)
require "active_support"
# Only generate the template app once.
require_relative "test/isolation/abstract_unit"
failing_files = []
dirs = (ENV["TEST_DIR"] || ENV["TEST_DIRS"] || "**").split(",")

@ -33,8 +33,6 @@ module Generators
rails: {
actions: "-a",
orm: "-o",
javascripts: "-j",
javascript_engine: "-je",
resource_controller: "-c",
scaffold_controller: "-c",
stylesheets: "-y",

@ -68,10 +68,7 @@ def self.add_shared_options_for(name)
class_option :skip_listen, type: :boolean, default: false,
desc: "Don't generate configuration that depends on the listen gem"
class_option :skip_coffee, type: :boolean, default: false,
desc: "Don't use CoffeeScript"
class_option :skip_javascript, type: :boolean, aliases: "-J", default: false,
class_option :skip_javascript, type: :boolean, aliases: "-J", default: name == "plugin",
desc: "Skip JavaScript files"
class_option :skip_turbolinks, type: :boolean, default: false,
@ -327,24 +324,17 @@ def convert_database_option_for_jruby
def assets_gemfile_entry
return [] if options[:skip_sprockets]
gems = []
gems << GemfileEntry.version("sass-rails", "~> 5.0",
"Use SCSS for stylesheets")
if !options[:skip_javascript]
gems << GemfileEntry.version("uglifier",
">= 1.3.0",
"Use Uglifier as compressor for JavaScript assets")
end
gems
GemfileEntry.version("sass-rails", "~> 5.0", "Use SCSS for stylesheets")
end
def webpacker_gemfile_entry
return [] unless options[:webpack]
return [] if options[:skip_javascript]
comment = "Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker"
GemfileEntry.new "webpacker", nil, comment
if options.dev? || options.edge?
GemfileEntry.github "webpacker", "rails/webpacker", nil, "Use development version of Webpacker"
else
GemfileEntry.new "webpacker", nil, "Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker"
end
end
def jbuilder_gemfile_entry
@ -352,34 +342,12 @@ def jbuilder_gemfile_entry
GemfileEntry.new "jbuilder", "~> 2.5", comment, {}, options[:api]
end
def coffee_gemfile_entry
GemfileEntry.version "coffee-rails", "~> 4.2", "Use CoffeeScript for .coffee assets and views"
end
def javascript_gemfile_entry
if options[:skip_javascript] || options[:skip_sprockets]
if options[:skip_javascript] || options[:skip_turbolinks]
[]
else
gems = [javascript_runtime_gemfile_entry]
gems << coffee_gemfile_entry unless options[:skip_coffee]
unless options[:skip_turbolinks]
gems << GemfileEntry.version("turbolinks", "~> 5",
"Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks")
end
gems
end
end
def javascript_runtime_gemfile_entry
comment = "See https://github.com/rails/execjs#readme for more supported runtimes"
if defined?(JRUBY_VERSION)
GemfileEntry.version "therubyrhino", nil, comment
elsif RUBY_PLATFORM.match?(/mingw|mswin/)
GemfileEntry.version "duktape", nil, comment
else
GemfileEntry.new "mini_racer", nil, comment, { platforms: :ruby }, true
[ GemfileEntry.version("turbolinks", "~> 5",
"Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks") ]
end
end
@ -452,9 +420,9 @@ def run_bundle
end
def run_webpack
if !(webpack = options[:webpack]).nil?
unless options[:skip_javascript]
rails_command "webpacker:install"
rails_command "webpacker:install:#{webpack}" unless webpack == "webpack"
rails_command "webpacker:install:#{options[:webpack]}" if options[:webpack] && options[:webpack] != "webpack"
end
end

@ -1,15 +0,0 @@
# frozen_string_literal: true
require "rails/generators/named_base"
module Js # :nodoc:
module Generators # :nodoc:
class AssetsGenerator < Rails::Generators::NamedBase # :nodoc:
source_root File.expand_path("templates", __dir__)
def copy_javascript
copy_file "javascript.js", File.join("app/assets/javascripts", class_path, "#{file_name}.js")
end
end
end
end

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

@ -80,7 +80,6 @@ def app
directory "app"
keep_file "app/assets/images"
empty_directory_with_keep_file "app/assets/javascripts/channels" unless options[:skip_action_cable]
keep_file "app/controllers/concerns"
keep_file "app/models/concerns"
@ -260,7 +259,7 @@ class AppGenerator < AppBase # :nodoc:
desc: "Don't run bundle install"
class_option :webpack, type: :string, default: nil,
desc: "Preconfigure for app-like JavaScript with Webpack (options: #{WEBPACKS.join('/')})"
desc: "Preconfigure Webpack with a particular framework (options: #{WEBPACKS.join('/')})"
def initialize(*args)
super
@ -409,7 +408,7 @@ def delete_public_files_if_api_option
def delete_js_folder_skipping_javascript
if options[:skip_javascript]
remove_dir "app/assets/javascripts"
remove_dir "app/javascript"
end
end
@ -436,7 +435,8 @@ def delete_action_mailer_files_skipping_action_mailer
def delete_action_cable_files_skipping_action_cable
if options[:skip_action_cable]
remove_file "app/assets/javascripts/cable.js"
remove_file "app/javascript/channels/consumer.js"
remove_dir "app/javascript/channels"
remove_dir "app/channels"
end
end

@ -1,5 +1,2 @@
//= link_tree ../images
<% unless options.skip_javascript -%>
//= link_directory ../javascripts .js
<% end -%>
//= link_directory ../stylesheets .css

@ -1,22 +0,0 @@
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
// vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
<% unless options[:skip_javascript] -%>
//= require rails-ujs
<% unless skip_active_storage? -%>
//= require activestorage
<% end -%>
<% unless options[:skip_turbolinks] -%>
//= require turbolinks
<% end -%>
<% end -%>
//= require_tree .

@ -1,13 +1,6 @@
// Action Cable provides the framework to deal with WebSockets in Rails.
// You can generate new channels where WebSocket features live using the `rails generate channel` command.
//
//= require action_cable
//= require_self
//= require_tree ./channels
(function() {
this.App || (this.App = {});
import ActionCable from "actioncable"
App.cable = ActionCable.createConsumer();
}).call(this);
export default ActionCable.createConsumer()

@ -0,0 +1,5 @@
// 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)

@ -0,0 +1,21 @@
// 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"
Rails.start()
<%- unless options[:skip_turbolinks] -%>
import Turbolinks from "turbolinks"
Turbolinks.start()
<%- end -%>
<%- unless skip_active_storage? -%>
import * as ActiveStorage from "activestorage"
ActiveStorage.start()
<%- end -%>
<%- unless options[:skip_action_cable] -%>
import "channels"
<%- end -%>

@ -9,11 +9,11 @@
<%%= stylesheet_link_tag 'application', media: 'all' %>
<%- else -%>
<%- unless options[:skip_turbolinks] -%>
<%%= 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-turbolinks-track': 'reload' %>
<%%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
<%- else -%>
<%%= stylesheet_link_tag 'application', media: 'all' %>
<%%= javascript_include_tag 'application' %>
<%%= stylesheet_link_tag 'application', media: 'all' %>
<%%= javascript_pack_tag 'application' %>
<%- end -%>
<%- end -%>
</head>

@ -23,12 +23,7 @@ Rails.application.configure do
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
<%- unless options.skip_sprockets? -%>
<%- if options.skip_javascript? -%>
# Compress CSS.
<%- else -%>
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
<%- end -%>
# Compress CSS using a preprocessor.
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.

@ -1,5 +1,11 @@
{
"name": "<%= app_name %>",
"private": true,
"dependencies": {}
"dependencies": {
"rails-ujs": ">=5.2.1"<% unless options[:skip_turbolinks] %>,
"turbolinks": "5.1.1"<% end -%><% unless skip_active_storage? %>,
"activestorage": ">=5.2.1"<% end -%><% unless options[:skip_action_cable] %>,
"actioncable": ">=5.2.1"<% end -%>
},
"version": "0.1.0"
}

@ -5,16 +5,13 @@ Description:
To create an asset within a folder, specify the asset's name as a
path like 'parent/name'.
This generates a JavaScript stub in app/assets/javascripts and a stylesheet
stub in app/assets/stylesheets.
This generates a stylesheet stub in app/assets/stylesheets.
If CoffeeScript is available, JavaScripts will be generated with the .coffee extension.
If Sass 3 is available, stylesheets will be generated with the .scss extension.
Example:
`rails generate assets posts`
Posts assets.
JavaScript: app/assets/javascripts/posts.js
Stylesheet: app/assets/stylesheets/posts.css

@ -3,22 +3,14 @@
module Rails
module Generators
class AssetsGenerator < NamedBase # :nodoc:
class_option :javascripts, type: :boolean, desc: "Generate JavaScripts"
class_option :stylesheets, type: :boolean, desc: "Generate Stylesheets"
class_option :javascript_engine, desc: "Engine for JavaScripts"
class_option :stylesheet_engine, desc: "Engine for Stylesheets"
private
def asset_name
file_name
end
hook_for :javascript_engine do |javascript_engine|
invoke javascript_engine, [name] if options[:javascripts]
end
hook_for :stylesheet_engine do |stylesheet_engine|
invoke stylesheet_engine, [name] if options[:stylesheets]
end

@ -1,2 +0,0 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

@ -113,7 +113,7 @@ def test_dummy_config
end
def test_dummy_assets
template "rails/javascripts.js", "#{dummy_path}/app/assets/javascripts/application.js", force: true
template "rails/javascripts.js", "#{dummy_path}/app/javascript/packs/application.js", force: true
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
end

@ -67,6 +67,9 @@ def destination(path)
def run_generator(args = default_arguments, config = {})
capture(:stdout) do
args += ["--skip-bundle"] unless args.include? "--dev"
args |= ["--skip-bootsnap"] unless args.include? "--no-skip-bootsnap"
args |= ["--skip-javascript"] unless args.include? "--no-skip-javascript"
generator_class.start(args, config.reverse_merge(destination_root: destination_root))
end
end

@ -11,6 +11,7 @@ STATS_DIRECTORIES = [
%w(Mailers app/mailers),
%w(Channels app/channels),
%w(JavaScripts app/assets/javascripts),
%w(JavaScript app/javascript),
%w(Libraries lib/),
%w(APIs app/apis),
%w(Controller\ tests test/controllers),

@ -68,20 +68,6 @@ def assert_no_file_exists(filename)
assert_equal 'a = "/assets/rails.png";', last_response.body.strip
end
test "assets do not require compressors until it is used" do
app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"
add_to_env_config "production", "config.assets.compile = true"
add_to_env_config "production", "config.assets.precompile = []"
# Load app env
app "production"
assert_not defined?(Uglifier)
get "/assets/demo.js"
assert_match "alert()", last_response.body
assert defined?(Uglifier)
end
test "precompile creates the file, gives it the original asset's content and run in production as default" do
app_file "app/assets/config/manifest.js", "//= link_tree ../javascripts"
app_file "app/assets/javascripts/application.js", "alert();"
@ -443,13 +429,13 @@ class ::PostsController < ActionController::Base ; end
end
test "digested assets are not mistakenly removed" do
app_file "app/assets/application.js", "alert();"
app_file "app/assets/application.css", "div { font-weight: bold }"
add_to_config "config.assets.compile = true"
precompile!
files = Dir["#{app_path}/public/assets/application-*.js"]
assert_equal 1, files.length, "Expected digested application.js asset to be generated, but none found"
files = Dir["#{app_path}/public/assets/application-*.css"]
assert_equal 1, files.length, "Expected digested application.css asset to be generated, but none found"
end
test "digested assets are removed from configured path" do

@ -25,6 +25,7 @@ def app
boot!
assert_equal [
"Webpacker::DevServerProxy",
"Rack::Sendfile",
"ActionDispatch::Static",
"ActionDispatch::Executor",
@ -56,6 +57,7 @@ def app
boot!
assert_equal [
"Webpacker::DevServerProxy",
"Rack::Sendfile",
"ActionDispatch::Static",
"ActionDispatch::Executor",
@ -138,7 +140,7 @@ def app
add_to_config "config.ssl_options = { redirect: { host: 'example.com' } }"
boot!
assert_equal [{ redirect: { host: "example.com" } }], Rails.application.middleware.first.args
assert_equal [{ redirect: { host: "example.com" } }], Rails.application.middleware[1].args
end
test "removing Active Record omits its middleware" do
@ -222,30 +224,31 @@ def app
test "insert middleware after" do
add_to_config "config.middleware.insert_after Rack::Sendfile, Rack::Config"
boot!
assert_equal "Rack::Config", middleware.second
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.first
assert_equal "Rack::Config", middleware.second
end
test "Rails.cache does not respond to middleware" do
add_to_config "config.cache_store = :memory_store"
boot!
assert_equal "Rack::Runtime", middleware.fourth
assert_equal "Rack::Runtime", middleware.fifth
end
test "Rails.cache does respond to middleware" do
boot!
assert_equal "Rack::Runtime", middleware.fifth
assert_equal "ActiveSupport::Cache::Strategy::LocalCache", middleware.fifth
assert_equal "Rack::Runtime", 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.first
assert_equal "Rack::Config", middleware.second
end
test "can't change middleware after it's built" do

@ -118,7 +118,7 @@ def test_should_not_eager_load_model_for_rake
end
def test_code_statistics_sanity
assert_match "Code LOC: 25 Test LOC: 0 Code to Test Ratio: 1:0.0",
assert_match "Code LOC: 32 Test LOC: 0 Code to Test Ratio: 1:0.0",
rails("stats")
end
@ -190,6 +190,7 @@ def test_scaffold_with_references_columns_tests_pass_by_default
rails "generate", "model", "Cart"
rails "generate", "scaffold", "LineItems", "product:references", "cart:belongs_to"
with_rails_env("test") { rails("db:migrate") }
rails("webpacker:compile")
output = rails("test")
assert_match(/7 runs, 9 assertions, 0 failures, 0 errors/, output)

@ -24,7 +24,7 @@ def test_help_command_work_inside_engine
def test_runner_command_work_inside_engine
output = capture(:stdout) do
Dir.chdir(plugin_path) { system("bin/rails runner 'puts Rails.env'") }
Dir.chdir(plugin_path) { system({ "SKIP_REQUIRE_WEBPACKER" => "true" }, "bin/rails runner 'puts Rails.env'") }
end
assert_equal "test", output.strip
@ -67,6 +67,7 @@ def plugin_path
def spawn_command(command, fd)
Process.spawn(
{ "SKIP_REQUIRE_WEBPACKER" => "true" },
"#{plugin_path}/bin/rails #{command}",
in: fd, out: fd, err: fd
)

@ -40,7 +40,6 @@ def test_api_modified_files
end
assert_file "Gemfile" do |content|
assert_no_match(/gem 'coffee-rails'/, content)
assert_no_match(/gem 'sass-rails'/, content)
assert_no_match(/gem 'web-console'/, content)
assert_no_match(/gem 'capybara'/, content)

@ -13,10 +13,9 @@
config.ru
app/assets/config/manifest.js
app/assets/images
app/assets/javascripts
app/assets/javascripts/application.js
app/assets/javascripts/cable.js
app/assets/javascripts/channels
app/javascript
app/javascript/channels
app/javascript/packs/application.js
app/assets/stylesheets
app/assets/stylesheets/application.css
app/channels/application_cable/channel.rb
@ -114,12 +113,12 @@ def test_skip_bundle
end
def test_assets
run_generator
run_generator [destination_root, "--no-skip-javascript"]
assert_file("app/views/layouts/application.html.erb", /stylesheet_link_tag\s+'application', media: 'all', 'data-turbolinks-track': 'reload'/)
assert_file("app/views/layouts/application.html.erb", /javascript_include_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/assets/javascripts/application.js")
assert_file("app/javascript/packs/application.js")
end
def test_application_job_file_present
@ -215,7 +214,8 @@ def test_new_application_doesnt_need_defaults
def test_new_application_load_defaults
app_root = File.join(destination_root, "myfirstapp")
run_generator [app_root]
run_generator [app_root, "--no-skip-javascript"]
output = nil
assert_file "#{app_root}/config/application.rb", /\s+config\.load_defaults #{Rails::VERSION::STRING.to_f}/
@ -559,7 +559,6 @@ def test_generator_has_assets_gems
run_generator
assert_gem "sass-rails"
assert_gem "uglifier"
end
def test_action_cable_redis_gems
@ -601,24 +600,6 @@ def test_does_not_generate_system_test_files_if_skip_system_test_is_given
end
end
def test_inclusion_of_javascript_runtime
run_generator
if defined?(JRUBY_VERSION)
assert_gem "therubyrhino"
elsif RUBY_PLATFORM =~ /mingw|mswin/
assert_gem "duktape"
else
assert_file "Gemfile", /# gem 'mini_racer', platforms: :ruby/
end
end
def test_rails_ujs_is_the_default_ujs_library
run_generator
assert_file "app/assets/javascripts/application.js" do |contents|
assert_match %r{^//= require rails-ujs}, contents
end
end
def test_javascript_is_skipped_if_required
run_generator [destination_root, "--skip-javascript"]
@ -628,22 +609,6 @@ def test_javascript_is_skipped_if_required
assert_match(/stylesheet_link_tag\s+'application', media: 'all' %>/, contents)
assert_no_match(/javascript_include_tag\s+'application' \%>/, contents)
end
assert_no_gem "coffee-rails"
assert_no_gem "uglifier"
assert_file "config/environments/production.rb" do |content|
assert_no_match(/config\.assets\.js_compressor = :uglifier/, content)
end
end
def test_coffeescript_is_skipped_if_required
run_generator [destination_root, "--skip-coffee"]
assert_file "Gemfile" do |content|
assert_no_match(/coffee-rails/, content)
assert_match(/uglifier/, content)
end
end
def test_inclusion_of_jbuilder
@ -819,22 +784,22 @@ def test_spring_with_dev_option
assert_no_gem "spring"
end
def test_webpack_option
def test_skip_javascript_option
command_check = -> command, *_ do
@called ||= 0
if command == "webpacker:install"
@called += 1
assert_equal 1, @called, "webpacker:install expected to be called once, but was called #{@called} times."
assert_equal 0, @called, "webpacker:install expected not to be called once, but was called #{@called} times."
end
end
generator([destination_root], webpack: "webpack").stub(:rails_command, command_check) do
generator([destination_root], skip_javascript: true).stub(:rails_command, command_check) do
generator.stub :bundle_command, nil do
quietly { generator.invoke_all }
end
end
assert_gem "webpacker"
assert_no_gem "webpacker"
end
def test_webpack_option_with_js_framework
@ -856,22 +821,24 @@ def test_webpack_option_with_js_framework
quietly { generator.invoke_all }
end
end
assert_gem "webpacker"
end
def test_generator_if_skip_turbolinks_is_given
run_generator [destination_root, "--skip-turbolinks"]
run_generator [destination_root, "--skip-turbolinks", "--no-skip-javascript"]
assert_no_gem "turbolinks"
assert_file "app/views/layouts/application.html.erb" do |content|
assert_no_match(/data-turbolinks-track/, content)
end
assert_file "app/assets/javascripts/application.js" do |content|
assert_file "app/javascript/packs/application.js" do |content|
assert_no_match(/turbolinks/, content)
end
end
def test_bootsnap
run_generator
run_generator [destination_root, "--no-skip-bootsnap"]
unless defined?(JRUBY_VERSION)
assert_gem "bootsnap"
@ -972,7 +939,7 @@ def test_after_bundle_callback
template
end
sequence = ["git init", "install", "binstubs bundler", "exec spring binstub --all", "echo ran after_bundle"]
sequence = ["git init", "install", "binstubs bundler", "exec spring binstub --all", "webpacker:install", "echo ran after_bundle"]
@sequence_step ||= 0
ensure_bundler_first = -> command, options = nil do
assert_equal sequence[@sequence_step], command, "commands should be called in sequence #{sequence}"
@ -989,7 +956,7 @@ def test_after_bundle_callback
end
end
assert_equal 5, @sequence_step
assert_equal 6, @sequence_step
end
def test_gitignore

@ -9,13 +9,11 @@ class AssetsGeneratorTest < Rails::Generators::TestCase
def test_assets
run_generator
assert_file "app/assets/javascripts/posts.js"
assert_file "app/assets/stylesheets/posts.css"
end
def test_skipping_assets
run_generator ["posts", "--no-stylesheets", "--no-javascripts"]
assert_no_file "app/assets/javascripts/posts.js"
run_generator ["posts", "--no-stylesheets"]
assert_no_file "app/assets/stylesheets/posts.css"
end
end

@ -26,8 +26,8 @@ def test_channel_is_created
assert_match(/class ChatChannel < ApplicationCable::Channel/, channel)
end
assert_file "app/assets/javascripts/channels/chat.js" do |channel|
assert_match(/App\.chat = App\.cable\.subscriptions\.create\("ChatChannel/, channel)
assert_file "app/javascript/channels/chat_channel.js" do |channel|
assert_match(/import consumer from "\.\/consumer"\s+consumer\.subscriptions\.create\("ChatChannel/, channel)
end
end
@ -40,8 +40,8 @@ def test_channel_with_multiple_actions_is_created
assert_match(/def mute/, channel)
end
assert_file "app/assets/javascripts/channels/chat.js" do |channel|
assert_match(/App\.chat = App\.cable\.subscriptions\.create\("ChatChannel/, channel)
assert_file "app/javascript/channels/chat_channel.js" do |channel|
assert_match(/import consumer from "\.\/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
@ -54,15 +54,17 @@ def test_channel_asset_is_not_created_when_skip_assets_is_passed
assert_match(/class ChatChannel < ApplicationCable::Channel/, channel)
end
assert_no_file "app/assets/javascripts/channels/chat.js"
assert_no_file "app/javascript/channels/chat_channel.js"
end
def test_cable_js_is_created_if_not_present_already
run_generator ["chat"]
FileUtils.rm("#{destination_root}/app/assets/javascripts/cable.js")
FileUtils.rm("#{destination_root}/app/javascript/channels/index.js")
FileUtils.rm("#{destination_root}/app/javascript/channels/consumer.js")
run_generator ["camp"]
assert_file "app/assets/javascripts/cable.js"
assert_file "app/javascript/channels/index.js"
assert_file "app/javascript/channels/consumer.js"
end
def test_channel_on_revoke
@ -74,7 +76,8 @@ def test_channel_on_revoke
assert_file "app/channels/application_cable/channel.rb"
assert_file "app/channels/application_cable/connection.rb"
assert_file "app/assets/javascripts/cable.js"
assert_file "app/javascript/channels/index.js"
assert_file "app/javascript/channels/consumer.js"
end
def test_channel_suffix_is_not_duplicated
@ -84,6 +87,6 @@ def test_channel_suffix_is_not_duplicated
assert_file "app/channels/chat_channel.rb"
assert_no_file "app/assets/javascripts/channels/chat_channel.js"
assert_file "app/assets/javascripts/channels/chat.js"
assert_file "app/javascript/channels/chat_channel.js"
end
end

@ -39,13 +39,11 @@ def test_does_not_invoke_helper_if_required
def test_invokes_assets
run_generator
assert_file "app/assets/javascripts/account.js"
assert_file "app/assets/stylesheets/account.css"
end
def test_does_not_invoke_assets_if_required
run_generator ["account", "--skip-assets"]
assert_no_file "app/assets/javascripts/account.js"
assert_no_file "app/assets/stylesheets/account.css"
end
@ -133,7 +131,6 @@ def test_controller_suffix_is_not_duplicated
assert_file "app/helpers/account_helper.rb"
assert_no_file "app/assets/javascripts/account_controller.js"
assert_file "app/assets/javascripts/account.js"
assert_no_file "app/assets/stylesheets/account_controller.css"
assert_file "app/assets/stylesheets/account.css"

@ -140,10 +140,6 @@ def test_generating_adds_dummy_app_without_javascript_and_assets_deps
run_generator
assert_file "test/dummy/app/assets/stylesheets/application.css"
assert_file "test/dummy/app/assets/javascripts/application.js" do |contents|
assert_no_match(/jquery/, contents)
end
end
def test_ensure_that_plugin_options_are_not_passed_to_app_generator
@ -210,28 +206,10 @@ def test_generation_does_not_run_bundle_install_with_full_and_mountable
assert_no_file "#{destination_root}/Gemfile.lock"
end
def test_skipping_javascripts_without_mountable_option
run_generator
assert_no_file "app/assets/javascripts/bukkits/application.js"
end
def test_javascripts_generation
run_generator [destination_root, "--mountable"]
assert_file "app/assets/javascripts/bukkits/application.js" do |content|
assert_match "//= require rails-ujs", content
assert_match "//= require activestorage", content
assert_match "//= require_tree .", content
end
assert_file "app/views/layouts/bukkits/application.html.erb" do |content|
assert_match "javascript_include_tag", content
end
end
def test_skip_javascripts
def test_skip_javascript
run_generator [destination_root, "--skip-javascript", "--mountable"]
assert_no_file "app/assets/javascripts/bukkits/application.js"
assert_file "app/views/layouts/bukkits/application.html.erb" do |content|
assert_no_match "javascript_include_tag", content
assert_no_match "javascript_pack_tag", content
end
end
@ -264,7 +242,6 @@ def test_ensure_that_migration_tasks_work_with_mountable_option
def test_creating_engine_in_full_mode
run_generator [destination_root, "--full"]
assert_file "app/assets/javascripts/bukkits"
assert_file "app/assets/stylesheets/bukkits"
assert_file "app/assets/images/bukkits"
assert_file "app/models"
@ -280,7 +257,7 @@ def test_creating_engine_in_full_mode
def test_creating_engine_with_hyphenated_name_in_full_mode
run_generator [File.join(destination_root, "hyphenated-name"), "--full"]
assert_file "hyphenated-name/app/assets/javascripts/hyphenated/name"
assert_no_file "hyphenated-name/app/assets/javascripts/hyphenated/name"
assert_file "hyphenated-name/app/assets/stylesheets/hyphenated/name"
assert_file "hyphenated-name/app/assets/images/hyphenated/name"
assert_file "hyphenated-name/app/models"
@ -297,7 +274,7 @@ def test_creating_engine_with_hyphenated_name_in_full_mode
def test_creating_engine_with_hyphenated_and_underscored_name_in_full_mode
run_generator [File.join(destination_root, "my_hyphenated-name"), "--full"]
assert_file "my_hyphenated-name/app/assets/javascripts/my_hyphenated/name"
assert_no_file "my_hyphenated-name/app/assets/javascripts/my_hyphenated/name"
assert_file "my_hyphenated-name/app/assets/stylesheets/my_hyphenated/name"
assert_file "my_hyphenated-name/app/assets/images/my_hyphenated/name"
assert_file "my_hyphenated-name/app/models"
@ -318,7 +295,7 @@ def test_being_quiet_while_creating_dummy_application
def test_create_mountable_application_with_mountable_option
run_generator [destination_root, "--mountable"]
assert_file "app/assets/javascripts/bukkits"
assert_no_file "app/assets/javascripts/bukkits"
assert_file "app/assets/stylesheets/bukkits"
assert_file "app/assets/images/bukkits"
assert_file "config/routes.rb", /Bukkits::Engine\.routes\.draw do/
@ -334,7 +311,7 @@ def test_create_mountable_application_with_mountable_option
assert_match "<%= csrf_meta_tags %>", contents
assert_match "<%= csp_meta_tag %>", contents
assert_match(/stylesheet_link_tag\s+['"]bukkits\/application['"]/, contents)
assert_match(/javascript_include_tag\s+['"]bukkits\/application['"]/, contents)
assert_no_match(/javascript_include_tag\s+['"]bukkits\/application['"]/, contents)
assert_match "<%= yield %>", contents
end
assert_file "test/test_helper.rb" do |content|
@ -348,7 +325,7 @@ def test_create_mountable_application_with_mountable_option
def test_create_mountable_application_with_mountable_option_and_hypenated_name
run_generator [File.join(destination_root, "hyphenated-name"), "--mountable"]
assert_file "hyphenated-name/app/assets/javascripts/hyphenated/name"
assert_no_file "hyphenated-name/app/assets/javascripts/hyphenated/name"
assert_file "hyphenated-name/app/assets/stylesheets/hyphenated/name"
assert_file "hyphenated-name/app/assets/images/hyphenated/name"
assert_file "hyphenated-name/config/routes.rb", /Hyphenated::Name::Engine\.routes\.draw do/
@ -364,13 +341,13 @@ def test_create_mountable_application_with_mountable_option_and_hypenated_name
assert_file "hyphenated-name/app/views/layouts/hyphenated/name/application.html.erb" do |contents|
assert_match "<title>Hyphenated name</title>", contents
assert_match(/stylesheet_link_tag\s+['"]hyphenated\/name\/application['"]/, contents)
assert_match(/javascript_include_tag\s+['"]hyphenated\/name\/application['"]/, contents)
assert_no_match(/javascript_include_tag\s+['"]hyphenated\/name\/application['"]/, contents)
end
end
def test_create_mountable_application_with_mountable_option_and_hypenated_and_underscored_name
run_generator [File.join(destination_root, "my_hyphenated-name"), "--mountable"]
assert_file "my_hyphenated-name/app/assets/javascripts/my_hyphenated/name"
assert_no_file "my_hyphenated-name/app/assets/javascripts/my_hyphenated/name"
assert_file "my_hyphenated-name/app/assets/stylesheets/my_hyphenated/name"
assert_file "my_hyphenated-name/app/assets/images/my_hyphenated/name"
assert_file "my_hyphenated-name/config/routes.rb", /MyHyphenated::Name::Engine\.routes\.draw do/
@ -386,13 +363,13 @@ def test_create_mountable_application_with_mountable_option_and_hypenated_and_un
assert_file "my_hyphenated-name/app/views/layouts/my_hyphenated/name/application.html.erb" do |contents|
assert_match "<title>My hyphenated name</title>", contents
assert_match(/stylesheet_link_tag\s+['"]my_hyphenated\/name\/application['"]/, contents)
assert_match(/javascript_include_tag\s+['"]my_hyphenated\/name\/application['"]/, contents)
assert_no_match(/javascript_include_tag\s+['"]my_hyphenated\/name\/application['"]/, contents)
end
end
def test_create_mountable_application_with_mountable_option_and_multiple_hypenates_in_name
run_generator [File.join(destination_root, "deep-hyphenated-name"), "--mountable"]
assert_file "deep-hyphenated-name/app/assets/javascripts/deep/hyphenated/name"
assert_no_file "deep-hyphenated-name/app/assets/javascripts/deep/hyphenated/name"
assert_file "deep-hyphenated-name/app/assets/stylesheets/deep/hyphenated/name"
assert_file "deep-hyphenated-name/app/assets/images/deep/hyphenated/name"
assert_file "deep-hyphenated-name/config/routes.rb", /Deep::Hyphenated::Name::Engine\.routes\.draw do/
@ -408,7 +385,7 @@ def test_create_mountable_application_with_mountable_option_and_multiple_hypenat
assert_file "deep-hyphenated-name/app/views/layouts/deep/hyphenated/name/application.html.erb" do |contents|
assert_match "<title>Deep hyphenated name</title>", contents
assert_match(/stylesheet_link_tag\s+['"]deep\/hyphenated\/name\/application['"]/, contents)
assert_match(/javascript_include_tag\s+['"]deep\/hyphenated\/name\/application['"]/, contents)
assert_no_match(/javascript_include_tag\s+['"]deep\/hyphenated\/name\/application['"]/, contents)
end
end

@ -93,7 +93,6 @@ def test_scaffold_on_invoke
# Assets
assert_file "app/assets/stylesheets/scaffold.css"
assert_file "app/assets/javascripts/product_lines.js"
assert_file "app/assets/stylesheets/product_lines.css"
end
@ -166,7 +165,6 @@ def test_api_scaffold_on_invoke
# Assets
assert_no_file "app/assets/stylesheets/scaffold.css"
assert_no_file "app/assets/javascripts/product_lines.js"
assert_no_file "app/assets/stylesheets/product_lines.css"
end
@ -222,7 +220,6 @@ def test_scaffold_on_revoke
# Assets
assert_file "app/assets/stylesheets/scaffold.css", /:visited/
assert_no_file "app/assets/javascripts/product_lines.js"
assert_no_file "app/assets/stylesheets/product_lines.css"
end
@ -299,7 +296,6 @@ def test_scaffold_with_namespace_on_invoke
# Assets
assert_file "app/assets/stylesheets/scaffold.css", /:visited/
assert_file "app/assets/javascripts/admin/roles.js"
assert_file "app/assets/stylesheets/admin/roles.css"
end
@ -335,7 +331,6 @@ def test_scaffold_with_namespace_on_revoke
# Assets
assert_file "app/assets/stylesheets/scaffold.css"
assert_no_file "app/assets/javascripts/admin/roles.js"
assert_no_file "app/assets/stylesheets/admin/roles.css"
end
@ -380,28 +375,24 @@ def test_scaffold_generator_ignores_commented_routes
def test_scaffold_generator_no_assets_with_switch_no_assets
run_generator [ "posts", "--no-assets" ]
assert_no_file "app/assets/stylesheets/scaffold.css"
assert_no_file "app/assets/javascripts/posts.js"
assert_no_file "app/assets/stylesheets/posts.css"
end
def test_scaffold_generator_no_assets_with_switch_assets_false
run_generator [ "posts", "--assets=false" ]
assert_no_file "app/assets/stylesheets/scaffold.css"
assert_no_file "app/assets/javascripts/posts.js"
assert_no_file "app/assets/stylesheets/posts.css"
end
def test_scaffold_generator_no_scaffold_stylesheet_with_switch_no_scaffold_stylesheet
run_generator [ "posts", "--no-scaffold-stylesheet" ]
assert_no_file "app/assets/stylesheets/scaffold.css"
assert_file "app/assets/javascripts/posts.js"
assert_file "app/assets/stylesheets/posts.css"
end
def test_scaffold_generator_no_scaffold_stylesheet_with_switch_scaffold_stylesheet_false
run_generator [ "posts", "--scaffold-stylesheet=false" ]
assert_no_file "app/assets/stylesheets/scaffold.css"
assert_file "app/assets/javascripts/posts.js"
assert_file "app/assets/stylesheets/posts.css"
end
@ -429,17 +420,9 @@ def test_scaffold_generator_no_helper_with_switch_helper_false
def test_scaffold_generator_no_stylesheets
run_generator [ "posts", "--no-stylesheets" ]
assert_no_file "app/assets/stylesheets/scaffold.css"
assert_file "app/assets/javascripts/posts.js"
assert_no_file "app/assets/stylesheets/posts.css"
end
def test_scaffold_generator_no_javascripts
run_generator [ "posts", "--no-javascripts" ]
assert_file "app/assets/stylesheets/scaffold.css"
assert_no_file "app/assets/javascripts/posts.js"
assert_file "app/assets/stylesheets/posts.css"
end
def test_scaffold_generator_outputs_error_message_on_missing_attribute_type
run_generator ["post", "title", "body:text", "author"]
@ -630,7 +613,6 @@ def test_scaffold_on_invoke_inside_mountable_engine
assert File.exist?("app/helpers/bukkits/users_helper.rb")
assert File.exist?("app/assets/javascripts/bukkits/users.js")
assert File.exist?("app/assets/stylesheets/bukkits/users.css")
end
end
@ -660,7 +642,6 @@ def test_scaffold_on_revoke_inside_mountable_engine
assert_not File.exist?("app/helpers/bukkits/users_helper.rb")
assert_not File.exist?("app/assets/javascripts/bukkits/users.js")
assert_not File.exist?("app/assets/stylesheets/bukkits/users.css")
end
end

@ -27,7 +27,7 @@ def application_path
end
def test_skeleton_is_created
run_generator
run_generator [destination_root, "--no-skip-javascript"]
default_files.each { |path| assert_file path }
end
@ -196,10 +196,12 @@ def test_generator_if_skip_active_record_is_given
end
def test_generator_for_active_storage
run_generator
run_generator [destination_root, "--no-skip-javascript"]
assert_file "#{application_path}/app/assets/javascripts/application.js" do |content|
assert_match(/^\/\/= require activestorage/, content)
unless generator_class.name == "Rails::Generators::PluginGenerator"
assert_file "#{application_path}/app/javascript/packs/application.js" do |content|
assert_match(/^import \* as ActiveStorage from "activestorage"\nActiveStorage.start\(\)/, content)
end
end
assert_file "#{application_path}/config/environments/development.rb" do |content|
@ -224,11 +226,11 @@ def test_generator_for_active_storage
end
def test_generator_if_skip_active_storage_is_given
run_generator [destination_root, "--skip-active-storage"]
run_generator [destination_root, "--skip-active-storage", "--no-skip-javascript"]
assert_file "#{application_path}/config/application.rb", /#\s+require\s+["']active_storage\/engine["']/
assert_file "#{application_path}/app/assets/javascripts/application.js" do |content|
assert_file "#{application_path}/app/javascript/packs/application.js" do |content|
assert_no_match(/^\/\/= require activestorage/, content)
end
@ -254,12 +256,12 @@ def test_generator_if_skip_active_storage_is_given
end
def test_generator_does_not_generate_active_storage_contents_if_skip_active_record_is_given
run_generator [destination_root, "--skip-active-record"]
run_generator [destination_root, "--skip-active-record", "--no-skip-javascript"]
assert_file "#{application_path}/config/application.rb", /#\s+require\s+["']active_storage\/engine["']/
assert_file "#{application_path}/app/assets/javascripts/application.js" do |content|
assert_no_match(/^\/\/= require activestorage/, content)
assert_file "#{application_path}/app/javascript/packs/application.js" do |content|
assert_no_match(/^import * as ActiveStorage from "activestorage"\nActiveStorage.start()/, content)
end
assert_file "#{application_path}/config/environments/development.rb" do |content|
@ -320,8 +322,6 @@ def test_generator_if_skip_sprockets_is_given
assert_file "Gemfile" do |content|
assert_no_match(/sass-rails/, content)
assert_no_match(/uglifier/, content)
assert_no_match(/coffee-rails/, content)
end
assert_file "#{application_path}/config/environments/development.rb" do |content|
@ -330,7 +330,6 @@ def test_generator_if_skip_sprockets_is_given
assert_file "#{application_path}/config/environments/production.rb" do |content|
assert_no_match(/config\.assets\.digest/, content)
assert_no_match(/config\.assets\.js_compressor/, content)
assert_no_match(/config\.assets\.css_compressor/, content)
assert_no_match(/config\.assets\.compile/, content)
end

@ -30,11 +30,11 @@
module TestHelpers
module Paths
def app_template_path
File.join Dir.tmpdir, "app_template"
File.join RAILS_FRAMEWORK_ROOT, "tmp/templates/app_template"
end
def tmp_path(*args)
@tmp_path ||= File.realpath(Dir.mktmpdir)
@tmp_path ||= File.realpath(Dir.mktmpdir(nil, File.join(RAILS_FRAMEWORK_ROOT, "tmp")))
File.join(@tmp_path, *args)
end
@ -469,17 +469,28 @@ def frozen_error_class
# Build a rails app
FileUtils.rm_rf(app_template_path)
FileUtils.mkdir(app_template_path)
FileUtils.mkdir_p(app_template_path)
Dir.chdir "#{RAILS_FRAMEWORK_ROOT}/actionview" do
`yarn build`
end
`#{Gem.ruby} #{RAILS_FRAMEWORK_ROOT}/railties/exe/rails new #{app_template_path} --skip-gemfile --skip-listen --no-rc`
File.open("#{app_template_path}/config/boot.rb", "w") do |f|
f.puts "require 'rails/all'"
end
Dir.chdir(app_template_path) { `yarn add https://github.com/rails/webpacker.git` } # Use the latest version.
# Manually install `webpack` as bin symlinks are not created for subdependencies
# in workspaces. See https://github.com/yarnpkg/yarn/issues/4964
Dir.chdir(app_template_path) { `yarn add webpack@4.17.1 --tilde` }
Dir.chdir(app_template_path) { `yarn add webpack-cli` }
# 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).each { |r| require r }")
contents.sub!(/^Bundler\.require.*/, "%w(turbolinks webpacker).each { |r| require r }")
File.write("#{app_template_path}/config/application.rb", contents)
require "rails"