From 309090993f18653a169da4b8080a7eecdf03f1f0 Mon Sep 17 00:00:00 2001 From: PeachScript Date: Sun, 8 Nov 2020 23:44:20 +0800 Subject: [PATCH] fix(theme): use abs layout paths in theme loader (#365) --- .github/workflows/preview.yml | 2 +- package.json | 2 +- .../preset-dumi/src/routes/getRouteConfig.ts | 7 +- packages/preset-dumi/src/theme/loader.ts | 64 +++++++++++-------- .../preset-dumi/src/utils/moduleResolver.ts | 4 +- 5 files changed, 44 insertions(+), 35 deletions(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index d790046ab7..d35dcb948f 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@v2 - uses: afc163/surge-preview@v1 env: - DUMI_THEME: dumi-theme-mobile + DUMI_THEME: ./packages/dumi-theme-mobile with: surge_token: ${{ secrets.SURGE_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/package.json b/package.json index fe05edd4fd..853c80c44d 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "private": true, "scripts": { "dev": "cross-env BROWSER=none node ./packages/dumi/bin/dumi.js dev", - "dev:mobile": "cross-env BROWSER=none DUMI_THEME=dumi-theme-mobile node ./packages/dumi/bin/dumi.js dev", + "dev:mobile": "cross-env BROWSER=none DUMI_THEME=./packages/theme-mobile node ./packages/dumi/bin/dumi.js dev", "watch": "npm run build -- --watch", "doc:build": "cross-env BROWSER=none node ./packages/dumi/bin/dumi.js build", "build": "father-build", diff --git a/packages/preset-dumi/src/routes/getRouteConfig.ts b/packages/preset-dumi/src/routes/getRouteConfig.ts index 2d98d00200..fd0d318301 100644 --- a/packages/preset-dumi/src/routes/getRouteConfig.ts +++ b/packages/preset-dumi/src/routes/getRouteConfig.ts @@ -53,12 +53,7 @@ export default async (api: IApi, opts: IDumiOpts): Promise => { // builtin outer layout slash(path.relative(api.paths.absPagesPath, path.join(__dirname, '../theme/layout'))), // theme layout - slash( - path.relative( - api.paths.absPagesPath, - path.resolve(paths.absNodeModulesPath, theme.layoutPaths._), - ), - ), + slash(path.relative(api.paths.absPagesPath, theme.layoutPaths._)), ], // decorate standard umi routes routes: decorateRoutes(childRoutes, opts, api), diff --git a/packages/preset-dumi/src/theme/loader.ts b/packages/preset-dumi/src/theme/loader.ts index 9d81ca1ca9..273f4ff92e 100644 --- a/packages/preset-dumi/src/theme/loader.ts +++ b/packages/preset-dumi/src/theme/loader.ts @@ -1,9 +1,11 @@ import fs from 'fs'; import path from 'path'; -import { winPath } from '@umijs/utils'; +import { winPath, createDebug } from '@umijs/utils'; import { getModuleResolvePath } from '../utils/moduleResolver'; import ctx from '../context'; +const debug = createDebug('dumi:theme'); + interface ThemeComponent { /** * component name @@ -81,26 +83,46 @@ function detectTheme() { return localTheme ? [localTheme] : detectInstalledTheme(); } +/** + * get resolved path for theme module + * @param sourcePath + */ +function getThemeResolvePath(sourcePath: string) { + return getModuleResolvePath({ + basePath: ctx.umi.cwd, + sourcePath, + silent: true, + // use empty alias to avoid dumi repo start failed + // because the auto-alias target theme-default/src + alias: {}, + }); +} + export default async () => { if (!cache || process.env.NODE_ENV === 'test') { - const [name = process.env.DUMI_THEME || FALLBACK_THEME] = detectTheme(); - const theme = path.isAbsolute(name) ? name : `${name}/src`; - const modulePath = winPath(path.resolve(ctx.umi.paths.absNodeModulesPath, theme)); - const builtinPath = path.join(modulePath, 'builtins'); + const [theme = process.env.DUMI_THEME || FALLBACK_THEME] = detectTheme(); + const modulePath = path.isAbsolute(theme) + ? theme + : // resolve real absolute path for theme package + winPath(path.dirname(getThemeResolvePath(theme))); + // local theme has no src directory but theme package has + const srcPath = path.isAbsolute(theme) ? theme : `${modulePath}/src`; + const builtinPath = winPath(path.join(srcPath, 'builtins')); const components = fs.existsSync(builtinPath) ? fs .readdirSync(builtinPath) .filter(file => /\.(j|t)sx?$/.test(file)) .map(file => ({ identifier: path.parse(file).name, - source: winPath(path.join(theme, 'builtins', file)), + // still use module identifier rather than abs path for theme package modules + source: winPath(path.join(theme, builtinPath.replace(modulePath, ''), file)), })) : []; - const fallbacks = REQUIRED_THEME_BUILTINS.reduce((result, name) => { - if (components.every(({ identifier }) => identifier !== name)) { + const fallbacks = REQUIRED_THEME_BUILTINS.reduce((result, bName) => { + if (components.every(({ identifier }) => identifier !== bName)) { result.push({ - identifier: name, - source: winPath(path.join(FALLBACK_THEME, 'src', 'builtins', `${name}`)), + identifier: bName, + source: winPath(path.join(FALLBACK_THEME, 'src', 'builtins', `${bName}`)), }); } @@ -109,22 +131,16 @@ export default async () => { const layoutPaths = {} as IThemeLoadResult['layoutPaths']; // outer layout: layout.tsx or layouts/index.tsx - [winPath(path.join(theme, 'layout')), winPath(path.join(theme, 'layouts'))].some( + [winPath(path.join(srcPath, 'layout')), winPath(path.join(srcPath, 'layouts'))].some( (layoutPath, i, outerLayoutPaths) => { try { - getModuleResolvePath({ - basePath: ctx.umi.paths.cwd, - sourcePath: layoutPath, - silent: true, - }); - - layoutPaths._ = layoutPath; + layoutPaths._ = getThemeResolvePath(layoutPath); return true; } catch (err) { // fallback to default theme layout if cannot find any valid layout if (i === outerLayoutPaths.length - 1) { - layoutPaths._ = winPath(path.join(FALLBACK_THEME, 'src', 'layout')); + layoutPaths._ = getThemeResolvePath(path.join(FALLBACK_THEME, 'src', 'layout')); } } }, @@ -132,13 +148,7 @@ export default async () => { // demo layout try { - layoutPaths.demo = winPath(path.join(theme, 'layouts', 'demo')); - - getModuleResolvePath({ - basePath: ctx.umi.paths.cwd, - sourcePath: layoutPaths.demo, - silent: true, - }); + layoutPaths.demo = getThemeResolvePath(path.join(srcPath, 'layouts', 'demo')); } catch (err) { layoutPaths.demo = null; } @@ -154,6 +164,8 @@ export default async () => { layoutPaths, }, }); + + debug(cache); } return cache; diff --git a/packages/preset-dumi/src/utils/moduleResolver.ts b/packages/preset-dumi/src/utils/moduleResolver.ts index 9624aee0b9..d3967db4f5 100644 --- a/packages/preset-dumi/src/utils/moduleResolver.ts +++ b/packages/preset-dumi/src/utils/moduleResolver.ts @@ -12,6 +12,7 @@ interface IModuleResolverOpts { sourcePath: string; extensions?: string[]; silent?: boolean; + alias?: { [key: string]: string }; } const getResolveAlias = (() => { @@ -42,12 +43,13 @@ export const getModuleResolvePath = ({ sourcePath, extensions = DEFAULT_EXT, silent, + alias, }: IModuleResolverOpts) => { try { return slash( resolve.create.sync({ extensions, - alias: getResolveAlias(), + alias: alias || getResolveAlias(), symlinks: false, mainFiles: ['index', 'package.json'], })(fs.statSync(basePath).isDirectory() ? basePath : path.parse(basePath).dir, sourcePath),