UNPKG

dumi

Version:

📖 Documentation Generator of React Component

457 lines (437 loc) • 16 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/features/theme/index.ts var theme_exports = {}; __export(theme_exports, { default: () => theme_default }); module.exports = __toCommonJS(theme_exports); var import_constants = require("../../constants"); var import_bundler_utils = require("@umijs/bundler-utils"); var import_child_process = require("child_process"); var import_fs = __toESM(require("fs")); var import_hosted_git_info = __toESM(require("hosted-git-info")); var import_path = __toESM(require("path")); var import_plugin_utils = require("umi/plugin-utils"); var import_derivative = require("../derivative"); var import_loader = __toESM(require("./loader")); var DEFAULT_THEME_PATH = import_path.default.join(__dirname, "../../../theme-default"); function getPkgThemeName(api) { if (process.env.DUMI_THEME) { const envThemePkgPath = require.resolve( import_path.default.join(process.env.DUMI_THEME, "package.json"), { paths: [api.cwd] } ); return require(envThemePkgPath).name; } const validDeps = Object.assign( {}, api.pkg.dependencies, api.pkg.devDependencies ); const pkgThemeName = Object.keys(validDeps).find( (pkg) => pkg.split("/").pop().startsWith(import_constants.THEME_PREFIX) ); return pkgThemeName; } function getPkgThemePath(api) { const pkgThemeName = getPkgThemeName(api); if (process.env.DUMI_THEME) { return import_path.default.resolve(api.cwd, process.env.DUMI_THEME); } return pkgThemeName && import_path.default.dirname( import_plugin_utils.resolve.sync(`${pkgThemeName}/package.json`, { basedir: api.cwd, preserveSymlinks: true }) ); } async function getModuleExports(modulePath) { const [_, exports] = await (0, import_bundler_utils.parseModule)({ path: modulePath, content: import_fs.default.readFileSync(modulePath, "utf-8") }); return exports || []; } function checkMinor2ByPkg(pkg) { var _a, _b, _c; if ((_a = pkg.name) == null ? void 0 : _a.startsWith("@examples/")) return true; const ver = ((_b = pkg.peerDependencies) == null ? void 0 : _b.dumi) || ((_c = pkg.devDependencies) == null ? void 0 : _c.dumi) || "^2.0.0"; return import_plugin_utils.semver.subset(ver, import_constants.VERSION_2_LEVEL_NAV); } var theme_default = (api) => { const defaultThemeData = (0, import_loader.default)(DEFAULT_THEME_PATH); const pkgThemePath = getPkgThemePath(api); const pkgThemeData = (0, import_plugin_utils.deepmerge)( defaultThemeData, pkgThemePath ? (0, import_loader.default)(import_path.default.join(pkgThemePath, "dist")) : {} ); const localThemePath = import_path.default.join(api.cwd, import_constants.LOCAL_THEME_DIR); const localThemeData = import_fs.default.existsSync(localThemePath) ? (0, import_loader.default)(localThemePath) : void 0; const themeMapKeys = [ "layouts", "builtins", "slots" ]; let originalThemeData; api.describe({ key: "dumi:theme" }); [pkgThemeData.plugin, localThemeData == null ? void 0 : localThemeData.plugin].forEach((plugin) => { if (plugin) { api.registerPlugins([plugin]); } }); (0, import_derivative.safeExcludeInMFSU)( api, [ "dumi/theme-default", // for svgr "@ant-design/icons-svg", getPkgThemeName(api) ].filter(Boolean).map((pkg) => new RegExp(pkg)) ); api.register({ key: "modifyAppData", // prepare themeData before umi appData, for generate layout routes before: "appData", async fn(memo) { originalThemeData = await api.applyPlugins({ key: "modifyTheme", initialValue: pkgThemeData }); api.service.themeData = originalThemeData; if (localThemeData) { api.service.themeData = (0, import_plugin_utils.deepmerge)(originalThemeData, localThemeData, { clone: true }); } Object.assign(api.service.themeData.builtins, { DumiDemo: { specifier: "{ DumiDemo }", source: "dumi" }, DumiDemoGrid: { specifier: "{ DumiDemoGrid }", source: "dumi" }, Link: { specifier: "{ Link }", source: "dumi" } }); return memo; } }); api.modifyAppData((memo) => { memo._2LevelNavAvailable = checkMinor2ByPkg(api.pkg); if (pkgThemePath && !memo._2LevelNavAvailable) { memo._2LevelNavAvailable = checkMinor2ByPkg( require(import_path.default.join(pkgThemePath, "package.json")) ); } return memo; }); api.modifyConfig((memo) => { var _a, _b; if (localThemeData) { themeMapKeys.forEach((key) => { Object.values(localThemeData[key] || {}).forEach((item) => { memo.alias[`dumi/theme/${key}/${item.specifier}`] = item.source; }); }); } memo.alias["dumi/theme"] = "dumi/theme-original"; memo.alias["dumi/theme-original"] = import_path.default.join( api.paths.absTmpPath, "dumi/theme" ); memo.alias["dumi/theme-default"] = DEFAULT_THEME_PATH; memo.extraBabelIncludes ?? (memo.extraBabelIncludes = []); memo.extraBabelIncludes.push( import_path.default.resolve(__dirname, "../../client/theme-api") ); const repoUrl = ((_a = api.pkg.repository) == null ? void 0 : _a.url) || api.pkg.repository; if (((_b = memo.themeConfig) == null ? void 0 : _b.editLink) !== false && typeof repoUrl === "string") { const hostedGitIns = import_hosted_git_info.default.fromUrl(repoUrl); let branch = ""; try { branch = (0, import_child_process.execSync)("git branch --show-current", { stdio: "pipe" }).toString().trim(); } catch { branch = "master"; } if (hostedGitIns) { memo.themeConfig ?? (memo.themeConfig = {}); memo.themeConfig.editLink = `${hostedGitIns.edit( `${api.pkg.repository.directory || ""}/{filename}`, { committish: branch } )}`; } } return memo; }); api.chainWebpack((memo) => { const lessRule = memo.module.rule("less"); ["css", "css-modules"].forEach((rule) => { Object.values(lessRule.oneOf(rule).uses.entries()).forEach((loader) => { if (loader.get("loader").includes("less-loader")) { loader.tap((opts) => { var _a; (_a = opts.lessOptions).modifyVars ?? (_a.modifyVars = {}); opts.lessOptions.modifyVars["dark-selector"] = `~'[${import_constants.PREFERS_COLOR_ATTR}="dark"]'`; return opts; }); } }); }); return memo; }); api.onGenerateFiles({ // execute before umi tmpFiles plugin stage: -Infinity, fn() { const { globalLoading } = api.appData; const enableNProgress = !!api.config.themeConfig.nprogress; api.appData.globalLoading = "@@/dumi/theme/loading"; api.writeTmpFile({ noPluginDir: true, path: "dumi/theme/loading.tsx", content: `${enableNProgress ? `import nprogress from '${(0, import_plugin_utils.winPath)( import_path.default.dirname(require.resolve("nprogress/package")) )}'; import './nprogress.css';` : ""}${globalLoading ? ` import UserLoading from '${globalLoading}';` : ""} import React, { useLayoutEffect, type FC } from 'react'; import { useSiteData } from 'dumi'; const DumiLoading: FC = () => { const { setLoading } = useSiteData(); useLayoutEffect(() => { setLoading(true);${enableNProgress ? ` nprogress.start();` : ""} return () => { setLoading(false);${enableNProgress ? ` nprogress.done();` : ""} } }, []); return ${globalLoading ? "<UserLoading />" : "null"}; } export default DumiLoading; ` }); } }); api.onGenerateFiles(async () => { var _a, _b, _c, _d, _e; const pAll = themeMapKeys.flatMap( (key) => Object.values(originalThemeData[key] || {}).map(async (item) => { if (item.source === "dumi") return; const exports = await getModuleExports(item.source); const contents = []; if (exports.includes("default")) { contents.push(`export { default } from '${item.source}';`); } if (exports.some((exp) => exp !== "default")) { contents.push(`export * from '${item.source}';`); } api.writeTmpFile({ noPluginDir: true, path: `dumi/theme/${key}/${item.specifier}.ts`, content: contents.join("\n") }); }) ); await Promise.all(pAll); const entryFile = api.config.resolve.entryFile && [import_path.default.resolve(api.cwd, api.config.resolve.entryFile)].find(import_fs.default.existsSync); const entryExports = entryFile ? await getModuleExports(entryFile) : []; const hasDefaultExport = entryExports.includes("default"); const hasNamedExport = entryExports.some((exp) => exp !== "default"); api.writeTmpFile({ noPluginDir: true, path: "dumi/theme/ContextWrapper.tsx", content: `import React, { useState, useEffect, useRef } from 'react'; import { useOutlet, history } from 'dumi'; import { SiteContext } from '${(0, import_plugin_utils.winPath)( require.resolve("../../client/theme-api/context") )}'; import { demos, components } from '../meta'; import { locales } from '../locales/config';${hasDefaultExport ? ` import entryDefaultExport from '${(0, import_plugin_utils.winPath)(entryFile)}';` : ""}${hasNamedExport ? ` import * as entryMemberExports from '${(0, import_plugin_utils.winPath)(entryFile)}';` : ""} const entryExports = { ${hasDefaultExport ? "default: entryDefaultExport," : ""} ${hasNamedExport ? "...entryMemberExports," : ""} }; export default function DumiContextWrapper() { const outlet = useOutlet(); const [loading, setLoading] = useState(false); const prev = useRef(history.location.pathname); useEffect(() => { return history.listen((next) => { if (next.location.pathname !== prev.current) { prev.current = next.location.pathname; // scroll to top when route changed document.documentElement.scrollTo(0, 0); } }); }, []); return ( <SiteContext.Provider value={{ pkg: ${JSON.stringify( import_plugin_utils.lodash.pick(api.pkg, ...Object.keys(import_constants.PICKED_PKG_FIELDS)) )}, historyType: "${((_a = api.config.history) == null ? void 0 : _a.type) || "browser"}", entryExports, demos, components, locales, loading, setLoading, hostname: ${JSON.stringify((_b = api.config.sitemap) == null ? void 0 : _b.hostname)}, themeConfig: ${JSON.stringify( Object.assign( import_plugin_utils.lodash.pick(api.config, "logo", "description", "title"), api.config.themeConfig ) )}, _2_level_nav_available: ${api.appData._2LevelNavAvailable}, }}> {outlet} </SiteContext.Provider> ); }` }); const primaryColor = typeof ((_c = api.config) == null ? void 0 : _c.theme) === "object" ? (_e = (_d = api.config) == null ? void 0 : _d.theme) == null ? void 0 : _e["@c-primary"] : "#1677ff"; api.writeTmpFile({ noPluginDir: true, path: "dumi/theme/nprogress.css", content: ` /* https://unpkg.com/browse/nprogress@0.2.0/nprogress.css */ #nprogress { pointer-events: none; } #nprogress .bar { background: var; position: fixed; z-index: 1031; top: 0; left: 0; width: 100%; height: 2px; } #nprogress .peg { display: block; position: absolute; right: 0px; width: 100px; height: 100%; box-shadow: 0 0 10px ${primaryColor}, 0 0 5px ${primaryColor}; opacity: 1.0; transform: rotate(3deg) translate(0px, -4px); } #nprogress .spinner { display: block; position: fixed; z-index: 1031; top: 15px; right: 15px; } #nprogress .spinner-icon { width: 18px; height: 18px; box-sizing: border-box; border: solid 2px transparent; border-top-color: ${primaryColor}; border-left-color: ${primaryColor}; border-radius: 50%; animation: nprogress-spinner 400ms linear infinite; } .nprogress-custom-parent { overflow: hidden; position: relative; } .nprogress-custom-parent #nprogress .spinner, .nprogress-custom-parent #nprogress .bar { position: absolute; } @keyframes nprogress-spinner { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } ` }); }); api.addEntryCodeAhead(() => { const { prefersColor } = api.config.themeConfig; if (prefersColor.switch === false && prefersColor.default !== "auto") { return `document.documentElement.setAttribute('${import_constants.PREFERS_COLOR_ATTR}', '${prefersColor.default}');`; } return `(function () { var cache = typeof navigator !== 'undefined' && navigator.cookieEnabled && typeof window.localStorage !== 'undefined' && localStorage.getItem('dumi:prefers-color') || '${prefersColor.default}'; var isDark = window.matchMedia('(prefers-color-scheme: dark)').matches; var enums = ['light', 'dark', 'auto']; document.documentElement.setAttribute( '${import_constants.PREFERS_COLOR_ATTR}', cache === enums[2] ? (isDark ? enums[1] : enums[0]) : (enums.indexOf(cache) > -1 ? cache : enums[0]) ); })();`; }); api.addEntryImportsAhead(() => [ { specifier: "{ getPluginManager as getDumiPluginManager }", source: "./core/plugin" }, { specifier: "{ setPluginManager as setDumiPluginManager }", source: (0, import_plugin_utils.winPath)(require.resolve("../../client/theme-api/utils")) } ]); api.addEntryCode(() => "setDumiPluginManager(getDumiPluginManager());"); api.addRuntimePluginKey(() => [ "modifyCodeSandboxData", "modifyStackBlitzData" ]); if ( /*isTnpm*/ require("@umijs/core/package").__npminstall_done && import_fs.default.existsSync(localThemePath) && import_fs.default.lstatSync(localThemePath).isSymbolicLink() ) { api.chainWebpack((memo) => { const devThemeNodeModules = import_path.default.join(api.cwd, "../node_modules"); memo.snapshot( (0, import_plugin_utils.deepmerge)(memo.get("snapshot"), { immutablePaths: [devThemeNodeModules], managedPaths: [devThemeNodeModules] }) ); return memo; }); } };