webpacker 3.1.1 → 3.2.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +77 -0
  3. data/Gemfile.lock +17 -18
  4. data/README.md +21 -0
  5. data/docs/css.md +8 -3
  6. data/docs/troubleshooting.md +18 -0
  7. data/docs/webpack.md +30 -3
  8. data/lib/install/angular.rb +12 -0
  9. data/lib/install/coffee.rb +22 -0
  10. data/lib/install/config/.postcssrc.yml +1 -1
  11. data/lib/install/elm.rb +12 -0
  12. data/lib/install/erb.rb +22 -0
  13. data/lib/install/examples/coffee/hello_coffee.coffee +4 -0
  14. data/lib/install/examples/erb/hello_erb.js.erb +6 -0
  15. data/{package/rules → lib/install/loaders}/coffee.js +0 -0
  16. data/{package/rules → lib/install/loaders}/elm.js +0 -0
  17. data/{package/rules → lib/install/loaders}/erb.js +0 -0
  18. data/{package/rules → lib/install/loaders}/typescript.js +0 -0
  19. data/{package/rules → lib/install/loaders}/vue.js +1 -1
  20. data/lib/install/vue.rb +12 -0
  21. data/lib/tasks/installers.rake +3 -1
  22. data/lib/tasks/webpacker.rake +3 -1
  23. data/lib/tasks/webpacker/check_node.rake +2 -6
  24. data/lib/webpacker/compiler.rb +6 -1
  25. data/lib/webpacker/configuration.rb +8 -0
  26. data/lib/webpacker/helper.rb +14 -2
  27. data/lib/webpacker/version.rb +1 -1
  28. data/package.json +4 -10
  29. data/package/__tests__/environment.js +74 -0
  30. data/package/config.js +3 -0
  31. data/package/config_types/config_list.js +2 -0
  32. data/package/environment.js +6 -9
  33. data/package/environments/development.js +3 -4
  34. data/package/index.js +1 -2
  35. data/package/rules/file.js +1 -3
  36. data/package/rules/index.js +0 -12
  37. data/test/compiler_test.rb +11 -0
  38. data/test/configuration_test.rb +8 -0
  39. data/test/helper_test.rb +8 -0
  40. data/test/test_app/app/javascript/packs/application.js +10 -0
  41. data/test/test_app/config/webpacker.yml +65 -0
  42. data/test/test_helper.rb +1 -1
  43. data/yarn.lock +100 -188
  44. metadata +16 -9
  45. data/package/asset_host.js +0 -20
  46. data/package/rules/url.js +0 -13
@@ -2,7 +2,9 @@ installers = {
2
2
  "Angular": :angular,
3
3
  "Elm": :elm,
4
4
  "React": :react,
5
- "Vue": :vue
5
+ "Vue": :vue,
6
+ "Erb": :erb,
7
+ "Coffee": :coffee
6
8
  }.freeze
7
9
 
8
10
  namespace :webpacker do
@@ -10,7 +10,9 @@ tasks = {
10
10
  "webpacker:install:react" => "Installs and setup example React component",
11
11
  "webpacker:install:vue" => "Installs and setup example Vue component",
12
12
  "webpacker:install:angular" => "Installs and setup example Angular component",
13
- "webpacker:install:elm" => "Installs and setup example Elm component"
13
+ "webpacker:install:elm" => "Installs and setup example Elm component",
14
+ "webpacker:install:erb" => "Installs Erb loader with an example",
15
+ "webpacker:install:coffee" => "Installs CoffeeScript loader with an example"
14
16
  }.freeze
15
17
 
16
18
  desc "Lists all available tasks in Webpacker"
@@ -2,12 +2,8 @@ namespace :webpacker do
2
2
  desc "Verifies if Node.js is installed"
3
3
  task :check_node do
4
4
  begin
5
- begin
6
- node_version = `node -v`
7
- rescue Errno::ENOENT
8
- node_version = `nodejs -v`
9
- raise Errno::ENOENT if node_version.blank?
10
- end
5
+ node_version = `node -v || nodejs -v`
6
+ raise Errno::ENOENT if node_version.blank?
11
7
 
12
8
  pkg_path = Pathname.new("#{__dir__}/../../../package.json").realpath
13
9
  node_requirement = JSON.parse(pkg_path.read)["engines"]["node"]
@@ -65,7 +65,12 @@ class Webpacker::Compiler
65
65
  end
66
66
 
67
67
  def default_watched_paths
68
- ["#{config.source_path}/**/*", "yarn.lock", "package.json", "config/webpack/**/*"].freeze
68
+ [
69
+ *config.resolved_paths_globbed,
70
+ "#{config.source_path.relative_path_from(Rails.root)}/**/*",
71
+ "yarn.lock", "package.json",
72
+ "config/webpack/**/*"
73
+ ].freeze
69
74
  end
70
75
 
71
76
  def compilation_digest_path
@@ -21,6 +21,14 @@ class Webpacker::Configuration
21
21
  root_path.join(fetch(:source_path))
22
22
  end
23
23
 
24
+ def resolved_paths
25
+ fetch(:resolved_paths)
26
+ end
27
+
28
+ def resolved_paths_globbed
29
+ resolved_paths.map { |p| "#{p}/**/*" }
30
+ end
31
+
24
32
  def source_entry_path
25
33
  source_path.join(fetch(:source_entry_path))
26
34
  end
@@ -1,6 +1,6 @@
1
1
  module Webpacker::Helper
2
- # Computes the full path for a given Webpacker asset.
3
- # Return relative path using manifest.json and passes it to asset_url helper
2
+ # Computes the relative path for a given Webpacker asset.
3
+ # Return relative path using manifest.json and passes it to asset_path helper
4
4
  # This will use asset_path internally, so most of their behaviors will be the same.
5
5
  #
6
6
  # Example:
@@ -9,6 +9,18 @@ module Webpacker::Helper
9
9
  def asset_pack_path(name, **options)
10
10
  asset_path(Webpacker.manifest.lookup!(name), **options)
11
11
  end
12
+
13
+ # Computes the absolute path for a given Webpacker asset.
14
+ # Return absolute path using manifest.json and passes it to asset_url helper
15
+ # This will use asset_url internally, so most of their behaviors will be the same.
16
+ #
17
+ # Example:
18
+ #
19
+ # <%= asset_pack_url 'calendar.css' %> # => "http://example.com/packs/calendar-1016838bab065ae1e122.css"
20
+ def asset_pack_url(name, **options)
21
+ asset_url(Webpacker.manifest.lookup!(name), **options)
22
+ end
23
+
12
24
  # Creates a script tag that references the named pack file, as compiled by webpack per the entries list
13
25
  # in config/webpack/shared.js. By default, this list is auto-generated to match everything in
14
26
  # app/javascript/packs/*.js. In production mode, the digested reference is automatically looked up.
@@ -1,4 +1,4 @@
1
1
  module Webpacker
2
2
  # Change the version in package.json too, please!
3
- VERSION = "3.1.1".freeze
3
+ VERSION = "3.2.0".freeze
4
4
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rails/webpacker",
3
- "version": "3.1.1",
3
+ "version": "3.2.0",
4
4
  "description": "Use webpack to manage app-like JavaScript modules in Rails",
5
5
  "main": "package/index.js",
6
6
  "files": [
@@ -20,7 +20,6 @@
20
20
  "babel-polyfill": "^6.26.0",
21
21
  "babel-preset-env": "^1.6.1",
22
22
  "case-sensitive-paths-webpack-plugin": "^2.1.1",
23
- "coffee-loader": "^0.9.0",
24
23
  "compression-webpack-plugin": "^1.0.1",
25
24
  "css-loader": "^0.28.7",
26
25
  "extract-text-webpack-plugin": "^3.0.2",
@@ -30,17 +29,15 @@
30
29
  "node-sass": "^4.7.2",
31
30
  "path-complete-extname": "^0.1.0",
32
31
  "postcss-cssnext": "^3.0.2",
32
+ "postcss-import": "^11.0.0",
33
33
  "postcss-loader": "^2.0.9",
34
- "postcss-smart-import": "^0.7.5",
35
- "rails-erb-loader": "^5.2.1",
36
34
  "sass-loader": "^6.0.6",
37
35
  "style-loader": "^0.19.0",
38
- "url-loader": "^0.6.2",
39
- "webpack": "^3.8.1",
36
+ "webpack": "^3.10.0",
40
37
  "webpack-manifest-plugin": "^1.3.2"
41
38
  },
42
39
  "devDependencies": {
43
- "eslint": "^4.11.0",
40
+ "eslint": "^4.13.0",
44
41
  "eslint-config-airbnb": "^16.1.0",
45
42
  "eslint-plugin-import": "^2.8.0",
46
43
  "eslint-plugin-jsx-a11y": "^6.0.2",
@@ -53,9 +50,6 @@
53
50
  "<rootDir>/package"
54
51
  ]
55
52
  },
56
- "peerDependencies": {
57
- "coffeescript": ">= 1.12.7 || >= 2.x"
58
- },
59
53
  "scripts": {
60
54
  "test": "jest",
61
55
  "lint": "eslint {package,lib}/"
@@ -0,0 +1,74 @@
1
+ /* global test expect, describe, afterAll, beforeEach */
2
+
3
+ // environment.js expects to find config/webpacker.yml and resolved modules from
4
+ // the root of a Rails project
5
+
6
+ const chdirApp = () => process.chdir('test/test_app')
7
+ const chdirCwd = () => process.chdir(process.cwd())
8
+ chdirApp()
9
+
10
+ const { resolve } = require('path')
11
+ const rules = require('../rules')
12
+ const { ConfigList } = require('../config_types')
13
+ const Environment = require('../environment')
14
+
15
+ describe('Environment', () => {
16
+ afterAll(chdirCwd)
17
+
18
+ let environment
19
+
20
+ describe('toWebpackConfig', () => {
21
+ beforeEach(() => {
22
+ environment = new Environment()
23
+ })
24
+
25
+ test('should return entry', () => {
26
+ const config = environment.toWebpackConfig()
27
+ expect(config.entry.application).toEqual(resolve('app', 'javascript', 'packs', 'application.js'))
28
+ })
29
+
30
+ test('should return output', () => {
31
+ const config = environment.toWebpackConfig()
32
+ expect(config.output.filename).toEqual('[name]-[chunkhash].js')
33
+ expect(config.output.chunkFilename).toEqual('[name]-[chunkhash].chunk.js')
34
+ expect(config.output.path).toEqual(resolve('public', 'packs-test'))
35
+ expect(config.output.publicPath).toEqual('/packs-test/')
36
+ })
37
+
38
+ test('should return default loader rules for each file in config/loaders', () => {
39
+ const config = environment.toWebpackConfig()
40
+ const defaultRules = Object.keys(rules)
41
+ const configRules = config.module.rules
42
+
43
+ expect(defaultRules.length).toBeGreaterThan(1)
44
+ expect(configRules.length).toEqual(defaultRules.length)
45
+ })
46
+
47
+ test('should return default plugins', () => {
48
+ const config = environment.toWebpackConfig()
49
+ expect(config.plugins.length).toEqual(4)
50
+ })
51
+
52
+ test('should return default resolveLoader', () => {
53
+ const config = environment.toWebpackConfig()
54
+ expect(config.resolveLoader.modules).toEqual(['node_modules'])
55
+ })
56
+
57
+ test('should return default resolve.modules with additions', () => {
58
+ const config = environment.toWebpackConfig()
59
+ expect(config.resolve.modules).toEqual([
60
+ resolve('app', 'javascript'),
61
+ resolve('app/assets'),
62
+ resolve('/etc/yarn'),
63
+ 'node_modules'
64
+ ])
65
+ })
66
+
67
+ test('returns plugins property as Array', () => {
68
+ const config = environment.toWebpackConfig()
69
+
70
+ expect(config.plugins).toBeInstanceOf(Array)
71
+ expect(config.plugins).not.toBeInstanceOf(ConfigList)
72
+ })
73
+ })
74
+ })
data/package/config.js CHANGED
@@ -28,4 +28,7 @@ if (config.dev_server) {
28
28
  })
29
29
  }
30
30
 
31
+ config.outputPath = resolve('public', config.public_output_path)
32
+ config.publicPath = `/${config.public_output_path}/`.replace(/([^:]\/)\/+/g, '$1')
33
+
31
34
  module.exports = config
@@ -3,6 +3,8 @@
3
3
  * @extends { Array }
4
4
  */
5
5
  class ConfigList extends Array {
6
+ static get [Symbol.species]() { return Array }
7
+
6
8
  get(key) {
7
9
  const index = this.getIndex(key, true)
8
10
  return this[index].value
@@ -15,7 +15,6 @@ const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
15
15
  const { ConfigList, ConfigObject } = require('./config_types')
16
16
  const rules = require('./rules')
17
17
  const config = require('./config')
18
- const assetHost = require('./asset_host')
19
18
 
20
19
  const getLoaderList = () => {
21
20
  const result = new ConfigList()
@@ -28,7 +27,7 @@ const getPluginList = () => {
28
27
  result.append('Environment', new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(process.env))))
29
28
  result.append('CaseSensitivePaths', new CaseSensitivePathsPlugin())
30
29
  result.append('ExtractText', new ExtractTextPlugin('[name]-[contenthash].css'))
31
- result.append('Manifest', new ManifestPlugin({ publicPath: assetHost.publicPath, writeToFileEmit: true }))
30
+ result.append('Manifest', new ManifestPlugin({ publicPath: config.publicPath, writeToFileEmit: true }))
32
31
  return result
33
32
  }
34
33
 
@@ -56,10 +55,10 @@ const getEntryObject = () => {
56
55
  const getModulePaths = () => {
57
56
  const result = new ConfigList()
58
57
  result.append('source', resolve(config.source_path))
59
- result.append('node_modules', 'node_modules')
60
58
  if (config.resolved_paths) {
61
- config.resolved_paths.forEach(path => result.append(basename(path), path))
59
+ config.resolved_paths.forEach(path => result.append(path, resolve(path)))
62
60
  }
61
+ result.append('node_modules', 'node_modules')
63
62
  return result
64
63
  }
65
64
 
@@ -68,8 +67,8 @@ const getBaseConfig = () =>
68
67
  output: {
69
68
  filename: '[name]-[chunkhash].js',
70
69
  chunkFilename: '[name]-[chunkhash].chunk.js',
71
- path: assetHost.path,
72
- publicPath: assetHost.publicPath
70
+ path: config.outputPath,
71
+ publicPath: config.publicPath
73
72
  },
74
73
 
75
74
  resolve: {
@@ -104,9 +103,7 @@ module.exports = class Environment {
104
103
 
105
104
  module: {
106
105
  strictExportPresence: true,
107
- rules: [
108
- { oneOf: this.loaders.values() }
109
- ]
106
+ rules: this.loaders.values()
110
107
  },
111
108
 
112
109
  plugins: this.plugins.values(),
@@ -1,7 +1,6 @@
1
1
  const webpack = require('webpack')
2
2
  const Environment = require('../environment')
3
- const { dev_server: devServer } = require('../config')
4
- const assetHost = require('../asset_host')
3
+ const { dev_server: devServer, outputPath: contentBase, publicPath } = require('../config')
5
4
 
6
5
  module.exports = class extends Environment {
7
6
  constructor() {
@@ -27,11 +26,11 @@ module.exports = class extends Environment {
27
26
  port: devServer.port,
28
27
  https: devServer.https,
29
28
  hot: devServer.hmr,
30
- contentBase: assetHost.path,
29
+ contentBase,
31
30
  inline: devServer.inline,
32
31
  useLocalIp: devServer.use_local_ip,
33
32
  public: devServer.public,
34
- publicPath: assetHost.publicPath,
33
+ publicPath,
35
34
  historyApiFallback: {
36
35
  disableDotRule: true
37
36
  },
data/package/index.js CHANGED
@@ -5,7 +5,6 @@ const { resolve } = require('path')
5
5
  const { existsSync } = require('fs')
6
6
  const Environment = require('./environment')
7
7
  const config = require('./config')
8
- const assetHost = require('./asset_host')
9
8
  const loaders = require('./rules')
10
9
 
11
10
  const createEnvironment = () => {
@@ -17,5 +16,5 @@ const createEnvironment = () => {
17
16
  const environment = createEnvironment()
18
17
 
19
18
  module.exports = {
20
- environment, config, assetHost, loaders, Environment
19
+ environment, config, loaders, Environment
21
20
  }
@@ -1,6 +1,5 @@
1
1
  const { join } = require('path')
2
2
  const { source_path } = require('../config')
3
- const assetHost = require('../asset_host')
4
3
 
5
4
  module.exports = {
6
5
  exclude: /\.(js|jsx|coffee|ts|tsx|vue|elm|scss|sass|css|html|json)?(\.erb)?$/,
@@ -8,8 +7,7 @@ module.exports = {
8
7
  loader: 'file-loader',
9
8
  options: {
10
9
  name: '[path][name]-[hash].[ext]',
11
- context: join(source_path),
12
- publicPath: assetHost.publicPathWithHost
10
+ context: join(source_path)
13
11
  }
14
12
  }]
15
13
  }
@@ -1,23 +1,11 @@
1
1
  const babel = require('./babel')
2
- const coffee = require('./coffee')
3
- const elm = require('./elm')
4
- const erb = require('./erb')
5
2
  const file = require('./file')
6
- const url = require('./url')
7
3
  const css = require('./css')
8
4
  const sass = require('./sass')
9
- const typescript = require('./typescript')
10
- const vue = require('./vue')
11
5
 
12
6
  module.exports = {
13
- url,
14
7
  babel,
15
- coffee,
16
- elm,
17
- erb,
18
8
  css,
19
9
  sass,
20
- typescript,
21
- vue,
22
10
  file
23
11
  }
@@ -13,6 +13,17 @@ class CompilerTest < Minitest::Test
13
13
  assert Webpacker.compiler.send(:webpack_env)["FOO"] == "BAR"
14
14
  end
15
15
 
16
+ def test_default_watched_paths
17
+ assert_equal Webpacker.compiler.send(:default_watched_paths), [
18
+ "app/assets/**/*",
19
+ "/etc/yarn/**/*",
20
+ "test/test_app/app/javascript/**/*",
21
+ "yarn.lock",
22
+ "package.json",
23
+ "config/webpack/**/*"
24
+ ]
25
+ end
26
+
16
27
  def test_freshness
17
28
  assert Webpacker.compiler.stale?
18
29
  assert !Webpacker.compiler.fresh?
@@ -26,6 +26,14 @@ class ConfigurationTest < Webpacker::Test
26
26
  assert_equal Webpacker.config.cache_path.to_s, cache_path
27
27
  end
28
28
 
29
+ def test_resolved_paths
30
+ assert_equal Webpacker.config.resolved_paths, ["app/assets", "/etc/yarn"]
31
+ end
32
+
33
+ def test_resolved_paths_globbed
34
+ assert_equal Webpacker.config.resolved_paths_globbed, ["app/assets/**/*", "/etc/yarn/**/*"]
35
+ end
36
+
29
37
  def test_extensions
30
38
  webpacker_yml = YAML.load_file("lib/install/config/webpacker.yml")
31
39
  assert_equal Webpacker.config.extensions, webpacker_yml["default"]["extensions"]
data/test/helper_test.rb CHANGED
@@ -8,6 +8,9 @@ class HelperTest < ActionView::TestCase
8
8
  def setup
9
9
  @request = Class.new do
10
10
  def send_early_hints(links) end
11
+ def base_url
12
+ "https://example.com"
13
+ end
11
14
  end.new
12
15
  end
13
16
 
@@ -16,6 +19,11 @@ class HelperTest < ActionView::TestCase
16
19
  assert_equal "/packs/bootstrap-c38deda30895059837cf.css", asset_pack_path("bootstrap.css")
17
20
  end
18
21
 
22
+ def test_asset_pack_url
23
+ assert_equal "https://example.com/packs/bootstrap-300631c4f0e0f9c865bc.js", asset_pack_url("bootstrap.js")
24
+ assert_equal "https://example.com/packs/bootstrap-c38deda30895059837cf.css", asset_pack_url("bootstrap.css")
25
+ end
26
+
19
27
  def test_javascript_pack_tag
20
28
  assert_equal \
21
29
  %(<script src="/packs/bootstrap-300631c4f0e0f9c865bc.js"></script>),
@@ -0,0 +1,10 @@
1
+ /* eslint no-console:0 */
2
+ // This file is automatically compiled by Webpack, along with any other files
3
+ // present in this directory. You're encouraged to place your actual application logic in
4
+ // a relevant structure within app/javascript and only use these pack files to reference
5
+ // that code so it'll be compiled.
6
+ //
7
+ // To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate
8
+ // layout file, like app/views/layouts/application.html.erb
9
+
10
+ console.log('Hello World from Webpacker')