shakapacker 9.0.0.beta.7 → 9.0.0.beta.8
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/.eslintrc.fast.js +40 -0
- data/.eslintrc.js +48 -0
- data/.gitignore +1 -3
- data/.npmignore +1 -0
- data/CHANGELOG.md +64 -1
- data/CONTRIBUTING.md +75 -21
- data/Gemfile.lock +1 -1
- data/TODO.md +15 -16
- data/lib/shakapacker/version.rb +1 -1
- data/package/babel/preset.ts +56 -0
- data/package/esbuild/index.ts +42 -0
- data/package/optimization/rspack.ts +36 -0
- data/package/optimization/{webpack.js → webpack.ts} +12 -4
- data/package/plugins/{rspack.js → rspack.ts} +20 -5
- data/package/plugins/{webpack.js → webpack.ts} +2 -2
- data/package/rspack/{index.js → index.ts} +17 -10
- data/package/rules/{babel.js → babel.ts} +1 -1
- data/package/rules/{coffee.js → coffee.ts} +1 -1
- data/package/rules/{css.js → css.ts} +1 -1
- data/package/rules/{erb.js → erb.ts} +1 -1
- data/package/rules/{esbuild.js → esbuild.ts} +2 -2
- data/package/rules/{file.js → file.ts} +11 -6
- data/package/rules/{jscommon.js → jscommon.ts} +4 -4
- data/package/rules/{less.js → less.ts} +3 -3
- data/package/rules/raw.ts +25 -0
- data/package/rules/{rspack.js → rspack.ts} +21 -11
- data/package/rules/{sass.js → sass.ts} +1 -1
- data/package/rules/{stylus.js → stylus.ts} +3 -7
- data/package/rules/{swc.js → swc.ts} +2 -2
- data/package/rules/{webpack.js → webpack.ts} +1 -1
- data/package/swc/index.ts +54 -0
- data/package.json +22 -2
- data/scripts/type-check-no-emit.js +27 -0
- data/test/package/rules/raw.test.js +40 -7
- data/test/package/rules/webpack.test.js +21 -2
- data/tsconfig.eslint.json +16 -0
- data/tsconfig.json +9 -10
- data/yarn.lock +415 -6
- metadata +27 -24
- data/package/babel/preset.js +0 -48
- data/package/esbuild/index.js +0 -40
- data/package/optimization/rspack.js +0 -29
- data/package/rules/raw.js +0 -15
- data/package/swc/index.js +0 -50
@@ -6,7 +6,22 @@ const config = require("../config")
|
|
6
6
|
const { isProduction } = require("../env")
|
7
7
|
const { moduleExists } = require("../utils/helpers")
|
8
8
|
|
9
|
-
|
9
|
+
interface ManifestFile {
|
10
|
+
name: string
|
11
|
+
path: string
|
12
|
+
}
|
13
|
+
|
14
|
+
interface EntrypointAssets {
|
15
|
+
js: string[]
|
16
|
+
css: string[]
|
17
|
+
}
|
18
|
+
|
19
|
+
interface Manifest {
|
20
|
+
entrypoints?: Record<string, { assets: EntrypointAssets }>
|
21
|
+
[key: string]: string | { assets: EntrypointAssets } | Record<string, { assets: EntrypointAssets }> | undefined
|
22
|
+
}
|
23
|
+
|
24
|
+
const getPlugins = (): unknown[] => {
|
10
25
|
const plugins = [
|
11
26
|
new rspack.EnvironmentPlugin(process.env),
|
12
27
|
new RspackManifestPlugin({
|
@@ -14,8 +29,8 @@ const getPlugins = () => {
|
|
14
29
|
publicPath: config.publicPathWithoutCDN,
|
15
30
|
writeToFileEmit: true,
|
16
31
|
// rspack-manifest-plugin uses different option names than webpack-assets-manifest
|
17
|
-
generate: (seed, files, entrypoints) => {
|
18
|
-
const manifest = seed || {}
|
32
|
+
generate: (seed: Manifest | null, files: ManifestFile[], entrypoints: Record<string, string[]>) => {
|
33
|
+
const manifest: Manifest = seed || {}
|
19
34
|
|
20
35
|
// Add files mapping first
|
21
36
|
files.forEach((file) => {
|
@@ -23,7 +38,7 @@ const getPlugins = () => {
|
|
23
38
|
})
|
24
39
|
|
25
40
|
// Add entrypoints information compatible with Shakapacker expectations
|
26
|
-
const entrypointsManifest = {}
|
41
|
+
const entrypointsManifest: Record<string, { assets: EntrypointAssets }> = {}
|
27
42
|
Object.entries(entrypoints).forEach(
|
28
43
|
([entrypointName, entrypointFiles]) => {
|
29
44
|
const jsFiles = entrypointFiles
|
@@ -83,6 +98,6 @@ const getPlugins = () => {
|
|
83
98
|
return plugins
|
84
99
|
}
|
85
100
|
|
86
|
-
|
101
|
+
export = {
|
87
102
|
getPlugins
|
88
103
|
}
|
@@ -6,7 +6,7 @@ const config = require("../config")
|
|
6
6
|
const { isProduction } = require("../env")
|
7
7
|
const { moduleExists } = require("../utils/helpers")
|
8
8
|
|
9
|
-
const getPlugins = () => {
|
9
|
+
const getPlugins = (): unknown[] => {
|
10
10
|
// TODO: Remove WebpackAssetsManifestConstructor workaround when dropping 'webpack-assets-manifest < 6.0.0' (Node >=20.10.0) support
|
11
11
|
const WebpackAssetsManifestConstructor =
|
12
12
|
"WebpackAssetsManifest" in WebpackAssetsManifest
|
@@ -57,6 +57,6 @@ const getPlugins = () => {
|
|
57
57
|
return plugins
|
58
58
|
}
|
59
59
|
|
60
|
-
|
60
|
+
export = {
|
61
61
|
getPlugins
|
62
62
|
}
|
@@ -1,14 +1,15 @@
|
|
1
1
|
/* eslint global-require: 0 */
|
2
2
|
/* eslint import/no-dynamic-require: 0 */
|
3
3
|
|
4
|
+
// Mixed require/import syntax:
|
5
|
+
// - Using require() for compiled JS modules that may not have proper ES module exports
|
6
|
+
// - Using import for type-only imports and Node.js built-in modules
|
4
7
|
const webpackMerge = require("webpack-merge")
|
5
|
-
|
6
|
-
|
8
|
+
import { resolve } from "path"
|
9
|
+
import { existsSync } from "fs"
|
10
|
+
import type { RspackConfigWithDevServer } from "../environments/types"
|
7
11
|
const config = require("../config")
|
8
12
|
const baseConfig = require("../environments/base")
|
9
|
-
|
10
|
-
const rulesPath = resolve(__dirname, "../rules", "rspack.js")
|
11
|
-
const rules = require(rulesPath)
|
12
13
|
const devServer = require("../dev_server")
|
13
14
|
const env = require("../env")
|
14
15
|
const { moduleExists, canProcess } = require("../utils/helpers")
|
@@ -17,7 +18,10 @@ const { getPlugins } = require("../plugins/rspack")
|
|
17
18
|
const { getOptimization } = require("../optimization/rspack")
|
18
19
|
const { validateRspackDependencies } = require("../utils/validateDependencies")
|
19
20
|
|
20
|
-
const
|
21
|
+
const rulesPath = resolve(__dirname, "../rules", "rspack.js")
|
22
|
+
const rules = require(rulesPath)
|
23
|
+
|
24
|
+
const generateRspackConfig = (extraConfig: RspackConfigWithDevServer = {}, ...extraArgs: unknown[]): RspackConfigWithDevServer => {
|
21
25
|
// Validate required dependencies first
|
22
26
|
validateRspackDependencies()
|
23
27
|
if (extraArgs.length > 0) {
|
@@ -28,10 +32,11 @@ const generateRspackConfig = (extraConfig = {}, ...extraArgs) => {
|
|
28
32
|
|
29
33
|
const { nodeEnv } = env
|
30
34
|
const path = resolve(__dirname, "../environments", `${nodeEnv}.js`)
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
31
36
|
const environmentConfig = existsSync(path) ? require(path) : baseConfig
|
32
37
|
|
33
38
|
// Create base rspack config
|
34
|
-
const rspackConfig = {
|
39
|
+
const rspackConfig: RspackConfigWithDevServer = {
|
35
40
|
...environmentConfig,
|
36
41
|
module: {
|
37
42
|
rules
|
@@ -43,7 +48,10 @@ const generateRspackConfig = (extraConfig = {}, ...extraArgs) => {
|
|
43
48
|
return webpackMerge.merge({}, rspackConfig, extraConfig)
|
44
49
|
}
|
45
50
|
|
46
|
-
|
51
|
+
// Re-export webpack-merge utilities for backward compatibility
|
52
|
+
export { merge, mergeWithCustomize, mergeWithRules, unique } from "webpack-merge"
|
53
|
+
|
54
|
+
export {
|
47
55
|
config, // shakapacker.yml
|
48
56
|
devServer,
|
49
57
|
generateRspackConfig,
|
@@ -52,6 +60,5 @@ module.exports = {
|
|
52
60
|
rules,
|
53
61
|
moduleExists,
|
54
62
|
canProcess,
|
55
|
-
inliningCss
|
56
|
-
...webpackMerge
|
63
|
+
inliningCss
|
57
64
|
}
|
@@ -3,7 +3,7 @@ const { javascript_transpiler: javascriptTranspiler } = require("../config")
|
|
3
3
|
const { isProduction } = require("../env")
|
4
4
|
const jscommon = require("./jscommon")
|
5
5
|
|
6
|
-
|
6
|
+
export = loaderMatches(javascriptTranspiler, "babel", () => ({
|
7
7
|
test: /\.(js|jsx|mjs|ts|tsx|coffee)?(\.erb)?$/,
|
8
8
|
...jscommon,
|
9
9
|
use: [
|
@@ -2,7 +2,7 @@ const { canProcess } = require("../utils/helpers")
|
|
2
2
|
|
3
3
|
const runner = /^win/.test(process.platform) ? "ruby " : ""
|
4
4
|
|
5
|
-
|
5
|
+
export = canProcess("rails-erb-loader", (resolvedPath: string) => ({
|
6
6
|
test: /\.erb$/,
|
7
7
|
enforce: "pre",
|
8
8
|
exclude: /node_modules/,
|
@@ -3,8 +3,8 @@ const { getEsbuildLoaderConfig } = require("../esbuild")
|
|
3
3
|
const { javascript_transpiler: javascriptTranspiler } = require("../config")
|
4
4
|
const jscommon = require("./jscommon")
|
5
5
|
|
6
|
-
|
6
|
+
export = loaderMatches(javascriptTranspiler, "esbuild", () => ({
|
7
7
|
test: /\.(ts|tsx|js|jsx|mjs|coffee)?(\.erb)?$/,
|
8
8
|
...jscommon,
|
9
|
-
use: ({ resource }) => getEsbuildLoaderConfig(resource)
|
9
|
+
use: ({ resource }: { resource: string }) => getEsbuildLoaderConfig(resource)
|
10
10
|
}))
|
@@ -1,21 +1,25 @@
|
|
1
|
-
|
1
|
+
import { dirname, sep, normalize } from "path"
|
2
2
|
const {
|
3
3
|
additional_paths: additionalPaths,
|
4
4
|
source_path: sourcePath
|
5
5
|
} = require("../config")
|
6
6
|
|
7
|
-
|
7
|
+
export = {
|
8
8
|
test: /\.(bmp|gif|jpe?g|png|tiff|ico|avif|webp|eot|otf|ttf|woff|woff2|svg)$/,
|
9
9
|
exclude: /\.(js|mjs|jsx|ts|tsx)$/,
|
10
10
|
type: "asset/resource",
|
11
11
|
generator: {
|
12
|
-
filename: (pathData) => {
|
12
|
+
filename: (pathData: { filename?: string }) => {
|
13
|
+
// Guard against null/undefined pathData or filename
|
14
|
+
if (!pathData || !pathData.filename) {
|
15
|
+
return `static/[name]-[hash][ext][query]`
|
16
|
+
}
|
13
17
|
const path = normalize(dirname(pathData.filename))
|
14
|
-
const stripPaths = [...additionalPaths, sourcePath].map((p) =>
|
18
|
+
const stripPaths = [...additionalPaths, sourcePath].map((p: string) =>
|
15
19
|
normalize(p)
|
16
20
|
)
|
17
21
|
|
18
|
-
const selectedStripPath = stripPaths.find((includePath) =>
|
22
|
+
const selectedStripPath = stripPaths.find((includePath: string) =>
|
19
23
|
path.startsWith(includePath)
|
20
24
|
)
|
21
25
|
|
@@ -23,9 +27,10 @@ module.exports = {
|
|
23
27
|
return `static/[name]-[hash][ext][query]`
|
24
28
|
}
|
25
29
|
|
30
|
+
// Split on both forward and backward slashes for cross-platform compatibility
|
26
31
|
const folders = path
|
27
32
|
.replace(selectedStripPath, "")
|
28
|
-
.split(
|
33
|
+
.split(/[\\/]/)
|
29
34
|
.filter(Boolean)
|
30
35
|
|
31
36
|
const foldersWithStatic = ["static", ...folders].join("/")
|
@@ -1,11 +1,11 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
import { resolve } from "path"
|
2
|
+
import { realpathSync } from "fs"
|
3
3
|
const {
|
4
4
|
source_path: sourcePath,
|
5
5
|
additional_paths: additionalPaths
|
6
6
|
} = require("../config")
|
7
7
|
|
8
|
-
const inclusions = [sourcePath, ...additionalPaths].map((p) => {
|
8
|
+
const inclusions = [sourcePath, ...additionalPaths].map((p: string) => {
|
9
9
|
try {
|
10
10
|
return realpathSync(p)
|
11
11
|
} catch (e) {
|
@@ -13,7 +13,7 @@ const inclusions = [sourcePath, ...additionalPaths].map((p) => {
|
|
13
13
|
}
|
14
14
|
})
|
15
15
|
|
16
|
-
|
16
|
+
export = {
|
17
17
|
include: inclusions,
|
18
18
|
exclude: [
|
19
19
|
{
|
@@ -1,4 +1,3 @@
|
|
1
|
-
const path = require("path")
|
2
1
|
const { canProcess } = require("../utils/helpers")
|
3
2
|
const { getStyleRule } = require("../utils/getStyleRule")
|
4
3
|
|
@@ -7,13 +6,14 @@ const {
|
|
7
6
|
source_path: sourcePath
|
8
7
|
} = require("../config")
|
9
8
|
|
10
|
-
|
9
|
+
export = canProcess("less-loader", (resolvedPath: string) =>
|
11
10
|
getStyleRule(/\.(less)(\.erb)?$/i, [
|
12
11
|
{
|
13
12
|
loader: resolvedPath,
|
14
13
|
options: {
|
15
14
|
lessOptions: {
|
16
|
-
paths
|
15
|
+
// Additional paths for Less imports (node_modules is resolved automatically)
|
16
|
+
paths: [sourcePath, ...paths]
|
17
17
|
},
|
18
18
|
sourceMap: true
|
19
19
|
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
const config = require("../config")
|
2
|
+
|
3
|
+
const rspackRawConfig = () => ({
|
4
|
+
resourceQuery: /raw/,
|
5
|
+
type: "asset/source"
|
6
|
+
})
|
7
|
+
|
8
|
+
const webpackRawConfig = () => ({
|
9
|
+
oneOf: [
|
10
|
+
{
|
11
|
+
// Match any file with ?raw query parameter
|
12
|
+
resourceQuery: /raw/,
|
13
|
+
type: "asset/source"
|
14
|
+
},
|
15
|
+
{
|
16
|
+
// Fallback: match .html files without query
|
17
|
+
test: /\.html$/,
|
18
|
+
exclude: /\.(js|mjs|jsx|ts|tsx)$/,
|
19
|
+
type: "asset/source"
|
20
|
+
}
|
21
|
+
]
|
22
|
+
})
|
23
|
+
|
24
|
+
export =
|
25
|
+
config.assets_bundler === "rspack" ? rspackRawConfig() : webpackRawConfig()
|
@@ -141,26 +141,36 @@ if (erb) {
|
|
141
141
|
}
|
142
142
|
|
143
143
|
// File/asset handling using Rspack's built-in asset modules
|
144
|
+
// This is a critical rule required for proper asset handling
|
144
145
|
debug("Adding file/asset handling rule...")
|
145
146
|
const file = require("./file")
|
146
147
|
|
147
|
-
if (file) {
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
148
|
+
if (!file) {
|
149
|
+
throw new Error(
|
150
|
+
"CRITICAL: file rule configuration returned null. " +
|
151
|
+
"Asset handling is required for proper bundling. " +
|
152
|
+
"Please ensure the file rule module exports a valid rule configuration."
|
153
|
+
)
|
152
154
|
}
|
153
155
|
|
156
|
+
debug("Successfully added file/asset rule")
|
157
|
+
rules.push(file)
|
158
|
+
|
154
159
|
// Raw file loading
|
160
|
+
// This is a critical rule required for raw file imports
|
155
161
|
debug("Adding raw file loading rule...")
|
156
162
|
const raw = require("./raw")
|
157
163
|
|
158
|
-
if (raw) {
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
164
|
+
if (!raw) {
|
165
|
+
throw new Error(
|
166
|
+
"CRITICAL: raw rule configuration returned null. " +
|
167
|
+
"Raw file loading is required for proper bundling. " +
|
168
|
+
"Please ensure the raw rule module exports a valid rule configuration."
|
169
|
+
)
|
163
170
|
}
|
164
171
|
|
172
|
+
debug("Successfully added raw file rule")
|
173
|
+
rules.push(raw)
|
174
|
+
|
165
175
|
debug(`Rspack rules configuration complete. Total rules: ${rules.length}`)
|
166
|
-
|
176
|
+
export = rules
|
@@ -4,7 +4,7 @@ const { getStyleRule } = require("../utils/getStyleRule")
|
|
4
4
|
const { canProcess, packageMajorVersion } = require("../utils/helpers")
|
5
5
|
const { additional_paths: extraPaths } = require("../config")
|
6
6
|
|
7
|
-
|
7
|
+
export = canProcess("sass-loader", (resolvedPath: string) => {
|
8
8
|
const optionKey =
|
9
9
|
packageMajorVersion("sass-loader") > 15 ? "loadPaths" : "includePaths"
|
10
10
|
return getStyleRule(/\.(scss|sass)(\.erb)?$/i, [
|
@@ -1,4 +1,3 @@
|
|
1
|
-
const path = require("path")
|
2
1
|
const { canProcess } = require("../utils/helpers")
|
3
2
|
const { getStyleRule } = require("../utils/getStyleRule")
|
4
3
|
|
@@ -7,17 +6,14 @@ const {
|
|
7
6
|
source_path: sourcePath
|
8
7
|
} = require("../config")
|
9
8
|
|
10
|
-
|
9
|
+
export = canProcess("stylus-loader", (resolvedPath: string) =>
|
11
10
|
getStyleRule(/\.(styl(us)?)(\.erb)?$/i, [
|
12
11
|
{
|
13
12
|
loader: resolvedPath,
|
14
13
|
options: {
|
15
14
|
stylusOptions: {
|
16
|
-
|
17
|
-
|
18
|
-
sourcePath,
|
19
|
-
...paths
|
20
|
-
]
|
15
|
+
// Additional paths for Stylus imports (node_modules is resolved automatically)
|
16
|
+
include: [sourcePath, ...paths]
|
21
17
|
},
|
22
18
|
sourceMap: true
|
23
19
|
}
|
@@ -3,8 +3,8 @@ const { getSwcLoaderConfig } = require("../swc")
|
|
3
3
|
const { javascript_transpiler: javascriptTranspiler } = require("../config")
|
4
4
|
const jscommon = require("./jscommon")
|
5
5
|
|
6
|
-
|
6
|
+
export = loaderMatches(javascriptTranspiler, "swc", () => ({
|
7
7
|
test: /\.(ts|tsx|js|jsx|mjs|coffee)?(\.erb)?$/,
|
8
8
|
...jscommon,
|
9
|
-
use: ({ resource }) => getSwcLoaderConfig(resource)
|
9
|
+
use: ({ resource }: { resource: string }) => getSwcLoaderConfig(resource)
|
10
10
|
}))
|
@@ -0,0 +1,54 @@
|
|
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 JSX_FILE_REGEX = /\.(jsx|tsx)(\.erb)?$/
|
10
|
+
const TYPESCRIPT_FILE_REGEX = /\.(ts|tsx)(\.erb)?$/
|
11
|
+
|
12
|
+
const isJsxFile = (filename: string): boolean => !!filename.match(JSX_FILE_REGEX)
|
13
|
+
|
14
|
+
const isTypescriptFile = (filename: string): boolean => !!filename.match(TYPESCRIPT_FILE_REGEX)
|
15
|
+
|
16
|
+
const getCustomConfig = (): Partial<RuleSetRule> => {
|
17
|
+
const path = resolve("config", "swc.config.js")
|
18
|
+
if (existsSync(path)) {
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
20
|
+
return require(path)
|
21
|
+
}
|
22
|
+
return {}
|
23
|
+
}
|
24
|
+
|
25
|
+
const getSwcLoaderConfig = (filenameToProcess: string): RuleSetRule => {
|
26
|
+
const customConfig = getCustomConfig()
|
27
|
+
const isTs = isTypescriptFile(filenameToProcess)
|
28
|
+
const isJsx = isJsxFile(filenameToProcess)
|
29
|
+
const jsxKey = isTs ? "tsx" : "jsx"
|
30
|
+
|
31
|
+
const defaultConfig: RuleSetRule = {
|
32
|
+
loader: require.resolve("swc-loader"),
|
33
|
+
options: {
|
34
|
+
jsc: {
|
35
|
+
parser: {
|
36
|
+
dynamicImport: true,
|
37
|
+
syntax: isTs ? "typescript" : "ecmascript",
|
38
|
+
[jsxKey]: isJsx
|
39
|
+
},
|
40
|
+
loose: true
|
41
|
+
},
|
42
|
+
sourceMaps: true,
|
43
|
+
env: {
|
44
|
+
coreJs: 3,
|
45
|
+
exclude: ["transform-typeof-symbol"],
|
46
|
+
mode: "entry"
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
return merge(defaultConfig, customConfig)
|
52
|
+
}
|
53
|
+
|
54
|
+
export { getSwcLoaderConfig }
|
data/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "shakapacker",
|
3
|
-
"version": "9.0.0-beta.
|
3
|
+
"version": "9.0.0-beta.8",
|
4
4
|
"description": "Use webpack to manage app-like JavaScript modules in Rails",
|
5
5
|
"homepage": "https://github.com/shakacode/shakapacker",
|
6
6
|
"bugs": {
|
@@ -34,6 +34,7 @@
|
|
34
34
|
"build": "tsc && node scripts/remove-use-strict.js && yarn prettier --write 'package/**/*.js'",
|
35
35
|
"build:types": "tsc",
|
36
36
|
"lint": "eslint .",
|
37
|
+
"lint:fast": "eslint . --ext .js,.jsx,.ts,.tsx --config .eslintrc.fast.js",
|
37
38
|
"test": "jest",
|
38
39
|
"type-check": "tsc --noEmit",
|
39
40
|
"prepublishOnly": "yarn build && yarn type-check"
|
@@ -46,12 +47,15 @@
|
|
46
47
|
"devDependencies": {
|
47
48
|
"@rspack/cli": "^1.4.11",
|
48
49
|
"@rspack/core": "^1.4.11",
|
50
|
+
"@types/babel__core": "^7.20.5",
|
49
51
|
"@types/js-yaml": "^4.0.9",
|
50
52
|
"@types/node": "^24.5.2",
|
51
53
|
"@types/path-complete-extname": "^1.0.3",
|
52
54
|
"@types/webpack": "^5.28.5",
|
53
55
|
"@types/webpack-dev-server": "^4.7.2",
|
54
56
|
"@types/webpack-merge": "^5.0.0",
|
57
|
+
"@typescript-eslint/eslint-plugin": "^8.45.0",
|
58
|
+
"@typescript-eslint/parser": "^8.45.0",
|
55
59
|
"babel-loader": "^8.2.4",
|
56
60
|
"compression-webpack-plugin": "^9.0.0",
|
57
61
|
"css-loader": "^7.1.2",
|
@@ -65,7 +69,9 @@
|
|
65
69
|
"eslint-plugin-prettier": "^5.2.6",
|
66
70
|
"eslint-plugin-react": "^7.37.5",
|
67
71
|
"eslint-plugin-react-hooks": "^4.6.0",
|
72
|
+
"husky": "^9.1.7",
|
68
73
|
"jest": "^29.7.0",
|
74
|
+
"lint-staged": "^15.2.10",
|
69
75
|
"memory-fs": "^0.5.0",
|
70
76
|
"mini-css-extract-plugin": "^2.9.4",
|
71
77
|
"prettier": "^3.2.5",
|
@@ -83,8 +89,8 @@
|
|
83
89
|
"@babel/plugin-transform-runtime": "^7.17.0",
|
84
90
|
"@babel/preset-env": "^7.16.11",
|
85
91
|
"@babel/runtime": "^7.17.9",
|
86
|
-
"@rspack/core": "^1.0.0",
|
87
92
|
"@rspack/cli": "^1.0.0",
|
93
|
+
"@rspack/core": "^1.0.0",
|
88
94
|
"@rspack/plugin-react-refresh": "^1.0.0",
|
89
95
|
"@types/babel__core": "^7.0.0",
|
90
96
|
"@types/webpack": "^5.0.0",
|
@@ -183,6 +189,20 @@
|
|
183
189
|
}
|
184
190
|
},
|
185
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
|
+
},
|
186
206
|
"engines": {
|
187
207
|
"node": ">= 14",
|
188
208
|
"yarn": ">=1 <5"
|
@@ -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
|
+
}
|
@@ -1,12 +1,45 @@
|
|
1
|
-
const raw = require("../../../package/rules/raw")
|
2
|
-
|
3
1
|
describe("raw", () => {
|
4
|
-
|
5
|
-
|
2
|
+
describe("rspack bundler", () => {
|
3
|
+
beforeEach(() => {
|
4
|
+
jest.resetModules()
|
5
|
+
jest.doMock("../../../package/config", () => ({
|
6
|
+
assets_bundler: "rspack"
|
7
|
+
}))
|
8
|
+
})
|
9
|
+
|
10
|
+
afterEach(() => {
|
11
|
+
jest.dontMock("../../../package/config")
|
12
|
+
})
|
13
|
+
|
14
|
+
test("uses resourceQuery for any file with ?raw", () => {
|
15
|
+
const raw = require("../../../package/rules/raw")
|
16
|
+
expect(raw.resourceQuery).toStrictEqual(/raw/)
|
17
|
+
expect(raw.type).toBe("asset/source")
|
18
|
+
})
|
6
19
|
})
|
7
20
|
|
8
|
-
|
9
|
-
|
10
|
-
|
21
|
+
describe("webpack bundler", () => {
|
22
|
+
beforeEach(() => {
|
23
|
+
jest.resetModules()
|
24
|
+
jest.doMock("../../../package/config", () => ({
|
25
|
+
assets_bundler: "webpack"
|
26
|
+
}))
|
27
|
+
})
|
28
|
+
|
29
|
+
afterEach(() => {
|
30
|
+
jest.dontMock("../../../package/config")
|
31
|
+
})
|
32
|
+
|
33
|
+
test("supports ?raw query and .html fallback with oneOf", () => {
|
34
|
+
const raw = require("../../../package/rules/raw")
|
35
|
+
expect(raw.oneOf).toHaveLength(2)
|
36
|
+
// First rule: any file with ?raw
|
37
|
+
expect(raw.oneOf[0].resourceQuery).toStrictEqual(/raw/)
|
38
|
+
expect(raw.oneOf[0].type).toBe("asset/source")
|
39
|
+
// Second rule: .html files without query
|
40
|
+
expect(raw.oneOf[1].test.test(".html")).toBe(true)
|
41
|
+
expect(raw.oneOf[1].exclude.test(".js")).toBe(true)
|
42
|
+
expect(raw.oneOf[1].type).toBe("asset/source")
|
43
|
+
})
|
11
44
|
})
|
12
45
|
})
|
@@ -10,7 +10,26 @@ jest.mock("../../../package/utils/helpers", () => {
|
|
10
10
|
})
|
11
11
|
|
12
12
|
describe("index", () => {
|
13
|
-
test("rule tests are regexes", () => {
|
14
|
-
rules.
|
13
|
+
test("rule tests are regexes or oneOf arrays", () => {
|
14
|
+
const rulesWithTest = rules.filter((rule) => !rule.oneOf)
|
15
|
+
const rulesWithOneOf = rules.filter((rule) => rule.oneOf)
|
16
|
+
|
17
|
+
// Verify all non-oneOf rules have test property
|
18
|
+
rulesWithTest.forEach((rule) => {
|
19
|
+
expect(rule.test).toBeInstanceOf(RegExp)
|
20
|
+
})
|
21
|
+
|
22
|
+
// Verify all oneOf rules are properly structured
|
23
|
+
rulesWithOneOf.forEach((rule) => {
|
24
|
+
expect(Array.isArray(rule.oneOf)).toBe(true)
|
25
|
+
rule.oneOf.forEach((subRule) => {
|
26
|
+
// Each subRule must have either a test or resourceQuery property (RegExp)
|
27
|
+
const matchers = [
|
28
|
+
subRule.test instanceof RegExp,
|
29
|
+
subRule.resourceQuery instanceof RegExp
|
30
|
+
]
|
31
|
+
expect(matchers.some(Boolean)).toBe(true)
|
32
|
+
})
|
33
|
+
})
|
15
34
|
})
|
16
35
|
})
|
@@ -0,0 +1,16 @@
|
|
1
|
+
{
|
2
|
+
"extends": "./tsconfig.json",
|
3
|
+
"compilerOptions": {
|
4
|
+
"noEmit": true,
|
5
|
+
"rootDir": "."
|
6
|
+
},
|
7
|
+
"include": [
|
8
|
+
"package/**/*.ts",
|
9
|
+
"package/**/*.tsx",
|
10
|
+
"package/**/*.test.ts",
|
11
|
+
"package/**/*.spec.ts",
|
12
|
+
"test/**/*.ts",
|
13
|
+
"test/**/*.tsx"
|
14
|
+
],
|
15
|
+
"exclude": ["node_modules"]
|
16
|
+
}
|