webpacker 5.1.1 → 5.4.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 (59) 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 -3
  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 +44 -0
  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 +1 -1
  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 +27 -8
  29. data/lib/webpacker/dev_server_runner.rb +2 -2
  30. data/lib/webpacker/env.rb +5 -1
  31. data/lib/webpacker/helper.rb +25 -6
  32. data/lib/webpacker/runner.rb +1 -0
  33. data/lib/webpacker/version.rb +1 -1
  34. data/lib/webpacker/webpack_runner.rb +2 -2
  35. data/package.json +36 -36
  36. data/package/__tests__/config.js +12 -1
  37. data/package/__tests__/development.js +14 -1
  38. data/package/config.js +4 -1
  39. data/package/configPath.js +3 -0
  40. data/package/env.js +1 -2
  41. data/package/environments/__tests__/base.js +25 -8
  42. data/package/environments/base.js +5 -6
  43. data/package/environments/development.js +39 -33
  44. data/package/environments/production.js +1 -3
  45. data/package/rules/babel.js +11 -4
  46. data/package/rules/file.js +3 -2
  47. data/package/rules/node_modules.js +1 -3
  48. data/package/rules/sass.js +4 -1
  49. data/package/utils/helpers.js +1 -1
  50. data/test/compiler_test.rb +8 -3
  51. data/test/configuration_test.rb +8 -7
  52. data/test/dev_server_runner_test.rb +1 -1
  53. data/test/helper_test.rb +3 -0
  54. data/test/test_app/config/webpacker.yml +7 -1
  55. data/test/test_app/public/packs/manifest.json +1 -0
  56. data/test/webpack_runner_test.rb +1 -1
  57. data/webpacker.gemspec +1 -1
  58. data/yarn.lock +3497 -3628
  59. metadata +19 -13
@@ -1,4 +1,4 @@
1
1
  module Webpacker
2
2
  # Change the version in package.json too, please!
3
- VERSION = "5.1.1".freeze
3
+ VERSION = "5.4.0".freeze
4
4
  end
@@ -5,6 +5,7 @@ module Webpacker
5
5
  class WebpackRunner < Webpacker::Runner
6
6
  def run
7
7
  env = Webpacker::Compiler.env
8
+ env["WEBPACKER_CONFIG"] = @webpacker_config
8
9
 
9
10
  cmd = if node_modules_bin_exist?
10
11
  ["#{@node_modules_bin_path}/webpack"]
@@ -12,9 +13,8 @@ module Webpacker
12
13
  ["yarn", "webpack"]
13
14
  end
14
15
 
15
- if ARGV.include?("--debug")
16
+ if @argv.include?("--debug-webpacker")
16
17
  cmd = [ "node", "--inspect-brk"] + cmd
17
- ARGV.delete("--debug")
18
18
  end
19
19
 
20
20
  cmd += ["--config", @webpack_config] + @argv
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rails/webpacker",
3
- "version": "5.1.1",
3
+ "version": "5.4.0",
4
4
  "description": "Use webpack to manage app-like JavaScript modules in Rails",
5
5
  "main": "package/index.js",
6
6
  "files": [
@@ -8,56 +8,56 @@
8
8
  "lib/install/config/webpacker.yml"
9
9
  ],
10
10
  "engines": {
11
- "node": ">=10.13.0",
12
- "yarn": ">=1 <2"
11
+ "node": ">=10.17.0",
12
+ "yarn": ">=1 <3"
13
13
  },
14
14
  "dependencies": {
15
- "@babel/core": "^7.9.0",
16
- "@babel/plugin-proposal-class-properties": "^7.8.3",
17
- "@babel/plugin-proposal-object-rest-spread": "^7.9.0",
15
+ "@babel/core": "^7.14.3",
16
+ "@babel/plugin-proposal-class-properties": "^7.13.0",
17
+ "@babel/plugin-proposal-object-rest-spread": "^7.14.2",
18
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.9.0",
22
- "@babel/preset-env": "^7.9.0",
23
- "@babel/runtime": "^7.9.2",
24
- "babel-loader": "^8.1.0",
25
- "babel-plugin-dynamic-import-node": "^2.3.0",
19
+ "@babel/plugin-transform-destructuring": "^7.13.17",
20
+ "@babel/plugin-transform-regenerator": "^7.13.15",
21
+ "@babel/plugin-transform-runtime": "^7.14.3",
22
+ "@babel/preset-env": "^7.14.2",
23
+ "@babel/runtime": "^7.14.0",
24
+ "babel-loader": "^8.2.2",
25
+ "babel-plugin-dynamic-import-node": "^2.3.3",
26
26
  "babel-plugin-macros": "^2.8.0",
27
- "case-sensitive-paths-webpack-plugin": "^2.3.0",
28
- "compression-webpack-plugin": "^3.1.0",
29
- "core-js": "^3.6.4",
30
- "css-loader": "^3.4.2",
31
- "file-loader": "^6.0.0",
32
- "flatted": "^2.0.1",
33
- "glob": "^7.1.6",
34
- "js-yaml": "^3.13.1",
27
+ "case-sensitive-paths-webpack-plugin": "^2.4.0",
28
+ "compression-webpack-plugin": "^4.0.1",
29
+ "core-js": "^3.12.1",
30
+ "css-loader": "^3.6.0",
31
+ "file-loader": "^6.2.0",
32
+ "flatted": "^3.1.1",
33
+ "glob": "^7.1.7",
34
+ "js-yaml": "^3.14.1",
35
35
  "mini-css-extract-plugin": "^0.9.0",
36
- "node-sass": "^4.13.1",
37
- "optimize-css-assets-webpack-plugin": "^5.0.3",
36
+ "optimize-css-assets-webpack-plugin": "^5.0.6",
38
37
  "path-complete-extname": "^1.0.0",
39
38
  "pnp-webpack-plugin": "^1.6.4",
40
- "postcss-flexbugs-fixes": "^4.2.0",
39
+ "postcss-flexbugs-fixes": "^4.2.1",
41
40
  "postcss-import": "^12.0.1",
42
41
  "postcss-loader": "^3.0.0",
43
42
  "postcss-preset-env": "^6.7.0",
44
43
  "postcss-safe-parser": "^4.0.2",
45
- "regenerator-runtime": "^0.13.5",
46
- "sass-loader": "^8.0.2",
47
- "style-loader": "^1.1.3",
48
- "terser-webpack-plugin": "^2.3.5",
49
- "webpack": "^4.42.1",
44
+ "regenerator-runtime": "^0.13.7",
45
+ "sass": "^1.32.13",
46
+ "sass-loader": "10.1.1",
47
+ "style-loader": "^1.3.0",
48
+ "terser-webpack-plugin": "^4.2.3",
49
+ "webpack": "^4.46.0",
50
50
  "webpack-assets-manifest": "^3.1.1",
51
- "webpack-cli": "^3.3.11",
51
+ "webpack-cli": "^3.3.12",
52
52
  "webpack-sources": "^1.4.3"
53
53
  },
54
54
  "devDependencies": {
55
- "eslint": "^6.8.0",
56
- "eslint-config-airbnb": "^18.1.0",
57
- "eslint-plugin-import": "^2.20.1",
58
- "eslint-plugin-jsx-a11y": "^6.2.3",
59
- "eslint-plugin-react": "^7.19.0",
60
- "jest": "^25.1.0"
55
+ "eslint": "^7.26.0",
56
+ "eslint-config-airbnb": "^18.2.1",
57
+ "eslint-plugin-import": "^2.23.2",
58
+ "eslint-plugin-jsx-a11y": "^6.4.1",
59
+ "eslint-plugin-react": "^7.23.2",
60
+ "jest": "^26.6.3"
61
61
  },
62
62
  "jest": {
63
63
  "testRegex": "(/__tests__/.*|(\\.|/))\\.jsx?$",
@@ -23,6 +23,16 @@ describe('Config', () => {
23
23
  expect(config.publicPath).toEqual('http://foo.com/packs/')
24
24
  })
25
25
 
26
+ test('should return additional paths as listed in app config, with resolved paths', () => {
27
+ expect(config.additional_paths).toEqual(
28
+ [
29
+ 'app/assets',
30
+ '/etc/yarn',
31
+ 'app/elm'
32
+ ]
33
+ )
34
+ })
35
+
26
36
  test('should return extensions as listed in app config', () => {
27
37
  expect(config.extensions).toEqual([
28
38
  '.mjs',
@@ -37,7 +47,8 @@ describe('Config', () => {
37
47
  '.svg',
38
48
  '.gif',
39
49
  '.jpeg',
40
- '.jpg'
50
+ '.jpg',
51
+ '.elm'
41
52
  ])
42
53
  })
43
54
 
@@ -11,9 +11,10 @@ describe('Development environment', () => {
11
11
  describe('toWebpackConfig', () => {
12
12
  beforeEach(() => jest.resetModules())
13
13
 
14
- test('should use development config and environment', () => {
14
+ test('should use development config and environment including devServer if WEBPACK_DEV_SERVER', () => {
15
15
  process.env.RAILS_ENV = 'development'
16
16
  process.env.NODE_ENV = 'development'
17
+ process.env.WEBPACK_DEV_SERVER = 'YES'
17
18
  const { environment } = require('../index')
18
19
 
19
20
  const config = environment.toWebpackConfig()
@@ -26,5 +27,17 @@ describe('Development environment', () => {
26
27
  }
27
28
  })
28
29
  })
30
+
31
+ test('should use development config and environment if WEBPACK_DEV_SERVER', () => {
32
+ process.env.RAILS_ENV = 'development'
33
+ process.env.NODE_ENV = 'development'
34
+ process.env.WEBPACK_DEV_SERVER = undefined
35
+ const { environment } = require('../index')
36
+
37
+ const config = environment.toWebpackConfig()
38
+ expect(config.output.path).toEqual(resolve('public', 'packs'))
39
+ expect(config.output.publicPath).toEqual('/packs/')
40
+ expect(config.devServer).toEqual(undefined)
41
+ })
29
42
  })
30
43
  })
data/package/config.js CHANGED
@@ -4,9 +4,9 @@ const { readFileSync } = require('fs')
4
4
  const deepMerge = require('./utils/deep_merge')
5
5
  const { isArray, ensureTrailingSlash } = require('./utils/helpers')
6
6
  const { railsEnv } = require('./env')
7
+ const configPath = require('./configPath')
7
8
 
8
9
  const defaultConfigPath = require.resolve('../lib/install/config/webpacker.yml')
9
- const configPath = resolve('config', 'webpacker.yml')
10
10
 
11
11
  const getDefaultConfig = () => {
12
12
  const defaultConfig = safeLoad(readFileSync(defaultConfigPath), 'utf8')
@@ -24,6 +24,9 @@ if (isArray(app.static_assets_extensions) && app.static_assets_extensions.length
24
24
  const config = deepMerge(defaults, app)
25
25
  config.outputPath = resolve(config.public_root_path, config.public_output_path)
26
26
 
27
+ // Merge resolved_paths into additional_paths for backwards-compat
28
+ config.additional_paths = config.additional_paths.concat(config.resolved_paths || [])
29
+
27
30
  // Ensure that the publicPath includes our asset host so dynamic imports
28
31
  // (code-splitting chunks and static assets) load from the CDN instead of a relative path.
29
32
  const getPublicPath = () => {
@@ -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
  }