Skip to content

Commit

Permalink
refactor: extract inline plugin templates as independent files (#1874)
Browse files Browse the repository at this point in the history
* refactor: mv to tmpl

* refactor: more info

* refactor: to template

* docs: add customize page

* refactor: to contant

* chore: revert config

* chore: rm tmpl

* chore: dir path

* chore: clean up
  • Loading branch information
zombieJ authored Sep 7, 2023
1 parent 0ec05de commit 92db2c4
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 112 deletions.
2 changes: 2 additions & 0 deletions examples/normal/.dumi/pages/loader-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Customize Page for dumi test
export default () => 'Customize Dumi Test Page';
4 changes: 4 additions & 0 deletions src/client/theme-api/DumiDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,7 @@ export const DumiDemo: FC<IDumiDemoProps> = React.memo(
return JSON.stringify(prev).length === JSON.stringify(next).length;
},
);

if (process.env.NODE_ENV !== 'production') {
DumiDemo.displayName = 'DumiDemo';
}
4 changes: 4 additions & 0 deletions src/client/theme-api/DumiDemoGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,7 @@ export const DumiDemoGrid: FC<IDumiDemoGridProps> = (props) => {
</div>
);
};

if (process.env.NODE_ENV !== 'production') {
DumiDemoGrid.displayName = 'DumiDemoGrid';
}
4 changes: 4 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { join } from 'path';

export const LOCAL_DUMI_DIR = '.dumi';

export const LOCAL_THEME_DIR = `${LOCAL_DUMI_DIR}/theme`;
Expand Down Expand Up @@ -27,3 +29,5 @@ export const USELESS_TMP_FILES = ['tsconfig.json', 'typings.d.ts'];
export const VERSION_2_LEVEL_NAV = '^2.2.0';

export const VERSION_2_DEPRECATE_SOFT_BREAKS = '^2.2.0';

export const TEMPLATES_DIR = join(__dirname, './templates');
66 changes: 17 additions & 49 deletions src/features/meta.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { TEMPLATES_DIR } from '@/constants';
import type { IApi } from '@/types';
import path from 'path';
import path, { join } from 'path';
import type { IRoute } from 'umi';
import { Mustache, winPath } from 'umi/plugin-utils';
import { winPath } from 'umi/plugin-utils';
import { isTabRouteFile } from './tabs';

export const TABS_META_PATH = 'dumi/meta/tabs.ts';
export const ATOMS_META_PATH = 'dumi/meta/atoms.ts';

type MetaFiles = { index: number; file: string; id: string }[];

export default (api: IApi) => {
const metaFiles: { index: number; file: string; id: string }[] = [];
const metaFiles: MetaFiles = [];

api.register({
key: 'modifyRoutes',
Expand Down Expand Up @@ -46,55 +49,20 @@ export default (api: IApi) => {
content: 'export const components = null;',
});

// generate meta entry
// [legacy] generate meta entry
const parsedMetaFiles: MetaFiles = await api.applyPlugins({
type: api.ApplyPluginsType.modify,
key: 'dumi.modifyMetaFiles',
initialValue: JSON.parse(JSON.stringify(metaFiles)),
});

api.writeTmpFile({
noPluginDir: true,
path: 'dumi/meta/index.ts',
content: Mustache.render(
`{{#metaFiles}}
import { demos as dm{{{index}}}, frontmatter as fm{{{index}}}, toc as toc{{{index}}}, texts as txt{{{index}}} } from '{{{file}}}?type=meta';
{{/metaFiles}}
export { components } from './atoms';
export { tabs } from './tabs';
export const filesMeta = {
{{#metaFiles}}
'{{{id}}}': {
frontmatter: fm{{{index}}},
toc: toc{{{index}}},
texts: txt{{{index}}},
demos: dm{{{index}}},
{{#tabs}}
tabs: {{{tabs}}},
{{/tabs}}
},
{{/metaFiles}}
}
// generate demos data in runtime, for reuse route.id to reduce bundle size
export const demos = Object.entries(filesMeta).reduce((acc, [id, meta]) => {
// append route id to demo
Object.values(meta.demos).forEach((demo) => {
demo.routeId = id;
});
// merge demos
Object.assign(acc, meta.demos);
// remove demos from meta, to avoid deep clone demos in umi routes/children compatible logic
delete meta.demos;
return acc;
}, {});
`,
{
metaFiles: await api.applyPlugins({
type: api.ApplyPluginsType.modify,
key: 'dumi.modifyMetaFiles',
initialValue: metaFiles,
}),
},
),
tplPath: winPath(join(TEMPLATES_DIR, 'meta.ts.tpl')),
context: {
metaFiles: parsedMetaFiles,
},
});

// generate runtime plugin, to append page meta to route object
Expand Down
87 changes: 25 additions & 62 deletions src/features/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
LOCAL_THEME_DIR,
PICKED_PKG_FIELDS,
PREFERS_COLOR_ATTR,
TEMPLATES_DIR,
THEME_PREFIX,
VERSION_2_LEVEL_NAV,
} from '@/constants';
Expand All @@ -10,7 +11,7 @@ import { parseModuleSync } from '@umijs/bundler-utils';
import { execSync } from 'child_process';
import fs from 'fs';
import hostedGit from 'hosted-git-info';
import path from 'path';
import path, { join } from 'path';
import { deepmerge, lodash, resolve, semver, winPath } from 'umi/plugin-utils';
import { safeExcludeInMFSU } from '../derivative';
import loadTheme, { IThemeLoadResult } from './loader';
Expand Down Expand Up @@ -369,68 +370,30 @@ export default DumiLoading;
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 '${winPath(
require.resolve('../../client/theme-api/context'),
)}';
import { demos, components } from '../meta';
import { locales } from '../locales/config';${
hasDefaultExport
? `\nimport entryDefaultExport from '${winPath(entryFile!)}';`
: ''
}${
hasNamedExport
? `\nimport * as entryMemberExports from '${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(
lodash.pick(api.pkg, ...Object.keys(PICKED_PKG_FIELDS)),
)},
historyType: "${api.config.history?.type || 'browser'}",
entryExports,
demos,
components,
locales,
loading,
setLoading,
hostname: ${JSON.stringify(api.config.sitemap?.hostname)},
themeConfig: ${JSON.stringify(
Object.assign(
lodash.pick(api.config, 'logo', 'description', 'title'),
api.config.themeConfig,
tplPath: winPath(join(TEMPLATES_DIR, 'ContextWrapper.ts.tpl')),
context: {
contextPath: winPath(require.resolve('../../client/theme-api/context')),
defaultExport: hasDefaultExport
? `import entryDefaultExport from '${winPath(entryFile!)}';`
: '',
namedExport: hasNamedExport
? `import * as entryMemberExports from '${winPath(entryFile!)}';`
: '',
hasDefaultExport,
hasNamedExport,
pkg: JSON.stringify(
lodash.pick(api.pkg, ...Object.keys(PICKED_PKG_FIELDS)),
),
)},
_2_level_nav_available: ${api.appData._2LevelNavAvailable},
}}>
{outlet}
</SiteContext.Provider>
);
}`,
historyType: api.config.history?.type || 'browser',
hostname: String(JSON.stringify(api.config.sitemap?.hostname)),
themeConfig: JSON.stringify(
Object.assign(
lodash.pick(api.config, 'logo', 'description', 'title'),
api.config.themeConfig,
),
),
_2_level_nav_available: api.appData._2LevelNavAvailable,
},
});

const primaryColor =
Expand Down
2 changes: 1 addition & 1 deletion src/loaders/markdown/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export default DumiMarkdownContent;`;
}
}

function getDepsCacheKey(deps: typeof depsMapping['0'] = []) {
function getDepsCacheKey(deps: (typeof depsMapping)['0'] = []) {
return JSON.stringify(
deps.map((file) => `${file}:${fs.statSync(file).mtimeMs}`),
);
Expand Down
53 changes: 53 additions & 0 deletions src/templates/ContextWrapper.ts.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React, { useState, useEffect, useRef } from 'react';
import { useOutlet, history } from 'dumi';
import { SiteContext } from '{{{contextPath}}}';
import { demos, components } from '../meta';
import { locales } from '../locales/config';
{{{defaultExport}}}
{{{namedExport}}}

const entryExports = {
{{#hasDefaultExport}}
default: entryDefaultExport,
{{/hasDefaultExport}}
{{#hasNamedExport}}
...entryMemberExports,
{{/hasNamedExport}}
};

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);
}
});
}, []);

const context = {
pkg: {{{pkg}}},
historyType: "{{{historyType}}}",
entryExports,
demos,
components,
locales,
loading,
setLoading,
hostname: {{{hostname}}},
themeConfig: {{{themeConfig}}},
_2_level_nav_available: {{{_2_level_nav_available}}},
};

return (
<SiteContext.Provider value={context}>
{outlet}
</SiteContext.Provider>
);
}
35 changes: 35 additions & 0 deletions src/templates/meta.ts.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{{#metaFiles}}
import { demos as dm{{{index}}}, frontmatter as fm{{{index}}}, toc as toc{{{index}}}, texts as txt{{{index}}} } from '{{{file}}}?type=meta';
{{/metaFiles}}

export { components } from './atoms';
export { tabs } from './tabs';

export const filesMeta = {
{{#metaFiles}}
'{{{id}}}': {
frontmatter: fm{{{index}}},
toc: toc{{{index}}},
texts: txt{{{index}}},
demos: dm{{{index}}},
{{#tabs}}
tabs: {{{tabs}}},
{{/tabs}}
},
{{/metaFiles}}
}

// generate demos data in runtime, for reuse route.id to reduce bundle size
export const demos = Object.entries(filesMeta).reduce((acc, [id, meta]) => {
// append route id to demo
Object.values(meta.demos).forEach((demo) => {
demo.routeId = id;
});
// merge demos
Object.assign(acc, meta.demos);

// remove demos from meta, to avoid deep clone demos in umi routes/children compatible logic
delete meta.demos;

return acc;
}, {});

0 comments on commit 92db2c4

Please sign in to comment.