webpacker 6.0.0.beta.7 → 6.0.0.rc.5

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/jest.yml +5 -2
  3. data/.github/workflows/js-lint.yml +4 -1
  4. data/.github/workflows/rubocop.yml +1 -1
  5. data/.github/workflows/ruby.yml +12 -12
  6. data/.node-version +1 -1
  7. data/.rubocop.yml +1 -0
  8. data/CHANGELOG.md +21 -10
  9. data/Gemfile.lock +83 -83
  10. data/README.md +160 -157
  11. data/config/webpacker.yml +1 -1
  12. data/docs/developing_webpacker.md +29 -0
  13. data/docs/troubleshooting.md +53 -23
  14. data/docs/v6_upgrade.md +31 -42
  15. data/gemfiles/Gemfile-rails-edge +1 -1
  16. data/gemfiles/Gemfile-rails.6.1.x +12 -0
  17. data/lib/install/bin/yarn +18 -0
  18. data/lib/install/config/webpacker.yml +14 -17
  19. data/lib/install/package.json +17 -0
  20. data/lib/install/packs/entrypoints/application.js +3 -4
  21. data/lib/install/template.rb +28 -15
  22. data/lib/tasks/webpacker/check_node.rake +3 -1
  23. data/lib/tasks/webpacker/check_yarn.rake +4 -2
  24. data/lib/tasks/webpacker/clobber.rake +1 -1
  25. data/lib/tasks/webpacker/verify_config.rake +14 -0
  26. data/lib/tasks/webpacker/verify_install.rake +1 -11
  27. data/lib/tasks/yarn.rake +36 -0
  28. data/lib/webpacker/commands.rb +19 -15
  29. data/lib/webpacker/configuration.rb +15 -4
  30. data/lib/webpacker/dev_server.rb +6 -0
  31. data/lib/webpacker/dev_server_runner.rb +6 -3
  32. data/lib/webpacker/env.rb +5 -1
  33. data/lib/webpacker/helper.rb +14 -8
  34. data/lib/webpacker/instance.rb +4 -0
  35. data/lib/webpacker/manifest.rb +1 -2
  36. data/lib/webpacker/railtie.rb +1 -2
  37. data/lib/webpacker/runner.rb +1 -1
  38. data/lib/webpacker/version.rb +1 -1
  39. data/lib/webpacker.rb +1 -1
  40. data/package/__tests__/development.js +4 -4
  41. data/package/__tests__/env.js +8 -4
  42. data/package/babel/preset.js +0 -1
  43. data/package/config.js +3 -3
  44. data/package/env.js +6 -3
  45. data/package/environments/__tests__/base.js +3 -3
  46. data/package/environments/base.js +12 -7
  47. data/package/environments/development.js +37 -33
  48. data/package/index.js +2 -0
  49. data/package/inliningCss.js +7 -0
  50. data/package/rules/file.js +1 -1
  51. data/package/rules/sass.js +1 -2
  52. data/package/utils/get_style_rule.js +4 -2
  53. data/package.json +25 -29
  54. data/test/command_test.rb +76 -0
  55. data/test/configuration_test.rb +1 -1
  56. data/test/dev_server_runner_test.rb +5 -2
  57. data/test/helper_test.rb +48 -34
  58. data/test/manifest_test.rb +10 -2
  59. data/test/mounted_app/test/dummy/config/webpacker.yml +1 -1
  60. data/test/test_app/config/webpacker.yml +1 -3
  61. data/test/test_app/config/webpacker_other_location.yml +79 -0
  62. data/test/test_app/public/packs/manifest.json +12 -5
  63. data/test/webpacker_test.rb +17 -0
  64. data/webpacker.gemspec +1 -1
  65. data/yarn.lock +2202 -2680
  66. metadata +18 -9
@@ -42,7 +42,6 @@ module.exports = function config(api) {
42
42
  ]
43
43
  ].filter(Boolean),
44
44
  plugins: [
45
- 'babel-plugin-macros',
46
45
  ['@babel/plugin-proposal-class-properties', { loose: true }],
47
46
  ['@babel/plugin-transform-runtime', { helpers: false }],
48
47
  isProductionEnv &&
data/package/config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const { resolve } = require('path')
2
- const { safeLoad } = require('js-yaml')
2
+ const { load } = require('js-yaml')
3
3
  const { readFileSync } = require('fs')
4
4
  const { merge } = require('webpack-merge')
5
5
  const { ensureTrailingSlash } = require('./utils/helpers')
@@ -9,12 +9,12 @@ const configPath = require('./configPath')
9
9
  const defaultConfigPath = require.resolve('../lib/install/config/webpacker.yml')
10
10
 
11
11
  const getDefaultConfig = () => {
12
- const defaultConfig = safeLoad(readFileSync(defaultConfigPath), 'utf8')
12
+ const defaultConfig = load(readFileSync(defaultConfigPath), 'utf8')
13
13
  return defaultConfig[railsEnv] || defaultConfig.production
14
14
  }
15
15
 
16
16
  const defaults = getDefaultConfig()
17
- const app = safeLoad(readFileSync(configPath), 'utf8')[railsEnv]
17
+ const app = load(readFileSync(configPath), 'utf8')[railsEnv]
18
18
 
19
19
  const config = merge(defaults, app)
20
20
  config.outputPath = resolve(config.public_root_path, config.public_output_path)
data/package/env.js CHANGED
@@ -1,4 +1,4 @@
1
- const { safeLoad } = require('js-yaml')
1
+ const { load } = require('js-yaml')
2
2
  const { readFileSync } = require('fs')
3
3
 
4
4
  const NODE_ENVIRONMENTS = ['development', 'production', 'test']
@@ -12,13 +12,16 @@ const nodeEnv
12
12
  const isProduction = nodeEnv === 'production'
13
13
  const isDevelopment = nodeEnv === 'development'
14
14
 
15
- const config = safeLoad(readFileSync(configPath), 'utf8')
15
+ const config = load(readFileSync(configPath), 'utf8')
16
16
  const availableEnvironments = Object.keys(config).join('|')
17
17
  const regex = new RegExp(`^(${availableEnvironments})$`, 'g')
18
18
 
19
+ const runningWebpackDevServer = process.env.WEBPACK_SERVE === 'true'
20
+
19
21
  module.exports = {
20
22
  railsEnv: railsEnv && railsEnv.match(regex) ? railsEnv : DEFAULT,
21
23
  nodeEnv,
22
24
  isProduction,
23
- isDevelopment
25
+ isDevelopment,
26
+ runningWebpackDevServer
24
27
  }
@@ -29,9 +29,9 @@ describe('Base config', () => {
29
29
  })
30
30
 
31
31
  test('should return output', () => {
32
- expect(baseConfig.output.filename).toEqual('js/[name]-[contenthash].js')
32
+ expect(baseConfig.output.filename).toEqual('js/[name].js')
33
33
  expect(baseConfig.output.chunkFilename).toEqual(
34
- 'js/[name]-[contenthash].chunk.js'
34
+ 'js/[name].chunk.js'
35
35
  )
36
36
  })
37
37
 
@@ -44,7 +44,7 @@ describe('Base config', () => {
44
44
  })
45
45
 
46
46
  test('should return default plugins', () => {
47
- expect(baseConfig.plugins.length).toEqual(3)
47
+ expect(baseConfig.plugins.length).toEqual(2)
48
48
  })
49
49
 
50
50
  test('should return default resolveLoader', () => {
@@ -5,10 +5,10 @@ const { basename, dirname, join, relative, resolve } = require('path')
5
5
  const extname = require('path-complete-extname')
6
6
  const PnpWebpackPlugin = require('pnp-webpack-plugin')
7
7
  const { sync: globSync } = require('glob')
8
- const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
9
8
  const WebpackAssetsManifest = require('webpack-assets-manifest')
10
9
  const webpack = require('webpack')
11
10
  const rules = require('../rules')
11
+ const { isProduction } = require('../env')
12
12
  const config = require('../config')
13
13
  const { moduleExists } = require('../utils/helpers')
14
14
 
@@ -52,7 +52,6 @@ const getModulePaths = () => {
52
52
  const getPlugins = () => {
53
53
  const plugins = [
54
54
  new webpack.EnvironmentPlugin(process.env),
55
- new CaseSensitivePathsPlugin(),
56
55
  new WebpackAssetsManifest({
57
56
  entrypoints: true,
58
57
  writeToDisk: true,
@@ -63,11 +62,12 @@ const getPlugins = () => {
63
62
  ]
64
63
 
65
64
  if (moduleExists('css-loader') && moduleExists('mini-css-extract-plugin')) {
65
+ const hash = isProduction ? '-[contenthash:8]' : ''
66
66
  const MiniCssExtractPlugin = require('mini-css-extract-plugin')
67
67
  plugins.push(
68
68
  new MiniCssExtractPlugin({
69
- filename: 'css/[name]-[contenthash:8].css',
70
- chunkFilename: 'css/[id]-[contenthash:8].css'
69
+ filename: `css/[name]${hash}.css`,
70
+ chunkFilename: `css/[id]${hash}.css`
71
71
  })
72
72
  )
73
73
  }
@@ -75,12 +75,17 @@ const getPlugins = () => {
75
75
  return plugins
76
76
  }
77
77
 
78
+ // Don't use contentHash except for production for performance
79
+ // https://webpack.js.org/guides/build-performance/#avoid-production-specific-tooling
80
+ const hash = isProduction ? '-[contenthash]' : ''
78
81
  module.exports = {
79
82
  mode: 'production',
80
83
  output: {
81
- filename: 'js/[name]-[contenthash].js',
82
- chunkFilename: 'js/[name]-[contenthash].chunk.js',
83
- hotUpdateChunkFilename: 'js/[id]-[hash].hot-update.js',
84
+ filename: `js/[name]${hash}.js`,
85
+ chunkFilename: `js/[name]${hash}.chunk.js`,
86
+
87
+ // https://webpack.js.org/configuration/output/#outputhotupdatechunkfilename
88
+ hotUpdateChunkFilename: 'js/[id].[fullhash].hot-update.js',
84
89
  path: config.outputPath,
85
90
  publicPath: config.publicPath
86
91
  },
@@ -1,8 +1,8 @@
1
1
  const { merge } = require('webpack-merge')
2
- const webpack = require('webpack')
3
2
 
4
3
  const baseConfig = require('./base')
5
4
  const devServer = require('../dev_server')
5
+ const { runningWebpackDevServer } = require('../env')
6
6
 
7
7
  const { outputPath: contentBase, publicPath } = require('../config')
8
8
 
@@ -11,44 +11,48 @@ let devConfig = {
11
11
  devtool: 'cheap-module-source-map'
12
12
  }
13
13
 
14
- if (
15
- process.env.WEBPACK_DEV_SERVER &&
16
- process.env.WEBPACK_DEV_SERVER !== 'undefined'
17
- ) {
14
+ if (runningWebpackDevServer) {
18
15
  if (devServer.hmr) {
19
16
  devConfig = merge(devConfig, {
20
- output: { filename: '[name]-[hash].js' },
21
- plugins: [new webpack.HotModuleReplacementPlugin()]
17
+ output: { filename: '[name]-[hash].js' }
22
18
  })
23
19
  }
24
20
 
25
- devConfig = merge(devConfig, {
26
- devServer: {
27
- clientLogLevel: 'none',
28
- compress: devServer.compress,
29
- quiet: devServer.quiet,
30
- disableHostCheck: devServer.disable_host_check,
31
- host: devServer.host,
32
- port: devServer.port,
33
- https: devServer.https,
34
- hot: devServer.hmr,
35
- contentBase,
36
- inline: devServer.inline,
37
- injectClient: devServer.inject_client,
38
- useLocalIp: devServer.use_local_ip,
39
- public: devServer.public,
40
- publicPath,
41
- historyApiFallback: { disableDotRule: true },
42
- headers: devServer.headers,
43
- overlay: devServer.overlay,
44
- stats: {
45
- entrypoints: false,
46
- errorDetails: true,
47
- modules: false,
48
- moduleTrace: false
49
- },
50
- watchOptions: devServer.watch_options
21
+ const devServerConfig = {
22
+ devMiddleware: {
23
+ publicPath
24
+ },
25
+ compress: devServer.compress,
26
+ allowedHosts: devServer.allowed_hosts,
27
+ host: devServer.host,
28
+ port: devServer.port,
29
+ https: devServer.https,
30
+ hot: devServer.hmr,
31
+ liveReload: !devServer.hmr,
32
+ historyApiFallback: { disableDotRule: true },
33
+ headers: devServer.headers,
34
+ static: {
35
+ publicPath: contentBase
51
36
  }
37
+ }
38
+
39
+ if (devServer.static) {
40
+ devServerConfig.static = { ...devServerConfig.static, ...devServer.static }
41
+ }
42
+
43
+ if (devServer.client) {
44
+ devServerConfig.client = devServer.client
45
+ }
46
+
47
+ devConfig = merge(devConfig, {
48
+ stats: {
49
+ colors: true,
50
+ entrypoints: false,
51
+ errorDetails: true,
52
+ modules: false,
53
+ moduleTrace: false
54
+ },
55
+ devServer: devServerConfig
52
56
  })
53
57
  }
54
58
 
data/package/index.js CHANGED
@@ -10,6 +10,7 @@ const config = require('./config')
10
10
  const devServer = require('./dev_server')
11
11
  const { nodeEnv } = require('./env')
12
12
  const { moduleExists, canProcess } = require('./utils/helpers')
13
+ const inliningCss = require('./inliningCss')
13
14
 
14
15
  const webpackConfig = () => {
15
16
  const path = resolve(__dirname, 'environments', `${nodeEnv}.js`)
@@ -25,5 +26,6 @@ module.exports = {
25
26
  rules,
26
27
  moduleExists,
27
28
  canProcess,
29
+ inliningCss,
28
30
  ...webpackMerge
29
31
  }
@@ -0,0 +1,7 @@
1
+ const { runningWebpackDevServer } = require('./env')
2
+ const devServer = require('./dev_server')
3
+
4
+ // This logic is tied to lib/webpacker/instance.rb
5
+ const inliningCss = runningWebpackDevServer && devServer.hmr
6
+
7
+ module.exports = inliningCss
@@ -18,6 +18,6 @@ module.exports = {
18
18
  exclude: [/\.(js|mjs|jsx|ts|tsx)$/],
19
19
  type: 'asset/resource',
20
20
  generator: {
21
- filename: 'media/images/[hash][ext][query]'
21
+ filename: 'static/[hash][ext][query]'
22
22
  }
23
23
  }
@@ -9,8 +9,7 @@ module.exports = canProcess('sass-loader', (resolvedPath) =>
9
9
  {
10
10
  loader: resolvedPath,
11
11
  options: {
12
- sassOptions: { includePaths },
13
- implementation: require('sass')
12
+ sassOptions: { includePaths }
14
13
  }
15
14
  }
16
15
  ])
@@ -1,6 +1,6 @@
1
1
  /* eslint global-require: 0 */
2
-
3
2
  const { canProcess, moduleExists } = require('./helpers')
3
+ const inliningCss = require('../inliningCss')
4
4
 
5
5
  const getStyleRule = (test, preprocessors = []) => {
6
6
  if (moduleExists('css-loader')) {
@@ -10,8 +10,10 @@ const getStyleRule = (test, preprocessors = []) => {
10
10
  options: { sourceMap: true }
11
11
  }))
12
12
 
13
+ // style-loader is required when using css modules with HMR on the webpack-dev-server
14
+
13
15
  const use = [
14
- { loader: require('mini-css-extract-plugin').loader },
16
+ inliningCss ? 'style-loader' : require('mini-css-extract-plugin').loader,
15
17
  {
16
18
  loader: require.resolve('css-loader'),
17
19
  options: {
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rails/webpacker",
3
- "version": "6.0.0-beta.7",
3
+ "version": "6.0.0-rc.5",
4
4
  "description": "Use webpack to manage app-like JavaScript modules in Rails",
5
5
  "main": "package/index.js",
6
6
  "files": [
@@ -8,40 +8,36 @@
8
8
  "lib/install/config/webpacker.yml"
9
9
  ],
10
10
  "engines": {
11
- "node": ">=10.22.1 || ^12 || >=14",
12
- "yarn": ">=1 <3"
11
+ "node": ">= 12.13.0 || >=14",
12
+ "yarn": ">=1 <4"
13
13
  },
14
14
  "dependencies": {
15
- "@babel/core": "^7.12.9",
16
- "@babel/plugin-proposal-class-properties": "^7.12.1",
17
- "@babel/plugin-transform-runtime": "^7.12.1",
18
- "@babel/preset-env": "^7.12.11",
19
- "@babel/runtime": "^7.12.5",
15
+ "@babel/core": "^7.15.0",
16
+ "@babel/plugin-proposal-class-properties": "^7.14.5",
17
+ "@babel/plugin-transform-runtime": "^7.15.0",
18
+ "@babel/preset-env": "^7.15.0",
19
+ "@babel/runtime": "^7.15.3",
20
20
  "babel-loader": "^8.2.2",
21
- "babel-plugin-macros": "^3.0.1",
22
- "case-sensitive-paths-webpack-plugin": "^2.3.0",
23
- "compression-webpack-plugin": "^7.1.0",
24
- "core-js": "^3.8.0",
25
- "glob": "^7.1.6",
26
- "js-yaml": "^3.14.0",
21
+ "compression-webpack-plugin": "^8.0.1",
22
+ "glob": "^7.1.7",
23
+ "js-yaml": "^4.1.0",
27
24
  "path-complete-extname": "^1.0.0",
28
- "pnp-webpack-plugin": "^1.6.4",
29
- "regenerator-runtime": "^0.13.7",
30
- "terser-webpack-plugin": "^5.0.3",
31
- "webpack": "^5.11.0",
32
- "webpack-assets-manifest": "^5.0.0",
33
- "webpack-cli": "^4.2.0",
34
- "webpack-merge": "^5.7.2",
35
- "webpack-sources": "^2.2.0"
25
+ "pnp-webpack-plugin": "^1.7.0",
26
+ "terser-webpack-plugin": "^5.1.4",
27
+ "webpack": "^5.51.1",
28
+ "webpack-assets-manifest": "^5.0.6",
29
+ "webpack-cli": "^4.8.0",
30
+ "webpack-merge": "^5.8.0",
31
+ "webpack-sources": "^3.2.0"
36
32
  },
37
33
  "devDependencies": {
38
- "eslint": "^7.16.0",
39
- "eslint-config-airbnb": "^18.2.0",
40
- "eslint-config-prettier": "^7.1.0",
41
- "eslint-plugin-import": "^2.22.1",
42
- "eslint-plugin-jsx-a11y": "^6.3.1",
43
- "eslint-plugin-react": "^7.21.4",
44
- "jest": "^26.5.3"
34
+ "eslint": "^7.32.0",
35
+ "eslint-config-airbnb": "^18.2.1",
36
+ "eslint-config-prettier": "^8.3.0",
37
+ "eslint-plugin-import": "^2.24.1",
38
+ "eslint-plugin-jsx-a11y": "^6.4.1",
39
+ "eslint-plugin-react": "^7.24.0",
40
+ "jest": "^27.0.6"
45
41
  },
46
42
  "jest": {
47
43
  "testRegex": "(/__tests__/.*|(\\.|/))\\.jsx?$",
data/test/command_test.rb CHANGED
@@ -31,3 +31,79 @@ class CommandTest < Minitest::Test
31
31
  end
32
32
  end
33
33
  end
34
+
35
+ class ClearCommandVersioningTest < Minitest::Test
36
+ def setup
37
+ @now = Time.parse("2021-01-01 12:34:56 UTC")
38
+ # Test assets to be kept and deleted, path and mtime
39
+ @prev_files = {
40
+ # recent versions to be kept with Webpacker.commands.clean(count = 2)
41
+ "js/application-deadbeef.js" => @now - 4000,
42
+ "js/common-deadbeee.js" => @now - 4002,
43
+ "css/common-deadbeed.css" => @now - 4004,
44
+ "media/images/logo-deadbeeb.css" => @now - 4006,
45
+ "js/application-1eadbeef.js" => @now - 8000,
46
+ "js/common-1eadbeee.js" => @now - 8002,
47
+ "css/common-1eadbeed.css" => @now - 8004,
48
+ "media/images/logo-1eadbeeb.css" => @now - 8006,
49
+ # new files to be kept with Webpacker.commands.clean(age = 3600)
50
+ "js/brandnew-0001.js" => @now,
51
+ "js/brandnew-0002.js" => @now - 10,
52
+ "js/brandnew-0003.js" => @now - 20,
53
+ "js/brandnew-0004.js" => @now - 40,
54
+ }.transform_keys { |path| "#{Webpacker.config.public_output_path}/#{path}" }
55
+ @expired_files = {
56
+ # old files that are outside count = 2 or age = 3600 and to be deleted
57
+ "js/application-0eadbeef.js" => @now - 9000,
58
+ "js/common-0eadbeee.js" => @now - 9002,
59
+ "css/common-0eadbeed.css" => @now - 9004,
60
+ "js/brandnew-0005.js" => @now - 3640,
61
+ }.transform_keys { |path| "#{Webpacker.config.public_output_path}/#{path}" }
62
+ @all_files = @prev_files.merge(@expired_files)
63
+ @dir_glob_stub = Proc.new { |arg|
64
+ case arg
65
+ when "#{Webpacker.config.public_output_path}/**/*"
66
+ @all_files.keys
67
+ else
68
+ []
69
+ end
70
+ }
71
+ @file_mtime_stub = Proc.new { |longpath|
72
+ @all_files[longpath]
73
+ }
74
+ @file_delete_mock = Minitest::Mock.new
75
+ @expired_files.keys.each do |longpath|
76
+ @file_delete_mock.expect(:delete, 1, [longpath])
77
+ end
78
+ @file_delete_stub = Proc.new { |longpath|
79
+ if @prev_files.has_key?(longpath)
80
+ flunk "#{longpath} should not be deleted"
81
+ else
82
+ @file_delete_mock.delete(longpath)
83
+ end
84
+ }
85
+ end
86
+
87
+ def time_and_files_stub(&proc)
88
+ Time.stub :now, @now do
89
+ Dir.stub :glob, @dir_glob_stub do
90
+ File.stub :directory?, false do
91
+ File.stub :file?, true do
92
+ File.stub :mtime, @file_mtime_stub do
93
+ File.stub :delete, @file_delete_stub do
94
+ yield proc
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ @file_delete_mock.verify
102
+ end
103
+
104
+ def test_clean_command_with_versioned_files
105
+ time_and_files_stub do
106
+ assert Webpacker.commands.clean
107
+ end
108
+ end
109
+ end
@@ -44,7 +44,7 @@ class ConfigurationTest < Webpacker::Test
44
44
  end
45
45
 
46
46
  def test_cache_path
47
- cache_path = File.expand_path File.join(File.dirname(__FILE__), "test_app/tmp/cache/webpacker").to_s
47
+ cache_path = File.expand_path File.join(File.dirname(__FILE__), "test_app/tmp/webpacker").to_s
48
48
  assert_equal @config.cache_path.to_s, cache_path
49
49
  end
50
50