webpacker 2.0 → 3.0.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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +21 -21
  4. data/CHANGELOG.md +107 -4
  5. data/Gemfile +3 -1
  6. data/Gemfile.lock +15 -8
  7. data/README.md +137 -937
  8. data/docs/assets.md +106 -0
  9. data/docs/css.md +82 -0
  10. data/docs/deployment.md +39 -0
  11. data/docs/env.md +62 -0
  12. data/docs/es6.md +53 -0
  13. data/docs/folder-structure.md +66 -0
  14. data/docs/misc.md +23 -0
  15. data/docs/props.md +105 -0
  16. data/docs/testing.md +45 -0
  17. data/docs/troubleshooting.md +65 -0
  18. data/docs/typescript.md +115 -0
  19. data/docs/webpack-dev-server.md +32 -0
  20. data/docs/webpack.md +108 -0
  21. data/docs/yarn.md +12 -0
  22. data/lib/install/angular.rb +4 -7
  23. data/lib/install/bin/webpack-dev-server.tt +35 -11
  24. data/lib/install/bin/webpack.tt +3 -4
  25. data/lib/install/config/.babelrc +1 -0
  26. data/lib/install/config/.postcssrc.yml +1 -2
  27. data/lib/install/config/webpack/development.js +2 -31
  28. data/lib/install/config/webpack/environment.js +3 -0
  29. data/lib/install/config/webpack/production.js +2 -34
  30. data/lib/install/config/webpack/test.js +2 -5
  31. data/lib/install/config/webpacker.yml +20 -2
  32. data/lib/install/elm.rb +6 -11
  33. data/lib/install/examples/vue/hello_vue.js +31 -2
  34. data/lib/install/react.rb +2 -5
  35. data/lib/install/template.rb +3 -8
  36. data/lib/install/vue.rb +4 -7
  37. data/lib/tasks/webpacker.rake +1 -1
  38. data/lib/tasks/webpacker/{check_webpack_binstubs.rake → check_binstubs.rake} +3 -2
  39. data/lib/tasks/webpacker/check_node.rake +8 -6
  40. data/lib/tasks/webpacker/check_yarn.rake +2 -2
  41. data/lib/tasks/webpacker/clobber.rake +2 -3
  42. data/lib/tasks/webpacker/compile.rake +16 -18
  43. data/lib/tasks/webpacker/verify_install.rake +5 -5
  44. data/lib/tasks/webpacker/yarn_install.rake +1 -1
  45. data/lib/webpacker.rb +15 -11
  46. data/lib/webpacker/commands.rb +22 -0
  47. data/lib/webpacker/compiler.rb +66 -10
  48. data/lib/webpacker/configuration.rb +54 -38
  49. data/lib/webpacker/dev_server.rb +47 -0
  50. data/lib/webpacker/dev_server_proxy.rb +24 -0
  51. data/lib/webpacker/helper.rb +23 -5
  52. data/lib/webpacker/instance.rb +44 -0
  53. data/lib/webpacker/manifest.rb +58 -34
  54. data/lib/webpacker/railtie.rb +22 -3
  55. data/lib/webpacker/version.rb +2 -1
  56. data/package.json +37 -7
  57. data/package/asset_host.js +21 -0
  58. data/package/config.js +8 -0
  59. data/package/environment.js +95 -0
  60. data/package/environments/development.js +47 -0
  61. data/package/environments/production.js +34 -0
  62. data/package/environments/test.js +3 -0
  63. data/package/index.js +16 -0
  64. data/package/loaders/babel.js +11 -0
  65. data/{lib/install/config/loaders/core → package/loaders}/coffee.js +0 -0
  66. data/{lib/install/config/loaders/installers → package/loaders}/elm.js +4 -5
  67. data/{lib/install/config/loaders/core → package/loaders}/erb.js +0 -0
  68. data/package/loaders/file.js +15 -0
  69. data/package/loaders/style.js +31 -0
  70. data/{lib/install/config/loaders/installers/angular.js → package/loaders/typescript.js} +1 -1
  71. data/package/loaders/vue.js +12 -0
  72. data/test/compiler_test.rb +20 -0
  73. data/test/configuration_test.rb +43 -19
  74. data/test/dev_server_test.rb +24 -0
  75. data/test/helper_test.rb +21 -5
  76. data/test/manifest_test.rb +25 -19
  77. data/test/test_app/public/packs/manifest.json +3 -1
  78. data/test/webpacker_test_helper.rb +40 -0
  79. data/webpacker.gemspec +1 -1
  80. data/yarn.lock +4701 -578
  81. metadata +52 -29
  82. data/lib/install/config/loaders/core/assets.js +0 -12
  83. data/lib/install/config/loaders/core/babel.js +0 -5
  84. data/lib/install/config/loaders/core/sass.js +0 -15
  85. data/lib/install/config/loaders/installers/react.js +0 -5
  86. data/lib/install/config/loaders/installers/vue.js +0 -13
  87. data/lib/install/config/webpack/configuration.js +0 -35
  88. data/lib/install/config/webpack/shared.js +0 -58
  89. data/lib/webpacker/env.rb +0 -23
  90. data/lib/webpacker/file_loader.rb +0 -24
  91. data/test/env_test.rb +0 -14
  92. data/test/webpacker_test.rb +0 -15
@@ -1,51 +1,75 @@
1
- # Singleton registry for accessing the packs path using generated manifest.
1
+ # Singleton registry for accessing the packs path using a generated manifest.
2
2
  # This allows javascript_pack_tag, stylesheet_pack_tag, asset_pack_path to take a reference to,
3
3
  # say, "calendar.js" or "calendar.css" and turn it into "/packs/calendar.js" or
4
- # "/packs/calendar.css" in development. In production mode, it returns compiles
5
- # files, # "/packs/calendar-1016838bab065ae1e314.js" and
6
- # "/packs/calendar-1016838bab065ae1e314.css" for long-term caching
4
+ # "/packs/calendar.css" in development.
5
+ #
6
+ # In production mode, it returns compiles files, like
7
+ # "/packs/calendar-1016838bab065ae1e314.js" and "/packs/calendar-1016838bab065ae1e314.css",
8
+ # for long-term caching.
9
+ #
10
+ # When the configuration is set to on-demand compilation, with the `compile: true` option in
11
+ # the webpacker.yml file, any lookups will be preceeded by a compilation if one is needed.
12
+ class Webpacker::Manifest
13
+ class MissingEntryError < StandardError; end
7
14
 
8
- require "webpacker/file_loader"
15
+ delegate :config, :compiler, :dev_server, to: :@webpacker
9
16
 
10
- class Webpacker::Manifest < Webpacker::FileLoader
11
- class << self
12
- def file_path
13
- Webpacker::Configuration.manifest_path
14
- end
17
+ def initialize(webpacker)
18
+ @webpacker = webpacker
19
+ end
15
20
 
16
- def lookup(name)
17
- load if Webpacker.env.development?
21
+ def refresh
22
+ @data = load
23
+ end
18
24
 
19
- if Webpacker.env.test?
20
- find(name) || compile_and_find!(name)
21
- else
22
- find!(name)
23
- end
25
+ def lookup(name)
26
+ compile if compiling?
27
+ find name
28
+ end
29
+
30
+ private
31
+ def compiling?
32
+ config.compile? && !dev_server.running?
24
33
  end
25
34
 
26
- def lookup_path(name)
27
- Rails.root.join(File.join(Webpacker::Configuration.public_path, lookup(name)))
35
+ def compile
36
+ Webpacker.logger.tagged("Webpacker") { compiler.compile }
28
37
  end
29
38
 
30
- private
31
- def find(name)
32
- instance.data[name.to_s] if instance
33
- end
39
+ def find(name)
40
+ data[name.to_s] || handle_missing_entry(name)
41
+ end
34
42
 
35
- def find!(name)
36
- raise Webpacker::FileLoader::FileLoaderError.new("Webpacker::Manifest.load must be called first") unless instance
37
- instance.data[name.to_s] || raise(Webpacker::FileLoader::NotFoundError.new("Can't find #{name} in #{file_path}. Is webpack still compiling?"))
38
- end
43
+ def handle_missing_entry(name)
44
+ raise Webpacker::Manifest::MissingEntryError, missing_file_from_manifest_error(name)
45
+ end
39
46
 
40
- def compile_and_find!(name)
41
- Webpacker.compile
42
- find!(name)
47
+ def missing_file_from_manifest_error(bundle_name)
48
+ msg = <<-MSG
49
+ Webpacker can't find #{bundle_name} in #{config.public_manifest_path}. Possible causes:
50
+ 1. You want to set wepbacker.yml value of compile to true for your environment
51
+ unless you are using the `webpack -w` or the webpack-dev-server.
52
+ 2. Webpack has not yet re-run to reflect updates.
53
+ 3. You have misconfigured Webpacker's config/webpacker.yml file.
54
+ 4. Your Webpack configuration is not creating a manifest.
55
+ Your manifest contains:
56
+ #{JSON.pretty_generate(@data)}
57
+ MSG
58
+ end
59
+
60
+ def data
61
+ if config.cache_manifest?
62
+ @data ||= load
63
+ else
64
+ refresh
43
65
  end
44
- end
66
+ end
45
67
 
46
- private
47
68
  def load
48
- return super unless File.exist?(@path)
49
- JSON.parse(File.read(@path))
69
+ if config.public_manifest_path.exist?
70
+ JSON.parse config.public_manifest_path.read
71
+ else
72
+ {}
73
+ end
50
74
  end
51
75
  end
@@ -1,9 +1,18 @@
1
1
  require "rails/railtie"
2
2
 
3
3
  require "webpacker/helper"
4
+ require "webpacker/dev_server_proxy"
4
5
 
5
6
  class Webpacker::Engine < ::Rails::Engine
6
- initializer :webpacker do |app|
7
+ initializer "webpacker.proxy" do |app|
8
+ if Rails.env.development?
9
+ app.middleware.insert_before 0,
10
+ Rails::VERSION::MAJOR >= 5 ?
11
+ Webpacker::DevServerProxy : "Webpacker::DevServerProxy", ssl_verify_none: true
12
+ end
13
+ end
14
+
15
+ initializer "webpacker.helper" do |app|
7
16
  ActiveSupport.on_load :action_controller do
8
17
  ActionController::Base.helper Webpacker::Helper
9
18
  end
@@ -11,8 +20,18 @@ class Webpacker::Engine < ::Rails::Engine
11
20
  ActiveSupport.on_load :action_view do
12
21
  include Webpacker::Helper
13
22
  end
23
+ end
24
+
25
+ initializer "webpacker.logger" do
26
+ config.after_initialize do |app|
27
+ Webpacker.logger = ::Rails.logger
28
+ end
29
+ end
14
30
 
15
- Webpacker.bootstrap
16
- Spring.after_fork { Webpacker.bootstrap } if defined?(Spring)
31
+ initializer "webpacker.bootstrap" do
32
+ if defined?(Rails::Server) || defined?(Rails::Console)
33
+ Webpacker.bootstrap
34
+ Spring.after_fork { Webpacker.bootstrap } if defined?(Spring)
35
+ end
17
36
  end
18
37
  end
@@ -1,3 +1,4 @@
1
1
  module Webpacker
2
- VERSION = "2.0".freeze
2
+ # Change the version in package.json too, please!
3
+ VERSION = "3.0.0".freeze
3
4
  end
data/package.json CHANGED
@@ -1,12 +1,42 @@
1
1
  {
2
- "name": "webpacker",
3
- "version": "1.0.0",
4
- "description": "Webpacker makes it easy to use the JavaScript preprocessor and bundler [Webpack](https://webpack.github.io) to manage application-like JavaScript in Rails. It coexists with the asset pipeline, as the purpose is only to use Webpack for app-like JavaScript, not images, css, or even JavaScript Sprinkles (that all continues to live in app/assets).",
5
- "main": "index.js",
2
+ "name": "@rails/webpacker",
3
+ "version": "3.0.0",
4
+ "description": "Use Webpack to manage app-like JavaScript modules in Rails",
5
+ "main": "package/index.js",
6
+ "files": [
7
+ "package"
8
+ ],
6
9
  "engines": {
7
- "node": ">= 6.4.0"
10
+ "node": ">= 6.0.0"
11
+ },
12
+ "dependencies": {
13
+ "babel-core": "^6.26.0",
14
+ "babel-loader": "^7.1.2",
15
+ "babel-plugin-syntax-dynamic-import": "^6.18.0",
16
+ "babel-plugin-transform-class-properties": "^6.24.1",
17
+ "babel-plugin-transform-object-rest-spread": "^6.26.0",
18
+ "babel-polyfill": "^6.26.0",
19
+ "babel-preset-env": "^1.6.0",
20
+ "coffee-loader": "^0.8.0",
21
+ "coffee-script": "^1.12.7",
22
+ "compression-webpack-plugin": "^1.0.0",
23
+ "css-loader": "^0.28.5",
24
+ "extract-text-webpack-plugin": "^3.0.0",
25
+ "file-loader": "^0.11.2",
26
+ "glob": "^7.1.2",
27
+ "js-yaml": "^3.9.1",
28
+ "node-sass": "^4.5.3",
29
+ "path-complete-extname": "^0.1.0",
30
+ "postcss-cssnext": "^3.0.2",
31
+ "postcss-loader": "^2.0.6",
32
+ "postcss-smart-import": "^0.7.5",
33
+ "rails-erb-loader": "^5.2.1",
34
+ "resolve-url-loader": "^2.1.0",
35
+ "sass-loader": "^6.0.6",
36
+ "style-loader": "^0.18.2",
37
+ "webpack": "^3.5.5",
38
+ "webpack-manifest-plugin": "^1.3.1"
8
39
  },
9
- "dependencies": {},
10
40
  "devDependencies": {
11
41
  "eslint": "^3.16.1",
12
42
  "eslint-config-airbnb": "^14.1.0",
@@ -16,7 +46,7 @@
16
46
  },
17
47
  "scripts": {
18
48
  "test": "echo \"Error: no test specified\" && exit 1",
19
- "lint": "yarn run eslint lib/"
49
+ "lint": "eslint {package,lib}/"
20
50
  },
21
51
  "repository": {
22
52
  "type": "git",
@@ -0,0 +1,21 @@
1
+ const config = require('./config')
2
+ const { resolve } = require('path')
3
+
4
+ function removeOuterSlashes(string) {
5
+ return string.replace(/^\/*/, '').replace(/\/*$/, '')
6
+ }
7
+
8
+ function formatPublicPath(host = '', path = '') {
9
+ let formattedHost = removeOuterSlashes(host)
10
+ if (formattedHost && !/^http/i.test(formattedHost)) {
11
+ formattedHost = `//${formattedHost}`
12
+ }
13
+ const formattedPath = removeOuterSlashes(path)
14
+ return `${formattedHost}/${formattedPath}/`
15
+ }
16
+
17
+ module.exports = {
18
+ path: resolve('public', config.public_output_path),
19
+ publicPath: `/${config.public_output_path}/`.replace(/([^:]\/)\/+/g, '$1'),
20
+ publicPathWithHost: formatPublicPath(process.env.ASSET_HOST, config.public_output_path)
21
+ }
data/package/config.js ADDED
@@ -0,0 +1,8 @@
1
+ const { resolve } = require('path')
2
+ const { safeLoad } = require('js-yaml')
3
+ const { readFileSync } = require('fs')
4
+
5
+ const filePath = resolve('config', 'webpacker.yml')
6
+ const config = safeLoad(readFileSync(filePath), 'utf8')
7
+
8
+ module.exports = config[process.env.NODE_ENV]
@@ -0,0 +1,95 @@
1
+ /* eslint global-require: 0 */
2
+ /* eslint import/no-dynamic-require: 0 */
3
+
4
+ const config = require('./config')
5
+ const assetHost = require('./asset_host')
6
+
7
+ const { basename, dirname, join, relative, resolve } = require('path')
8
+ const { sync } = require('glob')
9
+ const extname = require('path-complete-extname')
10
+
11
+ const webpack = require('webpack')
12
+ const ExtractTextPlugin = require('extract-text-webpack-plugin')
13
+ const ManifestPlugin = require('webpack-manifest-plugin')
14
+
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
+ })
22
+ return result
23
+ }
24
+
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 }))
30
+ return result
31
+ }
32
+
33
+ function getExtensionsGlob() {
34
+ const { extensions } = config
35
+ if (!extensions.length) {
36
+ throw new Error('You must configure at least one extension to compile in webpacker.yml')
37
+ }
38
+ return extensions.length === 1 ? `**/${extensions[0]}` : `**/*{${extensions.join(',')}}`
39
+ }
40
+
41
+ function getEntryObject() {
42
+ const result = {}
43
+ const glob = getExtensionsGlob()
44
+ const rootPath = join(config.source_path, config.source_entry_path)
45
+ const paths = sync(join(rootPath, glob))
46
+ paths.forEach((path) => {
47
+ const namespace = relative(join(rootPath), dirname(path))
48
+ const name = join(namespace, basename(path, extname(path)))
49
+ result[name] = resolve(path)
50
+ })
51
+ return result
52
+ }
53
+
54
+ function getModulePaths() {
55
+ let result = [resolve(config.source_path), 'node_modules']
56
+ if (config.resolved_paths) {
57
+ result = result.concat(config.resolved_paths)
58
+ }
59
+ return result
60
+ }
61
+
62
+ module.exports = class Environment {
63
+ constructor() {
64
+ this.loaders = getLoaderMap()
65
+ this.plugins = getPluginMap()
66
+ }
67
+
68
+ 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
+ },
78
+
79
+ module: {
80
+ rules: Array.from(this.loaders.values())
81
+ },
82
+
83
+ plugins: Array.from(this.plugins.values()),
84
+
85
+ resolve: {
86
+ extensions: config.extensions,
87
+ modules: getModulePaths()
88
+ },
89
+
90
+ resolveLoader: {
91
+ modules: ['node_modules']
92
+ }
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,47 @@
1
+ const Environment = require('../environment')
2
+ const { dev_server } = require('../config')
3
+ const assetHost = require('../asset_host')
4
+ const webpack = require('webpack')
5
+
6
+ module.exports = class extends Environment {
7
+ constructor() {
8
+ super()
9
+
10
+ if (dev_server.hmr) {
11
+ this.plugins.set('HotModuleReplacement', new webpack.HotModuleReplacementPlugin())
12
+ this.plugins.set('NamedModules', new webpack.NamedModulesPlugin())
13
+ }
14
+ }
15
+
16
+ toWebpackConfig() {
17
+ const result = super.toWebpackConfig()
18
+ if (dev_server.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
+ host: dev_server.host,
25
+ port: dev_server.port,
26
+ https: dev_server.https,
27
+ hot: dev_server.hmr,
28
+ contentBase: assetHost.path,
29
+ publicPath: assetHost.publicPath,
30
+ clientLogLevel: 'none',
31
+ compress: true,
32
+ historyApiFallback: true,
33
+ headers: {
34
+ 'Access-Control-Allow-Origin': '*'
35
+ },
36
+ overlay: true,
37
+ watchContentBase: true,
38
+ watchOptions: {
39
+ ignored: /node_modules/
40
+ },
41
+ stats: {
42
+ errorDetails: true
43
+ }
44
+ }
45
+ return result
46
+ }
47
+ }
@@ -0,0 +1,34 @@
1
+ const Environment = require('../environment')
2
+ const webpack = require('webpack')
3
+ const CompressionPlugin = require('compression-webpack-plugin')
4
+
5
+ module.exports = class extends Environment {
6
+ constructor() {
7
+ super()
8
+
9
+ this.plugins.set('ModuleConcatenation', new webpack.optimize.ModuleConcatenationPlugin())
10
+
11
+ this.plugins.set('UglifyJs', new webpack.optimize.UglifyJsPlugin({
12
+ sourceMap: true,
13
+ compress: {
14
+ warnings: false
15
+ },
16
+ output: {
17
+ comments: false
18
+ }
19
+ }))
20
+
21
+ this.plugins.set('Compression', new CompressionPlugin({
22
+ asset: '[path].gz[query]',
23
+ algorithm: 'gzip',
24
+ test: /\.(js|css|html|json|ico|svg|eot|otf|ttf)$/
25
+ }))
26
+ }
27
+
28
+ toWebpackConfig() {
29
+ const result = super.toWebpackConfig()
30
+ result.devtool = 'source-map'
31
+ result.stats = 'normal'
32
+ return result
33
+ }
34
+ }
@@ -0,0 +1,3 @@
1
+ const Environment = require('../environment')
2
+
3
+ module.exports = class extends Environment {}
data/package/index.js ADDED
@@ -0,0 +1,16 @@
1
+ /* eslint global-require: 0 */
2
+ /* eslint import/no-dynamic-require: 0 */
3
+
4
+ const Environment = require('./environment')
5
+ const { resolve } = require('path')
6
+ const { existsSync } = require('fs')
7
+
8
+ function createEnvironment() {
9
+ const path = resolve(__dirname, 'environments', `${process.env.NODE_ENV}.js`)
10
+ const constructor = existsSync(path) ? require(path) : Environment
11
+ return new constructor()
12
+ }
13
+
14
+ const environment = createEnvironment()
15
+
16
+ module.exports = { environment, Environment }