webpacker 5.1.0 → 5.3.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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.js +8 -8
  3. data/.github/workflows/jest.yml +38 -0
  4. data/.github/workflows/js-lint.yml +39 -0
  5. data/.github/workflows/rubocop.yml +39 -0
  6. data/.github/workflows/ruby.yml +66 -0
  7. data/.node-version +1 -1
  8. data/.rubocop.yml +113 -13
  9. data/CHANGELOG.md +27 -2
  10. data/Gemfile.lock +112 -103
  11. data/README.md +11 -19
  12. data/docs/css.md +58 -3
  13. data/docs/integrations.md +1 -1
  14. data/docs/target.md +22 -0
  15. data/docs/testing.md +1 -1
  16. data/docs/troubleshooting.md +3 -1
  17. data/docs/typescript.md +89 -8
  18. data/docs/webpack-dev-server.md +1 -1
  19. data/lib/install/config/babel.config.js +1 -3
  20. data/lib/install/config/webpacker.yml +1 -1
  21. data/lib/install/template.rb +9 -1
  22. data/lib/install/typescript.rb +2 -5
  23. data/lib/tasks/webpacker/check_node.rake +1 -1
  24. data/lib/tasks/webpacker/check_yarn.rake +2 -3
  25. data/lib/tasks/webpacker/yarn_install.rake +7 -1
  26. data/lib/webpacker/commands.rb +1 -1
  27. data/lib/webpacker/compiler.rb +7 -2
  28. data/lib/webpacker/configuration.rb +12 -4
  29. data/lib/webpacker/dev_server_runner.rb +2 -2
  30. data/lib/webpacker/helper.rb +29 -10
  31. data/lib/webpacker/runner.rb +1 -0
  32. data/lib/webpacker/version.rb +1 -1
  33. data/lib/webpacker/webpack_runner.rb +2 -2
  34. data/package.json +35 -35
  35. data/package/__tests__/config.js +12 -1
  36. data/package/__tests__/development.js +14 -1
  37. data/package/config.js +4 -1
  38. data/package/configPath.js +3 -0
  39. data/package/env.js +1 -2
  40. data/package/environments/__tests__/base.js +25 -8
  41. data/package/environments/base.js +5 -6
  42. data/package/environments/development.js +39 -33
  43. data/package/environments/production.js +1 -3
  44. data/package/rules/babel.js +11 -4
  45. data/package/rules/file.js +3 -2
  46. data/package/rules/node_modules.js +1 -3
  47. data/package/rules/sass.js +4 -1
  48. data/package/utils/helpers.js +1 -1
  49. data/test/compiler_test.rb +8 -3
  50. data/test/configuration_test.rb +8 -7
  51. data/test/dev_server_runner_test.rb +1 -1
  52. data/test/helper_test.rb +3 -0
  53. data/test/test_app/config/webpacker.yml +7 -1
  54. data/test/test_app/public/packs/manifest.json +1 -0
  55. data/test/webpack_runner_test.rb +1 -1
  56. data/webpacker.gemspec +1 -1
  57. data/yarn.lock +3290 -3588
  58. metadata +19 -13
@@ -0,0 +1,3 @@
1
+ const { resolve } = require('path')
2
+
3
+ module.exports = process.env.WEBPACKER_CONFIG || resolve('config', 'webpacker.yml')
data/package/env.js CHANGED
@@ -1,10 +1,9 @@
1
- const { resolve } = require('path')
2
1
  const { safeLoad } = require('js-yaml')
3
2
  const { readFileSync } = require('fs')
4
3
 
5
4
  const NODE_ENVIRONMENTS = ['development', 'production', 'test']
6
5
  const DEFAULT = 'production'
7
- const configPath = resolve('config', 'webpacker.yml')
6
+ const configPath = require('./configPath')
8
7
 
9
8
  const railsEnv = process.env.RAILS_ENV
10
9
  const nodeEnv = process.env.NODE_ENV
@@ -31,18 +31,18 @@ describe('Environment', () => {
31
31
 
32
32
  test('should return multi file entry points', () => {
33
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
- )
34
+ expect(config.entry.multi_entry.sort()).toEqual([
35
+ resolve('app', 'javascript', 'packs', 'multi_entry.css'),
36
+ resolve('app', 'javascript', 'packs', 'multi_entry.js')
37
+ ])
40
38
  })
41
39
 
42
40
  test('should return output', () => {
43
41
  const config = environment.toWebpackConfig()
44
42
  expect(config.output.filename).toEqual('js/[name]-[contenthash].js')
45
- expect(config.output.chunkFilename).toEqual('js/[name]-[contenthash].chunk.js')
43
+ expect(config.output.chunkFilename).toEqual(
44
+ 'js/[name]-[contenthash].chunk.js'
45
+ )
46
46
  })
47
47
 
48
48
  test('should return default loader rules for each file in config/loaders', () => {
@@ -51,7 +51,23 @@ describe('Environment', () => {
51
51
  const configRules = config.module.rules
52
52
 
53
53
  expect(defaultRules.length).toEqual(7)
54
- expect(configRules.length).toEqual(8)
54
+ expect(configRules.length).toEqual(7)
55
+ })
56
+
57
+ test('should return cache path for nodeModules rule', () => {
58
+ const nodeModulesLoader = rules.nodeModules.use.find(
59
+ (rule) => rule.loader === 'babel-loader'
60
+ )
61
+
62
+ expect(nodeModulesLoader.options.cacheDirectory).toBeTruthy()
63
+ })
64
+
65
+ test('should return cache path for babel-loader rule', () => {
66
+ const babelLoader = rules.babel.use.find(
67
+ (rule) => rule.loader === 'babel-loader'
68
+ )
69
+
70
+ expect(babelLoader.options.cacheDirectory).toBeTruthy()
55
71
  })
56
72
 
57
73
  test('should return default plugins', () => {
@@ -70,6 +86,7 @@ describe('Environment', () => {
70
86
  resolve('app', 'javascript'),
71
87
  resolve('app/assets'),
72
88
  resolve('/etc/yarn'),
89
+ resolve('app/elm'),
73
90
  'node_modules'
74
91
  ])
75
92
  })
@@ -30,7 +30,7 @@ const getPluginList = () => {
30
30
  const result = new ConfigList()
31
31
  result.append(
32
32
  'Environment',
33
- new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(process.env)))
33
+ new webpack.EnvironmentPlugin(process.env)
34
34
  )
35
35
  result.append('CaseSensitivePaths', new CaseSensitivePathsPlugin())
36
36
  result.append(
@@ -43,7 +43,6 @@ const getPluginList = () => {
43
43
  result.append(
44
44
  'Manifest',
45
45
  new WebpackAssetsManifest({
46
- integrity: false,
47
46
  entrypoints: true,
48
47
  writeToDisk: true,
49
48
  publicPath: config.publicPathWithoutCDN
@@ -84,8 +83,8 @@ const getEntryObject = () => {
84
83
  const getModulePaths = () => {
85
84
  const result = new ConfigList()
86
85
  result.append('source', resolve(config.source_path))
87
- if (config.resolved_paths) {
88
- config.resolved_paths.forEach((path) => result.append(path, resolve(path)))
86
+ if (config.additional_paths) {
87
+ config.additional_paths.forEach((path) => result.append(path, resolve(path)))
89
88
  }
90
89
  result.append('node_modules', 'node_modules')
91
90
  return result
@@ -137,7 +136,7 @@ module.exports = class Base {
137
136
  // https://twitter.com/wSokra/status/969633336732905474
138
137
  splitChunks: {
139
138
  chunks: 'all',
140
- name: false
139
+ name: true
141
140
  },
142
141
  // Separate runtime chunk to enable long term caching
143
142
  // https://twitter.com/wSokra/status/969679223278505985
@@ -164,7 +163,7 @@ module.exports = class Base {
164
163
 
165
164
  module: {
166
165
  strictExportPresence: true,
167
- rules: [{ parser: { requireEnsure: false } }, ...this.loaders.values()]
166
+ rules: this.loaders.values()
168
167
  },
169
168
 
170
169
  plugins: this.plugins.values(),
@@ -7,41 +7,47 @@ module.exports = class extends Base {
7
7
  constructor() {
8
8
  super()
9
9
 
10
- if (devServer.hmr) {
11
- this.plugins.append('HotModuleReplacement', new webpack.HotModuleReplacementPlugin())
12
- this.config.output.filename = '[name]-[hash].js'
13
- }
14
-
15
10
  this.config.merge({
16
11
  mode: 'development',
17
- devtool: 'cheap-module-source-map',
18
- devServer: {
19
- clientLogLevel: 'none',
20
- compress: devServer.compress,
21
- quiet: devServer.quiet,
22
- disableHostCheck: devServer.disable_host_check,
23
- host: devServer.host,
24
- port: devServer.port,
25
- https: devServer.https,
26
- hot: devServer.hmr,
27
- contentBase,
28
- inline: devServer.inline,
29
- useLocalIp: devServer.use_local_ip,
30
- public: devServer.public,
31
- publicPath,
32
- historyApiFallback: {
33
- disableDotRule: true
34
- },
35
- headers: devServer.headers,
36
- overlay: devServer.overlay,
37
- stats: {
38
- entrypoints: false,
39
- errorDetails: true,
40
- modules: false,
41
- moduleTrace: false
42
- },
43
- watchOptions: devServer.watch_options
44
- }
12
+ devtool: 'cheap-module-source-map'
45
13
  })
14
+
15
+ if (process.env.WEBPACK_DEV_SERVER
16
+ && process.env.WEBPACK_DEV_SERVER !== 'undefined') {
17
+ if (devServer.hmr) {
18
+ this.plugins.append('HotModuleReplacement', new webpack.HotModuleReplacementPlugin())
19
+ this.config.output.filename = '[name]-[hash].js'
20
+ }
21
+
22
+ this.config.merge({
23
+ devServer: {
24
+ clientLogLevel: 'none',
25
+ compress: devServer.compress,
26
+ quiet: devServer.quiet,
27
+ disableHostCheck: devServer.disable_host_check,
28
+ host: devServer.host,
29
+ port: devServer.port,
30
+ https: devServer.https,
31
+ hot: devServer.hmr,
32
+ contentBase,
33
+ inline: devServer.inline,
34
+ useLocalIp: devServer.use_local_ip,
35
+ public: devServer.public,
36
+ publicPath,
37
+ historyApiFallback: {
38
+ disableDotRule: true
39
+ },
40
+ headers: devServer.headers,
41
+ overlay: devServer.overlay,
42
+ stats: {
43
+ entrypoints: false,
44
+ errorDetails: true,
45
+ modules: false,
46
+ moduleTrace: false
47
+ },
48
+ watchOptions: devServer.watch_options
49
+ }
50
+ })
51
+ }
46
52
  }
47
53
  }
@@ -13,7 +13,6 @@ module.exports = class extends Base {
13
13
  new CompressionPlugin({
14
14
  filename: '[path].gz[query]',
15
15
  algorithm: 'gzip',
16
- cache: true,
17
16
  test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
18
17
  })
19
18
  )
@@ -24,7 +23,6 @@ module.exports = class extends Base {
24
23
  new CompressionPlugin({
25
24
  filename: '[path].br[query]',
26
25
  algorithm: 'brotliCompress',
27
- cache: true,
28
26
  test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
29
27
  })
30
28
  )
@@ -48,7 +46,7 @@ module.exports = class extends Base {
48
46
  optimization: {
49
47
  minimizer: [
50
48
  new TerserPlugin({
51
- parallel: true,
49
+ parallel: Number.parseInt(process.env.WEBPACKER_PARALLEL, 10) || true,
52
50
  cache: true,
53
51
  sourceMap: true,
54
52
  terserOptions: {
@@ -1,18 +1,25 @@
1
- const { join, resolve } = require('path')
2
- const { cache_path: cachePath, source_path: sourcePath, resolved_paths: resolvedPaths } = require('../config')
1
+ const { resolve } = require('path')
2
+ const { realpathSync } = require('fs')
3
+ const { source_path: sourcePath, additional_paths: additionalPaths } = require('../config')
3
4
  const { nodeEnv } = require('../env')
4
5
 
5
6
  // Process application Javascript code with Babel.
6
7
  // Uses application .babelrc to apply any transformations
7
8
  module.exports = {
8
9
  test: /\.(js|jsx|mjs|ts|tsx)?(\.erb)?$/,
9
- include: [sourcePath, ...resolvedPaths].map((p) => resolve(p)),
10
+ include: [sourcePath, ...additionalPaths].map((p) => {
11
+ try {
12
+ return realpathSync(p)
13
+ } catch (e) {
14
+ return resolve(p)
15
+ }
16
+ }),
10
17
  exclude: /node_modules/,
11
18
  use: [
12
19
  {
13
20
  loader: 'babel-loader',
14
21
  options: {
15
- cacheDirectory: join(cachePath, 'babel-loader-node-modules'),
22
+ cacheDirectory: true,
16
23
  cacheCompression: nodeEnv === 'production',
17
24
  compact: nodeEnv === 'production'
18
25
  }
@@ -1,4 +1,4 @@
1
- const { join } = require('path')
1
+ const { join, normalize } = require('path')
2
2
  const { source_path: sourcePath, static_assets_extensions: fileExtensions } = require('../config')
3
3
 
4
4
  module.exports = {
@@ -8,11 +8,12 @@ module.exports = {
8
8
  loader: 'file-loader',
9
9
  options: {
10
10
  name(file) {
11
- if (file.includes(sourcePath)) {
11
+ if (file.includes(normalize(sourcePath))) {
12
12
  return 'media/[path][name]-[hash].[ext]'
13
13
  }
14
14
  return 'media/[folder]/[name]-[hash:8].[ext]'
15
15
  },
16
+ esModule: false,
16
17
  context: join(sourcePath)
17
18
  }
18
19
  }
@@ -1,5 +1,3 @@
1
- const { join } = require('path')
2
- const { cache_path: cachePath } = require('../config')
3
1
  const { nodeEnv } = require('../env')
4
2
 
5
3
  // Compile standard ES features for JS in node_modules with Babel.
@@ -14,7 +12,7 @@ module.exports = {
14
12
  options: {
15
13
  babelrc: false,
16
14
  presets: [['@babel/preset-env', { modules: false }]],
17
- cacheDirectory: join(cachePath, 'babel-loader-node-modules'),
15
+ cacheDirectory: true,
18
16
  cacheCompression: nodeEnv === 'production',
19
17
  compact: false,
20
18
  sourceMaps: false
@@ -1,11 +1,14 @@
1
+ /* eslint global-require: 0 */
2
+
1
3
  const getStyleRule = require('../utils/get_style_rule')
2
- const { resolved_paths: includePaths } = require('../config')
4
+ const { additional_paths: includePaths } = require('../config')
3
5
 
4
6
  module.exports = getStyleRule(/\.(scss|sass)(\.erb)?$/i, false, [
5
7
  {
6
8
  loader: 'sass-loader',
7
9
  options: {
8
10
  sourceMap: true,
11
+ implementation: require('sass'),
9
12
  sassOptions: {
10
13
  includePaths
11
14
  }
@@ -1,4 +1,4 @@
1
- const { stringify } = require('flatted/cjs')
1
+ const { stringify } = require('flatted')
2
2
 
3
3
  const isObject = (value) => typeof value === 'object'
4
4
  && value !== null
@@ -25,9 +25,10 @@ class CompilerTest < Minitest::Test
25
25
 
26
26
  def test_default_watched_paths
27
27
  assert_equal Webpacker.compiler.send(:default_watched_paths), [
28
- "app/assets/**/*{.mjs,.js,.sass,.scss,.css,.module.sass,.module.scss,.module.css,.png,.svg,.gif,.jpeg,.jpg}",
29
- "/etc/yarn/**/*{.mjs,.js,.sass,.scss,.css,.module.sass,.module.scss,.module.css,.png,.svg,.gif,.jpeg,.jpg}",
30
- "app/javascript/**/*{.mjs,.js,.sass,.scss,.css,.module.sass,.module.scss,.module.css,.png,.svg,.gif,.jpeg,.jpg}",
28
+ "app/assets/**/*{.mjs,.js,.sass,.scss,.css,.module.sass,.module.scss,.module.css,.png,.svg,.gif,.jpeg,.jpg,.elm}",
29
+ "/etc/yarn/**/*{.mjs,.js,.sass,.scss,.css,.module.sass,.module.scss,.module.css,.png,.svg,.gif,.jpeg,.jpg,.elm}",
30
+ "app/elm/**/*{.mjs,.js,.sass,.scss,.css,.module.sass,.module.scss,.module.css,.png,.svg,.gif,.jpeg,.jpg,.elm}",
31
+ "app/javascript/**/*{.mjs,.js,.sass,.scss,.css,.module.sass,.module.scss,.module.css,.png,.svg,.gif,.jpeg,.jpg,.elm}",
31
32
  "yarn.lock",
32
33
  "package.json",
33
34
  "config/webpack/**/*"
@@ -39,6 +40,10 @@ class CompilerTest < Minitest::Test
39
40
  assert !Webpacker.compiler.fresh?
40
41
  end
41
42
 
43
+ def test_compile
44
+ assert !Webpacker.compiler.compile
45
+ end
46
+
42
47
  def test_freshness_on_compile_success
43
48
  status = OpenStruct.new(success?: true)
44
49
 
@@ -16,7 +16,7 @@ class ConfigurationTest < Webpacker::Test
16
16
 
17
17
  def test_source_path_globbed
18
18
  assert_equal @config.source_path_globbed,
19
- "app/javascript/**/*{.mjs,.js,.sass,.scss,.css,.module.sass,.module.scss,.module.css,.png,.svg,.gif,.jpeg,.jpg}"
19
+ "app/javascript/**/*{.mjs,.js,.sass,.scss,.css,.module.sass,.module.scss,.module.css,.png,.svg,.gif,.jpeg,.jpg,.elm}"
20
20
  end
21
21
 
22
22
  def test_source_entry_path
@@ -53,14 +53,15 @@ class ConfigurationTest < Webpacker::Test
53
53
  assert_equal @config.cache_path.to_s, cache_path
54
54
  end
55
55
 
56
- def test_resolved_paths
57
- assert_equal @config.resolved_paths, ["app/assets", "/etc/yarn"]
56
+ def test_additional_paths
57
+ assert_equal @config.additional_paths, ["app/assets", "/etc/yarn", "app/elm"]
58
58
  end
59
59
 
60
- def test_resolved_paths_globbed
61
- assert_equal @config.resolved_paths_globbed, [
62
- "app/assets/**/*{.mjs,.js,.sass,.scss,.css,.module.sass,.module.scss,.module.css,.png,.svg,.gif,.jpeg,.jpg}",
63
- "/etc/yarn/**/*{.mjs,.js,.sass,.scss,.css,.module.sass,.module.scss,.module.css,.png,.svg,.gif,.jpeg,.jpg}"
60
+ def test_additional_paths_globbed
61
+ assert_equal @config.additional_paths_globbed, [
62
+ "app/assets/**/*{.mjs,.js,.sass,.scss,.css,.module.sass,.module.scss,.module.css,.png,.svg,.gif,.jpeg,.jpg,.elm}",
63
+ "/etc/yarn/**/*{.mjs,.js,.sass,.scss,.css,.module.sass,.module.scss,.module.css,.png,.svg,.gif,.jpeg,.jpg,.elm}",
64
+ "app/elm/**/*{.mjs,.js,.sass,.scss,.css,.module.sass,.module.scss,.module.css,.png,.svg,.gif,.jpeg,.jpg,.elm}"
64
65
  ]
65
66
  end
66
67
 
@@ -36,7 +36,7 @@ class DevServerRunnerTest < Webpacker::Test
36
36
  klass = Webpacker::DevServerRunner
37
37
  instance = klass.new([])
38
38
  mock = Minitest::Mock.new
39
- mock.expect(:call, nil, [{}, *cmd])
39
+ mock.expect(:call, nil, [Webpacker::Compiler.env, *cmd])
40
40
 
41
41
  klass.stub(:new, instance) do
42
42
  instance.stub(:node_modules_bin_exist?, use_node_modules) do
data/test/helper_test.rb CHANGED
@@ -50,6 +50,9 @@ class HelperTest < ActionView::TestCase
50
50
  assert_equal \
51
51
  "<img alt=\"Edit Entry\" src=\"/packs/media/images/nested/image-c38deda30895059837cf.jpg\" width=\"16\" height=\"10\" />",
52
52
  image_pack_tag("media/images/nested/image.jpg", size: "16x10", alt: "Edit Entry")
53
+ assert_equal \
54
+ "<img srcset=\"/packs/media/images/image-2x-7cca48e6cae66ec07b8e.jpg 2x\" src=\"/packs/media/images/image-c38deda30895059837cf.jpg\" />",
55
+ image_pack_tag("media/images/image.jpg", srcset: { "media/images/image-2x.jpg" => "2x" })
53
56
  end
54
57
 
55
58
  def test_favicon_pack_tag
@@ -10,10 +10,15 @@ default: &default
10
10
 
11
11
  # Additional paths webpack should lookup modules
12
12
  # ['app/assets', 'engine/foo/app/assets']
13
- resolved_paths:
13
+ additional_paths:
14
14
  - app/assets
15
15
  - /etc/yarn
16
16
 
17
+ # This configuration option is deprecated and is only here for testing, to
18
+ # ensure backwards-compatibility. Please use `additional_paths`.
19
+ resolved_paths:
20
+ - app/elm
21
+
17
22
  # Reload manifest.json on all requests so we reload latest compiled packs
18
23
  cache_manifest: false
19
24
 
@@ -43,6 +48,7 @@ default: &default
43
48
  - .gif
44
49
  - .jpeg
45
50
  - .jpg
51
+ - .elm
46
52
 
47
53
  development:
48
54
  <<: *default
@@ -6,6 +6,7 @@
6
6
  "application.png": "/packs/application-k344a6d59eef8632c9d1.png",
7
7
  "fonts/fa-regular-400.woff2": "/packs/fonts/fa-regular-400-944fb546bd7018b07190a32244f67dc9.woff2",
8
8
  "media/images/image.jpg": "/packs/media/images/image-c38deda30895059837cf.jpg",
9
+ "media/images/image-2x.jpg": "/packs/media/images/image-2x-7cca48e6cae66ec07b8e.jpg",
9
10
  "media/images/nested/image.jpg": "/packs/media/images/nested/image-c38deda30895059837cf.jpg",
10
11
  "media/images/mb-icon.png": "/packs/media/images/mb-icon-c38deda30895059837cf.png",
11
12
  "media/images/nested/mb-icon.png": "/packs/media/images/nested/mb-icon-c38deda30895059837cf.png",
@@ -36,7 +36,7 @@ class WebpackRunnerTest < Webpacker::Test
36
36
  klass = Webpacker::WebpackRunner
37
37
  instance = klass.new([])
38
38
  mock = Minitest::Mock.new
39
- mock.expect(:call, nil, [{}, *cmd])
39
+ mock.expect(:call, nil, [Webpacker::Compiler.env, *cmd])
40
40
 
41
41
  klass.stub(:new, instance) do
42
42
  instance.stub(:node_modules_bin_exist?, use_node_modules) do
data/webpacker.gemspec CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
23
23
  s.add_dependency "semantic_range", ">= 2.3.0"
24
24
 
25
25
  s.add_development_dependency "bundler", ">= 1.3.0"
26
- s.add_development_dependency "rubocop", "< 0.69"
26
+ s.add_development_dependency "rubocop", "0.93.1"
27
27
  s.add_development_dependency "rubocop-performance"
28
28
 
29
29
  s.files = `git ls-files`.split("\n")