vueComponent / ant-design-vue

🌈 An enterprise-class UI components based on Ant Design and Vue. 🐜
https://antdv.com/
Other
20.28k stars 3.79k forks source link

Support vite-plugin-components to load ant-design-vue2.x on demand #3916

Closed reaink closed 3 years ago

reaink commented 3 years ago

What problem does this feature solve?

issues: https://github.com/antfu/vite-plugin-components/issues/35

At present, MenuItem, MenuItemGroup and other components are exported as subcomponents, which does not support on-demand introduction

Need to be exported separately to support

What does the proposed API look like?

default

zkwolf commented 3 years ago

umm...我先去看看插件都做了啥

reaink commented 3 years ago

@zkwolf 按需引入,减少包大小

ajuner commented 3 years ago

这个包好像不能把css加进来吧

reaink commented 3 years ago

这个包好像不能把css加进来吧

可以自己写引入时响应,带上./style就可以实现了

EngHell commented 3 years ago

you can check this example here https://github.com/antfu/vite-plugin-components/blob/master/src/resolvers/element-plus.ts where the package imports style too

agoni1212 commented 3 years ago

you can check this example here https://github.com/antfu/vite-plugin-components/blob/master/src/resolvers/element-plus.ts where the package imports style too

Key is MenuItem, MenuItemGroup, LayoutSider, LayoutHeader and other components are exported as subcomponents

if u config the sideEffects to load style on demand, u will still got the error message

// Import kebabCase for formatting
import ViteComponents, { kebabCase } from 'vite-plugin-components'
ViteComponents({
  customComponentResolvers: [
    (name) => {
      if (name.match(/^A[A-Z]/)) { // Ant Design Vue
        const importName = name.slice(1)
        const dirName = kebabCase(importName) // e.g. date-picker
        return { 
          importName, 
          path: 'ant-design-vue/es',
          sideEffects: `ant-design-vue/es/${dirName}/style`,
        }
      } 
    }
  ]
})

@zkwolf any idea to share, appreciate

nabaonan commented 3 years ago

今天试了一下 naive完美支持, element我的自定义方法和官方的差不多,我没有引入sass,用css定义的,方法如下:

  ViteComponents({
      customComponentResolvers: [
        // AntDesignVueResolver(),
        // ElementPlusResolver(),
        NaiveUiResolver(),
        name => {
          if (name.startsWith("El")) {
            // Element UI
            const partialName = kebabCase(name); //ElButton->el-button
            return {
              path: `element-plus/lib/${partialName}`,
              sideEffects: `element-plus/lib/theme-chalk/${partialName}.css`,
            };
          } else if (name.match(/^A[A-Z]/)) {
            //ant-design-vue

            const importName = name.slice(1);
            const dirName = kebabCase(importName);
            const compName = pascalCase(importName); //AListItem->ListItem
            const compPath = getCompPath(compName);

            const sideEffects = [
              {
                path: `ant-design-vue/es/${compPath.styleDir}/style`,
              },
            ];
            if (compPath.sideEffects) {
              sideEffects.push(compPath.sideEffects);
            }
            return {
              path: `ant-design-vue/es/${compPath.dirName}/${compPath.compName}`,
              sideEffects,
            };
          }
          return null;
        },
      ],
      globalComponentsDeclaration: true,
    }),

至于antd,写了一个getCompPath方法,用来生成子组件的导入的路径,发现有很多组件的书写方式不一致,有的是直接用vc-xxx,比如ListItem组件就直接是在list下的Item文件,比如这个组件,在menu下叫MenuItem, 还有一些无法引入独立文件的组件有:ListItemMeta是一个函数式组件,layout下的是通过工厂函数生产的footer和content,像这种就没有想出什么好方法导入,还有命名规则不统一的子组件,,每个组件命名的规则都不尽相同,针对各种情况定义了集合判断每种情况,生成对应组件路径,具体getCompPath代码如下:

function getCompPath(
  compName: string
): {
  dirName: string;
  compName: string;
  styleDir: string;
  importName?: string;
  sideEffects?: ImportInfo;
} {
  const hasSubComp = [
    "Menu",
    "Layout",
    "Form",
    "Table",
    "Modal",
    "Radio",
    "Button",
    "Checkbox",
    "List",
    "Collapse",
    "Descriptions",
    "Tabs",
    "Mentions",
    "Select",
    "Anchor",
    "Typography",
    // "TreeSelect",
  ]; //包含子组件的组件
  const keepSelf = [
    "MenuItem",
    "SubMenu",
    "FormItem",
    "RadioButton",
    "CollapsePanel",
    "TabPane",
    "AnchorLink",
  ]; //保留原子组件名称
  const keepFather = [
    "LayoutHeader",
    "LayoutContent",
    "LayoutFooter",
    "DescriptionsItem",
  ]; //需要使用父组件名称的子组件  LayoutFooter->''  之所以转成空是因为最后拼接的结果是dirName+compName,避免重复
  const rootName = hasSubComp.find((name: string) => compName.startsWith(name));
  const usePrevLevelName = ["ListItemMeta"]; //使用当前组件的上一级名称  ListItemMeta->Item
  const getPrevLevelName = () => {
    const split = kebabCase(compName).split("-");
    return pascalCase(split[split.length - 2]);
  };

  const fatherAlias = {
    TabPane: "vc-tabs/src",
    MentionsOption: "vc-mentions/src",
    SelectOption: "vc-select",
    TreeSelectNode: "vc-tree-select/src",
  };

  const compAlias = {
    TreeSelectNode: "SelectNode",
  };

  const styleMap = {
    TabPane: "tabs",
    MentionsOption: "mentions",
    SelectOption: "select",
    TreeSelectNode: "tree-select",
  };
  // const importNameMap = {
  //   LayoutContent: "Content",
  //   LayoutHeader: "Header",
  //   LayoutFooter: "Footer",
  // };

  let dirName = rootName?.toLowerCase() ?? kebabCase(compName);

  if (fatherAlias[compName]) {
    dirName = fatherAlias[compName];
  }

  let compNameStr = "";
  if (keepSelf.includes(compName)) {
    compNameStr = compName;
  } else if (keepFather.includes(compName)) {
    compNameStr = "";
  } else if (usePrevLevelName.includes(compName)) {
    compNameStr = getPrevLevelName();
  } else if (rootName) {
    compNameStr = compName.replace(rootName, "");
  }
  const compRequired = {
    TypographyTitle: "ant-design-vue/es/" + dirName + "/Base",
    TypographyText: "ant-design-vue/es/" + dirName + "/Base",
  };

  return {
    // importName: importNameMap[compName],
    dirName: fatherAlias[compName] ?? dirName,
    styleDir: `${styleMap[compName] ?? dirName}`,
    compName: compAlias[compName] ?? compNameStr,
    sideEffects: compRequired[compName]
      ? {
          path: compRequired[compName],
        }
      : undefined,
  };
}

未解决的组件:layout的Content,Header,Footer ,typography下的组件(有报错,baseProps 不是一个方法,不知为什么没有导入进来),List的ListItemMeta

感觉写的挺麻烦的,希望大佬们指点一下,提供一个更简洁优雅的解决方案

最后附上我的demo地址demo地址 分支是feat-on-demand

nabaonan commented 3 years ago

看了一下layout中的content,footer header没有export出去,希望可以export出来,这样应该就更容易导入了,react版是在layout.tsx 中export出来的

tangjinzhou commented 3 years ago

我们来支持下吧

github-actions[bot] commented 3 years ago

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days

github-actions[bot] commented 2 years ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.