Просмотр исходного кода

feat(pc-components): 支持 babel-plugin-import 按需引入

chenlei 2 лет назад
Родитель
Сommit
a5666e2731
24 измененных файлов с 240 добавлено и 53 удалено
  1. 5 0
      packages/backend-cli/template/config/webpack.config.js
  2. 24 0
      packages/pc-components/babel-import-config.js
  3. 2 1
      packages/pc-components/package.json
  4. 114 0
      packages/pc-components/scripts/metadata.js
  5. 8 0
      packages/pc-components/src/components/DageFileCheckbox/constants.ts
  6. 75 37
      packages/pc-components/src/components/FileCheckbox/index.tsx
  7. 0 0
      packages/pc-components/src/components/DageFileCheckbox/style.ts
  8. 7 3
      packages/pc-components/src/components/FileCheckbox/types.ts
  9. 0 0
      packages/pc-components/src/components/DageMap/index.tsx
  10. 0 0
      packages/pc-components/src/components/DageMap/plugins/Geocoder/index.ts
  11. 0 0
      packages/pc-components/src/components/DageMap/plugins/Geocoder/types.ts
  12. 0 0
      packages/pc-components/src/components/DageMap/plugins/index.ts
  13. 0 0
      packages/pc-components/src/components/DageMap/types.ts
  14. 0 0
      packages/pc-components/src/components/DageMap/utils.ts
  15. 0 0
      packages/pc-components/src/components/DageTableActions/index.tsx
  16. 0 0
      packages/pc-components/src/components/DageUpload/ItemActions.tsx
  17. 0 0
      packages/pc-components/src/components/DageUpload/context.tsx
  18. 0 0
      packages/pc-components/src/components/DageUpload/index.tsx
  19. 0 0
      packages/pc-components/src/components/DageUpload/style.ts
  20. 0 0
      packages/pc-components/src/components/DageUpload/types.ts
  21. 0 0
      packages/pc-components/src/components/DageUpload/utils.ts
  22. 0 8
      packages/pc-components/src/components/FileCheckbox/constants.ts
  23. 4 4
      packages/pc-components/src/components/index.ts
  24. 1 0
      packages/pc-components/src/noncomponents.ts

+ 5 - 0
packages/backend-cli/template/config/webpack.config.js

@@ -4,6 +4,7 @@ const fs = require("fs");
 const path = require("path");
 const webpack = require("webpack");
 const resolve = require("resolve");
+const componentImportOptions = require("@dage/pc-components/babel-import-config");
 const HtmlWebpackPlugin = require("html-webpack-plugin");
 const CaseSensitivePathsPlugin = require("case-sensitive-paths-webpack-plugin");
 const InlineChunkHtmlPlugin = require("react-dev-utils/InlineChunkHtmlPlugin");
@@ -426,6 +427,10 @@ module.exports = function (webpackEnv) {
                   isEnvDevelopment &&
                     shouldUseReactRefresh &&
                     require.resolve("react-refresh/babel"),
+                  isEnvProduction && [
+                    "babel-plugin-import",
+                    componentImportOptions,
+                  ],
                 ].filter(Boolean),
                 // This is a feature of `babel-loader` for webpack (not Babel itself).
                 // It enables caching results in ./node_modules/.cache/babel-loader/

+ 24 - 0
packages/pc-components/babel-import-config.js

@@ -0,0 +1,24 @@
+const mapper = require("./dist/metadata.json");
+
+/**
+ * @type {{[key: string]: string}}
+ */
+const mapperCompiled = {};
+
+for (const key in mapper) {
+  mapper[key].forEach((i) => {
+    mapperCompiled[i] = key;
+  });
+}
+
+module.exports = {
+  libraryName: "@dage/pc-components",
+  camel2DashComponentName: false,
+  customName: (name) => {
+    if (name in mapperCompiled) {
+      return `@dage/pc-components/dist/components/${mapperCompiled[name]}`;
+    }
+    return `@dage/pc-components/dist/noncomponents`;
+  },
+  transformToDefaultImport: false,
+};

+ 2 - 1
packages/pc-components/package.json

@@ -13,7 +13,8 @@
     "prebuild": "rimraf dist",
     "build": "tsc --build tsconfig.build.json",
     "copy": "cpx \"src/**/*.+(scss|jpg|jpeg|gif|png|svg|css)\" ./dist",
-    "postbuild": "npm run copy",
+    "metadata": "node ./scripts/metadata.js",
+    "postbuild": "npm run copy && npm run metadata",
     "type-check": "tsc --noEmit",
     "test": "jest"
   },

+ 114 - 0
packages/pc-components/scripts/metadata.js

@@ -0,0 +1,114 @@
+const babel = require("@babel/core");
+const fs = require("fs");
+const path = require("path");
+const t = babel.types;
+
+const dirs = fs
+  .readdirSync(path.join(__dirname, "../src/components"))
+  .filter((file) => file.startsWith("Dage"));
+
+/**
+ * @type {{[name: string]: string[]}}
+ */
+const mapper = {};
+const extensions = [".ts", ".tsx"];
+
+const findFile = (file) => {
+  if (fs.existsSync(file)) {
+    if (fs.statSync(file).isDirectory()) {
+      return findFile(path.join(file, "index"));
+    }
+
+    return file;
+  }
+
+  for (const ext of extensions) {
+    const f = `${file}${ext}`;
+    if (fs.existsSync(f)) {
+      return f;
+    }
+  }
+
+  return null;
+};
+
+const walk = (context, entry) => {
+  const base = path.basename(context);
+
+  const addMapper = (name) => {
+    mapper[base] = mapper[base] || [];
+    mapper[base].push(name);
+  };
+  /**
+   * @type {import('@babel/core').PluginObj}
+   */
+  const plugin = {
+    visitor: {
+      ExportNamedDeclaration(path) {
+        const decl = path.node.declaration;
+
+        if (t.isVariableDeclaration(decl)) {
+          decl.declarations.forEach((i) => {
+            if (t.isIdentifier(i.id)) {
+              addMapper(i.id.name);
+            }
+          });
+        } else if (
+          (t.isFunctionDeclaration(decl) ||
+            t.isTSInterfaceDeclaration(decl) ||
+            t.isTSTypeAliasDeclaration(decl) ||
+            t.isTSEnumDeclaration(decl) ||
+            t.isClassDeclaration(decl)) &&
+          t.isIdentifier(decl.id)
+        ) {
+          addMapper(decl.id.name);
+        } else if (path.node.specifiers?.length) {
+          path.node.specifiers.forEach((i) => {
+            addMapper(i.exported.name);
+          });
+        }
+      },
+      ExportAllDeclaration(p) {
+        // 递归
+        if (p.node.source.value.startsWith("./")) {
+          const relativeEntry = findFile(
+            path.join(path.dirname(entry), p.node.source.value)
+          );
+          walk(context, relativeEntry);
+        }
+      },
+    },
+  };
+
+  babel.transformFileSync(entry, {
+    root: path.join(__dirname, "../"),
+    configFile: false,
+    babelrc: false,
+    parserOpts: {
+      plugins: [
+        "decorators-legacy",
+        "classProperties",
+        "dynamicImport",
+        "typescript",
+        "jsx",
+      ],
+    },
+    plugins: [plugin],
+  });
+};
+
+dirs.forEach((dir) => {
+  const context = path.join(__dirname, "../src/components", dir);
+  const entry = findFile(path.join(context, "index"));
+
+  if (entry == null) {
+    return;
+  }
+
+  walk(context, entry);
+});
+
+fs.writeFileSync(
+  path.join(__dirname, "../dist/metadata.json"),
+  JSON.stringify(mapper, null, 2)
+);

+ 8 - 0
packages/pc-components/src/components/DageFileCheckbox/constants.ts

@@ -0,0 +1,8 @@
+import { DageUploadType } from "../DageUpload";
+
+export const DAGE_FILE_CHECKBOX_OPTIONS = [
+  { label: "模型", value: DageUploadType.MODEL },
+  { label: "图片", value: DageUploadType.IMG },
+  { label: "音频", value: DageUploadType.AUDIO },
+  { label: "视频", value: DageUploadType.VIDEO },
+];

+ 75 - 37
packages/pc-components/src/components/FileCheckbox/index.tsx

@@ -1,12 +1,26 @@
-import { Checkbox } from 'antd';
-import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useState } from 'react';
-import { CheckboxValueType } from 'antd/es/checkbox/Group';
-import { DAGE_FILE_CHECKBOX_OPTIONS } from './constants';
-import { DageFileCheckboxMethods, DageFileCheckboxProps } from './types';
-import { DageFileResponseType, DageUpload, DageUploadType } from '../Upload';
-import { FileCheckboxItem } from './style';
+import { Checkbox } from "antd";
+import {
+  forwardRef,
+  useCallback,
+  useEffect,
+  useImperativeHandle,
+  useMemo,
+  useState,
+} from "react";
+import { CheckboxValueType } from "antd/es/checkbox/Group";
+import { DAGE_FILE_CHECKBOX_OPTIONS } from "./constants";
+import { DageFileCheckboxMethods, DageFileCheckboxProps } from "./types";
+import {
+  DageFileResponseType,
+  DageUpload,
+  DageUploadType,
+} from "../DageUpload";
+import { FileCheckboxItem } from "./style";
 
-export const DageFileCheckbox = forwardRef<DageFileCheckboxMethods, DageFileCheckboxProps>(
+export const DageFileCheckbox = forwardRef<
+  DageFileCheckboxMethods,
+  DageFileCheckboxProps
+>(
   (
     {
       value,
@@ -21,47 +35,65 @@ export const DageFileCheckbox = forwardRef<DageFileCheckboxMethods, DageFileChec
       onChange,
       onFileChange,
     },
-    ref,
+    ref
   ) => {
-    const checkboxVal = useMemo(() => (value ? value.split(',') : []), [value]);
+    const checkboxVal = useMemo(() => (value ? value.split(",") : []), [value]);
     const [modelFiles, setModelFiles] = useState<DageFileResponseType[]>([]);
-    const [mobileModelFiles, setMobileModelFiles] = useState<DageFileResponseType[]>([]);
+    const [mobileModelFiles, setMobileModelFiles] = useState<
+      DageFileResponseType[]
+    >([]);
     const [imgFiles, setImgFiles] = useState<DageFileResponseType[]>([]);
     const [videoFiles, setVideoFiles] = useState<DageFileResponseType[]>([]);
     const [audioFiles, setAudioFiles] = useState<DageFileResponseType[]>([]);
 
-    const hasModel = useMemo(() => checkboxVal.includes(DageUploadType.MODEL), [checkboxVal]);
-    const hasImg = useMemo(() => checkboxVal.includes(DageUploadType.IMG), [checkboxVal]);
-    const hasAudio = useMemo(() => checkboxVal.includes(DageUploadType.AUDIO), [checkboxVal]);
-    const hasVideo = useMemo(() => checkboxVal.includes(DageUploadType.VIDEO), [checkboxVal]);
+    const hasModel = useMemo(
+      () => checkboxVal.includes(DageUploadType.MODEL),
+      [checkboxVal]
+    );
+    const hasImg = useMemo(
+      () => checkboxVal.includes(DageUploadType.IMG),
+      [checkboxVal]
+    );
+    const hasAudio = useMemo(
+      () => checkboxVal.includes(DageUploadType.AUDIO),
+      [checkboxVal]
+    );
+    const hasVideo = useMemo(
+      () => checkboxVal.includes(DageUploadType.VIDEO),
+      [checkboxVal]
+    );
 
     useImperativeHandle(ref, () => ({
       validate(rule, val, callback) {
         if (!val) {
-          callback('请选择文件类型');
+          callback("请选择文件类型");
         } else if (
           hasModel &&
-          (!modelFiles.length || !modelFiles.some((i) => i.status === 'done'))
+          (!modelFiles.length || !modelFiles.some((i) => i.status === "done"))
         ) {
-          callback('PC端模型文件不能为空');
+          callback("PC端模型文件不能为空");
         } else if (
           hasModel &&
           hasMobileModel &&
-          (!mobileModelFiles.length || !mobileModelFiles.some((i) => i.status === 'done'))
+          (!mobileModelFiles.length ||
+            !mobileModelFiles.some((i) => i.status === "done"))
+        ) {
+          callback("移动端模型文件不能为空");
+        } else if (
+          hasImg &&
+          (!imgFiles.length || !imgFiles.some((i) => i.status === "done"))
         ) {
-          callback('移动端模型文件不能为空');
-        } else if (hasImg && (!imgFiles.length || !imgFiles.some((i) => i.status === 'done'))) {
-          callback('图片文件不能为空');
+          callback("图片文件不能为空");
         } else if (
           hasVideo &&
-          (!videoFiles.length || !videoFiles.some((i) => i.status === 'done'))
+          (!videoFiles.length || !videoFiles.some((i) => i.status === "done"))
         ) {
-          callback('视频文件不能为空');
+          callback("视频文件不能为空");
         } else if (
           hasAudio &&
-          (!audioFiles.length || !audioFiles.some((i) => i.status === 'done'))
+          (!audioFiles.length || !audioFiles.some((i) => i.status === "done"))
         ) {
-          callback('音频文件不能为空');
+          callback("音频文件不能为空");
         }
         callback();
       },
@@ -104,16 +136,19 @@ export const DageFileCheckbox = forwardRef<DageFileCheckboxMethods, DageFileChec
 
     const handleCheckbox = useCallback(
       (val: CheckboxValueType[]) => {
-        onChange?.(val.join(','));
+        onChange?.(val.join(","));
       },
-      [onChange],
+      [onChange]
     );
 
     const handleFileChange = useCallback(
-      (method: (v: DageFileResponseType[]) => void, list: DageFileResponseType[]) => {
+      (
+        method: (v: DageFileResponseType[]) => void,
+        list: DageFileResponseType[]
+      ) => {
         method(list);
       },
-      [],
+      []
     );
 
     useEffect(() => {
@@ -147,9 +182,9 @@ export const DageFileCheckbox = forwardRef<DageFileCheckboxMethods, DageFileChec
           value={checkboxVal}
           options={DAGE_FILE_CHECKBOX_OPTIONS}
           style={{
-            display: 'flex',
-            alignItems: 'center',
-            height: '32px',
+            display: "flex",
+            alignItems: "center",
+            height: "32px",
           }}
           onChange={handleCheckbox}
         />
@@ -181,7 +216,10 @@ export const DageFileCheckbox = forwardRef<DageFileCheckboxMethods, DageFileChec
                   maxCount={maxMobileModelCount}
                   maxSize={1000}
                   tips="仅支持zip格式的压缩包,大小不能超过1000M"
-                  onChange={handleFileChange.bind(undefined, setMobileModelFiles)}
+                  onChange={handleFileChange.bind(
+                    undefined,
+                    setMobileModelFiles
+                  )}
                 />
               </FileCheckboxItem>
             )}
@@ -234,8 +272,8 @@ export const DageFileCheckbox = forwardRef<DageFileCheckboxMethods, DageFileChec
         )}
       </div>
     );
-  },
+  }
 );
 
-export * from './types';
-export * from './constants';
+export * from "./types";
+export * from "./constants";

packages/pc-components/src/components/FileCheckbox/style.ts → packages/pc-components/src/components/DageFileCheckbox/style.ts


+ 7 - 3
packages/pc-components/src/components/FileCheckbox/types.ts

@@ -1,11 +1,15 @@
-import { RuleObject } from 'antd/es/form';
-import { DageFileResponseType } from '../Upload';
+import { RuleObject } from "antd/es/form";
+import { DageFileResponseType } from "../DageUpload";
 
 export interface DageFileCheckboxMethods {
   /**
    * 校验已选类型文件是否为空
    */
-  validate(rule: RuleObject, value: any, callback: (error?: string | undefined) => void): void;
+  validate(
+    rule: RuleObject,
+    value: any,
+    callback: (error?: string | undefined) => void
+  ): void;
   setFileList(list: DageFileResponseType[]): void;
 }
 

packages/pc-components/src/components/Map/index.tsx → packages/pc-components/src/components/DageMap/index.tsx


packages/pc-components/src/components/Map/plugins/Geocoder/index.ts → packages/pc-components/src/components/DageMap/plugins/Geocoder/index.ts


packages/pc-components/src/components/Map/plugins/Geocoder/types.ts → packages/pc-components/src/components/DageMap/plugins/Geocoder/types.ts


packages/pc-components/src/components/Map/plugins/index.ts → packages/pc-components/src/components/DageMap/plugins/index.ts


packages/pc-components/src/components/Map/types.ts → packages/pc-components/src/components/DageMap/types.ts


packages/pc-components/src/components/Map/utils.ts → packages/pc-components/src/components/DageMap/utils.ts


packages/pc-components/src/components/TableActions/index.tsx → packages/pc-components/src/components/DageTableActions/index.tsx


packages/pc-components/src/components/Upload/ItemActions.tsx → packages/pc-components/src/components/DageUpload/ItemActions.tsx


packages/pc-components/src/components/Upload/context.tsx → packages/pc-components/src/components/DageUpload/context.tsx


packages/pc-components/src/components/Upload/index.tsx → packages/pc-components/src/components/DageUpload/index.tsx


packages/pc-components/src/components/Upload/style.ts → packages/pc-components/src/components/DageUpload/style.ts


packages/pc-components/src/components/Upload/types.ts → packages/pc-components/src/components/DageUpload/types.ts


packages/pc-components/src/components/Upload/utils.ts → packages/pc-components/src/components/DageUpload/utils.ts


+ 0 - 8
packages/pc-components/src/components/FileCheckbox/constants.ts

@@ -1,8 +0,0 @@
-import { DageUploadType } from '../Upload';
-
-export const DAGE_FILE_CHECKBOX_OPTIONS = [
-  { label: '模型', value: DageUploadType.MODEL },
-  { label: '图片', value: DageUploadType.IMG },
-  { label: '音频', value: DageUploadType.AUDIO },
-  { label: '视频', value: DageUploadType.VIDEO },
-];

+ 4 - 4
packages/pc-components/src/components/index.ts

@@ -1,4 +1,4 @@
-export * from './FileCheckbox';
-export * from './Map';
-export * from './Upload';
-export * from './TableActions';
+export * from "./DageFileCheckbox";
+export * from "./DageMap";
+export * from "./DageUpload";
+export * from "./DageTableActions";

+ 1 - 0
packages/pc-components/src/noncomponents.ts

@@ -0,0 +1 @@
+export * from "./utils";