shakapacker 6.0.0.rc.6

Sign up to get free protection for your applications and to get access to all the features.
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
+ }