webpacker 4.0.0.pre.pre.2 → 4.0.0.pre.3

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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/.node-version +1 -0
  3. data/.travis.yml +4 -0
  4. data/CHANGELOG.md +22 -2
  5. data/Gemfile.lock +63 -53
  6. data/README.md +39 -23
  7. data/Rakefile +1 -2
  8. data/docs/cloud9.md +1 -1
  9. data/docs/css.md +1 -1
  10. data/docs/es6.md +4 -4
  11. data/docs/testing.md +1 -1
  12. data/docs/webpack.md +4 -0
  13. data/gemfiles/Gemfile-rails.4.2.x +1 -1
  14. data/gemfiles/Gemfile-rails.5.0.x +1 -1
  15. data/gemfiles/Gemfile-rails.5.1.x +1 -1
  16. data/gemfiles/Gemfile-rails.5.2.x +10 -0
  17. data/lib/install/angular.rb +2 -2
  18. data/lib/install/bin/webpack +6 -2
  19. data/lib/install/bin/webpack-dev-server +6 -2
  20. data/lib/install/coffee.rb +1 -1
  21. data/lib/install/config/.babelrc +35 -12
  22. data/lib/install/config/.browserslistrc +1 -0
  23. data/lib/install/config/.postcssrc.yml +1 -1
  24. data/lib/install/config/webpacker.yml +4 -0
  25. data/lib/install/elm.rb +5 -4
  26. data/lib/install/erb.rb +1 -1
  27. data/lib/install/examples/react/.babelrc +43 -2
  28. data/lib/install/examples/stimulus/application.js +1 -6
  29. data/lib/install/examples/stimulus/controllers/index.js +9 -0
  30. data/lib/install/examples/typescript/tsconfig.json +4 -0
  31. data/lib/install/examples/vue/hello_vue.js +1 -1
  32. data/lib/install/loaders/elm.js +3 -4
  33. data/lib/install/loaders/vue.js +0 -5
  34. data/lib/install/react.rb +5 -4
  35. data/lib/install/template.rb +16 -19
  36. data/lib/install/typescript.rb +2 -2
  37. data/lib/install/vue.rb +3 -3
  38. data/lib/tasks/installers.rake +4 -2
  39. data/lib/tasks/webpacker.rake +1 -0
  40. data/lib/tasks/webpacker/binstubs.rake +3 -2
  41. data/lib/tasks/webpacker/info.rake +19 -0
  42. data/lib/tasks/webpacker/install.rake +3 -2
  43. data/lib/tasks/webpacker/verify_install.rake +1 -4
  44. data/lib/webpacker.rb +1 -0
  45. data/lib/webpacker/commands.rb +0 -1
  46. data/lib/webpacker/compiler.rb +10 -3
  47. data/lib/webpacker/configuration.rb +17 -7
  48. data/lib/webpacker/dev_server.rb +8 -4
  49. data/lib/webpacker/dev_server_proxy.rb +4 -0
  50. data/lib/webpacker/dev_server_runner.rb +17 -9
  51. data/lib/webpacker/env.rb +1 -1
  52. data/lib/webpacker/instance.rb +6 -2
  53. data/lib/webpacker/railtie.rb +15 -6
  54. data/lib/webpacker/runner.rb +3 -3
  55. data/lib/webpacker/version.rb +1 -1
  56. data/lib/webpacker/webpack_runner.rb +2 -2
  57. data/package.json +40 -33
  58. data/package/__tests__/config.js +17 -1
  59. data/package/__tests__/production.js +3 -1
  60. data/package/__tests__/staging.js +4 -2
  61. data/package/__tests__/test.js +4 -1
  62. data/package/config.js +9 -1
  63. data/package/config_types/config_list.js +5 -6
  64. data/package/dev_server.js +1 -1
  65. data/package/env.js +2 -2
  66. data/package/environments/base.js +26 -27
  67. data/package/environments/production.js +10 -1
  68. data/package/utils/__tests__/deep_assign.js +27 -6
  69. data/package/utils/deep_assign.js +1 -1
  70. data/package/utils/deep_merge.js +5 -6
  71. data/package/utils/get_style_rule.js +2 -5
  72. data/package/utils/helpers.js +3 -4
  73. data/package/utils/objectify.js +1 -2
  74. data/test/compiler_test.rb +2 -2
  75. data/test/configuration_test.rb +46 -22
  76. data/test/test_app/config.ru +5 -0
  77. data/test/test_helper.rb +3 -3
  78. data/test/webpacker_test.rb +13 -0
  79. data/webpacker.gemspec +5 -0
  80. data/yarn.lock +2758 -3258
  81. metadata +14 -3
@@ -1,14 +1,30 @@
1
1
  /* global test expect, describe */
2
2
 
3
- const { chdirTestApp, chdirCwd } = require('../utils/helpers')
3
+ const { chdirCwd, chdirTestApp } = require('../utils/helpers')
4
4
 
5
5
  chdirTestApp()
6
6
 
7
7
  const config = require('../config')
8
8
 
9
9
  describe('Config', () => {
10
+ beforeEach(() => jest.resetModules())
10
11
  afterAll(chdirCwd)
11
12
 
13
+ test('public path', () => {
14
+ process.env.RAILS_ENV = 'development'
15
+ delete process.env.RAILS_RELATIVE_URL_ROOT
16
+ const config = require('../config')
17
+ expect(config.publicPath).toEqual('/packs/')
18
+ })
19
+
20
+ // also tests removal of extra slashes
21
+ test('public path with relative root', () => {
22
+ process.env.RAILS_ENV = 'development'
23
+ process.env.RAILS_RELATIVE_URL_ROOT = '/foo'
24
+ const config = require('../config')
25
+ expect(config.publicPath).toEqual('/foo/packs/')
26
+ })
27
+
12
28
  test('should return extensions as listed in app config', () => {
13
29
  expect(config.extensions).toEqual([
14
30
  '.js',
@@ -13,9 +13,11 @@ describe('Production environment', () => {
13
13
 
14
14
  test('should use production config and environment', () => {
15
15
  process.env.RAILS_ENV = 'production'
16
- const { environment } = require('../index')
16
+ process.env.NODE_ENV = 'production'
17
17
 
18
+ const { environment } = require('../index')
18
19
  const config = environment.toWebpackConfig()
20
+
19
21
  expect(config.output.path).toEqual(resolve('public', 'packs'))
20
22
  expect(config.output.publicPath).toEqual('/packs/')
21
23
  expect(config).toMatchObject({
@@ -11,11 +11,13 @@ describe('Custom environment', () => {
11
11
  describe('toWebpackConfig', () => {
12
12
  beforeEach(() => jest.resetModules())
13
13
 
14
- test('should use staging config and production environment', () => {
14
+ test('should use staging config and default production environment', () => {
15
15
  process.env.RAILS_ENV = 'staging'
16
- const { environment } = require('../index')
16
+ delete process.env.NODE_ENV
17
17
 
18
+ const { environment } = require('../index')
18
19
  const config = environment.toWebpackConfig()
20
+
19
21
  expect(config.output.path).toEqual(resolve('public', 'packs-staging'))
20
22
  expect(config.output.publicPath).toEqual('/packs-staging/')
21
23
  expect(config).toMatchObject({
@@ -13,11 +13,14 @@ describe('Test environment', () => {
13
13
 
14
14
  test('should use test config and production environment', () => {
15
15
  process.env.RAILS_ENV = 'test'
16
- const { environment } = require('../index')
16
+ process.env.NODE_ENV = 'test'
17
17
 
18
+ const { environment } = require('../index')
18
19
  const config = environment.toWebpackConfig()
20
+
19
21
  expect(config.output.path).toEqual(resolve('public', 'packs-test'))
20
22
  expect(config.output.publicPath).toEqual('/packs-test/')
23
+ expect(config.devServer).toEqual(undefined)
21
24
  })
22
25
  })
23
26
  })
@@ -20,6 +20,14 @@ if (isArray(app.extensions) && app.extensions.length) delete defaults.extensions
20
20
 
21
21
  const config = deepMerge(defaults, app)
22
22
  config.outputPath = resolve('public', config.public_output_path)
23
- config.publicPath = `/${config.public_output_path}/`.replace(/([^:]\/)\/+/g, '$1')
23
+
24
+ let publicPath = `/${config.public_output_path}/`
25
+ // Add prefix to publicPath.
26
+ if (process.env.RAILS_RELATIVE_URL_ROOT) {
27
+ publicPath = `/${process.env.RAILS_RELATIVE_URL_ROOT}${publicPath}`
28
+ }
29
+
30
+ // Remove extra slashes.
31
+ config.publicPath = publicPath.replace(/(^\/|[^:]\/)\/+/g, '$1')
24
32
 
25
33
  module.exports = config
@@ -38,12 +38,11 @@ class ConfigList extends Array {
38
38
  }
39
39
 
40
40
  getIndex(key, shouldThrow = false) {
41
- const index = this.findIndex(entry =>
42
- (
43
- entry === key ||
44
- entry.key === key ||
45
- (entry.constructor && entry.constructor.name === key)
46
- ))
41
+ const index = this.findIndex(entry => (
42
+ entry === key
43
+ || entry.key === key
44
+ || (entry.constructor && entry.constructor.name === key)
45
+ ))
47
46
 
48
47
  if (shouldThrow && index < 0) throw new Error(`Item ${key} not found`)
49
48
  return index
@@ -11,7 +11,7 @@ const devServerConfig = config.dev_server
11
11
  if (devServerConfig) {
12
12
  Object.keys(devServerConfig).forEach((key) => {
13
13
  const envValue = fetch(`WEBPACKER_DEV_SERVER_${key.toUpperCase().replace(/_/g, '')}`)
14
- if (envValue) devServerConfig[key] = envValue
14
+ if (envValue !== undefined) devServerConfig[key] = envValue
15
15
  })
16
16
  }
17
17
 
@@ -2,7 +2,7 @@ const { resolve } = require('path')
2
2
  const { safeLoad } = require('js-yaml')
3
3
  const { readFileSync } = require('fs')
4
4
 
5
- const NODE_ENVIRONMENTS = ['development', 'production']
5
+ const NODE_ENVIRONMENTS = ['development', 'production', 'test']
6
6
  const DEFAULT = 'production'
7
7
  const configPath = resolve('config', 'webpacker.yml')
8
8
 
@@ -11,7 +11,7 @@ const nodeEnv = process.env.NODE_ENV
11
11
 
12
12
  const config = safeLoad(readFileSync(configPath), 'utf8')
13
13
  const availableEnvironments = Object.keys(config).join('|')
14
- const regex = new RegExp(availableEnvironments, 'g')
14
+ const regex = new RegExp(`^(${availableEnvironments})$`, 'g')
15
15
 
16
16
  module.exports = {
17
17
  railsEnv: railsEnv && railsEnv.match(regex) ? railsEnv : DEFAULT,
@@ -74,33 +74,32 @@ const getModulePaths = () => {
74
74
  return result
75
75
  }
76
76
 
77
- const getBaseConfig = () =>
78
- new ConfigObject({
79
- mode: 'production',
80
- output: {
81
- filename: '[name]-[chunkhash].js',
82
- chunkFilename: '[name]-[chunkhash].chunk.js',
83
- hotUpdateChunkFilename: '[id]-[hash].hot-update.js',
84
- path: config.outputPath,
85
- publicPath: config.publicPath
86
- },
87
-
88
- resolve: {
89
- extensions: config.extensions
90
- },
91
-
92
- resolveLoader: {
93
- modules: ['node_modules']
94
- },
95
-
96
- node: {
97
- dgram: 'empty',
98
- fs: 'empty',
99
- net: 'empty',
100
- tls: 'empty',
101
- child_process: 'empty'
102
- }
103
- })
77
+ const getBaseConfig = () => new ConfigObject({
78
+ mode: 'production',
79
+ output: {
80
+ filename: '[name]-[chunkhash].js',
81
+ chunkFilename: '[name]-[chunkhash].chunk.js',
82
+ hotUpdateChunkFilename: '[id]-[hash].hot-update.js',
83
+ path: config.outputPath,
84
+ publicPath: config.publicPath
85
+ },
86
+
87
+ resolve: {
88
+ extensions: config.extensions
89
+ },
90
+
91
+ resolveLoader: {
92
+ modules: ['node_modules']
93
+ },
94
+
95
+ node: {
96
+ dgram: 'empty',
97
+ fs: 'empty',
98
+ net: 'empty',
99
+ tls: 'empty',
100
+ child_process: 'empty'
101
+ }
102
+ })
104
103
 
105
104
  module.exports = class Base {
106
105
  constructor() {
@@ -1,5 +1,6 @@
1
1
  const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
2
2
  const CompressionPlugin = require('compression-webpack-plugin')
3
+ const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
3
4
  const Base = require('./base')
4
5
 
5
6
  module.exports = class extends Base {
@@ -15,6 +16,8 @@ module.exports = class extends Base {
15
16
  })
16
17
  )
17
18
 
19
+ this.plugins.append('OptimizeCSSAssets', new OptimizeCSSAssetsPlugin())
20
+
18
21
  this.config.merge({
19
22
  devtool: 'nosources-source-map',
20
23
  stats: 'normal',
@@ -26,8 +29,13 @@ module.exports = class extends Base {
26
29
  cache: true,
27
30
  sourceMap: true,
28
31
  uglifyOptions: {
29
- ecma: 8,
32
+ parse: {
33
+ // Let uglify-js parse ecma 8 code but always output
34
+ // ES5 compliant code for older browsers
35
+ ecma: 8
36
+ },
30
37
  compress: {
38
+ ecma: 5,
31
39
  warnings: false,
32
40
  comparisons: false
33
41
  },
@@ -35,6 +43,7 @@ module.exports = class extends Base {
35
43
  safari10: true
36
44
  },
37
45
  output: {
46
+ ecma: 5,
38
47
  comments: false,
39
48
  ascii_only: true
40
49
  }
@@ -2,10 +2,31 @@
2
2
 
3
3
  const deepAssign = require('../deep_assign')
4
4
 
5
- test('deep assign property', () => {
6
- const object = { foo: { bar: { } } }
7
- const path = 'foo.bar'
8
- const value = { x: 1, y: 2 }
9
- const expectation = { foo: { bar: { x: 1, y: 2 } } }
10
- expect(deepAssign(object, path, value)).toEqual(expectation)
5
+ describe('deepAssign()', () => {
6
+ test('deeply assigns nested properties', () => {
7
+ const object = { foo: { bar: { } } }
8
+ const path = 'foo.bar'
9
+ const value = { x: 1, y: 2 }
10
+ const expectation = { foo: { bar: { x: 1, y: 2 } } }
11
+ expect(deepAssign(object, path, value)).toEqual(expectation)
12
+ })
13
+
14
+ test('allows assignment of a literal false', () => {
15
+ const object = { foo: { bar: { } } }
16
+ const path = 'foo.bar'
17
+ const value = false
18
+ const expectation = { foo: { bar: false } }
19
+ expect(deepAssign(object, path, value)).toEqual(expectation)
20
+ })
21
+
22
+ test('does not allow assignment of other falsy values', () => {
23
+ const object = { foo: { bar: { } } }
24
+ const path = 'foo.bar'
25
+ const values = [undefined, null, 0, '']
26
+
27
+ values.forEach(value => {
28
+ const expectation = new Error(`Value can't be ${value}`)
29
+ expect(() => deepAssign(object, path, value)).toThrow(expectation)
30
+ })
31
+ })
11
32
  })
@@ -2,7 +2,7 @@ const { canMerge, prettyPrint } = require('./helpers')
2
2
  const deepMerge = require('./deep_merge')
3
3
 
4
4
  const deepAssign = (obj, path, value) => {
5
- if (!value) throw new Error(`Value can't be ${value}`)
5
+ if (!value && value !== false) throw new Error(`Value can't be ${value}`)
6
6
 
7
7
  const keys = path.split('.')
8
8
  const key = keys.pop()
@@ -10,12 +10,11 @@ const deepMerge = (target, source) => {
10
10
  if (!(isObject(target) && isObject(source))) return source
11
11
 
12
12
  return [...Object.keys(target), ...Object.keys(source)].reduce(
13
- (result, key) =>
14
- (Object.assign(
15
- {},
16
- result,
17
- { [key]: deepMerge(target[key], source[key]) }
18
- )),
13
+ (result, key) => (Object.assign(
14
+ {},
15
+ result,
16
+ { [key]: deepMerge(target[key], source[key]) }
17
+ )),
19
18
  {}
20
19
  )
21
20
  }
@@ -1,9 +1,7 @@
1
1
  const MiniCssExtractPlugin = require('mini-css-extract-plugin')
2
- const path = require('path')
3
2
  const devServer = require('../dev_server')
4
3
  const { nodeEnv } = require('../env')
5
4
 
6
- const postcssConfigPath = path.resolve(process.cwd(), '.postcssrc.yml')
7
5
  const isProduction = nodeEnv === 'production'
8
6
  const inDevServer = process.argv.find(v => v.includes('webpack-dev-server'))
9
7
  const isHMR = inDevServer && (devServer && devServer.hmr)
@@ -22,17 +20,16 @@ const getStyleRule = (test, modules = false, preprocessors = []) => {
22
20
  {
23
21
  loader: 'css-loader',
24
22
  options: {
25
- minimize: isProduction,
26
23
  sourceMap: true,
27
24
  importLoaders: 2,
25
+ localIdentName: '[name]__[local]___[hash:base64:5]',
28
26
  modules
29
27
  }
30
28
  },
31
29
  {
32
30
  loader: 'postcss-loader',
33
31
  options: {
34
- sourceMap: true,
35
- config: { path: postcssConfigPath }
32
+ sourceMap: true
36
33
  }
37
34
  },
38
35
  ...preprocessors
@@ -1,7 +1,6 @@
1
- const isObject = value =>
2
- typeof value === 'object' &&
3
- value !== null &&
4
- (value.length === undefined || value.length === null)
1
+ const isObject = value => typeof value === 'object'
2
+ && value !== null
3
+ && (value.length === undefined || value.length === null)
5
4
 
6
5
  const isBoolean = str => /^true/.test(str) || /^false/.test(str)
7
6
 
@@ -1,4 +1,3 @@
1
- const objectify = (path, obj) =>
2
- path.split('.').reduce((prev, curr) => (prev ? prev[curr] : undefined), obj)
1
+ const objectify = (path, obj) => path.split('.').reduce((prev, curr) => (prev ? prev[curr] : undefined), obj)
3
2
 
4
3
  module.exports = objectify
@@ -25,7 +25,7 @@ class CompilerTest < Minitest::Test
25
25
  assert_equal Webpacker.compiler.send(:default_watched_paths), [
26
26
  "app/assets/**/*",
27
27
  "/etc/yarn/**/*",
28
- "test/test_app/app/javascript/**/*",
28
+ "app/javascript/**/*",
29
29
  "yarn.lock",
30
30
  "package.json",
31
31
  "config/webpack/**/*"
@@ -59,6 +59,6 @@ class CompilerTest < Minitest::Test
59
59
  end
60
60
 
61
61
  def test_compilation_digest_path
62
- assert Webpacker.compiler.send(:compilation_digest_path).to_s.ends_with?(Webpacker.env)
62
+ assert_equal Webpacker.compiler.send(:compilation_digest_path).basename.to_s, "last-compilation-digest-#{Webpacker.env}"
63
63
  end
64
64
  end
@@ -1,66 +1,90 @@
1
1
  require "test_helper"
2
2
 
3
3
  class ConfigurationTest < Webpacker::Test
4
+ def setup
5
+ @config = Webpacker::Configuration.new(
6
+ root_path: Pathname.new(File.expand_path("test_app", __dir__)),
7
+ config_path: Pathname.new(File.expand_path("./test_app/config/webpacker.yml", __dir__)),
8
+ env: "production"
9
+ )
10
+ end
11
+
4
12
  def test_source_path
5
13
  source_path = File.expand_path File.join(File.dirname(__FILE__), "test_app/app/javascript").to_s
6
- assert_equal source_path, Webpacker.config.source_path.to_s
14
+ assert_equal source_path, @config.source_path.to_s
7
15
  end
8
16
 
9
17
  def test_source_entry_path
10
18
  source_entry_path = File.expand_path File.join(File.dirname(__FILE__), "test_app/app/javascript", "packs").to_s
11
- assert_equal Webpacker.config.source_entry_path.to_s, source_entry_path
19
+ assert_equal @config.source_entry_path.to_s, source_entry_path
12
20
  end
13
21
 
14
22
  def test_public_output_path
15
23
  public_output_path = File.expand_path File.join(File.dirname(__FILE__), "test_app/public/packs").to_s
16
- assert_equal Webpacker.config.public_output_path.to_s, public_output_path
24
+ assert_equal @config.public_output_path.to_s, public_output_path
17
25
  end
18
26
 
19
27
  def test_public_manifest_path
20
28
  public_manifest_path = File.expand_path File.join(File.dirname(__FILE__), "test_app/public/packs", "manifest.json").to_s
21
- assert_equal Webpacker.config.public_manifest_path.to_s, public_manifest_path
29
+ assert_equal @config.public_manifest_path.to_s, public_manifest_path
22
30
  end
23
31
 
24
32
  def test_cache_path
25
33
  cache_path = File.expand_path File.join(File.dirname(__FILE__), "test_app/tmp/cache/webpacker").to_s
26
- assert_equal Webpacker.config.cache_path.to_s, cache_path
34
+ assert_equal @config.cache_path.to_s, cache_path
27
35
  end
28
36
 
29
37
  def test_resolved_paths
30
- assert_equal Webpacker.config.resolved_paths, ["app/assets", "/etc/yarn"]
38
+ assert_equal @config.resolved_paths, ["app/assets", "/etc/yarn"]
31
39
  end
32
40
 
33
41
  def test_resolved_paths_globbed
34
- assert_equal Webpacker.config.resolved_paths_globbed, ["app/assets/**/*", "/etc/yarn/**/*"]
42
+ assert_equal @config.resolved_paths_globbed, ["app/assets/**/*", "/etc/yarn/**/*"]
35
43
  end
36
44
 
37
45
  def test_extensions
38
46
  config_path = File.expand_path File.join(File.dirname(__FILE__), "test_app/config/webpacker.yml").to_s
39
47
  webpacker_yml = YAML.load_file(config_path)
40
- assert_equal Webpacker.config.extensions, webpacker_yml["default"]["extensions"]
48
+ assert_equal @config.extensions, webpacker_yml["default"]["extensions"]
41
49
  end
42
50
 
43
51
  def test_cache_manifest?
44
- assert Webpacker.config.cache_manifest?
52
+ assert @config.cache_manifest?
53
+
54
+ @config = Webpacker::Configuration.new(
55
+ root_path: @config.root_path,
56
+ config_path: @config.config_path,
57
+ env: "development"
58
+ )
45
59
 
46
- with_rails_env("development") do
47
- refute Webpacker.config.cache_manifest?
48
- end
60
+ refute @config.cache_manifest?
49
61
 
50
- with_rails_env("test") do
51
- refute Webpacker.config.cache_manifest?
52
- end
62
+ @config = Webpacker::Configuration.new(
63
+ root_path: @config.root_path,
64
+ config_path: @config.config_path,
65
+ env: "test"
66
+ )
67
+
68
+ refute @config.cache_manifest?
53
69
  end
54
70
 
55
71
  def test_compile?
56
- refute Webpacker.config.compile?
72
+ refute @config.compile?
73
+
74
+ @config = Webpacker::Configuration.new(
75
+ root_path: @config.root_path,
76
+ config_path: @config.config_path,
77
+ env: "development"
78
+ )
79
+
80
+ assert @config.compile?
57
81
 
58
- with_rails_env("development") do
59
- assert Webpacker.config.compile?
60
- end
82
+ @config = Webpacker::Configuration.new(
83
+ root_path: @config.root_path,
84
+ config_path: @config.config_path,
85
+ env: "test"
86
+ )
61
87
 
62
- with_rails_env("test") do
63
- assert Webpacker.config.compile?
64
- end
88
+ assert @config.compile?
65
89
  end
66
90
  end