webpacker 3.0.2 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }