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
@@ -8,11 +8,6 @@ test('new', () => {
8
8
  expect(list).toBeInstanceOf(Array)
9
9
  })
10
10
 
11
- test('set', () => {
12
- const list = new ConfigList()
13
- expect(list.set('key', 'value')).toEqual([{ key: 'key', value: 'value' }])
14
- })
15
-
16
11
  test('get', () => {
17
12
  const list = new ConfigList()
18
13
  list.append('key', 'value')
@@ -10,15 +10,6 @@ class ConfigList extends Array {
10
10
  return this[index].value
11
11
  }
12
12
 
13
- /**
14
- * @deprecated after the 3.0.2 release and will be removed in the next major release
15
- */
16
- set(key, value) {
17
- /* eslint no-console: 0 */
18
- console.warn('set is deprecated! Use append instead')
19
- return this.append(key, value)
20
- }
21
-
22
13
  append(key, value) {
23
14
  return this.add({ key, value })
24
15
  }
@@ -0,0 +1,23 @@
1
+ const { isBoolean, isEmpty } = require('./utils/helpers')
2
+ const config = require('./config')
3
+
4
+ const fetch = (key) => {
5
+ const value = process.env[key]
6
+ return isBoolean(value) ? JSON.parse(value) : value
7
+ }
8
+
9
+ const devServer = () => {
10
+ const devServerConfig = config.dev_server
11
+
12
+ if (devServerConfig) {
13
+ Object.keys(devServerConfig).forEach((key) => {
14
+ const envValue = fetch(`WEBPACKER_DEV_SERVER_${key.toUpperCase().replace(/_/g, '')}`)
15
+ if (isEmpty(envValue)) return devServerConfig[key]
16
+ devServerConfig[key] = envValue
17
+ })
18
+ }
19
+
20
+ return devServerConfig || {}
21
+ }
22
+
23
+ module.exports = devServer()
data/package/env.js ADDED
@@ -0,0 +1,23 @@
1
+ const { resolve } = require('path')
2
+ const { safeLoad } = require('js-yaml')
3
+ const { readFileSync } = require('fs')
4
+
5
+ const configPath = resolve('config', 'webpacker.yml')
6
+ const DEFAULT_ENV = 'production'
7
+
8
+ const env = () => {
9
+ const nodeEnv = process.env.NODE_ENV
10
+ const railsEnv = process.env.RAILS_ENV
11
+ const config = safeLoad(readFileSync(configPath), 'utf8')
12
+ const availableEnvironments = Object.keys(config).join('|')
13
+ const regex = new RegExp(availableEnvironments, 'g')
14
+
15
+ if (nodeEnv && nodeEnv.match(regex)) return nodeEnv
16
+ if (railsEnv && railsEnv.match(regex)) return railsEnv
17
+
18
+ /* eslint no-console: 0 */
19
+ console.warn(`NODE_ENV=${nodeEnv} and RAILS_ENV=${railsEnv} environment is not defined in config/webpacker.yml, falling back to ${DEFAULT_ENV}`)
20
+ return DEFAULT_ENV
21
+ }
22
+
23
+ module.exports = env()
@@ -3,14 +3,14 @@
3
3
  // environment.js expects to find config/webpacker.yml and resolved modules from
4
4
  // the root of a Rails project
5
5
 
6
- const chdirApp = () => process.chdir('test/test_app')
7
- const chdirCwd = () => process.chdir(process.cwd())
8
- chdirApp()
6
+ const { chdirTestApp, chdirCwd } = require('../../utils/helpers')
7
+
8
+ chdirTestApp()
9
9
 
10
10
  const { resolve } = require('path')
11
- const rules = require('../rules')
12
- const { ConfigList } = require('../config_types')
13
- const Environment = require('../environment')
11
+ const rules = require('../../rules')
12
+ const { ConfigList } = require('../../config_types')
13
+ const Environment = require('../base')
14
14
 
15
15
  describe('Environment', () => {
16
16
  afterAll(chdirCwd)
@@ -12,9 +12,9 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin')
12
12
  const ManifestPlugin = require('webpack-manifest-plugin')
13
13
  const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
14
14
 
15
- const { ConfigList, ConfigObject } = require('./config_types')
16
- const rules = require('./rules')
17
- const config = require('./config')
15
+ const { ConfigList, ConfigObject } = require('../config_types')
16
+ const rules = require('../rules')
17
+ const config = require('../config')
18
18
 
19
19
  const getLoaderList = () => {
20
20
  const result = new ConfigList()
@@ -85,7 +85,7 @@ const getBaseConfig = () =>
85
85
  }
86
86
  })
87
87
 
88
- module.exports = class Environment {
88
+ module.exports = class Base {
89
89
  constructor() {
90
90
  this.loaders = getLoaderList()
91
91
  this.plugins = getPluginList()
@@ -1,8 +1,9 @@
1
1
  const webpack = require('webpack')
2
- const Environment = require('../environment')
3
- const { dev_server: devServer, outputPath: contentBase, publicPath } = require('../config')
2
+ const Base = require('./base')
3
+ const devServer = require('../dev_server')
4
+ const { outputPath: contentBase, publicPath } = require('../config')
4
5
 
5
- module.exports = class extends Environment {
6
+ module.exports = class extends Base {
6
7
  constructor() {
7
8
  super()
8
9
 
@@ -1,40 +1,46 @@
1
1
  const webpack = require('webpack')
2
2
  const CompressionPlugin = require('compression-webpack-plugin')
3
3
  const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
4
- const Environment = require('../environment')
4
+ const Base = require('./base')
5
5
 
6
- module.exports = class extends Environment {
6
+ module.exports = class extends Base {
7
7
  constructor() {
8
8
  super()
9
9
 
10
10
  this.plugins.append('ModuleConcatenation', new webpack.optimize.ModuleConcatenationPlugin())
11
11
 
12
- this.plugins.append('UglifyJs', new UglifyJsPlugin({
13
- parallel: true,
14
- cache: true,
15
- sourceMap: true,
16
- uglifyOptions: {
17
- ie8: false,
18
- ecma: 8,
19
- warnings: false,
20
- mangle: {
21
- safari10: true
22
- },
23
- compress: {
12
+ this.plugins.append(
13
+ 'UglifyJs',
14
+ new UglifyJsPlugin({
15
+ parallel: true,
16
+ cache: true,
17
+ sourceMap: true,
18
+ uglifyOptions: {
19
+ ie8: false,
20
+ ecma: 8,
24
21
  warnings: false,
25
- comparisons: false
26
- },
27
- output: {
28
- ascii_only: true
22
+ mangle: {
23
+ safari10: true
24
+ },
25
+ compress: {
26
+ warnings: false,
27
+ comparisons: false
28
+ },
29
+ output: {
30
+ ascii_only: true
31
+ }
29
32
  }
30
- }
31
- }))
33
+ })
34
+ )
32
35
 
33
- this.plugins.append('Compression', new CompressionPlugin({
34
- asset: '[path].gz[query]',
35
- algorithm: 'gzip',
36
- test: /\.(js|css|html|json|ico|svg|eot|otf|ttf)$/
37
- }))
36
+ this.plugins.append(
37
+ 'Compression',
38
+ new CompressionPlugin({
39
+ asset: '[path].gz[query]',
40
+ algorithm: 'gzip',
41
+ test: /\.(js|css|html|json|ico|svg|eot|otf|ttf)$/
42
+ })
43
+ )
38
44
 
39
45
  this.config.merge({
40
46
  devtool: 'nosources-source-map',
@@ -1,3 +1,3 @@
1
- const Environment = require('../environment')
1
+ const Base = require('./base')
2
2
 
3
- module.exports = class extends Environment {}
3
+ module.exports = class extends Base {}
data/package/index.js CHANGED
@@ -3,18 +3,22 @@
3
3
 
4
4
  const { resolve } = require('path')
5
5
  const { existsSync } = require('fs')
6
- const Environment = require('./environment')
7
- const config = require('./config')
6
+ const Environment = require('./environments/base')
8
7
  const loaders = require('./rules')
8
+ const env = require('./env')
9
+ const config = require('./config')
10
+ const devServer = require('./dev_server')
9
11
 
10
12
  const createEnvironment = () => {
11
- const path = resolve(__dirname, 'environments', `${process.env.NODE_ENV}.js`)
13
+ const path = resolve(__dirname, 'environments', `${env}.js`)
12
14
  const constructor = existsSync(path) ? require(path) : Environment
13
15
  return new constructor()
14
16
  }
15
17
 
16
- const environment = createEnvironment()
17
-
18
18
  module.exports = {
19
- environment, config, loaders, Environment
19
+ config,
20
+ devServer,
21
+ environment: createEnvironment(),
22
+ Environment,
23
+ loaders
20
24
  }
@@ -1,13 +1,15 @@
1
1
  const { join } = require('path')
2
- const { cache_path } = require('../config')
2
+ const { cache_path: cachePath } = require('../config')
3
3
 
4
4
  module.exports = {
5
5
  test: /\.(js|jsx)?(\.erb)?$/,
6
6
  exclude: /node_modules/,
7
- use: [{
8
- loader: 'babel-loader',
9
- options: {
10
- cacheDirectory: join(cache_path, 'babel-loader')
7
+ use: [
8
+ {
9
+ loader: 'babel-loader',
10
+ options: {
11
+ cacheDirectory: join(cachePath, 'babel-loader')
12
+ }
11
13
  }
12
- }]
14
+ ]
13
15
  }
data/package/rules/css.js CHANGED
@@ -1,39 +1,3 @@
1
- const ExtractTextPlugin = require('extract-text-webpack-plugin')
2
- const path = require('path')
3
- const { dev_server: devServer } = require('../config')
1
+ const getStyleRule = require('../utils/get_style_rule')
4
2
 
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
3
+ module.exports = getStyleRule(/\.(css)$/i)
@@ -1,13 +1,15 @@
1
1
  const { join } = require('path')
2
- const { source_path } = require('../config')
2
+ const { source_path: sourcePath } = require('../config')
3
3
 
4
4
  module.exports = {
5
5
  test: /\.(jpg|jpeg|png|gif|tiff|ico|svg|eot|otf|ttf|woff|woff2)$/i,
6
- use: [{
7
- loader: 'file-loader',
8
- options: {
9
- name: '[path][name]-[hash].[ext]',
10
- context: join(source_path)
6
+ use: [
7
+ {
8
+ loader: 'file-loader',
9
+ options: {
10
+ name: '[path][name]-[hash].[ext]',
11
+ context: join(sourcePath)
12
+ }
11
13
  }
12
- }]
14
+ ]
13
15
  }
@@ -2,10 +2,14 @@ const babel = require('./babel')
2
2
  const file = require('./file')
3
3
  const css = require('./css')
4
4
  const sass = require('./sass')
5
+ const moduleCss = require('./module.css')
6
+ const moduleSass = require('./module.sass')
5
7
 
6
8
  module.exports = {
7
9
  babel,
8
10
  css,
9
11
  sass,
12
+ moduleCss,
13
+ moduleSass,
10
14
  file
11
15
  }
@@ -0,0 +1,3 @@
1
+ const getStyleRule = require('../utils/get_style_rule')
2
+
3
+ module.exports = getStyleRule(/\.(css)$/i, true)
@@ -0,0 +1,8 @@
1
+ const getStyleRule = require('../utils/get_style_rule')
2
+
3
+ module.exports = getStyleRule(/\.(scss|sass)$/i, true, [
4
+ {
5
+ loader: 'sass-loader',
6
+ options: { sourceMap: true }
7
+ }
8
+ ])
@@ -1,15 +1,8 @@
1
- const cssLoader = require('./css')
2
- const deepMerge = require('../utils/deep_merge')
1
+ const getStyleRule = require('../utils/get_style_rule')
3
2
 
4
- // Duplicate and remove css loader object reference
5
- let sassLoader = JSON.parse(JSON.stringify(cssLoader))
6
-
7
- sassLoader = deepMerge(sassLoader, {
8
- test: /\.(scss|sass)$/i,
9
- use: [{
3
+ module.exports = getStyleRule(/\.(scss|sass)$/i, false, [
4
+ {
10
5
  loader: 'sass-loader',
11
6
  options: { sourceMap: true }
12
- }]
13
- })
14
-
15
- module.exports = sassLoader
7
+ }
8
+ ])
@@ -0,0 +1,36 @@
1
+ const { chdirTestApp, chdirCwd } = require('../helpers')
2
+
3
+ chdirTestApp()
4
+
5
+ const getStyleRule = require('../get_style_rule')
6
+
7
+ describe('getStyleRule', () => {
8
+ afterAll(chdirCwd)
9
+
10
+ test('excludes modules by default', () => {
11
+ const cssRule = getStyleRule(/\.(css)$/i)
12
+ const expectation = {
13
+ test: /\.(css)$/i,
14
+ exclude: /\.module\.[a-z]+$/
15
+ }
16
+
17
+ expect(cssRule).toMatchObject(expectation)
18
+ })
19
+
20
+ test('includes modules if set to true', () => {
21
+ const cssRule = getStyleRule(/\.(scss)$/i, true)
22
+ const expectation = {
23
+ test: /\.(scss)$/i,
24
+ include: /\.module\.[a-z]+$/
25
+ }
26
+
27
+ expect(cssRule).toMatchObject(expectation)
28
+ })
29
+
30
+ test('adds extra preprocessors if supplied', () => {
31
+ const expectation = [{ foo: 'bar' }]
32
+ const cssRule = getStyleRule(/\.(css)$/i, true, expectation)
33
+
34
+ expect(cssRule.use).toMatchObject(expect.arrayContaining(expectation))
35
+ })
36
+ })
@@ -0,0 +1,62 @@
1
+ const ExtractTextPlugin = require('extract-text-webpack-plugin')
2
+ const path = require('path')
3
+ const devServer = require('../dev_server')
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 getStyleRule = (test, modules = false, preprocessors = []) => {
20
+ const extractOptions = {
21
+ fallback: styleLoader,
22
+ use: [
23
+ {
24
+ loader: 'css-loader',
25
+ options: {
26
+ minimize: isProduction,
27
+ sourceMap: true,
28
+ importLoaders: 2,
29
+ modules
30
+ }
31
+ },
32
+ {
33
+ loader: 'postcss-loader',
34
+ options: {
35
+ sourceMap: true,
36
+ config: { path: postcssConfigPath }
37
+ }
38
+ },
39
+ ...preprocessors
40
+ ]
41
+ }
42
+
43
+ const options = modules ? { include: /\.module\.[a-z]+$/ } : { exclude: /\.module\.[a-z]+$/ }
44
+
45
+ // For production extract styles to a separate bundle
46
+ const extractCSSLoader = Object.assign(
47
+ {},
48
+ { test, use: ExtractTextPlugin.extract(extractOptions) },
49
+ options
50
+ )
51
+
52
+ // For hot-reloading use regular loaders
53
+ const inlineCSSLoader = Object.assign(
54
+ {},
55
+ { test, use: [styleLoader].concat(extractOptions.use) },
56
+ options
57
+ )
58
+
59
+ return extractCSS ? extractCSSLoader : inlineCSSLoader
60
+ }
61
+
62
+ module.exports = getStyleRule