diff --git a/README.md b/README.md index 238055e..38329ca 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,17 @@ - 不依赖 css3 vars - 浏览器兼容性良好(IE9+ ?,待验证 ,但 vite 构建的产物最低 Polyfill 到 IE11,需更低的,你可以用 webpack 版本的插件[@zougt/some-loader-utils](https://github.com/GitOfZGT/some-loader-utils),所以兼容性问题取决用的框架) +[demo仓库](https://github.com/GitOfZGT/dynamic-theme-demos) + ## 动态主题模式 > v1.4.0 + 支持 -可用颜色板选择任意的主题色,会自动处理项目中包括组件库涉及的梯度颜色替换,这里以less为例,同样适用于scss。 +可用颜色板选择任意的主题色,这里以less为例,同样适用于scss。 + +[在线demo之一](https://gitofzgt.github.io/vite-dynamictheme-antd-vue-demo/) -[在线DEMO](https://gitofzgt.github.io/vite-dynamictheme-antd-vue-demo/) [在线DEMO源码](https://github.com/GitOfZGT/vite-dynamictheme-antd-vue-demo) +[demo源码之一](https://github.com/GitOfZGT/vite-dynamictheme-antd-vue-demo) ![效果图](https://img-blog.csdnimg.cn/9bee30d711c54933a7e4ac0e28cdb7c3.gif#pic_center) @@ -32,7 +36,7 @@ yarn add color @zougt/vite-plugin-theme-preprocessor @zougt/some-loader-utils - **vite.config.js** -> 注意:以下的配置适用于 动态主题模式 , 预设主题模式 请往文档下面对应的看。 +> 注意:以下的配置只适用于 动态主题模式 , 预设主题模式 请往文档下面对应的看。 ```js import { defineConfig } from "vite"; @@ -108,6 +112,8 @@ export default defineConfig({ **在线切换主题** +动态主题切换必须使用的 "@setCustomTheme" 模块,会自动处理项目中包括组件库涉及的梯度颜色替换 + ```js import Color from "color"; // "@setCustomTheme" 是 themePreprocessorPlugin 提供的模块,setCustomTheme的参数必须提供Color模块,至于为什么不把 Color 直接依赖进去是有原因的 @@ -131,13 +137,15 @@ npx z-theme inspect **动态主题模式的原理** -一言难尽 +> 一言难尽 ## 预设主题模式 预设多种主题,其实也可以用动态主题模式来做,如需类似效果图中有暗黑主题的,可能使用此模式更加方便 -[在线DEMO](https://gitofzgt.github.io/dynamic-theme-demos/vite-antd-vue-preset-theme/) [在线DEMO源码](https://github.com/GitOfZGT/dynamic-theme-demos/tree/master/projects/vite-antd-vue-preset-theme) +[在线demo之一](https://gitofzgt.github.io/dynamic-theme-demos/vite-antd-vue-preset-theme/) + +[demo源码之一](https://github.com/GitOfZGT/dynamic-theme-demos/tree/master/projects/vite-antd-vue-preset-theme) ![效果图](https://img-blog.csdnimg.cn/caa3ccb9949a4fc4a6a8c7442291ed07.gif) @@ -152,7 +160,7 @@ yarn add @zougt/vite-plugin-theme-preprocessor -D **vite.config.js** -> 注意:以下的配置适用于 预设主题模式。文档的参数值都是默认值。 +> 注意:以下的配置只适用于 预设主题模式。文档的参数值都是默认值。 ```js import themePreprocessorPlugin from "@zougt/vite-plugin-theme-preprocessor"; @@ -221,7 +229,7 @@ export default { 1、开发时只需,html标签的calss添加对应的scopeName,移除上个scopeName 2、打包后,如果开启extract: true,需要切换对应的link标签的href -可以选择使用如下封装好的方法,都默认做了这些事情。 +可以选择使用如下封装好的方法,默认做好了这些事情。 ```js import { toggleTheme } from "@zougt/vite-plugin-theme-preprocessor/dist/browser-utils"; @@ -245,7 +253,7 @@ toggleTheme({ // vite.config.js export default { optimizeDeps: { - // 排除 browser-utils.js 在vite的缓存依赖 + // 排除 browser-utils.js 在vite的缓存依赖,对应 import { toggleTheme } from "@zougt/vite-plugin-theme-preprocessor/dist/browser-utils" 的路径 exclude: ["@zougt/vite-plugin-theme-preprocessor/dist/browser-utils"], }, }; diff --git a/package.json b/package.json index d4580ee..67b1d9c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zougt/vite-plugin-theme-preprocessor", - "version": "1.4.0-beta.9", + "version": "1.4.0", "description": "css theme preprocessor plugin for vite", "license": "MIT", "repository": "GitOfZGT/vite-plugin-theme-preprocessor", diff --git a/src/browser-utils.js b/src/browser-utils.js index ea02bd5..8937b40 100644 --- a/src/browser-utils.js +++ b/src/browser-utils.js @@ -34,6 +34,12 @@ function createThemeLinkTag({ id, href }) { styleLink.id = id; return styleLink; } +/** + * + * @param {object} opts + * @param {string} opts.scopeName + * @returns + */ export function toggleTheme(opts) { const options = { // multipleScopeVars: [], diff --git a/src/index.js b/src/index.js index 238f32e..8621fad 100644 --- a/src/index.js +++ b/src/index.js @@ -41,7 +41,8 @@ export default function themePreprocessorPlugin(options = {}) { .resolve(pack.name, { paths: [process.cwd()], }) - .replace(/[\\/]dist[\\/]index\.js$/, "").replace(/\\/g,'/'); + .replace(/[\\/]dist[\\/]index\.js$/, "") + .replace(/\\/g, "/"); const customThemeOutputPath = `${targetRsoleved}/setCustomTheme.js`; let buildCommand; const processorNames = Object.keys(options); @@ -99,6 +100,7 @@ export default function themePreprocessorPlugin(options = {}) { processorNames.forEach((lang) => { const langOptions = options[lang] || {}; + // 合并参数 defaultOptions = { ...defaultOptions, ...langOptions }; if ( Array.isArray(langOptions.multipleScopeVars) && @@ -112,21 +114,11 @@ export default function themePreprocessorPlugin(options = {}) { const founded = allmultipleScopeVars.find( (f) => f.scopeName === item.scopeName ); - if (founded) { - let paths = []; - if (Array.isArray(founded.path)) { - paths = paths.concat(founded.path); - } else if (founded.path) { - paths.push(founded.path); - } - if (Array.isArray(item.path)) { - paths = paths.concat(item.path); - } else if (item.path) { - paths.push(item.path); - } - founded.path = Array.from(new Set(paths)); - } else { - allmultipleScopeVars.push(item); + if (!founded) { + allmultipleScopeVars.push({ + ...item, + path: null, + }); } }); } @@ -134,7 +126,7 @@ export default function themePreprocessorPlugin(options = {}) { css.preprocessorOptions = preprocessorOptions; const modulesOptions = css.modules !== false ? css.modules || {} : null; - if (modulesOptions) { + if (modulesOptions && !defaultOptions.arbitraryMode) { modulesOptions.generateScopedName = getModulesScopeGenerater({ multipleScopeVars: allmultipleScopeVars, generateScopedName: modulesOptions.generateScopedName, @@ -150,32 +142,34 @@ export default function themePreprocessorPlugin(options = {}) { // 存储最终解析的配置 config = resolvedConfig; - const browerPreprocessorOptions = { - ...defaultOptions, - multipleScopeVars: allmultipleScopeVars, - }; - createPulignParamsFile({ extract: buildCommand !== "build" ? false : defaultOptions.extract, }); - - const packRoot = require - .resolve(pack.name, { - paths: [config.root], - }) - .replace(/[\\/]index\.js$/, "").replace(/\\/g,'/'); - // 将一些参数打入到 toBrowerEnvs.js , 由brower-utils.js 获取 - fsExtra.writeFileSync( - `${packRoot}/toBrowerEnvs.js`, - `export const browerPreprocessorOptions = ${JSON.stringify( - browerPreprocessorOptions - )};\nexport const basePath="${ - config.base || "" - }";\nexport const assetsDir="${ - config.build.assetsDir || "" - }";\nexport const buildCommand="${buildCommand}"; + if (!defaultOptions.arbitraryMode) { + // 预设主题模式,提供 brower-utils.js 需要的参数 + const browerPreprocessorOptions = { + ...defaultOptions, + multipleScopeVars: allmultipleScopeVars, + }; + const packRoot = require + .resolve(pack.name, { + paths: [config.root], + }) + .replace(/[\\/]index\.js$/, "") + .replace(/\\/g, "/"); + // 将一些参数打入到 toBrowerEnvs.js , 由brower-utils.js 获取 + fsExtra.writeFileSync( + `${packRoot}/toBrowerEnvs.js`, + `export const browerPreprocessorOptions = ${JSON.stringify( + browerPreprocessorOptions + )};\nexport const basePath="${ + config.base || "" + }";\nexport const assetsDir="${ + config.build.assetsDir || "" + }";\nexport const buildCommand="${buildCommand}"; ` - ); + ); + } if ( defaultOptions.arbitraryMode && preCustomThemeOutputPath !== defaultOptions.customThemeOutputPath @@ -215,9 +209,9 @@ export default function themePreprocessorPlugin(options = {}) { const resolveDir = `${pathnames .slice(0, index) .join("/")}/${resolveName}`; - const originalDir = path.resolve( - "node_modules/.zougtTheme/original" - ) .replace(/\\/g, "/"); + const originalDir = path + .resolve("node_modules/.zougtTheme/original") + .replace(/\\/g, "/"); if ( !fsExtra.existsSync(resolveDir) && !fsExtra.existsSync(`${originalDir}/${resolveName}`) @@ -269,22 +263,6 @@ export default function themePreprocessorPlugin(options = {}) { }); ` ); - // 如果 源less中存在bin,生成一份替代品的bin - // if (fsExtra.existsSync(`${resolveDir}/bin`)) { - // fsExtra.readdirSync(`${resolveDir}/bin`).forEach((name) => { - // if (fsExtra.statSync(`${resolveDir}/bin/${name}`).isFile()) { - // if (!fsExtra.existsSync(`${substitutePreprocessorDir}/bin`)) { - // fsExtra.mkdirSync(`${substitutePreprocessorDir}/bin`); - // } - // fsExtra.writeFileSync( - // `${substitutePreprocessorDir}/bin/${name}`, - // `#!/usr/bin/env node\n"use strict";\n - // require("${originalDir}/${resolveName}/bin/${name}"); - // ` - // ); - // } - // }); - // } // 替换了处理器的标识 @@ -325,12 +303,14 @@ export default function themePreprocessorPlugin(options = {}) { return null; }, load(id) { + // 动态主题模式下 加载虚拟模块 "@setCustomTheme" if ( id === "@setCustomTheme" && defaultOptions.arbitraryMode && defaultOptions.customThemeOutputPath ) { if (buildCommand !== "build") { + // 开发模式 return `import { default as setCustomTheme } from "${defaultOptions.customThemeOutputPath}"; export default setCustomTheme; import Color from "color"; @@ -339,11 +319,13 @@ export default function themePreprocessorPlugin(options = {}) { }) `; } + // 打包时"@setCustomTheme"模块的内容,会在 renderChunk 进行源码替换 return `${setCustomThemeCodeReplacer};export default setCustomTheme;`; } return null; }, renderChunk(code) { + // 打包才会进入这个钩子 if ( defaultOptions.arbitraryMode && code.includes(setCustomThemeCodeReplacer) @@ -457,7 +439,7 @@ export default function themePreprocessorPlugin(options = {}) { } /** - * 主题热更新插件 + * 动态主题模式的热更新插件 * @returns object */ @@ -465,7 +447,9 @@ function themePreprocessorHmrPlugin() { let parentApi = null; let cacheThemeStyleContent = ""; let buildCommand = ""; + // 触发热更新时的 样式文件 const hotUpdateStyleFiles = new Set(); + // 进入transform的样式文件 const transformStyleFiles = new Set(); let hotServer = null; let config = {}; @@ -481,6 +465,7 @@ function themePreprocessorHmrPlugin() { config = resolvedConfig; }, buildStart() { + // 获取依赖插件提供的 方法 const parentName = "vite-plugin-theme-preprocessor"; const parentPlugin = config.plugins.find( (plugin) => plugin.name === parentName @@ -492,15 +477,18 @@ function themePreprocessorHmrPlugin() { parentApi = parentPlugin.api; }, transform(code, id) { + // vite:css插件内的transform使用less/sass,需要在less/sass编译完后调用 getThemeStyleContent const defaultOptions = parentApi.getOptions(); if ( defaultOptions.arbitraryMode && /\.(less|scss|sass)(\?.+)?/.test(id) ) { transformStyleFiles.add(id); + + // 当transform的的样式文件数量 到达 触发热更新的样式文件数量时,就获取主题css,并触发热更新事件 import.meta.hot.on('custom-theme-update',()=>{}) if ( hotUpdateStyleFiles.size && - hotUpdateStyleFiles.size <= transformStyleFiles.size + hotUpdateStyleFiles.size === transformStyleFiles.size ) { getThemeStyleContent(); createSetCustomTheme({ @@ -559,6 +547,7 @@ function themePreprocessorHmrPlugin() { } }); } + if (file === customThemeOutputPath) { return Promise.resolve([]); }