diff --git a/e2e/cases/stylus/inline-query/index.test.ts b/e2e/cases/stylus/inline-query/index.test.ts new file mode 100644 index 0000000000..18c3ec4078 --- /dev/null +++ b/e2e/cases/stylus/inline-query/index.test.ts @@ -0,0 +1,43 @@ +import { build, dev, rspackOnlyTest } from '@e2e/helper'; +import { expect } from '@playwright/test'; + +rspackOnlyTest( + 'should allow to import inline Stylus files in development mode', + async ({ page }) => { + const rsbuild = await dev({ + cwd: __dirname, + page, + }); + + const aInline: string = await page.evaluate('window.aInline'); + const bInline: string = await page.evaluate('window.bInline'); + + expect( + aInline.includes('.header-class') && aInline.includes('color: red'), + ).toBe(true); + expect( + bInline.includes('.title-class') && bInline.includes('font-size: 14px'), + ).toBe(true); + + await rsbuild.close(); + }, +); + +rspackOnlyTest( + 'should allow to import inline Stylus files in production mode', + async ({ page }) => { + const rsbuild = await build({ + cwd: __dirname, + page, + }); + + expect(await page.evaluate('window.aInline')).toBe( + '.header-class{color:red}', + ); + expect(await page.evaluate('window.bInline')).toBe( + '.title-class{font-size:14px}', + ); + + await rsbuild.close(); + }, +); diff --git a/e2e/cases/stylus/raw/rsbuild.config.ts b/e2e/cases/stylus/inline-query/rsbuild.config.ts similarity index 100% rename from e2e/cases/stylus/raw/rsbuild.config.ts rename to e2e/cases/stylus/inline-query/rsbuild.config.ts diff --git a/e2e/cases/stylus/raw/src/a.styl b/e2e/cases/stylus/inline-query/src/a.styl similarity index 100% rename from e2e/cases/stylus/raw/src/a.styl rename to e2e/cases/stylus/inline-query/src/a.styl diff --git a/e2e/cases/stylus/raw/src/b.module.styl b/e2e/cases/stylus/inline-query/src/b.module.styl similarity index 100% rename from e2e/cases/stylus/raw/src/b.module.styl rename to e2e/cases/stylus/inline-query/src/b.module.styl diff --git a/e2e/cases/stylus/inline-query/src/index.js b/e2e/cases/stylus/inline-query/src/index.js new file mode 100644 index 0000000000..eedbbf898f --- /dev/null +++ b/e2e/cases/stylus/inline-query/src/index.js @@ -0,0 +1,5 @@ +import aInline from './a.styl?inline'; +import bInline from './b.module.styl?inline'; + +window.aInline = aInline; +window.bInline = bInline; diff --git a/e2e/cases/stylus/raw/index.test.ts b/e2e/cases/stylus/raw-query/index.test.ts similarity index 100% rename from e2e/cases/stylus/raw/index.test.ts rename to e2e/cases/stylus/raw-query/index.test.ts diff --git a/e2e/cases/stylus/raw-query/rsbuild.config.ts b/e2e/cases/stylus/raw-query/rsbuild.config.ts new file mode 100644 index 0000000000..accfadda7d --- /dev/null +++ b/e2e/cases/stylus/raw-query/rsbuild.config.ts @@ -0,0 +1,5 @@ +import { pluginStylus } from '@rsbuild/plugin-stylus'; + +export default { + plugins: [pluginStylus()], +}; diff --git a/e2e/cases/stylus/raw-query/src/a.styl b/e2e/cases/stylus/raw-query/src/a.styl new file mode 100644 index 0000000000..a608dcd44e --- /dev/null +++ b/e2e/cases/stylus/raw-query/src/a.styl @@ -0,0 +1,3 @@ +.header + &-class + color red diff --git a/e2e/cases/stylus/raw-query/src/b.module.styl b/e2e/cases/stylus/raw-query/src/b.module.styl new file mode 100644 index 0000000000..9319b87565 --- /dev/null +++ b/e2e/cases/stylus/raw-query/src/b.module.styl @@ -0,0 +1,3 @@ +.title + &-class + font-size 14px diff --git a/e2e/cases/stylus/raw/src/index.js b/e2e/cases/stylus/raw-query/src/index.js similarity index 100% rename from e2e/cases/stylus/raw/src/index.js rename to e2e/cases/stylus/raw-query/src/index.js diff --git a/packages/core/src/configChain.ts b/packages/core/src/configChain.ts index 2c6c1a8cc4..f442284003 100644 --- a/packages/core/src/configChain.ts +++ b/packages/core/src/configChain.ts @@ -69,6 +69,8 @@ export const CHAIN_ID = { STYLUS: 'stylus', /** Rule for raw stylus */ STYLUS_RAW: 'stylus-raw', + /** Rule for inline stylus */ + STYLUS_INLINE: 'stylus-inline', /** Rule for svg */ SVG: 'svg', /** Rule for pug */ diff --git a/packages/core/types.d.ts b/packages/core/types.d.ts index 1ba8ddf13e..d6a37f743a 100644 --- a/packages/core/types.d.ts +++ b/packages/core/types.d.ts @@ -203,6 +203,14 @@ declare module '*.less?inline' { const content: string; export default content; } +declare module '*.styl?inline' { + const content: string; + export default content; +} +declare module '*.stylus?inline' { + const content: string; + export default content; +} /** * Raw CSS diff --git a/packages/plugin-stylus/src/index.ts b/packages/plugin-stylus/src/index.ts index 6cd64f6336..5d293a72f8 100644 --- a/packages/plugin-stylus/src/index.ts +++ b/packages/plugin-stylus/src/index.ts @@ -1,5 +1,5 @@ import { createRequire } from 'node:module'; -import type { RsbuildPlugin } from '@rsbuild/core'; +import type { RsbuildPlugin, RspackChain } from '@rsbuild/core'; import deepmerge from 'deepmerge'; import { reduceConfigs } from 'reduce-configs'; @@ -54,11 +54,16 @@ export const pluginStylus = (options?: PluginStylusOptions): RsbuildPlugin => ({ const rule = chain.module .rule(CHAIN_ID.RULE.STYLUS) .test(test) + // exclude `import './foo.styl?raw'` and `import './foo.stylus?inline'` + .resourceQuery({ not: /raw|inline/ }) .sideEffects(true) .resolve.preferRelative(true) - .end() - // exclude `import './foo.styl?raw'` - .resourceQuery({ not: /raw/ }); + .end(); + + const inlineRule = chain.module + .rule(CHAIN_ID.RULE.STYLUS_INLINE) + .test(test) + .resourceQuery(/inline/); // Support for importing raw Stylus files chain.module @@ -67,27 +72,39 @@ export const pluginStylus = (options?: PluginStylusOptions): RsbuildPlugin => ({ .type('asset/source') .resourceQuery(/raw/); - // Copy the builtin CSS rules - const cssRule = chain.module.rules.get(CHAIN_ID.RULE.CSS); - rule.dependency(cssRule.get('dependency')); + // Update the normal rule and the inline rule + const updateRules = ( + callback: (rule: RspackChain.Rule, type: 'normal' | 'inline') => void, + ) => { + callback(rule, 'normal'); + callback(inlineRule, 'inline'); + }; - for (const id of Object.keys(cssRule.uses.entries())) { - const loader = cssRule.uses.get(id); - const options = loader.get('options') ?? {}; - const clonedOptions = deepmerge>({}, options); + updateRules((rule, type) => { + // Copy the builtin CSS rules + const cssRule = chain.module.rules.get( + type === 'normal' ? CHAIN_ID.RULE.CSS : CHAIN_ID.RULE.CSS_INLINE, + ); + rule.dependency(cssRule.get('dependency')); - if (id === CHAIN_ID.USE.CSS) { - // add stylus-loader - clonedOptions.importLoaders += 1; - } + for (const id of Object.keys(cssRule.uses.entries())) { + const loader = cssRule.uses.get(id); + const options = loader.get('options') ?? {}; + const clonedOptions = deepmerge>({}, options); - rule.use(id).loader(loader.get('loader')).options(clonedOptions); - } + if (id === CHAIN_ID.USE.CSS) { + // add stylus-loader + clonedOptions.importLoaders += 1; + } - rule - .use(CHAIN_ID.USE.STYLUS) - .loader(require.resolve('stylus-loader')) - .options(mergedOptions); + rule.use(id).loader(loader.get('loader')).options(clonedOptions); + } + + rule + .use(CHAIN_ID.USE.STYLUS) + .loader(require.resolve('stylus-loader')) + .options(mergedOptions); + }); }); }, }); diff --git a/packages/plugin-stylus/tests/__snapshots__/index.test.ts.snap b/packages/plugin-stylus/tests/__snapshots__/index.test.ts.snap index 2bfb3a2a3b..b6105ad047 100644 --- a/packages/plugin-stylus/tests/__snapshots__/index.test.ts.snap +++ b/packages/plugin-stylus/tests/__snapshots__/index.test.ts.snap @@ -10,7 +10,7 @@ exports[`plugin-stylus > should add stylus loader config correctly 1`] = ` "preferRelative": true, }, "resourceQuery": { - "not": /raw/, + "not": /raw\\|inline/, }, "sideEffects": true, "test": /\\\\\\.styl\\(us\\)\\?\\$/, @@ -51,6 +51,38 @@ exports[`plugin-stylus > should add stylus loader config correctly 1`] = ` }, ], }, + { + "resourceQuery": /inline/, + "test": /\\\\\\.styl\\(us\\)\\?\\$/, + "use": [ + { + "loader": "/packages/core/compiled/css-loader/index.js", + "options": { + "exportType": "string", + "importLoaders": 2, + "modules": false, + "sourceMap": false, + }, + }, + { + "loader": "builtin:lightningcss-loader", + "options": { + "targets": [ + "chrome >= 87", + "edge >= 88", + "firefox >= 78", + "safari >= 14", + ], + }, + }, + { + "loader": "/node_modules//stylus-loader/dist/cjs.js", + "options": { + "sourceMap": false, + }, + }, + ], + }, { "resourceQuery": /raw/, "test": /\\\\\\.styl\\(us\\)\\?\\$/, @@ -69,7 +101,7 @@ exports[`plugin-stylus > should allow to configure stylus options 1`] = ` "preferRelative": true, }, "resourceQuery": { - "not": /raw/, + "not": /raw\\|inline/, }, "sideEffects": true, "test": /\\\\\\.styl\\(us\\)\\?\\$/, @@ -113,6 +145,41 @@ exports[`plugin-stylus > should allow to configure stylus options 1`] = ` }, ], }, + { + "resourceQuery": /inline/, + "test": /\\\\\\.styl\\(us\\)\\?\\$/, + "use": [ + { + "loader": "/packages/core/compiled/css-loader/index.js", + "options": { + "exportType": "string", + "importLoaders": 2, + "modules": false, + "sourceMap": false, + }, + }, + { + "loader": "builtin:lightningcss-loader", + "options": { + "targets": [ + "chrome >= 87", + "edge >= 88", + "firefox >= 78", + "safari >= 14", + ], + }, + }, + { + "loader": "/node_modules//stylus-loader/dist/cjs.js", + "options": { + "sourceMap": false, + "stylusOptions": { + "lineNumbers": false, + }, + }, + }, + ], + }, { "resourceQuery": /raw/, "test": /\\\\\\.styl\\(us\\)\\?\\$/,