ant-design-vue antd-theme-webpack-plugin 動態改變主題

kxh166發表於2020-11-21

安裝

npm install -D antd-theme-webpack-plugin

關鍵原始碼

構造器選項:

const defaulOptions = {
  varFile: path.join(__dirname, "../../src/styles/variables.less"),
  antDir: path.join(__dirname, "../../node_modules/antd"),
  stylesDir: path.join(__dirname, "../../src/styles/antd"),
  themeVariables: ["@primary-color"],
  indexFileName: "index.html",
  generateOnce: false,
  lessUrl:
    "https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js",
  publicPath: ""
};

編譯過程:

compiler.hooks.emit.tapAsync('AntDesignThemePlugin', (compilation, callback) => { 
  const less = `
<link rel="stylesheet/less" type="text/css" href="${options.publicPath}/color.less" />
<script>
  window.less = {
    async: false,
    env: 'production'
  };
</script>
<script type="text/javascript" src="${options.lessUrl}"></script>
    `;
  if (
    options.indexFileName &&
    options.indexFileName in compilation.assets
  ) {
    const index = compilation.assets[options.indexFileName];
    let content = index.source();

    if (!content.match(/\/color\.less/g)) {
      index.source = () =>
        content.replace(less, "").replace(/<body>/gi, `<body>${less}`);
      content = index.source();
      index.size = () => content.length;
    }
  }

從原始碼可看出:若 index.html 檔案中沒有相關樣式、指令碼程式碼時,會自動在 body 開始標籤新增

使用

環境版本:

  • @vue/cli 4.5.8
  • ant-design-vue 1.7.2
  • antd-theme-webpack-plugin 1.3.7
  • less 3.0.4
  • less-loader 5.0.0

在 vue.config.js 中

const AntDesignThemePlugin = require("antd-theme-webpack-plugin");

module.exports = {

  css: {
    loaderOptions: {
      less: {
        modifyVars: { },
        javascriptEnabled: true
      }
    },
    extract: false
  },

  configureWebpack: {
	plugins: [

	    new AntDesignThemePlugin({
		  // ant 目錄
	      antDir: resolve("./node_modules/ant-design-vue"),
		  // 樣式目錄 會獲取該目錄下的 less 檔案編譯
	      stylesDir: resolve("./src/styles"),
		  // 變數檔案 
	      varFile: resolve(
			// ant-design-vue 變數檔案
	        // "./node_modules/ant-design-vue/lib/style/themes/default.less"
			// 自定義變數檔案 該檔案需要引入 ant-design-vue 變數檔案:@import "~ant-design-vue/lib/style/themes/default.less";
	        "./src/styles/themes/variables.less"
	      ),
	      themeVariables: [
	        "@primary-color",
	        "@secondary-color",
	        "@text-color",
	        "@text-color-secondary",
	        "@heading-color",
	        "@layout-body-background",
	        "@btn-primary-bg",
	        "@layout-header-background"
	      ],
	      generateOnce: false,
		  // 預設
	      indexFileName: "index.html",
		  // 預設
	      lessUrl:
	        "https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js",
		  // 實際上是專案名
	      publicPath: "/[proj_name]"
	      // customColorRegexArray: [] // An array of regex codes to match your custom color variable values so that code can identify that it's a valid color. Make sure your regex does not adds false positives.
	    })

	]
};

[proj_name] 需要修改成自身的專案名

執行 npm run build 命令生成 color.less 檔案:遇到以下異常:

Building for production...error [LessError: error evaluating function `darken`: color.toHSL is not a function] {
  message: 'error evaluating function `darken`: color.toHSL is not a function',
  stack: undefined,
  type: 'Runtime',
  filename: 'input',
  index: 363260,
  line: 16057,
  column: 32,
  callLine: NaN,
  callExtract: undefined,
  extract: [
    "@table-header-sort-active-bg: ~'darken(@table-header-bg, 3%)';",
    '@table-header-filter-active-bg: darken(@table-header-sort-active-bg, 5%);',
    '@table-selection-column-width: 60px;'
  ]
}

需要在 ant-design-vue 變數檔案【node_modules/ant-design-vue/lib/style/themes/default.less】加上以下使用 =========== 包裹的程式碼:建議在 // Table 註釋下加上

// Table
// --
===========
@table-header-sort-active-bg: darken(@table-header-bg, 3%);
@table-header-filter-active-bg: darken(@table-header-sort-active-bg, 5%);
@table-selection-column-width: 60px;
===========
@table-header-bg: @background-color-light;

加上後執行 npm run build 命令成功生成 color.less 檔案 檢視 index.html 檔案可發現 body 開始標籤下多出相關的樣式、指令碼程式碼:

<body> 
<link rel="stylesheet/less" type="text/css" href="/vue-antd-admin/color.less"><script>window.less = {
    async: false,
    env: true ? 'production' : 'development',
    javascriptEnabled: true,
    modifyVars: { },
};</script><script src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.js"></script><noscript><strong>We're sorry but Vue Antd Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript>

若要在開發環境中執行,需要將 color.less 檔案複製到 public 目錄,並在 public 目錄中的 index.htmlbody 開始標籤下新增以下程式碼:

<link rel="stylesheet/less" type="text/css" href="<%= BASE_URL %>color.less" />
<script>
  window.less = {
      async: false,
      env: 'production',
      javascriptEnabled: true,
      modifyVars: { },
  };
</script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.js"></script>

執行 npm run serve 命令後,在控制檯測試

window.less.modifyVars({
	"@primary-color": "#db8b12", 
	'@link-color': '#ee5e7b', 
	'@btn-primary-bg': '#db8b12', 
	"@primary-color2": "#db8b12"
})

@primary-color2 在自定義變數檔案定義,在其他樣式檔案使用時,需要先引入自定義變數檔案

至此,可以成功動態修改主題,但是耗費效能。在 ant-design-vue 官方的後臺管理系統 ant-design-vue-pro 使用 webpack-theme-color-replacer 動態修改,無需編譯 less

相關文章