webpacker 6.0.0.pre.2 → 6.0.0.rc.6

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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/jest.yml +7 -15
  3. data/.github/workflows/js-lint.yml +7 -15
  4. data/.github/workflows/rubocop.yml +1 -1
  5. data/.github/workflows/ruby.yml +18 -40
  6. data/.node-version +1 -1
  7. data/.rubocop.yml +107 -1
  8. data/CHANGELOG.md +48 -9
  9. data/CONTRIBUTING.md +20 -1
  10. data/Gemfile.lock +107 -104
  11. data/README.md +387 -177
  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 +61 -25
  17. data/docs/v6_upgrade.md +113 -0
  18. data/gemfiles/Gemfile-rails-edge +1 -1
  19. data/gemfiles/Gemfile-rails.6.1.x +12 -0
  20. data/lib/install/{javascript/packs/application.js → application.js} +2 -5
  21. data/lib/install/bin/webpack +4 -7
  22. data/lib/install/bin/yarn +18 -0
  23. data/lib/install/config/webpacker.yml +18 -17
  24. data/lib/install/package.json +15 -0
  25. data/lib/install/template.rb +50 -21
  26. data/lib/tasks/webpacker/binstubs.rake +2 -2
  27. data/lib/tasks/webpacker/check_node.rake +3 -0
  28. data/lib/tasks/webpacker/check_yarn.rake +4 -1
  29. data/lib/tasks/webpacker/clobber.rake +1 -1
  30. data/lib/tasks/webpacker/install.rake +2 -2
  31. data/lib/tasks/webpacker/verify_config.rake +14 -0
  32. data/lib/tasks/webpacker/verify_install.rake +1 -11
  33. data/lib/tasks/yarn.rake +38 -0
  34. data/lib/webpacker/commands.rb +21 -16
  35. data/lib/webpacker/compiler.rb +9 -3
  36. data/lib/webpacker/configuration.rb +19 -8
  37. data/lib/webpacker/dev_server.rb +6 -0
  38. data/lib/webpacker/dev_server_runner.rb +7 -2
  39. data/lib/webpacker/env.rb +5 -1
  40. data/lib/webpacker/helper.rb +26 -50
  41. data/lib/webpacker/instance.rb +4 -0
  42. data/lib/webpacker/manifest.rb +1 -2
  43. data/lib/webpacker/railtie.rb +8 -2
  44. data/lib/webpacker/runner.rb +1 -1
  45. data/lib/webpacker/version.rb +1 -1
  46. data/lib/webpacker/webpack_runner.rb +27 -6
  47. data/lib/webpacker.rb +1 -1
  48. data/package/__tests__/development.js +4 -10
  49. data/package/__tests__/env.js +8 -4
  50. data/package/__tests__/index.js +9 -0
  51. data/package/babel/preset.js +24 -14
  52. data/package/config.js +3 -3
  53. data/package/env.js +6 -3
  54. data/package/environments/__tests__/base.js +7 -7
  55. data/package/environments/base.js +25 -25
  56. data/package/environments/development.js +36 -35
  57. data/package/environments/production.js +28 -30
  58. data/package/index.js +9 -2
  59. data/package/inliningCss.js +7 -0
  60. data/package/rules/babel.js +1 -1
  61. data/package/rules/coffee.js +5 -5
  62. data/package/rules/erb.js +5 -3
  63. data/package/rules/file.js +5 -3
  64. data/package/rules/index.js +9 -17
  65. data/package/rules/less.js +14 -10
  66. data/package/rules/raw.js +5 -0
  67. data/package/rules/sass.js +12 -9
  68. data/package/rules/stylus.js +26 -0
  69. data/package/utils/get_style_rule.js +28 -30
  70. data/package/utils/helpers.js +25 -0
  71. data/package.json +25 -29
  72. data/test/command_test.rb +76 -0
  73. data/test/configuration_test.rb +3 -3
  74. data/test/dev_server_runner_test.rb +13 -2
  75. data/test/helper_test.rb +69 -61
  76. data/test/manifest_test.rb +16 -0
  77. data/test/mounted_app/test/dummy/config/webpacker.yml +4 -4
  78. data/test/test_app/app/{javascript/packs → packs/entrypoints}/application.js +1 -1
  79. data/test/test_app/config/initializers/inspect_autoload_paths.rb +1 -0
  80. data/test/test_app/config/webpacker.yml +4 -6
  81. data/test/test_app/config/webpacker_other_location.yml +79 -0
  82. data/test/test_app/public/packs/manifest.json +19 -5
  83. data/test/webpacker_test.rb +21 -0
  84. data/webpacker.gemspec +2 -2
  85. data/yarn.lock +2357 -3262
  86. metadata +34 -41
  87. data/docs/assets.md +0 -135
  88. data/docs/cloud9.md +0 -310
  89. data/docs/css.md +0 -303
  90. data/docs/docker.md +0 -68
  91. data/docs/engines.md +0 -213
  92. data/docs/env.md +0 -68
  93. data/docs/es6.md +0 -72
  94. data/docs/folder-structure.md +0 -66
  95. data/docs/integrations.md +0 -220
  96. data/docs/misc.md +0 -23
  97. data/docs/props.md +0 -187
  98. data/docs/react.md +0 -183
  99. data/docs/target.md +0 -22
  100. data/docs/testing.md +0 -147
  101. data/docs/typescript.md +0 -190
  102. data/docs/v4-upgrade.md +0 -142
  103. data/docs/webpack-dev-server.md +0 -94
  104. data/docs/webpack.md +0 -315
  105. data/docs/yarn.md +0 -23
  106. data/lib/install/examples/vue3/app.vue +0 -27
  107. data/lib/install/examples/vue3/hello_vue.js +0 -15
  108. data/lib/install/javascript/packs/application.css +0 -9
  109. data/package/babel/preset-react.js +0 -62
  110. data/package/rules/svg.js +0 -23
  111. /data/test/test_app/app/{javascript/packs → packs/entrypoints}/multi_entry.css +0 -0
  112. /data/test/test_app/app/{javascript/packs → packs/entrypoints}/multi_entry.js +0 -0
@@ -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/config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const { resolve } = require('path')
2
- const { safeLoad } = require('js-yaml')
2
+ const { load } = require('js-yaml')
3
3
  const { readFileSync } = require('fs')
4
4
  const { merge } = require('webpack-merge')
5
5
  const { ensureTrailingSlash } = require('./utils/helpers')
@@ -9,12 +9,12 @@ const configPath = require('./configPath')
9
9
  const defaultConfigPath = require.resolve('../lib/install/config/webpacker.yml')
10
10
 
11
11
  const getDefaultConfig = () => {
12
- const defaultConfig = safeLoad(readFileSync(defaultConfigPath), 'utf8')
12
+ const defaultConfig = load(readFileSync(defaultConfigPath), 'utf8')
13
13
  return defaultConfig[railsEnv] || defaultConfig.production
14
14
  }
15
15
 
16
16
  const defaults = getDefaultConfig()
17
- const app = safeLoad(readFileSync(configPath), 'utf8')[railsEnv]
17
+ const app = load(readFileSync(configPath), 'utf8')[railsEnv]
18
18
 
19
19
  const config = merge(defaults, app)
20
20
  config.outputPath = resolve(config.public_root_path, config.public_output_path)
data/package/env.js CHANGED
@@ -1,4 +1,4 @@
1
- const { safeLoad } = require('js-yaml')
1
+ const { load } = require('js-yaml')
2
2
  const { readFileSync } = require('fs')
3
3
 
4
4
  const NODE_ENVIRONMENTS = ['development', 'production', 'test']
@@ -12,13 +12,16 @@ const nodeEnv
12
12
  const isProduction = nodeEnv === 'production'
13
13
  const isDevelopment = nodeEnv === 'development'
14
14
 
15
- const config = safeLoad(readFileSync(configPath), 'utf8')
15
+ const config = load(readFileSync(configPath), 'utf8')
16
16
  const availableEnvironments = Object.keys(config).join('|')
17
17
  const regex = new RegExp(`^(${availableEnvironments})$`, 'g')
18
18
 
19
+ const runningWebpackDevServer = process.env.WEBPACK_SERVE === 'true'
20
+
19
21
  module.exports = {
20
22
  railsEnv: railsEnv && railsEnv.match(regex) ? railsEnv : DEFAULT,
21
23
  nodeEnv,
22
24
  isProduction,
23
- isDevelopment
25
+ isDevelopment,
26
+ runningWebpackDevServer
24
27
  }
@@ -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,43 +11,44 @@ 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
- ) {
18
- if (devServer.hmr) {
19
- devConfig = merge(devConfig, {
20
- output: { filename: '[name]-[hash].js' },
21
- plugins: [new webpack.HotModuleReplacementPlugin()]
22
- })
14
+ if (runningWebpackDevServer) {
15
+ const liveReload = devServer.live_reload !== undefined ? devServer.live_reload : !devServer.hmr
16
+
17
+ const devServerConfig = {
18
+ devMiddleware: {
19
+ publicPath
20
+ },
21
+ compress: devServer.compress,
22
+ allowedHosts: devServer.allowed_hosts,
23
+ host: devServer.host,
24
+ port: devServer.port,
25
+ https: devServer.https,
26
+ hot: devServer.hmr,
27
+ liveReload,
28
+ historyApiFallback: { disableDotRule: true },
29
+ headers: devServer.headers,
30
+ static: {
31
+ publicPath: contentBase
32
+ }
33
+ }
34
+
35
+ if (devServer.static) {
36
+ devServerConfig.static = { ...devServerConfig.static, ...devServer.static }
37
+ }
38
+
39
+ if (devServer.client) {
40
+ devServerConfig.client = devServer.client
23
41
  }
24
42
 
25
43
  devConfig = merge(devConfig, {
26
- devServer: {
27
- clientLogLevel: 'none',
28
- compress: devServer.compress,
29
- quiet: devServer.quiet,
30
- disableHostCheck: devServer.disable_host_check,
31
- host: devServer.host,
32
- port: devServer.port,
33
- https: devServer.https,
34
- hot: devServer.hmr,
35
- contentBase,
36
- inline: devServer.inline,
37
- useLocalIp: devServer.use_local_ip,
38
- public: devServer.public,
39
- publicPath,
40
- historyApiFallback: { disableDotRule: true },
41
- headers: devServer.headers,
42
- overlay: devServer.overlay,
43
- stats: {
44
- entrypoints: false,
45
- errorDetails: true,
46
- modules: false,
47
- moduleTrace: false
48
- },
49
- watchOptions: devServer.watch_options
50
- }
44
+ stats: {
45
+ colors: true,
46
+ entrypoints: false,
47
+ errorDetails: true,
48
+ modules: false,
49
+ moduleTrace: false
50
+ },
51
+ devServer: devServerConfig
51
52
  })
52
53
  }
53
54
 
@@ -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
 
data/package/index.js CHANGED
@@ -1,13 +1,16 @@
1
1
  /* eslint global-require: 0 */
2
2
  /* eslint import/no-dynamic-require: 0 */
3
3
 
4
+ const webpackMerge = require('webpack-merge')
4
5
  const { resolve } = require('path')
5
6
  const { existsSync } = require('fs')
6
7
  const baseConfig = require('./environments/base')
7
- const loaders = require('./rules')
8
+ const rules = require('./rules')
8
9
  const config = require('./config')
9
10
  const devServer = require('./dev_server')
10
11
  const { nodeEnv } = require('./env')
12
+ const { moduleExists, canProcess } = require('./utils/helpers')
13
+ const inliningCss = require('./inliningCss')
11
14
 
12
15
  const webpackConfig = () => {
13
16
  const path = resolve(__dirname, 'environments', `${nodeEnv}.js`)
@@ -20,5 +23,9 @@ module.exports = {
20
23
  devServer,
21
24
  webpackConfig: webpackConfig(),
22
25
  baseConfig,
23
- loaders
26
+ rules,
27
+ moduleExists,
28
+ canProcess,
29
+ inliningCss,
30
+ ...webpackMerge
24
31
  }
@@ -0,0 +1,7 @@
1
+ const { runningWebpackDevServer } = require('./env')
2
+ const devServer = require('./dev_server')
3
+
4
+ // This logic is tied to lib/webpacker/instance.rb
5
+ const inliningCss = runningWebpackDevServer && devServer.hmr
6
+
7
+ module.exports = inliningCss
@@ -8,7 +8,7 @@ const {
8
8
  const { isProduction } = require('../env')
9
9
 
10
10
  module.exports = {
11
- test: /\.(js|jsx|mjs|ts|tsx)?(\.erb)?$/,
11
+ test: /\.(js|jsx|mjs|ts|tsx|coffee)?(\.erb)?$/,
12
12
  include: [sourcePath, ...additionalPaths].map((p) => {
13
13
  try {
14
14
  return realpathSync(p)
@@ -1,6 +1,6 @@
1
- module.exports = {
1
+ const { canProcess } = require('../utils/helpers')
2
+
3
+ module.exports = canProcess('coffee-loader', (resolvedPath) => ({
2
4
  test: /\.coffee(\.erb)?$/,
3
- use: [
4
- { loader: require.resolve('coffee-loader') }
5
- ]
6
- }
5
+ use: [{ loader: resolvedPath }]
6
+ }))
data/package/rules/erb.js CHANGED
@@ -1,13 +1,15 @@
1
+ const { canProcess } = require('../utils/helpers')
2
+
1
3
  const runner = /^win/.test(process.platform) ? 'ruby ' : ''
2
4
 
3
- module.exports = {
5
+ module.exports = canProcess('rails-erb-loader', (resolvedPath) => ({
4
6
  test: /\.erb$/,
5
7
  enforce: 'pre',
6
8
  exclude: /node_modules/,
7
9
  use: [
8
10
  {
9
- loader: require.resolve('rails-erb-loader'),
11
+ loader: resolvedPath,
10
12
  options: { runner: `${runner}bin/rails runner` }
11
13
  }
12
14
  ]
13
- }
15
+ }))
@@ -13,9 +13,11 @@ module.exports = {
13
13
  /\.ttf$/,
14
14
  /\.woff$/,
15
15
  /\.woff2$/,
16
- /\.html$/,
17
- /\.json$/
16
+ /\.svg$/
18
17
  ],
19
18
  exclude: [/\.(js|mjs|jsx|ts|tsx)$/],
20
- type: 'asset/resource'
19
+ type: 'asset/resource',
20
+ generator: {
21
+ filename: 'static/[name]-[hash][ext][query]'
22
+ }
21
23
  }
@@ -1,24 +1,16 @@
1
1
  /* eslint global-require: 0 */
2
2
  /* eslint import/no-dynamic-require: 0 */
3
3
 
4
- const load = (name) => {
5
- try {
6
- return require(`./${name}`)
7
- } catch (e) {
8
- return null
9
- }
10
- }
11
-
12
4
  const rules = {
13
- file: load('file'),
14
- svg: load('svg'),
15
- css: load('css'),
16
- sass: load('sass'),
17
- babel: load('babel'),
18
- erb: load('erb'),
19
- coffee: load('coffee'),
20
- html: load('html'),
21
- less: load('less')
5
+ raw: require('./raw'),
6
+ file: require('./file'),
7
+ css: require('./css'),
8
+ sass: require('./sass'),
9
+ babel: require('./babel'),
10
+ erb: require('./erb'),
11
+ coffee: require('./coffee'),
12
+ less: require('./less'),
13
+ stylus: require('./stylus')
22
14
  }
23
15
 
24
16
  module.exports = Object.keys(rules)
@@ -1,18 +1,22 @@
1
1
  const path = require('path')
2
+ const { canProcess } = require('../utils/helpers')
2
3
  const getStyleRule = require('../utils/get_style_rule')
4
+
3
5
  const {
4
6
  additional_paths: paths,
5
7
  source_path: sourcePath
6
8
  } = require('../config')
7
9
 
8
- module.exports = getStyleRule(/\.(less)(\.erb)?$/i, [
9
- {
10
- loader: require.resolve('less-loader'),
11
- options: {
12
- lessOptions: {
13
- paths: [path.resolve(__dirname, 'node_modules'), sourcePath, ...paths]
14
- },
15
- sourceMap: true
10
+ module.exports = canProcess('less-loader', (resolvedPath) =>
11
+ getStyleRule(/\.(less)(\.erb)?$/i, [
12
+ {
13
+ loader: resolvedPath,
14
+ options: {
15
+ lessOptions: {
16
+ paths: [path.resolve(__dirname, 'node_modules'), sourcePath, ...paths]
17
+ },
18
+ sourceMap: true
19
+ }
16
20
  }
17
- }
18
- ])
21
+ ])
22
+ )
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ test: [/\.html$/],
3
+ exclude: [/\.(js|mjs|jsx|ts|tsx)$/],
4
+ type: 'asset/source'
5
+ }