shakapacker 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 (147) hide show
  1. checksums.yaml +7 -0
  2. data/.eslintignore +4 -0
  3. data/.eslintrc.js +14 -0
  4. data/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
  5. data/.github/ISSUE_TEMPLATE/feature-request.md +18 -0
  6. data/.github/workflows/jest.yml +30 -0
  7. data/.github/workflows/js-lint.yml +31 -0
  8. data/.github/workflows/rubocop.yml +39 -0
  9. data/.github/workflows/ruby.yml +48 -0
  10. data/.gitignore +13 -0
  11. data/.node-version +1 -0
  12. data/.rubocop.yml +229 -0
  13. data/CHANGELOG.md +32 -0
  14. data/CONTRIBUTING.md +62 -0
  15. data/Gemfile +13 -0
  16. data/Gemfile.lock +183 -0
  17. data/MIT-LICENSE +20 -0
  18. data/README.md +666 -0
  19. data/Rakefile +11 -0
  20. data/config/README.md +3 -0
  21. data/config/webpacker.yml +1 -0
  22. data/docs/customizing_babel_config.md +59 -0
  23. data/docs/deployment.md +116 -0
  24. data/docs/developing_webpacker.md +29 -0
  25. data/docs/troubleshooting.md +212 -0
  26. data/docs/v6_upgrade.md +158 -0
  27. data/gemfiles/Gemfile-rails-edge +12 -0
  28. data/gemfiles/Gemfile-rails.5.2.x +9 -0
  29. data/gemfiles/Gemfile-rails.6.0.x +9 -0
  30. data/gemfiles/Gemfile-rails.6.1.x +12 -0
  31. data/lib/install/application.js +15 -0
  32. data/lib/install/bin/webpacker +15 -0
  33. data/lib/install/bin/webpacker-dev-server +18 -0
  34. data/lib/install/bin/yarn +18 -0
  35. data/lib/install/binstubs.rb +4 -0
  36. data/lib/install/config/webpack/webpack.config.js +5 -0
  37. data/lib/install/config/webpacker.yml +64 -0
  38. data/lib/install/package.json +15 -0
  39. data/lib/install/template.rb +100 -0
  40. data/lib/shakapacker/utils/git_utils.rb +23 -0
  41. data/lib/shakapacker/utils/version_syntax_converter.rb +24 -0
  42. data/lib/tasks/webpacker/binstubs.rake +15 -0
  43. data/lib/tasks/webpacker/check_binstubs.rake +12 -0
  44. data/lib/tasks/webpacker/check_node.rake +31 -0
  45. data/lib/tasks/webpacker/check_yarn.rake +33 -0
  46. data/lib/tasks/webpacker/clean.rake +25 -0
  47. data/lib/tasks/webpacker/clobber.rake +20 -0
  48. data/lib/tasks/webpacker/compile.rake +45 -0
  49. data/lib/tasks/webpacker/info.rake +21 -0
  50. data/lib/tasks/webpacker/install.rake +17 -0
  51. data/lib/tasks/webpacker/verify_config.rake +14 -0
  52. data/lib/tasks/webpacker/verify_install.rake +4 -0
  53. data/lib/tasks/webpacker/yarn_install.rake +18 -0
  54. data/lib/tasks/webpacker.rake +19 -0
  55. data/lib/tasks/yarn.rake +38 -0
  56. data/lib/webpacker/commands.rb +79 -0
  57. data/lib/webpacker/compiler.rb +130 -0
  58. data/lib/webpacker/configuration.rb +111 -0
  59. data/lib/webpacker/dev_server.rb +72 -0
  60. data/lib/webpacker/dev_server_proxy.rb +33 -0
  61. data/lib/webpacker/dev_server_runner.rb +96 -0
  62. data/lib/webpacker/env.rb +43 -0
  63. data/lib/webpacker/helper.rb +161 -0
  64. data/lib/webpacker/instance.rb +41 -0
  65. data/lib/webpacker/manifest.rb +120 -0
  66. data/lib/webpacker/railtie.rb +63 -0
  67. data/lib/webpacker/runner.rb +23 -0
  68. data/lib/webpacker/version.rb +4 -0
  69. data/lib/webpacker/webpack_runner.rb +58 -0
  70. data/lib/webpacker.rb +46 -0
  71. data/package/__tests__/config.js +34 -0
  72. data/package/__tests__/dev_server.js +45 -0
  73. data/package/__tests__/development.js +35 -0
  74. data/package/__tests__/env.js +58 -0
  75. data/package/__tests__/index.js +9 -0
  76. data/package/__tests__/production.js +29 -0
  77. data/package/__tests__/staging.js +30 -0
  78. data/package/__tests__/test.js +25 -0
  79. data/package/babel/preset.js +41 -0
  80. data/package/config.js +32 -0
  81. data/package/configPath.js +3 -0
  82. data/package/dev_server.js +20 -0
  83. data/package/env.js +27 -0
  84. data/package/environments/__tests__/base.js +69 -0
  85. data/package/environments/base.js +116 -0
  86. data/package/environments/development.js +55 -0
  87. data/package/environments/production.js +79 -0
  88. data/package/environments/test.js +3 -0
  89. data/package/index.js +33 -0
  90. data/package/inliningCss.js +7 -0
  91. data/package/rules/babel.js +30 -0
  92. data/package/rules/coffee.js +6 -0
  93. data/package/rules/css.js +3 -0
  94. data/package/rules/erb.js +15 -0
  95. data/package/rules/file.js +23 -0
  96. data/package/rules/index.js +18 -0
  97. data/package/rules/less.js +22 -0
  98. data/package/rules/raw.js +5 -0
  99. data/package/rules/sass.js +16 -0
  100. data/package/rules/stylus.js +26 -0
  101. data/package/utils/get_style_rule.js +37 -0
  102. data/package/utils/helpers.js +51 -0
  103. data/package.json +71 -0
  104. data/rakelib/release.rake +57 -0
  105. data/test/command_test.rb +109 -0
  106. data/test/compiler_test.rb +68 -0
  107. data/test/configuration_test.rb +78 -0
  108. data/test/dev_server_runner_test.rb +81 -0
  109. data/test/dev_server_test.rb +47 -0
  110. data/test/engine_rake_tasks_test.rb +39 -0
  111. data/test/env_test.rb +23 -0
  112. data/test/helper_test.rb +159 -0
  113. data/test/manifest_test.rb +89 -0
  114. data/test/mounted_app/Rakefile +4 -0
  115. data/test/mounted_app/test/dummy/Rakefile +3 -0
  116. data/test/mounted_app/test/dummy/bin/rails +3 -0
  117. data/test/mounted_app/test/dummy/bin/rake +3 -0
  118. data/test/mounted_app/test/dummy/config/application.rb +10 -0
  119. data/test/mounted_app/test/dummy/config/environment.rb +3 -0
  120. data/test/mounted_app/test/dummy/config/webpacker.yml +75 -0
  121. data/test/mounted_app/test/dummy/config.ru +5 -0
  122. data/test/mounted_app/test/dummy/package.json +7 -0
  123. data/test/rake_tasks_test.rb +71 -0
  124. data/test/test_app/Rakefile +3 -0
  125. data/test/test_app/app/packs/entrypoints/application.js +10 -0
  126. data/test/test_app/app/packs/entrypoints/multi_entry.css +4 -0
  127. data/test/test_app/app/packs/entrypoints/multi_entry.js +4 -0
  128. data/test/test_app/bin/webpacker +14 -0
  129. data/test/test_app/bin/webpacker-dev-server +14 -0
  130. data/test/test_app/config/application.rb +11 -0
  131. data/test/test_app/config/environment.rb +4 -0
  132. data/test/test_app/config/initializers/inspect_autoload_paths.rb +1 -0
  133. data/test/test_app/config/webpack/webpack.config.js +0 -0
  134. data/test/test_app/config/webpacker.yml +77 -0
  135. data/test/test_app/config/webpacker_other_location.yml +79 -0
  136. data/test/test_app/config/webpacker_public_root.yml +18 -0
  137. data/test/test_app/config.ru +5 -0
  138. data/test/test_app/package.json +13 -0
  139. data/test/test_app/public/packs/manifest.json +50 -0
  140. data/test/test_app/some.config.js +0 -0
  141. data/test/test_app/yarn.lock +11 -0
  142. data/test/test_helper.rb +33 -0
  143. data/test/webpack_runner_test.rb +57 -0
  144. data/test/webpacker_test.rb +34 -0
  145. data/webpacker.gemspec +31 -0
  146. data/yarn.lock +4029 -0
  147. metadata +331 -0
@@ -0,0 +1,58 @@
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 and RAILS_ENV set to development', () => {
12
+ process.env.RAILS_ENV = 'development'
13
+ process.env.NODE_ENV = 'development'
14
+ expect(require('../env')).toEqual({
15
+ railsEnv: 'development',
16
+ nodeEnv: 'development',
17
+ isProduction: false,
18
+ isDevelopment: true,
19
+ runningWebpackDevServer: false
20
+ })
21
+ })
22
+
23
+ test('with undefined NODE_ENV and RAILS_ENV set to development', () => {
24
+ process.env.RAILS_ENV = 'development'
25
+ delete process.env.NODE_ENV
26
+ expect(require('../env')).toEqual({
27
+ railsEnv: 'development',
28
+ nodeEnv: 'production',
29
+ isProduction: true,
30
+ isDevelopment: false,
31
+ runningWebpackDevServer: false
32
+ })
33
+ })
34
+
35
+ test('with undefined NODE_ENV and RAILS_ENV', () => {
36
+ delete process.env.NODE_ENV
37
+ delete process.env.RAILS_ENV
38
+ expect(require('../env')).toEqual({
39
+ railsEnv: 'production',
40
+ nodeEnv: 'production',
41
+ isProduction: true,
42
+ isDevelopment: false,
43
+ runningWebpackDevServer: false
44
+ })
45
+ })
46
+
47
+ test('with a non-standard environment', () => {
48
+ process.env.RAILS_ENV = 'staging'
49
+ process.env.NODE_ENV = 'staging'
50
+ expect(require('../env')).toEqual({
51
+ railsEnv: 'staging',
52
+ nodeEnv: 'production',
53
+ isProduction: true,
54
+ isDevelopment: false,
55
+ runningWebpackDevServer: false
56
+ })
57
+ })
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
+ })
@@ -0,0 +1,29 @@
1
+ /* test expect, describe, afterAll, beforeEach */
2
+
3
+ const { resolve } = require('path')
4
+ const { chdirTestApp, chdirCwd } = require('../utils/helpers')
5
+
6
+ chdirTestApp()
7
+
8
+ describe('Production environment', () => {
9
+ afterAll(chdirCwd)
10
+
11
+ describe('webpackConfig', () => {
12
+ beforeEach(() => jest.resetModules())
13
+
14
+ test('should use production config and environment', () => {
15
+ process.env.RAILS_ENV = 'production'
16
+ process.env.NODE_ENV = 'production'
17
+
18
+ const { webpackConfig } = require('../index')
19
+
20
+ expect(webpackConfig.output.path).toEqual(resolve('public', 'packs'))
21
+ expect(webpackConfig.output.publicPath).toEqual('/packs/')
22
+
23
+ expect(webpackConfig).toMatchObject({
24
+ devtool: 'source-map',
25
+ stats: 'normal'
26
+ })
27
+ })
28
+ })
29
+ })
@@ -0,0 +1,30 @@
1
+ /* test expect, describe, afterAll, beforeEach */
2
+
3
+ const { resolve } = require('path')
4
+ const { chdirTestApp, chdirCwd } = require('../utils/helpers')
5
+
6
+ chdirTestApp()
7
+
8
+ describe('Custom environment', () => {
9
+ afterAll(chdirCwd)
10
+
11
+ describe('webpackConfig', () => {
12
+ beforeEach(() => jest.resetModules())
13
+
14
+ test('should use staging config and default production environment', () => {
15
+ process.env.RAILS_ENV = 'staging'
16
+ delete process.env.NODE_ENV
17
+
18
+ const { webpackConfig } = require('../index')
19
+
20
+ expect(webpackConfig.output.path).toEqual(
21
+ resolve('public', 'packs-staging')
22
+ )
23
+ expect(webpackConfig.output.publicPath).toEqual('/packs-staging/')
24
+ expect(webpackConfig).toMatchObject({
25
+ devtool: 'source-map',
26
+ stats: 'normal'
27
+ })
28
+ })
29
+ })
30
+ })
@@ -0,0 +1,25 @@
1
+ /* test expect, describe, afterAll, beforeEach */
2
+
3
+ const { resolve } = require('path')
4
+ const { chdirTestApp, chdirCwd } = require('../utils/helpers')
5
+
6
+ chdirTestApp()
7
+
8
+ describe('Test environment', () => {
9
+ afterAll(chdirCwd)
10
+
11
+ describe('toWebpackConfig', () => {
12
+ beforeEach(() => jest.resetModules())
13
+
14
+ test('should use test config and production environment', () => {
15
+ process.env.RAILS_ENV = 'test'
16
+ process.env.NODE_ENV = 'test'
17
+
18
+ const { webpackConfig } = require('../index')
19
+
20
+ expect(webpackConfig.output.path).toEqual(resolve('public', 'packs-test'))
21
+ expect(webpackConfig.output.publicPath).toEqual('/packs-test/')
22
+ expect(webpackConfig.devServer).toEqual(undefined)
23
+ })
24
+ })
25
+ })
@@ -0,0 +1,41 @@
1
+ const { moduleExists } = require('@shakacode/shakapacker')
2
+
3
+ module.exports = function config(api) {
4
+ const validEnv = ['development', 'test', 'production']
5
+ const currentEnv = api.env()
6
+ const isDevelopmentEnv = api.env('development')
7
+ const isProductionEnv = api.env('production')
8
+ const isTestEnv = api.env('test')
9
+
10
+ if (!validEnv.includes(currentEnv)) {
11
+ throw new Error(
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
+ )}".`
15
+ )
16
+ }
17
+
18
+ return {
19
+ presets: [
20
+ isTestEnv && ['@babel/preset-env', { targets: { node: 'current' } }],
21
+ (isProductionEnv || isDevelopmentEnv) && [
22
+ '@babel/preset-env',
23
+ {
24
+ useBuiltIns: 'entry',
25
+ corejs: '3.8',
26
+ modules: 'auto',
27
+ bugfixes: true,
28
+ loose: true,
29
+ exclude: ['transform-typeof-symbol']
30
+ }
31
+ ],
32
+ moduleExists('@babel/preset-typescript') && [
33
+ '@babel/preset-typescript',
34
+ { allExtensions: true, isTSX: true }
35
+ ]
36
+ ].filter(Boolean),
37
+ plugins: [
38
+ ['@babel/plugin-transform-runtime', { helpers: false }]
39
+ ].filter(Boolean)
40
+ }
41
+ }
data/package/config.js ADDED
@@ -0,0 +1,32 @@
1
+ const { resolve } = require('path')
2
+ const { load } = require('js-yaml')
3
+ const { readFileSync } = require('fs')
4
+ const { merge } = require('webpack-merge')
5
+ const { ensureTrailingSlash } = require('./utils/helpers')
6
+ const { railsEnv } = require('./env')
7
+ const configPath = require('./configPath')
8
+
9
+ const defaultConfigPath = require.resolve('../lib/install/config/webpacker.yml')
10
+
11
+ const getDefaultConfig = () => {
12
+ const defaultConfig = load(readFileSync(defaultConfigPath), 'utf8')
13
+ return defaultConfig[railsEnv] || defaultConfig.production
14
+ }
15
+
16
+ const defaults = getDefaultConfig()
17
+ const app = load(readFileSync(configPath), 'utf8')[railsEnv]
18
+
19
+ const config = merge(defaults, app)
20
+ config.outputPath = resolve(config.public_root_path, config.public_output_path)
21
+
22
+ // Ensure that the publicPath includes our asset host so dynamic imports
23
+ // (code-splitting chunks and static assets) load from the CDN instead of a relative path.
24
+ const getPublicPath = () => {
25
+ const rootUrl = ensureTrailingSlash(process.env.WEBPACKER_ASSET_HOST || '/')
26
+ return `${rootUrl}${config.public_output_path}/`
27
+ }
28
+
29
+ config.publicPath = getPublicPath()
30
+ config.publicPathWithoutCDN = `/${config.public_output_path}/`
31
+
32
+ module.exports = config
@@ -0,0 +1,3 @@
1
+ const { resolve } = require('path')
2
+
3
+ module.exports = process.env.WEBPACKER_CONFIG || resolve('config', 'webpacker.yml')
@@ -0,0 +1,20 @@
1
+ const { isBoolean } = 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 devServerConfig = config.dev_server
10
+
11
+ if (devServerConfig) {
12
+ const envPrefix = config.dev_server.env_prefix || 'WEBPACKER_DEV_SERVER'
13
+
14
+ Object.keys(devServerConfig).forEach((key) => {
15
+ const envValue = fetch(`${envPrefix}_${key.toUpperCase()}`)
16
+ if (envValue !== undefined) devServerConfig[key] = envValue
17
+ })
18
+ }
19
+
20
+ module.exports = devServerConfig || {}
data/package/env.js ADDED
@@ -0,0 +1,27 @@
1
+ const { load } = require('js-yaml')
2
+ const { readFileSync } = require('fs')
3
+
4
+ const NODE_ENVIRONMENTS = ['development', 'production', 'test']
5
+ const DEFAULT = 'production'
6
+ const configPath = require('./configPath')
7
+
8
+ const railsEnv = process.env.RAILS_ENV
9
+ const rawNodeEnv = process.env.NODE_ENV
10
+ const nodeEnv
11
+ = rawNodeEnv && NODE_ENVIRONMENTS.includes(rawNodeEnv) ? rawNodeEnv : DEFAULT
12
+ const isProduction = nodeEnv === 'production'
13
+ const isDevelopment = nodeEnv === 'development'
14
+
15
+ const config = load(readFileSync(configPath), 'utf8')
16
+ const availableEnvironments = Object.keys(config).join('|')
17
+ const regex = new RegExp(`^(${availableEnvironments})$`, 'g')
18
+
19
+ const runningWebpackDevServer = process.env.WEBPACK_SERVE === 'true'
20
+
21
+ module.exports = {
22
+ railsEnv: railsEnv && railsEnv.match(regex) ? railsEnv : DEFAULT,
23
+ nodeEnv,
24
+ isProduction,
25
+ isDevelopment,
26
+ runningWebpackDevServer
27
+ }
@@ -0,0 +1,69 @@
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 { chdirTestApp, chdirCwd } = require('../../utils/helpers')
7
+
8
+ chdirTestApp()
9
+
10
+ const { resolve } = require('path')
11
+ const rules = require('../../rules')
12
+ const baseConfig = require('../base')
13
+
14
+ describe('Base config', () => {
15
+ afterAll(chdirCwd)
16
+
17
+ describe('config', () => {
18
+ test('should return entry', () => {
19
+ expect(baseConfig.entry.application).toEqual(
20
+ resolve('app', 'packs', 'entrypoints', 'application.js')
21
+ )
22
+ })
23
+
24
+ test('should return multi file entry points', () => {
25
+ expect(baseConfig.entry.multi_entry.sort()).toEqual([
26
+ resolve('app', 'packs', 'entrypoints', 'multi_entry.css'),
27
+ resolve('app', 'packs', 'entrypoints', 'multi_entry.js')
28
+ ])
29
+ })
30
+
31
+ test('should return output', () => {
32
+ expect(baseConfig.output.filename).toEqual('js/[name].js')
33
+ expect(baseConfig.output.chunkFilename).toEqual(
34
+ 'js/[name].chunk.js'
35
+ )
36
+ })
37
+
38
+ test('should return default loader rules for each file in config/loaders', () => {
39
+ const defaultRules = Object.keys(rules)
40
+ const configRules = baseConfig.module.rules
41
+
42
+ expect(defaultRules.length).toEqual(3)
43
+ expect(configRules.length).toEqual(3)
44
+ })
45
+
46
+ test('should return default plugins', () => {
47
+ expect(baseConfig.plugins.length).toEqual(2)
48
+ })
49
+
50
+ test('should return default resolveLoader', () => {
51
+ expect(baseConfig.resolveLoader.modules).toEqual(['node_modules'])
52
+ })
53
+
54
+ test('should return default resolve.modules with additions', () => {
55
+ expect(baseConfig.resolve.modules).toEqual([
56
+ resolve('app', 'packs'),
57
+ resolve('app/assets'),
58
+ resolve('/etc/yarn'),
59
+ resolve('some.config.js'),
60
+ resolve('app/elm'),
61
+ 'node_modules'
62
+ ])
63
+ })
64
+
65
+ test('returns plugins property as Array', () => {
66
+ expect(baseConfig.plugins).toBeInstanceOf(Array)
67
+ })
68
+ })
69
+ })
@@ -0,0 +1,116 @@
1
+ /* eslint global-require: 0 */
2
+ /* eslint import/no-dynamic-require: 0 */
3
+
4
+ const { basename, dirname, join, relative, resolve } = require('path')
5
+ const extname = require('path-complete-extname')
6
+ const PnpWebpackPlugin = require('pnp-webpack-plugin')
7
+ const { sync: globSync } = require('glob')
8
+ const WebpackAssetsManifest = require('webpack-assets-manifest')
9
+ const webpack = require('webpack')
10
+ const rules = require('../rules')
11
+ const { isProduction } = require('../env')
12
+ const config = require('../config')
13
+ const { moduleExists } = require('../utils/helpers')
14
+
15
+ const getEntryObject = () => {
16
+ const entries = {}
17
+ const rootPath = join(config.source_path, config.source_entry_path)
18
+
19
+ globSync(`${rootPath}/*.*`).forEach((path) => {
20
+ const namespace = relative(join(rootPath), dirname(path))
21
+ const name = join(namespace, basename(path, extname(path)))
22
+ let assetPaths = resolve(path)
23
+
24
+ // Allows for multiple filetypes per entry (https://webpack.js.org/guides/entry-advanced/)
25
+ // Transforms the config object value to an array with all values under the same name
26
+ let previousPaths = entries[name]
27
+ if (previousPaths) {
28
+ previousPaths = Array.isArray(previousPaths)
29
+ ? previousPaths
30
+ : [previousPaths]
31
+ previousPaths.push(assetPaths)
32
+ assetPaths = previousPaths
33
+ }
34
+
35
+ entries[name] = assetPaths
36
+ })
37
+
38
+ return entries
39
+ }
40
+
41
+ const getModulePaths = () => {
42
+ const result = [resolve(config.source_path)]
43
+
44
+ if (config.additional_paths) {
45
+ config.additional_paths.forEach((path) => result.push(resolve(path)))
46
+ }
47
+ result.push('node_modules')
48
+
49
+ return result
50
+ }
51
+
52
+ const getPlugins = () => {
53
+ const plugins = [
54
+ new webpack.EnvironmentPlugin(process.env),
55
+ new WebpackAssetsManifest({
56
+ entrypoints: true,
57
+ writeToDisk: true,
58
+ output: 'manifest.json',
59
+ entrypointsUseAssets: true,
60
+ publicPath: true
61
+ })
62
+ ]
63
+
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
+ )
73
+ }
74
+
75
+ return plugins
76
+ }
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]' : ''
81
+ module.exports = {
82
+ mode: 'production',
83
+ output: {
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',
89
+ path: config.outputPath,
90
+ publicPath: config.publicPath
91
+ },
92
+ entry: getEntryObject(),
93
+ resolve: {
94
+ extensions: ['.js', '.jsx', '.mjs', '.ts', '.tsx', '.coffee'],
95
+ modules: getModulePaths(),
96
+ plugins: [PnpWebpackPlugin]
97
+ },
98
+
99
+ plugins: getPlugins(),
100
+
101
+ resolveLoader: {
102
+ modules: ['node_modules'],
103
+ plugins: [PnpWebpackPlugin.moduleLoader(module)]
104
+ },
105
+
106
+ optimization: {
107
+ splitChunks: { chunks: 'all' },
108
+
109
+ runtimeChunk: 'single'
110
+ },
111
+
112
+ module: {
113
+ strictExportPresence: true,
114
+ rules
115
+ }
116
+ }
@@ -0,0 +1,55 @@
1
+ const { merge } = require('webpack-merge')
2
+
3
+ const baseConfig = require('./base')
4
+ const devServer = require('../dev_server')
5
+ const { runningWebpackDevServer } = require('../env')
6
+
7
+ const { outputPath: contentBase, publicPath } = require('../config')
8
+
9
+ let devConfig = {
10
+ mode: 'development',
11
+ devtool: 'cheap-module-source-map'
12
+ }
13
+
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
41
+ }
42
+
43
+ devConfig = merge(devConfig, {
44
+ stats: {
45
+ colors: true,
46
+ entrypoints: false,
47
+ errorDetails: true,
48
+ modules: false,
49
+ moduleTrace: false
50
+ },
51
+ devServer: devServerConfig
52
+ })
53
+ }
54
+
55
+ module.exports = merge(baseConfig, devConfig)
@@ -0,0 +1,79 @@
1
+ /* eslint global-require: 0 */
2
+ /* eslint import/no-dynamic-require: 0 */
3
+
4
+ const { merge } = require('webpack-merge')
5
+ const CompressionPlugin = require('compression-webpack-plugin')
6
+ const TerserPlugin = require('terser-webpack-plugin')
7
+ const baseConfig = require('./base')
8
+ const { moduleExists } = require('../utils/helpers')
9
+
10
+ const getPlugins = () => {
11
+ const plugins = []
12
+
13
+ plugins.push(
14
+ new CompressionPlugin({
15
+ filename: '[path][base].gz[query]',
16
+ algorithm: 'gzip',
17
+ test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
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
+ )
29
+ }
30
+
31
+ return plugins
32
+ }
33
+
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()
41
+ }
42
+
43
+ return null
44
+ }
45
+
46
+ const productionConfig = {
47
+ devtool: 'source-map',
48
+ stats: 'normal',
49
+ bail: true,
50
+ plugins: getPlugins(),
51
+ optimization: {
52
+ minimizer: [
53
+ tryCssMinimizer(),
54
+ new TerserPlugin({
55
+ parallel: Number.parseInt(process.env.WEBPACKER_PARALLEL, 10) || true,
56
+ terserOptions: {
57
+ parse: {
58
+ // Let terser parse ecma 8 code but always output
59
+ // ES5 compliant code for older browsers
60
+ ecma: 8
61
+ },
62
+ compress: {
63
+ ecma: 5,
64
+ warnings: false,
65
+ comparisons: false
66
+ },
67
+ mangle: { safari10: true },
68
+ output: {
69
+ ecma: 5,
70
+ comments: false,
71
+ ascii_only: true
72
+ }
73
+ }
74
+ })
75
+ ].filter(Boolean)
76
+ }
77
+ }
78
+
79
+ module.exports = merge(baseConfig, productionConfig)
@@ -0,0 +1,3 @@
1
+ const baseConfig = require('./base')
2
+
3
+ module.exports = baseConfig
data/package/index.js ADDED
@@ -0,0 +1,33 @@
1
+ /* eslint global-require: 0 */
2
+ /* eslint import/no-dynamic-require: 0 */
3
+
4
+ const webpackMerge = require('webpack-merge')
5
+ const { resolve } = require('path')
6
+ const { existsSync } = require('fs')
7
+ const baseConfig = require('./environments/base')
8
+ const rules = require('./rules')
9
+ const config = require('./config')
10
+ const devServer = require('./dev_server')
11
+ const env = require('./env')
12
+ const { moduleExists, canProcess } = require('./utils/helpers')
13
+ const inliningCss = require('./inliningCss')
14
+
15
+ const webpackConfig = () => {
16
+ const { nodeEnv } = env
17
+ const path = resolve(__dirname, 'environments', `${nodeEnv}.js`)
18
+ const environmentConfig = existsSync(path) ? require(path) : baseConfig
19
+ return environmentConfig
20
+ }
21
+
22
+ module.exports = {
23
+ config,
24
+ devServer,
25
+ webpackConfig: webpackConfig(),
26
+ baseConfig,
27
+ env,
28
+ rules,
29
+ moduleExists,
30
+ canProcess,
31
+ inliningCss,
32
+ ...webpackMerge
33
+ }
@@ -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
@@ -0,0 +1,30 @@
1
+ const { resolve } = require('path')
2
+ const { realpathSync } = require('fs')
3
+
4
+ const {
5
+ source_path: sourcePath,
6
+ additional_paths: additionalPaths
7
+ } = require('../config')
8
+ const { isProduction } = require('../env')
9
+
10
+ module.exports = {
11
+ test: /\.(js|jsx|mjs|ts|tsx|coffee)?(\.erb)?$/,
12
+ include: [sourcePath, ...additionalPaths].map((p) => {
13
+ try {
14
+ return realpathSync(p)
15
+ } catch (e) {
16
+ return resolve(p)
17
+ }
18
+ }),
19
+ exclude: /node_modules/,
20
+ use: [
21
+ {
22
+ loader: require.resolve('babel-loader'),
23
+ options: {
24
+ cacheDirectory: true,
25
+ cacheCompression: isProduction,
26
+ compact: isProduction
27
+ }
28
+ }
29
+ ]
30
+ }