import { createRequire } from "node:module"; import node_path from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; import deepmerge from "deepmerge"; import { reduceConfigsWithContext } from "reduce-configs"; import resolve_url_loader from "../compiled/resolve-url-loader/index.js"; let GLOBAL_PATCHED_SYMBOL = Symbol('GLOBAL_PATCHED_SYMBOL'); function patchGlobalLocation() { if (!global.location) { let location = Object.freeze({ [GLOBAL_PATCHED_SYMBOL]: !0, href: pathToFileURL(process.cwd()).href + node_path.sep }); global.location = location; } } function unpatchGlobalLocation() { global.location?.[GLOBAL_PATCHED_SYMBOL] && delete global.location; } function patchCompilerGlobalLocation(compiler) { compiler.hooks.run.tap('PatchGlobalLocation', patchGlobalLocation), compiler.hooks.watchRun.tap('PatchGlobalLocation', patchGlobalLocation), compiler.hooks.watchClose.tap('PatchGlobalLocation', unpatchGlobalLocation), compiler.hooks.done.tap('PatchGlobalLocation', unpatchGlobalLocation); } let src_dirname = node_path.dirname(fileURLToPath(import.meta.url)), src_require = createRequire(import.meta.url), PLUGIN_SASS_NAME = 'rsbuild:sass', pluginSass = (pluginOptions = {})=>({ name: PLUGIN_SASS_NAME, setup (api) { let { rewriteUrls = !0, include = /\.s(?:a|c)ss$/ } = pluginOptions, SASS_INLINE = 'sass-inline', SASS_RAW = 'sass-raw', isV1 = api.context.version.startsWith('1.'); api.onAfterCreateCompiler(({ compiler })=>{ patchCompilerGlobalLocation(compiler); }), api.modifyBundlerChain((chain, { CHAIN_ID, environment })=>{ var userOptions, callback; let excludes, mergedOptions, { config } = environment, { sourceMap } = config.output, isUseSourceMap = 'boolean' == typeof sourceMap ? sourceMap : sourceMap.css, { excludes: excludes1, options } = (userOptions = pluginOptions.sassLoaderOptions, excludes = [], mergedOptions = reduceConfigsWithContext({ initial: { sourceMap: !!rewriteUrls || isUseSourceMap, api: 'modern-compiler', implementation: src_require.resolve('sass-embedded'), sassOptions: { quietDeps: !0 } }, config: userOptions, ctx: { addExcludes: (items)=>{ excludes.push(...Array.isArray(items) ? items : [ items ]); } }, mergeFn: (defaults, userOptions)=>({ ...defaults, ...userOptions, sassOptions: defaults.sassOptions && userOptions.sassOptions ? deepmerge(defaults.sassOptions, userOptions.sassOptions) : userOptions.sassOptions || defaults.sassOptions }) }), mergedOptions.sassOptions ||= {}, mergedOptions.sassOptions.silenceDeprecations || (mergedOptions.sassOptions.silenceDeprecations = [ 'import' ], 'legacy' === mergedOptions.api && mergedOptions.sassOptions.silenceDeprecations.push('legacy-js-api')), { options: mergedOptions, excludes }), sassRule = chain.module.rule(((chain, defaultId)=>{ let id = defaultId, index = 0; for(; chain.module.rules.has(id);)id = `${defaultId}-${++index}`; return id; })(chain, CHAIN_ID.RULE.SASS)).test(include).dependency({ not: 'url' }).resolve.preferRelative(!0).end(); isV1 && (chain.module.rule(SASS_RAW).test(include), chain.module.rule(SASS_INLINE).test(include)); let getRule = (id)=>isV1 ? chain.module.rule(id) : (id.startsWith('sass') ? sassRule : chain.module.rule(CHAIN_ID.RULE.CSS)).oneOf(id), sassInlineRule = getRule(SASS_INLINE); getRule(SASS_RAW).type('asset/source').resourceQuery(getRule('css-raw').get('resourceQuery')); let sassMainRule = getRule('sass'), sassLoaderPath = node_path.join(src_dirname, '../compiled/sass-loader/index.js'), resolveUrlLoaderPath = node_path.join(src_dirname, '../compiled/resolve-url-loader/index.js'), resolveUrlLoaderOptions = { join: (()=>{ let { createJoinFunction, asGenerator, createJoinImplementation, defaultJoinGenerator } = resolve_url_loader; return createJoinFunction('rsbuild-resolve-join-fn', createJoinImplementation(asGenerator((item, ...rest)=>item.uri.startsWith('.') ? defaultJoinGenerator(item, ...rest) : [ null ]))); })(), sourceMap: !1 }; (callback = (rule, cssBranchRule)=>{ for (let item of excludes1)rule.exclude.add(item); for (let id of (pluginOptions.exclude && rule.exclude.add(pluginOptions.exclude), rule.sideEffects(!0).resourceQuery(cssBranchRule.get('resourceQuery')), Object.keys(cssBranchRule.uses.entries()))){ let loader = cssBranchRule.uses.get(id), clonedOptions = deepmerge({}, loader.get('options') ?? {}); id === CHAIN_ID.USE.CSS && (clonedOptions.importLoaders += rewriteUrls ? 2 : 1), rule.use(id).loader(loader.get('loader')).options(clonedOptions); } rewriteUrls && rule.use(CHAIN_ID.USE.RESOLVE_URL).loader(resolveUrlLoaderPath).options(resolveUrlLoaderOptions).end(), rule.use(CHAIN_ID.USE.SASS).loader(sassLoaderPath).options(options); })(sassMainRule, getRule('css')), callback(sassInlineRule, getRule('css-inline')); }); } }); export { PLUGIN_SASS_NAME, pluginSass };