From 977c5ad00f5a3b23caa5f2c3c5e9b28856f79c89 Mon Sep 17 00:00:00 2001 From: xuegan Date: Sat, 30 Nov 2024 12:18:06 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E5=88=A4=E6=96=ADcss=20loader?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/webpack-plugin/lib/index.js | 18 ++- .../lib/resolver/AddEnvPlugin.js | 2 +- .../lib/resolver/AddModePlugin.js | 4 +- .../lib/style-compiler/index.js | 6 +- .../strip-conditional-loader.js | 116 ++++++++++++++++++ 5 files changed, 135 insertions(+), 11 deletions(-) create mode 100644 packages/webpack-plugin/lib/style-compiler/strip-conditional-loader.js diff --git a/packages/webpack-plugin/lib/index.js b/packages/webpack-plugin/lib/index.js index 0216e633e..8ebfbe56d 100644 --- a/packages/webpack-plugin/lib/index.js +++ b/packages/webpack-plugin/lib/index.js @@ -54,6 +54,7 @@ const wxssLoaderPath = normalize.lib('wxss/index') const wxmlLoaderPath = normalize.lib('wxml/loader') const wxsLoaderPath = normalize.lib('wxs/loader') const styleCompilerPath = normalize.lib('style-compiler/index') +const styleStripConditaionalPath = normalize.lib('style-compiler/strip-conditional-loader') const templateCompilerPath = normalize.lib('template-compiler/index') const jsonCompilerPath = normalize.lib('json-compiler/index') const jsonThemeCompilerPath = normalize.lib('json-compiler/theme') @@ -1775,7 +1776,7 @@ try { }) const typeLoaderProcessInfo = { - styles: ['node_modules/css-loader', wxssLoaderPath, styleCompilerPath], + styles: ['node_modules/css-loader', wxssLoaderPath, styleCompilerPath, styleStripConditaionalPath], template: ['node_modules/html-loader', wxmlLoaderPath, templateCompilerPath] } @@ -1801,9 +1802,18 @@ try { } }) if (insertBeforeIndex > -1) { - loaders.splice(insertBeforeIndex + 1, 0, { - loader: info[2] - }) + if (type === 'styles') { + loaders.splice(insertBeforeIndex + 1, 0, { + loader: info[2] + }, { + loader: info[3] + }) + } else { + loaders.splice(insertBeforeIndex + 1, 0, { + loader: info[2] + }) + } + } break } diff --git a/packages/webpack-plugin/lib/resolver/AddEnvPlugin.js b/packages/webpack-plugin/lib/resolver/AddEnvPlugin.js index 584496b5b..c7dd1d1db 100644 --- a/packages/webpack-plugin/lib/resolver/AddEnvPlugin.js +++ b/packages/webpack-plugin/lib/resolver/AddEnvPlugin.js @@ -36,7 +36,7 @@ module.exports = class AddEnvPlugin { const queryObj = parseQuery(request.query || '?') queryObj.infix = `${queryObj.infix || ''}.${env}` // css | stylus | less | sass 中 import file 过滤query,避免在对应的 loader 中无法读取到文件 - if (!isCSSFileName(extname)) obj.query = stringifyQuery(queryObj) + obj.query = stringifyQuery(queryObj) obj.path = addInfix(resourcePath, env, extname) obj.relativePath = request.relativePath && addInfix(request.relativePath, env, extname) resolver.doResolve(target, Object.assign({}, request, obj), 'add env: ' + env, resolveContext, callback) diff --git a/packages/webpack-plugin/lib/resolver/AddModePlugin.js b/packages/webpack-plugin/lib/resolver/AddModePlugin.js index d56247bd7..26b543170 100644 --- a/packages/webpack-plugin/lib/resolver/AddModePlugin.js +++ b/packages/webpack-plugin/lib/resolver/AddModePlugin.js @@ -48,9 +48,7 @@ module.exports = class AddModePlugin { if (defaultMode && !result) { queryObj.infix = `${queryInfix || ''}.${defaultMode}` // css | stylus | less | sass 中 import file 过滤query,避免在对应的 loader 中无法读取到文件 - if (!isCSSFileName(extname)) { - obj.query = stringifyQuery(queryObj) - } + obj.query = stringifyQuery(queryObj) obj.path = addInfix(resourcePath, defaultMode, extname) resolver.doResolve(target, Object.assign({}, request, obj), 'add mode: ' + defaultMode, resolveContext, (err, result) => { callback(err, result) diff --git a/packages/webpack-plugin/lib/style-compiler/index.js b/packages/webpack-plugin/lib/style-compiler/index.js index 586561e2a..bb94ccee3 100644 --- a/packages/webpack-plugin/lib/style-compiler/index.js +++ b/packages/webpack-plugin/lib/style-compiler/index.js @@ -58,9 +58,9 @@ module.exports = function (css, map) { plugins.push(transSpecial({ id })) } - plugins.push(pluginCondStrip({ - defs - })) + // plugins.push(pluginCondStrip({ + // defs + // })) for (const item of transRpxRules) { const { diff --git a/packages/webpack-plugin/lib/style-compiler/strip-conditional-loader.js b/packages/webpack-plugin/lib/style-compiler/strip-conditional-loader.js new file mode 100644 index 000000000..fcef3fa17 --- /dev/null +++ b/packages/webpack-plugin/lib/style-compiler/strip-conditional-loader.js @@ -0,0 +1,116 @@ +const MagicString = require('magic-string') + +function cssConditionalStrip(cssContent, defs) { + const ms = new MagicString(cssContent) + + // 正则匹配 @mpx-if, @mpx-elif, @mpx-else, @mpx-endif 的模式 + const ifPattern = /\/\*\s*@mpx-if\s*\((.*?)\)\s*\*\//gs + const elifPattern = /\/\*\s*@mpx-elif\s*\((.*?)\)\s*\*\//gs + const elsePattern = /\/\*\s*@mpx-else\s*\*\//gs + const endifPattern = /\/\*\s*@mpx-endif\s*\*\//gs + + function evaluateCondition(condition) { + // 替换变量 + for (const key in defs) { + condition = condition.replace(new RegExp(`\\b${key}\\b`, 'g'), JSON.stringify(defs[key])) + } + + // 解析条件表达式 + try { + return Function('"use strict";return (' + condition + ')')() + } catch (e) { + throw new Error(`Failed to evaluate condition: ${condition}`) + } + } + + let currentStart = 0 + function processCondition(start, end, condition) { + const conditionResult = evaluateCondition(condition) + let hasElse = false + let elseStart = -1 + let elseLen = 0 + currentStart = end + 1 + + while (currentStart < ms.original.length) { + elsePattern.lastIndex = currentStart + const elseMatch = elsePattern.exec(ms.original) + if (elseMatch) { + elseLen = elseMatch[0].length + } + + ifPattern.lastIndex = currentStart + const ifMatch = ifPattern.exec(ms.original) + + elifPattern.lastIndex = currentStart + const elifMatch = elifPattern.exec(ms.original) + + endifPattern.lastIndex = currentStart + const endifMatch = endifPattern.exec(ms.original) + + const nextIf = ifMatch ? ifMatch.index : Infinity + const nextElseIf = elifMatch ? elifMatch.index : Infinity + const nextElse = elseMatch ? elseMatch.index : Infinity + const nextEndif = endifMatch ? endifMatch.index : Infinity + + const nextMarker = Math.min(nextIf, nextElseIf, nextElse, nextEndif) + + if (nextMarker === Infinity) break + + if (nextMarker === nextElse) { + // 处理 @mpx-else + hasElse = true + elseStart = nextElse + currentStart = elseMatch.index + elseLen + } else if (nextMarker === nextElseIf) { + // 处理 @mpx-elif + if (!conditionResult) { + ms.remove(start, nextElseIf) + } + if (elifMatch) { + currentStart = nextElseIf + elifMatch[0].length + processCondition(nextElseIf, nextElseIf + elifMatch[0].length, elifMatch[1]) + } + } else if (nextMarker === nextIf) { + // 处理嵌套的 @mpx-if + // 如果遇到了新的 @mpx-if,则递归处理 + if (ifMatch) { + currentStart = nextIf + ifMatch[0].length + processCondition(nextIf, nextIf + ifMatch[0].length, ifMatch[1]) + } + } else if (nextMarker === nextEndif) { + // 处理 @mpx-endif block块 + if (conditionResult && hasElse) { + // 移除 @mpx-else 至 @mpx-endif 代码 + ms.remove(elseStart, endifMatch.index + endifMatch[0].length) + } else if (!conditionResult && hasElse) { + ms.remove(start, elseStart + elseLen) + } else if (!conditionResult) { + ms.remove(start, endifMatch.index + endifMatch[0].length) + } + currentStart = endifMatch.index + endifMatch[0].length + break + } + // 兜底更新当前开始位置 + if (currentStart < nextMarker) { + currentStart = nextMarker + 1 + } + } + } + + // 处理所有条件 + let match + while ((match = ifPattern.exec(ms.original)) !== null) { + processCondition(match.index, ifPattern.lastIndex, match[1]) + ifPattern.lastIndex = currentStart + } + + return ms.toString() +} + +module.exports = function (css) { + this.cacheable() + const mpx = this.getMpx() + const defs = mpx.defs + + return cssConditionalStrip(css, defs) +}