Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions packages/sui-bundler/loaders/linkLoaderConfigBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,21 @@ module.exports = ({config, packagesToLink, linkAll}) => {

if (!regex.test('.css')) return rule

// Rules matching .css that don't already run through @s-ui/sass-loader
// (e.g. the plainCssPackages passthrough rule, see module-rules-sass.js)
// must be left alone — otherwise this force-injects the sass loader
// into plain CSS files, breaking packages that ship pre-built CSS
// (Tailwind v4 output, etc.) when they're consumed via -l/-L linking.
// Compared by resolved path rather than package-name substring so this
// also works when @s-ui/sass-loader itself is symlinked/linked (e.g.
// inside this monorepo), where its resolved path won't contain the
// package name.
const sassLoaderPath = require.resolve('@s-ui/sass-loader')
const usesSassLoader = use.some(
loaderUse => (typeof loaderUse === 'string' ? loaderUse : loaderUse.loader) === sassLoaderPath
)
if (!usesSassLoader) return rule

return {
...rule,
use: [...use.slice(0, -1), sassLoaderWithLinkImporter]
Expand Down
74 changes: 74 additions & 0 deletions packages/sui-bundler/test/server/linkLoaderConfigBuilderSpec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
const {expect} = require('chai')

const linkLoaderConfigBuilder = require('../../loaders/linkLoaderConfigBuilder.js')

describe('linkLoaderConfigBuilder', () => {
const packagesToLink = [__dirname]

it('injects the sass link importer into rules that already use @s-ui/sass-loader', () => {
const config = {
module: {
rules: [
{
test: /(\.css|\.scss)$/,
exclude: /node_modules/,
use: [
'mini-css-extract-plugin-loader',
'css-loader',
'postcss-loader',
require.resolve('@s-ui/sass-loader')
]
}
]
},
resolve: {alias: {}}
}

const nextConfig = linkLoaderConfigBuilder({config, packagesToLink})
const sassRule = nextConfig.module.rules[0]

expect(sassRule.use).to.have.lengthOf(4)
expect(sassRule.use[3]).to.be.an('object')
expect(sassRule.use[3].loader).to.equal(require.resolve('@s-ui/sass-loader'))
expect(sassRule.use[3].options.sassOptions).to.have.property('importer')
})

it('leaves the plainCssPackages passthrough rule untouched', () => {
const config = {
module: {
rules: [
{
test: /(\.css|\.scss)$/,
exclude: /node_modules[\\/](@adv-mt\/ui)[\\/]/,
use: [
'mini-css-extract-plugin-loader',
'css-loader',
'postcss-loader',
require.resolve('@s-ui/sass-loader')
]
},
{
test: /\.css$/,
include: /node_modules[\\/](@adv-mt\/ui)[\\/]/,
use: ['mini-css-extract-plugin-loader', 'css-loader']
}
]
},
resolve: {alias: {}}
}

const nextConfig = linkLoaderConfigBuilder({config, packagesToLink})
const plainCssRule = nextConfig.module.rules[1]

// Before the fix, this rule's last loader (css-loader) was replaced with
// @s-ui/sass-loader, breaking pre-built CSS (e.g. Tailwind v4 output)
// from plainCssPackages when consumed via -l/-L linking.
expect(plainCssRule.use).to.deep.equal(['mini-css-extract-plugin-loader', 'css-loader'])
})

it('returns the original config unmodified when there is nothing to link', () => {
const config = {module: {rules: []}}
const nextConfig = linkLoaderConfigBuilder({config, packagesToLink: [], linkAll: false})
expect(nextConfig).to.equal(config)
})
})
Loading