webpacker 4.3.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ */