shakapacker 8.4.0 → 9.0.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 +8 -4
- data/.github/workflows/generator.yml +17 -14
- data/.github/workflows/node.yml +23 -1
- data/.github/workflows/ruby.yml +11 -0
- data/.github/workflows/test-bundlers.yml +170 -0
- data/.gitignore +17 -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 +156 -18
- data/CLAUDE.md +29 -0
- data/CONTRIBUTING.md +138 -20
- data/Gemfile.lock +3 -3
- data/README.md +130 -5
- data/Rakefile +39 -4
- data/TODO.md +50 -0
- data/TODO_v9.md +87 -0
- data/conductor-setup.sh +70 -0
- data/conductor.json +7 -0
- data/docs/cdn_setup.md +379 -0
- data/docs/css-modules-export-mode.md +512 -0
- data/docs/deployment.md +10 -1
- data/docs/optional-peer-dependencies.md +198 -0
- data/docs/peer-dependencies.md +60 -0
- data/docs/rspack.md +190 -0
- data/docs/rspack_migration_guide.md +202 -0
- data/docs/transpiler-migration.md +188 -0
- data/docs/transpiler-performance.md +179 -0
- data/docs/troubleshooting.md +5 -0
- data/docs/typescript-migration.md +378 -0
- data/docs/typescript.md +99 -0
- data/docs/using_esbuild_loader.md +3 -3
- data/docs/using_swc_loader.md +5 -3
- data/docs/v6_upgrade.md +10 -0
- data/docs/v9_upgrade.md +413 -0
- data/lib/install/bin/shakapacker +3 -5
- 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 +12 -2
- 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/configuration.rb +141 -0
- data/lib/shakapacker/dev_server_runner.rb +25 -5
- data/lib/shakapacker/doctor.rb +844 -0
- data/lib/shakapacker/manifest.rb +4 -2
- data/lib/shakapacker/rspack_runner.rb +19 -0
- data/lib/shakapacker/runner.rb +144 -4
- data/lib/shakapacker/swc_migrator.rb +376 -0
- data/lib/shakapacker/utils/manager.rb +2 -0
- data/lib/shakapacker/version.rb +1 -1
- data/lib/shakapacker/version_checker.rb +1 -1
- data/lib/shakapacker/webpack_runner.rb +4 -42
- data/lib/shakapacker.rb +2 -1
- data/lib/tasks/shakapacker/doctor.rake +8 -0
- data/lib/tasks/shakapacker/install.rake +12 -2
- data/lib/tasks/shakapacker/migrate_to_swc.rake +13 -0
- data/lib/tasks/shakapacker.rake +1 -0
- data/package/.npmignore +4 -0
- data/package/babel/preset.ts +56 -0
- data/package/config.ts +175 -0
- data/package/{dev_server.js → dev_server.ts} +8 -5
- data/package/env.ts +92 -0
- data/package/environments/base.ts +138 -0
- 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 +90 -0
- data/package/esbuild/index.ts +42 -0
- data/package/index.d.ts +3 -97
- data/package/index.ts +52 -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/{index.js → webpack.ts} +1 -1
- data/package/swc/index.ts +54 -0
- data/package/types/README.md +87 -0
- data/package/types/index.ts +60 -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.json +134 -9
- data/scripts/remove-use-strict.js +45 -0
- data/scripts/type-check-no-emit.js +27 -0
- data/test/package/config.test.js +3 -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 +2704 -767
- metadata +111 -41
- data/package/babel/preset.js +0 -48
- data/package/config.js +0 -56
- data/package/env.js +0 -48
- data/package/environments/base.js +0 -171
- 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/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 -62
- data/package/utils/snakeToCamelCase.js +0 -5
- data/package/webpackDevServerConfig.js +0 -71
- data/test/package/rules/index.test.js +0 -16
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates that required dependencies are installed for the selected bundler
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { moduleExists } = require("./helpers")
|
|
6
|
+
const { error } = require("./debug")
|
|
7
|
+
|
|
8
|
+
const validateRspackDependencies = (): void => {
|
|
9
|
+
const requiredDependencies = ["@rspack/core", "rspack-manifest-plugin"]
|
|
10
|
+
|
|
11
|
+
const missingDependencies = requiredDependencies.filter(
|
|
12
|
+
(dep) => !moduleExists(dep)
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
if (missingDependencies.length > 0) {
|
|
16
|
+
error(
|
|
17
|
+
`Missing required dependencies for RSpack:\n${missingDependencies
|
|
18
|
+
.map((dep) => ` - ${dep}`)
|
|
19
|
+
.join(
|
|
20
|
+
"\n"
|
|
21
|
+
)}\n\nPlease install them with:\n npm install ${missingDependencies.join(
|
|
22
|
+
" "
|
|
23
|
+
)}`
|
|
24
|
+
)
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Missing RSpack dependencies: ${missingDependencies.join(", ")}`
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const validateWebpackDependencies = (): void => {
|
|
32
|
+
const requiredDependencies = [
|
|
33
|
+
"webpack",
|
|
34
|
+
"webpack-cli",
|
|
35
|
+
"webpack-assets-manifest"
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
const missingDependencies = requiredDependencies.filter(
|
|
39
|
+
(dep) => !moduleExists(dep)
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
if (missingDependencies.length > 0) {
|
|
43
|
+
error(
|
|
44
|
+
`Missing required dependencies for Webpack:\n${missingDependencies
|
|
45
|
+
.map((dep) => ` - ${dep}`)
|
|
46
|
+
.join(
|
|
47
|
+
"\n"
|
|
48
|
+
)}\n\nPlease install them with:\n npm install ${missingDependencies.join(
|
|
49
|
+
" "
|
|
50
|
+
)}`
|
|
51
|
+
)
|
|
52
|
+
throw new Error(
|
|
53
|
+
`Missing Webpack dependencies: ${missingDependencies.join(", ")}`
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export = {
|
|
59
|
+
validateRspackDependencies,
|
|
60
|
+
validateWebpackDependencies
|
|
61
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// @ts-ignore: webpack is an optional peer dependency (using type-only import)
|
|
2
|
+
import type { Configuration, RuleSetRule, RuleSetUseItem } from 'webpack'
|
|
3
|
+
|
|
4
|
+
export interface ShakapackerWebpackConfig extends Configuration {
|
|
5
|
+
module?: Configuration['module'] & {
|
|
6
|
+
rules?: RuleSetRule[]
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ShakapackerRule extends RuleSetRule {
|
|
11
|
+
test: RegExp
|
|
12
|
+
use: RuleSetUseItem[]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ShakapackerLoaderOptions {
|
|
16
|
+
[key: string]: any
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ShakapackerLoader {
|
|
20
|
+
loader: string
|
|
21
|
+
options?: ShakapackerLoaderOptions
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type LoaderType = string | ShakapackerLoader
|
|
25
|
+
|
|
26
|
+
export interface LoaderUtils {
|
|
27
|
+
resolveLoader(name: string): string
|
|
28
|
+
createRule(test: RegExp, loaders: LoaderType[]): ShakapackerRule
|
|
29
|
+
getStyleLoader(extract?: boolean): LoaderType
|
|
30
|
+
getCssLoader(modules?: boolean): LoaderType
|
|
31
|
+
getPostCssLoader(): LoaderType
|
|
32
|
+
getSassLoader(): LoaderType
|
|
33
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { DevServerConfig } from "./types"
|
|
2
|
+
const snakeToCamelCase = require("./utils/snakeToCamelCase")
|
|
3
|
+
|
|
4
|
+
const shakapackerDevServerYamlConfig = require("./dev_server") as DevServerConfig
|
|
5
|
+
const { outputPath: contentBase, publicPath } = require("./config") as {
|
|
6
|
+
outputPath: string
|
|
7
|
+
publicPath: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface WebpackDevServerConfig {
|
|
11
|
+
devMiddleware?: {
|
|
12
|
+
publicPath?: string
|
|
13
|
+
}
|
|
14
|
+
hot?: boolean | string
|
|
15
|
+
liveReload?: boolean
|
|
16
|
+
historyApiFallback?: boolean | {
|
|
17
|
+
disableDotRule?: boolean
|
|
18
|
+
}
|
|
19
|
+
static?: {
|
|
20
|
+
publicPath?: string
|
|
21
|
+
[key: string]: unknown
|
|
22
|
+
}
|
|
23
|
+
client?: Record<string, unknown>
|
|
24
|
+
allowedHosts?: "all" | "auto" | string | string[]
|
|
25
|
+
bonjour?: boolean | Record<string, unknown>
|
|
26
|
+
compress?: boolean
|
|
27
|
+
headers?: Record<string, unknown> | (() => Record<string, unknown>)
|
|
28
|
+
host?: "local-ip" | "local-ipv4" | "local-ipv6" | string
|
|
29
|
+
http2?: boolean
|
|
30
|
+
https?: boolean | Record<string, unknown>
|
|
31
|
+
ipc?: boolean | string
|
|
32
|
+
magicHtml?: boolean
|
|
33
|
+
onAfterSetupMiddleware?: (devServer: unknown) => void
|
|
34
|
+
onBeforeSetupMiddleware?: (devServer: unknown) => void
|
|
35
|
+
open?: boolean | string | string[] | Record<string, unknown> | Record<string, unknown>[]
|
|
36
|
+
port?: "auto" | string | number
|
|
37
|
+
proxy?: unknown
|
|
38
|
+
server?: string | boolean | Record<string, unknown>
|
|
39
|
+
setupExitSignals?: boolean
|
|
40
|
+
setupMiddlewares?: (middlewares: unknown[], devServer: unknown) => unknown[]
|
|
41
|
+
watchFiles?: string | string[] | unknown
|
|
42
|
+
webSocketServer?: string | boolean | Record<string, unknown>
|
|
43
|
+
[key: string]: unknown
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const webpackDevServerMappedKeys = new Set([
|
|
47
|
+
// client, server, liveReload, devMiddleware are handled separately
|
|
48
|
+
"allowedHosts",
|
|
49
|
+
"bonjour",
|
|
50
|
+
"compress",
|
|
51
|
+
"headers",
|
|
52
|
+
"historyApiFallback",
|
|
53
|
+
"host",
|
|
54
|
+
"hot",
|
|
55
|
+
"http2",
|
|
56
|
+
"https",
|
|
57
|
+
"ipc",
|
|
58
|
+
"magicHtml",
|
|
59
|
+
"onAfterSetupMiddleware",
|
|
60
|
+
"onBeforeSetupMiddleware",
|
|
61
|
+
"open",
|
|
62
|
+
"port",
|
|
63
|
+
"proxy",
|
|
64
|
+
"server",
|
|
65
|
+
"setupExitSignals",
|
|
66
|
+
"setupMiddlewares",
|
|
67
|
+
"watchFiles",
|
|
68
|
+
"webSocketServer"
|
|
69
|
+
])
|
|
70
|
+
|
|
71
|
+
function createDevServerConfig(): WebpackDevServerConfig {
|
|
72
|
+
const devServerYamlConfig = { ...shakapackerDevServerYamlConfig } as DevServerConfig & Record<string, unknown>
|
|
73
|
+
const liveReload =
|
|
74
|
+
devServerYamlConfig.live_reload !== undefined
|
|
75
|
+
? devServerYamlConfig.live_reload
|
|
76
|
+
: !devServerYamlConfig.hmr
|
|
77
|
+
delete devServerYamlConfig.live_reload
|
|
78
|
+
|
|
79
|
+
const config: WebpackDevServerConfig = {
|
|
80
|
+
devMiddleware: {
|
|
81
|
+
publicPath
|
|
82
|
+
},
|
|
83
|
+
hot: devServerYamlConfig.hmr,
|
|
84
|
+
liveReload,
|
|
85
|
+
historyApiFallback: {
|
|
86
|
+
disableDotRule: true
|
|
87
|
+
},
|
|
88
|
+
static: {
|
|
89
|
+
publicPath: contentBase
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
delete devServerYamlConfig.hmr
|
|
93
|
+
|
|
94
|
+
if (devServerYamlConfig.static) {
|
|
95
|
+
config.static = {
|
|
96
|
+
...config.static,
|
|
97
|
+
...(typeof devServerYamlConfig.static === 'object' ? devServerYamlConfig.static as Record<string, unknown> : {})
|
|
98
|
+
}
|
|
99
|
+
delete devServerYamlConfig.static
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (devServerYamlConfig.client) {
|
|
103
|
+
config.client = devServerYamlConfig.client
|
|
104
|
+
delete devServerYamlConfig.client
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
Object.keys(devServerYamlConfig).forEach((yamlKey) => {
|
|
108
|
+
const camelYamlKey = snakeToCamelCase(yamlKey)
|
|
109
|
+
if (webpackDevServerMappedKeys.has(camelYamlKey)) {
|
|
110
|
+
config[camelYamlKey] = devServerYamlConfig[yamlKey]
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
return config
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export = createDevServerConfig
|
data/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shakapacker",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0",
|
|
4
4
|
"description": "Use webpack to manage app-like JavaScript modules in Rails",
|
|
5
5
|
"homepage": "https://github.com/shakacode/shakapacker",
|
|
6
6
|
"bugs": {
|
|
@@ -14,24 +14,54 @@
|
|
|
14
14
|
"author": "David Heinemeier Hansson <david@basecamp.com>, Justin Gordon <justin@shakacode.com>",
|
|
15
15
|
"main": "package/index.js",
|
|
16
16
|
"types": "package/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": "./package/index.js",
|
|
19
|
+
"./types": "./package/types/index.js",
|
|
20
|
+
"./webpack": "./package/webpack/index.js",
|
|
21
|
+
"./rspack": "./package/rspack/index.js",
|
|
22
|
+
"./swc": "./package/swc/index.js",
|
|
23
|
+
"./esbuild": "./package/esbuild/index.js",
|
|
24
|
+
"./package.json": "./package.json",
|
|
25
|
+
"./package/babel/preset.js": "./package/babel/preset.js",
|
|
26
|
+
"./package/*": "./package/*"
|
|
27
|
+
},
|
|
17
28
|
"files": [
|
|
18
29
|
"package",
|
|
19
30
|
"lib/install/config/shakapacker.yml"
|
|
20
31
|
],
|
|
21
32
|
"scripts": {
|
|
33
|
+
"clean:ts": "find package -name '*.ts' -not -name '*.d.ts' | sed 's/\\.ts$//' | xargs -I {} rm -f {}.js {}.d.ts {}.d.ts.map {}.js.map",
|
|
34
|
+
"build": "tsc && node scripts/remove-use-strict.js && yarn prettier --write 'package/**/*.js'",
|
|
35
|
+
"build:types": "tsc",
|
|
22
36
|
"lint": "eslint .",
|
|
23
|
-
"
|
|
37
|
+
"lint:fast": "eslint . --ext .js,.jsx,.ts,.tsx --config .eslintrc.fast.js",
|
|
38
|
+
"test": "jest",
|
|
39
|
+
"type-check": "tsc --noEmit",
|
|
40
|
+
"prepublishOnly": "yarn build && yarn type-check"
|
|
24
41
|
},
|
|
25
42
|
"dependencies": {
|
|
26
43
|
"js-yaml": "^4.1.0",
|
|
27
|
-
"path-complete-extname": "^1.0.0"
|
|
44
|
+
"path-complete-extname": "^1.0.0",
|
|
45
|
+
"webpack-merge": "^5.8.0"
|
|
28
46
|
},
|
|
29
47
|
"devDependencies": {
|
|
48
|
+
"@rspack/cli": "^1.4.11",
|
|
49
|
+
"@rspack/core": "^1.4.11",
|
|
50
|
+
"@types/babel__core": "^7.20.5",
|
|
51
|
+
"@types/js-yaml": "^4.0.9",
|
|
52
|
+
"@types/node": "^24.5.2",
|
|
53
|
+
"@types/path-complete-extname": "^1.0.3",
|
|
54
|
+
"@types/webpack": "^5.28.5",
|
|
55
|
+
"@types/webpack-dev-server": "^4.7.2",
|
|
56
|
+
"@types/webpack-merge": "^5.0.0",
|
|
57
|
+
"@typescript-eslint/eslint-plugin": "^8.45.0",
|
|
58
|
+
"@typescript-eslint/parser": "^8.45.0",
|
|
30
59
|
"babel-loader": "^8.2.4",
|
|
31
60
|
"compression-webpack-plugin": "^9.0.0",
|
|
61
|
+
"css-loader": "^7.1.2",
|
|
32
62
|
"esbuild-loader": "^2.18.0",
|
|
33
63
|
"eslint": "^8.0.0",
|
|
34
|
-
"eslint-config-airbnb": "^19.0.
|
|
64
|
+
"eslint-config-airbnb": "^19.0.4",
|
|
35
65
|
"eslint-config-prettier": "^9.0.0",
|
|
36
66
|
"eslint-plugin-import": "^2.31.0",
|
|
37
67
|
"eslint-plugin-jest": "^27.9.0",
|
|
@@ -39,45 +69,140 @@
|
|
|
39
69
|
"eslint-plugin-prettier": "^5.2.6",
|
|
40
70
|
"eslint-plugin-react": "^7.37.5",
|
|
41
71
|
"eslint-plugin-react-hooks": "^4.6.0",
|
|
72
|
+
"husky": "^9.1.7",
|
|
42
73
|
"jest": "^29.7.0",
|
|
74
|
+
"lint-staged": "^15.2.10",
|
|
43
75
|
"memory-fs": "^0.5.0",
|
|
76
|
+
"mini-css-extract-plugin": "^2.9.4",
|
|
44
77
|
"prettier": "^3.2.5",
|
|
78
|
+
"rspack-manifest-plugin": "^5.0.3",
|
|
79
|
+
"sass-loader": "^16.0.5",
|
|
45
80
|
"swc-loader": "^0.1.15",
|
|
46
81
|
"thenify": "^3.3.1",
|
|
82
|
+
"typescript": "^5.9.2",
|
|
47
83
|
"webpack": "5.93.0",
|
|
48
84
|
"webpack-assets-manifest": "^5.0.6",
|
|
49
|
-
"webpack-subresource-integrity": "^5.1.0"
|
|
50
|
-
"webpack-merge": "^5.8.0"
|
|
85
|
+
"webpack-subresource-integrity": "^5.1.0"
|
|
51
86
|
},
|
|
52
87
|
"peerDependencies": {
|
|
53
88
|
"@babel/core": "^7.17.9",
|
|
54
89
|
"@babel/plugin-transform-runtime": "^7.17.0",
|
|
55
90
|
"@babel/preset-env": "^7.16.11",
|
|
56
91
|
"@babel/runtime": "^7.17.9",
|
|
92
|
+
"@rspack/cli": "^1.0.0",
|
|
93
|
+
"@rspack/core": "^1.0.0",
|
|
94
|
+
"@rspack/plugin-react-refresh": "^1.0.0",
|
|
57
95
|
"@types/babel__core": "^7.0.0",
|
|
58
96
|
"@types/webpack": "^5.0.0",
|
|
59
97
|
"babel-loader": "^8.2.4 || ^9.0.0 || ^10.0.0",
|
|
60
|
-
"compression-webpack-plugin": "^9.0.0 || ^10.0.0|| ^11.0.0",
|
|
98
|
+
"compression-webpack-plugin": "^9.0.0 || ^10.0.0 || ^11.0.0",
|
|
99
|
+
"css-loader": "^6.8.1 || ^7.0.0",
|
|
100
|
+
"esbuild": "^0.14.0 || ^0.15.0 || ^0.16.0 || ^0.17.0 || ^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0",
|
|
101
|
+
"esbuild-loader": "^2.0.0 || ^3.0.0 || ^4.0.0",
|
|
102
|
+
"mini-css-extract-plugin": "^2.0.0",
|
|
103
|
+
"rspack-manifest-plugin": "^5.0.0",
|
|
104
|
+
"sass": "^1.50.0",
|
|
105
|
+
"sass-loader": "^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
|
|
106
|
+
"swc-loader": "^0.1.15 || ^0.2.0",
|
|
61
107
|
"terser-webpack-plugin": "^5.3.1",
|
|
62
108
|
"webpack": "^5.76.0",
|
|
63
109
|
"webpack-assets-manifest": "^5.0.6 || ^6.0.0",
|
|
64
|
-
"webpack-subresource-integrity": "^5.1.0",
|
|
65
110
|
"webpack-cli": "^4.9.2 || ^5.0.0 || ^6.0.0",
|
|
66
111
|
"webpack-dev-server": "^4.15.2 || ^5.2.2",
|
|
67
|
-
"webpack-
|
|
112
|
+
"webpack-subresource-integrity": "^5.1.0"
|
|
68
113
|
},
|
|
69
114
|
"peerDependenciesMeta": {
|
|
115
|
+
"@babel/core": {
|
|
116
|
+
"optional": true
|
|
117
|
+
},
|
|
118
|
+
"@babel/plugin-transform-runtime": {
|
|
119
|
+
"optional": true
|
|
120
|
+
},
|
|
121
|
+
"@babel/preset-env": {
|
|
122
|
+
"optional": true
|
|
123
|
+
},
|
|
124
|
+
"@babel/runtime": {
|
|
125
|
+
"optional": true
|
|
126
|
+
},
|
|
127
|
+
"@rspack/core": {
|
|
128
|
+
"optional": true
|
|
129
|
+
},
|
|
130
|
+
"@rspack/cli": {
|
|
131
|
+
"optional": true
|
|
132
|
+
},
|
|
133
|
+
"@rspack/plugin-react-refresh": {
|
|
134
|
+
"optional": true
|
|
135
|
+
},
|
|
70
136
|
"@types/babel__core": {
|
|
71
137
|
"optional": true
|
|
72
138
|
},
|
|
73
139
|
"@types/webpack": {
|
|
74
140
|
"optional": true
|
|
75
141
|
},
|
|
142
|
+
"babel-loader": {
|
|
143
|
+
"optional": true
|
|
144
|
+
},
|
|
145
|
+
"compression-webpack-plugin": {
|
|
146
|
+
"optional": true
|
|
147
|
+
},
|
|
148
|
+
"css-loader": {
|
|
149
|
+
"optional": true
|
|
150
|
+
},
|
|
151
|
+
"esbuild": {
|
|
152
|
+
"optional": true
|
|
153
|
+
},
|
|
154
|
+
"esbuild-loader": {
|
|
155
|
+
"optional": true
|
|
156
|
+
},
|
|
157
|
+
"mini-css-extract-plugin": {
|
|
158
|
+
"optional": true
|
|
159
|
+
},
|
|
160
|
+
"rspack-manifest-plugin": {
|
|
161
|
+
"optional": true
|
|
162
|
+
},
|
|
163
|
+
"sass": {
|
|
164
|
+
"optional": true
|
|
165
|
+
},
|
|
166
|
+
"sass-loader": {
|
|
167
|
+
"optional": true
|
|
168
|
+
},
|
|
169
|
+
"swc-loader": {
|
|
170
|
+
"optional": true
|
|
171
|
+
},
|
|
172
|
+
"terser-webpack-plugin": {
|
|
173
|
+
"optional": true
|
|
174
|
+
},
|
|
175
|
+
"webpack": {
|
|
176
|
+
"optional": true
|
|
177
|
+
},
|
|
178
|
+
"webpack-assets-manifest": {
|
|
179
|
+
"optional": true
|
|
180
|
+
},
|
|
181
|
+
"webpack-cli": {
|
|
182
|
+
"optional": true
|
|
183
|
+
},
|
|
184
|
+
"webpack-dev-server": {
|
|
185
|
+
"optional": true
|
|
186
|
+
},
|
|
76
187
|
"webpack-subresource-integrity": {
|
|
77
188
|
"optional": true
|
|
78
189
|
}
|
|
79
190
|
},
|
|
80
191
|
"packageManager": "yarn@1.22.22",
|
|
192
|
+
"lint-staged": {
|
|
193
|
+
"*.{js,jsx}": [
|
|
194
|
+
"eslint --fix",
|
|
195
|
+
"prettier --write"
|
|
196
|
+
],
|
|
197
|
+
"*.{ts,tsx}": [
|
|
198
|
+
"eslint --fix",
|
|
199
|
+
"prettier --write",
|
|
200
|
+
"node scripts/type-check-no-emit.js"
|
|
201
|
+
],
|
|
202
|
+
"*.{json,yml,yaml,md}": [
|
|
203
|
+
"prettier --write"
|
|
204
|
+
]
|
|
205
|
+
},
|
|
81
206
|
"engines": {
|
|
82
207
|
"node": ">= 14",
|
|
83
208
|
"yarn": ">=1 <5"
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const fs = require("fs")
|
|
3
|
+
const path = require("path")
|
|
4
|
+
|
|
5
|
+
// Recursively find all .js files in a directory
|
|
6
|
+
function findJsFiles(dir) {
|
|
7
|
+
const files = []
|
|
8
|
+
const items = fs.readdirSync(dir, { withFileTypes: true })
|
|
9
|
+
|
|
10
|
+
items.forEach((item) => {
|
|
11
|
+
const fullPath = path.join(dir, item.name)
|
|
12
|
+
if (item.isDirectory()) {
|
|
13
|
+
files.push(...findJsFiles(fullPath))
|
|
14
|
+
} else if (item.isFile() && item.name.endsWith(".js")) {
|
|
15
|
+
files.push(fullPath)
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
return files
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Find all .js files in package directory
|
|
23
|
+
const files = findJsFiles("package")
|
|
24
|
+
|
|
25
|
+
files.forEach((file) => {
|
|
26
|
+
let content = fs.readFileSync(file, "utf8")
|
|
27
|
+
|
|
28
|
+
// Remove "use strict" directive with various quote styles and formatting
|
|
29
|
+
// Handles: optional whitespace, single/double/unicode quotes, optional semicolon,
|
|
30
|
+
// and any trailing whitespace/newline sequences
|
|
31
|
+
content = content.replace(
|
|
32
|
+
/^\s*["'\u2018\u2019\u201C\u201D]use\s+strict["'\u2018\u2019\u201C\u201D]\s*;?\s*[\r\n]*/,
|
|
33
|
+
""
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
// Ensure file ends with exactly one newline
|
|
37
|
+
if (!content.endsWith("\n")) {
|
|
38
|
+
content += "\n"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fs.writeFileSync(file, content, "utf8")
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
// eslint-disable-next-line no-console
|
|
45
|
+
console.log(`Removed "use strict" from ${files.length} files`)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Type-check script for lint-staged
|
|
5
|
+
*
|
|
6
|
+
* This script runs TypeScript type checking without emitting files.
|
|
7
|
+
* It ignores any arguments passed by lint-staged to ensure tsc uses
|
|
8
|
+
* the project's tsconfig.json rather than trying to compile individual files.
|
|
9
|
+
*
|
|
10
|
+
* Without this wrapper, lint-staged would pass staged file paths as arguments
|
|
11
|
+
* to tsc, causing it to ignore tsconfig.json and fail type checking.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const { execSync } = require("child_process")
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
// Run tsc with no arguments (ignoring any passed by lint-staged)
|
|
18
|
+
// This ensures it uses tsconfig.json properly
|
|
19
|
+
execSync("npx tsc --noEmit", {
|
|
20
|
+
stdio: "inherit",
|
|
21
|
+
cwd: process.cwd()
|
|
22
|
+
})
|
|
23
|
+
process.exit(0)
|
|
24
|
+
} catch (error) {
|
|
25
|
+
// Type checking failed
|
|
26
|
+
process.exit(1)
|
|
27
|
+
}
|
data/test/package/config.test.js
CHANGED
|
@@ -71,6 +71,7 @@ describe("Config", () => {
|
|
|
71
71
|
})
|
|
72
72
|
|
|
73
73
|
test("should allow enabling integrity", () => {
|
|
74
|
+
process.env.RAILS_ENV = "production"
|
|
74
75
|
process.env.SHAKAPACKER_CONFIG = "config/shakapacker_integrity.yml"
|
|
75
76
|
const config = require("../../package/config")
|
|
76
77
|
|
|
@@ -78,6 +79,7 @@ describe("Config", () => {
|
|
|
78
79
|
})
|
|
79
80
|
|
|
80
81
|
test("should allow configuring hash functions", () => {
|
|
82
|
+
process.env.RAILS_ENV = "production"
|
|
81
83
|
process.env.SHAKAPACKER_CONFIG = "config/shakapacker_integrity.yml"
|
|
82
84
|
const config = require("../../package/config")
|
|
83
85
|
|
|
@@ -89,6 +91,7 @@ describe("Config", () => {
|
|
|
89
91
|
})
|
|
90
92
|
|
|
91
93
|
test("should allow configuring crossorigin", () => {
|
|
94
|
+
process.env.RAILS_ENV = "production"
|
|
92
95
|
process.env.SHAKAPACKER_CONFIG = "config/shakapacker_integrity.yml"
|
|
93
96
|
const config = require("../../package/config")
|
|
94
97
|
|
data/test/package/env.test.js
CHANGED
|
@@ -24,6 +24,18 @@ describe("Env", () => {
|
|
|
24
24
|
delete process.env.NODE_ENV
|
|
25
25
|
expect(require("../../package/env")).toStrictEqual({
|
|
26
26
|
railsEnv: "development",
|
|
27
|
+
nodeEnv: "development",
|
|
28
|
+
isProduction: false,
|
|
29
|
+
isDevelopment: true,
|
|
30
|
+
runningWebpackDevServer: false
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test("with undefined NODE_ENV and RAILS_ENV set to production", () => {
|
|
35
|
+
process.env.RAILS_ENV = "production"
|
|
36
|
+
delete process.env.NODE_ENV
|
|
37
|
+
expect(require("../../package/env")).toStrictEqual({
|
|
38
|
+
railsEnv: "production",
|
|
27
39
|
nodeEnv: "production",
|
|
28
40
|
isProduction: true,
|
|
29
41
|
isDevelopment: false,
|
|
@@ -35,10 +47,10 @@ describe("Env", () => {
|
|
|
35
47
|
delete process.env.NODE_ENV
|
|
36
48
|
delete process.env.RAILS_ENV
|
|
37
49
|
expect(require("../../package/env")).toStrictEqual({
|
|
38
|
-
railsEnv: "
|
|
39
|
-
nodeEnv: "
|
|
40
|
-
isProduction:
|
|
41
|
-
isDevelopment:
|
|
50
|
+
railsEnv: "development",
|
|
51
|
+
nodeEnv: "development",
|
|
52
|
+
isProduction: false,
|
|
53
|
+
isDevelopment: true,
|
|
42
54
|
runningWebpackDevServer: false
|
|
43
55
|
})
|
|
44
56
|
})
|
|
@@ -48,10 +60,33 @@ describe("Env", () => {
|
|
|
48
60
|
process.env.NODE_ENV = "staging"
|
|
49
61
|
expect(require("../../package/env")).toStrictEqual({
|
|
50
62
|
railsEnv: "staging",
|
|
51
|
-
nodeEnv: "
|
|
52
|
-
isProduction:
|
|
53
|
-
isDevelopment:
|
|
63
|
+
nodeEnv: "development",
|
|
64
|
+
isProduction: false,
|
|
65
|
+
isDevelopment: true,
|
|
66
|
+
runningWebpackDevServer: false
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
test("rejects malicious NODE_ENV values and uses default", () => {
|
|
71
|
+
process.env.RAILS_ENV = "development"
|
|
72
|
+
process.env.NODE_ENV = "../../../etc/passwd"
|
|
73
|
+
expect(require("../../package/env")).toStrictEqual({
|
|
74
|
+
railsEnv: "development",
|
|
75
|
+
nodeEnv: "development",
|
|
76
|
+
isProduction: false,
|
|
77
|
+
isDevelopment: true,
|
|
54
78
|
runningWebpackDevServer: false
|
|
55
79
|
})
|
|
56
80
|
})
|
|
81
|
+
|
|
82
|
+
test("warns when NODE_ENV is invalid", () => {
|
|
83
|
+
const consoleSpy = jest.spyOn(console, "warn").mockImplementation()
|
|
84
|
+
process.env.NODE_ENV = "invalid"
|
|
85
|
+
delete process.env.RAILS_ENV
|
|
86
|
+
require("../../package/env")
|
|
87
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
88
|
+
expect.stringContaining("Invalid NODE_ENV value: invalid")
|
|
89
|
+
)
|
|
90
|
+
consoleSpy.mockRestore()
|
|
91
|
+
})
|
|
57
92
|
})
|
|
@@ -7,6 +7,10 @@ const { chdirTestApp, resetEnv } = require("../../helpers")
|
|
|
7
7
|
const rootPath = process.cwd()
|
|
8
8
|
chdirTestApp()
|
|
9
9
|
|
|
10
|
+
// Set NODE_ENV before requiring modules to ensure contenthash is enabled
|
|
11
|
+
// Base config tests expect production-like behavior with contenthash
|
|
12
|
+
process.env.NODE_ENV = "production"
|
|
13
|
+
|
|
10
14
|
const baseConfig = require("../../../package/environments/base")
|
|
11
15
|
const config = require("../../../package/config")
|
|
12
16
|
|
|
@@ -79,7 +83,7 @@ describe("Base config", () => {
|
|
|
79
83
|
})
|
|
80
84
|
|
|
81
85
|
test("should return default loader rules for each file in config/loaders", () => {
|
|
82
|
-
const rules = require("../../../package/rules")
|
|
86
|
+
const rules = require("../../../package/rules/webpack")
|
|
83
87
|
|
|
84
88
|
const defaultRules = Object.keys(rules)
|
|
85
89
|
const configRules = baseConfig.module.rules
|
|
@@ -11,6 +11,7 @@ jest.mock("../../../package/config", () => {
|
|
|
11
11
|
const original = jest.requireActual("../../../package/config")
|
|
12
12
|
return {
|
|
13
13
|
...original,
|
|
14
|
+
javascript_transpiler: "babel", // Force babel for this test
|
|
14
15
|
additional_paths: [...original.additional_paths, "node_modules/included"]
|
|
15
16
|
}
|
|
16
17
|
})
|
|
@@ -32,6 +33,21 @@ const createWebpackConfig = (file, use) => ({
|
|
|
32
33
|
})
|
|
33
34
|
|
|
34
35
|
describe("babel", () => {
|
|
36
|
+
// Mock validateBabelDependencies to avoid actual dependency checking in tests
|
|
37
|
+
beforeAll(() => {
|
|
38
|
+
jest.mock("../../../package/utils/helpers", () => {
|
|
39
|
+
const original = jest.requireActual("../../../package/utils/helpers")
|
|
40
|
+
return {
|
|
41
|
+
...original,
|
|
42
|
+
validateBabelDependencies: jest.fn() // Mock to do nothing
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
afterAll(() => {
|
|
48
|
+
jest.unmock("../../../package/utils/helpers")
|
|
49
|
+
})
|
|
50
|
+
|
|
35
51
|
test("process source path", async () => {
|
|
36
52
|
const normalPath = `${pathToAppJavascript}/a.js`
|
|
37
53
|
const [tracked, loader] = createTrackLoader()
|
|
@@ -11,7 +11,7 @@ jest.mock("../../../package/config", () => {
|
|
|
11
11
|
const original = jest.requireActual("../../../package/config")
|
|
12
12
|
return {
|
|
13
13
|
...original,
|
|
14
|
-
|
|
14
|
+
javascript_transpiler: "esbuild",
|
|
15
15
|
additional_paths: [...original.additional_paths, "node_modules/included"]
|
|
16
16
|
}
|
|
17
17
|
})
|