webpacker 6.0.0.pre.2 → 6.0.0.rc.1

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/jest.yml +5 -2
  3. data/.github/workflows/js-lint.yml +5 -2
  4. data/.github/workflows/rubocop.yml +1 -1
  5. data/.github/workflows/ruby.yml +17 -14
  6. data/.node-version +1 -1
  7. data/.rubocop.yml +106 -0
  8. data/CHANGELOG.md +36 -9
  9. data/CONTRIBUTING.md +1 -1
  10. data/Gemfile.lock +93 -90
  11. data/README.md +363 -107
  12. data/config/README.md +3 -0
  13. data/config/webpacker.yml +1 -0
  14. data/docs/deployment.md +9 -29
  15. data/docs/developing_webpacker.md +29 -0
  16. data/docs/troubleshooting.md +57 -25
  17. data/docs/v6_upgrade.md +75 -0
  18. data/gemfiles/Gemfile-rails-edge +1 -1
  19. data/gemfiles/Gemfile-rails.6.1.x +12 -0
  20. data/lib/install/config/webpacker.yml +5 -7
  21. data/lib/install/{javascript/packs → packs/entrypoints}/application.js +4 -3
  22. data/lib/install/template.rb +17 -10
  23. data/lib/tasks/webpacker/binstubs.rake +2 -2
  24. data/lib/tasks/webpacker/check_node.rake +3 -0
  25. data/lib/tasks/webpacker/check_yarn.rake +4 -1
  26. data/lib/tasks/webpacker/clobber.rake +1 -1
  27. data/lib/tasks/webpacker/install.rake +2 -2
  28. data/lib/tasks/webpacker/verify_config.rake +14 -0
  29. data/lib/tasks/webpacker/verify_install.rake +1 -11
  30. data/lib/webpacker.rb +1 -1
  31. data/lib/webpacker/commands.rb +2 -1
  32. data/lib/webpacker/compiler.rb +9 -3
  33. data/lib/webpacker/configuration.rb +19 -8
  34. data/lib/webpacker/dev_server.rb +6 -0
  35. data/lib/webpacker/dev_server_runner.rb +7 -2
  36. data/lib/webpacker/env.rb +5 -1
  37. data/lib/webpacker/helper.rb +26 -50
  38. data/lib/webpacker/instance.rb +4 -0
  39. data/lib/webpacker/manifest.rb +1 -2
  40. data/lib/webpacker/railtie.rb +1 -2
  41. data/lib/webpacker/runner.rb +1 -1
  42. data/lib/webpacker/version.rb +1 -1
  43. data/lib/webpacker/webpack_runner.rb +1 -0
  44. data/package.json +25 -29
  45. data/package/__tests__/development.js +3 -2
  46. data/package/__tests__/env.js +8 -4
  47. data/package/__tests__/index.js +9 -0
  48. data/package/babel/preset.js +24 -14
  49. data/package/env.js +7 -1
  50. data/package/environments/__tests__/base.js +7 -7
  51. data/package/environments/base.js +25 -25
  52. data/package/environments/development.js +7 -8
  53. data/package/environments/production.js +28 -30
  54. data/package/index.js +9 -2
  55. data/package/inliningCss.js +7 -0
  56. data/package/rules/babel.js +1 -1
  57. data/package/rules/coffee.js +5 -5
  58. data/package/rules/erb.js +5 -3
  59. data/package/rules/file.js +5 -3
  60. data/package/rules/index.js +9 -17
  61. data/package/rules/less.js +14 -10
  62. data/package/rules/raw.js +5 -0
  63. data/package/rules/sass.js +12 -9
  64. data/package/rules/stylus.js +26 -0
  65. data/package/utils/get_style_rule.js +28 -30
  66. data/package/utils/helpers.js +25 -0
  67. data/test/configuration_test.rb +3 -3
  68. data/test/dev_server_runner_test.rb +13 -2
  69. data/test/helper_test.rb +59 -60
  70. data/test/manifest_test.rb +16 -0
  71. data/test/mounted_app/test/dummy/config/webpacker.yml +4 -4
  72. data/test/test_app/app/{javascript/packs → packs/entrypoints}/application.js +1 -1
  73. data/test/test_app/app/{javascript/packs → packs/entrypoints}/multi_entry.css +0 -0
  74. data/test/test_app/app/{javascript/packs → packs/entrypoints}/multi_entry.js +0 -0
  75. data/test/test_app/config/webpacker.yml +4 -6
  76. data/test/test_app/config/webpacker_other_location.yml +79 -0
  77. data/test/test_app/public/packs/manifest.json +19 -5
  78. data/test/webpacker_test.rb +17 -0
  79. data/yarn.lock +1567 -1039
  80. metadata +24 -36
  81. data/docs/assets.md +0 -135
  82. data/docs/cloud9.md +0 -310
  83. data/docs/css.md +0 -303
  84. data/docs/docker.md +0 -68
  85. data/docs/engines.md +0 -213
  86. data/docs/env.md +0 -68
  87. data/docs/es6.md +0 -72
  88. data/docs/folder-structure.md +0 -66
  89. data/docs/integrations.md +0 -220
  90. data/docs/misc.md +0 -23
  91. data/docs/props.md +0 -187
  92. data/docs/react.md +0 -183
  93. data/docs/target.md +0 -22
  94. data/docs/testing.md +0 -147
  95. data/docs/typescript.md +0 -190
  96. data/docs/v4-upgrade.md +0 -142
  97. data/docs/webpack-dev-server.md +0 -94
  98. data/docs/webpack.md +0 -315
  99. data/docs/yarn.md +0 -23
  100. data/lib/install/examples/vue3/app.vue +0 -27
  101. data/lib/install/examples/vue3/hello_vue.js +0 -15
  102. data/lib/install/javascript/packs/application.css +0 -9
  103. data/package/babel/preset-react.js +0 -62
  104. data/package/rules/svg.js +0 -23
@@ -1,4 +1,4 @@
1
1
  module Webpacker
2
2
  # Change the version in package.json too, please!
3
- VERSION = "6.0.0.pre.2".freeze
3
+ VERSION = "6.0.0.rc.1".freeze
4
4
  end
@@ -15,6 +15,7 @@ module Webpacker
15
15
 
16
16
  if @argv.include?("--debug-webpacker")
17
17
  cmd = [ "node", "--inspect-brk"] + cmd
18
+ @argv.delete "--debug-webpacker"
18
19
  end
19
20
 
20
21
  if @argv.include?("--trace-deprecation")
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rails/webpacker",
3
- "version": "6.0.0-pre.2",
3
+ "version": "6.0.0-rc.1",
4
4
  "description": "Use webpack to manage app-like JavaScript modules in Rails",
5
5
  "main": "package/index.js",
6
6
  "files": [
@@ -8,40 +8,36 @@
8
8
  "lib/install/config/webpacker.yml"
9
9
  ],
10
10
  "engines": {
11
- "node": ">=10.22.1 || ^12 || >=14",
12
- "yarn": ">=1 <3"
11
+ "node": "^12 || >=14",
12
+ "yarn": ">=1 <4"
13
13
  },
14
14
  "dependencies": {
15
- "@babel/core": "^7.12.9",
16
- "@babel/plugin-proposal-class-properties": "^7.12.1",
17
- "@babel/plugin-transform-runtime": "^7.12.1",
18
- "@babel/preset-env": "^7.12.11",
19
- "@babel/runtime": "^7.12.5",
15
+ "@babel/core": "^7.15.0",
16
+ "@babel/plugin-proposal-class-properties": "^7.14.5",
17
+ "@babel/plugin-transform-runtime": "^7.15.0",
18
+ "@babel/preset-env": "^7.15.0",
19
+ "@babel/runtime": "^7.15.3",
20
20
  "babel-loader": "^8.2.2",
21
- "babel-plugin-macros": "^3.0.1",
22
- "case-sensitive-paths-webpack-plugin": "^2.3.0",
23
- "compression-webpack-plugin": "^7.1.0",
24
- "core-js": "^3.8.0",
25
- "glob": "^7.1.6",
26
- "js-yaml": "^3.14.0",
21
+ "compression-webpack-plugin": "^7.1.2",
22
+ "glob": "^7.1.7",
23
+ "js-yaml": "^3.14.1",
27
24
  "path-complete-extname": "^1.0.0",
28
- "pnp-webpack-plugin": "^1.6.4",
29
- "regenerator-runtime": "^0.13.7",
30
- "terser-webpack-plugin": "^5.0.3",
31
- "webpack": "^5.11.0",
32
- "webpack-assets-manifest": "^5.0.0",
33
- "webpack-cli": "^4.2.0",
34
- "webpack-merge": "^5.7.2",
35
- "webpack-sources": "^2.2.0"
25
+ "pnp-webpack-plugin": "^1.7.0",
26
+ "terser-webpack-plugin": "^5.1.4",
27
+ "webpack": "^5.50.0",
28
+ "webpack-assets-manifest": "^5.0.6",
29
+ "webpack-cli": "^4.8.0",
30
+ "webpack-merge": "^5.8.0",
31
+ "webpack-sources": "^3.2.0"
36
32
  },
37
33
  "devDependencies": {
38
- "eslint": "^7.16.0",
39
- "eslint-config-airbnb": "^18.2.0",
40
- "eslint-config-prettier": "^7.1.0",
41
- "eslint-plugin-import": "^2.22.1",
42
- "eslint-plugin-jsx-a11y": "^6.3.1",
43
- "eslint-plugin-react": "^7.21.4",
44
- "jest": "^26.5.3"
34
+ "eslint": "^7.32.0",
35
+ "eslint-config-airbnb": "^18.2.1",
36
+ "eslint-config-prettier": "^7.2.0",
37
+ "eslint-plugin-import": "^2.24.0",
38
+ "eslint-plugin-jsx-a11y": "^6.4.1",
39
+ "eslint-plugin-react": "^7.24.0",
40
+ "jest": "^26.6.3"
45
41
  },
46
42
  "jest": {
47
43
  "testRegex": "(/__tests__/.*|(\\.|/))\\.jsx?$",
@@ -14,7 +14,7 @@ describe('Development environment', () => {
14
14
  test('should use development config and environment including devServer if WEBPACK_DEV_SERVER', () => {
15
15
  process.env.RAILS_ENV = 'development'
16
16
  process.env.NODE_ENV = 'development'
17
- process.env.WEBPACK_DEV_SERVER = 'YES'
17
+ process.env.WEBPACK_DEV_SERVER = 'true'
18
18
  const { webpackConfig } = require('../index')
19
19
 
20
20
  expect(webpackConfig.output.path).toEqual(resolve('public', 'packs'))
@@ -22,7 +22,8 @@ describe('Development environment', () => {
22
22
  expect(webpackConfig).toMatchObject({
23
23
  devServer: {
24
24
  host: 'localhost',
25
- port: 3035
25
+ port: 3035,
26
+ injectClient: false
26
27
  }
27
28
  })
28
29
  })
@@ -15,7 +15,8 @@ describe('Env', () => {
15
15
  railsEnv: 'development',
16
16
  nodeEnv: 'development',
17
17
  isProduction: false,
18
- isDevelopment: true
18
+ isDevelopment: true,
19
+ runningWebpackDevServer: false
19
20
  })
20
21
  })
21
22
 
@@ -26,7 +27,8 @@ describe('Env', () => {
26
27
  railsEnv: 'development',
27
28
  nodeEnv: 'production',
28
29
  isProduction: true,
29
- isDevelopment: false
30
+ isDevelopment: false,
31
+ runningWebpackDevServer: false
30
32
  })
31
33
  })
32
34
 
@@ -37,7 +39,8 @@ describe('Env', () => {
37
39
  railsEnv: 'production',
38
40
  nodeEnv: 'production',
39
41
  isProduction: true,
40
- isDevelopment: false
42
+ isDevelopment: false,
43
+ runningWebpackDevServer: false
41
44
  })
42
45
  })
43
46
 
@@ -48,7 +51,8 @@ describe('Env', () => {
48
51
  railsEnv: 'staging',
49
52
  nodeEnv: 'production',
50
53
  isProduction: true,
51
- isDevelopment: false
54
+ isDevelopment: false,
55
+ runningWebpackDevServer: false
52
56
  })
53
57
  })
54
58
  })
@@ -0,0 +1,9 @@
1
+ const index = require('../index')
2
+
3
+ describe('index', () => {
4
+ test('exports webpack-merge v5 functions', () => {
5
+ expect(index.merge).toBeInstanceOf(Function)
6
+ expect(index.mergeWithRules).toBeInstanceOf(Function)
7
+ expect(index.mergeWithCustomize).toBeInstanceOf(Function)
8
+ })
9
+ })
@@ -1,3 +1,5 @@
1
+ const { moduleExists } = require('@rails/webpacker')
2
+
1
3
  module.exports = function config(api) {
2
4
  const validEnv = ['development', 'test', 'production']
3
5
  const currentEnv = api.env()
@@ -7,16 +9,15 @@ module.exports = function config(api) {
7
9
 
8
10
  if (!validEnv.includes(currentEnv)) {
9
11
  throw new Error(
10
- `Please specify a valid NODE_ENV or BABEL_ENV environment variable. Valid values are "development", "test", and "production". Instead, received: "${JSON.stringify(currentEnv)}".`
12
+ `Please specify a valid NODE_ENV or BABEL_ENV environment variable. Valid values are "development", "test", and "production". Instead, received: "${JSON.stringify(
13
+ currentEnv
14
+ )}".`
11
15
  )
12
16
  }
13
17
 
14
18
  return {
15
19
  presets: [
16
- isTestEnv && [
17
- '@babel/preset-env',
18
- { targets: { node: 'current' } }
19
- ],
20
+ isTestEnv && ['@babel/preset-env', { targets: { node: 'current' } }],
20
21
  (isProductionEnv || isDevelopmentEnv) && [
21
22
  '@babel/preset-env',
22
23
  {
@@ -27,18 +28,27 @@ module.exports = function config(api) {
27
28
  loose: true,
28
29
  exclude: ['transform-typeof-symbol']
29
30
  }
31
+ ],
32
+ moduleExists('@babel/preset-typescript') && [
33
+ '@babel/preset-typescript',
34
+ { allExtensions: true, isTSX: true }
35
+ ],
36
+ moduleExists('@babel/preset-react') && [
37
+ '@babel/preset-react',
38
+ {
39
+ development: isDevelopmentEnv || isTestEnv,
40
+ useBuiltIns: true
41
+ }
30
42
  ]
31
43
  ].filter(Boolean),
32
44
  plugins: [
33
- 'babel-plugin-macros',
34
- [
35
- '@babel/plugin-proposal-class-properties',
36
- { loose: true }
37
- ],
38
- [
39
- '@babel/plugin-transform-runtime',
40
- { helpers: false }
41
- ]
45
+ ['@babel/plugin-proposal-class-properties', { loose: true }],
46
+ ['@babel/plugin-transform-runtime', { helpers: false }],
47
+ isProductionEnv &&
48
+ moduleExists('babel-plugin-transform-react-remove-prop-types') && [
49
+ 'babel-plugin-transform-react-remove-prop-types',
50
+ { removeImport: true }
51
+ ]
42
52
  ].filter(Boolean)
43
53
  }
44
54
  }
data/package/env.js CHANGED
@@ -16,9 +16,15 @@ const config = safeLoad(readFileSync(configPath), 'utf8')
16
16
  const availableEnvironments = Object.keys(config).join('|')
17
17
  const regex = new RegExp(`^(${availableEnvironments})$`, 'g')
18
18
 
19
+ // v4 of webpack-dev-server will switch to WEBPACK_DEV_SERVE
20
+ // https://github.com/rails/webpacker/issues/3057
21
+ const runningWebpackDevServer = process.env.WEBPACK_DEV_SERVER === 'true' ||
22
+ process.env.WEBPACK_DEV_SERVE === 'true'
23
+
19
24
  module.exports = {
20
25
  railsEnv: railsEnv && railsEnv.match(regex) ? railsEnv : DEFAULT,
21
26
  nodeEnv,
22
27
  isProduction,
23
- isDevelopment
28
+ isDevelopment,
29
+ runningWebpackDevServer
24
30
  }
@@ -17,21 +17,21 @@ describe('Base config', () => {
17
17
  describe('config', () => {
18
18
  test('should return entry', () => {
19
19
  expect(baseConfig.entry.application).toEqual(
20
- resolve('app', 'javascript', 'packs', 'application.js')
20
+ resolve('app', 'packs', 'entrypoints', 'application.js')
21
21
  )
22
22
  })
23
23
 
24
24
  test('should return multi file entry points', () => {
25
25
  expect(baseConfig.entry.multi_entry.sort()).toEqual([
26
- resolve('app', 'javascript', 'packs', 'multi_entry.css'),
27
- resolve('app', 'javascript', 'packs', 'multi_entry.js')
26
+ resolve('app', 'packs', 'entrypoints', 'multi_entry.css'),
27
+ resolve('app', 'packs', 'entrypoints', 'multi_entry.js')
28
28
  ])
29
29
  })
30
30
 
31
31
  test('should return output', () => {
32
- expect(baseConfig.output.filename).toEqual('js/[name]-[contenthash].js')
32
+ expect(baseConfig.output.filename).toEqual('js/[name].js')
33
33
  expect(baseConfig.output.chunkFilename).toEqual(
34
- 'js/[name]-[contenthash].chunk.js'
34
+ 'js/[name].chunk.js'
35
35
  )
36
36
  })
37
37
 
@@ -44,7 +44,7 @@ describe('Base config', () => {
44
44
  })
45
45
 
46
46
  test('should return default plugins', () => {
47
- expect(baseConfig.plugins.length).toEqual(4)
47
+ expect(baseConfig.plugins.length).toEqual(2)
48
48
  })
49
49
 
50
50
  test('should return default resolveLoader', () => {
@@ -53,7 +53,7 @@ describe('Base config', () => {
53
53
 
54
54
  test('should return default resolve.modules with additions', () => {
55
55
  expect(baseConfig.resolve.modules).toEqual([
56
- resolve('app', 'javascript'),
56
+ resolve('app', 'packs'),
57
57
  resolve('app/assets'),
58
58
  resolve('/etc/yarn'),
59
59
  resolve('some.config.js'),
@@ -4,19 +4,19 @@
4
4
  const { basename, dirname, join, relative, resolve } = require('path')
5
5
  const extname = require('path-complete-extname')
6
6
  const PnpWebpackPlugin = require('pnp-webpack-plugin')
7
- const { sync } = require('glob')
8
- const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
7
+ const { sync: globSync } = require('glob')
9
8
  const WebpackAssetsManifest = require('webpack-assets-manifest')
10
9
  const webpack = require('webpack')
11
10
  const rules = require('../rules')
11
+ const { isProduction } = require('../env')
12
12
  const config = require('../config')
13
- const { isDevelopment } = require('../env')
13
+ const { moduleExists } = require('../utils/helpers')
14
14
 
15
15
  const getEntryObject = () => {
16
16
  const entries = {}
17
17
  const rootPath = join(config.source_path, config.source_entry_path)
18
18
 
19
- sync(`${rootPath}/**/*.*`).forEach((path) => {
19
+ globSync(`${rootPath}/**/*.*`).forEach((path) => {
20
20
  const namespace = relative(join(rootPath), dirname(path))
21
21
  const name = join(namespace, basename(path, extname(path)))
22
22
  let assetPaths = resolve(path)
@@ -52,8 +52,6 @@ const getModulePaths = () => {
52
52
  const getPlugins = () => {
53
53
  const plugins = [
54
54
  new webpack.EnvironmentPlugin(process.env),
55
- PnpWebpackPlugin,
56
- new CaseSensitivePathsPlugin(),
57
55
  new WebpackAssetsManifest({
58
56
  entrypoints: true,
59
57
  writeToDisk: true,
@@ -63,37 +61,39 @@ const getPlugins = () => {
63
61
  })
64
62
  ]
65
63
 
66
- try {
67
- if (require.resolve('css-loader')) {
68
- const MiniCssExtractPlugin = require('mini-css-extract-plugin')
69
- plugins.push(
70
- new MiniCssExtractPlugin({
71
- filename: isDevelopment ? '[name].css' : '[name].[contenthash:8].css',
72
- chunkFilename: isDevelopment ? '[id].css' : '[id].[contenthash:8].css'
73
- })
74
- )
75
- }
76
- } catch (e) {
77
- /* Work out what to print here */
64
+ if (moduleExists('css-loader') && moduleExists('mini-css-extract-plugin')) {
65
+ const hash = isProduction ? '-[contenthash:8]' : ''
66
+ const MiniCssExtractPlugin = require('mini-css-extract-plugin')
67
+ plugins.push(
68
+ new MiniCssExtractPlugin({
69
+ filename: `css/[name]${hash}.css`,
70
+ chunkFilename: `css/[id]${hash}.css`
71
+ })
72
+ )
78
73
  }
79
74
 
80
75
  return plugins
81
76
  }
82
77
 
78
+ // Don't use contentHash except for production for performance
79
+ // https://webpack.js.org/guides/build-performance/#avoid-production-specific-tooling
80
+ const hash = isProduction ? '-[contenthash]' : ''
83
81
  module.exports = {
84
82
  mode: 'production',
85
83
  output: {
86
- filename: 'js/[name]-[contenthash].js',
87
- chunkFilename: 'js/[name]-[contenthash].chunk.js',
88
- hotUpdateChunkFilename: 'js/[id]-[hash].hot-update.js',
89
- assetModuleFilename: 'static/[hash][ext][query]',
84
+ filename: `js/[name]${hash}.js`,
85
+ chunkFilename: `js/[name]${hash}.chunk.js`,
86
+
87
+ // https://webpack.js.org/configuration/output/#outputhotupdatechunkfilename
88
+ hotUpdateChunkFilename: 'js/[id].[fullhash].hot-update.js',
90
89
  path: config.outputPath,
91
90
  publicPath: config.publicPath
92
91
  },
93
92
  entry: getEntryObject(),
94
93
  resolve: {
95
- extensions: ['.js', '.mjs', '.ts'],
96
- modules: getModulePaths()
94
+ extensions: ['.js', '.jsx', '.mjs', '.ts', '.tsx', '.coffee'],
95
+ modules: getModulePaths(),
96
+ plugins: [PnpWebpackPlugin]
97
97
  },
98
98
 
99
99
  plugins: getPlugins(),
@@ -106,7 +106,7 @@ module.exports = {
106
106
  optimization: {
107
107
  splitChunks: { chunks: 'all' },
108
108
 
109
- runtimeChunk: { name: (entrypoint) => `runtime-${entrypoint.name}` }
109
+ runtimeChunk: 'single'
110
110
  },
111
111
 
112
112
  module: {
@@ -1,8 +1,8 @@
1
1
  const { merge } = require('webpack-merge')
2
- const webpack = require('webpack')
3
2
 
4
3
  const baseConfig = require('./base')
5
4
  const devServer = require('../dev_server')
5
+ const { runningWebpackDevServer } = require('../env')
6
6
 
7
7
  const { outputPath: contentBase, publicPath } = require('../config')
8
8
 
@@ -11,14 +11,10 @@ let devConfig = {
11
11
  devtool: 'cheap-module-source-map'
12
12
  }
13
13
 
14
- if (
15
- process.env.WEBPACK_DEV_SERVER &&
16
- process.env.WEBPACK_DEV_SERVER !== 'undefined'
17
- ) {
14
+ if (runningWebpackDevServer) {
18
15
  if (devServer.hmr) {
19
16
  devConfig = merge(devConfig, {
20
- output: { filename: '[name]-[hash].js' },
21
- plugins: [new webpack.HotModuleReplacementPlugin()]
17
+ output: { filename: '[name]-[hash].js' }
22
18
  })
23
19
  }
24
20
 
@@ -33,7 +29,9 @@ if (
33
29
  https: devServer.https,
34
30
  hot: devServer.hmr,
35
31
  contentBase,
36
- inline: devServer.inline,
32
+ inline: devServer.inline || devServer.hmr,
33
+ injectClient: devServer.hmr,
34
+ injectHot: devServer.hmr,
37
35
  useLocalIp: devServer.use_local_ip,
38
36
  public: devServer.public,
39
37
  publicPath,
@@ -41,6 +39,7 @@ if (
41
39
  headers: devServer.headers,
42
40
  overlay: devServer.overlay,
43
41
  stats: {
42
+ colors: true,
44
43
  entrypoints: false,
45
44
  errorDetails: true,
46
45
  modules: false,
@@ -5,45 +5,42 @@ const { merge } = require('webpack-merge')
5
5
  const CompressionPlugin = require('compression-webpack-plugin')
6
6
  const TerserPlugin = require('terser-webpack-plugin')
7
7
  const baseConfig = require('./base')
8
+ const { moduleExists } = require('../utils/helpers')
8
9
 
9
10
  const getPlugins = () => {
10
- let compressionPlugin = new CompressionPlugin({
11
- filename: '[path].gz[query]',
12
- algorithm: 'gzip',
13
- test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
14
- })
11
+ const plugins = []
15
12
 
16
- if ('brotli' in process.versions) {
17
- compressionPlugin = new CompressionPlugin({
18
- filename: '[path].br[query]',
19
- algorithm: 'brotliCompress',
13
+ plugins.push(
14
+ new CompressionPlugin({
15
+ filename: '[path][base].gz[query]',
16
+ algorithm: 'gzip',
20
17
  test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
21
18
  })
19
+ )
20
+
21
+ if ('brotli' in process.versions) {
22
+ plugins.push(
23
+ new CompressionPlugin({
24
+ filename: '[path][base].br[query]',
25
+ algorithm: 'brotliCompress',
26
+ test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
27
+ })
28
+ )
22
29
  }
23
30
 
24
- const plugins = [compressionPlugin]
31
+ return plugins
32
+ }
25
33
 
26
- try {
27
- if (require.resolve('css-loader')) {
28
- const OptimizeCSSAssetsPlugin = require.resolve(
29
- 'optimize-css-assets-webpack-plugin'
30
- )
31
- const safePostCssParser = require.resolve('postcss-safe-parser')
32
- plugins.push(
33
- new OptimizeCSSAssetsPlugin({
34
- parser: safePostCssParser,
35
- map: {
36
- inline: false,
37
- annotation: true
38
- }
39
- })
40
- )
41
- }
42
- } catch (e) {
43
- /* Work out what to output without clutter */
34
+ const tryCssMinimizer = () => {
35
+ if (
36
+ moduleExists('css-loader') &&
37
+ moduleExists('css-minimizer-webpack-plugin')
38
+ ) {
39
+ const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
40
+ return new CssMinimizerPlugin()
44
41
  }
45
42
 
46
- return plugins
43
+ return null
47
44
  }
48
45
 
49
46
  const productionConfig = {
@@ -53,6 +50,7 @@ const productionConfig = {
53
50
  plugins: getPlugins(),
54
51
  optimization: {
55
52
  minimizer: [
53
+ tryCssMinimizer(),
56
54
  new TerserPlugin({
57
55
  parallel: Number.parseInt(process.env.WEBPACKER_PARALLEL, 10) || true,
58
56
  terserOptions: {
@@ -74,7 +72,7 @@ const productionConfig = {
74
72
  }
75
73
  }
76
74
  })
77
- ]
75
+ ].filter(Boolean)
78
76
  }
79
77
  }
80
78