webpacker 4.3.0 → 5.0.0

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.
@@ -4,16 +4,22 @@ require "webpacker/configuration"
4
4
 
5
5
  namespace :webpacker do
6
6
  desc "Remove old compiled webpacks"
7
- task :clean, [:keep] => ["webpacker:verify_install", :environment] do |_, args|
7
+ task :clean, [:keep, :age] => ["webpacker:verify_install", :environment] do |_, args|
8
8
  Webpacker.ensure_log_goes_to_stdout do
9
- Webpacker.clean(Integer(args.keep || 2))
9
+ Webpacker.clean(Integer(args.keep || 2), Integer(args.age || 3600))
10
10
  end
11
11
  end
12
12
  end
13
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
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")
18
24
  end
19
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,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
@@ -5,12 +5,34 @@ class Webpacker::Commands
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
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)
19
+ if config.public_output_path.exist? && config.public_manifest_path.exist?
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
14
36
  end
15
37
 
16
38
  true
@@ -37,14 +59,16 @@ class Webpacker::Commands
37
59
  manifest_config = Dir.glob("#{config.public_manifest_path}*")
38
60
 
39
61
  packs = all_files - manifest_config - current_version
40
- packs.group_by { |file| File.mtime(file).utc.to_i }.sort.reverse
62
+ packs.reject { |file| File.directory?(file) }.group_by { |file| File.mtime(file).utc.to_i }
41
63
  end
42
64
 
43
65
  def current_version
44
- manifest.refresh.values.map do |value|
66
+ packs = manifest.refresh.values.map do |value|
45
67
  next if value.is_a?(Hash)
46
68
 
47
- File.join(config.root_path, "public", value)
69
+ File.join(config.root_path, "public", "#{value}*")
48
70
  end.compact
71
+
72
+ Dir.glob(packs).uniq
49
73
  end
50
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
 
@@ -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
@@ -1,4 +1,4 @@
1
1
  module Webpacker
2
2
  # Change the version in package.json too, please!
3
- VERSION = "4.3.0".freeze
3
+ VERSION = "5.0.0".freeze
4
4
  end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rails/webpacker",
3
- "version": "4.3.0",
3
+ "version": "5.0.0",
4
4
  "description": "Use webpack to manage app-like JavaScript modules in Rails",
5
5
  "main": "package/index.js",
6
6
  "files": [
@@ -8,32 +8,32 @@
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",
15
+ "@babel/core": "^7.8.7",
16
+ "@babel/plugin-proposal-class-properties": "^7.8.3",
17
+ "@babel/plugin-proposal-object-rest-spread": "^7.8.3",
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.8.3",
22
+ "@babel/preset-env": "^7.8.7",
23
+ "@babel/runtime": "^7.8.7",
24
24
  "babel-loader": "^8.0.6",
25
25
  "babel-plugin-dynamic-import-node": "^2.3.0",
26
- "babel-plugin-macros": "^2.6.1",
26
+ "babel-plugin-macros": "^2.8.0",
27
27
  "case-sensitive-paths-webpack-plugin": "^2.2.0",
28
- "compression-webpack-plugin": "^4.0.0",
29
- "core-js": "^3.4.0",
30
- "css-loader": "^3.2.0",
31
- "file-loader": "^4.2.0",
28
+ "compression-webpack-plugin": "^3.0.1",
29
+ "core-js": "^3.6.4",
30
+ "css-loader": "^3.4.1",
31
+ "file-loader": "^5.0.2",
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
39
  "pnp-webpack-plugin": "^1.5.0",
@@ -43,20 +43,20 @@
43
43
  "postcss-preset-env": "^6.7.0",
44
44
  "postcss-safe-parser": "^4.0.1",
45
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",
46
+ "sass-loader": "^7.3.1",
47
+ "style-loader": "^1.1.2",
48
+ "terser-webpack-plugin": "^2.3.5",
49
+ "webpack": "^4.42.0",
50
50
  "webpack-assets-manifest": "^3.1.1",
51
51
  "webpack-cli": "^3.3.10",
52
52
  "webpack-sources": "^1.4.3"
53
53
  },
54
54
  "devDependencies": {
55
- "eslint": "^6.6.0",
55
+ "eslint": "^6.8.0",
56
56
  "eslint-config-airbnb": "^18.0.1",
57
- "eslint-plugin-import": "^2.18.2",
57
+ "eslint-plugin-import": "^2.19.1",
58
58
  "eslint-plugin-jsx-a11y": "^6.2.3",
59
- "eslint-plugin-react": "^7.16.0",
59
+ "eslint-plugin-react": "^7.17.0",
60
60
  "jest": "^24.9.0"
61
61
  },
62
62
  "jest": {
@@ -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,9 @@
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: { sourceMap: true, includePaths }
7
8
  }
8
9
  ])
@@ -2,16 +2,23 @@ require "test_helper"
2
2
 
3
3
  class ManifestTest < Minitest::Test
4
4
  def test_lookup_exception!
5
- manifest_path = File.expand_path File.join(File.dirname(__FILE__), "test_app/public/packs", "manifest.json").to_s
6
5
  asset_file = "calendar.js"
7
6
 
8
- Webpacker.config.stub :compile?, false do
9
- error = assert_raises Webpacker::Manifest::MissingEntryError do
10
- Webpacker.manifest.lookup!(asset_file)
11
- end
7
+ error = assert_raises_manifest_missing_entry_error do
8
+ Webpacker.manifest.lookup!(asset_file)
9
+ end
10
+
11
+ assert_match "Webpacker can't find #{asset_file} in #{manifest_path}", error.message
12
+ end
13
+
14
+ def test_lookup_with_type_exception!
15
+ asset_file = "calendar"
12
16
 
13
- assert_match "Webpacker can't find #{asset_file} in #{manifest_path}", error.message
17
+ error = assert_raises_manifest_missing_entry_error do
18
+ Webpacker.manifest.lookup!(asset_file, type: :javascript)
14
19
  end
20
+
21
+ assert_match "Webpacker can't find #{asset_file}.js in #{manifest_path}", error.message
15
22
  end
16
23
 
17
24
  def test_lookup_success!
@@ -30,6 +37,16 @@ class ManifestTest < Minitest::Test
30
37
  assert_equal Webpacker.manifest.lookup("bootstrap.js"), "/packs/bootstrap-300631c4f0e0f9c865bc.js"
31
38
  end
32
39
 
40
+ def test_lookup_entrypoint_exception!
41
+ asset_file = "calendar"
42
+
43
+ error = assert_raises_manifest_missing_entry_error do
44
+ Webpacker.manifest.lookup_pack_with_chunks!(asset_file, type: :javascript)
45
+ end
46
+
47
+ assert_match "Webpacker can't find #{asset_file}.js in #{manifest_path}", error.message
48
+ end
49
+
33
50
  def test_lookup_entrypoint
34
51
  application_entrypoints = [
35
52
  "/packs/vendors~application~bootstrap-c20632e7baf2c81200d3.chunk.js",
@@ -39,4 +56,18 @@ class ManifestTest < Minitest::Test
39
56
 
40
57
  assert_equal Webpacker.manifest.lookup_pack_with_chunks!("application", type: :javascript), application_entrypoints
41
58
  end
59
+
60
+ private
61
+
62
+ def assert_raises_manifest_missing_entry_error(&block)
63
+ error = nil
64
+ Webpacker.config.stub :compile?, false do
65
+ error = assert_raises Webpacker::Manifest::MissingEntryError, &block
66
+ end
67
+ error
68
+ end
69
+
70
+ def manifest_path
71
+ File.expand_path File.join(File.dirname(__FILE__), "test_app/public/packs", "manifest.json").to_s
72
+ end
42
73
  end
@@ -28,6 +28,17 @@ class RakeTasksTest < Minitest::Test
28
28
  refute_includes output, "webpack binstubs not found."
29
29
  end
30
30
 
31
+ def test_check_node_version
32
+ output = Dir.chdir(test_app_path) { `rake webpacker:check_node 2>&1` }
33
+ refute_includes output, "Webpacker requires Node.js"
34
+ end
35
+
36
+ def test_check_yarn_version
37
+ output = Dir.chdir(test_app_path) { `rake webpacker:check_yarn 2>&1` }
38
+ refute_includes output, "Yarn not installed"
39
+ refute_includes output, "Webpacker requires Yarn"
40
+ end
41
+
31
42
  def test_rake_webpacker_yarn_install_in_non_production_environments
32
43
  assert_includes test_app_dev_dependencies, "right-pad"
33
44
 
@@ -0,0 +1,4 @@
1
+ /*
2
+ * Dummy file #1 for Multi File Entry points: https://webpack.js.org/guides/entry-advanced/
3
+ * This file must be named the same
4
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ * Dummy file #2 for Multi File Entry points: https://webpack.js.org/guides/entry-advanced/
3
+ * This file must be named the same
4
+ */