webpacker 5.0.1 → 5.2.2

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/.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 +32 -3
  10. data/Gemfile.lock +112 -103
  11. data/README.md +20 -41
  12. data/docs/css.md +58 -3
  13. data/docs/env.md +0 -2
  14. data/docs/integrations.md +1 -1
  15. data/docs/target.md +22 -0
  16. data/docs/testing.md +2 -3
  17. data/docs/troubleshooting.md +3 -1
  18. data/docs/typescript.md +92 -27
  19. data/docs/webpack-dev-server.md +1 -1
  20. data/lib/install/config/babel.config.js +1 -3
  21. data/lib/install/config/webpacker.yml +1 -5
  22. data/lib/install/examples/react/tsconfig.json +2 -1
  23. data/lib/install/examples/typescript/tsconfig.json +2 -1
  24. data/lib/install/template.rb +9 -1
  25. data/lib/install/typescript.rb +6 -13
  26. data/lib/tasks/webpacker/check_node.rake +1 -1
  27. data/lib/tasks/webpacker/check_yarn.rake +2 -3
  28. data/lib/tasks/webpacker/yarn_install.rake +7 -1
  29. data/lib/webpacker/compiler.rb +9 -5
  30. data/lib/webpacker/configuration.rb +13 -9
  31. data/lib/webpacker/dev_server_proxy.rb +3 -1
  32. data/lib/webpacker/dev_server_runner.rb +2 -2
  33. data/lib/webpacker/helper.rb +37 -18
  34. data/lib/webpacker/railtie.rb +0 -43
  35. data/lib/webpacker/runner.rb +1 -0
  36. data/lib/webpacker/version.rb +1 -1
  37. data/lib/webpacker/webpack_runner.rb +2 -2
  38. data/package.json +35 -35
  39. data/package/__tests__/config.js +12 -1
  40. data/package/__tests__/dev_server.js +2 -0
  41. data/package/__tests__/development.js +14 -1
  42. data/package/config.js +4 -1
  43. data/package/configPath.js +3 -0
  44. data/package/dev_server.js +1 -1
  45. data/package/env.js +1 -2
  46. data/package/environments/__tests__/base.js +25 -8
  47. data/package/environments/base.js +5 -6
  48. data/package/environments/development.js +39 -33
  49. data/package/environments/production.js +1 -3
  50. data/package/rules/babel.js +12 -5
  51. data/package/rules/file.js +3 -2
  52. data/package/rules/node_modules.js +1 -3
  53. data/package/rules/sass.js +4 -1
  54. data/package/utils/helpers.js +1 -1
  55. data/test/compiler_test.rb +8 -3
  56. data/test/configuration_test.rb +8 -7
  57. data/test/dev_server_runner_test.rb +1 -1
  58. data/test/helper_test.rb +3 -0
  59. data/test/test_app/config/application.rb +0 -1
  60. data/test/test_app/config/webpacker.yml +7 -1
  61. data/test/test_app/public/packs/manifest.json +1 -0
  62. data/test/webpack_runner_test.rb +1 -1
  63. data/webpacker.gemspec +1 -1
  64. data/yarn.lock +3296 -3594
  65. metadata +19 -14
  66. data/lib/install/loaders/typescript.js +0 -11
@@ -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')
@@ -12,7 +12,7 @@ if (devServerConfig) {
12
12
  const envPrefix = config.dev_server.env_prefix || 'WEBPACKER_DEV_SERVER'
13
13
 
14
14
  Object.keys(devServerConfig).forEach((key) => {
15
- const envValue = fetch(`${envPrefix}_${key.toUpperCase().replace(/_/g, '')}`)
15
+ const envValue = fetch(`${envPrefix}_${key.toUpperCase()}`)
16
16
  if (envValue !== undefined) devServerConfig[key] = envValue
17
17
  })
18
18
  }
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
- test: /\.(js|jsx|mjs)?(\.erb)?$/,
9
- include: [sourcePath, ...resolvedPaths].map((p) => resolve(p)),
9
+ test: /\.(js|jsx|mjs|ts|tsx)?(\.erb)?$/,
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