shakapacker 6.5.5 → 6.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.js +1 -0
  3. data/.github/FUNDING.yml +1 -0
  4. data/.github/ISSUE_TEMPLATE/bug_report.md +11 -7
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
  6. data/.github/PULL_REQUEST_TEMPLATE.md +18 -0
  7. data/.github/workflows/ruby.yml +3 -1
  8. data/.gitignore +3 -3
  9. data/.rspec +1 -0
  10. data/CHANGELOG.md +20 -2
  11. data/CONTRIBUTING.md +11 -1
  12. data/Gemfile.development_dependencies +3 -1
  13. data/README.md +41 -8
  14. data/Rakefile +4 -5
  15. data/docs/v6_upgrade.md +1 -1
  16. data/gemfiles/Gemfile-rails-edge +1 -1
  17. data/gemfiles/Gemfile-rails.5.2.x +1 -1
  18. data/gemfiles/Gemfile-rails.6.0.x +1 -1
  19. data/gemfiles/Gemfile-rails.6.1.x +1 -1
  20. data/gemfiles/Gemfile-rails.7.0.x +1 -1
  21. data/lib/install/template.rb +21 -16
  22. data/lib/tasks/webpacker/compile.rake +5 -10
  23. data/lib/webpacker/helper.rb +20 -9
  24. data/lib/webpacker/instance.rb +3 -1
  25. data/lib/webpacker/version.rb +1 -1
  26. data/package/rules/__tests__/__utils__/webpack.js +50 -0
  27. data/package/rules/__tests__/babel.js +63 -0
  28. data/package/rules/__tests__/esbuild.js +64 -0
  29. data/package/rules/__tests__/index.js +0 -4
  30. data/package/rules/__tests__/swc.js +64 -0
  31. data/package/rules/babel.js +13 -24
  32. data/package/rules/esbuild.js +2 -13
  33. data/package/rules/jscommon.js +26 -0
  34. data/package/rules/swc.js +2 -13
  35. data/package/utils/helpers.js +1 -1
  36. data/package.json +8 -2
  37. data/spec/command_spec.rb +114 -0
  38. data/spec/compiler_spec.rb +57 -0
  39. data/spec/compiler_strategy_spec.rb +20 -0
  40. data/spec/configuration_spec.rb +281 -0
  41. data/{test/dev_server_runner_test.rb → spec/dev_server_runner_spec.rb} +30 -40
  42. data/spec/dev_server_spec.rb +45 -0
  43. data/spec/digest_strategy_spec.rb +33 -0
  44. data/{test/engine_rake_tasks_test.rb → spec/engine_rake_tasks_spec.rb} +17 -9
  45. data/spec/env_spec.rb +21 -0
  46. data/spec/helper_spec.rb +241 -0
  47. data/spec/manifest_spec.rb +98 -0
  48. data/spec/mtime_strategy_spec.rb +53 -0
  49. data/spec/rake_tasks_spec.rb +32 -0
  50. data/spec/spec_helper.rb +123 -0
  51. data/{test → spec}/test_app/public/packs/manifest.json +8 -0
  52. data/spec/version_checker_spec.rb +950 -0
  53. data/{test/webpack_runner_test.rb → spec/webpack_runner_spec.rb} +12 -15
  54. data/spec/webpacker_spec.rb +61 -0
  55. data/yarn.lock +846 -844
  56. metadata +104 -187
  57. data/.github/ISSUE_TEMPLATE/feature-request.md +0 -18
  58. data/lib/tasks/yarn.rake +0 -44
  59. data/test/command_test.rb +0 -109
  60. data/test/compiler_strategy_test.rb +0 -27
  61. data/test/compiler_test.rb +0 -60
  62. data/test/configuration_test.rb +0 -186
  63. data/test/dev_server_test.rb +0 -47
  64. data/test/digest_strategy_test.rb +0 -33
  65. data/test/env_test.rb +0 -23
  66. data/test/helper_test.rb +0 -248
  67. data/test/manifest_test.rb +0 -89
  68. data/test/mtime_strategy_test.rb +0 -42
  69. data/test/rake_tasks_test.rb +0 -37
  70. data/test/test_helper.rb +0 -33
  71. data/test/version_checker_test.rb +0 -826
  72. data/test/webpacker_test.rb +0 -49
  73. /data/{test → spec}/fixtures/beta_package-lock.v1.json +0 -0
  74. /data/{test → spec}/fixtures/beta_package-lock.v2.json +0 -0
  75. /data/{test → spec}/fixtures/beta_package.json +0 -0
  76. /data/{test → spec}/fixtures/beta_yarn.v1.lock +0 -0
  77. /data/{test → spec}/fixtures/beta_yarn.v2.lock +0 -0
  78. /data/{test → spec}/fixtures/git_url_package-lock.v1.json +0 -0
  79. /data/{test → spec}/fixtures/git_url_package-lock.v2.json +0 -0
  80. /data/{test → spec}/fixtures/git_url_package.json +0 -0
  81. /data/{test → spec}/fixtures/git_url_yarn.v1.lock +0 -0
  82. /data/{test → spec}/fixtures/git_url_yarn.v2.lock +0 -0
  83. /data/{test → spec}/fixtures/github_url_package-lock.v1.json +0 -0
  84. /data/{test → spec}/fixtures/github_url_package-lock.v2.json +0 -0
  85. /data/{test → spec}/fixtures/github_url_package.json +0 -0
  86. /data/{test → spec}/fixtures/github_url_yarn.v1.lock +0 -0
  87. /data/{test → spec}/fixtures/github_url_yarn.v2.lock +0 -0
  88. /data/{test → spec}/fixtures/relative_path_package-lock.v1.json +0 -0
  89. /data/{test → spec}/fixtures/relative_path_package-lock.v2.json +0 -0
  90. /data/{test → spec}/fixtures/relative_path_package.json +0 -0
  91. /data/{test → spec}/fixtures/relative_path_yarn.v1.lock +0 -0
  92. /data/{test → spec}/fixtures/relative_path_yarn.v2.lock +0 -0
  93. /data/{test → spec}/fixtures/semver_caret_package-lock.v1.json +0 -0
  94. /data/{test → spec}/fixtures/semver_caret_package-lock.v2.json +0 -0
  95. /data/{test → spec}/fixtures/semver_caret_package.json +0 -0
  96. /data/{test → spec}/fixtures/semver_caret_yarn.v1.lock +0 -0
  97. /data/{test → spec}/fixtures/semver_caret_yarn.v2.lock +0 -0
  98. /data/{test → spec}/fixtures/semver_exact_package-lock.v1.json +0 -0
  99. /data/{test → spec}/fixtures/semver_exact_package-lock.v2.json +0 -0
  100. /data/{test → spec}/fixtures/semver_exact_package.json +0 -0
  101. /data/{test → spec}/fixtures/semver_exact_yarn.v1.lock +0 -0
  102. /data/{test → spec}/fixtures/semver_exact_yarn.v2.lock +0 -0
  103. /data/{test → spec}/fixtures/semver_tilde_package-lock.v1.json +0 -0
  104. /data/{test → spec}/fixtures/semver_tilde_package-lock.v2.json +0 -0
  105. /data/{test → spec}/fixtures/semver_tilde_package.json +0 -0
  106. /data/{test → spec}/fixtures/semver_tilde_yarn.v1.lock +0 -0
  107. /data/{test → spec}/fixtures/semver_tilde_yarn.v2.lock +0 -0
  108. /data/{test → spec}/fixtures/without_package-lock.v1.json +0 -0
  109. /data/{test → spec}/fixtures/without_package-lock.v2.json +0 -0
  110. /data/{test → spec}/fixtures/without_package.json +0 -0
  111. /data/{test → spec}/fixtures/without_yarn.v1.lock +0 -0
  112. /data/{test → spec}/fixtures/without_yarn.v2.lock +0 -0
  113. /data/{test → spec}/mounted_app/Rakefile +0 -0
  114. /data/{test → spec}/mounted_app/test/dummy/Rakefile +0 -0
  115. /data/{test → spec}/mounted_app/test/dummy/bin/rails +0 -0
  116. /data/{test → spec}/mounted_app/test/dummy/bin/rake +0 -0
  117. /data/{test → spec}/mounted_app/test/dummy/config/application.rb +0 -0
  118. /data/{test → spec}/mounted_app/test/dummy/config/environment.rb +0 -0
  119. /data/{test → spec}/mounted_app/test/dummy/config/webpacker.yml +0 -0
  120. /data/{test → spec}/mounted_app/test/dummy/config.ru +0 -0
  121. /data/{test → spec}/mounted_app/test/dummy/package.json +0 -0
  122. /data/{test → spec}/test_app/Rakefile +0 -0
  123. /data/{test → spec}/test_app/app/packs/entrypoints/application.js +0 -0
  124. /data/{test → spec}/test_app/app/packs/entrypoints/generated/something.js +0 -0
  125. /data/{test → spec}/test_app/app/packs/entrypoints/multi_entry.css +0 -0
  126. /data/{test → spec}/test_app/app/packs/entrypoints/multi_entry.js +0 -0
  127. /data/{test → spec}/test_app/bin/webpacker +0 -0
  128. /data/{test → spec}/test_app/bin/webpacker-dev-server +0 -0
  129. /data/{test → spec}/test_app/config/application.rb +0 -0
  130. /data/{test → spec}/test_app/config/environment.rb +0 -0
  131. /data/{test → spec}/test_app/config/initializers/inspect_autoload_paths.rb +0 -0
  132. /data/{test → spec}/test_app/config/webpack/webpack.config.js +0 -0
  133. /data/{test → spec}/test_app/config/webpacker.yml +0 -0
  134. /data/{test → spec}/test_app/config/webpacker_css_extract_ignore_order_warnings.yml +0 -0
  135. /data/{test → spec}/test_app/config/webpacker_defaults_fallback.yml +0 -0
  136. /data/{test → spec}/test_app/config/webpacker_manifest_path.yml +0 -0
  137. /data/{test → spec}/test_app/config/webpacker_nested_entries.yml +0 -0
  138. /data/{test → spec}/test_app/config/webpacker_no_precompile.yml +0 -0
  139. /data/{test → spec}/test_app/config/webpacker_other_location.yml +0 -0
  140. /data/{test → spec}/test_app/config/webpacker_public_root.yml +0 -0
  141. /data/{test → spec}/test_app/config.ru +0 -0
  142. /data/{test → spec}/test_app/package.json +0 -0
  143. /data/{test → spec}/test_app/some.config.js +0 -0
  144. /data/{test → spec}/test_app/yarn.lock +0 -0
@@ -0,0 +1,64 @@
1
+ const path = require("path");
2
+ const {
3
+ app_javascript,
4
+ node_modules,
5
+ node_modules_included,
6
+ createTestCompiler,
7
+ createTrackLoader,
8
+ } = require("./__utils__/webpack");
9
+ const esbuildConfig = require("../esbuild");
10
+
11
+ jest.mock("../../config", () => {
12
+ const original = jest.requireActual("../../config");
13
+ return {
14
+ ...original,
15
+ webpack_loader: "esbuild",
16
+ additional_paths: [...original.additional_paths, "node_modules/included"],
17
+ };
18
+ });
19
+
20
+ const createWebpackConfig = (file, use) => {
21
+ return {
22
+ entry: { file },
23
+ module: {
24
+ rules: [
25
+ {
26
+ ...esbuildConfig,
27
+ use,
28
+ },
29
+ ],
30
+ },
31
+ output: {
32
+ path: "/",
33
+ filename: "scripts-bundled.js",
34
+ },
35
+ };
36
+ };
37
+
38
+ describe("swc", () => {
39
+ test("process source path", async () => {
40
+ const normalPath = `${app_javascript}/a.js`;
41
+ const [tracked, loader] = createTrackLoader();
42
+ const compiler = createTestCompiler(
43
+ createWebpackConfig(normalPath, loader)
44
+ );
45
+ await compiler.run();
46
+ expect(tracked[normalPath]).toBeTruthy();
47
+ });
48
+
49
+ test("exclude node_modules", async () => {
50
+ const ignored = `${node_modules}/a.js`;
51
+ const [tracked, loader] = createTrackLoader();
52
+ const compiler = createTestCompiler(createWebpackConfig(ignored, loader));
53
+ await compiler.run();
54
+ expect(tracked[ignored]).toBeUndefined();
55
+ });
56
+
57
+ test("explicitly included node_modules should be transpiled", async () => {
58
+ const included = `${node_modules_included}/a.js`;
59
+ const [tracked, loader] = createTrackLoader();
60
+ const compiler = createTestCompiler(createWebpackConfig(included, loader));
61
+ await compiler.run();
62
+ expect(tracked[included]).toBeTruthy();
63
+ });
64
+ });
@@ -4,8 +4,4 @@ describe('index', () => {
4
4
  test('rule tests are regexes', () => {
5
5
  rules.forEach(rule => expect(rule.test instanceof RegExp).toBe(true))
6
6
  })
7
-
8
- test('rule excludes are regexes', () => {
9
- rules.forEach(rule => expect(rule.exclude instanceof RegExp).toBe(true))
10
- })
11
7
  })
@@ -0,0 +1,64 @@
1
+ const path = require("path");
2
+ const {
3
+ app_javascript,
4
+ node_modules,
5
+ node_modules_included,
6
+ createTestCompiler,
7
+ createTrackLoader,
8
+ } = require("./__utils__/webpack");
9
+ const swcConfig = require("../swc");
10
+
11
+ jest.mock("../../config", () => {
12
+ const original = jest.requireActual("../../config");
13
+ return {
14
+ ...original,
15
+ webpack_loader: "swc",
16
+ additional_paths: [...original.additional_paths, "node_modules/included"],
17
+ };
18
+ });
19
+
20
+ const createWebpackConfig = (file, use) => {
21
+ return {
22
+ entry: { file },
23
+ module: {
24
+ rules: [
25
+ {
26
+ ...swcConfig,
27
+ use,
28
+ },
29
+ ],
30
+ },
31
+ output: {
32
+ path: "/",
33
+ filename: "scripts-bundled.js",
34
+ },
35
+ };
36
+ };
37
+
38
+ describe("swc", () => {
39
+ test("process source path", async () => {
40
+ const normalPath = `${app_javascript}/a.js`;
41
+ const [tracked, loader] = createTrackLoader();
42
+ const compiler = createTestCompiler(
43
+ createWebpackConfig(normalPath, loader)
44
+ );
45
+ await compiler.run();
46
+ expect(tracked[normalPath]).toBeTruthy();
47
+ });
48
+
49
+ test("exclude node_modules", async () => {
50
+ const ignored = `${node_modules}/a.js`;
51
+ const [tracked, loader] = createTrackLoader();
52
+ const compiler = createTestCompiler(createWebpackConfig(ignored, loader));
53
+ await compiler.run();
54
+ expect(tracked[ignored]).toBeUndefined();
55
+ });
56
+
57
+ test("explicitly included node_modules should be transpiled", async () => {
58
+ const included = `${node_modules_included}/a.js`;
59
+ const [tracked, loader] = createTrackLoader();
60
+ const compiler = createTestCompiler(createWebpackConfig(included, loader));
61
+ await compiler.run();
62
+ expect(tracked[included]).toBeTruthy();
63
+ });
64
+ });
@@ -1,32 +1,21 @@
1
- const { resolve } = require('path')
2
- const { realpathSync } = require('fs')
3
1
  const { loaderMatches } = require('../utils/helpers')
4
-
5
2
  const {
6
- source_path: sourcePath,
7
- additional_paths: additionalPaths,
8
3
  webpack_loader: webpackLoader
9
4
  } = require('../config')
10
5
  const { isProduction } = require('../env')
6
+ const jscommon = require('./jscommon')
11
7
 
12
8
  module.exports = loaderMatches(webpackLoader, 'babel', () => ({
13
- test: /\.(js|jsx|mjs|ts|tsx|coffee)?(\.erb)?$/,
14
- include: [sourcePath, ...additionalPaths].map((p) => {
15
- try {
16
- return realpathSync(p)
17
- } catch (e) {
18
- return resolve(p)
19
- }
20
- }),
21
- exclude: /node_modules/,
22
- use: [
23
- {
24
- loader: require.resolve('babel-loader'),
25
- options: {
26
- cacheDirectory: true,
27
- cacheCompression: isProduction,
28
- compact: isProduction
29
- }
9
+ test: /\.(js|jsx|mjs|ts|tsx|coffee)?(\.erb)?$/,
10
+ ...jscommon,
11
+ use: [
12
+ {
13
+ loader: require.resolve('babel-loader'),
14
+ options: {
15
+ cacheDirectory: true,
16
+ cacheCompression: isProduction,
17
+ compact: isProduction
30
18
  }
31
- ]
32
- }))
19
+ }
20
+ ]
21
+ }))
@@ -1,23 +1,12 @@
1
- const { resolve } = require('path')
2
- const { realpathSync } = require('fs')
3
1
  const { loaderMatches } = require('../utils/helpers')
4
2
  const { getEsbuildLoaderConfig } = require('../esbuild')
5
-
6
3
  const {
7
- source_path: sourcePath,
8
- additional_paths: additionalPaths,
9
4
  webpack_loader: webpackLoader
10
5
  } = require('../config')
6
+ const jscommon = require('./jscommon')
11
7
 
12
8
  module.exports = loaderMatches(webpackLoader, 'esbuild', () => ({
13
9
  test: /\.(ts|tsx|js|jsx|mjs|coffee)?(\.erb)?$/,
14
- include: [sourcePath, ...additionalPaths].map((p) => {
15
- try {
16
- return realpathSync(p)
17
- } catch (e) {
18
- return resolve(p)
19
- }
20
- }),
21
- exclude: /node_modules/,
10
+ ...jscommon,
22
11
  use: ({ resource }) => getEsbuildLoaderConfig(resource)
23
12
  }))
@@ -0,0 +1,26 @@
1
+ const { resolve } = require('path')
2
+ const { realpathSync } = require('fs')
3
+ const {
4
+ source_path: sourcePath,
5
+ additional_paths: additionalPaths
6
+ } = require('../config')
7
+
8
+ const inclusions = [sourcePath, ...additionalPaths].map(p => {
9
+ try {
10
+ return realpathSync(p)
11
+ } catch (e) {
12
+ return resolve(p)
13
+ }
14
+ })
15
+
16
+ module.exports = {
17
+ include: inclusions,
18
+ exclude: [
19
+ {
20
+ // exclude all node_modules from running through babel-loader
21
+ and: [resolve('node_modules')],
22
+ // Do not exclude inclusions, as otherwise these won't be transpiled
23
+ not: [...inclusions]
24
+ }
25
+ ]
26
+ }
data/package/rules/swc.js CHANGED
@@ -1,23 +1,12 @@
1
- const { resolve } = require('path')
2
- const { realpathSync } = require('fs')
3
1
  const { loaderMatches } = require('../utils/helpers')
4
2
  const { getSwcLoaderConfig } = require('../swc')
5
-
6
3
  const {
7
- source_path: sourcePath,
8
- additional_paths: additionalPaths,
9
4
  webpack_loader: webpackLoader
10
5
  } = require('../config')
6
+ const jscommon = require('./jscommon')
11
7
 
12
8
  module.exports = loaderMatches(webpackLoader, 'swc', () => ({
13
9
  test: /\.(ts|tsx|js|jsx|mjs|coffee)?(\.erb)?$/,
14
- include: [sourcePath, ...additionalPaths].map((p) => {
15
- try {
16
- return realpathSync(p)
17
- } catch (e) {
18
- return resolve(p)
19
- }
20
- }),
21
- exclude: /node_modules/,
10
+ ...jscommon,
22
11
  use: ({ resource }) => getSwcLoaderConfig(resource)
23
12
  }))
@@ -2,7 +2,7 @@ const isArray = (value) => Array.isArray(value)
2
2
  const isBoolean = (str) => /^true/.test(str) || /^false/.test(str)
3
3
  const chdirTestApp = () => {
4
4
  try {
5
- return process.chdir('test/test_app')
5
+ return process.chdir('spec/test_app')
6
6
  } catch (e) {
7
7
  return null
8
8
  }
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shakapacker",
3
- "version": "6.5.5",
3
+ "version": "6.6.0",
4
4
  "description": "Use webpack to manage app-like JavaScript modules in Rails",
5
5
  "main": "package/index.js",
6
6
  "files": [
@@ -40,14 +40,20 @@
40
40
  "eslint-plugin-import": "^2.24.2",
41
41
  "eslint-plugin-jsx-a11y": "^6.4.1",
42
42
  "eslint-plugin-react": "^7.26.0",
43
- "jest": "^27.2.1",
43
+ "jest": "^28.1.3",
44
+ "memory-fs": "^0.5.0",
44
45
  "swc-loader": "^0.1.15",
46
+ "thenify": "^3.3.1",
45
47
  "webpack": "^5.72.0",
46
48
  "webpack-assets-manifest": "^5.0.6",
47
49
  "webpack-merge": "^5.8.0"
48
50
  },
49
51
  "jest": {
50
52
  "testRegex": "(/__tests__/.*|(\\.|/))\\.jsx?$",
53
+ "testPathIgnorePatterns": [
54
+ "/__fixtures__/",
55
+ "/__utils__/"
56
+ ],
51
57
  "roots": [
52
58
  "<rootDir>/package"
53
59
  ]
@@ -0,0 +1,114 @@
1
+ describe "Command" do
2
+ before do
3
+ allow(Webpacker.logger).to receive(:info)
4
+ end
5
+
6
+ describe "#compile" do
7
+ it "returns success status when stale" do
8
+ expect(Webpacker.compiler).to receive(:stale?).and_return(true)
9
+ expect(Webpacker.compiler).to receive(:run_webpack).and_return(true)
10
+
11
+ expect(Webpacker.commands.compile).to be true
12
+ end
13
+
14
+ it "returns success status when fresh" do
15
+ expect(Webpacker.compiler).to receive(:stale?).and_return(false)
16
+
17
+ expect(Webpacker.commands.compile).to be true
18
+ end
19
+
20
+ it "returns failure status when stale" do
21
+ expect(Webpacker.compiler).to receive(:stale?).and_return(true)
22
+ expect(Webpacker.compiler).to receive(:run_webpack).and_return(false)
23
+
24
+ expect(Webpacker.commands.compile).to be false
25
+ end
26
+ end
27
+
28
+ describe "#clean" do
29
+ let(:now) { Time.parse("2021-01-01 12:34:56 UTC") }
30
+ let(:prev_files) do
31
+ # Test assets to be kept and deleted, path and mtime
32
+ {
33
+ # recent versions to be kept with Webpacker.commands.clean(count = 2)
34
+ "js/application-deadbeef.js" => now - 4000,
35
+ "js/common-deadbeee.js" => now - 4002,
36
+ "css/common-deadbeed.css" => now - 4004,
37
+ "media/images/logo-deadbeeb.css" => now - 4006,
38
+ "js/application-1eadbeef.js" => now - 8000,
39
+ "js/common-1eadbeee.js" => now - 8002,
40
+ "css/common-1eadbeed.css" => now - 8004,
41
+ "media/images/logo-1eadbeeb.css" => now - 8006,
42
+ # new files to be kept with Webpacker.commands.clean(age = 3600)
43
+ "js/brandnew-0001.js" => now,
44
+ "js/brandnew-0002.js" => now - 10,
45
+ "js/brandnew-0003.js" => now - 20,
46
+ "js/brandnew-0004.js" => now - 40,
47
+ }.transform_keys { |path| "#{Webpacker.config.public_output_path}/#{path}" }
48
+ end
49
+
50
+ let(:expired_files) do
51
+ {
52
+ # old files that are outside count = 2 or age = 3600 and to be deleted
53
+ "js/application-0eadbeef.js" => now - 9000,
54
+ "js/common-0eadbeee.js" => now - 9002,
55
+ "css/common-0eadbeed.css" => now - 9004,
56
+ "js/brandnew-0005.js" => now - 3640,
57
+ }.transform_keys { |path| "#{Webpacker.config.public_output_path}/#{path}" }
58
+ end
59
+
60
+ let(:all_files) { prev_files.merge(expired_files) }
61
+
62
+ let(:file_delete_mock) { double("File Delete") }
63
+ let(:file_mtime_stub) { Proc.new { |longpath| all_files[longpath] } }
64
+ let(:file_delete_stub) { Proc.new { |longpath| file_delete_mock.delete(longpath) } }
65
+
66
+ before :context do
67
+ @dir_glob_stub = Proc.new { |arg|
68
+ case arg
69
+ when "#{Webpacker.config.public_output_path}/**/*"
70
+ all_files.keys
71
+ else
72
+ []
73
+ end
74
+ }
75
+ end
76
+
77
+ it "works with nested hashes and without any compiled files" do
78
+ allow(File).to receive(:delete).and_return(true)
79
+ expect(Webpacker.commands.clean).to be true
80
+ end
81
+
82
+ it "deletes only and only expired versioned files if no parameter passed" do
83
+ all_files.keys.each do |longpath|
84
+ allow(file_delete_mock).to receive(:delete).with(longpath)
85
+ end
86
+
87
+ with_time_dir_and_files_stub do
88
+ expect(Webpacker.commands.clean).to be true
89
+
90
+ # Verify that only and only expired files are deleted
91
+ all_files.keys.each do |longpath|
92
+ if expired_files.has_key? longpath
93
+ expect(file_delete_mock).to have_received(:delete).with(longpath)
94
+ else
95
+ expect(file_delete_mock).to_not have_received(:delete).with(longpath)
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ private
102
+
103
+ def with_time_dir_and_files_stub(&proc)
104
+ allow(Time).to receive(:now).and_return(now)
105
+ allow(Dir).to receive(:glob) { |arg| @dir_glob_stub.call(arg) }
106
+ allow(File).to receive(:directory?).and_return(false)
107
+ allow(File).to receive(:file?).and_return(true)
108
+ allow(File).to receive(:mtime) { |arg| file_mtime_stub.call(arg) }
109
+ allow(File).to receive(:delete) { |arg| file_delete_stub.call(arg) }
110
+
111
+ yield proc
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,57 @@
1
+ describe "Webpacker::Compiler" do
2
+ it "accepts custom environment variables" do
3
+ expect(Webpacker.compiler.send(:webpack_env)["FOO"]).to be nil
4
+
5
+ Webpacker.compiler.env["FOO"] = "BAR"
6
+ expect(Webpacker.compiler.send(:webpack_env)["FOO"]).to eq "BAR"
7
+ ensure
8
+ Webpacker.compiler.env = {}
9
+ end
10
+
11
+ it "returns true when fresh" do
12
+ mocked_strategy = double("Strategy")
13
+ expect(mocked_strategy).to receive(:stale?).and_return(false)
14
+
15
+ expect(Webpacker.compiler).to receive(:strategy).and_return(mocked_strategy)
16
+
17
+ expect(Webpacker.compiler.compile).to be true
18
+ end
19
+
20
+ it "returns true and calls after_compile_hook on successful compile" do
21
+ mocked_strategy = spy("Strategy")
22
+ expect(mocked_strategy).to receive(:stale?).and_return(true)
23
+
24
+ allow(Webpacker.compiler).to receive(:strategy).and_return(mocked_strategy)
25
+
26
+ status = OpenStruct.new(success?: true)
27
+ allow(Open3).to receive(:capture3).and_return([:sterr, :stdout, status])
28
+
29
+ expect(Webpacker.compiler.compile).to be true
30
+ expect(mocked_strategy).to have_received(:after_compile_hook)
31
+ end
32
+
33
+ it "returns false and calls after_compile_hook on failed compile" do
34
+ mocked_strategy = spy("Strategy")
35
+ allow(mocked_strategy).to receive(:stale?).and_return(true)
36
+ allow(mocked_strategy).to receive(:after_compile_hook)
37
+
38
+ allow(Webpacker.compiler).to receive(:strategy).and_return(mocked_strategy)
39
+
40
+ status = OpenStruct.new(success?: false)
41
+ allow(Open3).to receive(:capture3).and_return([:sterr, :stdout, status])
42
+
43
+ expect(Webpacker.compiler.compile).to be false
44
+ expect(mocked_strategy).to have_received(:after_compile_hook)
45
+ end
46
+
47
+ it "accepts external env variables" do
48
+ expect(Webpacker.compiler.send(:webpack_env)["WEBPACKER_ASSET_HOST"]).to be nil
49
+ expect(Webpacker.compiler.send(:webpack_env)["WEBPACKER_RELATIVE_URL_ROOT"]).to be nil
50
+
51
+ ENV["WEBPACKER_ASSET_HOST"] = "foo.bar"
52
+ ENV["WEBPACKER_RELATIVE_URL_ROOT"] = "/baz"
53
+
54
+ expect(Webpacker.compiler.send(:webpack_env)["WEBPACKER_ASSET_HOST"]).to eq "foo.bar"
55
+ expect(Webpacker.compiler.send(:webpack_env)["WEBPACKER_RELATIVE_URL_ROOT"]).to eq "/baz"
56
+ end
57
+ end
@@ -0,0 +1,20 @@
1
+ describe "Webpacker::CompilerStrategy" do
2
+ describe "#from_config" do
3
+ it "returns and instance of MtimeStrategy when compiler_strategy is set to mtime" do
4
+ allow(Webpacker.config).to receive(:compiler_strategy).and_return("mtime")
5
+ expect(Webpacker::CompilerStrategy.from_config).to be_an_instance_of(Webpacker::MtimeStrategy)
6
+ end
7
+
8
+ it "returns and instance of DigestStrategy when compiler_strategy is set to digest" do
9
+ allow(Webpacker.config).to receive(:compiler_strategy).and_return("digest")
10
+ expect(Webpacker::CompilerStrategy.from_config).to be_an_instance_of(Webpacker::DigestStrategy)
11
+ end
12
+
13
+ it "raise exception for unknown compiler_strategy in the config file" do
14
+ expected_error_message = "Unknown strategy 'other'. Available options are 'mtime' and 'digest'."
15
+ allow(Webpacker.config).to receive(:compiler_strategy).and_return("other")
16
+
17
+ expect { Webpacker::CompilerStrategy.from_config }.to raise_error(expected_error_message)
18
+ end
19
+ end
20
+ end