webpacker 4.1.0 → 5.0.1

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/.node-version +1 -1
  3. data/.travis.yml +7 -20
  4. data/CHANGELOG.md +35 -0
  5. data/Gemfile +1 -0
  6. data/Gemfile.lock +8 -5
  7. data/README.md +45 -260
  8. data/docs/css.md +3 -4
  9. data/docs/deployment.md +2 -2
  10. data/docs/docker.md +17 -17
  11. data/docs/engines.md +13 -0
  12. data/docs/integrations.md +220 -0
  13. data/docs/typescript.md +2 -3
  14. data/lib/install/loaders/svelte.js +2 -2
  15. data/lib/install/template.rb +2 -2
  16. data/lib/tasks/webpacker/check_node.rake +14 -7
  17. data/lib/tasks/webpacker/check_yarn.rake +16 -9
  18. data/lib/tasks/webpacker/clean.rake +16 -6
  19. data/lib/tasks/webpacker/clobber.rake +8 -4
  20. data/lib/tasks/webpacker/compile.rake +1 -9
  21. data/lib/tasks/webpacker/yarn_install.rake +5 -16
  22. data/lib/webpacker.rb +8 -0
  23. data/lib/webpacker/commands.rb +45 -19
  24. data/lib/webpacker/dev_server_runner.rb +4 -4
  25. data/lib/webpacker/env.rb +1 -1
  26. data/lib/webpacker/manifest.rb +4 -4
  27. data/lib/webpacker/railtie.rb +3 -1
  28. data/lib/webpacker/version.rb +1 -1
  29. data/package.json +35 -35
  30. data/package/environments/__tests__/base.js +10 -0
  31. data/package/environments/base.js +12 -1
  32. data/package/environments/development.js +0 -4
  33. data/package/rules/sass.js +7 -1
  34. data/test/manifest_test.rb +37 -6
  35. data/test/rake_tasks_test.rb +11 -0
  36. data/test/test_app/app/javascript/packs/multi_entry.css +4 -0
  37. data/test/test_app/app/javascript/packs/multi_entry.js +4 -0
  38. data/webpacker.gemspec +4 -3
  39. data/yarn.lock +2624 -1544
  40. metadata +28 -12
  41. data/gemfiles/Gemfile-rails.4.2.x +0 -9
  42. data/gemfiles/Gemfile-rails.5.0.x +0 -9
  43. data/gemfiles/Gemfile-rails.5.1.x +0 -9
@@ -1,15 +1,25 @@
1
+ $stdout.sync = true
2
+
1
3
  require "webpacker/configuration"
2
4
 
3
5
  namespace :webpacker do
4
6
  desc "Remove old compiled webpacks"
5
- task :clean, [:keep] => ["webpacker:verify_install", :environment] do |_, args|
6
- Webpacker.clean(Integer(args.keep || 2))
7
+ task :clean, [:keep, :age] => ["webpacker:verify_install", :environment] do |_, args|
8
+ Webpacker.ensure_log_goes_to_stdout do
9
+ Webpacker.clean(Integer(args.keep || 2), Integer(args.age || 3600))
10
+ end
7
11
  end
8
12
  end
9
13
 
10
- # Run clean if the assets:clean is run
11
- if Rake::Task.task_defined?("assets:clean")
12
- Rake::Task["assets:clean"].enhance do
13
- Rake::Task["webpacker:clean"].invoke
14
+ skip_webpacker_clean = %w(no false n f).include?(ENV["WEBPACKER_PRECOMPILE"])
15
+
16
+ unless skip_webpacker_clean
17
+ # Run clean if the assets:clean is run
18
+ if Rake::Task.task_defined?("assets:clean")
19
+ Rake::Task["assets:clean"].enhance do
20
+ Rake::Task["webpacker:clean"].invoke
21
+ end
22
+ else
23
+ Rake::Task.define_task("assets:clean" => "webpacker:clean")
14
24
  end
15
25
  end
@@ -8,9 +8,13 @@ namespace :webpacker do
8
8
  end
9
9
  end
10
10
 
11
- # Run clobber if the assets:clobber is run
12
- if Rake::Task.task_defined?("assets:clobber")
13
- Rake::Task["assets:clobber"].enhance do
14
- Rake::Task["webpacker:clobber"].invoke
11
+ skip_webpacker_clobber = %w(no false n f).include?(ENV["WEBPACKER_PRECOMPILE"])
12
+
13
+ unless skip_webpacker_clobber
14
+ # Run clobber if the assets:clobber is run
15
+ if Rake::Task.task_defined?("assets:clobber")
16
+ Rake::Task["assets:clobber"].enhance do
17
+ Rake::Task["webpacker:clobber"].invoke
18
+ end
15
19
  end
16
20
  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
@@ -27,7 +19,7 @@ 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
21
  Webpacker.with_node_env(ENV.fetch("NODE_ENV", "production")) do
30
- ensure_log_goes_to_stdout do
22
+ Webpacker.ensure_log_goes_to_stdout do
31
23
  if Webpacker.compile
32
24
  # Successful compilation!
33
25
  else
@@ -1,21 +1,10 @@
1
1
  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
- system "yarn install --no-progress"
5
-
6
- exit(1) unless $?.success?
4
+ valid_node_envs = %w[test development production]
5
+ node_env = ENV.fetch("NODE_ENV") do
6
+ valid_node_envs.include?(Rails.env) ? Rails.env : "production"
7
+ end
8
+ system({ "NODE_ENV" => node_env }, "yarn install --no-progress --frozen-lockfile")
7
9
  end
8
10
  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,6 +22,14 @@ 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
35
  delegate :bootstrap, :clean, :clobber, :compile, to: :commands
@@ -1,25 +1,41 @@
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_to_keep = 2)
8
+ # Cleanup old assets in the compile directory. By default it will
9
+ # keep the latest version, 2 backups created within the past hour.
10
+ #
11
+ # Examples
12
+ #
13
+ # To force only 1 backup to be kept, set count=1 and age=0.
14
+ #
15
+ # To only keep files created within the last 10 minutes, set count=0 and
16
+ # age=600.
17
+ #
18
+ def clean(count = 2, age = 3600)
9
19
  if config.public_output_path.exist? && config.public_manifest_path.exist?
10
- files_in_manifest = process_manifest_hash(manifest.refresh)
11
- files_to_be_removed = files_in_manifest.flat_map do |file_in_manifest|
12
- file_prefix, file_ext = file_in_manifest.scan(/(.*)[0-9a-f]{20}(.*)/).first
13
- versions_of_file = Dir.glob("#{file_prefix}*#{file_ext}").grep(/#{file_prefix}[0-9a-f]{20}#{file_ext}/)
14
- versions_of_file.map do |version_of_file|
15
- next if version_of_file == file_in_manifest
16
-
17
- [version_of_file, File.mtime(version_of_file).utc.to_i]
18
- end.compact.sort_by(&:last).reverse.drop(count_to_keep).map(&:first)
19
- end
20
-
21
- files_to_be_removed.each { |f| File.delete f }
20
+ versions
21
+ .sort
22
+ .reverse
23
+ .each_with_index
24
+ .drop_while do |(mtime, _), index|
25
+ max_age = [0, Time.now - Time.at(mtime)].max
26
+ max_age < age && index < count
27
+ end
28
+ .each do |(_, files), index|
29
+ files.each do |file|
30
+ if File.file?(file)
31
+ File.delete(file)
32
+ logger.info "Removed #{file}"
33
+ end
34
+ end
35
+ end
22
36
  end
37
+
38
+ true
23
39
  end
24
40
 
25
41
  def clobber
@@ -38,11 +54,21 @@ class Webpacker::Commands
38
54
  end
39
55
 
40
56
  private
41
- def process_manifest_hash(manifest_hash)
42
- manifest_hash.values.map do |value|
43
- next process_manifest_hash(value) if value.is_a?(Hash)
57
+ def versions
58
+ all_files = Dir.glob("#{config.public_output_path}/**/*")
59
+ manifest_config = Dir.glob("#{config.public_manifest_path}*")
60
+
61
+ packs = all_files - manifest_config - current_version
62
+ packs.reject { |file| File.directory?(file) }.group_by { |file| File.mtime(file).utc.to_i }
63
+ end
64
+
65
+ def current_version
66
+ packs = manifest.refresh.values.map do |value|
67
+ next if value.is_a?(Hash)
68
+
69
+ File.join(config.root_path, "public", "#{value}*")
70
+ end.compact
44
71
 
45
- File.join(config.root_path, "public", value)
46
- end.flatten
72
+ Dir.glob(packs).uniq
47
73
  end
48
74
  end
@@ -16,20 +16,20 @@ module Webpacker
16
16
  def load_config
17
17
  app_root = Pathname.new(@app_path)
18
18
 
19
- config = Configuration.new(
19
+ @config = Configuration.new(
20
20
  root_path: app_root,
21
21
  config_path: app_root.join("config/webpacker.yml"),
22
22
  env: ENV["RAILS_ENV"]
23
23
  )
24
24
 
25
- dev_server = DevServer.new(config)
25
+ dev_server = DevServer.new(@config)
26
26
 
27
27
  @hostname = dev_server.host
28
28
  @port = dev_server.port
29
29
  @pretty = dev_server.pretty?
30
30
 
31
31
  rescue Errno::ENOENT, NoMethodError
32
- $stdout.puts "webpack dev_server configuration not found in #{config.config_path}[#{ENV["RAILS_ENV"]}]."
32
+ $stdout.puts "webpack dev_server configuration not found in #{@config.config_path}[#{ENV["RAILS_ENV"]}]."
33
33
  $stdout.puts "Please run bundle exec rails webpacker:install to install Webpacker"
34
34
  exit!
35
35
  end
@@ -39,7 +39,7 @@ module Webpacker
39
39
  server.close
40
40
 
41
41
  rescue Errno::EADDRINUSE
42
- $stdout.puts "Another program is running on port #{@port}. Set a new port in #{@config_file} for dev_server"
42
+ $stdout.puts "Another program is running on port #{@port}. Set a new port in #{@config.config_path} for dev_server"
43
43
  exit!
44
44
  end
45
45
 
@@ -12,7 +12,7 @@ class Webpacker::Env
12
12
  end
13
13
 
14
14
  def inquire
15
- fallback_env_warning unless current
15
+ fallback_env_warning if config_path.exist? && !current
16
16
  current || DEFAULT.inquiry
17
17
  end
18
18
 
@@ -29,7 +29,7 @@ class Webpacker::Manifest
29
29
  end
30
30
 
31
31
  def lookup_pack_with_chunks!(name, pack_type = {})
32
- lookup_pack_with_chunks(name, pack_type) || handle_missing_entry(name)
32
+ lookup_pack_with_chunks(name, pack_type) || handle_missing_entry(name, pack_type)
33
33
  end
34
34
 
35
35
  # Computes the relative path for a given Webpacker asset using manifest.json.
@@ -46,7 +46,7 @@ class Webpacker::Manifest
46
46
 
47
47
  # Like lookup, except that if no asset is found, raises a Webpacker::Manifest::MissingEntryError.
48
48
  def lookup!(name, pack_type = {})
49
- lookup(name, pack_type) || handle_missing_entry(name)
49
+ lookup(name, pack_type) || handle_missing_entry(name, pack_type)
50
50
  end
51
51
 
52
52
  private
@@ -75,8 +75,8 @@ class Webpacker::Manifest
75
75
  "#{name}.#{manifest_type(pack_type)}"
76
76
  end
77
77
 
78
- def handle_missing_entry(name)
79
- raise Webpacker::Manifest::MissingEntryError, missing_file_from_manifest_error(name)
78
+ def handle_missing_entry(name, pack_type)
79
+ raise Webpacker::Manifest::MissingEntryError, missing_file_from_manifest_error(full_pack_name(name, pack_type[:type]))
80
80
  end
81
81
 
82
82
  def load
@@ -91,6 +91,8 @@ class Webpacker::Engine < ::Rails::Engine
91
91
  end
92
92
 
93
93
  initializer "webpacker.set_source" do |app|
94
- app.config.javascript_path = Webpacker.config.source_path.relative_path_from(Rails.root.join("app")).to_s
94
+ if Webpacker.config.config_path.exist?
95
+ app.config.javascript_path = Webpacker.config.source_path.relative_path_from(Rails.root.join("app")).to_s
96
+ end
95
97
  end
96
98
  end
@@ -1,4 +1,4 @@
1
1
  module Webpacker
2
2
  # Change the version in package.json too, please!
3
- VERSION = "4.1.0".freeze
3
+ VERSION = "5.0.1".freeze
4
4
  end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rails/webpacker",
3
- "version": "4.1.0",
3
+ "version": "5.0.1",
4
4
  "description": "Use webpack to manage app-like JavaScript modules in Rails",
5
5
  "main": "package/index.js",
6
6
  "files": [
@@ -8,56 +8,56 @@
8
8
  "lib/install/config/webpacker.yml"
9
9
  ],
10
10
  "engines": {
11
- "node": ">=8.16.0",
12
- "yarn": ">=1.0.0"
11
+ "node": ">=10.13.0",
12
+ "yarn": ">=1 <2"
13
13
  },
14
14
  "dependencies": {
15
- "@babel/core": "^7.7.2",
16
- "@babel/plugin-proposal-class-properties": "^7.7.0",
17
- "@babel/plugin-proposal-object-rest-spread": "^7.6.2",
18
- "@babel/plugin-syntax-dynamic-import": "^7.2.0",
19
- "@babel/plugin-transform-destructuring": "^7.6.0",
20
- "@babel/plugin-transform-regenerator": "^7.7.0",
21
- "@babel/plugin-transform-runtime": "^7.6.2",
22
- "@babel/preset-env": "^7.7.1",
23
- "@babel/runtime": "^7.7.2",
24
- "babel-loader": "^8.0.6",
15
+ "@babel/core": "^7.9.0",
16
+ "@babel/plugin-proposal-class-properties": "^7.8.3",
17
+ "@babel/plugin-proposal-object-rest-spread": "^7.9.0",
18
+ "@babel/plugin-syntax-dynamic-import": "^7.8.3",
19
+ "@babel/plugin-transform-destructuring": "^7.8.8",
20
+ "@babel/plugin-transform-regenerator": "^7.8.7",
21
+ "@babel/plugin-transform-runtime": "^7.9.0",
22
+ "@babel/preset-env": "^7.9.0",
23
+ "@babel/runtime": "^7.9.2",
24
+ "babel-loader": "^8.1.0",
25
25
  "babel-plugin-dynamic-import-node": "^2.3.0",
26
- "babel-plugin-macros": "^2.6.1",
27
- "case-sensitive-paths-webpack-plugin": "^2.2.0",
28
- "compression-webpack-plugin": "^3.0.0",
29
- "core-js": "^3.4.0",
30
- "css-loader": "^3.2.0",
31
- "file-loader": "^4.2.0",
26
+ "babel-plugin-macros": "^2.8.0",
27
+ "case-sensitive-paths-webpack-plugin": "^2.3.0",
28
+ "compression-webpack-plugin": "^3.1.0",
29
+ "core-js": "^3.6.4",
30
+ "css-loader": "^3.4.2",
31
+ "file-loader": "^6.0.0",
32
32
  "flatted": "^2.0.1",
33
33
  "glob": "^7.1.6",
34
34
  "js-yaml": "^3.13.1",
35
- "mini-css-extract-plugin": "^0.8.0",
36
- "node-sass": "^4.13.0",
35
+ "mini-css-extract-plugin": "^0.9.0",
36
+ "node-sass": "^4.13.1",
37
37
  "optimize-css-assets-webpack-plugin": "^5.0.3",
38
38
  "path-complete-extname": "^1.0.0",
39
- "pnp-webpack-plugin": "^1.5.0",
40
- "postcss-flexbugs-fixes": "^4.1.0",
39
+ "pnp-webpack-plugin": "^1.6.4",
40
+ "postcss-flexbugs-fixes": "^4.2.0",
41
41
  "postcss-import": "^12.0.1",
42
42
  "postcss-loader": "^3.0.0",
43
43
  "postcss-preset-env": "^6.7.0",
44
- "postcss-safe-parser": "^4.0.1",
45
- "regenerator-runtime": "^0.13.3",
46
- "sass-loader": "7.3.1",
47
- "style-loader": "^1.0.0",
48
- "terser-webpack-plugin": "^2.2.1",
49
- "webpack": "^4.41.2",
44
+ "postcss-safe-parser": "^4.0.2",
45
+ "regenerator-runtime": "^0.13.5",
46
+ "sass-loader": "^8.0.2",
47
+ "style-loader": "^1.1.3",
48
+ "terser-webpack-plugin": "^2.3.5",
49
+ "webpack": "^4.42.1",
50
50
  "webpack-assets-manifest": "^3.1.1",
51
- "webpack-cli": "^3.3.10",
51
+ "webpack-cli": "^3.3.11",
52
52
  "webpack-sources": "^1.4.3"
53
53
  },
54
54
  "devDependencies": {
55
- "eslint": "^6.6.0",
56
- "eslint-config-airbnb": "^18.0.1",
57
- "eslint-plugin-import": "^2.18.2",
55
+ "eslint": "^6.8.0",
56
+ "eslint-config-airbnb": "^18.1.0",
57
+ "eslint-plugin-import": "^2.20.1",
58
58
  "eslint-plugin-jsx-a11y": "^6.2.3",
59
- "eslint-plugin-react": "^7.16.0",
60
- "jest": "^24.9.0"
59
+ "eslint-plugin-react": "^7.19.0",
60
+ "jest": "^25.1.0"
61
61
  },
62
62
  "jest": {
63
63
  "testRegex": "(/__tests__/.*|(\\.|/))\\.jsx?$",
@@ -29,6 +29,16 @@ describe('Environment', () => {
29
29
  )
30
30
  })
31
31
 
32
+ test('should return multi file entry points', () => {
33
+ const config = environment.toWebpackConfig()
34
+ expect(config.entry.multi_entry.sort()).toEqual(
35
+ [
36
+ resolve('app', 'javascript', 'packs', 'multi_entry.css'),
37
+ resolve('app', 'javascript', 'packs', 'multi_entry.js')
38
+ ]
39
+ )
40
+ })
41
+
32
42
  test('should return output', () => {
33
43
  const config = environment.toWebpackConfig()
34
44
  expect(config.output.filename).toEqual('js/[name]-[contenthash].js')
@@ -65,7 +65,18 @@ const getEntryObject = () => {
65
65
  paths.forEach((path) => {
66
66
  const namespace = relative(join(rootPath), dirname(path))
67
67
  const name = join(namespace, basename(path, extname(path)))
68
- result.set(name, resolve(path))
68
+ let assetPaths = resolve(path)
69
+
70
+ // Allows for multiple filetypes per entry (https://webpack.js.org/guides/entry-advanced/)
71
+ // Transforms the config object value to an array with all values under the same name
72
+ let previousPaths = result.get(name)
73
+ if (previousPaths) {
74
+ previousPaths = Array.isArray(previousPaths) ? previousPaths : [previousPaths]
75
+ previousPaths.push(assetPaths)
76
+ assetPaths = previousPaths
77
+ }
78
+
79
+ result.set(name, assetPaths)
69
80
  })
70
81
  return result
71
82
  }
@@ -14,11 +14,7 @@ module.exports = class extends Base {
14
14
 
15
15
  this.config.merge({
16
16
  mode: 'development',
17
- cache: true,
18
17
  devtool: 'cheap-module-source-map',
19
- output: {
20
- pathinfo: true
21
- },
22
18
  devServer: {
23
19
  clientLogLevel: 'none',
24
20
  compress: devServer.compress,
@@ -1,8 +1,14 @@
1
1
  const getStyleRule = require('../utils/get_style_rule')
2
+ const { resolved_paths: includePaths } = require('../config')
2
3
 
3
4
  module.exports = getStyleRule(/\.(scss|sass)(\.erb)?$/i, false, [
4
5
  {
5
6
  loader: 'sass-loader',
6
- options: { sourceMap: true }
7
+ options: {
8
+ sourceMap: true,
9
+ sassOptions: {
10
+ includePaths
11
+ }
12
+ }
7
13
  }
8
14
  ])