webpacker 3.2.2 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -1
  3. data/Gemfile.lock +38 -38
  4. data/README.md +48 -49
  5. data/docs/css.md +31 -1
  6. data/docs/docker.md +1 -1
  7. data/docs/typescript.md +36 -1
  8. data/{exe → lib/install/bin}/webpack +7 -0
  9. data/{exe → lib/install/bin}/webpack-dev-server +7 -0
  10. data/lib/install/binstubs.rb +4 -0
  11. data/lib/install/config/webpacker.yml +3 -0
  12. data/lib/install/loaders/erb.js +1 -1
  13. data/lib/install/template.rb +1 -2
  14. data/lib/install/typescript.rb +1 -1
  15. data/lib/tasks/webpacker.rake +1 -0
  16. data/lib/tasks/webpacker/binstubs.rake +12 -0
  17. data/lib/tasks/webpacker/check_binstubs.rake +1 -1
  18. data/lib/webpacker.rb +1 -0
  19. data/lib/webpacker/compiler.rb +4 -2
  20. data/lib/webpacker/dev_server_runner.rb +1 -1
  21. data/lib/webpacker/env.rb +39 -0
  22. data/lib/webpacker/instance.rb +1 -12
  23. data/lib/webpacker/version.rb +1 -1
  24. data/package.json +2 -2
  25. data/package/__tests__/config.js +7 -4
  26. data/package/__tests__/dev_server.js +26 -0
  27. data/package/__tests__/env.js +28 -0
  28. data/package/__tests__/index.js +31 -0
  29. data/package/config.js +14 -30
  30. data/package/config_types/__tests__/config_list.js +0 -5
  31. data/package/config_types/config_list.js +0 -9
  32. data/package/dev_server.js +23 -0
  33. data/package/env.js +23 -0
  34. data/package/{__tests__/environment.js → environments/__tests__/base.js} +6 -6
  35. data/package/{environment.js → environments/base.js} +4 -4
  36. data/package/environments/development.js +4 -3
  37. data/package/environments/production.js +31 -25
  38. data/package/environments/test.js +2 -2
  39. data/package/index.js +10 -6
  40. data/package/rules/babel.js +8 -6
  41. data/package/rules/css.js +2 -38
  42. data/package/rules/file.js +9 -7
  43. data/package/rules/index.js +4 -0
  44. data/package/rules/module.css.js +3 -0
  45. data/package/rules/module.sass.js +8 -0
  46. data/package/rules/sass.js +5 -12
  47. data/package/utils/__tests__/get_style_rule.js +36 -0
  48. data/package/utils/get_style_rule.js +62 -0
  49. data/package/utils/helpers.js +17 -3
  50. data/test/env_test.rb +19 -0
  51. data/test/test_app/bin/webpack +15 -0
  52. data/test/test_app/bin/webpack-dev-server +15 -0
  53. data/test/test_app/config/webpacker.yml +3 -0
  54. data/test/test_helper.rb +3 -1
  55. data/webpacker.gemspec +0 -2
  56. data/yarn.lock +8 -4
  57. metadata +26 -10
data/docs/docker.md CHANGED
@@ -11,7 +11,7 @@ services:
11
11
  build: .
12
12
  env_file:
13
13
  - '.env.docker'
14
- command: bundle exec webpack-dev-server
14
+ command: ./bin/webpack-dev-server
15
15
  volumes:
16
16
  - .:/webpacker-example-app
17
17
  ports:
data/docs/typescript.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  ## Typescript with React
5
5
 
6
- 1. Setup react using Webpacker [react installer](#react). Then run the typescript installer
6
+ 1. Setup react using Webpacker [react installer](../README.md#react). Then run the typescript installer
7
7
 
8
8
  ```bash
9
9
  bundle exec rails webpacker:install:typescript
@@ -13,6 +13,41 @@ yarn add @types/react @types/react-dom
13
13
  2. Rename the generated `hello_react.js` to `hello_react.tsx`. Make the file valid typescript and
14
14
  now you can use typescript, JSX with React.
15
15
 
16
+ ## Typescript with Vue components
17
+
18
+ 1. Setup vue using Webpacker [vue installer](../README.md#vue). Then run the typescript installer
19
+
20
+ ```bash
21
+ bundle exec rails webpacker:install:typescript
22
+ ```
23
+
24
+ 2. Rename generated `hello_vue.js` to `hello_vue.ts`.
25
+ 3. Change generated `config/webpack/loaders/typescript.js` from
26
+
27
+ ```js
28
+ module.exports = {
29
+ test: /\.(ts|tsx)?(\.erb)?$/,
30
+ use: [{
31
+ loader: 'ts-loader'
32
+ }]
33
+ }
34
+ ```
35
+
36
+ to
37
+
38
+ ```js
39
+ module.exports = {
40
+ test: /\.(ts|tsx)?(\.erb)?$/,
41
+ use: [{
42
+ loader: 'ts-loader',
43
+ options: {
44
+ appendTsSuffixTo: [/\.vue$/]
45
+ }
46
+ }]
47
+ }
48
+ ```
49
+
50
+ and now you can use `<script lang="ts">` in your `.vue` component files.
16
51
 
17
52
  ## HTML templates with Typescript and Angular
18
53
 
@@ -3,6 +3,13 @@
3
3
  ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
4
4
  ENV["NODE_ENV"] ||= ENV["RAILS_ENV"]
5
5
 
6
+ require "pathname"
7
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
8
+ Pathname.new(__FILE__).realpath)
9
+
10
+ require "rubygems"
11
+ require "bundler/setup"
12
+
6
13
  require "webpacker"
7
14
  require "webpacker/webpack_runner"
8
15
  Webpacker::WebpackRunner.run(ARGV)
@@ -3,6 +3,13 @@
3
3
  ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
4
4
  ENV["NODE_ENV"] ||= ENV["RAILS_ENV"]
5
5
 
6
+ require "pathname"
7
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
8
+ Pathname.new(__FILE__).realpath)
9
+
10
+ require "rubygems"
11
+ require "bundler/setup"
12
+
6
13
  require "webpacker"
7
14
  require "webpacker/dev_server_runner"
8
15
  Webpacker::DevServerRunner.run(ARGV)
@@ -0,0 +1,4 @@
1
+ say "Copying binstubs"
2
+ directory "#{__dir__}/bin", "bin"
3
+
4
+ chmod "bin", 0755 & ~File.umask, verbose: false
@@ -18,6 +18,9 @@ default: &default
18
18
  - .sass
19
19
  - .scss
20
20
  - .css
21
+ - .module.sass
22
+ - .module.scss
23
+ - .module.css
21
24
  - .png
22
25
  - .svg
23
26
  - .gif
@@ -5,7 +5,7 @@ module.exports = {
5
5
  use: [{
6
6
  loader: 'rails-erb-loader',
7
7
  options: {
8
- runner: 'bin/rails runner'
8
+ runner: (/^win/.test(process.platform) ? 'ruby ' : '') + 'bin/rails runner'
9
9
  }
10
10
  }]
11
11
  }
@@ -13,8 +13,7 @@ copy_file "#{__dir__}/config/.babelrc", ".babelrc"
13
13
  say "Creating JavaScript app source directory"
14
14
  directory "#{__dir__}/javascript", Webpacker.config.source_path
15
15
 
16
- say "Installing binstubs"
17
- run "bundle binstubs webpacker"
16
+ apply "#{__dir__}/binstubs.rb"
18
17
 
19
18
  say "Adding configurations"
20
19
 
@@ -41,6 +41,6 @@ copy_file "#{__dir__}/examples/typescript/hello_typescript.ts",
41
41
  "#{Webpacker.config.source_entry_path}/hello_typescript.ts"
42
42
 
43
43
  say "Installing all typescript dependencies"
44
- run "yarn add typescript ts-loader #{additional_packages}"
44
+ run "yarn add typescript ts-loader@3.5.0 #{additional_packages}"
45
45
 
46
46
  say "Webpacker now supports typescript 🎉", :green
@@ -5,6 +5,7 @@ tasks = {
5
5
  "webpacker:check_node" => "Verifies if Node.js is installed",
6
6
  "webpacker:check_yarn" => "Verifies if Yarn is installed",
7
7
  "webpacker:check_binstubs" => "Verifies that webpack & webpack-dev-server are present",
8
+ "webpacker:binstubs" => "Installs Webpacker binstubs in this application",
8
9
  "webpacker:verify_install" => "Verifies if Webpacker is installed",
9
10
  "webpacker:yarn_install" => "Support for older Rails versions. Install all JavaScript dependencies as specified via Yarn",
10
11
  "webpacker:install:react" => "Installs and setup example React component",
@@ -0,0 +1,12 @@
1
+ binstubs_template_path = File.expand_path("../../install/binstubs.rb", __dir__).freeze
2
+
3
+ namespace :webpacker do
4
+ desc "Installs Webpacker binstubs in this application"
5
+ task binstubs: [:check_node, :check_yarn] do
6
+ if Rails::VERSION::MAJOR >= 5
7
+ exec "#{RbConfig.ruby} ./bin/rails app:template LOCATION=#{binstubs_template_path}"
8
+ else
9
+ exec "#{RbConfig.ruby} ./bin/rake rails:template LOCATION=#{binstubs_template_path}"
10
+ end
11
+ end
12
+ end
@@ -1,7 +1,7 @@
1
1
  namespace :webpacker do
2
2
  desc "Verifies that webpack & webpack-dev-server are present."
3
3
  task :check_binstubs do
4
- unless Bundler.which(Gem.win_platform? ? "webpack.bat" : "webpack")
4
+ unless File.exist?("bin/webpack")
5
5
  $stderr.puts "webpack binstubs not found.\n"\
6
6
  "Have you run rails webpacker:install ?\n"\
7
7
  "Make sure the bin directory or binstubs are not included in .gitignore\n"\
data/lib/webpacker.rb CHANGED
@@ -19,6 +19,7 @@ module Webpacker
19
19
  end
20
20
 
21
21
  require "webpacker/instance"
22
+ require "webpacker/env"
22
23
  require "webpacker/configuration"
23
24
  require "webpacker/manifest"
24
25
  require "webpacker/compiler"
@@ -53,7 +53,7 @@ class Webpacker::Compiler
53
53
  def run_webpack
54
54
  logger.info "Compiling…"
55
55
 
56
- sterr, stdout, status = Open3.capture3(webpack_env, "bundle exec webpack")
56
+ sterr, stdout, status = Open3.capture3(webpack_env, "#{RbConfig.ruby} ./bin/webpack")
57
57
 
58
58
  if status.success?
59
59
  logger.info "Compiled all packs in #{config.public_output_path}"
@@ -78,6 +78,8 @@ class Webpacker::Compiler
78
78
  end
79
79
 
80
80
  def webpack_env
81
- env.merge("NODE_ENV" => @webpacker.env, "WEBPACKER_ASSET_HOST" => ActionController::Base.helpers.compute_asset_host)
81
+ env.merge("NODE_ENV" => @webpacker.env,
82
+ "WEBPACKER_ASSET_HOST" => ActionController::Base.helpers.compute_asset_host,
83
+ "WEBPACKER_RELATIVE_URL_ROOT" => ActionController::Base.relative_url_root)
82
84
  end
83
85
  end
@@ -14,7 +14,7 @@ module Webpacker
14
14
  private
15
15
  def load_config
16
16
  @config_file = File.join(@app_path, "config/webpacker.yml")
17
- dev_server = YAML.load_file(@config_file)[ENV["RAILS_ENV"]]["dev_server"]
17
+ dev_server = YAML.load_file(@config_file)[ENV["NODE_ENV"]]["dev_server"]
18
18
 
19
19
  @hostname = dev_server["host"]
20
20
  @port = dev_server["port"]
@@ -0,0 +1,39 @@
1
+ class Webpacker::Env
2
+ DEFAULT = "production".freeze
3
+
4
+ delegate :config_path, :logger, to: :@webpacker
5
+
6
+ def self.inquire(webpacker)
7
+ new(webpacker).inquire
8
+ end
9
+
10
+ def initialize(webpacker)
11
+ @webpacker = webpacker
12
+ end
13
+
14
+ def inquire
15
+ fallback_env_warning unless current
16
+ (current || DEFAULT).inquiry
17
+ end
18
+
19
+ private
20
+ def current
21
+ (ENV["NODE_ENV"] || Rails.env).presence_in(available_environments)
22
+ end
23
+
24
+ def fallback_env_warning
25
+ logger.info "NODE_ENV=#{ENV["NODE_ENV"]} and RAILS_ENV=#{Rails.env} environment is not defined in config/webpacker.yml, falling back to #{DEFAULT} environment"
26
+ end
27
+
28
+ def available_environments
29
+ if config_path.exist?
30
+ YAML.load(config_path.read).keys
31
+ else
32
+ [].freeze
33
+ end
34
+ rescue Psych::SyntaxError => e
35
+ raise "YAML syntax error occurred while parsing #{config_path}. " \
36
+ "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
37
+ "Error: #{e.message}"
38
+ end
39
+ end
@@ -8,9 +8,7 @@ class Webpacker::Instance
8
8
  end
9
9
 
10
10
  def env
11
- (ENV["NODE_ENV"].presence_in(available_environments) ||
12
- Rails.env.presence_in(available_environments) ||
13
- "production".freeze).inquiry
11
+ @env ||= Webpacker::Env.inquire self
14
12
  end
15
13
 
16
14
  def config
@@ -32,13 +30,4 @@ class Webpacker::Instance
32
30
  def commands
33
31
  @commands ||= Webpacker::Commands.new self
34
32
  end
35
-
36
- private
37
- def available_environments
38
- if config_path.exist?
39
- YAML.load(config_path.read).keys
40
- else
41
- [].freeze
42
- end
43
- end
44
33
  end
@@ -1,4 +1,4 @@
1
1
  module Webpacker
2
2
  # Change the version in package.json too, please!
3
- VERSION = "3.2.2".freeze
3
+ VERSION = "3.3.0".freeze
4
4
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rails/webpacker",
3
- "version": "3.2.2",
3
+ "version": "3.3.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,7 @@
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
- "compression-webpack-plugin": "^1.1.6",
23
+ "compression-webpack-plugin": "^1.1.10",
24
24
  "css-loader": "^0.28.9",
25
25
  "extract-text-webpack-plugin": "^3.0.2",
26
26
  "file-loader": "^1.1.6",
@@ -1,12 +1,12 @@
1
1
  /* global test expect, describe */
2
2
 
3
- const chdirApp = () => process.chdir('test/test_app')
4
- const chdirCwd = () => process.chdir(process.cwd())
5
- chdirApp()
3
+ const { chdirTestApp, chdirCwd } = require('../utils/helpers')
4
+
5
+ chdirTestApp()
6
6
 
7
7
  const config = require('../config')
8
8
 
9
- describe('Webpacker.yml config', () => {
9
+ describe('Config', () => {
10
10
  afterAll(chdirCwd)
11
11
 
12
12
  test('should return extensions as listed in app config', () => {
@@ -15,6 +15,9 @@ describe('Webpacker.yml config', () => {
15
15
  '.sass',
16
16
  '.scss',
17
17
  '.css',
18
+ '.module.sass',
19
+ '.module.scss',
20
+ '.module.css',
18
21
  '.png',
19
22
  '.svg',
20
23
  '.gif',
@@ -0,0 +1,26 @@
1
+ /* global test expect, describe */
2
+
3
+ const { chdirTestApp, chdirCwd } = require('../utils/helpers')
4
+
5
+ chdirTestApp()
6
+
7
+ describe('DevServer', () => {
8
+ beforeEach(() => jest.resetModules())
9
+ afterAll(chdirCwd)
10
+
11
+ test('with NODE_ENV set to development', () => {
12
+ process.env.NODE_ENV = 'development'
13
+ process.env.WEBPACKER_DEV_SERVER_HOST = '0.0.0.0'
14
+ process.env.WEBPACKER_DEV_SERVER_PORT = 5000
15
+
16
+ const devServer = require('../dev_server')
17
+ expect(devServer).toBeDefined()
18
+ expect(devServer.host).toEqual('0.0.0.0')
19
+ expect(devServer.port).toEqual('5000')
20
+ })
21
+
22
+ test('with NODE_ENV set to production', () => {
23
+ process.env.NODE_ENV = 'production'
24
+ expect(require('../dev_server')).toEqual({})
25
+ })
26
+ })
@@ -0,0 +1,28 @@
1
+ /* global test expect, describe */
2
+
3
+ const { chdirTestApp, chdirCwd } = require('../utils/helpers')
4
+
5
+ chdirTestApp()
6
+
7
+ describe('Env', () => {
8
+ beforeEach(() => jest.resetModules())
9
+ afterAll(chdirCwd)
10
+
11
+ test('with NODE_ENV set to development', () => {
12
+ process.env.NODE_ENV = 'development'
13
+ expect(require('../env')).toEqual('development')
14
+ })
15
+
16
+ test('with undefined NODE_ENV and RAILS_ENV set to development', () => {
17
+ delete process.env.NODE_ENV
18
+ process.env.RAILS_ENV = 'development'
19
+ expect(require('../env')).toEqual('development')
20
+ })
21
+
22
+ test('with a non-standard environment', () => {
23
+ process.env.NODE_ENV = 'foo'
24
+ process.env.RAILS_ENV = 'foo'
25
+ expect(require('../env')).toEqual('production')
26
+ delete process.env.RAILS_ENV
27
+ })
28
+ })
@@ -0,0 +1,31 @@
1
+ /* global test expect, describe */
2
+
3
+ const { chdirTestApp, chdirCwd } = require('../utils/helpers')
4
+
5
+ chdirTestApp()
6
+
7
+ describe('Webpacker', () => {
8
+ beforeEach(() => jest.resetModules())
9
+ afterAll(chdirCwd)
10
+
11
+ test('with NODE_ENV set to development', () => {
12
+ process.env.NODE_ENV = 'development'
13
+ const { environment } = require('../index')
14
+ expect(environment.toWebpackConfig()).toMatchObject({
15
+ devServer: {
16
+ host: 'localhost',
17
+ port: 3035
18
+ }
19
+ })
20
+ })
21
+
22
+ test('with a non-standard env', () => {
23
+ process.env.NODE_ENV = 'staging'
24
+ process.env.RAILS_ENV = 'staging'
25
+ const { environment } = require('../index')
26
+ expect(environment.toWebpackConfig()).toMatchObject({
27
+ devtool: 'nosources-source-map',
28
+ stats: 'normal'
29
+ })
30
+ })
31
+ })
data/package/config.js CHANGED
@@ -3,41 +3,25 @@ const { safeLoad } = require('js-yaml')
3
3
  const { readFileSync } = require('fs')
4
4
  const deepMerge = require('./utils/deep_merge')
5
5
  const { isArray } = require('./utils/helpers')
6
+ const env = require('./env')
6
7
 
7
- const defaultFilePath = require.resolve('../lib/install/config/webpacker.yml')
8
- const filePath = resolve('config', 'webpacker.yml')
8
+ const defaultConfigPath = require.resolve('../lib/install/config/webpacker.yml')
9
+ const configPath = resolve('config', 'webpacker.yml')
9
10
 
10
- const environment = process.env.NODE_ENV || 'development'
11
- const defaultConfig = safeLoad(readFileSync(defaultFilePath), 'utf8')[environment]
12
- const appConfig = safeLoad(readFileSync(filePath), 'utf8')[environment]
11
+ const getConfig = () => {
12
+ const defaults = safeLoad(readFileSync(defaultConfigPath), 'utf8')[env]
13
+ const app = safeLoad(readFileSync(configPath), 'utf8')[env]
13
14
 
14
- if (isArray(appConfig.extensions) && appConfig.extensions.length) {
15
- delete defaultConfig.extensions
16
- } else {
17
- /* eslint no-console: 0 */
18
- console.warn('No extensions specified in webpacker.yml, using default extensions\n')
19
- }
20
-
21
- const config = deepMerge(defaultConfig, appConfig)
15
+ if (isArray(app.extensions) && app.extensions.length) {
16
+ delete defaults.extensions
17
+ }
22
18
 
23
- const isBoolean = str => /^true/.test(str) || /^false/.test(str)
19
+ const config = deepMerge(defaults, app)
24
20
 
25
- const fetch = key =>
26
- (isBoolean(process.env[key]) ? JSON.parse(process.env[key]) : process.env[key])
21
+ config.outputPath = resolve('public', config.public_output_path)
22
+ config.publicPath = `/${config.public_output_path}/`.replace(/([^:]\/)\/+/g, '$1')
27
23
 
28
- const devServer = (key) => {
29
- const envValue = fetch(`WEBPACKER_DEV_SERVER_${key.toUpperCase().replace(/_/g, '')}`)
30
- if (typeof envValue === 'undefined' || envValue === null) return config.dev_server[key]
31
- return envValue
24
+ return config
32
25
  }
33
26
 
34
- if (config.dev_server) {
35
- Object.keys(config.dev_server).forEach((key) => {
36
- config.dev_server[key] = devServer(key)
37
- })
38
- }
39
-
40
- config.outputPath = resolve('public', config.public_output_path)
41
- config.publicPath = `/${config.public_output_path}/`.replace(/([^:]\/)\/+/g, '$1')
42
-
43
- module.exports = config
27
+ module.exports = getConfig()