shakapacker 8.3.0 → 9.0.0.beta.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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/STATUS.md +1 -0
  3. data/.github/workflows/dummy.yml +1 -1
  4. data/.github/workflows/generator.yml +4 -14
  5. data/.github/workflows/node.yml +1 -1
  6. data/CHANGELOG.md +17 -1
  7. data/Gemfile.lock +3 -3
  8. data/README.md +3 -3
  9. data/docs/css-modules-export-mode.md +288 -0
  10. data/docs/peer-dependencies.md +40 -0
  11. data/docs/react.md +2 -10
  12. data/docs/rspack.md +190 -0
  13. data/docs/subresource_integrity.md +54 -0
  14. data/docs/troubleshooting.md +5 -0
  15. data/lib/install/bin/shakapacker +14 -2
  16. data/lib/install/bin/shakapacker-rspack +13 -0
  17. data/lib/install/config/rspack/rspack.config.js +6 -0
  18. data/lib/install/config/shakapacker.yml +16 -3
  19. data/lib/install/package.json +30 -0
  20. data/lib/install/template.rb +13 -3
  21. data/lib/shakapacker/configuration.rb +16 -0
  22. data/lib/shakapacker/dev_server_runner.rb +17 -7
  23. data/lib/shakapacker/helper.rb +40 -4
  24. data/lib/shakapacker/manifest.rb +9 -3
  25. data/lib/shakapacker/rspack_runner.rb +57 -0
  26. data/lib/shakapacker/runner.rb +48 -2
  27. data/lib/shakapacker/version.rb +1 -1
  28. data/package/config.js +2 -0
  29. data/package/environments/base.js +16 -48
  30. data/package/environments/development.js +18 -3
  31. data/package/environments/production.js +24 -51
  32. data/package/environments/test.js +15 -1
  33. data/package/index.d.ts +14 -0
  34. data/package/index.js +4 -2
  35. data/package/optimization/rspack.js +25 -0
  36. data/package/optimization/webpack.js +49 -0
  37. data/package/plugins/rspack.js +104 -0
  38. data/package/plugins/webpack.js +62 -0
  39. data/package/rules/css.js +1 -1
  40. data/package/rules/file.js +11 -5
  41. data/package/rules/less.js +1 -1
  42. data/package/rules/raw.js +11 -1
  43. data/package/rules/rspack.js +96 -0
  44. data/package/rules/sass.js +6 -2
  45. data/package/rules/stylus.js +1 -1
  46. data/package/utils/getStyleRule.js +16 -3
  47. data/package/utils/requireOrError.js +15 -0
  48. data/package.json +19 -26
  49. data/test/package/config.test.js +40 -0
  50. data/test/package/environments/base.test.js +1 -1
  51. data/test/package/rules/{index.test.js → webpack.test.js} +1 -1
  52. data/yarn.lock +2146 -724
  53. metadata +22 -11
  54. /data/package/rules/{index.js → webpack.js} +0 -0
@@ -1,13 +1,28 @@
1
1
  const { merge } = require("webpack-merge")
2
-
2
+ const config = require("../config")
3
3
  const baseConfig = require("./base")
4
4
  const webpackDevServerConfig = require("../webpackDevServerConfig")
5
5
  const { runningWebpackDevServer } = require("../env")
6
6
 
7
- const devConfig = {
7
+ const webpackDevConfig = {
8
8
  mode: "development",
9
9
  devtool: "cheap-module-source-map",
10
10
  ...(runningWebpackDevServer && { devServer: webpackDevServerConfig() })
11
11
  }
12
12
 
13
- module.exports = merge(baseConfig, devConfig)
13
+ const rspackDevConfig = {
14
+ mode: "development",
15
+ devtool: "cheap-module-source-map",
16
+ // Force writing assets to disk in development for Rails compatibility
17
+ devServer: {
18
+ ...webpackDevServerConfig(),
19
+ devMiddleware: {
20
+ writeToDisk: true
21
+ }
22
+ }
23
+ }
24
+
25
+ const bundlerConfig =
26
+ config.bundler === "rspack" ? rspackDevConfig : webpackDevConfig
27
+
28
+ module.exports = merge(baseConfig, bundlerConfig)
@@ -2,46 +2,44 @@
2
2
  /* eslint import/no-dynamic-require: 0 */
3
3
 
4
4
  const { merge } = require("webpack-merge")
5
- const CompressionPlugin = require("compression-webpack-plugin")
6
- const TerserPlugin = require("terser-webpack-plugin")
5
+ const { resolve } = require("path")
7
6
  const baseConfig = require("./base")
8
7
  const { moduleExists } = require("../utils/helpers")
9
8
  const config = require("../config")
10
9
 
10
+ const path = resolve(__dirname, "..", "optimization", `${config.bundler}.js`)
11
+ const { getOptimization } = require(path)
12
+
13
+ let CompressionPlugin = null
14
+ if (moduleExists("compression-webpack-plugin")) {
15
+ // eslint-disable-next-line global-require
16
+ CompressionPlugin = require("compression-webpack-plugin")
17
+ }
18
+
11
19
  const getPlugins = () => {
12
20
  const plugins = []
13
21
 
14
- plugins.push(
15
- new CompressionPlugin({
16
- filename: "[path][base].gz[query]",
17
- algorithm: "gzip",
18
- test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
19
- })
20
- )
21
-
22
- if ("brotli" in process.versions) {
22
+ if (CompressionPlugin) {
23
23
  plugins.push(
24
24
  new CompressionPlugin({
25
- filename: "[path][base].br[query]",
26
- algorithm: "brotliCompress",
25
+ filename: "[path][base].gz[query]",
26
+ algorithm: "gzip",
27
27
  test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
28
28
  })
29
29
  )
30
- }
31
30
 
32
- return plugins
33
- }
34
-
35
- const tryCssMinimizer = () => {
36
- if (
37
- moduleExists("css-loader") &&
38
- moduleExists("css-minimizer-webpack-plugin")
39
- ) {
40
- const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
41
- return new CssMinimizerPlugin()
31
+ if ("brotli" in process.versions) {
32
+ plugins.push(
33
+ new CompressionPlugin({
34
+ filename: "[path][base].br[query]",
35
+ algorithm: "brotliCompress",
36
+ test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/
37
+ })
38
+ )
39
+ }
42
40
  }
43
41
 
44
- return null
42
+ return plugins
45
43
  }
46
44
 
47
45
  const productionConfig = {
@@ -49,32 +47,7 @@ const productionConfig = {
49
47
  stats: "normal",
50
48
  bail: true,
51
49
  plugins: getPlugins(),
52
- optimization: {
53
- minimizer: [
54
- tryCssMinimizer(),
55
- new TerserPlugin({
56
- parallel: Number.parseInt(process.env.SHAKAPACKER_PARALLEL, 10) || true,
57
- terserOptions: {
58
- parse: {
59
- // Let terser parse ecma 8 code but always output
60
- // ES5 compliant code for older browsers
61
- ecma: 8
62
- },
63
- compress: {
64
- ecma: 5,
65
- warnings: false,
66
- comparisons: false
67
- },
68
- mangle: { safari10: true },
69
- output: {
70
- ecma: 5,
71
- comments: false,
72
- ascii_only: true
73
- }
74
- }
75
- })
76
- ].filter(Boolean)
77
- }
50
+ optimization: getOptimization()
78
51
  }
79
52
 
80
53
  if (config.useContentHash === false) {
@@ -1,3 +1,17 @@
1
+ const { merge } = require("webpack-merge")
2
+ const config = require("../config")
1
3
  const baseConfig = require("./base")
2
4
 
3
- module.exports = baseConfig
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 bundlerConfig =
15
+ config.bundler === "rspack" ? rspackTestConfig : baseConfig
16
+
17
+ module.exports = merge(baseConfig, bundlerConfig)
data/package/index.d.ts CHANGED
@@ -81,6 +81,20 @@ declare module 'shakapacker' {
81
81
  export * from 'webpack-merge'
82
82
  }
83
83
 
84
+ declare module 'shakapacker/rspack' {
85
+ import type { RspackOptions, RuleSetRule } from '@rspack/core'
86
+
87
+ export const config: Config
88
+ export function generateRspackConfig(extraConfig?: RspackOptions): RspackOptions
89
+ export const baseConfig: RspackOptions
90
+ export const env: Env
91
+ export const rules: RuleSetRule[]
92
+ export function moduleExists(packageName: string): boolean
93
+ export function canProcess<T = unknown>(rule: string, fn: (modulePath: string) => T): T | null
94
+ export const inliningCss: boolean
95
+ export * from 'webpack-merge'
96
+ }
97
+
84
98
  declare module 'shakapacker/package/babel/preset.js' {
85
99
  import { ConfigAPI, PluginItem, TransformOptions } from '@babel/core'
86
100
 
data/package/index.js CHANGED
@@ -4,9 +4,11 @@
4
4
  const webpackMerge = require("webpack-merge")
5
5
  const { resolve } = require("path")
6
6
  const { existsSync } = require("fs")
7
- const baseConfig = require("./environments/base")
8
- const rules = require("./rules")
9
7
  const config = require("./config")
8
+ const baseConfig = require("./environments/base")
9
+
10
+ const rulesPath = resolve(__dirname, "rules", `${config.bundler}.js`)
11
+ const rules = require(rulesPath)
10
12
  const devServer = require("./dev_server")
11
13
  const env = require("./env")
12
14
  const { moduleExists, canProcess } = require("./utils/helpers")
@@ -0,0 +1,25 @@
1
+ const { requireOrError } = require("../utils/requireOrError")
2
+
3
+ const { rspack } = requireOrError("@rspack/core")
4
+
5
+ const getOptimization = () => {
6
+ // Use Rspack's built-in minification instead of terser-webpack-plugin
7
+ const result = { minimize: true }
8
+ try {
9
+ result.minimizer = [
10
+ new rspack.SwcJsMinimizerRspackPlugin(),
11
+ new rspack.LightningCssMinimizerRspackPlugin()
12
+ ]
13
+ } catch (error) {
14
+ // eslint-disable-next-line no-console
15
+ console.warn(
16
+ "[SHAKAPACKER]: Warning: Could not configure Rspack minimizers:",
17
+ error.message
18
+ )
19
+ }
20
+ return result
21
+ }
22
+
23
+ module.exports = {
24
+ getOptimization
25
+ }
@@ -0,0 +1,49 @@
1
+ const { requireOrError } = require("../utils/requireOrError")
2
+
3
+ const TerserPlugin = requireOrError("terser-webpack-plugin")
4
+ const { moduleExists } = require("../utils/helpers")
5
+
6
+ const tryCssMinimizer = () => {
7
+ if (
8
+ moduleExists("css-loader") &&
9
+ moduleExists("css-minimizer-webpack-plugin")
10
+ ) {
11
+ const CssMinimizerPlugin = requireOrError("css-minimizer-webpack-plugin")
12
+ return new CssMinimizerPlugin()
13
+ }
14
+
15
+ return null
16
+ }
17
+
18
+ const getOptimization = () => {
19
+ return {
20
+ minimizer: [
21
+ tryCssMinimizer(),
22
+ new TerserPlugin({
23
+ parallel: Number.parseInt(process.env.SHAKAPACKER_PARALLEL, 10) || true,
24
+ terserOptions: {
25
+ parse: {
26
+ // Let terser parse ecma 8 code but always output
27
+ // ES5 compliant code for older browsers
28
+ ecma: 8
29
+ },
30
+ compress: {
31
+ ecma: 5,
32
+ warnings: false,
33
+ comparisons: false
34
+ },
35
+ mangle: { safari10: true },
36
+ output: {
37
+ ecma: 5,
38
+ comments: false,
39
+ ascii_only: true
40
+ }
41
+ }
42
+ })
43
+ ].filter(Boolean)
44
+ }
45
+ }
46
+
47
+ module.exports = {
48
+ getOptimization
49
+ }
@@ -0,0 +1,104 @@
1
+ const { existsSync, readFileSync } = require("fs")
2
+ const { requireOrError } = require("../utils/requireOrError")
3
+
4
+ const { RspackManifestPlugin } = requireOrError("rspack-manifest-plugin")
5
+ const rspack = requireOrError("@rspack/core")
6
+ const config = require("../config")
7
+ const { isProduction } = require("../env")
8
+ const { moduleExists } = require("../utils/helpers")
9
+
10
+ const getPlugins = () => {
11
+ const plugins = [
12
+ new rspack.EnvironmentPlugin(process.env),
13
+ new RspackManifestPlugin({
14
+ fileName: config.manifestPath.split("/").pop(), // Get just the filename
15
+ publicPath: config.publicPathWithoutCDN,
16
+ writeToFileEmit: true,
17
+ // rspack-manifest-plugin uses different option names than webpack-assets-manifest
18
+ generate: (seed, files, entrypoints) => {
19
+ let manifest = seed || {}
20
+
21
+ // Load existing manifest if it exists to handle concurrent builds
22
+ try {
23
+ if (existsSync(config.manifestPath)) {
24
+ const existingContent = readFileSync(config.manifestPath, "utf8")
25
+ const parsed = JSON.parse(existingContent)
26
+ if (parsed && typeof parsed === "object") {
27
+ manifest = {
28
+ ...manifest,
29
+ ...parsed
30
+ }
31
+ }
32
+ }
33
+ } catch (error) {
34
+ // eslint-disable-next-line no-console
35
+ console.warn(
36
+ "[SHAKAPACKER]: Warning: Could not read existing manifest.json:",
37
+ String(error)
38
+ )
39
+ }
40
+
41
+ // Add files mapping first
42
+ files.forEach((file) => {
43
+ manifest[file.name] = file.path
44
+ })
45
+
46
+ // Add entrypoints information compatible with Shakapacker expectations
47
+ const entrypointsManifest = {}
48
+ Object.entries(entrypoints).forEach(
49
+ ([entrypointName, entrypointFiles]) => {
50
+ const jsFiles = entrypointFiles.filter((file) =>
51
+ file.endsWith(".js")
52
+ )
53
+ const cssFiles = entrypointFiles.filter((file) =>
54
+ file.endsWith(".css")
55
+ )
56
+
57
+ entrypointsManifest[entrypointName] = {
58
+ assets: {
59
+ js: jsFiles,
60
+ css: cssFiles
61
+ }
62
+ }
63
+ }
64
+ )
65
+ manifest.entrypoints = entrypointsManifest
66
+
67
+ return manifest
68
+ }
69
+ })
70
+ ]
71
+
72
+ if (moduleExists("css-loader")) {
73
+ const hash = isProduction || config.useContentHash ? "-[contenthash:8]" : ""
74
+ // Use Rspack's built-in CSS extraction
75
+ const { CssExtractRspackPlugin } = rspack
76
+ plugins.push(
77
+ new CssExtractRspackPlugin({
78
+ filename: `css/[name]${hash}.css`,
79
+ chunkFilename: `css/[id]${hash}.css`,
80
+ // For projects where css ordering has been mitigated through consistent use of scoping or naming conventions,
81
+ // the css order warnings can be disabled by setting the ignoreOrder flag.
82
+ ignoreOrder: config.css_extract_ignore_order_warnings,
83
+ // Force writing CSS files to disk in development for Rails compatibility
84
+ emit: true
85
+ })
86
+ )
87
+ }
88
+
89
+ // Use Rspack's built-in SubresourceIntegrityPlugin
90
+ if (config.integrity.enabled) {
91
+ plugins.push(
92
+ new rspack.SubresourceIntegrityPlugin({
93
+ hashFuncNames: config.integrity.hash_functions,
94
+ enabled: isProduction
95
+ })
96
+ )
97
+ }
98
+
99
+ return plugins
100
+ }
101
+
102
+ module.exports = {
103
+ getPlugins
104
+ }
@@ -0,0 +1,62 @@
1
+ const { requireOrError } = require("../utils/requireOrError")
2
+ // TODO: Change to `const { WebpackAssetsManifest }` when dropping 'webpack-assets-manifest < 6.0.0' (Node >=20.10.0) support
3
+ const WebpackAssetsManifest = requireOrError("webpack-assets-manifest")
4
+ const webpack = requireOrError("webpack")
5
+ const config = require("../config")
6
+ const { isProduction } = require("../env")
7
+ const { moduleExists } = require("../utils/helpers")
8
+
9
+ const getPlugins = () => {
10
+ // TODO: Remove WebpackAssetsManifestConstructor workaround when dropping 'webpack-assets-manifest < 6.0.0' (Node >=20.10.0) support
11
+ const WebpackAssetsManifestConstructor =
12
+ "WebpackAssetsManifest" in WebpackAssetsManifest
13
+ ? WebpackAssetsManifest.WebpackAssetsManifest
14
+ : WebpackAssetsManifest
15
+ const plugins = [
16
+ new webpack.EnvironmentPlugin(process.env),
17
+ new WebpackAssetsManifestConstructor({
18
+ entrypoints: true,
19
+ writeToDisk: true,
20
+ output: config.manifestPath,
21
+ entrypointsUseAssets: true,
22
+ publicPath: config.publicPathWithoutCDN,
23
+ integrity: config.integrity.enabled,
24
+ integrityHashes: config.integrity.hash_functions
25
+ })
26
+ ]
27
+
28
+ if (moduleExists("css-loader") && moduleExists("mini-css-extract-plugin")) {
29
+ const hash = isProduction || config.useContentHash ? "-[contenthash:8]" : ""
30
+ const MiniCssExtractPlugin = requireOrError("mini-css-extract-plugin")
31
+ plugins.push(
32
+ new MiniCssExtractPlugin({
33
+ filename: `css/[name]${hash}.css`,
34
+ chunkFilename: `css/[id]${hash}.css`,
35
+ // For projects where css ordering has been mitigated through consistent use of scoping or naming conventions,
36
+ // the css order warnings can be disabled by setting the ignoreOrder flag.
37
+ ignoreOrder: config.css_extract_ignore_order_warnings
38
+ })
39
+ )
40
+ }
41
+
42
+ if (
43
+ config.integrity.enabled &&
44
+ moduleExists("webpack-subresource-integrity")
45
+ ) {
46
+ const SubresourceIntegrityPlugin = requireOrError(
47
+ "webpack-subresource-integrity"
48
+ )
49
+ plugins.push(
50
+ new SubresourceIntegrityPlugin({
51
+ hashFuncNames: config.integrity.hash_functions,
52
+ enabled: isProduction
53
+ })
54
+ )
55
+ }
56
+
57
+ return plugins
58
+ }
59
+
60
+ module.exports = {
61
+ getPlugins
62
+ }
data/package/rules/css.js CHANGED
@@ -1,3 +1,3 @@
1
- const getStyleRule = require("../utils/getStyleRule")
1
+ const { getStyleRule } = require("../utils/getStyleRule")
2
2
 
3
3
  module.exports = getStyleRule(/\.(css)$/i)
@@ -1,4 +1,4 @@
1
- const { dirname } = require("path")
1
+ const { dirname, sep, normalize } = require("path")
2
2
  const {
3
3
  additional_paths: additionalPaths,
4
4
  source_path: sourcePath
@@ -10,16 +10,22 @@ module.exports = {
10
10
  type: "asset/resource",
11
11
  generator: {
12
12
  filename: (pathData) => {
13
- const path = dirname(pathData.filename)
14
- const stripPaths = [...additionalPaths, sourcePath]
13
+ const path = normalize(dirname(pathData.filename))
14
+ const stripPaths = [...additionalPaths, sourcePath].map((p) =>
15
+ normalize(p)
16
+ )
15
17
 
16
18
  const selectedStripPath = stripPaths.find((includePath) =>
17
19
  path.startsWith(includePath)
18
20
  )
19
21
 
22
+ if (!selectedStripPath) {
23
+ return `static/[name]-[hash][ext][query]`
24
+ }
25
+
20
26
  const folders = path
21
- .replace(`${selectedStripPath}`, "")
22
- .split("/")
27
+ .replace(selectedStripPath, "")
28
+ .split(sep)
23
29
  .filter(Boolean)
24
30
 
25
31
  const foldersWithStatic = ["static", ...folders].join("/")
@@ -1,6 +1,6 @@
1
1
  const path = require("path")
2
2
  const { canProcess } = require("../utils/helpers")
3
- const getStyleRule = require("../utils/getStyleRule")
3
+ const { getStyleRule } = require("../utils/getStyleRule")
4
4
 
5
5
  const {
6
6
  additional_paths: paths,
data/package/rules/raw.js CHANGED
@@ -1,5 +1,15 @@
1
- module.exports = {
1
+ const config = require("../config")
2
+
3
+ const rspackRawConfig = {
4
+ resourceQuery: /raw/,
5
+ type: "asset/source"
6
+ }
7
+
8
+ const webpackRawConfig = {
2
9
  test: /\.html$/,
3
10
  exclude: /\.(js|mjs|jsx|ts|tsx)$/,
4
11
  type: "asset/source"
5
12
  }
13
+
14
+ module.exports =
15
+ config.bundler === "rspack" ? rspackRawConfig : webpackRawConfig
@@ -0,0 +1,96 @@
1
+ /* eslint global-require: 0 */
2
+
3
+ const { moduleExists } = require("../utils/helpers")
4
+
5
+ const rules = []
6
+
7
+ // Use Rspack's built-in SWC loader for JavaScript files
8
+ rules.push({
9
+ test: /\.(js|jsx|mjs)$/,
10
+ exclude: /node_modules/,
11
+ type: "javascript/auto",
12
+ use: [
13
+ {
14
+ loader: "builtin:swc-loader",
15
+ options: {
16
+ jsc: {
17
+ parser: {
18
+ syntax: "ecmascript",
19
+ jsx: true
20
+ },
21
+ transform: {
22
+ react: {
23
+ runtime: "automatic"
24
+ }
25
+ }
26
+ }
27
+ }
28
+ }
29
+ ]
30
+ })
31
+
32
+ // Use Rspack's built-in SWC loader for TypeScript files
33
+ rules.push({
34
+ test: /\.(ts|tsx)$/,
35
+ exclude: /node_modules/,
36
+ type: "javascript/auto",
37
+ use: [
38
+ {
39
+ loader: "builtin:swc-loader",
40
+ options: {
41
+ jsc: {
42
+ parser: {
43
+ syntax: "typescript",
44
+ tsx: true
45
+ },
46
+ transform: {
47
+ react: {
48
+ runtime: "automatic"
49
+ }
50
+ }
51
+ }
52
+ }
53
+ }
54
+ ]
55
+ })
56
+
57
+ // CSS rules using Rspack's built-in CSS handling
58
+ if (moduleExists("css-loader")) {
59
+ const css = require("./css")
60
+ rules.push(css)
61
+ }
62
+
63
+ // Sass rules
64
+ if (moduleExists("sass") && moduleExists("sass-loader")) {
65
+ const sass = require("./sass")
66
+ rules.push(sass)
67
+ }
68
+
69
+ // Less rules
70
+ if (moduleExists("less") && moduleExists("less-loader")) {
71
+ const less = require("./less")
72
+ rules.push(less)
73
+ }
74
+
75
+ // Stylus rules
76
+ if (moduleExists("stylus") && moduleExists("stylus-loader")) {
77
+ const stylus = require("./stylus")
78
+ rules.push(stylus)
79
+ }
80
+
81
+ // ERB template support
82
+ const erb = require("./erb")
83
+
84
+ rules.push(erb)
85
+
86
+ // File/asset handling using Rspack's built-in asset modules
87
+ const file = require("./file")
88
+
89
+ rules.push(file)
90
+
91
+ // Raw file loading
92
+ const raw = require("./raw")
93
+
94
+ rules.push(raw)
95
+
96
+ module.exports = rules
@@ -1,6 +1,6 @@
1
1
  /* eslint global-require: 0 */
2
2
 
3
- const getStyleRule = require("../utils/getStyleRule")
3
+ const { getStyleRule } = require("../utils/getStyleRule")
4
4
  const { canProcess, packageMajorVersion } = require("../utils/helpers")
5
5
  const { additional_paths: extraPaths } = require("../config")
6
6
 
@@ -11,7 +11,11 @@ module.exports = canProcess("sass-loader", (resolvedPath) => {
11
11
  {
12
12
  loader: resolvedPath,
13
13
  options: {
14
- sassOptions: { [optionKey]: extraPaths }
14
+ sourceMap: true,
15
+ sassOptions: {
16
+ [optionKey]: extraPaths,
17
+ quietDeps: true
18
+ }
15
19
  }
16
20
  }
17
21
  ])
@@ -1,6 +1,6 @@
1
1
  const path = require("path")
2
2
  const { canProcess } = require("../utils/helpers")
3
- const getStyleRule = require("../utils/getStyleRule")
3
+ const { getStyleRule } = require("../utils/getStyleRule")
4
4
 
5
5
  const {
6
6
  additional_paths: paths,
@@ -1,5 +1,7 @@
1
1
  /* eslint global-require: 0 */
2
2
  const { canProcess, moduleExists } = require("./helpers")
3
+ const { requireOrError } = require("./requireOrError")
4
+ const config = require("../config")
3
5
  const inliningCss = require("./inliningCss")
4
6
 
5
7
  const getStyleRule = (test, preprocessors = []) => {
@@ -12,8 +14,13 @@ const getStyleRule = (test, preprocessors = []) => {
12
14
 
13
15
  // style-loader is required when using css modules with HMR on the webpack-dev-server
14
16
 
17
+ const extractionPlugin =
18
+ config.bundle === "rspack"
19
+ ? requireOrError("@rspack/core").CssExtractRspackPlugin.loader
20
+ : requireOrError("mini-css-extract-plugin").loader
21
+
15
22
  const use = [
16
- inliningCss ? "style-loader" : require("mini-css-extract-plugin").loader,
23
+ inliningCss ? "style-loader" : extractionPlugin,
17
24
  {
18
25
  loader: require.resolve("css-loader"),
19
26
  options: {
@@ -28,13 +35,19 @@ const getStyleRule = (test, preprocessors = []) => {
28
35
  ...preprocessors
29
36
  ].filter(Boolean)
30
37
 
31
- return {
38
+ const result = {
32
39
  test,
33
40
  use
34
41
  }
42
+
43
+ if (config.bundle === "rspack") {
44
+ result.type = "javascript/auto" // Required for rspack CSS extraction
45
+ }
46
+
47
+ return result
35
48
  }
36
49
 
37
50
  return null
38
51
  }
39
52
 
40
- module.exports = getStyleRule
53
+ module.exports = { getStyleRule }