webpacker 4.0.7 → 4.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.node-version +1 -1
  3. data/.rubocop.yml +2 -1
  4. data/.travis.yml +7 -4
  5. data/CHANGELOG.md +226 -137
  6. data/Gemfile.lock +78 -59
  7. data/README.md +110 -3
  8. data/docs/css.md +12 -0
  9. data/docs/deployment.md +38 -9
  10. data/docs/docker.md +25 -6
  11. data/docs/engines.md +40 -3
  12. data/docs/es6.md +19 -1
  13. data/docs/troubleshooting.md +37 -9
  14. data/docs/typescript.md +8 -5
  15. data/docs/webpack-dev-server.md +1 -1
  16. data/docs/webpack.md +18 -3
  17. data/gemfiles/Gemfile-rails.6.0.x +9 -0
  18. data/lib/install/bin/webpack +0 -1
  19. data/lib/install/bin/webpack-dev-server +0 -1
  20. data/lib/install/coffee.rb +1 -1
  21. data/lib/install/config/babel.config.js +10 -10
  22. data/lib/install/config/webpacker.yml +2 -1
  23. data/lib/install/elm.rb +1 -1
  24. data/lib/install/erb.rb +2 -2
  25. data/lib/install/examples/angular/hello_angular/polyfills.ts +2 -2
  26. data/lib/install/examples/react/babel.config.js +16 -14
  27. data/lib/install/examples/svelte/app.svelte +11 -0
  28. data/lib/install/examples/svelte/hello_svelte.js +20 -0
  29. data/lib/install/loaders/elm.js +9 -6
  30. data/lib/install/loaders/svelte.js +9 -0
  31. data/lib/install/loaders/typescript.js +1 -1
  32. data/lib/install/svelte.rb +29 -0
  33. data/lib/install/template.rb +1 -1
  34. data/lib/install/typescript.rb +1 -1
  35. data/lib/install/vue.rb +1 -1
  36. data/lib/tasks/installers.rake +1 -0
  37. data/lib/tasks/webpacker.rake +2 -0
  38. data/lib/tasks/webpacker/clean.rake +19 -0
  39. data/lib/tasks/webpacker/compile.rake +2 -10
  40. data/lib/tasks/webpacker/yarn_install.rake +15 -0
  41. data/lib/webpacker.rb +9 -1
  42. data/lib/webpacker/commands.rb +29 -1
  43. data/lib/webpacker/compiler.rb +15 -8
  44. data/lib/webpacker/configuration.rb +9 -1
  45. data/lib/webpacker/dev_server.rb +1 -1
  46. data/lib/webpacker/dev_server_proxy.rb +2 -8
  47. data/lib/webpacker/env.rb +1 -1
  48. data/lib/webpacker/helper.rb +39 -13
  49. data/lib/webpacker/railtie.rb +6 -0
  50. data/lib/webpacker/version.rb +1 -1
  51. data/package.json +36 -36
  52. data/package/__tests__/config.js +0 -23
  53. data/package/config.js +2 -10
  54. data/package/config_types/config_list.js +3 -3
  55. data/package/config_types/config_object.js +1 -1
  56. data/package/environments/base.js +2 -2
  57. data/package/environments/development.js +1 -1
  58. data/package/environments/production.js +12 -0
  59. data/package/rules/babel.js +1 -1
  60. data/package/rules/node_modules.js +2 -2
  61. data/package/rules/sass.js +1 -1
  62. data/package/utils/__tests__/get_style_rule.js +9 -0
  63. data/package/utils/deep_merge.js +5 -5
  64. data/package/utils/get_style_rule.js +7 -12
  65. data/package/utils/helpers.js +9 -9
  66. data/test/command_test.rb +6 -0
  67. data/test/compiler_test.rb +5 -6
  68. data/test/configuration_test.rb +36 -27
  69. data/test/dev_server_test.rb +22 -0
  70. data/test/helper_test.rb +34 -0
  71. data/test/rake_tasks_test.rb +6 -0
  72. data/test/test_app/bin/webpack +0 -1
  73. data/test/test_app/bin/webpack-dev-server +0 -1
  74. data/test/test_app/config/webpacker.yml +1 -0
  75. data/test/test_app/public/packs/manifest.json +3 -0
  76. data/webpacker.gemspec +1 -0
  77. data/yarn.lock +1934 -1634
  78. metadata +24 -4
@@ -38,8 +38,8 @@
38
38
  // import 'classlist.js'; // Run `npm install --save classlist.js`.
39
39
 
40
40
  /** Evergreen browsers require these. **/
41
- import 'core-js/es6/reflect';
42
- import 'core-js/es7/reflect';
41
+ import 'core-js/es/reflect';
42
+ import 'core-js/proposals/reflect-metadata';
43
43
 
44
44
 
45
45
  /**
@@ -18,15 +18,17 @@ module.exports = function(api) {
18
18
  return {
19
19
  presets: [
20
20
  isTestEnv && [
21
- require('@babel/preset-env').default,
21
+ '@babel/preset-env',
22
22
  {
23
23
  targets: {
24
24
  node: 'current'
25
- }
26
- }
25
+ },
26
+ modules: 'commonjs'
27
+ },
28
+ '@babel/preset-react'
27
29
  ],
28
30
  (isProductionEnv || isDevelopmentEnv) && [
29
- require('@babel/preset-env').default,
31
+ '@babel/preset-env',
30
32
  {
31
33
  forceAllTransforms: true,
32
34
  useBuiltIns: 'entry',
@@ -36,7 +38,7 @@ module.exports = function(api) {
36
38
  }
37
39
  ],
38
40
  [
39
- require('@babel/preset-react').default,
41
+ '@babel/preset-react',
40
42
  {
41
43
  development: isDevelopmentEnv || isTestEnv,
42
44
  useBuiltIns: true
@@ -44,24 +46,24 @@ module.exports = function(api) {
44
46
  ]
45
47
  ].filter(Boolean),
46
48
  plugins: [
47
- require('babel-plugin-macros'),
48
- require('@babel/plugin-syntax-dynamic-import').default,
49
- isTestEnv && require('babel-plugin-dynamic-import-node'),
50
- require('@babel/plugin-transform-destructuring').default,
49
+ 'babel-plugin-macros',
50
+ '@babel/plugin-syntax-dynamic-import',
51
+ isTestEnv && 'babel-plugin-dynamic-import-node',
52
+ '@babel/plugin-transform-destructuring',
51
53
  [
52
- require('@babel/plugin-proposal-class-properties').default,
54
+ '@babel/plugin-proposal-class-properties',
53
55
  {
54
56
  loose: true
55
57
  }
56
58
  ],
57
59
  [
58
- require('@babel/plugin-proposal-object-rest-spread').default,
60
+ '@babel/plugin-proposal-object-rest-spread',
59
61
  {
60
62
  useBuiltIns: true
61
63
  }
62
64
  ],
63
65
  [
64
- require('@babel/plugin-transform-runtime').default,
66
+ '@babel/plugin-transform-runtime',
65
67
  {
66
68
  helpers: false,
67
69
  regenerator: true,
@@ -69,13 +71,13 @@ module.exports = function(api) {
69
71
  }
70
72
  ],
71
73
  [
72
- require('@babel/plugin-transform-regenerator').default,
74
+ '@babel/plugin-transform-regenerator',
73
75
  {
74
76
  async: false
75
77
  }
76
78
  ],
77
79
  isProductionEnv && [
78
- require('babel-plugin-transform-react-remove-prop-types').default,
80
+ 'babel-plugin-transform-react-remove-prop-types',
79
81
  {
80
82
  removeImport: true
81
83
  }
@@ -0,0 +1,11 @@
1
+ <script>
2
+ export let name;
3
+ </script>
4
+
5
+ <style>
6
+ h1 {
7
+ color: #FF3E00;
8
+ }
9
+ </style>
10
+
11
+ <h1>Hello {name}!</h1>
@@ -0,0 +1,20 @@
1
+ /* eslint no-console: 0 */
2
+ // Run this example by adding <%= javascript_pack_tag 'hello_svelte' %> (and
3
+ // <%= stylesheet_pack_tag 'hello_svelte' %> if you have styles in your component)
4
+ // to the head of your layout file,
5
+ // like app/views/layouts/application.html.erb.
6
+ // All it does is render <div>Hello Svelte!</div> at the bottom of the page.
7
+
8
+ import App from '../app.svelte'
9
+
10
+ document.addEventListener('DOMContentLoaded', () => {
11
+ const app = new App({
12
+ target: document.body,
13
+ props: {
14
+ name: 'Svelte'
15
+ }
16
+ });
17
+
18
+ window.app = app;
19
+ })
20
+
@@ -1,18 +1,21 @@
1
1
  const { resolve } = require('path')
2
2
 
3
3
  const isProduction = process.env.NODE_ENV === 'production'
4
+ const isDevelopment = process.env.NODE_ENV === 'development'
4
5
  const elmSource = resolve(process.cwd())
5
6
  const elmBinary = `${elmSource}/node_modules/.bin/elm`
6
7
 
7
- const elmDefaultOptions = { cwd: elmSource, pathToElm: elmBinary }
8
- const developmentOptions = Object.assign({}, elmDefaultOptions, {
9
- verbose: true,
10
- debug: true
11
- })
8
+ const options = {
9
+ cwd: elmSource,
10
+ pathToElm: elmBinary,
11
+ optimize: isProduction,
12
+ verbose: isDevelopment,
13
+ debug: isDevelopment
14
+ }
12
15
 
13
16
  const elmWebpackLoader = {
14
17
  loader: 'elm-webpack-loader',
15
- options: isProduction ? elmDefaultOptions : developmentOptions
18
+ options: options
16
19
  }
17
20
 
18
21
  module.exports = {
@@ -0,0 +1,9 @@
1
+ module.exports = {
2
+ test: /\.svelte$/,
3
+ use: [{
4
+ loader: 'svelte-loader',
5
+ options: {
6
+ hotReload: true
7
+ }
8
+ }],
9
+ }
@@ -1,7 +1,7 @@
1
1
  const PnpWebpackPlugin = require('pnp-webpack-plugin')
2
2
 
3
3
  module.exports = {
4
- test: /\.(ts|tsx)?(\.erb)?$/,
4
+ test: /\.tsx?(\.erb)?$/,
5
5
  use: [
6
6
  {
7
7
  loader: 'ts-loader',
@@ -0,0 +1,29 @@
1
+ require "webpacker/configuration"
2
+
3
+ say "Copying svelte loader to config/webpack/loaders"
4
+ copy_file "#{__dir__}/loaders/svelte.js", Rails.root.join("config/webpack/loaders/svelte.js").to_s
5
+
6
+ say "Adding svelte loader to config/webpack/environment.js"
7
+ insert_into_file Rails.root.join("config/webpack/environment.js").to_s,
8
+ "const svelte = require('./loaders/svelte')\n",
9
+ after: /require\(('|")@rails\/webpacker\1\);?\n/
10
+
11
+ insert_into_file Rails.root.join("config/webpack/environment.js").to_s,
12
+ "environment.loaders.prepend('svelte', svelte)\n",
13
+ before: "module.exports"
14
+
15
+ say "Copying Svelte example entry file to #{Webpacker.config.source_entry_path}"
16
+ copy_file "#{__dir__}/examples/svelte/hello_svelte.js",
17
+ "#{Webpacker.config.source_entry_path}/hello_svelte.js"
18
+
19
+ say "Copying Svelte app file to #{Webpacker.config.source_path}"
20
+ copy_file "#{__dir__}/examples/svelte/app.svelte",
21
+ "#{Webpacker.config.source_path}/app.svelte"
22
+
23
+ say "Installing all Svelte dependencies"
24
+ run "yarn add svelte svelte-loader"
25
+
26
+ say "Updating webpack paths to include .svelte file extension"
27
+ insert_into_file Webpacker.config.config_path, "- .svelte\n".indent(4), after: /\s+extensions:\n/
28
+
29
+ say "Webpacker now supports Svelte 🎉", :green
@@ -36,7 +36,7 @@ end
36
36
 
37
37
  if Webpacker::VERSION =~ /^[0-9]+\.[0-9]+\.[0-9]+$/
38
38
  say "Installing all JavaScript dependencies [#{Webpacker::VERSION}]"
39
- run "yarn add @rails/webpacker"
39
+ run "yarn add @rails/webpacker@#{Webpacker::VERSION}"
40
40
  else
41
41
  say "Installing all JavaScript dependencies [from prerelease rails/webpacker]"
42
42
  run "yarn add @rails/webpacker@next"
@@ -21,7 +21,7 @@ copy_file "#{__dir__}/loaders/typescript.js", Rails.root.join("config/webpack/lo
21
21
  say "Adding typescript loader to config/webpack/environment.js"
22
22
  insert_into_file Rails.root.join("config/webpack/environment.js").to_s,
23
23
  "const typescript = require('./loaders/typescript')\n",
24
- after: "require('@rails/webpacker')\n"
24
+ after: /require\(('|")@rails\/webpacker\1\);?\n/
25
25
 
26
26
  insert_into_file Rails.root.join("config/webpack/environment.js").to_s,
27
27
  "environment.loaders.prepend('typescript', typescript)\n",
@@ -6,7 +6,7 @@ copy_file "#{__dir__}/loaders/vue.js", Rails.root.join("config/webpack/loaders/v
6
6
  say "Adding vue loader plugin to config/webpack/environment.js"
7
7
  insert_into_file Rails.root.join("config/webpack/environment.js").to_s,
8
8
  "const { VueLoaderPlugin } = require('vue-loader')\n",
9
- after: "require('@rails/webpacker')\n"
9
+ after: /require\(('|")@rails\/webpacker\1\);?\n/
10
10
 
11
11
  insert_into_file Rails.root.join("config/webpack/environment.js").to_s,
12
12
  "environment.plugins.prepend('VueLoaderPlugin', new VueLoaderPlugin())\n",
@@ -6,6 +6,7 @@ installers = {
6
6
  "Erb": :erb,
7
7
  "Coffee": :coffee,
8
8
  "Typescript": :typescript,
9
+ "Svelte": :svelte,
9
10
  "Stimulus": :stimulus
10
11
  }.freeze
11
12
 
@@ -2,6 +2,7 @@ tasks = {
2
2
  "webpacker:info" => "Provides information on Webpacker's environment",
3
3
  "webpacker:install" => "Installs and setup webpack with Yarn",
4
4
  "webpacker:compile" => "Compiles webpack bundles based on environment",
5
+ "webpacker:clean" => "Remove old compiled webpacks",
5
6
  "webpacker:clobber" => "Removes the webpack compiled output directory",
6
7
  "webpacker:check_node" => "Verifies if Node.js is installed",
7
8
  "webpacker:check_yarn" => "Verifies if Yarn is installed",
@@ -13,6 +14,7 @@ tasks = {
13
14
  "webpacker:install:vue" => "Installs and setup example Vue component",
14
15
  "webpacker:install:angular" => "Installs and setup example Angular component",
15
16
  "webpacker:install:elm" => "Installs and setup example Elm component",
17
+ "webpacker:install:svelte" => "Installs and setup example Svelte component",
16
18
  "webpacker:install:stimulus" => "Installs and setup example Stimulus component",
17
19
  "webpacker:install:erb" => "Installs Erb loader with an example",
18
20
  "webpacker:install:coffee" => "Installs CoffeeScript loader with an example",
@@ -0,0 +1,19 @@
1
+ $stdout.sync = true
2
+
3
+ require "webpacker/configuration"
4
+
5
+ namespace :webpacker do
6
+ desc "Remove old compiled webpacks"
7
+ task :clean, [:keep] => ["webpacker:verify_install", :environment] do |_, args|
8
+ Webpacker.ensure_log_goes_to_stdout do
9
+ Webpacker.clean(Integer(args.keep || 2))
10
+ end
11
+ end
12
+ end
13
+
14
+ # Run clean if the assets:clean is run
15
+ if Rake::Task.task_defined?("assets:clean")
16
+ Rake::Task["assets:clean"].enhance do
17
+ Rake::Task["webpacker:clean"].invoke
18
+ end
19
+ end
@@ -1,13 +1,5 @@
1
1
  $stdout.sync = true
2
2
 
3
- def ensure_log_goes_to_stdout
4
- old_logger = Webpacker.logger
5
- Webpacker.logger = ActiveSupport::Logger.new(STDOUT)
6
- yield
7
- ensure
8
- Webpacker.logger = old_logger
9
- end
10
-
11
3
  def yarn_install_available?
12
4
  rails_major = Rails::VERSION::MAJOR
13
5
  rails_minor = Rails::VERSION::MINOR
@@ -26,8 +18,8 @@ end
26
18
  namespace :webpacker do
27
19
  desc "Compile JavaScript packs using webpack for production with digests"
28
20
  task compile: ["webpacker:verify_install", :environment] do
29
- Webpacker.with_node_env("production") do
30
- ensure_log_goes_to_stdout do
21
+ Webpacker.with_node_env(ENV.fetch("NODE_ENV", "production")) do
22
+ Webpacker.ensure_log_goes_to_stdout do
31
23
  if Webpacker.compile
32
24
  # Successful compilation!
33
25
  else
@@ -2,5 +2,20 @@ namespace :webpacker do
2
2
  desc "Support for older Rails versions. Install all JavaScript dependencies as specified via Yarn"
3
3
  task :yarn_install do
4
4
  system "yarn install --no-progress"
5
+
6
+ exit(1) unless $?.success?
5
7
  end
6
8
  end
9
+
10
+ def enhance_yarn_install
11
+ Rake::Task["yarn:install"].enhance do
12
+ exit(1) unless $?.success?
13
+ end
14
+ end
15
+
16
+ if Rake::Task.task_defined?("yarn:install")
17
+ enhance_yarn_install
18
+ else
19
+ # this is mainly for pre-5.x era
20
+ Rake::Task.define_task("yarn:install" => "webpacker:yarn_install")
21
+ end
@@ -22,9 +22,17 @@ module Webpacker
22
22
  ENV["NODE_ENV"] = original
23
23
  end
24
24
 
25
+ def ensure_log_goes_to_stdout
26
+ old_logger = Webpacker.logger
27
+ Webpacker.logger = ActiveSupport::Logger.new(STDOUT)
28
+ yield
29
+ ensure
30
+ Webpacker.logger = old_logger
31
+ end
32
+
25
33
  delegate :logger, :logger=, :env, to: :instance
26
34
  delegate :config, :compiler, :manifest, :commands, :dev_server, to: :instance
27
- delegate :bootstrap, :clobber, :compile, to: :commands
35
+ delegate :bootstrap, :clean, :clobber, :compile, to: :commands
28
36
  end
29
37
 
30
38
  require "webpacker/instance"
@@ -1,10 +1,21 @@
1
1
  class Webpacker::Commands
2
- delegate :config, :compiler, :manifest, to: :@webpacker
2
+ delegate :config, :compiler, :manifest, :logger, to: :@webpacker
3
3
 
4
4
  def initialize(webpacker)
5
5
  @webpacker = webpacker
6
6
  end
7
7
 
8
+ def clean(count = 2)
9
+ if config.public_output_path.exist? && config.public_manifest_path.exist? && versions.count > count
10
+ versions.drop(count).flat_map(&:last).each do |file|
11
+ File.delete(file) if File.file?(file)
12
+ logger.info "Removed #{file}"
13
+ end
14
+ end
15
+
16
+ true
17
+ end
18
+
8
19
  def clobber
9
20
  config.public_output_path.rmtree if config.public_output_path.exist?
10
21
  config.cache_path.rmtree if config.cache_path.exist?
@@ -19,4 +30,21 @@ class Webpacker::Commands
19
30
  manifest.refresh if success
20
31
  end
21
32
  end
33
+
34
+ private
35
+ def versions
36
+ all_files = Dir.glob("#{config.public_output_path}/**/*")
37
+ manifest_config = Dir.glob("#{config.public_manifest_path}*")
38
+
39
+ packs = all_files - manifest_config - current_version
40
+ packs.group_by { |file| File.mtime(file).utc.to_i }.sort.reverse
41
+ end
42
+
43
+ def current_version
44
+ manifest.refresh.values.map do |value|
45
+ next if value.is_a?(Hash)
46
+
47
+ File.join(config.root_path, "public", value)
48
+ end.compact
49
+ end
22
50
  end
@@ -19,9 +19,15 @@ class Webpacker::Compiler
19
19
  def compile
20
20
  if stale?
21
21
  run_webpack.tap do |success|
22
- record_compilation_digest if success
22
+ # We used to only record the digest on success
23
+ # However, the output file is still written on error, (at least with ts-loader), meaning that the
24
+ # digest should still be updated. If it's not, you can end up in a situation where a recompile doesn't
25
+ # take place when it should.
26
+ # See https://github.com/rails/webpacker/issues/2113
27
+ record_compilation_digest
23
28
  end
24
29
  else
30
+ logger.info "Everything's up-to-date. Nothing to do"
25
31
  true
26
32
  end
27
33
  end
@@ -56,7 +62,7 @@ class Webpacker::Compiler
56
62
  end
57
63
 
58
64
  def run_webpack
59
- logger.info "Compiling"
65
+ logger.info "Compiling..."
60
66
 
61
67
  stdout, stderr, status = Open3.capture3(
62
68
  webpack_env,
@@ -67,12 +73,13 @@ class Webpacker::Compiler
67
73
  if status.success?
68
74
  logger.info "Compiled all packs in #{config.public_output_path}"
69
75
  logger.error "#{stderr}" unless stderr.empty?
70
- else
71
- logger.error "Compilation failed:\n#{stderr}"
72
- end
73
76
 
74
- if config.webpack_compile_output?
75
- logger.info stdout
77
+ if config.webpack_compile_output?
78
+ logger.info stdout
79
+ end
80
+ else
81
+ non_empty_streams = [stdout, stderr].delete_if(&:empty?)
82
+ logger.error "Compilation failed:\n#{non_empty_streams.join("\n\n")}"
76
83
  end
77
84
 
78
85
  status.success?
@@ -81,7 +88,7 @@ class Webpacker::Compiler
81
88
  def default_watched_paths
82
89
  [
83
90
  *config.resolved_paths_globbed,
84
- "#{config.source_path.relative_path_from(config.root_path)}/**/*",
91
+ config.source_path_globbed,
85
92
  "yarn.lock", "package.json",
86
93
  "config/webpack/**/*"
87
94
  ].freeze
@@ -23,12 +23,16 @@ class Webpacker::Configuration
23
23
  root_path.join(fetch(:source_path))
24
24
  end
25
25
 
26
+ def source_path_globbed
27
+ globbed_path_with_extensions(source_path.relative_path_from(root_path))
28
+ end
29
+
26
30
  def resolved_paths
27
31
  fetch(:resolved_paths)
28
32
  end
29
33
 
30
34
  def resolved_paths_globbed
31
- resolved_paths.map { |p| "#{p}/**/*" }
35
+ resolved_paths.map { |p| globbed_path_with_extensions(p) }
32
36
  end
33
37
 
34
38
  def source_entry_path
@@ -102,4 +106,8 @@ class Webpacker::Configuration
102
106
  @defaults ||= \
103
107
  HashWithIndifferentAccess.new(YAML.load_file(File.expand_path("../../install/config/webpacker.yml", __FILE__))[env])
104
108
  end
109
+
110
+ def globbed_path_with_extensions(path)
111
+ "#{path}/**/*{#{extensions.join(',')}}"
112
+ end
105
113
  end