shakapacker 8.0.2 → 9.2.0
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.
- checksums.yaml +4 -4
- data/.eslintignore +1 -0
- data/.eslintrc.fast.js +40 -0
- data/.eslintrc.js +48 -0
- data/.github/STATUS.md +1 -0
- data/.github/workflows/claude-code-review.yml +54 -0
- data/.github/workflows/claude.yml +50 -0
- data/.github/workflows/dummy.yml +9 -4
- data/.github/workflows/generator.yml +32 -10
- data/.github/workflows/node.yml +23 -1
- data/.github/workflows/ruby.yml +33 -2
- data/.github/workflows/test-bundlers.yml +170 -0
- data/.gitignore +20 -0
- data/.husky/pre-commit +2 -0
- data/.npmignore +56 -0
- data/.prettierignore +3 -0
- data/.rubocop.yml +1 -0
- data/.yalcignore +26 -0
- data/CHANGELOG.md +302 -16
- data/CLAUDE.md +29 -0
- data/CONTRIBUTING.md +138 -20
- data/Gemfile.lock +83 -89
- data/README.md +343 -105
- data/Rakefile +39 -4
- data/TODO.md +50 -0
- data/TODO_v9.md +87 -0
- data/bin/export-bundler-config +11 -0
- data/conductor-setup.sh +70 -0
- data/conductor.json +7 -0
- data/docs/cdn_setup.md +379 -0
- data/docs/common-upgrades.md +615 -0
- data/docs/css-modules-export-mode.md +512 -0
- data/docs/deployment.md +62 -9
- data/docs/optional-peer-dependencies.md +198 -0
- data/docs/peer-dependencies.md +60 -0
- data/docs/react.md +6 -14
- data/docs/releasing.md +197 -0
- data/docs/rspack.md +190 -0
- data/docs/rspack_migration_guide.md +305 -0
- data/docs/subresource_integrity.md +54 -0
- data/docs/transpiler-migration.md +209 -0
- data/docs/transpiler-performance.md +179 -0
- data/docs/troubleshooting.md +157 -22
- data/docs/typescript-migration.md +379 -0
- data/docs/typescript.md +99 -0
- data/docs/using_esbuild_loader.md +3 -3
- data/docs/using_swc_loader.md +112 -10
- data/docs/v6_upgrade.md +10 -0
- data/docs/v8_upgrade.md +3 -5
- data/docs/v9_upgrade.md +458 -0
- data/gemfiles/Gemfile-rails.6.0.x +2 -1
- data/gemfiles/Gemfile-rails.6.1.x +1 -1
- data/gemfiles/Gemfile-rails.7.0.x +2 -2
- data/gemfiles/Gemfile-rails.7.1.x +1 -2
- data/gemfiles/Gemfile-rails.7.2.x +11 -0
- data/gemfiles/Gemfile-rails.8.0.x +11 -0
- data/lib/install/bin/export-bundler-config +11 -0
- data/lib/install/bin/shakapacker +4 -6
- data/lib/install/bin/shakapacker-dev-server +1 -1
- data/lib/install/config/rspack/rspack.config.js +6 -0
- data/lib/install/config/rspack/rspack.config.ts +7 -0
- data/lib/install/config/shakapacker.yml +25 -5
- data/lib/install/config/webpack/webpack.config.ts +7 -0
- data/lib/install/package.json +38 -0
- data/lib/install/template.rb +194 -44
- data/lib/shakapacker/bundler_switcher.rb +329 -0
- data/lib/shakapacker/compiler.rb +2 -1
- data/lib/shakapacker/compiler_strategy.rb +2 -2
- data/lib/shakapacker/configuration.rb +173 -2
- data/lib/shakapacker/dev_server_runner.rb +29 -8
- data/lib/shakapacker/digest_strategy.rb +2 -1
- data/lib/shakapacker/doctor.rb +905 -0
- data/lib/shakapacker/helper.rb +64 -16
- data/lib/shakapacker/manifest.rb +10 -3
- data/lib/shakapacker/mtime_strategy.rb +1 -1
- data/lib/shakapacker/railtie.rb +4 -4
- data/lib/shakapacker/rspack_runner.rb +19 -0
- data/lib/shakapacker/runner.rb +159 -10
- data/lib/shakapacker/swc_migrator.rb +384 -0
- data/lib/shakapacker/utils/manager.rb +15 -2
- data/lib/shakapacker/version.rb +1 -1
- data/lib/shakapacker/version_checker.rb +2 -2
- data/lib/shakapacker/webpack_runner.rb +6 -43
- data/lib/shakapacker.rb +22 -11
- data/lib/tasks/shakapacker/doctor.rake +8 -0
- data/lib/tasks/shakapacker/export_bundler_config.rake +72 -0
- data/lib/tasks/shakapacker/install.rake +12 -2
- data/lib/tasks/shakapacker/migrate_to_swc.rake +13 -0
- data/lib/tasks/shakapacker/switch_bundler.rake +82 -0
- data/lib/tasks/shakapacker.rake +2 -0
- data/package/.npmignore +4 -0
- data/package/babel/preset.ts +56 -0
- data/package/config.ts +175 -0
- data/package/configExporter/cli.ts +683 -0
- data/package/configExporter/configDocs.ts +102 -0
- data/package/configExporter/fileWriter.ts +92 -0
- data/package/configExporter/index.ts +5 -0
- data/package/configExporter/types.ts +36 -0
- data/package/configExporter/yamlSerializer.ts +266 -0
- data/package/{dev_server.js → dev_server.ts} +8 -5
- data/package/env.ts +92 -0
- data/package/environments/__type-tests__/rspack-plugin-compatibility.ts +30 -0
- data/package/environments/{base.js → base.ts} +56 -60
- data/package/environments/development.ts +90 -0
- data/package/environments/production.ts +80 -0
- data/package/environments/test.ts +53 -0
- data/package/environments/types.ts +98 -0
- data/package/esbuild/index.ts +42 -0
- data/package/index.d.ts +3 -60
- data/package/index.ts +55 -0
- data/package/loaders.d.ts +28 -0
- data/package/optimization/rspack.ts +36 -0
- data/package/optimization/webpack.ts +57 -0
- data/package/plugins/rspack.ts +103 -0
- data/package/plugins/webpack.ts +62 -0
- data/package/rspack/index.ts +64 -0
- data/package/rules/{babel.js → babel.ts} +2 -2
- data/package/rules/{coffee.js → coffee.ts} +1 -1
- data/package/rules/css.ts +3 -0
- data/package/rules/{erb.js → erb.ts} +1 -1
- data/package/rules/esbuild.ts +10 -0
- data/package/rules/file.ts +40 -0
- data/package/rules/{jscommon.js → jscommon.ts} +4 -4
- data/package/rules/{less.js → less.ts} +4 -4
- data/package/rules/raw.ts +25 -0
- data/package/rules/rspack.ts +176 -0
- data/package/rules/{sass.js → sass.ts} +7 -3
- data/package/rules/{stylus.js → stylus.ts} +4 -8
- data/package/rules/swc.ts +10 -0
- data/package/rules/webpack.ts +16 -0
- data/package/swc/index.ts +56 -0
- data/package/types/README.md +88 -0
- data/package/types/index.ts +61 -0
- data/package/types.ts +108 -0
- data/package/utils/configPath.ts +6 -0
- data/package/utils/debug.ts +49 -0
- data/package/utils/defaultConfigPath.ts +4 -0
- data/package/utils/errorCodes.ts +219 -0
- data/package/utils/errorHelpers.ts +143 -0
- data/package/utils/getStyleRule.ts +64 -0
- data/package/utils/helpers.ts +85 -0
- data/package/utils/{inliningCss.js → inliningCss.ts} +3 -3
- data/package/utils/pathValidation.ts +139 -0
- data/package/utils/requireOrError.ts +15 -0
- data/package/utils/snakeToCamelCase.ts +5 -0
- data/package/utils/typeGuards.ts +342 -0
- data/package/utils/validateDependencies.ts +61 -0
- data/package/webpack-types.d.ts +33 -0
- data/package/webpackDevServerConfig.ts +117 -0
- data/package-lock.json +13047 -0
- data/package.json +154 -18
- data/scripts/remove-use-strict.js +45 -0
- data/scripts/type-check-no-emit.js +27 -0
- data/test/helpers.js +1 -1
- data/test/package/config.test.js +43 -0
- data/test/package/env.test.js +42 -7
- data/test/package/environments/base.test.js +5 -1
- data/test/package/rules/babel.test.js +16 -0
- data/test/package/rules/esbuild.test.js +1 -1
- data/test/package/rules/raw.test.js +40 -7
- data/test/package/rules/swc.test.js +1 -1
- data/test/package/rules/webpack.test.js +35 -0
- data/test/package/staging.test.js +4 -3
- data/test/package/transpiler-defaults.test.js +127 -0
- data/test/peer-dependencies.sh +85 -0
- data/test/scripts/remove-use-strict.test.js +125 -0
- data/test/typescript/build.test.js +118 -0
- data/test/typescript/environments.test.js +107 -0
- data/test/typescript/pathValidation.test.js +142 -0
- data/test/typescript/securityValidation.test.js +182 -0
- data/tools/README.md +124 -0
- data/tools/css-modules-v9-codemod.js +179 -0
- data/tsconfig.eslint.json +16 -0
- data/tsconfig.json +38 -0
- data/yarn.lock +4165 -2706
- metadata +129 -41
- data/package/babel/preset.js +0 -37
- data/package/config.js +0 -54
- data/package/env.js +0 -48
- data/package/environments/development.js +0 -13
- data/package/environments/production.js +0 -88
- data/package/environments/test.js +0 -3
- data/package/esbuild/index.js +0 -40
- data/package/index.js +0 -40
- data/package/rules/css.js +0 -3
- data/package/rules/esbuild.js +0 -10
- data/package/rules/file.js +0 -29
- data/package/rules/index.js +0 -20
- data/package/rules/raw.js +0 -5
- data/package/rules/swc.js +0 -10
- data/package/swc/index.js +0 -50
- data/package/utils/configPath.js +0 -4
- data/package/utils/defaultConfigPath.js +0 -2
- data/package/utils/getStyleRule.js +0 -40
- data/package/utils/helpers.js +0 -58
- data/package/utils/snakeToCamelCase.js +0 -5
- data/package/webpackDevServerConfig.js +0 -71
- data/test/package/rules/index.test.js +0 -16
|
@@ -1,22 +1,40 @@
|
|
|
1
1
|
/* eslint global-require: 0 */
|
|
2
2
|
/* eslint import/no-dynamic-require: 0 */
|
|
3
3
|
|
|
4
|
-
const { existsSync, readdirSync } = require("fs")
|
|
5
4
|
const { basename, dirname, join, relative, resolve } = require("path")
|
|
5
|
+
const { existsSync, readdirSync } = require("fs")
|
|
6
|
+
import { Dirent } from "fs"
|
|
6
7
|
const extname = require("path-complete-extname")
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const rules = require("../rules")
|
|
8
|
+
// @ts-ignore: webpack is an optional peer dependency (using type-only import)
|
|
9
|
+
import type { Configuration, Entry } from "webpack"
|
|
10
10
|
const config = require("../config")
|
|
11
11
|
const { isProduction } = require("../env")
|
|
12
|
-
const { moduleExists } = require("../utils/helpers")
|
|
13
12
|
|
|
14
|
-
const
|
|
13
|
+
const pluginsPath = resolve(
|
|
14
|
+
__dirname,
|
|
15
|
+
"..",
|
|
16
|
+
"plugins",
|
|
17
|
+
`${config.assets_bundler}.js`
|
|
18
|
+
)
|
|
19
|
+
const { getPlugins } = require(pluginsPath)
|
|
20
|
+
const rulesPath = resolve(
|
|
21
|
+
__dirname,
|
|
22
|
+
"..",
|
|
23
|
+
"rules",
|
|
24
|
+
`${config.assets_bundler}.js`
|
|
25
|
+
)
|
|
26
|
+
const rules = require(rulesPath)
|
|
27
|
+
|
|
28
|
+
// Don't use contentHash except for production for performance
|
|
29
|
+
// https://webpack.js.org/guides/build-performance/#avoid-production-specific-tooling
|
|
30
|
+
const hash = isProduction || config.useContentHash ? "-[contenthash]" : ""
|
|
31
|
+
|
|
32
|
+
const getFilesInDirectory = (dir: string, includeNested: boolean): string[] => {
|
|
15
33
|
if (!existsSync(dir)) {
|
|
16
34
|
return []
|
|
17
35
|
}
|
|
18
36
|
|
|
19
|
-
return readdirSync(dir, { withFileTypes: true }).flatMap((dirent) => {
|
|
37
|
+
return readdirSync(dir, { withFileTypes: true }).flatMap((dirent: Dirent) => {
|
|
20
38
|
const filePath = join(dir, dirent.name)
|
|
21
39
|
|
|
22
40
|
if (dirent.isDirectory() && includeNested) {
|
|
@@ -29,84 +47,56 @@ const getFilesInDirectory = (dir, includeNested) => {
|
|
|
29
47
|
})
|
|
30
48
|
}
|
|
31
49
|
|
|
32
|
-
const getEntryObject = () => {
|
|
33
|
-
const entries = {}
|
|
50
|
+
const getEntryObject = (): Entry => {
|
|
51
|
+
const entries: Entry = {}
|
|
34
52
|
const rootPath = join(config.source_path, config.source_entry_path)
|
|
35
53
|
if (config.source_entry_path === "/" && config.nested_entries) {
|
|
36
54
|
throw new Error(
|
|
37
|
-
|
|
38
|
-
|
|
55
|
+
`Invalid Shakapacker configuration detected!\n\n` +
|
|
56
|
+
`You have set source_entry_path to '/' with nested_entries enabled.\n` +
|
|
57
|
+
`This would create webpack entry points for EVERY file in your source directory,\n` +
|
|
58
|
+
`which would severely impact build performance.\n\n` +
|
|
59
|
+
`To fix this issue, either:\n` +
|
|
60
|
+
`1. Set 'nested_entries: false' in your shakapacker.yml\n` +
|
|
61
|
+
`2. Change 'source_entry_path' to a specific subdirectory (e.g., 'packs')\n` +
|
|
62
|
+
`3. Or use both options for better organization of your entry points`
|
|
39
63
|
)
|
|
40
64
|
}
|
|
41
65
|
|
|
42
66
|
getFilesInDirectory(rootPath, config.nested_entries).forEach((path) => {
|
|
43
67
|
const namespace = relative(join(rootPath), dirname(path))
|
|
44
68
|
const name = join(namespace, basename(path, extname(path)))
|
|
45
|
-
|
|
69
|
+
const assetPath: string = resolve(path)
|
|
46
70
|
|
|
47
71
|
// Allows for multiple filetypes per entry (https://webpack.js.org/guides/entry-advanced/)
|
|
48
72
|
// Transforms the config object value to an array with all values under the same name
|
|
49
|
-
|
|
73
|
+
const previousPaths = entries[name]
|
|
50
74
|
if (previousPaths) {
|
|
51
|
-
|
|
52
|
-
? previousPaths
|
|
53
|
-
: [previousPaths]
|
|
54
|
-
|
|
55
|
-
|
|
75
|
+
const pathArray = Array.isArray(previousPaths)
|
|
76
|
+
? previousPaths as string[]
|
|
77
|
+
: [previousPaths as string]
|
|
78
|
+
pathArray.push(assetPath)
|
|
79
|
+
entries[name] = pathArray
|
|
80
|
+
} else {
|
|
81
|
+
entries[name] = assetPath
|
|
56
82
|
}
|
|
57
|
-
|
|
58
|
-
entries[name] = assetPaths
|
|
59
83
|
})
|
|
60
84
|
|
|
61
85
|
return entries
|
|
62
86
|
}
|
|
63
87
|
|
|
64
|
-
const getModulePaths = () => {
|
|
88
|
+
const getModulePaths = (): string[] => {
|
|
65
89
|
const result = [resolve(config.source_path)]
|
|
66
90
|
|
|
67
91
|
if (config.additional_paths) {
|
|
68
|
-
config.additional_paths.forEach((path) => result.push(resolve(path)))
|
|
92
|
+
config.additional_paths.forEach((path: string) => result.push(resolve(path)))
|
|
69
93
|
}
|
|
70
94
|
result.push("node_modules")
|
|
71
95
|
|
|
72
96
|
return result
|
|
73
97
|
}
|
|
74
98
|
|
|
75
|
-
const
|
|
76
|
-
const plugins = [
|
|
77
|
-
new webpack.EnvironmentPlugin(process.env),
|
|
78
|
-
new WebpackAssetsManifest({
|
|
79
|
-
entrypoints: true,
|
|
80
|
-
writeToDisk: true,
|
|
81
|
-
output: config.manifestPath,
|
|
82
|
-
entrypointsUseAssets: true,
|
|
83
|
-
publicPath: config.publicPathWithoutCDN
|
|
84
|
-
})
|
|
85
|
-
]
|
|
86
|
-
|
|
87
|
-
if (moduleExists("css-loader") && moduleExists("mini-css-extract-plugin")) {
|
|
88
|
-
const hash = isProduction || config.useContentHash ? "-[contenthash:8]" : ""
|
|
89
|
-
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
|
|
90
|
-
plugins.push(
|
|
91
|
-
new MiniCssExtractPlugin({
|
|
92
|
-
filename: `css/[name]${hash}.css`,
|
|
93
|
-
chunkFilename: `css/[id]${hash}.css`,
|
|
94
|
-
// For projects where css ordering has been mitigated through consistent use of scoping or naming conventions,
|
|
95
|
-
// the css order warnings can be disabled by setting the ignoreOrder flag.
|
|
96
|
-
// Read: https://stackoverflow.com/questions/51971857/mini-css-extract-plugin-warning-in-chunk-chunkname-mini-css-extract-plugin-con
|
|
97
|
-
ignoreOrder: config.css_extract_ignore_order_warnings
|
|
98
|
-
})
|
|
99
|
-
)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return plugins
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Don't use contentHash except for production for performance
|
|
106
|
-
// https://webpack.js.org/guides/build-performance/#avoid-production-specific-tooling
|
|
107
|
-
const hash = isProduction || config.useContentHash ? "-[contenthash]" : ""
|
|
108
|
-
|
|
109
|
-
module.exports = {
|
|
99
|
+
const baseConfig: Configuration = {
|
|
110
100
|
mode: "production",
|
|
111
101
|
output: {
|
|
112
102
|
filename: `js/[name]${hash}.js`,
|
|
@@ -115,7 +105,12 @@ module.exports = {
|
|
|
115
105
|
// https://webpack.js.org/configuration/output/#outputhotupdatechunkfilename
|
|
116
106
|
hotUpdateChunkFilename: "js/[id].[fullhash].hot-update.js",
|
|
117
107
|
path: config.outputPath,
|
|
118
|
-
publicPath: config.publicPath
|
|
108
|
+
publicPath: config.publicPath,
|
|
109
|
+
|
|
110
|
+
// This is required for SRI to work.
|
|
111
|
+
crossOriginLoading: config.integrity && config.integrity.enabled
|
|
112
|
+
? (config.integrity.cross_origin as "anonymous" | "use-credentials" | false)
|
|
113
|
+
: false
|
|
119
114
|
},
|
|
120
115
|
entry: getEntryObject(),
|
|
121
116
|
resolve: {
|
|
@@ -131,12 +126,13 @@ module.exports = {
|
|
|
131
126
|
|
|
132
127
|
optimization: {
|
|
133
128
|
splitChunks: { chunks: "all" },
|
|
134
|
-
|
|
135
129
|
runtimeChunk: "single"
|
|
136
130
|
},
|
|
137
131
|
|
|
138
132
|
module: {
|
|
139
|
-
strictExportPresence: true,
|
|
140
133
|
rules
|
|
141
134
|
}
|
|
142
135
|
}
|
|
136
|
+
|
|
137
|
+
export = baseConfig
|
|
138
|
+
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Development environment configuration for webpack and rspack bundlers
|
|
3
|
+
* @module environments/development
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { merge } = require("webpack-merge")
|
|
7
|
+
const config = require("../config")
|
|
8
|
+
const baseConfig = require("./base")
|
|
9
|
+
const webpackDevServerConfig = require("../webpackDevServerConfig")
|
|
10
|
+
const { runningWebpackDevServer } = require("../env")
|
|
11
|
+
const { moduleExists } = require("../utils/helpers")
|
|
12
|
+
import type {
|
|
13
|
+
WebpackConfigWithDevServer,
|
|
14
|
+
RspackConfigWithDevServer,
|
|
15
|
+
ReactRefreshWebpackPlugin,
|
|
16
|
+
ReactRefreshRspackPlugin
|
|
17
|
+
} from "./types"
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Base development configuration shared between webpack and rspack
|
|
21
|
+
*/
|
|
22
|
+
const baseDevConfig = {
|
|
23
|
+
mode: "development" as const,
|
|
24
|
+
devtool: "cheap-module-source-map" as const
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Generate webpack-specific development configuration
|
|
29
|
+
* @returns Webpack configuration with dev server settings
|
|
30
|
+
*/
|
|
31
|
+
const webpackDevConfig = (): WebpackConfigWithDevServer => {
|
|
32
|
+
const webpackConfig: WebpackConfigWithDevServer = {
|
|
33
|
+
...baseDevConfig,
|
|
34
|
+
...(runningWebpackDevServer && { devServer: webpackDevServerConfig() })
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const devServerConfig = webpackDevServerConfig()
|
|
38
|
+
if (
|
|
39
|
+
runningWebpackDevServer &&
|
|
40
|
+
devServerConfig.hot &&
|
|
41
|
+
moduleExists("@pmmmwh/react-refresh-webpack-plugin")
|
|
42
|
+
) {
|
|
43
|
+
// eslint-disable-next-line global-require
|
|
44
|
+
const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin")
|
|
45
|
+
webpackConfig.plugins = [
|
|
46
|
+
...(webpackConfig.plugins || []),
|
|
47
|
+
new ReactRefreshWebpackPlugin()
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return webpackConfig
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Generate rspack-specific development configuration
|
|
56
|
+
* @returns Rspack configuration with dev server settings
|
|
57
|
+
*/
|
|
58
|
+
const rspackDevConfig = (): RspackConfigWithDevServer => {
|
|
59
|
+
const devServerConfig = webpackDevServerConfig()
|
|
60
|
+
const rspackConfig: RspackConfigWithDevServer = {
|
|
61
|
+
...baseDevConfig,
|
|
62
|
+
devServer: {
|
|
63
|
+
...devServerConfig,
|
|
64
|
+
devMiddleware: {
|
|
65
|
+
...(devServerConfig.devMiddleware || {}),
|
|
66
|
+
writeToDisk: (filePath: string) => !filePath.includes(".hot-update.")
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (
|
|
72
|
+
runningWebpackDevServer &&
|
|
73
|
+
devServerConfig.hot &&
|
|
74
|
+
moduleExists("@rspack/plugin-react-refresh")
|
|
75
|
+
) {
|
|
76
|
+
// eslint-disable-next-line global-require
|
|
77
|
+
const ReactRefreshPlugin = require("@rspack/plugin-react-refresh")
|
|
78
|
+
rspackConfig.plugins = [
|
|
79
|
+
...(rspackConfig.plugins || []),
|
|
80
|
+
new ReactRefreshPlugin()
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return rspackConfig
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const bundlerConfig =
|
|
88
|
+
config.assets_bundler === "rspack" ? rspackDevConfig() : webpackDevConfig()
|
|
89
|
+
|
|
90
|
+
module.exports = merge(baseConfig, bundlerConfig)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Production environment configuration for webpack and rspack bundlers
|
|
3
|
+
* @module environments/production
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* eslint global-require: 0 */
|
|
7
|
+
/* eslint import/no-dynamic-require: 0 */
|
|
8
|
+
|
|
9
|
+
const { resolve } = require("path")
|
|
10
|
+
const { merge } = require("webpack-merge")
|
|
11
|
+
const baseConfig = require("./base")
|
|
12
|
+
const { moduleExists } = require("../utils/helpers")
|
|
13
|
+
const config = require("../config")
|
|
14
|
+
import type { Configuration as WebpackConfiguration, WebpackPluginInstance } from "webpack"
|
|
15
|
+
import type { CompressionPluginConstructor } from "./types"
|
|
16
|
+
|
|
17
|
+
const optimizationPath = resolve(
|
|
18
|
+
__dirname,
|
|
19
|
+
"..",
|
|
20
|
+
"optimization",
|
|
21
|
+
`${config.assets_bundler}.js`
|
|
22
|
+
)
|
|
23
|
+
const { getOptimization } = require(optimizationPath)
|
|
24
|
+
|
|
25
|
+
let CompressionPlugin: CompressionPluginConstructor | null = null
|
|
26
|
+
if (moduleExists("compression-webpack-plugin")) {
|
|
27
|
+
// eslint-disable-next-line global-require
|
|
28
|
+
CompressionPlugin = require("compression-webpack-plugin")
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Generate production plugins including compression
|
|
33
|
+
* @returns Array of webpack plugins for production
|
|
34
|
+
*/
|
|
35
|
+
const getPlugins = (): WebpackPluginInstance[] => {
|
|
36
|
+
const plugins: WebpackPluginInstance[] = []
|
|
37
|
+
|
|
38
|
+
if (CompressionPlugin) {
|
|
39
|
+
plugins.push(
|
|
40
|
+
new CompressionPlugin({
|
|
41
|
+
filename: "[path][base].gz[query]",
|
|
42
|
+
algorithm: "gzip",
|
|
43
|
+
test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
|
|
44
|
+
})
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
if ("brotli" in process.versions) {
|
|
48
|
+
plugins.push(
|
|
49
|
+
new CompressionPlugin({
|
|
50
|
+
filename: "[path][base].br[query]",
|
|
51
|
+
algorithm: "brotliCompress",
|
|
52
|
+
test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
|
|
53
|
+
})
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return plugins
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Production configuration with optimizations and compression
|
|
63
|
+
*/
|
|
64
|
+
const productionConfig: Partial<WebpackConfiguration> = {
|
|
65
|
+
devtool: "source-map",
|
|
66
|
+
stats: "normal",
|
|
67
|
+
bail: true,
|
|
68
|
+
plugins: getPlugins(),
|
|
69
|
+
optimization: getOptimization()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (config.useContentHash === false) {
|
|
73
|
+
// eslint-disable-next-line no-console
|
|
74
|
+
console.warn(`⚠️ WARNING
|
|
75
|
+
Setting 'useContentHash' to 'false' in the production environment (specified by NODE_ENV environment variable) is not allowed!
|
|
76
|
+
Content hashes get added to the filenames regardless of setting useContentHash in 'shakapacker.yml' to false.
|
|
77
|
+
`)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
module.exports = merge(baseConfig, productionConfig)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test environment configuration for webpack and rspack bundlers
|
|
3
|
+
* @module environments/test
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { merge } = require("webpack-merge")
|
|
7
|
+
const config = require("../config")
|
|
8
|
+
const baseConfig = require("./base")
|
|
9
|
+
import type { Configuration as WebpackConfiguration } from "webpack"
|
|
10
|
+
|
|
11
|
+
interface TestConfig {
|
|
12
|
+
mode: "development" | "production" | "none"
|
|
13
|
+
devtool: string | false
|
|
14
|
+
watchOptions?: {
|
|
15
|
+
ignored: RegExp
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Shared test configuration for both webpack and rspack
|
|
21
|
+
* Ensures consistent test behavior across bundlers
|
|
22
|
+
*/
|
|
23
|
+
const sharedTestConfig: TestConfig = {
|
|
24
|
+
mode: "development",
|
|
25
|
+
devtool: "cheap-module-source-map",
|
|
26
|
+
// Disable file watching in test mode
|
|
27
|
+
watchOptions: {
|
|
28
|
+
ignored: /node_modules/
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Generate rspack-specific test configuration
|
|
34
|
+
* @returns Rspack configuration optimized for testing
|
|
35
|
+
*/
|
|
36
|
+
const rspackTestConfig = (): TestConfig => ({
|
|
37
|
+
...sharedTestConfig
|
|
38
|
+
// Add any rspack-specific overrides here if needed
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Generate webpack-specific test configuration
|
|
43
|
+
* @returns Webpack configuration for testing with same settings as rspack
|
|
44
|
+
*/
|
|
45
|
+
const webpackTestConfig = (): Partial<WebpackConfiguration> => ({
|
|
46
|
+
...sharedTestConfig
|
|
47
|
+
// Add any webpack-specific overrides here if needed
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const bundlerConfig =
|
|
51
|
+
config.assets_bundler === "rspack" ? rspackTestConfig() : webpackTestConfig()
|
|
52
|
+
|
|
53
|
+
module.exports = merge(baseConfig, bundlerConfig)
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for environment configurations
|
|
3
|
+
* These types are exported for consumer use
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
Configuration as WebpackConfiguration,
|
|
8
|
+
WebpackPluginInstance
|
|
9
|
+
} from "webpack"
|
|
10
|
+
import type { Configuration as DevServerConfiguration } from "webpack-dev-server"
|
|
11
|
+
import type { RspackPluginInstance as ImportedRspackPluginInstance } from "@rspack/core"
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Webpack configuration extended with dev server support
|
|
15
|
+
*/
|
|
16
|
+
export interface WebpackConfigWithDevServer extends WebpackConfiguration {
|
|
17
|
+
devServer?: DevServerConfiguration
|
|
18
|
+
plugins?: WebpackPluginInstance[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Rspack plugin instance interface
|
|
23
|
+
* Uses the RspackPluginInstance type from @rspack/core
|
|
24
|
+
*/
|
|
25
|
+
export type RspackPluginInstance = ImportedRspackPluginInstance
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Rspack plugin type alias
|
|
29
|
+
* @deprecated Use RspackPluginInstance instead
|
|
30
|
+
* Retained for backward compatibility with existing code
|
|
31
|
+
*/
|
|
32
|
+
export type RspackPlugin = RspackPluginInstance
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Rspack dev server configuration
|
|
36
|
+
* Similar to webpack-dev-server but with some rspack-specific options
|
|
37
|
+
*/
|
|
38
|
+
export interface RspackDevServerConfig {
|
|
39
|
+
port?: number | string | "auto"
|
|
40
|
+
host?: string
|
|
41
|
+
hot?: boolean | "only"
|
|
42
|
+
historyApiFallback?: boolean | Record<string, unknown>
|
|
43
|
+
headers?: Record<string, string | string[]>
|
|
44
|
+
proxy?: unknown
|
|
45
|
+
static?: boolean | string | Array<string | Record<string, unknown>>
|
|
46
|
+
devMiddleware?: {
|
|
47
|
+
writeToDisk?: boolean | ((filePath: string) => boolean)
|
|
48
|
+
publicPath?: string
|
|
49
|
+
[key: string]: unknown
|
|
50
|
+
}
|
|
51
|
+
[key: string]: unknown
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Rspack configuration with dev server support
|
|
56
|
+
*/
|
|
57
|
+
export interface RspackConfigWithDevServer {
|
|
58
|
+
mode?: "development" | "production" | "none"
|
|
59
|
+
devtool?: string | false
|
|
60
|
+
devServer?: RspackDevServerConfig
|
|
61
|
+
plugins?: RspackPluginInstance[]
|
|
62
|
+
module?: WebpackConfiguration["module"]
|
|
63
|
+
resolve?: WebpackConfiguration["resolve"]
|
|
64
|
+
entry?: WebpackConfiguration["entry"]
|
|
65
|
+
output?: WebpackConfiguration["output"]
|
|
66
|
+
optimization?: WebpackConfiguration["optimization"]
|
|
67
|
+
[key: string]: unknown
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Compression plugin options interface
|
|
72
|
+
*/
|
|
73
|
+
export interface CompressionPluginOptions {
|
|
74
|
+
filename: string
|
|
75
|
+
algorithm: string | "gzip" | "brotliCompress"
|
|
76
|
+
test: RegExp
|
|
77
|
+
threshold?: number
|
|
78
|
+
minRatio?: number
|
|
79
|
+
deleteOriginalAssets?: boolean
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Compression plugin constructor type
|
|
84
|
+
*/
|
|
85
|
+
export type CompressionPluginConstructor = new (
|
|
86
|
+
options: CompressionPluginOptions
|
|
87
|
+
) => WebpackPluginInstance
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* React Refresh plugin types
|
|
91
|
+
*/
|
|
92
|
+
export interface ReactRefreshWebpackPlugin {
|
|
93
|
+
new (options?: Record<string, unknown>): WebpackPluginInstance
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface ReactRefreshRspackPlugin {
|
|
97
|
+
new (options?: Record<string, unknown>): RspackPluginInstance
|
|
98
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/* eslint global-require: 0 */
|
|
2
|
+
/* eslint import/no-dynamic-require: 0 */
|
|
3
|
+
|
|
4
|
+
import { resolve } from "path"
|
|
5
|
+
import { existsSync } from "fs"
|
|
6
|
+
import { merge } from "webpack-merge"
|
|
7
|
+
import type { RuleSetRule } from "webpack"
|
|
8
|
+
|
|
9
|
+
const LOADER_EXT_REGEX = /\.([jt]sx?)(\.erb)?$/
|
|
10
|
+
|
|
11
|
+
const getLoaderExtension = (filename: string): string => {
|
|
12
|
+
const matchData = filename.match(LOADER_EXT_REGEX)
|
|
13
|
+
|
|
14
|
+
if (!matchData) {
|
|
15
|
+
return "js"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return matchData[1] ?? "js"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const getCustomConfig = (): Partial<RuleSetRule> => {
|
|
22
|
+
const path = resolve("config", "esbuild.config.js")
|
|
23
|
+
if (existsSync(path)) {
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
25
|
+
return require(path)
|
|
26
|
+
}
|
|
27
|
+
return {}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const getEsbuildLoaderConfig = (filenameToProcess: string): RuleSetRule => {
|
|
31
|
+
const customConfig = getCustomConfig()
|
|
32
|
+
const defaultConfig: RuleSetRule = {
|
|
33
|
+
loader: require.resolve("esbuild-loader"),
|
|
34
|
+
options: {
|
|
35
|
+
loader: getLoaderExtension(filenameToProcess)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return merge(defaultConfig, customConfig)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { getEsbuildLoaderConfig }
|
data/package/index.d.ts
CHANGED
|
@@ -1,60 +1,3 @@
|
|
|
1
|
-
declare
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export interface Config {
|
|
5
|
-
source_path: string
|
|
6
|
-
source_entry_path: string
|
|
7
|
-
nested_entries: boolean
|
|
8
|
-
css_extract_ignore_order_warnings: boolean
|
|
9
|
-
public_root_path: string
|
|
10
|
-
public_output_path: string
|
|
11
|
-
cache_path: string
|
|
12
|
-
webpack_compile_output: boolean
|
|
13
|
-
shakapacker_precompile: boolean
|
|
14
|
-
additional_paths: string[]
|
|
15
|
-
cache_manifest: boolean
|
|
16
|
-
webpack_loader: string
|
|
17
|
-
ensure_consistent_versioning: boolean
|
|
18
|
-
compiler_strategy: string
|
|
19
|
-
useContentHash: boolean
|
|
20
|
-
compile: boolean,
|
|
21
|
-
outputPath: string
|
|
22
|
-
publicPath: string
|
|
23
|
-
publicPathWithoutCDN: string
|
|
24
|
-
manifestPath: string
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface Env {
|
|
28
|
-
railsEnv: string
|
|
29
|
-
nodeEnv: string
|
|
30
|
-
isProduction: boolean
|
|
31
|
-
isDevelopment: boolean
|
|
32
|
-
runningWebpackDevServer: boolean
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export const config: Config
|
|
36
|
-
export const devServer: Record<string, unknown>
|
|
37
|
-
export function generateWebpackConfig(extraConfig?: Configuration): Configuration
|
|
38
|
-
export const baseConfig: Configuration
|
|
39
|
-
export const env: Env
|
|
40
|
-
export const rules: Record<string, unknown>
|
|
41
|
-
export function moduleExists(packageName: string): boolean
|
|
42
|
-
export function canProcess<T = unknown>(rule: string, fn: (modulePath: string) => T): T | null
|
|
43
|
-
export const inliningCss: boolean
|
|
44
|
-
export * from 'webpack-merge'
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
declare module 'shakapacker/package/babel/preset.js' {
|
|
48
|
-
import { ConfigAPI, PluginItem, TransformOptions } from '@babel/core'
|
|
49
|
-
|
|
50
|
-
interface RequiredTransformOptions {
|
|
51
|
-
plugins: PluginItem[]
|
|
52
|
-
presets: PluginItem[]
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const defaultConfigFunc: (
|
|
56
|
-
api: ConfigAPI
|
|
57
|
-
) => TransformOptions & RequiredTransformOptions
|
|
58
|
-
|
|
59
|
-
export = defaultConfigFunc
|
|
60
|
-
}
|
|
1
|
+
declare const _default: any;
|
|
2
|
+
export = _default;
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
data/package/index.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/* eslint global-require: 0 */
|
|
2
|
+
/* eslint import/no-dynamic-require: 0 */
|
|
3
|
+
|
|
4
|
+
const webpackMerge = require("webpack-merge")
|
|
5
|
+
import { resolve } from "path"
|
|
6
|
+
import { existsSync } from "fs"
|
|
7
|
+
// @ts-ignore: webpack is an optional peer dependency (using type-only import)
|
|
8
|
+
import type { Configuration } from "webpack"
|
|
9
|
+
const config = require("./config")
|
|
10
|
+
const baseConfig = require("./environments/base")
|
|
11
|
+
const devServer = require("./dev_server")
|
|
12
|
+
const env = require("./env")
|
|
13
|
+
const { moduleExists, canProcess } = require("./utils/helpers")
|
|
14
|
+
const inliningCss = require("./utils/inliningCss")
|
|
15
|
+
|
|
16
|
+
const rulesPath = resolve(__dirname, "rules", `${config.assets_bundler}.js`)
|
|
17
|
+
const rules = require(rulesPath)
|
|
18
|
+
|
|
19
|
+
const generateWebpackConfig = (
|
|
20
|
+
extraConfig: Configuration = {},
|
|
21
|
+
...extraArgs: unknown[]
|
|
22
|
+
): Configuration => {
|
|
23
|
+
if (extraArgs.length > 0) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`Invalid usage: generateWebpackConfig() accepts only one configuration object.\n\n` +
|
|
26
|
+
`You passed ${extraArgs.length + 1} arguments. Only one extra config may be passed here - use webpack-merge to merge configs before passing them to Shakapacker.\n\n` +
|
|
27
|
+
`Example:\n` +
|
|
28
|
+
` const { merge } = require('webpack-merge')\n` +
|
|
29
|
+
` const mergedConfig = merge(config1, config2, config3)\n` +
|
|
30
|
+
` const finalConfig = generateWebpackConfig(mergedConfig)\n\n` +
|
|
31
|
+
`Or if using ES6:\n` +
|
|
32
|
+
` import { merge } from 'webpack-merge'\n` +
|
|
33
|
+
` const finalConfig = generateWebpackConfig(merge(config1, config2))`
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const { nodeEnv } = env
|
|
38
|
+
const path = resolve(__dirname, "environments", `${nodeEnv}.js`)
|
|
39
|
+
const environmentConfig = existsSync(path) ? require(path) : baseConfig
|
|
40
|
+
|
|
41
|
+
return webpackMerge.merge({}, environmentConfig, extraConfig)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export = {
|
|
45
|
+
config, // shakapacker.yml
|
|
46
|
+
devServer,
|
|
47
|
+
generateWebpackConfig,
|
|
48
|
+
baseConfig,
|
|
49
|
+
env,
|
|
50
|
+
rules,
|
|
51
|
+
moduleExists,
|
|
52
|
+
canProcess,
|
|
53
|
+
inliningCss,
|
|
54
|
+
...webpackMerge
|
|
55
|
+
}
|