shakapacker 9.0.0.beta.6 → 9.0.0.beta.7
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/.github/workflows/generator.yml +6 -0
- data/.gitignore +0 -1
- data/.npmignore +55 -0
- data/Gemfile.lock +1 -1
- data/README.md +4 -0
- data/docs/transpiler-migration.md +191 -0
- data/docs/typescript-migration.md +378 -0
- data/lib/install/template.rb +54 -7
- data/lib/shakapacker/version.rb +1 -1
- data/package/.npmignore +4 -0
- data/package/config.ts +23 -10
- data/package/env.ts +15 -2
- data/package/environments/{development.js → development.ts} +30 -8
- data/package/environments/{production.js → production.ts} +18 -4
- data/package/environments/test.ts +53 -0
- data/package/environments/types.ts +90 -0
- data/package/types/README.md +87 -0
- data/package/types/index.ts +60 -0
- data/package/utils/errorCodes.ts +219 -0
- data/package/utils/errorHelpers.ts +68 -2
- data/package/utils/pathValidation.ts +139 -0
- data/package/utils/typeGuards.ts +161 -47
- data/package.json +5 -3
- data/scripts/remove-use-strict.js +45 -0
- data/test/package/transpiler-defaults.test.js +127 -0
- data/test/scripts/remove-use-strict.test.js +125 -0
- data/test/typescript/build.test.js +3 -2
- data/test/typescript/environments.test.js +107 -0
- data/test/typescript/pathValidation.test.js +142 -0
- data/test/typescript/securityValidation.test.js +182 -0
- metadata +25 -6
- data/package/environments/base.js +0 -103
- data/package/environments/test.js +0 -19
@@ -0,0 +1,107 @@
|
|
1
|
+
// Type-specific tests for environment modules
|
2
|
+
// Test imports to ensure TypeScript modules compile correctly
|
3
|
+
const developmentConfig = require("../../package/environments/development")
|
4
|
+
const productionConfig = require("../../package/environments/production")
|
5
|
+
const testConfig = require("../../package/environments/test")
|
6
|
+
|
7
|
+
describe("TypeScript Environment Modules", () => {
|
8
|
+
describe("development.ts", () => {
|
9
|
+
it("exports a valid webpack/rspack configuration", () => {
|
10
|
+
expect(developmentConfig).toBeDefined()
|
11
|
+
expect(typeof developmentConfig).toBe("object")
|
12
|
+
expect(developmentConfig.mode).toBe("development")
|
13
|
+
})
|
14
|
+
|
15
|
+
it("includes proper devtool configuration", () => {
|
16
|
+
expect(developmentConfig.devtool).toBe("cheap-module-source-map")
|
17
|
+
})
|
18
|
+
|
19
|
+
it("can be used as webpack configuration", () => {
|
20
|
+
// This test verifies the module exports valid config
|
21
|
+
const config = developmentConfig
|
22
|
+
expect(config).toBeDefined()
|
23
|
+
expect(typeof config).toBe("object")
|
24
|
+
})
|
25
|
+
})
|
26
|
+
|
27
|
+
describe("production.ts", () => {
|
28
|
+
it("exports a valid webpack/rspack configuration", () => {
|
29
|
+
expect(productionConfig).toBeDefined()
|
30
|
+
expect(typeof productionConfig).toBe("object")
|
31
|
+
expect(productionConfig.mode).toBe("production")
|
32
|
+
})
|
33
|
+
|
34
|
+
it("includes proper devtool configuration", () => {
|
35
|
+
expect(productionConfig.devtool).toBe("source-map")
|
36
|
+
})
|
37
|
+
|
38
|
+
it("includes optimization configuration", () => {
|
39
|
+
expect(productionConfig.optimization).toBeDefined()
|
40
|
+
})
|
41
|
+
|
42
|
+
it("includes plugins array", () => {
|
43
|
+
expect(Array.isArray(productionConfig.plugins)).toBe(true)
|
44
|
+
})
|
45
|
+
|
46
|
+
it("can be used as webpack configuration", () => {
|
47
|
+
const config = productionConfig
|
48
|
+
expect(config).toBeDefined()
|
49
|
+
expect(typeof config).toBe("object")
|
50
|
+
})
|
51
|
+
})
|
52
|
+
|
53
|
+
describe("test.ts", () => {
|
54
|
+
it("exports a valid webpack/rspack configuration", () => {
|
55
|
+
expect(testConfig).toBeDefined()
|
56
|
+
expect(typeof testConfig).toBe("object")
|
57
|
+
})
|
58
|
+
|
59
|
+
it("includes proper mode configuration", () => {
|
60
|
+
// Test environment should always have a mode defined
|
61
|
+
expect(testConfig.mode).toBeDefined()
|
62
|
+
expect(["development", "production", "test"]).toContain(testConfig.mode)
|
63
|
+
})
|
64
|
+
|
65
|
+
it("can be used as webpack configuration", () => {
|
66
|
+
const config = testConfig
|
67
|
+
expect(config).toBeDefined()
|
68
|
+
expect(typeof config).toBe("object")
|
69
|
+
})
|
70
|
+
})
|
71
|
+
|
72
|
+
describe("type safety", () => {
|
73
|
+
it("ensures all environment configs have consistent base structure", () => {
|
74
|
+
const configs = [developmentConfig, productionConfig, testConfig]
|
75
|
+
|
76
|
+
configs.forEach((config) => {
|
77
|
+
expect(config).toHaveProperty("module")
|
78
|
+
expect(config).toHaveProperty("entry")
|
79
|
+
expect(config).toHaveProperty("output")
|
80
|
+
expect(config).toHaveProperty("resolve")
|
81
|
+
})
|
82
|
+
})
|
83
|
+
|
84
|
+
it("validates dev server configuration when present", () => {
|
85
|
+
// Development config may or may not have devServer depending on environment
|
86
|
+
const { devServer = {} } = developmentConfig
|
87
|
+
|
88
|
+
// Validate devServer type (either undefined or object from config)
|
89
|
+
const actualDevServer = developmentConfig.devServer
|
90
|
+
expect(["undefined", "object"]).toContain(typeof actualDevServer)
|
91
|
+
|
92
|
+
// For port validation, we accept: undefined, "auto", number, or string
|
93
|
+
const { port } = devServer
|
94
|
+
|
95
|
+
// Map "auto" string to type "auto", everything else to its typeof
|
96
|
+
// Use array to avoid conditional operators - mappedType takes precedence
|
97
|
+
const portTypeMap = { auto: "auto" }
|
98
|
+
const mappedType = portTypeMap[port]
|
99
|
+
const actualType = typeof port
|
100
|
+
const possibleTypes = [mappedType, actualType]
|
101
|
+
const portType = possibleTypes.find((t) => t !== undefined)
|
102
|
+
|
103
|
+
// Port should be undefined, "auto", number, or string
|
104
|
+
expect(["undefined", "auto", "number", "string"]).toContain(portType)
|
105
|
+
})
|
106
|
+
})
|
107
|
+
})
|
@@ -0,0 +1,142 @@
|
|
1
|
+
// Tests for path validation and security utilities
|
2
|
+
const path = require("path")
|
3
|
+
const {
|
4
|
+
isPathTraversalSafe,
|
5
|
+
safeResolvePath,
|
6
|
+
validatePaths,
|
7
|
+
sanitizeEnvValue,
|
8
|
+
validatePort
|
9
|
+
} = require("../../package/utils/pathValidation")
|
10
|
+
|
11
|
+
describe("Path Validation Security", () => {
|
12
|
+
describe("isPathTraversalSafe", () => {
|
13
|
+
it("detects directory traversal patterns", () => {
|
14
|
+
const unsafePaths = [
|
15
|
+
"../etc/passwd",
|
16
|
+
"../../secrets",
|
17
|
+
"/etc/passwd",
|
18
|
+
"~/ssh/keys",
|
19
|
+
"C:\\Windows\\System32",
|
20
|
+
"C:/Windows/System32", // Windows with forward slash
|
21
|
+
"D:\\Program Files", // Different drive letter
|
22
|
+
"\\\\server\\share\\file", // Windows UNC path
|
23
|
+
"\\\\192.168.1.1\\share", // UNC with IP
|
24
|
+
"%2e%2e%2fsecrets",
|
25
|
+
"%2E%2E%2Fsecrets", // URL encoded uppercase
|
26
|
+
"path\x00with\x00null" // Null bytes
|
27
|
+
]
|
28
|
+
|
29
|
+
unsafePaths.forEach((unsafePath) => {
|
30
|
+
expect(isPathTraversalSafe(unsafePath)).toBe(false)
|
31
|
+
})
|
32
|
+
})
|
33
|
+
|
34
|
+
it("allows safe relative paths", () => {
|
35
|
+
const safePaths = [
|
36
|
+
path.join("src", "index.js"),
|
37
|
+
path.join(".", "components", "App.tsx"),
|
38
|
+
path.join("node_modules", "package", "index.js"),
|
39
|
+
path.join("dist", "bundle.js")
|
40
|
+
]
|
41
|
+
|
42
|
+
safePaths.forEach((safePath) => {
|
43
|
+
expect(isPathTraversalSafe(safePath)).toBe(true)
|
44
|
+
})
|
45
|
+
})
|
46
|
+
})
|
47
|
+
|
48
|
+
describe("safeResolvePath", () => {
|
49
|
+
it("resolves paths within base directory", () => {
|
50
|
+
const basePath = path.join(path.sep, "app")
|
51
|
+
const userPath = path.join("src", "index.js")
|
52
|
+
const result = safeResolvePath(basePath, userPath)
|
53
|
+
|
54
|
+
expect(result).toContain(basePath)
|
55
|
+
expect(result).toContain(userPath.replace(/\\/g, path.sep))
|
56
|
+
})
|
57
|
+
|
58
|
+
it("throws on traversal attempts", () => {
|
59
|
+
const basePath = path.join(path.sep, "app")
|
60
|
+
const maliciousPath = path.join("..", "etc", "passwd")
|
61
|
+
|
62
|
+
expect(() => {
|
63
|
+
safeResolvePath(basePath, maliciousPath)
|
64
|
+
}).toThrow("Path traversal attempt detected")
|
65
|
+
})
|
66
|
+
})
|
67
|
+
|
68
|
+
describe("validatePaths", () => {
|
69
|
+
it("filters out unsafe paths with warnings", () => {
|
70
|
+
const consoleSpy = jest.spyOn(console, "warn").mockImplementation()
|
71
|
+
|
72
|
+
const paths = [
|
73
|
+
path.join("src", "index.js"),
|
74
|
+
path.join("..", "etc", "passwd"),
|
75
|
+
path.join("components", "App.tsx")
|
76
|
+
]
|
77
|
+
|
78
|
+
const result = validatePaths(paths, path.join(path.sep, "app"))
|
79
|
+
|
80
|
+
expect(result).toHaveLength(2)
|
81
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
82
|
+
expect.stringContaining("potentially unsafe path")
|
83
|
+
)
|
84
|
+
|
85
|
+
consoleSpy.mockRestore()
|
86
|
+
})
|
87
|
+
})
|
88
|
+
|
89
|
+
describe("sanitizeEnvValue", () => {
|
90
|
+
it("removes control characters", () => {
|
91
|
+
const dirty = "normal\x00text\x1Fwith\x7Fcontrol"
|
92
|
+
const clean = sanitizeEnvValue(dirty)
|
93
|
+
|
94
|
+
expect(clean).toBe("normaltextwithcontrol")
|
95
|
+
})
|
96
|
+
|
97
|
+
it("warns when sanitization occurs", () => {
|
98
|
+
const consoleSpy = jest.spyOn(console, "warn").mockImplementation()
|
99
|
+
|
100
|
+
sanitizeEnvValue("text\x00with\x00nulls")
|
101
|
+
|
102
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
103
|
+
expect.stringContaining("control characters")
|
104
|
+
)
|
105
|
+
|
106
|
+
consoleSpy.mockRestore()
|
107
|
+
})
|
108
|
+
|
109
|
+
it("returns undefined for undefined input", () => {
|
110
|
+
expect(sanitizeEnvValue(undefined)).toBeUndefined()
|
111
|
+
})
|
112
|
+
})
|
113
|
+
|
114
|
+
describe("validatePort", () => {
|
115
|
+
it("accepts valid port numbers", () => {
|
116
|
+
expect(validatePort(3000)).toBe(true)
|
117
|
+
expect(validatePort(80)).toBe(true)
|
118
|
+
expect(validatePort(65535)).toBe(true)
|
119
|
+
})
|
120
|
+
|
121
|
+
it("accepts valid port strings", () => {
|
122
|
+
expect(validatePort("3000")).toBe(true)
|
123
|
+
expect(validatePort("auto")).toBe(true)
|
124
|
+
})
|
125
|
+
|
126
|
+
it("rejects invalid ports", () => {
|
127
|
+
expect(validatePort(0)).toBe(false)
|
128
|
+
expect(validatePort(65536)).toBe(false)
|
129
|
+
expect(validatePort(-1)).toBe(false)
|
130
|
+
expect(validatePort(3000.5)).toBe(false)
|
131
|
+
expect(validatePort("invalid")).toBe(false)
|
132
|
+
expect(validatePort("3000abc")).toBe(false) // Should reject strings with non-digits
|
133
|
+
expect(validatePort("abc3000")).toBe(false) // Should reject strings with non-digits
|
134
|
+
expect(validatePort("30.00")).toBe(false) // Should reject decimal strings
|
135
|
+
expect(validatePort("3000 ")).toBe(false) // Should reject strings with spaces
|
136
|
+
expect(validatePort(" 3000")).toBe(false) // Should reject strings with spaces
|
137
|
+
expect(validatePort("0x1234")).toBe(false) // Should reject hex notation
|
138
|
+
expect(validatePort(null)).toBe(false)
|
139
|
+
expect(validatePort(undefined)).toBe(false)
|
140
|
+
})
|
141
|
+
})
|
142
|
+
})
|
@@ -0,0 +1,182 @@
|
|
1
|
+
const {
|
2
|
+
isValidConfig,
|
3
|
+
clearValidationCache
|
4
|
+
} = require("../../package/utils/typeGuards")
|
5
|
+
|
6
|
+
describe("security validation", () => {
|
7
|
+
const originalNodeEnv = process.env.NODE_ENV
|
8
|
+
const originalStrictValidation = process.env.SHAKAPACKER_STRICT_VALIDATION
|
9
|
+
|
10
|
+
afterEach(() => {
|
11
|
+
process.env.NODE_ENV = originalNodeEnv
|
12
|
+
process.env.SHAKAPACKER_STRICT_VALIDATION = originalStrictValidation
|
13
|
+
clearValidationCache()
|
14
|
+
})
|
15
|
+
|
16
|
+
describe("path traversal security checks", () => {
|
17
|
+
const baseConfig = {
|
18
|
+
source_path: "./app/javascript",
|
19
|
+
source_entry_path: "./packs",
|
20
|
+
public_root_path: "./public",
|
21
|
+
public_output_path: "packs",
|
22
|
+
cache_path: "tmp/shakapacker",
|
23
|
+
javascript_transpiler: "babel",
|
24
|
+
nested_entries: false,
|
25
|
+
css_extract_ignore_order_warnings: false,
|
26
|
+
webpack_compile_output: true,
|
27
|
+
shakapacker_precompile: true,
|
28
|
+
cache_manifest: false,
|
29
|
+
ensure_consistent_versioning: false,
|
30
|
+
useContentHash: true,
|
31
|
+
compile: true,
|
32
|
+
additional_paths: []
|
33
|
+
}
|
34
|
+
|
35
|
+
it("always validates path traversal in required path fields in production", () => {
|
36
|
+
process.env.NODE_ENV = "production"
|
37
|
+
delete process.env.SHAKAPACKER_STRICT_VALIDATION
|
38
|
+
|
39
|
+
const unsafeConfig = {
|
40
|
+
...baseConfig,
|
41
|
+
source_path: "../../../etc/passwd"
|
42
|
+
}
|
43
|
+
|
44
|
+
expect(isValidConfig(unsafeConfig)).toBe(false)
|
45
|
+
})
|
46
|
+
|
47
|
+
it("always validates path traversal in required path fields in development", () => {
|
48
|
+
process.env.NODE_ENV = "development"
|
49
|
+
|
50
|
+
const unsafeConfig = {
|
51
|
+
...baseConfig,
|
52
|
+
public_output_path: "../../sensitive/data"
|
53
|
+
}
|
54
|
+
|
55
|
+
expect(isValidConfig(unsafeConfig)).toBe(false)
|
56
|
+
})
|
57
|
+
|
58
|
+
it("always validates path traversal in additional_paths in production", () => {
|
59
|
+
process.env.NODE_ENV = "production"
|
60
|
+
delete process.env.SHAKAPACKER_STRICT_VALIDATION
|
61
|
+
|
62
|
+
const unsafeConfig = {
|
63
|
+
...baseConfig,
|
64
|
+
additional_paths: ["./safe/path", "../../../etc/passwd"]
|
65
|
+
}
|
66
|
+
|
67
|
+
expect(isValidConfig(unsafeConfig)).toBe(false)
|
68
|
+
})
|
69
|
+
|
70
|
+
it("always validates path traversal in additional_paths in development", () => {
|
71
|
+
process.env.NODE_ENV = "development"
|
72
|
+
|
73
|
+
const unsafeConfig = {
|
74
|
+
...baseConfig,
|
75
|
+
additional_paths: ["./safe/path", "../../../../root/.ssh"]
|
76
|
+
}
|
77
|
+
|
78
|
+
expect(isValidConfig(unsafeConfig)).toBe(false)
|
79
|
+
})
|
80
|
+
|
81
|
+
it("allows safe paths in production", () => {
|
82
|
+
process.env.NODE_ENV = "production"
|
83
|
+
delete process.env.SHAKAPACKER_STRICT_VALIDATION
|
84
|
+
|
85
|
+
const safeConfig = {
|
86
|
+
...baseConfig,
|
87
|
+
additional_paths: ["./app/assets", "./vendor/assets", "node_modules"]
|
88
|
+
}
|
89
|
+
|
90
|
+
expect(isValidConfig(safeConfig)).toBe(true)
|
91
|
+
})
|
92
|
+
|
93
|
+
it("allows safe paths in development", () => {
|
94
|
+
process.env.NODE_ENV = "development"
|
95
|
+
|
96
|
+
const safeConfig = {
|
97
|
+
...baseConfig,
|
98
|
+
additional_paths: ["./app/components", "./lib/assets"]
|
99
|
+
}
|
100
|
+
|
101
|
+
expect(isValidConfig(safeConfig)).toBe(true)
|
102
|
+
})
|
103
|
+
})
|
104
|
+
|
105
|
+
describe("optional field validation", () => {
|
106
|
+
const validConfig = {
|
107
|
+
source_path: "./app/javascript",
|
108
|
+
source_entry_path: "./packs",
|
109
|
+
public_root_path: "./public",
|
110
|
+
public_output_path: "packs",
|
111
|
+
cache_path: "tmp/shakapacker",
|
112
|
+
javascript_transpiler: "babel",
|
113
|
+
nested_entries: false,
|
114
|
+
css_extract_ignore_order_warnings: false,
|
115
|
+
webpack_compile_output: true,
|
116
|
+
shakapacker_precompile: true,
|
117
|
+
cache_manifest: false,
|
118
|
+
ensure_consistent_versioning: false,
|
119
|
+
useContentHash: true,
|
120
|
+
compile: true,
|
121
|
+
additional_paths: [],
|
122
|
+
dev_server: {
|
123
|
+
hmr: true,
|
124
|
+
port: 3035
|
125
|
+
},
|
126
|
+
integrity: {
|
127
|
+
enabled: true,
|
128
|
+
cross_origin: "anonymous"
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
it("skips deep validation of optional fields in production without strict mode", () => {
|
133
|
+
process.env.NODE_ENV = "production"
|
134
|
+
delete process.env.SHAKAPACKER_STRICT_VALIDATION
|
135
|
+
|
136
|
+
// Invalid integrity config that would fail deep validation
|
137
|
+
const configWithInvalidOptional = {
|
138
|
+
...validConfig,
|
139
|
+
integrity: {
|
140
|
+
enabled: "not-a-boolean", // Invalid type
|
141
|
+
cross_origin: "anonymous"
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
// Should pass because deep validation is skipped in production
|
146
|
+
expect(isValidConfig(configWithInvalidOptional)).toBe(true)
|
147
|
+
})
|
148
|
+
|
149
|
+
it("performs deep validation of optional fields in development", () => {
|
150
|
+
process.env.NODE_ENV = "development"
|
151
|
+
|
152
|
+
// Invalid integrity config
|
153
|
+
const configWithInvalidOptional = {
|
154
|
+
...validConfig,
|
155
|
+
integrity: {
|
156
|
+
enabled: "not-a-boolean", // Invalid type
|
157
|
+
cross_origin: "anonymous"
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
// Should fail because deep validation runs in development
|
162
|
+
expect(isValidConfig(configWithInvalidOptional)).toBe(false)
|
163
|
+
})
|
164
|
+
|
165
|
+
it("performs deep validation in production with strict mode", () => {
|
166
|
+
process.env.NODE_ENV = "production"
|
167
|
+
process.env.SHAKAPACKER_STRICT_VALIDATION = "true"
|
168
|
+
|
169
|
+
// Invalid integrity config
|
170
|
+
const configWithInvalidOptional = {
|
171
|
+
...validConfig,
|
172
|
+
integrity: {
|
173
|
+
enabled: "not-a-boolean", // Invalid type
|
174
|
+
cross_origin: "anonymous"
|
175
|
+
}
|
176
|
+
}
|
177
|
+
|
178
|
+
// Should fail because strict validation is enabled
|
179
|
+
expect(isValidConfig(configWithInvalidOptional)).toBe(false)
|
180
|
+
})
|
181
|
+
})
|
182
|
+
})
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shakapacker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 9.0.0.beta.
|
4
|
+
version: 9.0.0.beta.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
@@ -147,6 +147,7 @@ files:
|
|
147
147
|
- ".github/workflows/test-bundlers.yml"
|
148
148
|
- ".gitignore"
|
149
149
|
- ".node-version"
|
150
|
+
- ".npmignore"
|
150
151
|
- ".rspec"
|
151
152
|
- ".rubocop.yml"
|
152
153
|
- ".yalcignore"
|
@@ -180,8 +181,10 @@ files:
|
|
180
181
|
- docs/sprockets.md
|
181
182
|
- docs/style_loader_vs_mini_css.md
|
182
183
|
- docs/subresource_integrity.md
|
184
|
+
- docs/transpiler-migration.md
|
183
185
|
- docs/transpiler-performance.md
|
184
186
|
- docs/troubleshooting.md
|
187
|
+
- docs/typescript-migration.md
|
185
188
|
- docs/typescript.md
|
186
189
|
- docs/using_esbuild_loader.md
|
187
190
|
- docs/using_swc_loader.md
|
@@ -248,15 +251,16 @@ files:
|
|
248
251
|
- lib/tasks/shakapacker/verify_config.rake
|
249
252
|
- lib/tasks/shakapacker/verify_install.rake
|
250
253
|
- package.json
|
254
|
+
- package/.npmignore
|
251
255
|
- package/babel/preset.js
|
252
256
|
- package/config.ts
|
253
257
|
- package/dev_server.ts
|
254
258
|
- package/env.ts
|
255
|
-
- package/environments/base.js
|
256
259
|
- package/environments/base.ts
|
257
|
-
- package/environments/development.
|
258
|
-
- package/environments/production.
|
259
|
-
- package/environments/test.
|
260
|
+
- package/environments/development.ts
|
261
|
+
- package/environments/production.ts
|
262
|
+
- package/environments/test.ts
|
263
|
+
- package/environments/types.ts
|
260
264
|
- package/esbuild/index.js
|
261
265
|
- package/index.d.ts
|
262
266
|
- package/index.ts
|
@@ -282,13 +286,17 @@ files:
|
|
282
286
|
- package/rules/webpack.js
|
283
287
|
- package/swc/index.js
|
284
288
|
- package/types.ts
|
289
|
+
- package/types/README.md
|
290
|
+
- package/types/index.ts
|
285
291
|
- package/utils/configPath.ts
|
286
292
|
- package/utils/debug.ts
|
287
293
|
- package/utils/defaultConfigPath.ts
|
294
|
+
- package/utils/errorCodes.ts
|
288
295
|
- package/utils/errorHelpers.ts
|
289
296
|
- package/utils/getStyleRule.ts
|
290
297
|
- package/utils/helpers.ts
|
291
298
|
- package/utils/inliningCss.ts
|
299
|
+
- package/utils/pathValidation.ts
|
292
300
|
- package/utils/requireOrError.ts
|
293
301
|
- package/utils/snakeToCamelCase.ts
|
294
302
|
- package/utils/typeGuards.ts
|
@@ -296,6 +304,7 @@ files:
|
|
296
304
|
- package/webpack-types.d.ts
|
297
305
|
- package/webpackDevServerConfig.ts
|
298
306
|
- prettier.config.js
|
307
|
+
- scripts/remove-use-strict.js
|
299
308
|
- shakapacker.gemspec
|
300
309
|
- test/helpers.js
|
301
310
|
- test/package/config.test.js
|
@@ -318,9 +327,14 @@ files:
|
|
318
327
|
- test/package/rules/webpack.test.js
|
319
328
|
- test/package/staging.test.js
|
320
329
|
- test/package/test.test.js
|
330
|
+
- test/package/transpiler-defaults.test.js
|
321
331
|
- test/peer-dependencies.sh
|
322
332
|
- test/resolver.js
|
333
|
+
- test/scripts/remove-use-strict.test.js
|
323
334
|
- test/typescript/build.test.js
|
335
|
+
- test/typescript/environments.test.js
|
336
|
+
- test/typescript/pathValidation.test.js
|
337
|
+
- test/typescript/securityValidation.test.js
|
324
338
|
- tools/README.md
|
325
339
|
- tools/css-modules-v9-codemod.js
|
326
340
|
- tsconfig.json
|
@@ -329,7 +343,7 @@ homepage: https://github.com/shakacode/shakapacker
|
|
329
343
|
licenses:
|
330
344
|
- MIT
|
331
345
|
metadata:
|
332
|
-
source_code_uri: https://github.com/shakacode/shakapacker/tree/v9.0.0.beta.
|
346
|
+
source_code_uri: https://github.com/shakacode/shakapacker/tree/v9.0.0.beta.7
|
333
347
|
rdoc_options: []
|
334
348
|
require_paths:
|
335
349
|
- lib
|
@@ -369,6 +383,11 @@ test_files:
|
|
369
383
|
- test/package/rules/webpack.test.js
|
370
384
|
- test/package/staging.test.js
|
371
385
|
- test/package/test.test.js
|
386
|
+
- test/package/transpiler-defaults.test.js
|
372
387
|
- test/peer-dependencies.sh
|
373
388
|
- test/resolver.js
|
389
|
+
- test/scripts/remove-use-strict.test.js
|
374
390
|
- test/typescript/build.test.js
|
391
|
+
- test/typescript/environments.test.js
|
392
|
+
- test/typescript/pathValidation.test.js
|
393
|
+
- test/typescript/securityValidation.test.js
|
@@ -1,103 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
/* eslint global-require: 0 */
|
3
|
-
/* eslint import/no-dynamic-require: 0 */
|
4
|
-
const { basename, dirname, join, relative, resolve } = require("path");
|
5
|
-
const { existsSync, readdirSync } = require("fs");
|
6
|
-
const extname = require("path-complete-extname");
|
7
|
-
const config = require("../config");
|
8
|
-
const { isProduction } = require("../env");
|
9
|
-
const pluginsPath = resolve(__dirname, "..", "plugins", `${config.assets_bundler}.js`);
|
10
|
-
const { getPlugins } = require(pluginsPath);
|
11
|
-
const rulesPath = resolve(__dirname, "..", "rules", `${config.assets_bundler}.js`);
|
12
|
-
const rules = require(rulesPath);
|
13
|
-
// Don't use contentHash except for production for performance
|
14
|
-
// https://webpack.js.org/guides/build-performance/#avoid-production-specific-tooling
|
15
|
-
const hash = isProduction || config.useContentHash ? "-[contenthash]" : "";
|
16
|
-
const getFilesInDirectory = (dir, includeNested) => {
|
17
|
-
if (!existsSync(dir)) {
|
18
|
-
return [];
|
19
|
-
}
|
20
|
-
return readdirSync(dir, { withFileTypes: true }).flatMap((dirent) => {
|
21
|
-
const filePath = join(dir, dirent.name);
|
22
|
-
if (dirent.isDirectory() && includeNested) {
|
23
|
-
return getFilesInDirectory(filePath, includeNested);
|
24
|
-
}
|
25
|
-
if (dirent.isFile()) {
|
26
|
-
return filePath;
|
27
|
-
}
|
28
|
-
return [];
|
29
|
-
});
|
30
|
-
};
|
31
|
-
const getEntryObject = () => {
|
32
|
-
const entries = {};
|
33
|
-
const rootPath = join(config.source_path, config.source_entry_path);
|
34
|
-
if (config.source_entry_path === "/" && config.nested_entries) {
|
35
|
-
throw new Error(`Invalid Shakapacker configuration detected!\n\n` +
|
36
|
-
`You have set source_entry_path to '/' with nested_entries enabled.\n` +
|
37
|
-
`This would create webpack entry points for EVERY file in your source directory,\n` +
|
38
|
-
`which would severely impact build performance.\n\n` +
|
39
|
-
`To fix this issue, either:\n` +
|
40
|
-
`1. Set 'nested_entries: false' in your shakapacker.yml\n` +
|
41
|
-
`2. Change 'source_entry_path' to a specific subdirectory (e.g., 'packs')\n` +
|
42
|
-
`3. Or use both options for better organization of your entry points`);
|
43
|
-
}
|
44
|
-
getFilesInDirectory(rootPath, config.nested_entries).forEach((path) => {
|
45
|
-
const namespace = relative(join(rootPath), dirname(path));
|
46
|
-
const name = join(namespace, basename(path, extname(path)));
|
47
|
-
const assetPath = resolve(path);
|
48
|
-
// Allows for multiple filetypes per entry (https://webpack.js.org/guides/entry-advanced/)
|
49
|
-
// Transforms the config object value to an array with all values under the same name
|
50
|
-
const previousPaths = entries[name];
|
51
|
-
if (previousPaths) {
|
52
|
-
const pathArray = Array.isArray(previousPaths)
|
53
|
-
? previousPaths
|
54
|
-
: [previousPaths];
|
55
|
-
pathArray.push(assetPath);
|
56
|
-
entries[name] = pathArray;
|
57
|
-
}
|
58
|
-
else {
|
59
|
-
entries[name] = assetPath;
|
60
|
-
}
|
61
|
-
});
|
62
|
-
return entries;
|
63
|
-
};
|
64
|
-
const getModulePaths = () => {
|
65
|
-
const result = [resolve(config.source_path)];
|
66
|
-
if (config.additional_paths) {
|
67
|
-
config.additional_paths.forEach((path) => result.push(resolve(path)));
|
68
|
-
}
|
69
|
-
result.push("node_modules");
|
70
|
-
return result;
|
71
|
-
};
|
72
|
-
const baseConfig = {
|
73
|
-
mode: "production",
|
74
|
-
output: {
|
75
|
-
filename: `js/[name]${hash}.js`,
|
76
|
-
chunkFilename: `js/[name]${hash}.chunk.js`,
|
77
|
-
// https://webpack.js.org/configuration/output/#outputhotupdatechunkfilename
|
78
|
-
hotUpdateChunkFilename: "js/[id].[fullhash].hot-update.js",
|
79
|
-
path: config.outputPath,
|
80
|
-
publicPath: config.publicPath,
|
81
|
-
// This is required for SRI to work.
|
82
|
-
crossOriginLoading: config.integrity && config.integrity.enabled
|
83
|
-
? config.integrity.cross_origin
|
84
|
-
: false
|
85
|
-
},
|
86
|
-
entry: getEntryObject(),
|
87
|
-
resolve: {
|
88
|
-
extensions: [".js", ".jsx", ".mjs", ".ts", ".tsx", ".coffee"],
|
89
|
-
modules: getModulePaths()
|
90
|
-
},
|
91
|
-
plugins: getPlugins(),
|
92
|
-
resolveLoader: {
|
93
|
-
modules: ["node_modules"]
|
94
|
-
},
|
95
|
-
optimization: {
|
96
|
-
splitChunks: { chunks: "all" },
|
97
|
-
runtimeChunk: "single"
|
98
|
-
},
|
99
|
-
module: {
|
100
|
-
rules
|
101
|
-
}
|
102
|
-
};
|
103
|
-
module.exports = baseConfig;
|
@@ -1,19 +0,0 @@
|
|
1
|
-
const { merge } = require("webpack-merge")
|
2
|
-
const config = require("../config")
|
3
|
-
const baseConfig = require("./base")
|
4
|
-
|
5
|
-
const rspackTestConfig = () => ({
|
6
|
-
mode: "development",
|
7
|
-
devtool: "cheap-module-source-map",
|
8
|
-
// Disable file watching in test mode
|
9
|
-
watchOptions: {
|
10
|
-
ignored: /node_modules/
|
11
|
-
}
|
12
|
-
})
|
13
|
-
|
14
|
-
const webpackTestConfig = () => ({})
|
15
|
-
|
16
|
-
const bundlerConfig =
|
17
|
-
config.assets_bundler === "rspack" ? rspackTestConfig() : webpackTestConfig()
|
18
|
-
|
19
|
-
module.exports = merge(baseConfig, bundlerConfig)
|