webpacker 3.0.2 → 3.1.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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintignore +1 -0
  3. data/.travis.yml +10 -0
  4. data/CHANGELOG.md +110 -0
  5. data/Gemfile.lock +69 -67
  6. data/MIT-LICENSE +1 -1
  7. data/README.md +86 -30
  8. data/docs/assets.md +4 -4
  9. data/docs/cloud9.md +310 -0
  10. data/docs/css.md +32 -3
  11. data/docs/deployment.md +42 -4
  12. data/docs/docker.md +49 -0
  13. data/docs/env.md +5 -5
  14. data/docs/folder-structure.md +2 -2
  15. data/docs/testing.md +14 -34
  16. data/docs/troubleshooting.md +40 -4
  17. data/docs/typescript.md +2 -2
  18. data/docs/webpack-dev-server.md +21 -4
  19. data/docs/webpack.md +103 -25
  20. data/gemfiles/Gemfile-rails-edge +13 -0
  21. data/gemfiles/Gemfile-rails.4.2.x +10 -0
  22. data/gemfiles/Gemfile-rails.5.0.x +10 -0
  23. data/gemfiles/Gemfile-rails.5.1.x +10 -0
  24. data/lib/install/angular.rb +5 -5
  25. data/lib/install/config/webpacker.yml +7 -0
  26. data/lib/install/elm.rb +7 -7
  27. data/lib/install/examples/vue/hello_vue.js +30 -4
  28. data/lib/install/react.rb +5 -5
  29. data/lib/install/template.rb +19 -9
  30. data/lib/install/vue.rb +4 -4
  31. data/lib/tasks/installers.rake +2 -2
  32. data/lib/tasks/webpacker.rake +7 -6
  33. data/lib/tasks/webpacker/check_binstubs.rake +3 -3
  34. data/lib/tasks/webpacker/compile.rake +15 -8
  35. data/lib/tasks/webpacker/install.rake +4 -4
  36. data/lib/tasks/webpacker/verify_install.rake +1 -1
  37. data/lib/webpacker/compiler.rb +6 -6
  38. data/lib/webpacker/dev_server.rb +2 -2
  39. data/lib/webpacker/dev_server_proxy.rb +2 -1
  40. data/lib/webpacker/dev_server_runner.rb +4 -4
  41. data/lib/webpacker/helper.rb +3 -3
  42. data/lib/webpacker/manifest.rb +2 -2
  43. data/lib/webpacker/railtie.rb +41 -2
  44. data/lib/webpacker/runner.rb +1 -1
  45. data/lib/webpacker/version.rb +1 -1
  46. data/package.json +29 -21
  47. data/package/asset_host.js +4 -5
  48. data/package/config.js +7 -1
  49. data/package/config_types/__tests__/config_list.js +123 -0
  50. data/package/config_types/__tests__/config_object.js +43 -0
  51. data/package/config_types/config_list.js +83 -0
  52. data/package/config_types/config_object.js +55 -0
  53. data/package/config_types/index.js +7 -0
  54. data/package/environment.js +64 -40
  55. data/package/environments/development.js +31 -34
  56. data/package/environments/production.js +14 -11
  57. data/package/index.js +7 -2
  58. data/package/{loaders → rules}/babel.js +6 -4
  59. data/package/{loaders → rules}/coffee.js +3 -1
  60. data/package/rules/css.js +39 -0
  61. data/package/rules/elm.js +23 -0
  62. data/package/rules/erb.js +11 -0
  63. data/package/{loaders → rules}/file.js +1 -1
  64. data/package/rules/index.js +23 -0
  65. data/package/rules/sass.js +15 -0
  66. data/package/{loaders → rules}/typescript.js +3 -1
  67. data/package/rules/url.js +13 -0
  68. data/package/rules/vue.js +13 -0
  69. data/package/utils/__tests__/deep_assign.js +11 -0
  70. data/package/utils/__tests__/deep_merge.js +10 -0
  71. data/package/utils/__tests__/objectify.js +9 -0
  72. data/package/utils/deep_assign.js +22 -0
  73. data/package/utils/deep_merge.js +23 -0
  74. data/package/utils/helpers.js +32 -0
  75. data/package/utils/objectify.js +4 -0
  76. data/test/command_test.rb +1 -1
  77. data/test/compiler_test.rb +5 -1
  78. data/test/configuration_test.rb +1 -1
  79. data/test/dev_server_test.rb +1 -1
  80. data/test/helper_test.rb +15 -10
  81. data/test/manifest_test.rb +1 -1
  82. data/test/rake_tasks_test.rb +29 -0
  83. data/test/test_app/Rakefile +3 -0
  84. data/test/test_app/config/application.rb +11 -0
  85. data/test/test_app/config/environment.rb +4 -0
  86. data/test/{webpacker_test_helper.rb → test_helper.rb} +3 -14
  87. data/webpacker.gemspec +1 -1
  88. data/yarn.lock +1552 -829
  89. metadata +43 -16
  90. data/package/loaders/elm.js +0 -19
  91. data/package/loaders/erb.js +0 -9
  92. data/package/loaders/style.js +0 -31
  93. data/package/loaders/vue.js +0 -12
  94. data/test/test_app/config/secrets.yml +0 -5
@@ -0,0 +1,55 @@
1
+ const objectify = require('../utils/objectify')
2
+ const deepAssign = require('../utils/deep_assign')
3
+ const deepMerge = require('../utils/deep_merge')
4
+ const { isStrPath, prettyPrint } = require('../utils/helpers')
5
+
6
+ /**
7
+ * @class
8
+ * @extends { Object }
9
+ */
10
+ class ConfigObject extends Object {
11
+ constructor(props = {}) {
12
+ super()
13
+ this.merge(props)
14
+ }
15
+
16
+ get(key) {
17
+ return isStrPath(key) ? objectify(key, this) : this[key]
18
+ }
19
+
20
+ set(key, value) {
21
+ Object.assign(this, deepAssign(this, key, value))
22
+ return this
23
+ }
24
+
25
+ delete(key) {
26
+ let obj = this
27
+ let propKey = key
28
+
29
+ if (isStrPath(key)) {
30
+ const keys = key.split('.')
31
+ propKey = keys.pop()
32
+ const parentObjPath = keys.join('.')
33
+ obj = objectify(parentObjPath, this)
34
+ }
35
+
36
+ if (!obj) throw new Error(`Prop not found: ${key} in ${prettyPrint(obj)}`)
37
+ delete obj[propKey]
38
+
39
+ return this
40
+ }
41
+
42
+ toObject() {
43
+ const object = {}
44
+ /* eslint no-return-assign: 0 */
45
+ Object.keys(this).forEach(key => (object[key] = this[key]))
46
+ return object
47
+ }
48
+
49
+ merge(config) {
50
+ Object.assign(this, deepMerge(this, config))
51
+ return this
52
+ }
53
+ }
54
+
55
+ module.exports = ConfigObject
@@ -0,0 +1,7 @@
1
+ const ConfigObject = require('./config_object')
2
+ const ConfigList = require('./config_list')
3
+
4
+ module.exports = {
5
+ ConfigObject,
6
+ ConfigList
7
+ }
@@ -1,36 +1,38 @@
1
1
  /* eslint global-require: 0 */
2
2
  /* eslint import/no-dynamic-require: 0 */
3
3
 
4
- const { basename, dirname, join, relative, resolve } = require('path')
4
+ const {
5
+ basename, dirname, join, relative, resolve
6
+ } = require('path')
5
7
  const { sync } = require('glob')
6
8
  const extname = require('path-complete-extname')
7
9
 
8
10
  const webpack = require('webpack')
9
11
  const ExtractTextPlugin = require('extract-text-webpack-plugin')
10
12
  const ManifestPlugin = require('webpack-manifest-plugin')
13
+ const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
11
14
 
15
+ const { ConfigList, ConfigObject } = require('./config_types')
16
+ const rules = require('./rules')
12
17
  const config = require('./config')
13
18
  const assetHost = require('./asset_host')
14
19
 
15
- function getLoaderMap() {
16
- const result = new Map()
17
- const paths = sync(resolve(__dirname, 'loaders', '*.js'))
18
- paths.forEach((path) => {
19
- const name = basename(path, extname(path))
20
- result.set(name, require(path))
21
- })
20
+ const getLoaderList = () => {
21
+ const result = new ConfigList()
22
+ Object.keys(rules).forEach(key => result.append(key, rules[key]))
22
23
  return result
23
24
  }
24
25
 
25
- function getPluginMap() {
26
- const result = new Map()
27
- result.set('Environment', new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(process.env))))
28
- result.set('ExtractText', new ExtractTextPlugin('[name]-[contenthash].css'))
29
- result.set('Manifest', new ManifestPlugin({ publicPath: assetHost.publicPath, writeToFileEmit: true }))
26
+ const getPluginList = () => {
27
+ const result = new ConfigList()
28
+ result.append('Environment', new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(process.env))))
29
+ result.append('CaseSensitivePaths', new CaseSensitivePathsPlugin())
30
+ result.append('ExtractText', new ExtractTextPlugin('[name]-[contenthash].css'))
31
+ result.append('Manifest', new ManifestPlugin({ publicPath: assetHost.publicPath, writeToFileEmit: true }))
30
32
  return result
31
33
  }
32
34
 
33
- function getExtensionsGlob() {
35
+ const getExtensionsGlob = () => {
34
36
  const { extensions } = config
35
37
  if (!extensions.length) {
36
38
  throw new Error('You must configure at least one extension to compile in webpacker.yml')
@@ -38,58 +40,80 @@ function getExtensionsGlob() {
38
40
  return extensions.length === 1 ? `**/${extensions[0]}` : `**/*{${extensions.join(',')}}`
39
41
  }
40
42
 
41
- function getEntryObject() {
42
- const result = {}
43
+ const getEntryObject = () => {
44
+ const result = new ConfigObject()
43
45
  const glob = getExtensionsGlob()
44
46
  const rootPath = join(config.source_path, config.source_entry_path)
45
47
  const paths = sync(join(rootPath, glob))
46
48
  paths.forEach((path) => {
47
49
  const namespace = relative(join(rootPath), dirname(path))
48
50
  const name = join(namespace, basename(path, extname(path)))
49
- result[name] = resolve(path)
51
+ result.set(name, resolve(path))
50
52
  })
51
53
  return result
52
54
  }
53
55
 
54
- function getModulePaths() {
55
- let result = [resolve(config.source_path), 'node_modules']
56
+ const getModulePaths = () => {
57
+ const result = new ConfigList()
58
+ result.append('source', resolve(config.source_path))
59
+ result.append('node_modules', 'node_modules')
56
60
  if (config.resolved_paths) {
57
- result = result.concat(config.resolved_paths)
61
+ config.resolved_paths.forEach(path => result.append(basename(path), path))
58
62
  }
59
63
  return result
60
64
  }
61
65
 
66
+ const getBaseConfig = () =>
67
+ new ConfigObject({
68
+ output: {
69
+ filename: '[name]-[chunkhash].js',
70
+ chunkFilename: '[name]-[chunkhash].chunk.js',
71
+ path: assetHost.path,
72
+ publicPath: assetHost.publicPath
73
+ },
74
+
75
+ resolve: {
76
+ extensions: config.extensions
77
+ },
78
+
79
+ resolveLoader: {
80
+ modules: ['node_modules']
81
+ },
82
+
83
+ node: {
84
+ dgram: 'empty',
85
+ fs: 'empty',
86
+ net: 'empty',
87
+ tls: 'empty',
88
+ child_process: 'empty'
89
+ }
90
+ })
91
+
62
92
  module.exports = class Environment {
63
93
  constructor() {
64
- this.loaders = getLoaderMap()
65
- this.plugins = getPluginMap()
94
+ this.loaders = getLoaderList()
95
+ this.plugins = getPluginList()
96
+ this.config = getBaseConfig()
97
+ this.entry = getEntryObject()
98
+ this.resolvedModules = getModulePaths()
66
99
  }
67
100
 
68
101
  toWebpackConfig() {
69
- return {
70
- entry: getEntryObject(),
71
-
72
- output: {
73
- filename: '[name]-[chunkhash].js',
74
- chunkFilename: '[name]-[chunkhash].chunk.js',
75
- path: assetHost.path,
76
- publicPath: assetHost.publicPath
77
- },
102
+ return this.config.merge({
103
+ entry: this.entry.toObject(),
78
104
 
79
105
  module: {
80
- rules: Array.from(this.loaders.values())
106
+ strictExportPresence: true,
107
+ rules: [
108
+ { oneOf: this.loaders.values() }
109
+ ]
81
110
  },
82
111
 
83
- plugins: Array.from(this.plugins.values()),
112
+ plugins: this.plugins.values(),
84
113
 
85
114
  resolve: {
86
- extensions: config.extensions,
87
- modules: getModulePaths()
88
- },
89
-
90
- resolveLoader: {
91
- modules: ['node_modules']
115
+ modules: this.resolvedModules.values()
92
116
  }
93
- }
117
+ })
94
118
  }
95
119
  }
@@ -8,43 +8,40 @@ module.exports = class extends Environment {
8
8
  super()
9
9
 
10
10
  if (devServer.hmr) {
11
- this.plugins.set('HotModuleReplacement', new webpack.HotModuleReplacementPlugin())
12
- this.plugins.set('NamedModules', new webpack.NamedModulesPlugin())
11
+ this.plugins.append('HotModuleReplacement', new webpack.HotModuleReplacementPlugin())
12
+ this.plugins.append('NamedModules', new webpack.NamedModulesPlugin())
13
+ this.config.output.filename = '[name]-[hash].js'
13
14
  }
14
- }
15
15
 
16
- toWebpackConfig() {
17
- const result = super.toWebpackConfig()
18
- if (devServer.hmr) {
19
- result.output.filename = '[name]-[hash].js'
20
- }
21
- result.output.pathinfo = true
22
- result.devtool = 'cheap-eval-source-map'
23
- result.devServer = {
24
- clientLogLevel: 'none',
25
- compress: true,
26
- disableHostCheck: devServer.disable_host_check,
27
- host: devServer.host,
28
- port: devServer.port,
29
- https: devServer.https,
30
- hot: devServer.hmr,
31
- contentBase: assetHost.path,
32
- inline: devServer.inline,
33
- useLocalIp: devServer.use_local_ip,
34
- public: devServer.public,
35
- publicPath: assetHost.publicPath,
36
- historyApiFallback: true,
37
- headers: {
38
- 'Access-Control-Allow-Origin': '*'
16
+ this.config.merge({
17
+ devtool: 'cheap-module-source-map',
18
+ output: {
19
+ pathinfo: true
39
20
  },
40
- overlay: devServer.overlay,
41
- watchOptions: {
42
- ignored: /node_modules/
43
- },
44
- stats: {
45
- errorDetails: true
21
+ devServer: {
22
+ clientLogLevel: 'none',
23
+ compress: devServer.compress,
24
+ quiet: devServer.quiet,
25
+ disableHostCheck: devServer.disable_host_check,
26
+ host: devServer.host,
27
+ port: devServer.port,
28
+ https: devServer.https,
29
+ hot: devServer.hmr,
30
+ contentBase: assetHost.path,
31
+ inline: devServer.inline,
32
+ useLocalIp: devServer.use_local_ip,
33
+ public: devServer.public,
34
+ publicPath: assetHost.publicPath,
35
+ historyApiFallback: {
36
+ disableDotRule: true
37
+ },
38
+ headers: devServer.headers,
39
+ overlay: devServer.overlay,
40
+ stats: {
41
+ errorDetails: true
42
+ },
43
+ watchOptions: devServer.watch_options
46
44
  }
47
- }
48
- return result
45
+ })
49
46
  }
50
47
  }
@@ -6,29 +6,32 @@ module.exports = class extends Environment {
6
6
  constructor() {
7
7
  super()
8
8
 
9
- this.plugins.set('ModuleConcatenation', new webpack.optimize.ModuleConcatenationPlugin())
9
+ this.plugins.append('ModuleConcatenation', new webpack.optimize.ModuleConcatenationPlugin())
10
10
 
11
- this.plugins.set('UglifyJs', new webpack.optimize.UglifyJsPlugin({
11
+ this.plugins.append('UglifyJs', new webpack.optimize.UglifyJsPlugin({
12
12
  sourceMap: true,
13
+ mangle: {
14
+ safari10: true
15
+ },
13
16
  compress: {
14
- warnings: false
17
+ warnings: false,
18
+ comparisons: false
15
19
  },
16
20
  output: {
17
- comments: false
21
+ comments: false,
22
+ ascii_only: true
18
23
  }
19
24
  }))
20
25
 
21
- this.plugins.set('Compression', new CompressionPlugin({
26
+ this.plugins.append('Compression', new CompressionPlugin({
22
27
  asset: '[path].gz[query]',
23
28
  algorithm: 'gzip',
24
29
  test: /\.(js|css|html|json|ico|svg|eot|otf|ttf)$/
25
30
  }))
26
- }
27
31
 
28
- toWebpackConfig() {
29
- const result = super.toWebpackConfig()
30
- result.devtool = 'nosources-source-map'
31
- result.stats = 'normal'
32
- return result
32
+ this.config.merge({
33
+ devtool: 'nosources-source-map',
34
+ stats: 'normal'
35
+ })
33
36
  }
34
37
  }
data/package/index.js CHANGED
@@ -4,8 +4,11 @@
4
4
  const { resolve } = require('path')
5
5
  const { existsSync } = require('fs')
6
6
  const Environment = require('./environment')
7
+ const config = require('./config')
8
+ const assetHost = require('./asset_host')
9
+ const loaders = require('./rules')
7
10
 
8
- function createEnvironment() {
11
+ const createEnvironment = () => {
9
12
  const path = resolve(__dirname, 'environments', `${process.env.NODE_ENV}.js`)
10
13
  const constructor = existsSync(path) ? require(path) : Environment
11
14
  return new constructor()
@@ -13,4 +16,6 @@ function createEnvironment() {
13
16
 
14
17
  const environment = createEnvironment()
15
18
 
16
- module.exports = { environment, Environment }
19
+ module.exports = {
20
+ environment, config, assetHost, loaders, Environment
21
+ }
@@ -4,8 +4,10 @@ const { cache_path } = require('../config')
4
4
  module.exports = {
5
5
  test: /\.(js|jsx)?(\.erb)?$/,
6
6
  exclude: /node_modules/,
7
- loader: 'babel-loader',
8
- options: {
9
- cacheDirectory: join(cache_path, 'babel-loader')
10
- }
7
+ use: [{
8
+ loader: 'babel-loader',
9
+ options: {
10
+ cacheDirectory: join(cache_path, 'babel-loader')
11
+ }
12
+ }]
11
13
  }
@@ -1,4 +1,6 @@
1
1
  module.exports = {
2
2
  test: /\.coffee(\.erb)?$/,
3
- loader: 'coffee-loader'
3
+ use: [{
4
+ loader: 'coffee-loader'
5
+ }]
4
6
  }
@@ -0,0 +1,39 @@
1
+ const ExtractTextPlugin = require('extract-text-webpack-plugin')
2
+ const path = require('path')
3
+ const { dev_server: devServer } = require('../config')
4
+
5
+ const postcssConfigPath = path.resolve(process.cwd(), '.postcssrc.yml')
6
+ const isProduction = process.env.NODE_ENV === 'production'
7
+ const inDevServer = process.argv.find(v => v.includes('webpack-dev-server'))
8
+ const isHMR = inDevServer && (devServer && devServer.hmr)
9
+ const extractCSS = !(isHMR) || isProduction
10
+
11
+ const styleLoader = {
12
+ loader: 'style-loader',
13
+ options: {
14
+ hmr: isHMR,
15
+ sourceMap: true
16
+ }
17
+ }
18
+
19
+ const extractOptions = {
20
+ fallback: styleLoader,
21
+ use: [
22
+ { loader: 'css-loader', options: { minimize: isProduction, sourceMap: true, importLoaders: 2 } },
23
+ { loader: 'postcss-loader', options: { sourceMap: true, config: { path: postcssConfigPath } } }
24
+ ]
25
+ }
26
+
27
+ // For production extract styles to a separate bundle
28
+ const extractCSSLoader = {
29
+ test: /\.(css)$/i,
30
+ use: ExtractTextPlugin.extract(extractOptions)
31
+ }
32
+
33
+ // For hot-reloading use regular loaders
34
+ const inlineCSSLoader = {
35
+ test: /\.(css)$/i,
36
+ use: [styleLoader].concat(extractOptions.use)
37
+ }
38
+
39
+ module.exports = extractCSS ? extractCSSLoader : inlineCSSLoader
@@ -0,0 +1,23 @@
1
+ const { resolve } = require('path')
2
+
3
+ const isProduction = process.env.NODE_ENV === 'production'
4
+ const elmSource = resolve(process.cwd())
5
+ const elmMake = `${elmSource}/node_modules/.bin/elm-make`
6
+
7
+ const elmDefaultOptions = { cwd: elmSource, pathToMake: elmMake }
8
+ const developmentOptions = Object.assign(elmDefaultOptions, {
9
+ verbose: true,
10
+ warn: true,
11
+ debug: true
12
+ })
13
+
14
+ const elmWebpackLoader = {
15
+ loader: 'elm-webpack-loader',
16
+ options: isProduction ? elmDefaultOptions : developmentOptions
17
+ }
18
+
19
+ module.exports = {
20
+ test: /\.elm(\.erb)?$/,
21
+ exclude: [/elm-stuff/, /node_modules/],
22
+ use: isProduction ? [elmWebpackLoader] : [{ loader: 'elm-hot-loader' }, elmWebpackLoader]
23
+ }