webpacker 6.0.0.beta.7 → 6.0.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/jest.yml +1 -1
  3. data/.github/workflows/js-lint.yml +1 -1
  4. data/.github/workflows/ruby.yml +6 -9
  5. data/.rubocop.yml +0 -105
  6. data/CHANGELOG.md +6 -22
  7. data/CONTRIBUTING.md +1 -1
  8. data/Gemfile.lock +90 -93
  9. data/README.md +110 -308
  10. data/docs/assets.md +135 -0
  11. data/docs/cloud9.md +310 -0
  12. data/docs/css.md +303 -0
  13. data/docs/deployment.md +29 -9
  14. data/docs/docker.md +68 -0
  15. data/docs/engines.md +213 -0
  16. data/docs/env.md +68 -0
  17. data/docs/es6.md +72 -0
  18. data/docs/folder-structure.md +66 -0
  19. data/docs/integrations.md +220 -0
  20. data/docs/misc.md +23 -0
  21. data/docs/props.md +187 -0
  22. data/docs/react.md +183 -0
  23. data/docs/target.md +22 -0
  24. data/docs/testing.md +147 -0
  25. data/docs/troubleshooting.md +3 -5
  26. data/docs/typescript.md +190 -0
  27. data/docs/v4-upgrade.md +142 -0
  28. data/docs/webpack-dev-server.md +94 -0
  29. data/docs/webpack.md +315 -0
  30. data/docs/yarn.md +23 -0
  31. data/lib/install/config/webpacker.yml +3 -5
  32. data/lib/install/examples/vue3/app.vue +27 -0
  33. data/lib/install/examples/vue3/hello_vue.js +15 -0
  34. data/lib/install/javascript/packs/application.css +9 -0
  35. data/lib/install/{packs/entrypoints → javascript/packs}/application.js +2 -4
  36. data/lib/install/template.rb +9 -16
  37. data/lib/tasks/webpacker/binstubs.rake +2 -2
  38. data/lib/tasks/webpacker/check_node.rake +0 -1
  39. data/lib/tasks/webpacker/check_yarn.rake +0 -1
  40. data/lib/tasks/webpacker/install.rake +2 -2
  41. data/lib/webpacker/commands.rb +1 -2
  42. data/lib/webpacker/compiler.rb +3 -9
  43. data/lib/webpacker/configuration.rb +4 -4
  44. data/lib/webpacker/dev_server_runner.rb +0 -2
  45. data/lib/webpacker/helper.rb +43 -13
  46. data/lib/webpacker/manifest.rb +1 -1
  47. data/lib/webpacker/version.rb +1 -1
  48. data/lib/webpacker/webpack_runner.rb +0 -1
  49. data/package.json +1 -1
  50. data/package/__tests__/development.js +1 -2
  51. data/package/babel/preset-react.js +62 -0
  52. data/package/babel/preset.js +13 -24
  53. data/package/environments/__tests__/base.js +5 -5
  54. data/package/environments/base.js +20 -15
  55. data/package/environments/development.js +0 -1
  56. data/package/environments/production.js +30 -28
  57. data/package/index.js +2 -7
  58. data/package/rules/babel.js +1 -1
  59. data/package/rules/coffee.js +5 -5
  60. data/package/rules/erb.js +3 -5
  61. data/package/rules/file.js +3 -5
  62. data/package/rules/index.js +17 -9
  63. data/package/rules/less.js +10 -14
  64. data/package/rules/sass.js +9 -13
  65. data/package/rules/svg.js +23 -0
  66. data/package/utils/get_style_rule.js +31 -27
  67. data/package/utils/helpers.js +0 -25
  68. data/test/configuration_test.rb +2 -2
  69. data/test/dev_server_runner_test.rb +2 -10
  70. data/test/helper_test.rb +39 -33
  71. data/test/manifest_test.rb +0 -8
  72. data/test/mounted_app/test/dummy/config/webpacker.yml +3 -3
  73. data/test/test_app/app/{packs/entrypoints → javascript/packs}/application.js +1 -1
  74. data/test/test_app/app/{packs/entrypoints → javascript/packs}/multi_entry.css +0 -0
  75. data/test/test_app/app/{packs/entrypoints → javascript/packs}/multi_entry.js +0 -0
  76. data/test/test_app/config/webpacker.yml +3 -3
  77. data/test/test_app/public/packs/manifest.json +0 -7
  78. metadata +36 -18
  79. data/config/README.md +0 -3
  80. data/config/webpacker.yml +0 -1
  81. data/docs/v6_upgrade.md +0 -86
  82. data/package/__tests__/index.js +0 -9
  83. data/package/rules/raw.js +0 -5
  84. data/package/rules/stylus.js +0 -26
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rails/webpacker",
3
- "version": "6.0.0-beta.7",
3
+ "version": "6.0.0-pre.1",
4
4
  "description": "Use webpack to manage app-like JavaScript modules in Rails",
5
5
  "main": "package/index.js",
6
6
  "files": [
@@ -22,8 +22,7 @@ describe('Development environment', () => {
22
22
  expect(webpackConfig).toMatchObject({
23
23
  devServer: {
24
24
  host: 'localhost',
25
- port: 3035,
26
- injectClient: true
25
+ port: 3035
27
26
  }
28
27
  })
29
28
  })
@@ -0,0 +1,62 @@
1
+ module.exports = function config(api) {
2
+ const validEnv = ['development', 'test', 'production']
3
+ const currentEnv = api.env()
4
+ const isDevelopmentEnv = api.env('development')
5
+ const isProductionEnv = api.env('production')
6
+ const isTestEnv = api.env('test')
7
+
8
+ if (!validEnv.includes(currentEnv)) {
9
+ 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)}".`
11
+ )
12
+ }
13
+
14
+ return {
15
+ presets: [
16
+ isTestEnv && [
17
+ '@babel/preset-env',
18
+ {
19
+ targets: { node: 'current' },
20
+ modules: 'commonjs'
21
+ }
22
+ ],
23
+ (isProductionEnv || isDevelopmentEnv) && [
24
+ '@babel/preset-env',
25
+ {
26
+ useBuiltIns: 'entry',
27
+ corejs: '3.8',
28
+ modules: false,
29
+ bugfixes: true,
30
+ loose: true,
31
+ exclude: ['transform-typeof-symbol']
32
+ }
33
+ ],
34
+ [
35
+ '@babel/preset-react',
36
+ {
37
+ development: isDevelopmentEnv || isTestEnv,
38
+ useBuiltIns: true
39
+ }
40
+ ]
41
+ ].filter(Boolean),
42
+ plugins: [
43
+ 'babel-plugin-macros',
44
+ [
45
+ '@babel/plugin-proposal-class-properties',
46
+ { loose: true }
47
+ ],
48
+ [
49
+ '@babel/plugin-transform-runtime',
50
+ {
51
+ helpers: false,
52
+ regenerator: true,
53
+ corejs: false
54
+ }
55
+ ],
56
+ isProductionEnv && [
57
+ 'babel-plugin-transform-react-remove-prop-types',
58
+ { removeImport: true }
59
+ ]
60
+ ].filter(Boolean)
61
+ }
62
+ }
@@ -1,5 +1,3 @@
1
- const { moduleExists } = require('@rails/webpacker')
2
-
3
1
  module.exports = function config(api) {
4
2
  const validEnv = ['development', 'test', 'production']
5
3
  const currentEnv = api.env()
@@ -9,15 +7,16 @@ module.exports = function config(api) {
9
7
 
10
8
  if (!validEnv.includes(currentEnv)) {
11
9
  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
- )}".`
10
+ `Please specify a valid NODE_ENV or BABEL_ENV environment variable. Valid values are "development", "test", and "production". Instead, received: "${JSON.stringify(currentEnv)}".`
15
11
  )
16
12
  }
17
13
 
18
14
  return {
19
15
  presets: [
20
- isTestEnv && ['@babel/preset-env', { targets: { node: 'current' } }],
16
+ isTestEnv && [
17
+ '@babel/preset-env',
18
+ { targets: { node: 'current' } }
19
+ ],
21
20
  (isProductionEnv || isDevelopmentEnv) && [
22
21
  '@babel/preset-env',
23
22
  {
@@ -28,28 +27,18 @@ module.exports = function config(api) {
28
27
  loose: true,
29
28
  exclude: ['transform-typeof-symbol']
30
29
  }
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
- }
42
30
  ]
43
31
  ].filter(Boolean),
44
32
  plugins: [
45
33
  'babel-plugin-macros',
46
- ['@babel/plugin-proposal-class-properties', { loose: true }],
47
- ['@babel/plugin-transform-runtime', { helpers: false }],
48
- isProductionEnv &&
49
- moduleExists('babel-plugin-transform-react-remove-prop-types') && [
50
- 'babel-plugin-transform-react-remove-prop-types',
51
- { removeImport: true }
52
- ]
34
+ [
35
+ '@babel/plugin-proposal-class-properties',
36
+ { loose: true }
37
+ ],
38
+ [
39
+ '@babel/plugin-transform-runtime',
40
+ { helpers: false }
41
+ ]
53
42
  ].filter(Boolean)
54
43
  }
55
44
  }
@@ -17,14 +17,14 @@ describe('Base config', () => {
17
17
  describe('config', () => {
18
18
  test('should return entry', () => {
19
19
  expect(baseConfig.entry.application).toEqual(
20
- resolve('app', 'packs', 'entrypoints', 'application.js')
20
+ resolve('app', 'javascript', 'packs', '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', 'packs', 'entrypoints', 'multi_entry.css'),
27
- resolve('app', 'packs', 'entrypoints', 'multi_entry.js')
26
+ resolve('app', 'javascript', 'packs', 'multi_entry.css'),
27
+ resolve('app', 'javascript', 'packs', 'multi_entry.js')
28
28
  ])
29
29
  })
30
30
 
@@ -44,7 +44,7 @@ describe('Base config', () => {
44
44
  })
45
45
 
46
46
  test('should return default plugins', () => {
47
- expect(baseConfig.plugins.length).toEqual(3)
47
+ expect(baseConfig.plugins.length).toEqual(4)
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', 'packs'),
56
+ resolve('app', 'javascript'),
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: globSync } = require('glob')
7
+ const { sync } = require('glob')
8
8
  const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
9
9
  const WebpackAssetsManifest = require('webpack-assets-manifest')
10
10
  const webpack = require('webpack')
11
11
  const rules = require('../rules')
12
12
  const config = require('../config')
13
- const { moduleExists } = require('../utils/helpers')
13
+ const { isDevelopment } = require('../env')
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
- globSync(`${rootPath}/**/*.*`).forEach((path) => {
19
+ sync(`${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,6 +52,7 @@ const getModulePaths = () => {
52
52
  const getPlugins = () => {
53
53
  const plugins = [
54
54
  new webpack.EnvironmentPlugin(process.env),
55
+ PnpWebpackPlugin,
55
56
  new CaseSensitivePathsPlugin(),
56
57
  new WebpackAssetsManifest({
57
58
  entrypoints: true,
@@ -62,14 +63,18 @@ const getPlugins = () => {
62
63
  })
63
64
  ]
64
65
 
65
- if (moduleExists('css-loader') && moduleExists('mini-css-extract-plugin')) {
66
- const MiniCssExtractPlugin = require('mini-css-extract-plugin')
67
- plugins.push(
68
- new MiniCssExtractPlugin({
69
- filename: 'css/[name]-[contenthash:8].css',
70
- chunkFilename: 'css/[id]-[contenthash:8].css'
71
- })
72
- )
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 */
73
78
  }
74
79
 
75
80
  return plugins
@@ -81,14 +86,14 @@ module.exports = {
81
86
  filename: 'js/[name]-[contenthash].js',
82
87
  chunkFilename: 'js/[name]-[contenthash].chunk.js',
83
88
  hotUpdateChunkFilename: 'js/[id]-[hash].hot-update.js',
89
+ assetModuleFilename: 'static/[hash][ext][query]',
84
90
  path: config.outputPath,
85
91
  publicPath: config.publicPath
86
92
  },
87
93
  entry: getEntryObject(),
88
94
  resolve: {
89
- extensions: ['.js', '.jsx', '.mjs', '.ts', '.tsx', '.coffee'],
90
- modules: getModulePaths(),
91
- plugins: [PnpWebpackPlugin]
95
+ extensions: ['.js', '.mjs', '.ts'],
96
+ modules: getModulePaths()
92
97
  },
93
98
 
94
99
  plugins: getPlugins(),
@@ -101,7 +106,7 @@ module.exports = {
101
106
  optimization: {
102
107
  splitChunks: { chunks: 'all' },
103
108
 
104
- runtimeChunk: 'single'
109
+ runtimeChunk: { name: (entrypoint) => `runtime-${entrypoint.name}` }
105
110
  },
106
111
 
107
112
  module: {
@@ -34,7 +34,6 @@ if (
34
34
  hot: devServer.hmr,
35
35
  contentBase,
36
36
  inline: devServer.inline,
37
- injectClient: devServer.inject_client,
38
37
  useLocalIp: devServer.use_local_ip,
39
38
  public: devServer.public,
40
39
  publicPath,
@@ -5,42 +5,45 @@ 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')
9
8
 
10
9
  const getPlugins = () => {
11
- const plugins = []
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
+ })
12
15
 
13
- plugins.push(
14
- new CompressionPlugin({
15
- filename: '[path][base].gz[query]',
16
- algorithm: 'gzip',
16
+ if ('brotli' in process.versions) {
17
+ compressionPlugin = new CompressionPlugin({
18
+ filename: '[path].br[query]',
19
+ algorithm: 'brotliCompress',
17
20
  test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
18
21
  })
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
22
  }
30
23
 
31
- return plugins
32
- }
24
+ const plugins = [compressionPlugin]
33
25
 
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()
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 */
41
44
  }
42
45
 
43
- return null
46
+ return plugins
44
47
  }
45
48
 
46
49
  const productionConfig = {
@@ -50,7 +53,6 @@ const productionConfig = {
50
53
  plugins: getPlugins(),
51
54
  optimization: {
52
55
  minimizer: [
53
- tryCssMinimizer(),
54
56
  new TerserPlugin({
55
57
  parallel: Number.parseInt(process.env.WEBPACKER_PARALLEL, 10) || true,
56
58
  terserOptions: {
@@ -72,7 +74,7 @@ const productionConfig = {
72
74
  }
73
75
  }
74
76
  })
75
- ].filter(Boolean)
77
+ ]
76
78
  }
77
79
  }
78
80
 
data/package/index.js CHANGED
@@ -1,15 +1,13 @@
1
1
  /* eslint global-require: 0 */
2
2
  /* eslint import/no-dynamic-require: 0 */
3
3
 
4
- const webpackMerge = require('webpack-merge')
5
4
  const { resolve } = require('path')
6
5
  const { existsSync } = require('fs')
7
6
  const baseConfig = require('./environments/base')
8
- const rules = require('./rules')
7
+ const loaders = require('./rules')
9
8
  const config = require('./config')
10
9
  const devServer = require('./dev_server')
11
10
  const { nodeEnv } = require('./env')
12
- const { moduleExists, canProcess } = require('./utils/helpers')
13
11
 
14
12
  const webpackConfig = () => {
15
13
  const path = resolve(__dirname, 'environments', `${nodeEnv}.js`)
@@ -22,8 +20,5 @@ module.exports = {
22
20
  devServer,
23
21
  webpackConfig: webpackConfig(),
24
22
  baseConfig,
25
- rules,
26
- moduleExists,
27
- canProcess,
28
- ...webpackMerge
23
+ loaders
29
24
  }
@@ -8,7 +8,7 @@ const {
8
8
  const { isProduction } = require('../env')
9
9
 
10
10
  module.exports = {
11
- test: /\.(js|jsx|mjs|ts|tsx|coffee)?(\.erb)?$/,
11
+ test: /\.(js|jsx|mjs|ts|tsx)?(\.erb)?$/,
12
12
  include: [sourcePath, ...additionalPaths].map((p) => {
13
13
  try {
14
14
  return realpathSync(p)
@@ -1,6 +1,6 @@
1
- const { canProcess } = require('../utils/helpers')
2
-
3
- module.exports = canProcess('coffee-loader', (resolvedPath) => ({
1
+ module.exports = {
4
2
  test: /\.coffee(\.erb)?$/,
5
- use: [{ loader: resolvedPath }]
6
- }))
3
+ use: [
4
+ { loader: require.resolve('coffee-loader') }
5
+ ]
6
+ }
data/package/rules/erb.js CHANGED
@@ -1,15 +1,13 @@
1
- const { canProcess } = require('../utils/helpers')
2
-
3
1
  const runner = /^win/.test(process.platform) ? 'ruby ' : ''
4
2
 
5
- module.exports = canProcess('rails-erb-loader', (resolvedPath) => ({
3
+ module.exports = {
6
4
  test: /\.erb$/,
7
5
  enforce: 'pre',
8
6
  exclude: /node_modules/,
9
7
  use: [
10
8
  {
11
- loader: resolvedPath,
9
+ loader: require.resolve('rails-erb-loader'),
12
10
  options: { runner: `${runner}bin/rails runner` }
13
11
  }
14
12
  ]
15
- }))
13
+ }
@@ -13,11 +13,9 @@ module.exports = {
13
13
  /\.ttf$/,
14
14
  /\.woff$/,
15
15
  /\.woff2$/,
16
- /\.svg$/
16
+ /\.html$/,
17
+ /\.json$/
17
18
  ],
18
19
  exclude: [/\.(js|mjs|jsx|ts|tsx)$/],
19
- type: 'asset/resource',
20
- generator: {
21
- filename: 'media/images/[hash][ext][query]'
22
- }
20
+ type: 'asset/resource'
23
21
  }