webpacker 3.1.1 → 3.2.0

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