From 7cbbf8cd8472552e3d373dfd411f2e866752062a Mon Sep 17 00:00:00 2001 From: Tomas Madariaga Date: Tue, 26 May 2026 16:08:07 +0200 Subject: [PATCH] feat(packages/sui-bundler): add plainCssPackages config to bypass sass-loader Adds a new `plainCssPackages` option to `sui-bundler` config that allows projects to specify npm packages whose CSS files should skip the sass-loader pipeline entirely. Packages that ship pre-compiled CSS (e.g. Tailwind CSS v4 output) use modern CSS syntax (@layer, @property, nested rules) that Dart Sass cannot parse. This causes `Error: expected ";"` at build time. Usage in package.json: ```json { "config": { "sui-bundler": { "plainCssPackages": ["@adv-mt/ui", "@adv-mt/theme"] } } } ``` CSS files from listed packages are processed only by css-loader (+ MiniCssExtractPlugin or style-loader), bypassing postcss-loader and sass-loader. Co-Authored-By: Claude Opus 4.6 --- .../sui-bundler/shared/module-rules-sass.js | 21 ++++++++++++- .../sui-bundler/webpack.config.client.dev.js | 31 ++----------------- packages/sui-bundler/webpack.config.dev.js | 17 ++++++++++ packages/sui-bundler/webpack.config.lib.js | 2 +- packages/sui-bundler/webpack.config.prod.js | 2 +- 5 files changed, 42 insertions(+), 31 deletions(-) diff --git a/packages/sui-bundler/shared/module-rules-sass.js b/packages/sui-bundler/shared/module-rules-sass.js index 5379db53b..72ea5602d 100644 --- a/packages/sui-bundler/shared/module-rules-sass.js +++ b/packages/sui-bundler/shared/module-rules-sass.js @@ -2,8 +2,17 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin') const {cleanList, config, when, isTailwindEnabled} = require('./index') -module.exports = { +const plainCssPackages = config.plainCssPackages || [] + +const plainCssExclude = plainCssPackages.length + ? new RegExp( + `node_modules[\\\\/](${plainCssPackages.map(p => p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|')})[\\\\/]` + ) + : null + +const sassRule = { test: /(\.css|\.scss)$/, + ...(plainCssExclude ? {exclude: plainCssExclude} : {}), use: cleanList([ MiniCssExtractPlugin.loader, require.resolve('css-loader'), @@ -29,3 +38,13 @@ module.exports = { require.resolve('@s-ui/sass-loader') ]) } + +const plainCssRule = plainCssExclude + ? { + test: /\.css$/, + include: plainCssExclude, + use: [MiniCssExtractPlugin.loader, require.resolve('css-loader')] + } + : null + +module.exports = plainCssRule ? [sassRule, plainCssRule] : sassRule diff --git a/packages/sui-bundler/webpack.config.client.dev.js b/packages/sui-bundler/webpack.config.client.dev.js index 6e1bc93d5..de9cf0a17 100644 --- a/packages/sui-bundler/webpack.config.client.dev.js +++ b/packages/sui-bundler/webpack.config.client.dev.js @@ -9,9 +9,10 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin') const HtmlWebpackInjectAttributesPlugin = require('html-webpack-inject-attributes-plugin') const {withHydrationOverlayWebpack} = require('@builder.io/react-hydration-overlay/webpack') -const {envVars, MAIN_ENTRY_POINT, config, cleanList, when, isTailwindEnabled} = require('./shared/index.js') +const {envVars, MAIN_ENTRY_POINT, config, cleanList, when} = require('./shared/index.js') const definePlugin = require('./shared/define.js') const manifestLoaderRules = require('./shared/module-rules-manifest-loader.js') +const sassRules = require('./shared/module-rules-sass.js') const createSVGSpritemapPlugin = require('./shared/svg-spritemap') const {aliasFromConfig, defaultAlias} = require('./shared/resolve-alias.js') const {supportLegacyBrowsers, cacheDirectory} = require('./shared/config.js') @@ -96,33 +97,7 @@ const webpackConfig = { module: { rules: cleanList([ createCompilerRules({supportLegacyBrowsers, isDevelopment: true}), - { - test: /(\.css|\.scss)$/, - use: cleanList([ - MiniCssExtractPlugin.loader, - require.resolve('css-loader'), - when(config['externals-manifest'], () => ({ - loader: 'externals-manifest-loader', - options: { - manifestURL: config['externals-manifest'] - } - })), - { - loader: require.resolve('postcss-loader'), - options: { - postcssOptions: { - plugins: [ - ...(isTailwindEnabled() ? [require('tailwindcss')()] : []), - require('autoprefixer')({ - overrideBrowserslist: config.targets - }) - ] - } - } - }, - require.resolve('@s-ui/sass-loader') - ]) - }, + ...(Array.isArray(sassRules) ? sassRules : [sassRules]), when(config['externals-manifest'], () => manifestLoaderRules(config['externals-manifest'])) ]) }, diff --git a/packages/sui-bundler/webpack.config.dev.js b/packages/sui-bundler/webpack.config.dev.js index 3b262f382..0622bf606 100644 --- a/packages/sui-bundler/webpack.config.dev.js +++ b/packages/sui-bundler/webpack.config.dev.js @@ -14,6 +14,13 @@ const {supportLegacyBrowsers, cacheDirectory} = require('./shared/config.js') const {resolveLoader} = require('./shared/resolve-loader.js') const createCompilerRules = require('./shared/module-rules-compiler.js') +const plainCssPackages = config.plainCssPackages || [] +const plainCssExclude = plainCssPackages.length + ? new RegExp( + `node_modules[\\\\/](${plainCssPackages.map(p => p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|')})[\\\\/]` + ) + : null + const outputPath = path.join(process.cwd(), 'dist') const {CI = false} = process.env @@ -90,6 +97,7 @@ const webpackConfig = { createCompilerRules({supportLegacyBrowsers, isDevelopment: true}), { test: /(\.css|\.scss)$/, + ...(plainCssExclude ? {exclude: plainCssExclude} : {}), use: cleanList([ require.resolve('style-loader'), when(config['externals-manifest'], () => ({ @@ -115,6 +123,15 @@ const webpackConfig = { require.resolve('@s-ui/sass-loader') ]) }, + ...(plainCssExclude + ? [ + { + test: /\.css$/, + include: plainCssExclude, + use: [require.resolve('style-loader'), require.resolve('css-loader')] + } + ] + : []), when(config['externals-manifest'], () => manifestLoaderRules(config['externals-manifest'])) ]) }, diff --git a/packages/sui-bundler/webpack.config.lib.js b/packages/sui-bundler/webpack.config.lib.js index c992196aa..ba7b18ae3 100644 --- a/packages/sui-bundler/webpack.config.lib.js +++ b/packages/sui-bundler/webpack.config.lib.js @@ -60,7 +60,7 @@ module.exports = ({chunkCss} = {}) => { definePlugin() ]), module: { - rules: [createCompilerRules({supportLegacyBrowsers}), sassRules] + rules: [createCompilerRules({supportLegacyBrowsers}), ...(Array.isArray(sassRules) ? sassRules : [sassRules])] } } } diff --git a/packages/sui-bundler/webpack.config.prod.js b/packages/sui-bundler/webpack.config.prod.js index e7c91f191..b9b8bcbe5 100644 --- a/packages/sui-bundler/webpack.config.prod.js +++ b/packages/sui-bundler/webpack.config.prod.js @@ -106,7 +106,7 @@ const webpackConfig = { module: { rules: cleanList([ createCompilerRules({supportLegacyBrowsers}), - sassRules, + ...(Array.isArray(sassRules) ? sassRules : [sassRules]), when(config['externals-manifest'], () => manifestLoaderRules(config['externals-manifest'])) ]) },